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