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