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