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