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