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 #include <sys/cdefs.h>
24 #ifndef lint
25 __RCSID("$NetBSD: readfile.c,v 1.21 2019/02/03 03:19:30 mrg Exp $");
26 #endif
27 
28 
29 /*
30  * bootpd configuration file reading code.
31  *
32  * The routines in this file deal with reading, interpreting, and storing
33  * the information found in the bootpd configuration file (usually
34  * /etc/bootptab).
35  */
36 
37 
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/file.h>
41 #include <sys/time.h>
42 #include <netinet/in.h>
43 
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <time.h>
50 #include <ctype.h>
51 #include <assert.h>
52 #include <syslog.h>
53 
54 #include "bootp.h"
55 #include "hash.h"
56 #include "hwaddr.h"
57 #include "lookup.h"
58 #include "readfile.h"
59 #include "report.h"
60 #include "tzone.h"
61 #include "bootpd.h"
62 
63 #define HASHTABLESIZE                   257       /* Hash table size (prime) */
64 
65 /* Non-standard hardware address type (see bootp.h) */
66 #define HTYPE_DIRECT          0
67 
68 /* Error codes returned by eval_symbol: */
69 #define SUCCESS                           0
70 #define E_END_OF_ENTRY                  (-1)
71 #define E_SYNTAX_ERROR                  (-2)
72 #define E_UNKNOWN_SYMBOL      (-3)
73 #define E_BAD_IPADDR                    (-4)
74 #define E_BAD_HWADDR                    (-5)
75 #define E_BAD_LONGWORD                  (-6)
76 #define E_BAD_HWATYPE                   (-7)
77 #define E_BAD_PATHNAME                  (-8)
78 #define E_BAD_VALUE                     (-9)
79 
80 /* Tag idendities. */
81 #define SYM_NULL                0
82 #define SYM_BOOTFILE                      1
83 #define SYM_COOKIE_SERVER       2
84 #define SYM_DOMAIN_SERVER       3
85 #define SYM_GATEWAY             4
86 #define SYM_HWADDR              5
87 #define SYM_HOMEDIR             6
88 #define SYM_HTYPE               7
89 #define SYM_IMPRESS_SERVER      8
90 #define SYM_IPADDR              9
91 #define SYM_LOG_SERVER                   10
92 #define SYM_LPR_SERVER                   11
93 #define SYM_NAME_SERVER                  12
94 #define SYM_RLP_SERVER                   13
95 #define SYM_SUBNET_MASK                  14
96 #define SYM_TIME_OFFSET                  15
97 #define SYM_TIME_SERVER                  16
98 #define SYM_VENDOR_MAGIC       17
99 #define SYM_SIMILAR_ENTRY      18
100 #define SYM_NAME_SWITCH                  19
101 #define SYM_BOOTSIZE                     20
102 #define SYM_BOOT_SERVER                  22
103 #define SYM_TFTPDIR            23
104 #define SYM_DUMP_FILE                    24
105 #define SYM_DOMAIN_NAME          25
106 #define SYM_SWAP_SERVER          26
107 #define SYM_ROOT_PATH            27
108 #define SYM_EXTEN_FILE           28
109 #define SYM_REPLY_ADDR           29
110 #define SYM_NIS_DOMAIN           30     /* RFC 1533 */
111 #define SYM_NIS_SERVER           31     /* RFC 1533 */
112 #define SYM_NTP_SERVER           32     /* RFC 1533 */
113 #define SYM_EXEC_FILE                    33       /* YORK_EX_OPTION */
114 #define SYM_MSG_SIZE                     34
115 #define SYM_MIN_WAIT                     35
116 /* XXX - Add new tags here */
117 
118 #define OP_ADDITION             1       /* Operations on tags */
119 #define OP_DELETION             2
120 #define OP_BOOLEAN              3
121 
122 #define MAXINADDRS             16       /* Max size of an IP address list */
123 #define MAXBUFLEN             256       /* Max temp buffer space */
124 #define MAXENTRYLEN        2048         /* Max size of an entire entry */
125 
126 
127 
128 /*
129  * Structure used to map a configuration-file symbol (such as "ds") to a
130  * unique integer.
131  */
132 
133 struct symbolmap {
134           const char *symbol;
135           int symbolcode;
136 };
137 
138 
139 struct htypename {
140           const char *name;
141           byte htype;
142 };
143 
144 
145 PRIVATE int nhosts;                               /* Number of hosts (/w hw or IP address) */
146 PRIVATE int nentries;                             /* Total number of entries */
147 PRIVATE int32 modtime = 0;              /* Last modification time of bootptab */
148 PRIVATE char *current_hostname;         /* Name of the current entry. */
149 PRIVATE char current_tagname[8];
150 
151 /*
152  * List of symbolic names used in the bootptab file.  The order and actual
153  * values of the symbol codes (SYM_. . .) are unimportant, but they must
154  * all be unique.
155  */
156 
157 PRIVATE struct symbolmap symbol_list[] = {
158           {"bf", SYM_BOOTFILE},
159           {"bs", SYM_BOOTSIZE},
160           {"cs", SYM_COOKIE_SERVER},
161           {"df", SYM_DUMP_FILE},
162           {"dn", SYM_DOMAIN_NAME},
163           {"ds", SYM_DOMAIN_SERVER},
164           {"ef", SYM_EXTEN_FILE},
165           {"ex", SYM_EXEC_FILE},                  /* YORK_EX_OPTION */
166           {"gw", SYM_GATEWAY},
167           {"ha", SYM_HWADDR},
168           {"hd", SYM_HOMEDIR},
169           {"hn", SYM_NAME_SWITCH},
170           {"ht", SYM_HTYPE},
171           {"im", SYM_IMPRESS_SERVER},
172           {"ip", SYM_IPADDR},
173           {"lg", SYM_LOG_SERVER},
174           {"lp", SYM_LPR_SERVER},
175           {"ms", SYM_MSG_SIZE},
176           {"mw", SYM_MIN_WAIT},
177           {"ns", SYM_NAME_SERVER},
178           {"nt", SYM_NTP_SERVER},
179           {"ra", SYM_REPLY_ADDR},
180           {"rl", SYM_RLP_SERVER},
181           {"rp", SYM_ROOT_PATH},
182           {"sa", SYM_BOOT_SERVER},
183           {"sm", SYM_SUBNET_MASK},
184           {"sw", SYM_SWAP_SERVER},
185           {"tc", SYM_SIMILAR_ENTRY},
186           {"td", SYM_TFTPDIR},
187           {"to", SYM_TIME_OFFSET},
188           {"ts", SYM_TIME_SERVER},
189           {"vm", SYM_VENDOR_MAGIC},
190           {"yd", SYM_NIS_DOMAIN},
191           {"ys", SYM_NIS_SERVER},
192           /* XXX - Add new tags here */
193 };
194 
195 
196 /*
197  * List of symbolic names for hardware types.  Name translates into
198  * hardware type code listed with it.  Names must begin with a letter
199  * and must be all lowercase.  This is searched linearly, so put
200  * commonly-used entries near the beginning.
201  */
202 
203 PRIVATE struct htypename htnamemap[] = {
204           {"ethernet", HTYPE_ETHERNET},
205           {"ethernet3", HTYPE_EXP_ETHERNET},
206           {"ether", HTYPE_ETHERNET},
207           {"ether3", HTYPE_EXP_ETHERNET},
208           {"ieee802", HTYPE_IEEE802},
209           {"tr", HTYPE_IEEE802},
210           {"token-ring", HTYPE_IEEE802},
211           {"pronet", HTYPE_PRONET},
212           {"chaos", HTYPE_CHAOS},
213           {"arcnet", HTYPE_ARCNET},
214           {"ax.25", HTYPE_AX25},
215           {"direct", HTYPE_DIRECT},
216           {"serial", HTYPE_DIRECT},
217           {"slip", HTYPE_DIRECT},
218           {"ppp", HTYPE_DIRECT}
219 };
220 
221 
222 
223 /*
224  * Externals and forward declarations.
225  */
226 
227 boolean nmcmp(hash_datum *, hash_datum *);
228 
229 PRIVATE void
230           adjust(char **);
231 PRIVATE void
232           del_string(struct shared_string *);
233 PRIVATE void
234           del_bindata(struct shared_bindata *);
235 PRIVATE void
236           del_iplist(struct in_addr_list *);
237 PRIVATE void
238           eat_whitespace(char **);
239 PRIVATE int
240           eval_symbol(char **, struct host *);
241 PRIVATE void
242           fill_defaults(struct host *, char **);
243 PRIVATE void
244           free_host(hash_datum *);
245 PRIVATE struct in_addr_list *
246           get_addresses(char **);
247 PRIVATE struct shared_string *
248           get_shared_string(char **);
249 PRIVATE char *
250           get_string(char **, char *, u_int *);
251 PRIVATE u_int32
252           get_u_long(char **);
253 PRIVATE boolean
254           goodname(char *);
255 PRIVATE boolean
256           hwinscmp(hash_datum *, hash_datum *);
257 PRIVATE int
258           interp_byte(char **, byte *);
259 PRIVATE void
260           makelower(char *);
261 PRIVATE boolean
262         nullcmp(hash_datum *, hash_datum *);
263 PRIVATE int
264           process_entry(struct host *, char *);
265 PRIVATE int
266           process_generic(char **, struct shared_bindata **, u_int);
267 PRIVATE byte *
268           prs_haddr(char **, u_int);
269 PRIVATE int
270           prs_inetaddr(char **, u_int32 *);
271 PRIVATE void
272           read_entry(FILE *, char *, u_int *);
273 PRIVATE char *
274           smalloc(u_int);
275 
276 
277 
278 /*
279  * Vendor magic cookies for CMU and RFC1048
280  */
281 u_char vm_cmu[4] = VM_CMU;
282 u_char vm_rfc1048[4] = VM_RFC1048;
283 
284 /*
285  * Main hash tables
286  */
287 hash_tbl *hwhashtable;
288 hash_tbl *iphashtable;
289 hash_tbl *nmhashtable;
290 
291 /*
292  * Allocate hash tables for hardware address, ip address, and hostname
293  * (shared by bootpd and bootpef)
294  */
295 void
rdtab_init(void)296 rdtab_init(void)
297 {
298           hwhashtable = hash_Init(HASHTABLESIZE);
299           iphashtable = hash_Init(HASHTABLESIZE);
300           nmhashtable = hash_Init(HASHTABLESIZE);
301           if (!(hwhashtable && iphashtable && nmhashtable)) {
302                     report(LOG_ERR, "Unable to allocate hash tables.");
303                     exit(1);
304           }
305 }
306 
307 
308 /*
309  * Read bootptab database file.  Avoid rereading the file if the
310  * write date hasn't changed since the last time we read it.
311  */
312 
313 void
readtab(int force)314 readtab(int force)
315 {
316           struct host *hp;
317           FILE *fp;
318           struct stat st;
319           unsigned hashcode, buflen;
320           static char buffer[MAXENTRYLEN];
321 
322           /*
323            * Check the last modification time.
324            */
325           if (stat(bootptab, &st) < 0) {
326                     report(LOG_ERR, "stat on \"%s\": %s",
327                                  bootptab, get_errmsg());
328                     return;
329           }
330 #ifdef DEBUG
331           if (debug > 3) {
332                     char timestr[28];
333                     strlcpy(timestr, ctime(&(st.st_mtime)), sizeof(timestr));
334                     /* zap the newline */
335                     timestr[24] = '\0';
336                     report(LOG_INFO, "bootptab mtime: %s",
337                                  timestr);
338           }
339 #endif
340           if ((force == 0) &&
341                     (st.st_mtime == modtime) &&
342                     st.st_nlink) {
343                     /*
344                      * hasn't been modified or deleted yet.
345                      */
346                     return;
347           }
348           if (debug)
349                     report(LOG_INFO, "reading %s\"%s\"",
350                                  (modtime != 0L) ? "new " : "",
351                                  bootptab);
352 
353           /*
354            * Open bootptab file.
355            */
356           if ((fp = fopen(bootptab, "r")) == NULL) {
357                     report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
358                     return;
359           }
360           /*
361            * Record file modification time.
362            */
363           if (fstat(fileno(fp), &st) < 0) {
364                     report(LOG_ERR, "fstat: %s", get_errmsg());
365                     fclose(fp);
366                     return;
367           }
368           modtime = st.st_mtime;
369 
370           /*
371            * Entirely erase all hash tables.
372            */
373           hash_Reset(hwhashtable, free_host);
374           hash_Reset(iphashtable, free_host);
375           hash_Reset(nmhashtable, free_host);
376 
377           nhosts = 0;
378           nentries = 0;
379           while (TRUE) {
380                     buflen = sizeof(buffer);
381                     read_entry(fp, buffer, &buflen);
382                     if (buflen == 0) {            /* More entries? */
383                               break;
384                     }
385                     hp = (struct host *) smalloc(sizeof(struct host));
386                     bzero((char *) hp, sizeof(*hp));
387                     /* the link count it zero */
388 
389                     /*
390                      * Get individual info
391                      */
392                     if (process_entry(hp, buffer) < 0) {
393                               hp->linkcount = 1;
394                               free_host((hash_datum *) hp);
395                               continue;
396                     }
397                     /*
398                      * If this is not a dummy entry, and the IP or HW
399                      * address is not yet set, try to get them here.
400                      * Dummy entries have . as first char of name.
401                      */
402                     if (goodname(hp->hostname->string)) {
403                               char *hn = hp->hostname->string;
404                               u_int32 value;
405                               if (hp->flags.iaddr == 0) {
406                                         if (lookup_ipa(hn, &value)) {
407                                                   report(LOG_ERR, "can not get IP addr for %s", hn);
408                                                   report(LOG_ERR, "(dummy names should start with '.')");
409                                         } else {
410                                                   hp->iaddr.s_addr = value;
411                                                   hp->flags.iaddr = TRUE;
412                                         }
413                               }
414                               /* Set default subnet mask. */
415                               if (hp->flags.subnet_mask == 0) {
416                                         if (lookup_netmask(hp->iaddr.s_addr, &value)) {
417                                                   report(LOG_ERR, "can not get netmask for %s", hn);
418                                         } else {
419                                                   hp->subnet_mask.s_addr = value;
420                                                   hp->flags.subnet_mask = TRUE;
421                                         }
422                               }
423                     }
424                     if (hp->flags.iaddr) {
425                               nhosts++;
426                     }
427                     /* Register by HW addr if known. */
428                     if (hp->flags.htype && hp->flags.haddr) {
429                               /* We will either insert it or free it. */
430                               hp->linkcount++;
431                               hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
432                               if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
433                                         report(LOG_NOTICE, "duplicate %s address: %s",
434                                                      netname(hp->htype),
435                                                      haddrtoa(hp->haddr, haddrlength(hp->htype)));
436                                         free_host((hash_datum *) hp);
437                                         continue;
438                               }
439                     }
440                     /* Register by IP addr if known. */
441                     if (hp->flags.iaddr) {
442                               hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
443                               if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
444                                         report(LOG_ERR,
445                                                      "hash_Insert() failed on IP address insertion");
446                               } else {
447                                         /* Just inserted the host struct in a new hash list. */
448                                         hp->linkcount++;
449                               }
450                     }
451                     /* Register by Name (always known) */
452                     hashcode = hash_HashFunction((u_char *) hp->hostname->string,
453                                                                                            strlen(hp->hostname->string));
454                     if (hash_Insert(nmhashtable, hashcode, nullcmp,
455                                                             hp->hostname->string, hp) < 0) {
456                               report(LOG_ERR,
457                                          "hash_Insert() failed on insertion of hostname: \"%s\"",
458                                            hp->hostname->string);
459                     } else {
460                               /* Just inserted the host struct in a new hash list. */
461                               hp->linkcount++;
462                     }
463 
464                     nentries++;
465           }
466 
467           fclose(fp);
468           if (debug)
469                     report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
470                                  nentries, nhosts, bootptab);
471           return;
472 }
473 
474 
475 
476 /*
477  * Read an entire host entry from the file pointed to by "fp" and insert it
478  * into the memory pointed to by "buffer".  Leading whitespace and comments
479  * starting with "#" are ignored (removed).  Backslashes (\) always quote
480  * the next character except that newlines preceded by a backslash cause
481  * line-continuation onto the next line.  The entry is terminated by a
482  * newline character which is not preceded by a backslash.  Sequences
483  * surrounded by double quotes are taken literally (including newlines, but
484  * not backslashes).
485  *
486  * The "bufsiz" parameter points to an unsigned int which specifies the
487  * maximum permitted buffer size.  Upon return, this value will be replaced
488  * with the actual length of the entry (not including the null terminator).
489  *
490  * This code is a little scary. . . .  I don't like using gotos in C
491  * either, but I first wrote this as an FSM diagram and gotos seemed like
492  * the easiest way to implement it.  Maybe later I'll clean it up.
493  */
494 
495 PRIVATE void
read_entry(FILE * fp,char * buffer,unsigned int * bufsiz)496 read_entry(FILE *fp, char *buffer, unsigned int *bufsiz)
497 {
498           int c;
499           unsigned int length;
500 
501           length = 0;
502 
503           /*
504            * Eat whitespace, blank lines, and comment lines.
505            */
506   top:
507           c = fgetc(fp);
508           if (c < 0) {
509                     goto done;                                        /* Exit if end-of-file */
510           }
511           if (isspace(c)) {
512                     goto top;                               /* Skip over whitespace */
513           }
514           if (c == '#') {
515                     while (TRUE) {                          /* Eat comments after # */
516                               c = fgetc(fp);
517                               if (c < 0) {
518                                         goto done;                    /* Exit if end-of-file */
519                               }
520                               if (c == '\n') {
521                                         goto top;           /* Try to read the next line */
522                               }
523                     }
524           }
525           ungetc(c, fp);                                    /* Other character, push it back to reprocess it */
526 
527 
528           /*
529            * Now we're actually reading a data entry.  Get each character and
530            * assemble it into the data buffer, processing special characters like
531            * double quotes (") and backslashes (\).
532            */
533 
534   mainloop:
535           c = fgetc(fp);
536           switch (c) {
537           case EOF:
538           case '\n':
539                     goto done;                                        /* Exit on EOF or newline */
540           case '\\':
541                     c = fgetc(fp);                          /* Backslash, read a new character */
542                     if (c < 0) {
543                               goto done;                              /* Exit on EOF */
544                     }
545                     *buffer++ = c;                          /* Store the literal character */
546                     length++;
547                     if (length < *bufsiz - 1) {
548                               goto mainloop;
549                     } else {
550                               goto done;
551                     }
552           case '"':
553                     *buffer++ = '"';              /* Store double-quote */
554                     length++;
555                     if (length >= *bufsiz - 1) {
556                               goto done;
557                     }
558                     while (TRUE) {                          /* Special quote processing loop */
559                               c = fgetc(fp);
560                               switch (c) {
561                               case EOF:
562                                         goto done;                    /* Exit on EOF . . . */
563                               case '"':
564                                         *buffer++ = '"';/* Store matching quote */
565                                         length++;
566                                         if (length < *bufsiz - 1) {
567                                                   goto mainloop;      /* And continue main loop */
568                                         } else {
569                                                   goto done;
570                                         }
571                               case '\\':
572                                         if ((c = fgetc(fp)) < 0) {    /* Backslash */
573                                                   goto done;          /* EOF. . . .*/
574                                         }                                       /* else fall through */
575                               default:
576                                         *buffer++ = c;      /* Other character, store it */
577                                         length++;
578                                         if (length >= *bufsiz - 1) {
579                                                   goto done;
580                                         }
581                               }
582                     }
583           case ':':
584                     *buffer++ = c;                          /* Store colons */
585                     length++;
586                     if (length >= *bufsiz - 1) {
587                               goto done;
588                     }
589                     do {                                              /* But remove whitespace after them */
590                               c = fgetc(fp);
591                               if ((c < 0) || (c == '\n')) {
592                                         goto done;
593                               }
594                     } while (isspace(c));         /* Skip whitespace */
595 
596                     if (c == '\\') {              /* Backslash quotes next character */
597                               c = fgetc(fp);
598                               if (c < 0) {
599                                         goto done;
600                               }
601                               if (c == '\n') {
602                                         goto top;           /* Backslash-newline continuation */
603                               }
604                     }
605                     /* fall through if "other" character */
606                     /* FALLTHROUGH */
607           default:
608                     *buffer++ = c;                          /* Store other characters */
609                     length++;
610                     if (length >= *bufsiz - 1) {
611                               goto done;
612                     }
613           }
614           goto mainloop;                                    /* Keep going */
615 
616   done:
617           *buffer = '\0';                                   /* Terminate string */
618           *bufsiz = length;                       /* Tell the caller its length */
619 }
620 
621 
622 
623 /*
624  * Parse out all the various tags and parameters in the host entry pointed
625  * to by "src".  Stuff all the data into the appropriate fields of the
626  * host structure pointed to by "host".  If there is any problem with the
627  * entry, an error message is reported via report(), no further processing
628  * is done, and -1 is returned.  Successful calls return 0.
629  *
630  * (Some errors probably shouldn't be so completely fatal. . . .)
631  */
632 
633 PRIVATE int
process_entry(struct host * host,char * src)634 process_entry(struct host *host, char *src)
635 {
636           int retval;
637           const char *msg;
638 
639           if (!host || *src == '\0') {
640                     return -1;
641           }
642           host->hostname = get_shared_string(&src);
643 #if 0
644           /* Be more liberal for the benefit of dummy tag names. */
645           if (!goodname(host->hostname->string)) {
646                     report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
647                     del_string(host->hostname);
648                     return -1;
649           }
650 #endif
651           current_hostname = host->hostname->string;
652           adjust(&src);
653           while (TRUE) {
654                     retval = eval_symbol(&src, host);
655                     if (retval == SUCCESS) {
656                               adjust(&src);
657                               continue;
658                     }
659                     if (retval == E_END_OF_ENTRY) {
660                               /* The default subnet mask is set in readtab() */
661                               return 0;
662                     }
663                     /* Some kind of error. */
664                     switch (retval) {
665                     case E_SYNTAX_ERROR:
666                               msg = "bad syntax";
667                               break;
668                     case E_UNKNOWN_SYMBOL:
669                               msg = "unknown symbol";
670                               break;
671                     case E_BAD_IPADDR:
672                               msg = "bad INET address";
673                               break;
674                     case E_BAD_HWADDR:
675                               msg = "bad hardware address";
676                               break;
677                     case E_BAD_LONGWORD:
678                               msg = "bad longword value";
679                               break;
680                     case E_BAD_HWATYPE:
681                               msg = "bad HW address type";
682                               break;
683                     case E_BAD_PATHNAME:
684                               msg = "bad pathname (need leading '/')";
685                               break;
686                     case E_BAD_VALUE:
687                               msg = "bad value";
688                               break;
689                     default:
690                               msg = "unknown error";
691                               break;
692                     }                                                           /* switch */
693                     report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
694                                  current_hostname, current_tagname, msg);
695                     return -1;
696           }
697 }
698 
699 
700 /*
701  * Macros for use in the function below:
702  */
703 
704 /* Parse one INET address stored directly in MEMBER. */
705 #define PARSE_IA1(MEMBER) do \
706 { \
707           if (optype == OP_BOOLEAN) \
708                     return E_SYNTAX_ERROR; \
709           hp->flags.MEMBER = FALSE; \
710           if (optype == OP_ADDITION) { \
711                     if (prs_inetaddr(symbol, &value) < 0) \
712                               return E_BAD_IPADDR; \
713                     hp->MEMBER.s_addr = value; \
714                     hp->flags.MEMBER = TRUE; \
715           } \
716 } while (0)
717 
718 /* Parse a list of INET addresses pointed to by MEMBER */
719 #define PARSE_IAL(MEMBER) do \
720 { \
721           if (optype == OP_BOOLEAN) \
722                     return E_SYNTAX_ERROR; \
723           if (hp->flags.MEMBER) { \
724                     hp->flags.MEMBER = FALSE; \
725                     assert(hp->MEMBER); \
726                     del_iplist(hp->MEMBER); \
727                     hp->MEMBER = NULL; \
728           } \
729           if (optype == OP_ADDITION) { \
730                     hp->MEMBER = get_addresses(symbol); \
731                     if (hp->MEMBER == NULL) \
732                               return E_SYNTAX_ERROR; \
733                     hp->flags.MEMBER = TRUE; \
734           } \
735 } while (0)
736 
737 /* Parse a shared string pointed to by MEMBER */
738 #define PARSE_STR(MEMBER) do \
739 { \
740           if (optype == OP_BOOLEAN) \
741                     return E_SYNTAX_ERROR; \
742           if (hp->flags.MEMBER) { \
743                     hp->flags.MEMBER = FALSE; \
744                     assert(hp->MEMBER); \
745                     del_string(hp->MEMBER); \
746                     hp->MEMBER = NULL; \
747           } \
748           if (optype == OP_ADDITION) { \
749                     hp->MEMBER = get_shared_string(symbol); \
750                     if (hp->MEMBER == NULL) \
751                               return E_SYNTAX_ERROR; \
752                     hp->flags.MEMBER = TRUE; \
753           } \
754 } while (0)
755 
756 /* Parse an integer value for MEMBER */
757 #define PARSE_INT(MEMBER) do \
758 { \
759           if (optype == OP_BOOLEAN) \
760                     return E_SYNTAX_ERROR; \
761           hp->flags.MEMBER = FALSE; \
762           if (optype == OP_ADDITION) { \
763                     value = get_u_long(symbol); \
764                     hp->MEMBER = value; \
765                     hp->flags.MEMBER = TRUE; \
766           } \
767 } while (0)
768 
769 /*
770  * Evaluate the two-character tag symbol pointed to by "symbol" and place
771  * the data in the structure pointed to by "hp".  The pointer pointed to
772  * by "symbol" is updated to point past the source string (but may not
773  * point to the next tag entry).
774  *
775  * Obviously, this need a few more comments. . . .
776  */
777 PRIVATE int
eval_symbol(char ** symbol,struct host * hp)778 eval_symbol(char **symbol, struct host *hp)
779 {
780           char tmpstr[MAXSTRINGLEN];
781           byte *tmphaddr;
782           struct symbolmap *symbolptr;
783           u_int32 value;
784           int32 ltimeoff;
785           int i, numsymbols;
786           unsigned len;
787           int optype;                                                 /* Indicates boolean, addition, or deletion */
788 
789           eat_whitespace(symbol);
790 
791           /* Make sure this is set before returning. */
792           current_tagname[0] = (*symbol)[0];
793           current_tagname[1] = (*symbol)[1];
794           current_tagname[2] = 0;
795 
796           if ((*symbol)[0] == '\0') {
797                     return E_END_OF_ENTRY;
798           }
799           if ((*symbol)[0] == ':') {
800                     return SUCCESS;
801           }
802           if ((*symbol)[0] == 'T') {    /* generic symbol */
803                     (*symbol)++;
804                     value = get_u_long(symbol);
805                     snprintf(current_tagname, sizeof(current_tagname),
806                         "T%d", value);
807                     eat_whitespace(symbol);
808                     if ((*symbol)[0] != '=') {
809                               return E_SYNTAX_ERROR;
810                     }
811                     (*symbol)++;
812                     if (!(hp->generic)) {
813                               hp->generic = (struct shared_bindata *)
814                                         smalloc(sizeof(struct shared_bindata));
815                     }
816                     if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
817                               return E_SYNTAX_ERROR;
818                     hp->flags.generic = TRUE;
819                     return SUCCESS;
820           }
821           /*
822            * Determine the type of operation to be done on this symbol
823            */
824           switch ((*symbol)[2]) {
825           case '=':
826                     optype = OP_ADDITION;
827                     break;
828           case '@':
829                     optype = OP_DELETION;
830                     break;
831           case ':':
832           case '\0':
833                     optype = OP_BOOLEAN;
834                     break;
835           default:
836                     return E_SYNTAX_ERROR;
837           }
838 
839           symbolptr = symbol_list;
840           numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
841           for (i = 0; i < numsymbols; i++) {
842                     if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
843                               ((symbolptr->symbol)[1] == (*symbol)[1])) {
844                               break;
845                     }
846                     symbolptr++;
847           }
848           if (i >= numsymbols) {
849                     return E_UNKNOWN_SYMBOL;
850           }
851           /*
852            * Skip past the = or @ character (to point to the data) if this
853            * isn't a boolean operation.  For boolean operations, just skip
854            * over the two-character tag symbol (and nothing else. . . .).
855            */
856           (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
857 
858           eat_whitespace(symbol);
859 
860           /* The cases below are in order by symbolcode value. */
861           switch (symbolptr->symbolcode) {
862 
863           case SYM_BOOTFILE:
864                     PARSE_STR(bootfile);
865                     break;
866 
867           case SYM_COOKIE_SERVER:
868                     PARSE_IAL(cookie_server);
869                     break;
870 
871           case SYM_DOMAIN_SERVER:
872                     PARSE_IAL(domain_server);
873                     break;
874 
875           case SYM_GATEWAY:
876                     PARSE_IAL(gateway);
877                     break;
878 
879           case SYM_HWADDR:
880                     if (optype == OP_BOOLEAN)
881                               return E_SYNTAX_ERROR;
882                     hp->flags.haddr = FALSE;
883                     if (optype == OP_ADDITION) {
884                               /* Default the HW type to Ethernet */
885                               if (hp->flags.htype == 0) {
886                                         hp->flags.htype = TRUE;
887                                         hp->htype = HTYPE_ETHERNET;
888                               }
889                               tmphaddr = prs_haddr(symbol, hp->htype);
890                               if (!tmphaddr)
891                                         return E_BAD_HWADDR;
892                               bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
893                               hp->flags.haddr = TRUE;
894                     }
895                     break;
896 
897           case SYM_HOMEDIR:
898                     PARSE_STR(homedir);
899                     break;
900 
901           case SYM_HTYPE:
902                     if (optype == OP_BOOLEAN)
903                               return E_SYNTAX_ERROR;
904                     hp->flags.htype = FALSE;
905                     if (optype == OP_ADDITION) {
906                               value = 0L;                             /* Assume an illegal value */
907                               eat_whitespace(symbol);
908                               if (isdigit((unsigned char)**symbol)) {
909                                         value = get_u_long(symbol);
910                               } else {
911                                         len = sizeof(tmpstr);
912                                         (void) get_string(symbol, tmpstr, &len);
913                                         makelower(tmpstr);
914                                         numsymbols = sizeof(htnamemap) /
915                                                   sizeof(struct htypename);
916                                         for (i = 0; i < numsymbols; i++) {
917                                                   if (!strcmp(htnamemap[i].name, tmpstr)) {
918                                                             break;
919                                                   }
920                                         }
921                                         if (i < numsymbols) {
922                                                   value = htnamemap[i].htype;
923                                         }
924                               }
925                               if (value >= hwinfocnt) {
926                                         return E_BAD_HWATYPE;
927                               }
928                               hp->htype = (byte) (value & 0xFF);
929                               hp->flags.htype = TRUE;
930                     }
931                     break;
932 
933           case SYM_IMPRESS_SERVER:
934                     PARSE_IAL(impress_server);
935                     break;
936 
937           case SYM_IPADDR:
938                     PARSE_IA1(iaddr);
939                     break;
940 
941           case SYM_LOG_SERVER:
942                     PARSE_IAL(log_server);
943                     break;
944 
945           case SYM_LPR_SERVER:
946                     PARSE_IAL(lpr_server);
947                     break;
948 
949           case SYM_NAME_SERVER:
950                     PARSE_IAL(name_server);
951                     break;
952 
953           case SYM_RLP_SERVER:
954                     PARSE_IAL(rlp_server);
955                     break;
956 
957           case SYM_SUBNET_MASK:
958                     PARSE_IA1(subnet_mask);
959                     break;
960 
961           case SYM_TIME_OFFSET:
962                     if (optype == OP_BOOLEAN)
963                               return E_SYNTAX_ERROR;
964                     hp->flags.time_offset = FALSE;
965                     if (optype == OP_ADDITION) {
966                               len = sizeof(tmpstr);
967                               (void) get_string(symbol, tmpstr, &len);
968                               if (!strncmp(tmpstr, "auto", 4)) {
969                                         hp->time_offset = secondswest;
970                               } else {
971                                         if (sscanf(tmpstr, "%d", &ltimeoff) != 1)
972                                                   return E_BAD_LONGWORD;
973                                         hp->time_offset = ltimeoff;
974                               }
975                               hp->flags.time_offset = TRUE;
976                     }
977                     break;
978 
979           case SYM_TIME_SERVER:
980                     PARSE_IAL(time_server);
981                     break;
982 
983           case SYM_VENDOR_MAGIC:
984                     if (optype == OP_BOOLEAN)
985                               return E_SYNTAX_ERROR;
986                     hp->flags.vm_cookie = FALSE;
987                     if (optype == OP_ADDITION) {
988                               if (strncmp(*symbol, "auto", 4)) {
989                                         /* The string is not "auto" */
990                                         if (!strncmp(*symbol, "rfc", 3)) {
991                                                   bcopy(vm_rfc1048, hp->vm_cookie, 4);
992                                         } else if (!strncmp(*symbol, "cmu", 3)) {
993                                                   bcopy(vm_cmu, hp->vm_cookie, 4);
994                                         } else {
995                                                   if (!isdigit((unsigned char)**symbol))
996                                                             return E_BAD_IPADDR;
997                                                   if (prs_inetaddr(symbol, &value) < 0)
998                                                             return E_BAD_IPADDR;
999                                                   bcopy(&value, hp->vm_cookie, 4);
1000                                         }
1001                                         hp->flags.vm_cookie = TRUE;
1002                               }
1003                     }
1004                     break;
1005 
1006           case SYM_SIMILAR_ENTRY:
1007                     switch (optype) {
1008                     case OP_ADDITION:
1009                               fill_defaults(hp, symbol);
1010                               break;
1011                     default:
1012                               return E_SYNTAX_ERROR;
1013                     }
1014                     break;
1015 
1016           case SYM_NAME_SWITCH:
1017                     switch (optype) {
1018                     case OP_ADDITION:
1019                               return E_SYNTAX_ERROR;
1020                     case OP_DELETION:
1021                               hp->flags.send_name = FALSE;
1022                               hp->flags.name_switch = FALSE;
1023                               break;
1024                     case OP_BOOLEAN:
1025                               hp->flags.send_name = TRUE;
1026                               hp->flags.name_switch = TRUE;
1027                               break;
1028                     }
1029                     break;
1030 
1031           case SYM_BOOTSIZE:
1032                     switch (optype) {
1033                     case OP_ADDITION:
1034                               if (!strncmp(*symbol, "auto", 4)) {
1035                                         hp->flags.bootsize = TRUE;
1036                                         hp->flags.bootsize_auto = TRUE;
1037                               } else {
1038                                         hp->bootsize = (unsigned int) get_u_long(symbol);
1039                                         hp->flags.bootsize = TRUE;
1040                                         hp->flags.bootsize_auto = FALSE;
1041                               }
1042                               break;
1043                     case OP_DELETION:
1044                               hp->flags.bootsize = FALSE;
1045                               break;
1046                     case OP_BOOLEAN:
1047                               hp->flags.bootsize = TRUE;
1048                               hp->flags.bootsize_auto = TRUE;
1049                               break;
1050                     }
1051                     break;
1052 
1053           case SYM_BOOT_SERVER:
1054                     PARSE_IA1(bootserver);
1055                     break;
1056 
1057           case SYM_TFTPDIR:
1058                     PARSE_STR(tftpdir);
1059                     if ((hp->tftpdir != NULL) &&
1060                               (hp->tftpdir->string[0] != '/'))
1061                               return E_BAD_PATHNAME;
1062                     break;
1063 
1064           case SYM_DUMP_FILE:
1065                     PARSE_STR(dump_file);
1066                     break;
1067 
1068           case SYM_DOMAIN_NAME:
1069                     PARSE_STR(domain_name);
1070                     break;
1071 
1072           case SYM_SWAP_SERVER:
1073                     PARSE_IA1(swap_server);
1074                     break;
1075 
1076           case SYM_ROOT_PATH:
1077                     PARSE_STR(root_path);
1078                     break;
1079 
1080           case SYM_EXTEN_FILE:
1081                     PARSE_STR(exten_file);
1082                     break;
1083 
1084           case SYM_REPLY_ADDR:
1085                     PARSE_IA1(reply_addr);
1086                     break;
1087 
1088           case SYM_NIS_DOMAIN:
1089                     PARSE_STR(nis_domain);
1090                     break;
1091 
1092           case SYM_NIS_SERVER:
1093                     PARSE_IAL(nis_server);
1094                     break;
1095 
1096           case SYM_NTP_SERVER:
1097                     PARSE_IAL(ntp_server);
1098                     break;
1099 
1100 #ifdef    YORK_EX_OPTION
1101           case SYM_EXEC_FILE:
1102                     PARSE_STR(exec_file);
1103                     break;
1104 #endif
1105 
1106           case SYM_MSG_SIZE:
1107                     PARSE_INT(msg_size);
1108                     if (hp->msg_size < BP_MINPKTSZ ||
1109                               hp->msg_size > MAX_MSG_SIZE)
1110                               return E_BAD_VALUE;
1111                     break;
1112 
1113           case SYM_MIN_WAIT:
1114                     PARSE_INT(min_wait);
1115                     if (hp->min_wait == 0)
1116                               return E_BAD_VALUE;
1117                     break;
1118 
1119                     /* XXX - Add new tags here */
1120 
1121           default:
1122                     return E_UNKNOWN_SYMBOL;
1123 
1124           }                                                                     /* switch symbolcode */
1125 
1126           return SUCCESS;
1127 }
1128 #undef    PARSE_IA1
1129 #undef    PARSE_IAL
1130 #undef    PARSE_STR
1131 
1132 
1133 
1134 
1135 /*
1136  * Read a string from the buffer indirectly pointed to through "src" and
1137  * move it into the buffer pointed to by "dest".  A pointer to the maximum
1138  * allowable length of the string (including null-terminator) is passed as
1139  * "length".  The actual length of the string which was read is returned in
1140  * the unsigned integer pointed to by "length".  This value is the same as
1141  * that which would be returned by applying the strlen() function on the
1142  * destination string (i.e the terminating null is not counted as a
1143  * character).  Trailing whitespace is removed from the string.  For
1144  * convenience, the function returns the new value of "dest".
1145  *
1146  * The string is read until the maximum number of characters, an unquoted
1147  * colon (:), or a null character is read.  The return string in "dest" is
1148  * null-terminated.
1149  */
1150 
1151 PRIVATE char *
get_string(char ** src,char * dest,unsigned int * length)1152 get_string(char **src, char *dest, unsigned int *length)
1153 {
1154           int n, len, quoteflag;
1155 
1156           quoteflag = FALSE;
1157           n = 0;
1158           len = *length - 1;
1159           while ((n < len) && (**src)) {
1160                     if (!quoteflag && (**src == ':')) {
1161                               break;
1162                     }
1163                     if (**src == '"') {
1164                               (*src)++;
1165                               quoteflag = !quoteflag;
1166                               continue;
1167                     }
1168                     if (**src == '\\') {
1169                               (*src)++;
1170                               if (!**src) {
1171                                         break;
1172                               }
1173                     }
1174                     *dest++ = *(*src)++;
1175                     n++;
1176           }
1177 
1178           /*
1179            * Remove that troublesome trailing whitespace. . .
1180            */
1181           while ((n > 0) && isspace((unsigned char)dest[-1])) {
1182                     dest--;
1183                     n--;
1184           }
1185 
1186           *dest = '\0';
1187           *length = n;
1188           return dest;
1189 }
1190 
1191 
1192 
1193 /*
1194  * Read the string indirectly pointed to by "src", update the caller's
1195  * pointer, and return a pointer to a malloc'ed shared_string structure
1196  * containing the string.
1197  *
1198  * The string is read using the same rules as get_string() above.
1199  */
1200 
1201 PRIVATE struct shared_string *
get_shared_string(char ** src)1202 get_shared_string(char **src)
1203 {
1204           char retstring[MAXSTRINGLEN];
1205           struct shared_string *s;
1206           unsigned length;
1207 
1208           length = sizeof(retstring);
1209           (void) get_string(src, retstring, &length);
1210 
1211           s = (struct shared_string *) smalloc(sizeof(struct shared_string) +
1212               length + 1);
1213           s->linkcount = 1;
1214           memcpy(s->string, retstring, length + 1);
1215 
1216           return s;
1217 }
1218 
1219 
1220 
1221 /*
1222  * Load RFC1048 generic information directly into a memory buffer.
1223  *
1224  * "src" indirectly points to the ASCII representation of the generic data.
1225  * "dest" points to a string structure which is updated to point to a new
1226  * string with the new data appended to the old string.  The old string is
1227  * freed.
1228  *
1229  * The given tag value is inserted with the new data.
1230  *
1231  * The data may be represented as either a stream of hexadecimal numbers
1232  * representing bytes (any or all bytes may optionally start with '0x' and
1233  * be separated with periods ".") or as a quoted string of ASCII
1234  * characters (the quotes are required).
1235  */
1236 
1237 PRIVATE int
process_generic(char ** src,struct shared_bindata ** dest,u_int tagvalue)1238 process_generic(char **src, struct shared_bindata **dest, u_int tagvalue)
1239 {
1240           byte tmpbuf[MAXBUFLEN];
1241           byte *str;
1242           struct shared_bindata *bdata;
1243           u_int newlength, oldlength;
1244 
1245           str = tmpbuf;
1246           *str++ = (tagvalue & 0xFF);   /* Store tag value */
1247           str++;                                                      /* Skip over length field */
1248           if ((*src)[0] == '"') {                 /* ASCII data */
1249                     newlength = sizeof(tmpbuf) - 2;         /* Set maximum allowed length */
1250                     (void) get_string(src, (char *) str, &newlength);
1251                     /* Do NOT include the terminating null. */
1252           } else {                                          /* Numeric data */
1253                     newlength = 0;
1254                     while (newlength < sizeof(tmpbuf) - 2) {
1255                               if (interp_byte(src, str++) < 0)
1256                                         break;
1257                               newlength++;
1258                               if (**src == '.') {
1259                                         (*src)++;
1260                               }
1261                     }
1262           }
1263           if ((*src)[0] != ':')
1264                     return -1;
1265 
1266           tmpbuf[1] = (newlength & 0xFF);
1267           oldlength = ((*dest)->length);
1268           bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1269                                                                                                               + oldlength + newlength + 1);
1270           if (oldlength > 0) {
1271                     bcopy((*dest)->data, bdata->data, oldlength);
1272           }
1273           bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1274           bdata->length = oldlength + newlength + 2;
1275           bdata->linkcount = 1;
1276           del_bindata(*dest);
1277           *dest = bdata;
1278           return 0;
1279 }
1280 
1281 
1282 
1283 /*
1284  * Verify that the given string makes sense as a hostname (according to
1285  * Appendix 1, page 29 of RFC882).
1286  *
1287  * Return TRUE for good names, FALSE otherwise.
1288  */
1289 
1290 PRIVATE boolean
goodname(char * hostname)1291 goodname(char *hostname)
1292 {
1293           do {
1294                     if (!isalpha((unsigned char)*hostname++)) {       /* First character must be a letter */
1295                               return FALSE;
1296                     }
1297                     while (isalnum((unsigned char)*hostname) ||
1298                                  (*hostname == '-') ||
1299                                  (*hostname == '_') )
1300                     {
1301                               hostname++;                             /* Alphanumeric or a hyphen */
1302                     }
1303                     if (!isalnum((unsigned char)hostname[-1])) {      /* Last must be alphanumeric */
1304                               return FALSE;
1305                     }
1306                     if (*hostname == '\0') {/* Done? */
1307                               return TRUE;
1308                     }
1309           } while (*hostname++ == '.'); /* Dot, loop for next label */
1310 
1311           return FALSE;                                     /* If it's not a dot, lose */
1312 }
1313 
1314 
1315 
1316 /*
1317  * Null compare function -- always returns FALSE so an element is always
1318  * inserted into a hash table (i.e. there is never a collision with an
1319  * existing element).
1320  */
1321 
1322 PRIVATE boolean
nullcmp(hash_datum * d1,hash_datum * d2)1323 nullcmp(hash_datum *d1, hash_datum *d2)
1324 {
1325           return FALSE;
1326 }
1327 
1328 
1329 /*
1330  * Function for comparing a string with the hostname field of a host
1331  * structure.
1332  */
1333 
1334 boolean
nmcmp(hash_datum * d1,hash_datum * d2)1335 nmcmp(hash_datum *d1, hash_datum *d2)
1336 {
1337           char *name = (char *) d1;     /* XXX - OK? */
1338           struct host *hp = (struct host *) d2;
1339 
1340           return !strcmp(name, hp->hostname->string);
1341 }
1342 
1343 
1344 /*
1345  * Compare function to determine whether two hardware addresses are
1346  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
1347  * otherwise.
1348  *
1349  * If the hardware addresses of "host1" and "host2" are identical, but
1350  * they are on different IP subnets, this function returns FALSE.
1351  *
1352  * This function is used when inserting elements into the hardware address
1353  * hash table.
1354  */
1355 
1356 PRIVATE boolean
hwinscmp(hash_datum * d1,hash_datum * d2)1357 hwinscmp(hash_datum *d1, hash_datum *d2)
1358 {
1359           struct host *host1 = (struct host *) d1;
1360           struct host *host2 = (struct host *) d2;
1361 
1362           if (host1->htype != host2->htype) {
1363                     return FALSE;
1364           }
1365           if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1366                     return FALSE;
1367           }
1368           /* XXX - Is the subnet_mask field set yet? */
1369           if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1370                     if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1371                               ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1372                     {
1373                               return FALSE;
1374                     }
1375           }
1376           return TRUE;
1377 }
1378 
1379 
1380 /*
1381  * Macros for use in the function below:
1382  */
1383 
1384 #define DUP_COPY(MEMBER) do \
1385 { \
1386           if (!hp->flags.MEMBER) { \
1387                     if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1388                               hp->MEMBER = hp2->MEMBER; \
1389                     } \
1390           } \
1391 } while (0)
1392 
1393 #define DUP_LINK(MEMBER) do \
1394 { \
1395           if (!hp->flags.MEMBER) { \
1396                     if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1397                               assert(hp2->MEMBER); \
1398                               hp->MEMBER = hp2->MEMBER; \
1399                               (hp->MEMBER->linkcount)++; \
1400                     } \
1401           } \
1402 } while (0)
1403 
1404 /*
1405  * Process the "similar entry" symbol.
1406  *
1407  * The host specified as the value of the "tc" symbol is used as a template
1408  * for the current host entry.  Symbol values not explicitly set in the
1409  * current host entry are inferred from the template entry.
1410  */
1411 PRIVATE void
fill_defaults(struct host * hp,char ** src)1412 fill_defaults(struct host *hp, char **src)
1413 {
1414           unsigned int tlen, hashcode;
1415           struct host *hp2;
1416           char tstring[MAXSTRINGLEN];
1417 
1418           tlen = sizeof(tstring);
1419           (void) get_string(src, tstring, &tlen);
1420           hashcode = hash_HashFunction((u_char *) tstring, tlen);
1421           hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1422 
1423           if (hp2 == NULL) {
1424                     report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1425                     return;
1426           }
1427           DUP_LINK(bootfile);
1428           DUP_LINK(cookie_server);
1429           DUP_LINK(domain_server);
1430           DUP_LINK(gateway);
1431           /* haddr not copied */
1432           DUP_LINK(homedir);
1433           DUP_COPY(htype);
1434 
1435           DUP_LINK(impress_server);
1436           /* iaddr not copied */
1437           DUP_LINK(log_server);
1438           DUP_LINK(lpr_server);
1439           DUP_LINK(name_server);
1440           DUP_LINK(rlp_server);
1441 
1442           DUP_COPY(subnet_mask);
1443           DUP_COPY(time_offset);
1444           DUP_LINK(time_server);
1445 
1446           if (!hp->flags.vm_cookie) {
1447                     if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1448                               bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1449                     }
1450           }
1451           if (!hp->flags.name_switch) {
1452                     if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1453                               hp->flags.send_name = hp2->flags.send_name;
1454                     }
1455           }
1456           if (!hp->flags.bootsize) {
1457                     if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1458                               hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1459                               hp->bootsize = hp2->bootsize;
1460                     }
1461           }
1462           DUP_COPY(bootserver);
1463 
1464           DUP_LINK(tftpdir);
1465           DUP_LINK(dump_file);
1466           DUP_LINK(domain_name);
1467 
1468           DUP_COPY(swap_server);
1469           DUP_LINK(root_path);
1470           DUP_LINK(exten_file);
1471 
1472           DUP_COPY(reply_addr);
1473 
1474           DUP_LINK(nis_domain);
1475           DUP_LINK(nis_server);
1476           DUP_LINK(ntp_server);
1477 
1478 #ifdef    YORK_EX_OPTION
1479           DUP_LINK(exec_file);
1480 #endif
1481 
1482           DUP_COPY(msg_size);
1483           DUP_COPY(min_wait);
1484 
1485           /* XXX - Add new tags here */
1486 
1487           DUP_LINK(generic);
1488 
1489 }
1490 #undef    DUP_COPY
1491 #undef    DUP_LINK
1492 
1493 
1494 
1495 /*
1496  * This function adjusts the caller's pointer to point just past the
1497  * first-encountered colon.  If it runs into a null character, it leaves
1498  * the pointer pointing to it.
1499  */
1500 
1501 PRIVATE void
adjust(char ** s)1502 adjust(char **s)
1503 {
1504           char *t;
1505 
1506           t = *s;
1507           while (*t && (*t != ':')) {
1508                     t++;
1509           }
1510           if (*t) {
1511                     t++;
1512           }
1513           *s = t;
1514 }
1515 
1516 
1517 
1518 
1519 /*
1520  * This function adjusts the caller's pointer to point to the first
1521  * non-whitespace character.  If it runs into a null character, it leaves
1522  * the pointer pointing to it.
1523  */
1524 
1525 PRIVATE void
eat_whitespace(char ** s)1526 eat_whitespace(char **s)
1527 {
1528           char *t;
1529 
1530           t = *s;
1531           while (*t && isspace((unsigned char)*t)) {
1532                     t++;
1533           }
1534           *s = t;
1535 }
1536 
1537 
1538 
1539 /*
1540  * This function converts the given string to all lowercase.
1541  */
1542 
1543 PRIVATE void
makelower(char * s)1544 makelower(char *s)
1545 {
1546           while (*s) {
1547                     if (isupper((unsigned char)*s)) {
1548                               *s = tolower((unsigned char)*s);
1549                     }
1550                     s++;
1551           }
1552 }
1553 
1554 
1555 
1556 /*
1557  *
1558  *        N O T E :
1559  *
1560  *        In many of the functions which follow, a parameter such as "src" or
1561  *        "symbol" is passed as a pointer to a pointer to something.  This is
1562  *        done for the purpose of letting the called function update the
1563  *        caller's copy of the parameter (i.e. to effect call-by-reference
1564  *        parameter passing).  The value of the actual parameter is only used
1565  *        to locate the real parameter of interest and then update this indirect
1566  *        parameter.
1567  *
1568  *        I'm sure somebody out there won't like this. . . .
1569  *  (Yea, because it usually makes code slower... -gwr)
1570  *
1571  */
1572 
1573 
1574 
1575 /*
1576  * "src" points to a character pointer which points to an ASCII string of
1577  * whitespace-separated IP addresses.  A pointer to an in_addr_list
1578  * structure containing the list of addresses is returned.  NULL is
1579  * returned if no addresses were found at all.  The pointer pointed to by
1580  * "src" is updated to point to the first non-address (illegal) character.
1581  */
1582 
1583 PRIVATE struct in_addr_list *
get_addresses(char ** src)1584 get_addresses(char **src)
1585 {
1586           __aligned(4) struct in_addr tmpaddrlist[MAXINADDRS];
1587           struct in_addr_list *result;
1588           unsigned addrcount, totalsize, address;
1589 
1590           for (address = 0, addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1591                     while (isspace((unsigned char)**src) || (**src == ',')) {
1592                               (*src)++;
1593                     }
1594                     if (!**src) {                           /* Quit if nothing more */
1595                               break;
1596                     }
1597                     if (prs_inetaddr(src, &tmpaddrlist[address].s_addr) < 0) {
1598                               break;
1599                     }
1600                     address++;                                        /* Point to next address slot */
1601           }
1602           if (addrcount < 1) {
1603                     result = NULL;
1604           } else {
1605                     totalsize = sizeof(struct in_addr_list)
1606                     +                             (addrcount - 1) * sizeof(struct in_addr);
1607                     result = (struct in_addr_list *) smalloc(totalsize);
1608                     result->linkcount = 1;
1609                     result->addrcount = addrcount;
1610                     for (address = 0; address < addrcount; ++address)
1611                               result->addr[address] = tmpaddrlist[address];
1612           }
1613           return result;
1614 }
1615 
1616 
1617 
1618 /*
1619  * prs_inetaddr(src, result)
1620  *
1621  * "src" is a value-result parameter; the pointer it points to is updated
1622  * to point to the next data position.   "result" points to an unsigned long
1623  * in which an address is returned.
1624  *
1625  * This function parses the IP address string in ASCII "dot notation" pointed
1626  * to by (*src) and places the result (in network byte order) in the unsigned
1627  * long pointed to by "result".  For malformed addresses, -1 is returned,
1628  * (*src) points to the first illegal character, and the unsigned long pointed
1629  * to by "result" is unchanged.  Successful calls return 0.
1630  */
1631 
1632 PRIVATE int
prs_inetaddr(char ** src,u_int32 * result)1633 prs_inetaddr(char **src, u_int32 *result)
1634 {
1635           char tmpstr[MAXSTRINGLEN];
1636           u_int32 value;
1637           u_int32 parts[4], *pp;
1638           int n;
1639           char *s, *t;
1640 
1641 #if 1     /* XXX - experimental */
1642           /* Leading alpha char causes IP addr lookup. */
1643           if (isalpha((unsigned char)**src)) {
1644                     /* Lookup IP address. */
1645                     s = *src;
1646                     t = tmpstr;
1647                     while ((isalnum((unsigned char)*s) || (*s == '.') ||
1648                                         (*s == '-') || (*s == '_') ) &&
1649                                  (t < &tmpstr[MAXSTRINGLEN - 1]) )
1650                               *t++ = *s++;
1651                     *t = '\0';
1652                     *src = s;
1653 
1654                     n = lookup_ipa(tmpstr, result);
1655                     if (n < 0)
1656                               report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1657                     return n;
1658           }
1659 #endif
1660 
1661           /*
1662            * Parse an address in Internet format:
1663            *        a.b.c.d
1664            *        a.b.c     (with c treated as 16-bits)
1665            *        a.b       (with b treated as 24 bits)
1666            */
1667           pp = parts;
1668   loop:
1669           /* If it's not a digit, return error. */
1670           if (!isdigit((unsigned char)**src))
1671                     return -1;
1672           *pp++ = get_u_long(src);
1673           if (**src == '.') {
1674                     if (pp < (parts + 4)) {
1675                               (*src)++;
1676                               goto loop;
1677                     }
1678                     return (-1);
1679           }
1680 #if 0
1681           /* This is handled by the caller. */
1682           if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) {
1683                     return (-1);
1684           }
1685 #endif
1686 
1687           /*
1688            * Construct the address according to
1689            * the number of parts specified.
1690            */
1691           n = pp - parts;
1692           switch (n) {
1693           case 1:                                           /* a -- 32 bits */
1694                     value = parts[0];
1695                     break;
1696           case 2:                                           /* a.b -- 8.24 bits */
1697                     value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1698                     break;
1699           case 3:                                           /* a.b.c -- 8.8.16 bits */
1700                     value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1701                               (parts[2] & 0xFFFF);
1702                     break;
1703           case 4:                                           /* a.b.c.d -- 8.8.8.8 bits */
1704                     value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1705                               ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1706                     break;
1707           default:
1708                     return (-1);
1709           }
1710           *result = htonl(value);
1711           return (0);
1712 }
1713 
1714 
1715 
1716 /*
1717  * "src" points to a pointer which in turn points to a hexadecimal ASCII
1718  * string.  This string is interpreted as a hardware address and returned
1719  * as a pointer to the actual hardware address, represented as an array of
1720  * bytes.
1721  *
1722  * The ASCII string must have the proper number of digits for the specified
1723  * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1724  * Two-digit sequences (bytes) may be separated with periods (.)  and/or
1725  * prefixed with '0x' for readability, but this is not required.
1726  *
1727  * For bad addresses, the pointer which "src" points to is updated to point
1728  * to the start of the first two-digit sequence which was bad, and the
1729  * function returns a NULL pointer.
1730  */
1731 
1732 PRIVATE byte *
prs_haddr(char ** src,u_int htype)1733 prs_haddr(char **src, u_int htype)
1734 {
1735           static byte haddr[MAXHADDRLEN];
1736           byte *hap;
1737           char tmpstr[MAXSTRINGLEN];
1738           u_int tmplen;
1739           unsigned hal;
1740           char *p;
1741 
1742           hal = haddrlength(htype);     /* Get length of this address type */
1743           if (hal <= 0) {
1744                     report(LOG_ERR, "Invalid addr type for HW addr parse");
1745                     return NULL;
1746           }
1747           tmplen = sizeof(tmpstr);
1748           get_string(src, tmpstr, &tmplen);
1749           p = tmpstr;
1750 
1751 #if 1     /* XXX - experimental */
1752           /* If it's a valid host name, try to lookup the HW address. */
1753           if (goodname(p)) {
1754                     /* Lookup Hardware Address for hostname. */
1755                     if ((hap = lookup_hwa(p, htype)) != NULL)
1756                               return hap; /* success */
1757                     report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1758                     /* OK, assume it must be numeric. */
1759           }
1760 #endif
1761 
1762           hap = haddr;
1763           while (hap < haddr + hal) {
1764                     if ((*p == '.') || (*p == ':'))
1765                               p++;
1766                     if (interp_byte(&p, hap++) < 0) {
1767                               return NULL;
1768                     }
1769           }
1770           return haddr;
1771 }
1772 
1773 
1774 
1775 /*
1776  * "src" is a pointer to a character pointer which in turn points to a
1777  * hexadecimal ASCII representation of a byte.  This byte is read, the
1778  * character pointer is updated, and the result is deposited into the
1779  * byte pointed to by "retbyte".
1780  *
1781  * The usual '0x' notation is allowed but not required.  The number must be
1782  * a two digit hexadecimal number.  If the number is invalid, "src" and
1783  * "retbyte" are left untouched and -1 is returned as the function value.
1784  * Successful calls return 0.
1785  */
1786 
1787 PRIVATE int
interp_byte(char ** src,byte * retbyte)1788 interp_byte(char **src, byte *retbyte)
1789 {
1790           int v;
1791 
1792           if ((*src)[0] == '0' &&
1793                     ((*src)[1] == 'x' ||
1794                      (*src)[1] == 'X')) {
1795                     (*src) += 2;                            /* allow 0x for hex, but don't require it */
1796           }
1797           if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) {
1798                     return -1;
1799           }
1800           if (sscanf(*src, "%2x", &v) != 1) {
1801                     return -1;
1802           }
1803           (*src) += 2;
1804           *retbyte = (byte) (v & 0xFF);
1805           return 0;
1806 }
1807 
1808 
1809 
1810 /*
1811  * The parameter "src" points to a character pointer which points to an
1812  * ASCII string representation of an unsigned number.  The number is
1813  * returned as an unsigned long and the character pointer is updated to
1814  * point to the first illegal character.
1815  */
1816 
1817 PRIVATE u_int32
get_u_long(char ** src)1818 get_u_long(char **src)
1819 {
1820           u_int32 value, base;
1821           char c;
1822 
1823           /*
1824            * Collect number up to first illegal character.  Values are specified
1825            * as for C:  0x=hex, 0=octal, other=decimal.
1826            */
1827           value = 0;
1828           base = 10;
1829           if (**src == '0') {
1830                     base = 8;
1831                     (*src)++;
1832           }
1833           if (**src == 'x' || **src == 'X') {
1834                     base = 16;
1835                     (*src)++;
1836           }
1837           while ((c = **src)) {
1838                     if (isdigit((unsigned char)c)) {
1839                               value = (value * base) + (c - '0');
1840                               (*src)++;
1841                               continue;
1842                     }
1843                     if (base == 16 && isxdigit((unsigned char)c)) {
1844                               value = (value << 4) + ((c & ~32) + 10 - 'A');
1845                               (*src)++;
1846                               continue;
1847                     }
1848                     break;
1849           }
1850           return value;
1851 }
1852 
1853 
1854 
1855 /*
1856  * Routines for deletion of data associated with the main data structure.
1857  */
1858 
1859 
1860 /*
1861  * Frees the entire host data structure given.  Does nothing if the passed
1862  * pointer is NULL.
1863  */
1864 
1865 PRIVATE void
free_host(hash_datum * hmp)1866 free_host(hash_datum *hmp)
1867 {
1868           struct host *hostptr = (struct host *) hmp;
1869           if (hostptr == NULL)
1870                     return;
1871           assert(hostptr->linkcount > 0);
1872           if (--(hostptr->linkcount))
1873                     return;                                           /* Still has references */
1874           del_iplist(hostptr->cookie_server);
1875           del_iplist(hostptr->domain_server);
1876           del_iplist(hostptr->gateway);
1877           del_iplist(hostptr->impress_server);
1878           del_iplist(hostptr->log_server);
1879           del_iplist(hostptr->lpr_server);
1880           del_iplist(hostptr->name_server);
1881           del_iplist(hostptr->rlp_server);
1882           del_iplist(hostptr->time_server);
1883           del_iplist(hostptr->nis_server);
1884           del_iplist(hostptr->ntp_server);
1885 
1886           /*
1887            * XXX - Add new tags here
1888            * (if the value is an IP list)
1889            */
1890 
1891           del_string(hostptr->hostname);
1892           del_string(hostptr->homedir);
1893           del_string(hostptr->bootfile);
1894           del_string(hostptr->tftpdir);
1895           del_string(hostptr->root_path);
1896           del_string(hostptr->domain_name);
1897           del_string(hostptr->dump_file);
1898           del_string(hostptr->exten_file);
1899           del_string(hostptr->nis_domain);
1900 
1901 #ifdef    YORK_EX_OPTION
1902           del_string(hostptr->exec_file);
1903 #endif
1904 
1905           /*
1906            * XXX - Add new tags here
1907            * (if it is a shared string)
1908            */
1909 
1910           del_bindata(hostptr->generic);
1911           free((char *) hostptr);
1912 }
1913 
1914 
1915 
1916 /*
1917  * Decrements the linkcount on the given IP address data structure.  If the
1918  * linkcount goes to zero, the memory associated with the data is freed.
1919  */
1920 
1921 PRIVATE void
del_iplist(struct in_addr_list * iplist)1922 del_iplist(struct in_addr_list *iplist)
1923 {
1924           if (iplist) {
1925                     if (!(--(iplist->linkcount))) {
1926                               free((char *) iplist);
1927                     }
1928           }
1929 }
1930 
1931 
1932 
1933 /*
1934  * Decrements the linkcount on a string data structure.  If the count
1935  * goes to zero, the memory associated with the string is freed.  Does
1936  * nothing if the passed pointer is NULL.
1937  */
1938 
1939 PRIVATE void
del_string(struct shared_string * stringptr)1940 del_string(struct shared_string *stringptr)
1941 {
1942           if (stringptr) {
1943                     if (!(--(stringptr->linkcount))) {
1944                               free((char *) stringptr);
1945                     }
1946           }
1947 }
1948 
1949 
1950 
1951 /*
1952  * Decrements the linkcount on a shared_bindata data structure.  If the
1953  * count goes to zero, the memory associated with the data is freed.  Does
1954  * nothing if the passed pointer is NULL.
1955  */
1956 
1957 PRIVATE void
del_bindata(struct shared_bindata * dataptr)1958 del_bindata(struct shared_bindata *dataptr)
1959 {
1960           if (dataptr) {
1961                     if (!(--(dataptr->linkcount))) {
1962                               free((char *) dataptr);
1963                     }
1964           }
1965 }
1966 
1967 
1968 
1969 
1970 /* smalloc()  --  safe malloc()
1971  *
1972  * Always returns a valid pointer (if it returns at all).  The allocated
1973  * memory is initialized to all zeros.  If malloc() returns an error, a
1974  * message is printed using the report() function and the program aborts
1975  * with a status of 1.
1976  */
1977 
1978 PRIVATE char *
smalloc(unsigned int nbytes)1979 smalloc(unsigned int nbytes)
1980 {
1981           char *retvalue;
1982 
1983           retvalue = malloc(nbytes);
1984           if (!retvalue) {
1985                     report(LOG_ERR, "malloc() failure -- exiting");
1986                     exit(1);
1987           }
1988           bzero(retvalue, nbytes);
1989           return retvalue;
1990 }
1991 
1992 
1993 /*
1994  * Compare function to determine whether two hardware addresses are
1995  * equivalent.  Returns TRUE if "host1" and "host2" are equivalent, FALSE
1996  * otherwise.
1997  *
1998  * This function is used when retrieving elements from the hardware address
1999  * hash table.
2000  */
2001 
2002 boolean
hwlookcmp(hash_datum * d1,hash_datum * d2)2003 hwlookcmp(hash_datum *d1, hash_datum *d2)
2004 {
2005           struct host *host1 = (struct host *) d1;
2006           struct host *host2 = (struct host *) d2;
2007 
2008           if (host1->htype != host2->htype) {
2009                     return FALSE;
2010           }
2011           if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2012                     return FALSE;
2013           }
2014           return TRUE;
2015 }
2016 
2017 
2018 /*
2019  * Compare function for doing IP address hash table lookup.
2020  */
2021 
2022 boolean
iplookcmp(hash_datum * d1,hash_datum * d2)2023 iplookcmp(hash_datum *d1, hash_datum *d2)
2024 {
2025           struct host *host1 = (struct host *) d1;
2026           struct host *host2 = (struct host *) d2;
2027 
2028           return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2029 }
2030 
2031 /*
2032  * Local Variables:
2033  * tab-width: 4
2034  * c-indent-level: 4
2035  * c-argdecl-indent: 4
2036  * c-continued-statement-offset: 4
2037  * c-continued-brace-offset: -4
2038  * c-label-offset: -4
2039  * c-brace-offset: 0
2040  * End:
2041  */
2042