]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/bootpd/bootpd.c
Add UPDATING entries and bump version.
[FreeBSD/FreeBSD.git] / libexec / bootpd / bootpd.c
1 /************************************************************************
2           Copyright 1988, 1991 by Carnegie Mellon University
3
4                           All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted, provided
8 that the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation, and that the name of Carnegie Mellon University not be used
11 in advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
13
14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21
22 ************************************************************************/
23
24 /*
25  * BOOTP (bootstrap protocol) server daemon.
26  *
27  * Answers BOOTP request packets from booting client machines.
28  * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
29  * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
30  * See RFC 1395 for option tags 14-17.
31  * See accompanying man page -- bootpd.8
32  *
33  * HISTORY
34  *      See ./Changes
35  *
36  * BUGS
37  *      See ./ToDo
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <sys/file.h>
48 #include <sys/time.h>
49 #include <sys/stat.h>
50 #include <sys/utsname.h>
51
52 #include <net/if.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>  /* inet_ntoa */
55
56 #ifndef NO_UNISTD
57 #include <unistd.h>
58 #endif
59
60 #include <stdlib.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <errno.h>
65 #include <ctype.h>
66 #include <netdb.h>
67 #include <paths.h>
68 #include <syslog.h>
69 #include <assert.h>
70 #include <inttypes.h>
71
72 #ifdef  NO_SETSID
73 # include <fcntl.h>             /* for O_RDONLY, etc */
74 #endif
75
76 #include "bootp.h"
77 #include "hash.h"
78 #include "hwaddr.h"
79 #include "bootpd.h"
80 #include "dovend.h"
81 #include "getif.h"
82 #include "readfile.h"
83 #include "report.h"
84 #include "tzone.h"
85 #include "patchlevel.h"
86
87 #ifndef CONFIG_FILE
88 #define CONFIG_FILE             "/etc/bootptab"
89 #endif
90 #ifndef DUMPTAB_FILE
91 #define DUMPTAB_FILE            "/tmp/bootpd.dump"
92 #endif
93
94 \f
95
96 /*
97  * Externals, forward declarations, and global variables
98  */
99
100 extern void dumptab(char *);
101
102 PRIVATE void catcher(int);
103 PRIVATE int chk_access(char *, int32 *);
104 #ifdef VEND_CMU
105 PRIVATE void dovend_cmu(struct bootp *, struct host *);
106 #endif
107 PRIVATE void dovend_rfc1048(struct bootp *, struct host *, int32);
108 PRIVATE void handle_reply(void);
109 PRIVATE void handle_request(void);
110 PRIVATE void sendreply(int forward, int32 dest_override);
111 PRIVATE void usage(void);
112
113 /*
114  * IP port numbers for client and server obtained from /etc/services
115  */
116
117 u_short bootps_port, bootpc_port;
118
119
120 /*
121  * Internet socket and interface config structures
122  */
123
124 struct sockaddr_in bind_addr;   /* Listening */
125 struct sockaddr_in recv_addr;   /* Packet source */
126 struct sockaddr_in send_addr;   /*  destination */
127
128
129 /*
130  * option defaults
131  */
132 int debug = 0;                                  /* Debugging flag (level) */
133 struct timeval actualtimeout =
134 {                                                               /* fifteen minutes */
135         15 * 60L,                                       /* tv_sec */
136         0                                                       /* tv_usec */
137 };
138 int arpmod = TRUE;                              /* modify the ARP table */
139
140 /*
141  * General
142  */
143
144 int s;                                                  /* Socket file descriptor */
145 char *pktbuf;                                   /* Receive packet buffer */
146 int pktlen;
147 char *progname;
148 char *chdir_path;
149 struct in_addr my_ip_addr;
150
151 static const char *hostname;
152 static char default_hostname[MAXHOSTNAMELEN];
153
154 /* Flags set by signal catcher. */
155 PRIVATE int do_readtab = 0;
156 PRIVATE int do_dumptab = 0;
157
158 /*
159  * Globals below are associated with the bootp database file (bootptab).
160  */
161
162 char *bootptab = CONFIG_FILE;
163 char *bootpd_dump = DUMPTAB_FILE;
164
165 \f
166
167 /*
168  * Initialization such as command-line processing is done and then the
169  * main server loop is started.
170  */
171
172 int
173 main(argc, argv)
174         int argc;
175         char **argv;
176 {
177         struct timeval *timeout;
178         struct bootp *bp;
179         struct servent *servp;
180         struct hostent *hep;
181         char *stmp;
182         socklen_t ba_len, ra_len;
183         int n;
184         int nfound;
185         fd_set readfds;
186         int standalone;
187 #ifdef  SA_NOCLDSTOP    /* Have POSIX sigaction(2). */
188         struct sigaction sa;
189 #endif
190
191         progname = strrchr(argv[0], '/');
192         if (progname) progname++;
193         else progname = argv[0];
194
195         /*
196          * Initialize logging.
197          */
198         report_init(0);                         /* uses progname */
199
200         /*
201          * Log startup
202          */
203         report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
204
205         /* Debugging for compilers with struct padding. */
206         assert(sizeof(struct bootp) == BP_MINPKTSZ);
207
208         /* Get space for receiving packets and composing replies. */
209         pktbuf = malloc(MAX_MSG_SIZE);
210         if (!pktbuf) {
211                 report(LOG_ERR, "malloc failed");
212                 exit(1);
213         }
214         bp = (struct bootp *) pktbuf;
215
216         /*
217          * Check to see if a socket was passed to us from inetd.
218          *
219          * Use getsockname() to determine if descriptor 0 is indeed a socket
220          * (and thus we are probably a child of inetd) or if it is instead
221          * something else and we are running standalone.
222          */
223         s = 0;
224         ba_len = sizeof(bind_addr);
225         bzero((char *) &bind_addr, ba_len);
226         errno = 0;
227         standalone = TRUE;
228         if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
229                 /*
230                  * Descriptor 0 is a socket.  Assume we are a child of inetd.
231                  */
232                 if (bind_addr.sin_family == AF_INET) {
233                         standalone = FALSE;
234                         bootps_port = ntohs(bind_addr.sin_port);
235                 } else {
236                         /* Some other type of socket? */
237                         report(LOG_ERR, "getsockname: not an INET socket");
238                 }
239         }
240
241         /*
242          * Set defaults that might be changed by option switches.
243          */
244         stmp = NULL;
245         timeout = &actualtimeout;
246
247         if (gethostname(default_hostname, sizeof(default_hostname) - 1) < 0) {
248                 report(LOG_ERR, "bootpd: can't get hostname\n");
249                 exit(1);
250         }
251         default_hostname[sizeof(default_hostname) - 1] = '\0';
252         hostname = default_hostname;
253
254         /*
255          * Read switches.
256          */
257         for (argc--, argv++; argc > 0; argc--, argv++) {
258                 if (argv[0][0] != '-')
259                         break;
260                 switch (argv[0][1]) {
261
262                 case 'a':                               /* don't modify the ARP table */
263                         arpmod = FALSE;
264                         break;
265                 case 'c':                               /* chdir_path */
266                         if (argv[0][2]) {
267                                 stmp = &(argv[0][2]);
268                         } else {
269                                 argc--;
270                                 argv++;
271                                 stmp = argv[0];
272                         }
273                         if (!stmp || (stmp[0] != '/')) {
274                                 report(LOG_ERR,
275                                                 "bootpd: invalid chdir specification\n");
276                                 break;
277                         }
278                         chdir_path = stmp;
279                         break;
280
281                 case 'd':                               /* debug level */
282                         if (argv[0][2]) {
283                                 stmp = &(argv[0][2]);
284                         } else if (argv[1] && argv[1][0] == '-') {
285                                 /*
286                                  * Backwards-compatible behavior:
287                                  * no parameter, so just increment the debug flag.
288                                  */
289                                 debug++;
290                                 break;
291                         } else {
292                                 argc--;
293                                 argv++;
294                                 stmp = argv[0];
295                         }
296                         if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
297                                 report(LOG_ERR,
298                                                 "%s: invalid debug level\n", progname);
299                                 break;
300                         }
301                         debug = n;
302                         break;
303
304                 case 'h':                               /* override hostname */
305                         if (argv[0][2]) {
306                                 stmp = &(argv[0][2]);
307                         } else {
308                                 argc--;
309                                 argv++;
310                                 stmp = argv[0];
311                         }
312                         if (!stmp) {
313                                 report(LOG_ERR,
314                                                 "bootpd: missing hostname\n");
315                                 break;
316                         }
317                         hostname = stmp;
318                         break;
319
320                 case 'i':                               /* inetd mode */
321                         standalone = FALSE;
322                         break;
323
324                 case 's':                               /* standalone mode */
325                         standalone = TRUE;
326                         break;
327
328                 case 't':                               /* timeout */
329                         if (argv[0][2]) {
330                                 stmp = &(argv[0][2]);
331                         } else {
332                                 argc--;
333                                 argv++;
334                                 stmp = argv[0];
335                         }
336                         if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
337                                 report(LOG_ERR,
338                                                 "%s: invalid timeout specification\n", progname);
339                                 break;
340                         }
341                         actualtimeout.tv_sec = (int32) (60 * n);
342                         /*
343                          * If the actual timeout is zero, pass a NULL pointer
344                          * to select so it blocks indefinitely, otherwise,
345                          * point to the actual timeout value.
346                          */
347                         timeout = (n > 0) ? &actualtimeout : NULL;
348                         break;
349
350                 default:
351                         report(LOG_ERR, "%s: unknown switch: -%c\n",
352                                         progname, argv[0][1]);
353                         usage();
354                         break;
355
356                 } /* switch */
357         } /* for args */
358
359         /*
360          * Override default file names if specified on the command line.
361          */
362         if (argc > 0)
363                 bootptab = argv[0];
364
365         if (argc > 1)
366                 bootpd_dump = argv[1];
367
368         /*
369          * Get my hostname and IP address.
370          */
371
372         hep = gethostbyname(hostname);
373         if (!hep) {
374                 report(LOG_ERR, "Can not get my IP address\n");
375                 exit(1);
376         }
377         bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
378
379         if (standalone) {
380                 /*
381                  * Go into background and disassociate from controlling terminal.
382                  */
383                 if (debug < 3) {
384                         if (fork())
385                                 exit(0);
386 #ifdef  NO_SETSID
387                         setpgrp(0,0);
388 #ifdef TIOCNOTTY
389                         n = open(_PATH_TTY, O_RDWR);
390                         if (n >= 0) {
391                                 ioctl(n, TIOCNOTTY, (char *) 0);
392                                 (void) close(n);
393                         }
394 #endif  /* TIOCNOTTY */
395 #else   /* SETSID */
396                         if (setsid() < 0)
397                                 perror("setsid");
398 #endif  /* SETSID */
399                 } /* if debug < 3 */
400
401                 /*
402                  * Nuke any timeout value
403                  */
404                 timeout = NULL;
405
406         } /* if standalone (1st) */
407
408         /* Set the cwd (i.e. to /tftpboot) */
409         if (chdir_path) {
410                 if (chdir(chdir_path) < 0)
411                         report(LOG_ERR, "%s: chdir failed", chdir_path);
412         }
413
414         /* Get the timezone. */
415         tzone_init();
416
417         /* Allocate hash tables. */
418         rdtab_init();
419
420         /*
421          * Read the bootptab file.
422          */
423         readtab(1);                                     /* force read */
424
425         if (standalone) {
426
427                 /*
428                  * Create a socket.
429                  */
430                 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
431                         report(LOG_ERR, "socket: %s", get_network_errmsg());
432                         exit(1);
433                 }
434
435                 /*
436                  * Get server's listening port number
437                  */
438                 servp = getservbyname("bootps", "udp");
439                 if (servp) {
440                         bootps_port = ntohs((u_short) servp->s_port);
441                 } else {
442                         bootps_port = (u_short) IPPORT_BOOTPS;
443                         report(LOG_ERR,
444                                 "bootps/udp: unknown service -- using port %d",
445                                    bootps_port);
446                 }
447
448                 /*
449                  * Bind socket to BOOTPS port.
450                  */
451                 bind_addr.sin_family = AF_INET;
452                 bind_addr.sin_addr.s_addr = INADDR_ANY;
453                 bind_addr.sin_port = htons(bootps_port);
454                 if (bind(s, (struct sockaddr *) &bind_addr,
455                                  sizeof(bind_addr)) < 0)
456                 {
457                         report(LOG_ERR, "bind: %s", get_network_errmsg());
458                         exit(1);
459                 }
460         } /* if standalone (2nd)*/
461
462         /*
463          * Get destination port number so we can reply to client
464          */
465         servp = getservbyname("bootpc", "udp");
466         if (servp) {
467                 bootpc_port = ntohs(servp->s_port);
468         } else {
469                 report(LOG_ERR,
470                            "bootpc/udp: unknown service -- using port %d",
471                            IPPORT_BOOTPC);
472                 bootpc_port = (u_short) IPPORT_BOOTPC;
473         }
474
475         /*
476          * Set up signals to read or dump the table.
477          */
478 #ifdef  SA_NOCLDSTOP    /* Have POSIX sigaction(2). */
479         sa.sa_handler = catcher;
480         sigemptyset(&sa.sa_mask);
481         sa.sa_flags = 0;
482         if (sigaction(SIGHUP, &sa, NULL) < 0) {
483                 report(LOG_ERR, "sigaction: %s", get_errmsg());
484                 exit(1);
485         }
486         if (sigaction(SIGUSR1, &sa, NULL) < 0) {
487                 report(LOG_ERR, "sigaction: %s", get_errmsg());
488                 exit(1);
489         }
490 #else   /* SA_NOCLDSTOP */
491         /* Old-fashioned UNIX signals */
492         if ((int) signal(SIGHUP, catcher) < 0) {
493                 report(LOG_ERR, "signal: %s", get_errmsg());
494                 exit(1);
495         }
496         if ((int) signal(SIGUSR1, catcher) < 0) {
497                 report(LOG_ERR, "signal: %s", get_errmsg());
498                 exit(1);
499         }
500 #endif  /* SA_NOCLDSTOP */
501
502         /*
503          * Process incoming requests.
504          */
505         FD_ZERO(&readfds);
506         for (;;) {
507                 struct timeval tv;
508
509                 FD_SET(s, &readfds);
510                 if (timeout)
511                         tv = *timeout;
512
513                 nfound = select(s + 1, &readfds, NULL, NULL,
514                                                 (timeout) ? &tv : NULL);
515                 if (nfound < 0) {
516                         if (errno != EINTR) {
517                                 report(LOG_ERR, "select: %s", get_errmsg());
518                         }
519                         /*
520                          * Call readtab() or dumptab() here to avoid the
521                          * dangers of doing I/O from a signal handler.
522                          */
523                         if (do_readtab) {
524                                 do_readtab = 0;
525                                 readtab(1);             /* force read */
526                         }
527                         if (do_dumptab) {
528                                 do_dumptab = 0;
529                                 dumptab(bootpd_dump);
530                         }
531                         continue;
532                 }
533                 if (!FD_ISSET(s, &readfds)) {
534                         if (debug > 1)
535                                 report(LOG_INFO, "exiting after %jd minutes of inactivity",
536                                            (intmax_t)actualtimeout.tv_sec / 60);
537                         exit(0);
538                 }
539                 ra_len = sizeof(recv_addr);
540                 n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
541                                          (struct sockaddr *) &recv_addr, &ra_len);
542                 if (n <= 0) {
543                         continue;
544                 }
545                 if (debug > 1) {
546                         report(LOG_INFO, "recvd pkt from IP addr %s",
547                                    inet_ntoa(recv_addr.sin_addr));
548                 }
549                 if (n < sizeof(struct bootp)) {
550                         if (debug) {
551                                 report(LOG_NOTICE, "received short packet");
552                         }
553                         continue;
554                 }
555                 pktlen = n;
556
557                 readtab(0);                             /* maybe re-read bootptab */
558
559                 switch (bp->bp_op) {
560                 case BOOTREQUEST:
561                         handle_request();
562                         break;
563                 case BOOTREPLY:
564                         handle_reply();
565                         break;
566                 }
567         }
568         return 0;
569 }
570
571 \f
572
573
574 /*
575  * Print "usage" message and exit
576  */
577
578 PRIVATE void
579 usage()
580 {
581         fprintf(stderr,
582                 "usage: bootpd [-a] [-i | -s] [-c chdir-path] [-d level] [-h hostname]\n"
583                 "              [-t timeout] [bootptab [dumpfile]]\n");
584         fprintf(stderr, "\t -a\tdon't modify ARP table\n");
585         fprintf(stderr, "\t -c n\tset current directory\n");
586         fprintf(stderr, "\t -d n\tset debug level\n");
587         fprintf(stderr, "\t -h n\tset the hostname to listen on\n");
588         fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
589         fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
590         fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
591         exit(1);
592 }
593
594 /* Signal catchers */
595 PRIVATE void
596 catcher(sig)
597         int sig;
598 {
599         if (sig == SIGHUP)
600                 do_readtab = 1;
601         if (sig == SIGUSR1)
602                 do_dumptab = 1;
603 #if     !defined(SA_NOCLDSTOP) && defined(SYSV)
604         /* For older "System V" derivatives with no sigaction(). */
605         signal(sig, catcher);
606 #endif
607 }
608
609 \f
610
611 /*
612  * Process BOOTREQUEST packet.
613  *
614  * Note:  This version of the bootpd.c server never forwards
615  * a request to another server.  That is the job of a gateway
616  * program such as the "bootpgw" program included here.
617  *
618  * (Also this version does not interpret the hostname field of
619  * the request packet;  it COULD do a name->address lookup and
620  * forward the request there.)
621  */
622 PRIVATE void
623 handle_request()
624 {
625         struct bootp *bp = (struct bootp *) pktbuf;
626         struct host *hp = NULL;
627         struct host dummyhost;
628         int32 bootsize = 0;
629         unsigned hlen, hashcode;
630         int32 dest;
631         char realpath[1024];
632         char *clntpath;
633         char *homedir, *bootfile;
634         int n;
635
636         if (bp->bp_htype >= hwinfocnt) {
637                 report(LOG_NOTICE, "bad hw addr type %u", bp->bp_htype);
638                 return;
639         }
640         bp->bp_file[sizeof(bp->bp_file)-1] = '\0';
641
642         /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
643
644         /*
645          * If the servername field is set, compare it against us.
646          * If we're not being addressed, ignore this request.
647          * If the server name field is null, throw in our name.
648          */
649         if (strlen(bp->bp_sname)) {
650                 if (strcmp(bp->bp_sname, hostname)) {
651                         if (debug)
652                                 report(LOG_INFO, "\
653 ignoring request for server %s from client at %s address %s",
654                                            bp->bp_sname, netname(bp->bp_htype),
655                                            haddrtoa(bp->bp_chaddr, bp->bp_hlen));
656                         /* XXX - Is it correct to ignore such a request? -gwr */
657                         return;
658                 }
659         } else {
660                 strcpy(bp->bp_sname, hostname);
661         }
662
663         /* Convert the request into a reply. */
664         bp->bp_op = BOOTREPLY;
665         if (bp->bp_ciaddr.s_addr == 0) {
666                 /*
667                  * client doesn't know his IP address,
668                  * search by hardware address.
669                  */
670                 if (debug > 1) {
671                         report(LOG_INFO, "request from %s address %s",
672                                    netname(bp->bp_htype),
673                                    haddrtoa(bp->bp_chaddr, bp->bp_hlen));
674                 }
675                 hlen = haddrlength(bp->bp_htype);
676                 if (hlen != bp->bp_hlen) {
677                         report(LOG_NOTICE, "bad addr len from %s address %s",
678                                    netname(bp->bp_htype),
679                                    haddrtoa(bp->bp_chaddr, hlen));
680                 }
681                 dummyhost.htype = bp->bp_htype;
682                 bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
683                 hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
684                 hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
685                                                                                  &dummyhost);
686                 if (hp == NULL &&
687                         bp->bp_htype == HTYPE_IEEE802)
688                 {
689                         /* Try again with address in "canonical" form. */
690                         haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
691                         if (debug > 1) {
692                                 report(LOG_INFO, "\
693 HW addr type is IEEE 802.  convert to %s and check again\n",
694                                            haddrtoa(dummyhost.haddr, bp->bp_hlen));
695                         }
696                         hashcode = hash_HashFunction(dummyhost.haddr, hlen);
697                         hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
698                                                                                          hwlookcmp, &dummyhost);
699                 }
700                 if (hp == NULL) {
701                         /*
702                          * XXX - Add dynamic IP address assignment?
703                          */
704                         if (debug)
705                                 report(LOG_NOTICE, "unknown client %s address %s",
706                                            netname(bp->bp_htype),
707                                            haddrtoa(bp->bp_chaddr, bp->bp_hlen));
708                         return; /* not found */
709                 }
710                 (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
711
712         } else {
713
714                 /*
715                  * search by IP address.
716                  */
717                 if (debug > 1) {
718                         report(LOG_INFO, "request from IP addr %s",
719                                    inet_ntoa(bp->bp_ciaddr));
720                 }
721                 dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
722                 hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
723                 hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
724                                                                                  &dummyhost);
725                 if (hp == NULL) {
726                         if (debug) {
727                                 report(LOG_NOTICE, "IP address not found: %s",
728                                            inet_ntoa(bp->bp_ciaddr));
729                         }
730                         return;
731                 }
732         }
733
734         if (debug) {
735                 report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
736                            hp->hostname->string);
737         }
738
739         /*
740          * If there is a response delay threshold, ignore requests
741          * with a timestamp lower than the threshold.
742          */
743         if (hp->flags.min_wait) {
744                 u_int32 t = (u_int32) ntohs(bp->bp_secs);
745                 if (t < hp->min_wait) {
746                         if (debug > 1)
747                                 report(LOG_INFO,
748                                            "ignoring request due to timestamp (%d < %d)",
749                                            t, hp->min_wait);
750                         return;
751                 }
752         }
753
754 #ifdef  YORK_EX_OPTION
755         /*
756          * The need for the "ex" tag arose out of the need to empty
757          * shared networked drives on diskless PCs.  This solution is
758          * not very clean but it does work fairly well.
759          * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
760          *
761          * XXX - This could compromise security if a non-trusted user
762          * managed to write an entry in the bootptab with :ex=trojan:
763          * so I would leave this turned off unless you need it. -gwr
764          */
765         /* Run a program, passing the client name as a parameter. */
766         if (hp->flags.exec_file) {
767                 char tst[100];
768                 /* XXX - Check string lengths? -gwr */
769                 strcpy (tst, hp->exec_file->string);
770                 strcat (tst, " ");
771                 strcat (tst, hp->hostname->string);
772                 strcat (tst, " &");
773                 if (debug)
774                         report(LOG_INFO, "executing %s", tst);
775                 system(tst);    /* Hope this finishes soon... */
776         }
777 #endif  /* YORK_EX_OPTION */
778
779         /*
780          * If a specific TFTP server address was specified in the bootptab file,
781          * fill it in, otherwise zero it.
782          * XXX - Rather than zero it, should it be the bootpd address? -gwr
783          */
784         (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
785                 hp->bootserver.s_addr : 0L;
786
787 #ifdef  STANFORD_PROM_COMPAT
788         /*
789          * Stanford bootp PROMs (for a Sun?) have no way to leave
790          * the boot file name field blank (because the boot file
791          * name is automatically generated from some index).
792          * As a work-around, this little hack allows those PROMs to
793          * specify "sunboot14" with the same effect as a NULL name.
794          * (The user specifies boot device 14 or some such magic.)
795          */
796         if (strcmp(bp->bp_file, "sunboot14") == 0)
797                 bp->bp_file[0] = '\0';  /* treat it as unspecified */
798 #endif
799
800         /*
801          * Fill in the client's proper bootfile.
802          *
803          * If the client specifies an absolute path, try that file with a
804          * ".host" suffix and then without.  If the file cannot be found, no
805          * reply is made at all.
806          *
807          * If the client specifies a null or relative file, use the following
808          * table to determine the appropriate action:
809          *
810          *  Homedir      Bootfile    Client's file
811          * specified?   specified?   specification   Action
812          * -------------------------------------------------------------------
813          *      No          No          Null         Send null filename
814          *      No          No          Relative     Discard request
815          *      No          Yes         Null         Send if absolute else null
816          *      No          Yes         Relative     Discard request     *XXX
817          *      Yes         No          Null         Send null filename
818          *      Yes         No          Relative     Lookup with ".host"
819          *      Yes         Yes         Null         Send home/boot or bootfile
820          *      Yes         Yes         Relative     Lookup with ".host" *XXX
821          *
822          */
823
824         /*
825          * XXX - I don't like the policy of ignoring a client when the
826          * boot file is not accessible.  The TFTP server might not be
827          * running on the same machine as the BOOTP server, in which
828          * case checking accessibility of the boot file is pointless.
829          *
830          * Therefore, file accessibility is now demanded ONLY if you
831          * define CHECK_FILE_ACCESS in the Makefile options. -gwr
832          */
833
834         /*
835          * The "real" path is as seen by the BOOTP daemon on this
836          * machine, while the client path is relative to the TFTP
837          * daemon chroot directory (i.e. /tftpboot).
838          */
839         if (hp->flags.tftpdir) {
840                 snprintf(realpath, sizeof(realpath), "%s", hp->tftpdir->string);
841                 clntpath = &realpath[strlen(realpath)];
842         } else {
843                 realpath[0] = '\0';
844                 clntpath = realpath;
845         }
846
847         /*
848          * Determine client's requested homedir and bootfile.
849          */
850         homedir = NULL;
851         bootfile = NULL;
852         if (bp->bp_file[0]) {
853                 homedir = bp->bp_file;
854                 bootfile = strrchr(homedir, '/');
855                 if (bootfile) {
856                         if (homedir == bootfile)
857                                 homedir = NULL;
858                         *bootfile++ = '\0';
859                 } else {
860                         /* no "/" in the string */
861                         bootfile = homedir;
862                         homedir = NULL;
863                 }
864                 if (debug > 2) {
865                         report(LOG_INFO, "requested path=\"%s\"  file=\"%s\"",
866                                    (homedir) ? homedir : "",
867                                    (bootfile) ? bootfile : "");
868                 }
869         }
870
871         /*
872          * Specifications in bootptab override client requested values.
873          */
874         if (hp->flags.homedir)
875                 homedir = hp->homedir->string;
876         if (hp->flags.bootfile)
877                 bootfile = hp->bootfile->string;
878
879         /*
880          * Construct bootfile path.
881          */
882         if (homedir) {
883                 if (homedir[0] != '/')
884                         strcat(clntpath, "/");
885                 strcat(clntpath, homedir);
886                 homedir = NULL;
887         }
888         if (bootfile) {
889                 if (bootfile[0] != '/')
890                         strcat(clntpath, "/");
891                 strcat(clntpath, bootfile);
892                 bootfile = NULL;
893         }
894
895         /*
896          * First try to find the file with a ".host" suffix
897          */
898         n = strlen(clntpath);
899         strcat(clntpath, ".");
900         strcat(clntpath, hp->hostname->string);
901         if (chk_access(realpath, &bootsize) < 0) {
902                 clntpath[n] = 0;                        /* Try it without the suffix */
903                 if (chk_access(realpath, &bootsize) < 0) {
904                         /* neither "file.host" nor "file" was found */
905 #ifdef  CHECK_FILE_ACCESS
906
907                         if (bp->bp_file[0]) {
908                                 /*
909                                  * Client wanted specific file
910                                  * and we didn't have it.
911                                  */
912                                 report(LOG_NOTICE,
913                                            "requested file not found: \"%s\"", clntpath);
914                                 return;
915                         }
916                         /*
917                          * Client didn't ask for a specific file and we couldn't
918                          * access the default file, so just zero-out the bootfile
919                          * field in the packet and continue processing the reply.
920                          */
921                         bzero(bp->bp_file, sizeof(bp->bp_file));
922                         goto null_file_name;
923
924 #else   /* CHECK_FILE_ACCESS */
925
926                         /* Complain only if boot file size was needed. */
927                         if (hp->flags.bootsize_auto) {
928                                 report(LOG_ERR, "can not determine size of file \"%s\"",
929                                            clntpath);
930                         }
931
932 #endif  /* CHECK_FILE_ACCESS */
933                 }
934         }
935         strncpy(bp->bp_file, clntpath, BP_FILE_LEN);
936         if (debug > 2)
937                 report(LOG_INFO, "bootfile=\"%s\"", clntpath);
938
939 #ifdef  CHECK_FILE_ACCESS
940 null_file_name:
941 #endif  /* CHECK_FILE_ACCESS */
942
943 \f
944         /*
945          * Handle vendor options based on magic number.
946          */
947
948         if (debug > 1) {
949                 report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
950                            (int) ((bp->bp_vend)[0]),
951                            (int) ((bp->bp_vend)[1]),
952                            (int) ((bp->bp_vend)[2]),
953                            (int) ((bp->bp_vend)[3]));
954         }
955         /*
956          * If this host isn't set for automatic vendor info then copy the
957          * specific cookie into the bootp packet, thus forcing a certain
958          * reply format.  Only force reply format if user specified it.
959          */
960         if (hp->flags.vm_cookie) {
961                 /* Slam in the user specified magic number. */
962                 bcopy(hp->vm_cookie, bp->bp_vend, 4);
963         }
964         /*
965          * Figure out the format for the vendor-specific info.
966          * Note that bp->bp_vend may have been set above.
967          */
968         if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
969                 /* RFC1048 conformant bootp client */
970                 dovend_rfc1048(bp, hp, bootsize);
971                 if (debug > 1) {
972                         report(LOG_INFO, "sending reply (with RFC1048 options)");
973                 }
974         }
975 #ifdef VEND_CMU
976         else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
977                 dovend_cmu(bp, hp);
978                 if (debug > 1) {
979                         report(LOG_INFO, "sending reply (with CMU options)");
980                 }
981         }
982 #endif
983         else {
984                 if (debug > 1) {
985                         report(LOG_INFO, "sending reply (with no options)");
986                 }
987         }
988
989         dest = (hp->flags.reply_addr) ?
990                 hp->reply_addr.s_addr : 0L;
991
992         /* not forwarded */
993         sendreply(0, dest);
994 }
995
996
997 /*
998  * Process BOOTREPLY packet.
999  */
1000 PRIVATE void
1001 handle_reply()
1002 {
1003         if (debug) {
1004                 report(LOG_INFO, "processing boot reply");
1005         }
1006         /* forwarded, no destination override */
1007         sendreply(1, 0);
1008 }
1009
1010
1011 /*
1012  * Send a reply packet to the client.  'forward' flag is set if we are
1013  * not the originator of this reply packet.
1014  */
1015 PRIVATE void
1016 sendreply(forward, dst_override)
1017         int forward;
1018         int32 dst_override;
1019 {
1020         struct bootp *bp = (struct bootp *) pktbuf;
1021         struct in_addr dst;
1022         u_short port = bootpc_port;
1023         unsigned char *ha;
1024         int len, haf;
1025
1026         /*
1027          * XXX - Should honor bp_flags "broadcast" bit here.
1028          * Temporary workaround: use the :ra=ADDR: option to
1029          * set the reply address to the broadcast address.
1030          */
1031
1032         /*
1033          * If the destination address was specified explicitly
1034          * (i.e. the broadcast address for HP compatibility)
1035          * then send the response to that address.  Otherwise,
1036          * act in accordance with RFC951:
1037          *   If the client IP address is specified, use that
1038          * else if gateway IP address is specified, use that
1039          * else make a temporary arp cache entry for the client's
1040          * NEW IP/hardware address and use that.
1041          */
1042         if (dst_override) {
1043                 dst.s_addr = dst_override;
1044                 if (debug > 1) {
1045                         report(LOG_INFO, "reply address override: %s",
1046                                    inet_ntoa(dst));
1047                 }
1048         } else if (bp->bp_ciaddr.s_addr) {
1049                 dst = bp->bp_ciaddr;
1050         } else if (bp->bp_giaddr.s_addr && forward == 0) {
1051                 dst = bp->bp_giaddr;
1052                 port = bootps_port;
1053                 if (debug > 1) {
1054                         report(LOG_INFO, "sending reply to gateway %s",
1055                                    inet_ntoa(dst));
1056                 }
1057         } else {
1058                 dst = bp->bp_yiaddr;
1059                 ha = bp->bp_chaddr;
1060                 len = bp->bp_hlen;
1061                 if (len > MAXHADDRLEN)
1062                         len = MAXHADDRLEN;
1063                 haf = (int) bp->bp_htype;
1064                 if (haf == 0)
1065                         haf = HTYPE_ETHERNET;
1066
1067                 if (arpmod) {
1068                         if (debug > 1)
1069                                 report(LOG_INFO, "setarp %s - %s",
1070                                            inet_ntoa(dst), haddrtoa(ha, len));
1071                         setarp(s, &dst, haf, ha, len);
1072                 }
1073         }
1074
1075         if ((forward == 0) &&
1076                 (bp->bp_siaddr.s_addr == 0))
1077         {
1078                 struct ifreq *ifr;
1079                 struct in_addr siaddr;
1080                 /*
1081                  * If we are originating this reply, we
1082                  * need to find our own interface address to
1083                  * put in the bp_siaddr field of the reply.
1084                  * If this server is multi-homed, pick the
1085                  * 'best' interface (the one on the same net
1086                  * as the client).  Of course, the client may
1087                  * be on the other side of a BOOTP gateway...
1088                  */
1089                 ifr = getif(s, &dst);
1090                 if (ifr) {
1091                         struct sockaddr_in *sip;
1092                         sip = (struct sockaddr_in *) &(ifr->ifr_addr);
1093                         siaddr = sip->sin_addr;
1094                 } else {
1095                         /* Just use my "official" IP address. */
1096                         siaddr = my_ip_addr;
1097                 }
1098
1099                 /* XXX - No need to set bp_giaddr here. */
1100
1101                 /* Finally, set the server address field. */
1102                 bp->bp_siaddr = siaddr;
1103         }
1104         /* Set up socket address for send. */
1105         send_addr.sin_family = AF_INET;
1106         send_addr.sin_port = htons(port);
1107         send_addr.sin_addr = dst;
1108
1109         /* Send reply with same size packet as request used. */
1110         if (sendto(s, pktbuf, pktlen, 0,
1111                            (struct sockaddr *) &send_addr,
1112                            sizeof(send_addr)) < 0)
1113         {
1114                 report(LOG_ERR, "sendto: %s", get_network_errmsg());
1115         }
1116 } /* sendreply */
1117 \f
1118
1119 /* nmatch() - now in getif.c */
1120 /* setarp() - now in hwaddr.c */
1121
1122
1123 /*
1124  * This call checks read access to a file.  It returns 0 if the file given
1125  * by "path" exists and is publicly readable.  A value of -1 is returned if
1126  * access is not permitted or an error occurs.  Successful calls also
1127  * return the file size in bytes using the long pointer "filesize".
1128  *
1129  * The read permission bit for "other" users is checked.  This bit must be
1130  * set for tftpd(8) to allow clients to read the file.
1131  */
1132
1133 PRIVATE int
1134 chk_access(path, filesize)
1135         char *path;
1136         int32 *filesize;
1137 {
1138         struct stat st;
1139
1140         if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
1141                 *filesize = (int32) st.st_size;
1142                 return 0;
1143         } else {
1144                 return -1;
1145         }
1146 }
1147 \f
1148
1149 /*
1150  * Now in dumptab.c :
1151  *      dumptab()
1152  *      dump_host()
1153  *      list_ipaddresses()
1154  */
1155
1156 #ifdef VEND_CMU
1157
1158 /*
1159  * Insert the CMU "vendor" data for the host pointed to by "hp" into the
1160  * bootp packet pointed to by "bp".
1161  */
1162
1163 PRIVATE void
1164 dovend_cmu(bp, hp)
1165         struct bootp *bp;
1166         struct host *hp;
1167 {
1168         struct cmu_vend *vendp;
1169         struct in_addr_list *taddr;
1170
1171         /*
1172          * Initialize the entire vendor field to zeroes.
1173          */
1174         bzero(bp->bp_vend, sizeof(bp->bp_vend));
1175
1176         /*
1177          * Fill in vendor information. Subnet mask, default gateway,
1178          * domain name server, ien name server, time server
1179          */
1180         vendp = (struct cmu_vend *) bp->bp_vend;
1181         strcpy(vendp->v_magic, (char *)vm_cmu);
1182         if (hp->flags.subnet_mask) {
1183                 (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
1184                 (vendp->v_flags) |= VF_SMASK;
1185                 if (hp->flags.gateway) {
1186                         (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
1187                 }
1188         }
1189         if (hp->flags.domain_server) {
1190                 taddr = hp->domain_server;
1191                 if (taddr->addrcount > 0) {
1192                         (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
1193                         if (taddr->addrcount > 1) {
1194                                 (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
1195                         }
1196                 }
1197         }
1198         if (hp->flags.name_server) {
1199                 taddr = hp->name_server;
1200                 if (taddr->addrcount > 0) {
1201                         (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
1202                         if (taddr->addrcount > 1) {
1203                                 (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
1204                         }
1205                 }
1206         }
1207         if (hp->flags.time_server) {
1208                 taddr = hp->time_server;
1209                 if (taddr->addrcount > 0) {
1210                         (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
1211                         if (taddr->addrcount > 1) {
1212                                 (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
1213                         }
1214                 }
1215         }
1216         /* Log message now done by caller. */
1217 } /* dovend_cmu */
1218
1219 #endif /* VEND_CMU */
1220 \f
1221
1222
1223 /*
1224  * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
1225  * bootp packet pointed to by "bp".
1226  */
1227 #define NEED(LEN, MSG) do \
1228         if (bytesleft < (LEN)) { \
1229                 report(LOG_NOTICE, noroom, \
1230                            hp->hostname->string, MSG); \
1231                 return; \
1232         } while (0)
1233 PRIVATE void
1234 dovend_rfc1048(bp, hp, bootsize)
1235         struct bootp *bp;
1236         struct host *hp;
1237         int32 bootsize;
1238 {
1239         int bytesleft, len;
1240         byte *vp;
1241
1242         static const char noroom[] = "%s: No room for \"%s\" option";
1243
1244         vp = bp->bp_vend;
1245
1246         if (hp->flags.msg_size) {
1247                 pktlen = hp->msg_size;
1248         } else {
1249                 /*
1250                  * If the request was longer than the official length, build
1251                  * a response of that same length where the additional length
1252                  * is assumed to be part of the bp_vend (options) area.
1253                  */
1254                 if (pktlen > sizeof(*bp)) {
1255                         if (debug > 1)
1256                                 report(LOG_INFO, "request message length=%d", pktlen);
1257                 }
1258                 /*
1259                  * Check whether the request contains the option:
1260                  * Maximum DHCP Message Size (RFC1533 sec. 9.8)
1261                  * and if so, override the response length with its value.
1262                  * This request must lie within the first BP_VEND_LEN
1263                  * bytes of the option space.
1264                  */
1265                 {
1266                         byte *p, *ep;
1267                         byte tag, len;
1268                         short msgsz = 0;
1269
1270                         p = vp + 4;
1271                         ep = p + BP_VEND_LEN - 4;
1272                         while (p < ep) {
1273                                 tag = *p++;
1274                                 /* Check for tags with no data first. */
1275                                 if (tag == TAG_PAD)
1276                                         continue;
1277                                 if (tag == TAG_END)
1278                                         break;
1279                                 /* Now scan the length byte. */
1280                                 len = *p++;
1281                                 switch (tag) {
1282                                 case TAG_MAX_MSGSZ:
1283                                         if (len == 2) {
1284                                                 bcopy(p, (char*)&msgsz, 2);
1285                                                 msgsz = ntohs(msgsz);
1286                                         }
1287                                         break;
1288                                 case TAG_SUBNET_MASK:
1289                                         /* XXX - Should preserve this if given... */
1290                                         break;
1291                                 } /* swtich */
1292                                 p += len;
1293                         }
1294
1295                         if (msgsz > sizeof(*bp) + BP_MSG_OVERHEAD) {
1296                                 if (debug > 1)
1297                                         report(LOG_INFO, "request has DHCP msglen=%d", msgsz);
1298                                 pktlen = msgsz - BP_MSG_OVERHEAD;
1299                         }
1300                 }
1301         }
1302
1303         if (pktlen < sizeof(*bp)) {
1304                 report(LOG_ERR, "invalid response length=%d", pktlen);
1305                 pktlen = sizeof(*bp);
1306         }
1307         bytesleft = ((byte*)bp + pktlen) - vp;
1308         if (pktlen > sizeof(*bp)) {
1309                 if (debug > 1)
1310                         report(LOG_INFO, "extended reply, length=%d, options=%d",
1311                                    pktlen, bytesleft);
1312         }
1313
1314         /* Copy in the magic cookie */
1315         bcopy(vm_rfc1048, vp, 4);
1316         vp += 4;
1317         bytesleft -= 4;
1318
1319         if (hp->flags.subnet_mask) {
1320                 /* always enough room here. */
1321                 *vp++ = TAG_SUBNET_MASK;/* -1 byte  */
1322                 *vp++ = 4;                              /* -1 byte  */
1323                 insert_u_long(hp->subnet_mask.s_addr, &vp);     /* -4 bytes */
1324                 bytesleft -= 6;                 /* Fix real count */
1325                 if (hp->flags.gateway) {
1326                         (void) insert_ip(TAG_GATEWAY,
1327                                                          hp->gateway,
1328                                                          &vp, &bytesleft);
1329                 }
1330         }
1331         if (hp->flags.bootsize) {
1332                 /* always enough room here */
1333                 bootsize = (hp->flags.bootsize_auto) ?
1334                         ((bootsize + 511) / 512) : (hp->bootsize);      /* Round up */
1335                 *vp++ = TAG_BOOT_SIZE;
1336                 *vp++ = 2;
1337                 *vp++ = (byte) ((bootsize >> 8) & 0xFF);
1338                 *vp++ = (byte) (bootsize & 0xFF);
1339                 bytesleft -= 4;                 /* Tag, length, and 16 bit blocksize */
1340         }
1341         /*
1342          * This one is special: Remaining options go in the ext file.
1343          * Only the subnet_mask, bootsize, and gateway should precede.
1344          */
1345         if (hp->flags.exten_file) {
1346                 /*
1347                  * Check for room for exten_file.  Add 3 to account for
1348                  * TAG_EXTEN_FILE, length, and TAG_END.
1349                  */
1350                 len = strlen(hp->exten_file->string);
1351                 NEED((len + 3), "ef");
1352                 *vp++ = TAG_EXTEN_FILE;
1353                 *vp++ = (byte) (len & 0xFF);
1354                 bcopy(hp->exten_file->string, vp, len);
1355                 vp += len;
1356                 *vp++ = TAG_END;
1357                 bytesleft -= len + 3;
1358                 return;                                 /* no more options here. */
1359         }
1360         /*
1361          * The remaining options are inserted by the following
1362          * function (which is shared with bootpef.c).
1363          * Keep back one byte for the TAG_END.
1364          */
1365         len = dovend_rfc1497(hp, vp, bytesleft - 1);
1366         vp += len;
1367         bytesleft -= len;
1368
1369         /* There should be at least one byte left. */
1370         NEED(1, "(end)");
1371         *vp++ = TAG_END;
1372         bytesleft--;
1373
1374         /* Log message done by caller. */
1375         if (bytesleft > 0) {
1376                 /*
1377                  * Zero out any remaining part of the vendor area.
1378                  */
1379                 bzero(vp, bytesleft);
1380         }
1381 } /* dovend_rfc1048 */
1382 #undef  NEED
1383 \f
1384
1385 /*
1386  * Now in readfile.c:
1387  *      hwlookcmp()
1388  *      iplookcmp()
1389  */
1390
1391 /* haddrtoa() - now in hwaddr.c */
1392 /*
1393  * Now in dovend.c:
1394  * insert_ip()
1395  * insert_generic()
1396  * insert_u_long()
1397  */
1398
1399 /* get_errmsg() - now in report.c */
1400
1401 /*
1402  * Local Variables:
1403  * tab-width: 4
1404  * c-indent-level: 4
1405  * c-argdecl-indent: 4
1406  * c-continued-statement-offset: 4
1407  * c-continued-brace-offset: -4
1408  * c-label-offset: -4
1409  * c-brace-offset: 0
1410  * End:
1411  */