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