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