1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
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.
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
24 ************************************************************************/
27 * bootpd configuration file reading code.
29 * The routines in this file deal with reading, interpreting, and storing
30 * the information found in the bootpd configuration file (usually
35 #include <sys/errno.h>
36 #include <sys/types.h>
40 #include <netinet/in.h>
58 #define HASHTABLESIZE 257 /* Hash table size (prime) */
60 /* Non-standard hardware address type (see bootp.h) */
61 #define HTYPE_DIRECT 0
63 /* Error codes returned by eval_symbol: */
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)
77 #define SYM_BOOTFILE 1
78 #define SYM_COOKIE_SERVER 2
79 #define SYM_DOMAIN_SERVER 3
84 #define SYM_IMPRESS_SERVER 8
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 */
113 #define OP_ADDITION 1 /* Operations on tags */
114 #define OP_DELETION 2
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 */
124 * Structure used to map a configuration-file symbol (such as "ds") to a
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];
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
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 */
164 {"hn", SYM_NAME_SWITCH},
166 {"im", SYM_IMPRESS_SERVER},
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},
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 */
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.
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}
219 * Externals and forward declarations.
222 boolean nmcmp(hash_datum *, hash_datum *);
227 del_string(struct shared_string *);
229 del_bindata(struct shared_bindata *);
231 del_iplist(struct in_addr_list *);
233 eat_whitespace(char **);
235 eval_symbol(char **, struct host *);
237 fill_defaults(struct host *, char **);
239 free_host(hash_datum *);
240 PRIVATE struct in_addr_list *
241 get_addresses(char **);
242 PRIVATE struct shared_string *
243 get_shared_string(char **);
245 get_string(char **, char *, u_int *);
251 hwinscmp(hash_datum *, hash_datum *);
253 interp_byte(char **, byte *);
257 nullcmp(hash_datum *, hash_datum *);
259 process_entry(struct host *, char *);
261 process_generic(char **, struct shared_bindata **, u_int);
263 prs_haddr(char **, u_int);
265 prs_inetaddr(char **, u_int32 *);
267 read_entry(FILE *, char *, u_int *);
273 * Vendor magic cookies for CMU and RFC1048
275 u_char vm_cmu[4] = VM_CMU;
276 u_char vm_rfc1048[4] = VM_RFC1048;
281 hash_tbl *hwhashtable;
282 hash_tbl *iphashtable;
283 hash_tbl *nmhashtable;
286 * Allocate hash tables for hardware address, ip address, and hostname
287 * (shared by bootpd and bootpef)
292 hwhashtable = hash_Init(HASHTABLESIZE);
293 iphashtable = hash_Init(HASHTABLESIZE);
294 nmhashtable = hash_Init(HASHTABLESIZE);
295 if (!(hwhashtable && iphashtable && nmhashtable)) {
296 report(LOG_ERR, "Unable to allocate hash tables.");
303 * Read bootptab database file. Avoid rereading the file if the
304 * write date hasn't changed since the last time we read it.
313 unsigned hashcode, buflen;
314 static char buffer[MAXENTRYLEN];
317 * Check the last modification time.
319 if (stat(bootptab, &st) < 0) {
320 report(LOG_ERR, "stat on \"%s\": %s",
321 bootptab, get_errmsg());
327 strcpy(timestr, ctime(&(st.st_mtime)));
328 /* zap the newline */
330 report(LOG_INFO, "bootptab mtime: %s",
335 (st.st_mtime == modtime) &&
338 * hasn't been modified or deleted yet.
343 report(LOG_INFO, "reading %s\"%s\"",
344 (modtime != 0L) ? "new " : "",
348 * Open bootptab file.
350 if ((fp = fopen(bootptab, "r")) == NULL) {
351 report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
355 * Record file modification time.
357 if (fstat(fileno(fp), &st) < 0) {
358 report(LOG_ERR, "fstat: %s", get_errmsg());
362 modtime = st.st_mtime;
365 * Entirely erase all hash tables.
367 hash_Reset(hwhashtable, free_host);
368 hash_Reset(iphashtable, free_host);
369 hash_Reset(nmhashtable, free_host);
374 buflen = sizeof(buffer);
375 read_entry(fp, buffer, &buflen);
376 if (buflen == 0) { /* More entries? */
379 hp = (struct host *) smalloc(sizeof(struct host));
380 bzero((char *) hp, sizeof(*hp));
381 /* the link count it zero */
384 * Get individual info
386 if (process_entry(hp, buffer) < 0) {
388 free_host((hash_datum *) hp);
392 * If this is not a dummy entry, and the IP or HW
393 * address is not yet set, try to get them here.
394 * Dummy entries have . as first char of name.
396 if (goodname(hp->hostname->string)) {
397 char *hn = hp->hostname->string;
399 if (hp->flags.iaddr == 0) {
400 if (lookup_ipa(hn, &value)) {
401 report(LOG_ERR, "can not get IP addr for %s", hn);
402 report(LOG_ERR, "(dummy names should start with '.')");
404 hp->iaddr.s_addr = value;
405 hp->flags.iaddr = TRUE;
408 /* Set default subnet mask. */
409 if (hp->flags.subnet_mask == 0) {
410 if (lookup_netmask(hp->iaddr.s_addr, &value)) {
411 report(LOG_ERR, "can not get netmask for %s", hn);
413 hp->subnet_mask.s_addr = value;
414 hp->flags.subnet_mask = TRUE;
418 if (hp->flags.iaddr) {
421 /* Register by HW addr if known. */
422 if (hp->flags.htype && hp->flags.haddr) {
423 /* We will either insert it or free it. */
425 hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
426 if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
427 report(LOG_NOTICE, "duplicate %s address: %s",
429 haddrtoa(hp->haddr, haddrlength(hp->htype)));
430 free_host((hash_datum *) hp);
434 /* Register by IP addr if known. */
435 if (hp->flags.iaddr) {
436 hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
437 if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
439 "hash_Insert() failed on IP address insertion");
441 /* Just inserted the host struct in a new hash list. */
445 /* Register by Name (always known) */
446 hashcode = hash_HashFunction((u_char *) hp->hostname->string,
447 strlen(hp->hostname->string));
448 if (hash_Insert(nmhashtable, hashcode, nullcmp,
449 hp->hostname->string, hp) < 0) {
451 "hash_Insert() failed on insertion of hostname: \"%s\"",
452 hp->hostname->string);
454 /* Just inserted the host struct in a new hash list. */
463 report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
464 nentries, nhosts, bootptab);
471 * Read an entire host entry from the file pointed to by "fp" and insert it
472 * into the memory pointed to by "buffer". Leading whitespace and comments
473 * starting with "#" are ignored (removed). Backslashes (\) always quote
474 * the next character except that newlines preceded by a backslash cause
475 * line-continuation onto the next line. The entry is terminated by a
476 * newline character which is not preceded by a backslash. Sequences
477 * surrounded by double quotes are taken literally (including newlines, but
480 * The "bufsiz" parameter points to an unsigned int which specifies the
481 * maximum permitted buffer size. Upon return, this value will be replaced
482 * with the actual length of the entry (not including the null terminator).
484 * This code is a little scary. . . . I don't like using gotos in C
485 * either, but I first wrote this as an FSM diagram and gotos seemed like
486 * the easiest way to implement it. Maybe later I'll clean it up.
490 read_entry(FILE *fp, char *buffer, unsigned *bufsiz)
497 * Eat whitespace, blank lines, and comment lines.
502 goto done; /* Exit if end-of-file */
505 goto top; /* Skip over whitespace */
508 while (TRUE) { /* Eat comments after # */
511 goto done; /* Exit if end-of-file */
514 goto top; /* Try to read the next line */
518 ungetc(c, fp); /* Other character, push it back to reprocess it */
522 * Now we're actually reading a data entry. Get each character and
523 * assemble it into the data buffer, processing special characters like
524 * double quotes (") and backslashes (\).
532 goto done; /* Exit on EOF or newline */
534 c = fgetc(fp); /* Backslash, read a new character */
536 goto done; /* Exit on EOF */
538 *buffer++ = c; /* Store the literal character */
540 if (length < *bufsiz - 1) {
546 *buffer++ = '"'; /* Store double-quote */
548 if (length >= *bufsiz - 1) {
551 while (TRUE) { /* Special quote processing loop */
555 goto done; /* Exit on EOF . . . */
557 *buffer++ = '"';/* Store matching quote */
559 if (length < *bufsiz - 1) {
560 goto mainloop; /* And continue main loop */
565 if ((c = fgetc(fp)) < 0) { /* Backslash */
566 goto done; /* EOF. . . .*/
570 *buffer++ = c; /* Other character, store it */
572 if (length >= *bufsiz - 1) {
578 *buffer++ = c; /* Store colons */
580 if (length >= *bufsiz - 1) {
583 do { /* But remove whitespace after them */
585 if ((c < 0) || (c == '\n')) {
588 } while (isspace(c)); /* Skip whitespace */
590 if (c == '\\') { /* Backslash quotes next character */
596 goto top; /* Backslash-newline continuation */
599 /* FALLTHROUGH if "other" character */
601 *buffer++ = c; /* Store other characters */
603 if (length >= *bufsiz - 1) {
607 goto mainloop; /* Keep going */
610 *buffer = '\0'; /* Terminate string */
611 *bufsiz = length; /* Tell the caller its length */
617 * Parse out all the various tags and parameters in the host entry pointed
618 * to by "src". Stuff all the data into the appropriate fields of the
619 * host structure pointed to by "host". If there is any problem with the
620 * entry, an error message is reported via report(), no further processing
621 * is done, and -1 is returned. Successful calls return 0.
623 * (Some errors probably shouldn't be so completely fatal. . . .)
627 process_entry(struct host *host, char *src)
632 if (!host || *src == '\0') {
635 host->hostname = get_shared_string(&src);
637 /* Be more liberal for the benefit of dummy tag names. */
638 if (!goodname(host->hostname->string)) {
639 report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
640 del_string(host->hostname);
644 current_hostname = host->hostname->string;
647 retval = eval_symbol(&src, host);
648 if (retval == SUCCESS) {
652 if (retval == E_END_OF_ENTRY) {
653 /* The default subnet mask is set in readtab() */
656 /* Some kind of error. */
661 case E_UNKNOWN_SYMBOL:
662 msg = "unknown symbol";
665 msg = "bad INET address";
668 msg = "bad hardware address";
671 msg = "bad longword value";
674 msg = "bad HW address type";
677 msg = "bad pathname (need leading '/')";
683 msg = "unknown error";
686 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
687 current_hostname, current_tagname, msg);
694 * Macros for use in the function below:
697 /* Parse one INET address stored directly in MEMBER. */
698 #define PARSE_IA1(MEMBER) do \
700 if (optype == OP_BOOLEAN) \
701 return E_SYNTAX_ERROR; \
702 hp->flags.MEMBER = FALSE; \
703 if (optype == OP_ADDITION) { \
704 if (prs_inetaddr(symbol, &value) < 0) \
705 return E_BAD_IPADDR; \
706 hp->MEMBER.s_addr = value; \
707 hp->flags.MEMBER = TRUE; \
711 /* Parse a list of INET addresses pointed to by MEMBER */
712 #define PARSE_IAL(MEMBER) do \
714 if (optype == OP_BOOLEAN) \
715 return E_SYNTAX_ERROR; \
716 if (hp->flags.MEMBER) { \
717 hp->flags.MEMBER = FALSE; \
718 assert(hp->MEMBER); \
719 del_iplist(hp->MEMBER); \
722 if (optype == OP_ADDITION) { \
723 hp->MEMBER = get_addresses(symbol); \
724 if (hp->MEMBER == NULL) \
725 return E_SYNTAX_ERROR; \
726 hp->flags.MEMBER = TRUE; \
730 /* Parse a shared string pointed to by MEMBER */
731 #define PARSE_STR(MEMBER) do \
733 if (optype == OP_BOOLEAN) \
734 return E_SYNTAX_ERROR; \
735 if (hp->flags.MEMBER) { \
736 hp->flags.MEMBER = FALSE; \
737 assert(hp->MEMBER); \
738 del_string(hp->MEMBER); \
741 if (optype == OP_ADDITION) { \
742 hp->MEMBER = get_shared_string(symbol); \
743 if (hp->MEMBER == NULL) \
744 return E_SYNTAX_ERROR; \
745 hp->flags.MEMBER = TRUE; \
749 /* Parse an unsigned integer value for MEMBER */
750 #define PARSE_UINT(MEMBER) do \
752 if (optype == OP_BOOLEAN) \
753 return E_SYNTAX_ERROR; \
754 hp->flags.MEMBER = FALSE; \
755 if (optype == OP_ADDITION) { \
756 value = get_u_long(symbol); \
757 hp->MEMBER = value; \
758 hp->flags.MEMBER = TRUE; \
763 * Evaluate the two-character tag symbol pointed to by "symbol" and place
764 * the data in the structure pointed to by "hp". The pointer pointed to
765 * by "symbol" is updated to point past the source string (but may not
766 * point to the next tag entry).
768 * Obviously, this need a few more comments. . . .
771 eval_symbol(char **symbol, struct host *hp)
773 char tmpstr[MAXSTRINGLEN];
775 struct symbolmap *symbolptr;
780 int optype; /* Indicates boolean, addition, or deletion */
782 eat_whitespace(symbol);
784 /* Make sure this is set before returning. */
785 current_tagname[0] = (*symbol)[0];
786 current_tagname[1] = (*symbol)[1];
787 current_tagname[2] = 0;
789 if ((*symbol)[0] == '\0') {
790 return E_END_OF_ENTRY;
792 if ((*symbol)[0] == ':') {
795 if ((*symbol)[0] == 'T') { /* generic symbol */
797 value = get_u_long(symbol);
798 snprintf(current_tagname, sizeof(current_tagname),
800 eat_whitespace(symbol);
801 if ((*symbol)[0] != '=') {
802 return E_SYNTAX_ERROR;
805 if (!(hp->generic)) {
806 hp->generic = (struct shared_bindata *)
807 smalloc(sizeof(struct shared_bindata));
809 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
810 return E_SYNTAX_ERROR;
811 hp->flags.generic = TRUE;
815 * Determine the type of operation to be done on this symbol
817 switch ((*symbol)[2]) {
819 optype = OP_ADDITION;
822 optype = OP_DELETION;
829 return E_SYNTAX_ERROR;
832 symbolptr = symbol_list;
833 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
834 for (i = 0; i < numsymbols; i++) {
835 if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
836 ((symbolptr->symbol)[1] == (*symbol)[1])) {
841 if (i >= numsymbols) {
842 return E_UNKNOWN_SYMBOL;
845 * Skip past the = or @ character (to point to the data) if this
846 * isn't a boolean operation. For boolean operations, just skip
847 * over the two-character tag symbol (and nothing else. . . .).
849 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
851 eat_whitespace(symbol);
853 /* The cases below are in order by symbolcode value. */
854 switch (symbolptr->symbolcode) {
860 case SYM_COOKIE_SERVER:
861 PARSE_IAL(cookie_server);
864 case SYM_DOMAIN_SERVER:
865 PARSE_IAL(domain_server);
873 if (optype == OP_BOOLEAN)
874 return E_SYNTAX_ERROR;
875 hp->flags.haddr = FALSE;
876 if (optype == OP_ADDITION) {
877 /* Default the HW type to Ethernet */
878 if (hp->flags.htype == 0) {
879 hp->flags.htype = TRUE;
880 hp->htype = HTYPE_ETHERNET;
882 tmphaddr = prs_haddr(symbol, hp->htype);
885 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
886 hp->flags.haddr = TRUE;
895 if (optype == OP_BOOLEAN)
896 return E_SYNTAX_ERROR;
897 hp->flags.htype = FALSE;
898 if (optype == OP_ADDITION) {
899 value = 0L; /* Assume an illegal value */
900 eat_whitespace(symbol);
901 if (isdigit(**symbol)) {
902 value = get_u_long(symbol);
904 len = sizeof(tmpstr);
905 (void) get_string(symbol, tmpstr, &len);
907 numsymbols = sizeof(htnamemap) /
908 sizeof(struct htypename);
909 for (i = 0; i < numsymbols; i++) {
910 if (!strcmp(htnamemap[i].name, tmpstr)) {
914 if (i < numsymbols) {
915 value = htnamemap[i].htype;
918 if (value >= hwinfocnt) {
919 return E_BAD_HWATYPE;
921 hp->htype = (byte) (value & 0xFF);
922 hp->flags.htype = TRUE;
926 case SYM_IMPRESS_SERVER:
927 PARSE_IAL(impress_server);
935 PARSE_IAL(log_server);
939 PARSE_IAL(lpr_server);
942 case SYM_NAME_SERVER:
943 PARSE_IAL(name_server);
947 PARSE_IAL(rlp_server);
950 case SYM_SUBNET_MASK:
951 PARSE_IA1(subnet_mask);
954 case SYM_TIME_OFFSET:
955 if (optype == OP_BOOLEAN)
956 return E_SYNTAX_ERROR;
957 hp->flags.time_offset = FALSE;
958 if (optype == OP_ADDITION) {
959 len = sizeof(tmpstr);
960 (void) get_string(symbol, tmpstr, &len);
961 if (!strncmp(tmpstr, "auto", 4)) {
962 hp->time_offset = secondswest;
964 if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
965 return E_BAD_LONGWORD;
966 hp->time_offset = timeoff;
968 hp->flags.time_offset = TRUE;
972 case SYM_TIME_SERVER:
973 PARSE_IAL(time_server);
976 case SYM_VENDOR_MAGIC:
977 if (optype == OP_BOOLEAN)
978 return E_SYNTAX_ERROR;
979 hp->flags.vm_cookie = FALSE;
980 if (optype == OP_ADDITION) {
981 if (strncmp(*symbol, "auto", 4)) {
982 /* The string is not "auto" */
983 if (!strncmp(*symbol, "rfc", 3)) {
984 bcopy(vm_rfc1048, hp->vm_cookie, 4);
985 } else if (!strncmp(*symbol, "cmu", 3)) {
986 bcopy(vm_cmu, hp->vm_cookie, 4);
988 if (!isdigit(**symbol))
990 if (prs_inetaddr(symbol, &value) < 0)
992 bcopy(&value, hp->vm_cookie, 4);
994 hp->flags.vm_cookie = TRUE;
999 case SYM_SIMILAR_ENTRY:
1002 fill_defaults(hp, symbol);
1005 return E_SYNTAX_ERROR;
1009 case SYM_NAME_SWITCH:
1012 return E_SYNTAX_ERROR;
1014 hp->flags.send_name = FALSE;
1015 hp->flags.name_switch = FALSE;
1018 hp->flags.send_name = TRUE;
1019 hp->flags.name_switch = TRUE;
1027 if (!strncmp(*symbol, "auto", 4)) {
1028 hp->flags.bootsize = TRUE;
1029 hp->flags.bootsize_auto = TRUE;
1031 hp->bootsize = (unsigned int) get_u_long(symbol);
1032 hp->flags.bootsize = TRUE;
1033 hp->flags.bootsize_auto = FALSE;
1037 hp->flags.bootsize = FALSE;
1040 hp->flags.bootsize = TRUE;
1041 hp->flags.bootsize_auto = TRUE;
1046 case SYM_BOOT_SERVER:
1047 PARSE_IA1(bootserver);
1052 if ((hp->tftpdir != NULL) &&
1053 (hp->tftpdir->string[0] != '/'))
1054 return E_BAD_PATHNAME;
1058 PARSE_STR(dump_file);
1061 case SYM_DOMAIN_NAME:
1062 PARSE_STR(domain_name);
1065 case SYM_SWAP_SERVER:
1066 PARSE_IA1(swap_server);
1070 PARSE_STR(root_path);
1073 case SYM_EXTEN_FILE:
1074 PARSE_STR(exten_file);
1077 case SYM_REPLY_ADDR:
1078 PARSE_IA1(reply_addr);
1081 case SYM_NIS_DOMAIN:
1082 PARSE_STR(nis_domain);
1085 case SYM_NIS_SERVER:
1086 PARSE_IAL(nis_server);
1089 case SYM_NTP_SERVER:
1090 PARSE_IAL(ntp_server);
1093 #ifdef YORK_EX_OPTION
1095 PARSE_STR(exec_file);
1100 PARSE_UINT(msg_size);
1101 if (hp->msg_size < BP_MINPKTSZ ||
1102 hp->msg_size > MAX_MSG_SIZE)
1107 PARSE_UINT(min_wait);
1110 /* XXX - Add new tags here */
1113 return E_UNKNOWN_SYMBOL;
1115 } /* switch symbolcode */
1127 * Read a string from the buffer indirectly pointed to through "src" and
1128 * move it into the buffer pointed to by "dest". A pointer to the maximum
1129 * allowable length of the string (including null-terminator) is passed as
1130 * "length". The actual length of the string which was read is returned in
1131 * the unsigned integer pointed to by "length". This value is the same as
1132 * that which would be returned by applying the strlen() function on the
1133 * destination string (i.e the terminating null is not counted as a
1134 * character). Trailing whitespace is removed from the string. For
1135 * convenience, the function returns the new value of "dest".
1137 * The string is read until the maximum number of characters, an unquoted
1138 * colon (:), or a null character is read. The return string in "dest" is
1143 get_string(char **src, char *dest, unsigned *length)
1145 int n, len, quoteflag;
1150 while ((n < len) && (**src)) {
1151 if (!quoteflag && (**src == ':')) {
1156 quoteflag = !quoteflag;
1159 if (**src == '\\') {
1165 *dest++ = *(*src)++;
1170 * Remove that troublesome trailing whitespace. . .
1172 while ((n > 0) && isspace(dest[-1])) {
1185 * Read the string indirectly pointed to by "src", update the caller's
1186 * pointer, and return a pointer to a malloc'ed shared_string structure
1187 * containing the string.
1189 * The string is read using the same rules as get_string() above.
1192 PRIVATE struct shared_string *
1193 get_shared_string(char **src)
1195 char retstring[MAXSTRINGLEN];
1196 struct shared_string *s;
1199 length = sizeof(retstring);
1200 (void) get_string(src, retstring, &length);
1202 s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1205 strcpy(s->string, retstring);
1213 * Load RFC1048 generic information directly into a memory buffer.
1215 * "src" indirectly points to the ASCII representation of the generic data.
1216 * "dest" points to a string structure which is updated to point to a new
1217 * string with the new data appended to the old string. The old string is
1220 * The given tag value is inserted with the new data.
1222 * The data may be represented as either a stream of hexadecimal numbers
1223 * representing bytes (any or all bytes may optionally start with '0x' and
1224 * be separated with periods ".") or as a quoted string of ASCII
1225 * characters (the quotes are required).
1229 process_generic(char **src, struct shared_bindata **dest, u_int tagvalue)
1231 byte tmpbuf[MAXBUFLEN];
1233 struct shared_bindata *bdata;
1234 u_int newlength, oldlength;
1237 *str++ = (tagvalue & 0xFF); /* Store tag value */
1238 str++; /* Skip over length field */
1239 if ((*src)[0] == '"') { /* ASCII data */
1240 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
1241 (void) get_string(src, (char *) str, &newlength);
1242 newlength++; /* null terminator */
1243 } else { /* Numeric data */
1245 while (newlength < sizeof(tmpbuf) - 2) {
1246 if (interp_byte(src, str++) < 0)
1254 if ((*src)[0] != ':')
1257 tmpbuf[1] = (newlength & 0xFF);
1258 oldlength = ((*dest)->length);
1259 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1260 + oldlength + newlength + 1);
1261 if (oldlength > 0) {
1262 bcopy((*dest)->data, bdata->data, oldlength);
1264 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1265 bdata->length = oldlength + newlength + 2;
1266 bdata->linkcount = 1;
1277 * Verify that the given string makes sense as a hostname (according to
1278 * Appendix 1, page 29 of RFC882).
1280 * Return TRUE for good names, FALSE otherwise.
1284 goodname(char *hostname)
1287 if (!isalpha(*hostname++)) { /* First character must be a letter */
1290 while (isalnum(*hostname) ||
1291 (*hostname == '-') ||
1292 (*hostname == '_') )
1294 hostname++; /* Alphanumeric or a hyphen */
1296 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
1299 if (*hostname == '\0') {/* Done? */
1302 } while (*hostname++ == '.'); /* Dot, loop for next label */
1304 return FALSE; /* If it's not a dot, lose */
1310 * Null compare function -- always returns FALSE so an element is always
1311 * inserted into a hash table (i.e. there is never a collision with an
1312 * existing element).
1316 nullcmp(hash_datum *d1, hash_datum *d2)
1323 * Function for comparing a string with the hostname field of a host
1328 nmcmp(hash_datum *d1, hash_datum *d2)
1330 char *name = (char *) d1; /* XXX - OK? */
1331 struct host *hp = (struct host *) d2;
1333 return !strcmp(name, hp->hostname->string);
1338 * Compare function to determine whether two hardware addresses are
1339 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1342 * If the hardware addresses of "host1" and "host2" are identical, but
1343 * they are on different IP subnets, this function returns FALSE.
1345 * This function is used when inserting elements into the hardware address
1350 hwinscmp(hash_datum *d1, hash_datum *d2)
1352 struct host *host1 = (struct host *) d1;
1353 struct host *host2 = (struct host *) d2;
1355 if (host1->htype != host2->htype) {
1358 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1361 /* XXX - Is the subnet_mask field set yet? */
1362 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1363 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1364 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1374 * Macros for use in the function below:
1377 #define DUP_COPY(MEMBER) do \
1379 if (!hp->flags.MEMBER) { \
1380 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1381 hp->MEMBER = hp2->MEMBER; \
1386 #define DUP_LINK(MEMBER) do \
1388 if (!hp->flags.MEMBER) { \
1389 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1390 assert(hp2->MEMBER); \
1391 hp->MEMBER = hp2->MEMBER; \
1392 (hp->MEMBER->linkcount)++; \
1398 * Process the "similar entry" symbol.
1400 * The host specified as the value of the "tc" symbol is used as a template
1401 * for the current host entry. Symbol values not explicitly set in the
1402 * current host entry are inferred from the template entry.
1405 fill_defaults(struct host *hp, char **src)
1407 unsigned int tlen, hashcode;
1409 char tstring[MAXSTRINGLEN];
1411 tlen = sizeof(tstring);
1412 (void) get_string(src, tstring, &tlen);
1413 hashcode = hash_HashFunction((u_char *) tstring, tlen);
1414 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1417 report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1421 DUP_LINK(cookie_server);
1422 DUP_LINK(domain_server);
1424 /* haddr not copied */
1428 DUP_LINK(impress_server);
1429 /* iaddr not copied */
1430 DUP_LINK(log_server);
1431 DUP_LINK(lpr_server);
1432 DUP_LINK(name_server);
1433 DUP_LINK(rlp_server);
1435 DUP_COPY(subnet_mask);
1436 DUP_COPY(time_offset);
1437 DUP_LINK(time_server);
1439 if (!hp->flags.vm_cookie) {
1440 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1441 bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1444 if (!hp->flags.name_switch) {
1445 if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1446 hp->flags.send_name = hp2->flags.send_name;
1449 if (!hp->flags.bootsize) {
1450 if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1451 hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1452 hp->bootsize = hp2->bootsize;
1455 DUP_COPY(bootserver);
1458 DUP_LINK(dump_file);
1459 DUP_LINK(domain_name);
1461 DUP_COPY(swap_server);
1462 DUP_LINK(root_path);
1463 DUP_LINK(exten_file);
1465 DUP_COPY(reply_addr);
1467 DUP_LINK(nis_domain);
1468 DUP_LINK(nis_server);
1469 DUP_LINK(ntp_server);
1471 #ifdef YORK_EX_OPTION
1472 DUP_LINK(exec_file);
1478 /* XXX - Add new tags here */
1489 * This function adjusts the caller's pointer to point just past the
1490 * first-encountered colon. If it runs into a null character, it leaves
1491 * the pointer pointing to it.
1500 while (*t && (*t != ':')) {
1513 * This function adjusts the caller's pointer to point to the first
1514 * non-whitespace character. If it runs into a null character, it leaves
1515 * the pointer pointing to it.
1519 eat_whitespace(char **s)
1524 while (*t && isspace(*t)) {
1533 * This function converts the given string to all lowercase.
1553 * In many of the functions which follow, a parameter such as "src" or
1554 * "symbol" is passed as a pointer to a pointer to something. This is
1555 * done for the purpose of letting the called function update the
1556 * caller's copy of the parameter (i.e. to effect call-by-reference
1557 * parameter passing). The value of the actual parameter is only used
1558 * to locate the real parameter of interest and then update this indirect
1561 * I'm sure somebody out there won't like this. . . .
1562 * (Yea, because it usually makes code slower... -gwr)
1569 * "src" points to a character pointer which points to an ASCII string of
1570 * whitespace-separated IP addresses. A pointer to an in_addr_list
1571 * structure containing the list of addresses is returned. NULL is
1572 * returned if no addresses were found at all. The pointer pointed to by
1573 * "src" is updated to point to the first non-address (illegal) character.
1576 PRIVATE struct in_addr_list *
1577 get_addresses(char **src)
1579 struct in_addr tmpaddrlist[MAXINADDRS];
1580 struct in_addr *address1, *address2;
1581 struct in_addr_list *result;
1582 unsigned addrcount, totalsize;
1584 address1 = tmpaddrlist;
1585 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1586 while (isspace(**src) || (**src == ',')) {
1589 if (!**src) { /* Quit if nothing more */
1592 if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1595 address1++; /* Point to next address slot */
1597 if (addrcount < 1) {
1600 totalsize = sizeof(struct in_addr_list)
1601 + (addrcount - 1) * sizeof(struct in_addr);
1602 result = (struct in_addr_list *) smalloc(totalsize);
1603 result->linkcount = 1;
1604 result->addrcount = addrcount;
1605 address1 = tmpaddrlist;
1606 address2 = result->addr;
1607 for (; addrcount > 0; addrcount--) {
1608 address2->s_addr = address1->s_addr;
1619 * prs_inetaddr(src, result)
1621 * "src" is a value-result parameter; the pointer it points to is updated
1622 * to point to the next data position. "result" points to an unsigned long
1623 * in which an address is returned.
1625 * This function parses the IP address string in ASCII "dot notation" pointed
1626 * to by (*src) and places the result (in network byte order) in the unsigned
1627 * long pointed to by "result". For malformed addresses, -1 is returned,
1628 * (*src) points to the first illegal character, and the unsigned long pointed
1629 * to by "result" is unchanged. Successful calls return 0.
1633 prs_inetaddr(char **src, u_int32 *result)
1635 char tmpstr[MAXSTRINGLEN];
1637 u_int32 parts[4], *pp;
1641 /* Leading alpha char causes IP addr lookup. */
1642 if (isalpha(**src)) {
1643 /* Lookup IP address. */
1646 while ((isalnum(*s) || (*s == '.') ||
1647 (*s == '-') || (*s == '_') ) &&
1648 (t < &tmpstr[MAXSTRINGLEN - 1]) )
1653 n = lookup_ipa(tmpstr, result);
1655 report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1660 * Parse an address in Internet format:
1662 * a.b.c (with c treated as 16-bits)
1663 * a.b (with b treated as 24 bits)
1667 /* If it's not a digit, return error. */
1668 if (!isdigit(**src))
1670 *pp++ = get_u_long(src);
1672 if (pp < (parts + 4)) {
1679 /* This is handled by the caller. */
1680 if (**src && !(isspace(**src) || (**src == ':'))) {
1686 * Construct the address according to
1687 * the number of parts specified.
1691 case 1: /* a -- 32 bits */
1694 case 2: /* a.b -- 8.24 bits */
1695 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1697 case 3: /* a.b.c -- 8.8.16 bits */
1698 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1699 (parts[2] & 0xFFFF);
1701 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1702 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1703 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1708 *result = htonl(value);
1715 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1716 * string. This string is interpreted as a hardware address and returned
1717 * as a pointer to the actual hardware address, represented as an array of
1720 * The ASCII string must have the proper number of digits for the specified
1721 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1722 * Two-digit sequences (bytes) may be separated with periods (.) and/or
1723 * prefixed with '0x' for readability, but this is not required.
1725 * For bad addresses, the pointer which "src" points to is updated to point
1726 * to the start of the first two-digit sequence which was bad, and the
1727 * function returns a NULL pointer.
1731 prs_haddr(char **src, u_int htype)
1733 static byte haddr[MAXHADDRLEN];
1735 char tmpstr[MAXSTRINGLEN];
1740 hal = haddrlength(htype); /* Get length of this address type */
1742 report(LOG_ERR, "Invalid addr type for HW addr parse");
1745 tmplen = sizeof(tmpstr);
1746 get_string(src, tmpstr, &tmplen);
1749 /* If it's a valid host name, try to lookup the HW address. */
1751 /* Lookup Hardware Address for hostname. */
1752 if ((hap = lookup_hwa(p, htype)) != NULL)
1753 return hap; /* success */
1754 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1755 /* OK, assume it must be numeric. */
1759 while (hap < haddr + hal) {
1760 if ((*p == '.') || (*p == ':'))
1762 if (interp_byte(&p, hap++) < 0) {
1772 * "src" is a pointer to a character pointer which in turn points to a
1773 * hexadecimal ASCII representation of a byte. This byte is read, the
1774 * character pointer is updated, and the result is deposited into the
1775 * byte pointed to by "retbyte".
1777 * The usual '0x' notation is allowed but not required. The number must be
1778 * a two digit hexadecimal number. If the number is invalid, "src" and
1779 * "retbyte" are left untouched and -1 is returned as the function value.
1780 * Successful calls return 0.
1784 interp_byte(char **src, byte *retbyte)
1788 if ((*src)[0] == '0' &&
1789 ((*src)[1] == 'x' ||
1790 (*src)[1] == 'X')) {
1791 (*src) += 2; /* allow 0x for hex, but don't require it */
1793 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1796 if (sscanf(*src, "%2x", &v) != 1) {
1800 *retbyte = (byte) (v & 0xFF);
1807 * The parameter "src" points to a character pointer which points to an
1808 * ASCII string representation of an unsigned number. The number is
1809 * returned as an unsigned long and the character pointer is updated to
1810 * point to the first illegal character.
1814 get_u_long(char **src)
1816 u_int32 value, base;
1820 * Collect number up to first illegal character. Values are specified
1821 * as for C: 0x=hex, 0=octal, other=decimal.
1829 if (**src == 'x' || **src == 'X') {
1833 while ((c = **src)) {
1835 value = (value * base) + (c - '0');
1839 if (base == 16 && isxdigit(c)) {
1840 value = (value << 4) + ((c & ~32) + 10 - 'A');
1852 * Routines for deletion of data associated with the main data structure.
1857 * Frees the entire host data structure given. Does nothing if the passed
1862 free_host(hash_datum *hmp)
1864 struct host *hostptr = (struct host *) hmp;
1865 if (hostptr == NULL)
1867 assert(hostptr->linkcount > 0);
1868 if (--(hostptr->linkcount))
1869 return; /* Still has references */
1870 del_iplist(hostptr->cookie_server);
1871 del_iplist(hostptr->domain_server);
1872 del_iplist(hostptr->gateway);
1873 del_iplist(hostptr->impress_server);
1874 del_iplist(hostptr->log_server);
1875 del_iplist(hostptr->lpr_server);
1876 del_iplist(hostptr->name_server);
1877 del_iplist(hostptr->rlp_server);
1878 del_iplist(hostptr->time_server);
1879 del_iplist(hostptr->nis_server);
1880 del_iplist(hostptr->ntp_server);
1883 * XXX - Add new tags here
1884 * (if the value is an IP list)
1887 del_string(hostptr->hostname);
1888 del_string(hostptr->homedir);
1889 del_string(hostptr->bootfile);
1890 del_string(hostptr->tftpdir);
1891 del_string(hostptr->root_path);
1892 del_string(hostptr->domain_name);
1893 del_string(hostptr->dump_file);
1894 del_string(hostptr->exten_file);
1895 del_string(hostptr->nis_domain);
1897 #ifdef YORK_EX_OPTION
1898 del_string(hostptr->exec_file);
1902 * XXX - Add new tags here
1903 * (if it is a shared string)
1906 del_bindata(hostptr->generic);
1907 free((char *) hostptr);
1913 * Decrements the linkcount on the given IP address data structure. If the
1914 * linkcount goes to zero, the memory associated with the data is freed.
1918 del_iplist(struct in_addr_list *iplist)
1921 if (!(--(iplist->linkcount))) {
1922 free((char *) iplist);
1930 * Decrements the linkcount on a string data structure. If the count
1931 * goes to zero, the memory associated with the string is freed. Does
1932 * nothing if the passed pointer is NULL.
1936 del_string(struct shared_string *stringptr)
1939 if (!(--(stringptr->linkcount))) {
1940 free((char *) stringptr);
1948 * Decrements the linkcount on a shared_bindata data structure. If the
1949 * count goes to zero, the memory associated with the data is freed. Does
1950 * nothing if the passed pointer is NULL.
1954 del_bindata(struct shared_bindata *dataptr)
1957 if (!(--(dataptr->linkcount))) {
1958 free((char *) dataptr);
1966 /* smalloc() -- safe malloc()
1968 * Always returns a valid pointer (if it returns at all). The allocated
1969 * memory is initialized to all zeros. If malloc() returns an error, a
1970 * message is printed using the report() function and the program aborts
1971 * with a status of 1.
1975 smalloc(unsigned nbytes)
1979 retvalue = malloc(nbytes);
1981 report(LOG_ERR, "malloc() failure -- exiting");
1984 bzero(retvalue, nbytes);
1990 * Compare function to determine whether two hardware addresses are
1991 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1994 * This function is used when retrieving elements from the hardware address
1999 hwlookcmp(hash_datum *d1, hash_datum *d2)
2001 struct host *host1 = (struct host *) d1;
2002 struct host *host2 = (struct host *) d2;
2004 if (host1->htype != host2->htype) {
2007 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2015 * Compare function for doing IP address hash table lookup.
2019 iplookcmp(hash_datum *d1, hash_datum *d2)
2021 struct host *host1 = (struct host *) d1;
2022 struct host *host2 = (struct host *) d2;
2024 return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2031 * c-argdecl-indent: 4
2032 * c-continued-statement-offset: 4
2033 * c-continued-brace-offset: -4
2034 * c-label-offset: -4