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