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 extern boolean iplookcmp();
223 boolean nmcmp(hash_datum *, hash_datum *);
228 del_string(struct shared_string *);
230 del_bindata(struct shared_bindata *);
232 del_iplist(struct in_addr_list *);
234 eat_whitespace(char **);
236 eval_symbol(char **, struct host *);
238 fill_defaults(struct host *, char **);
240 free_host(hash_datum *);
241 PRIVATE struct in_addr_list *
242 get_addresses(char **);
243 PRIVATE struct shared_string *
244 get_shared_string(char **);
246 get_string(char **, char *, u_int *);
252 hwinscmp(hash_datum *, hash_datum *);
254 interp_byte(char **, byte *);
258 nullcmp(hash_datum *, hash_datum *);
260 process_entry(struct host *, char *);
262 process_generic(char **, struct shared_bindata **, u_int);
264 prs_haddr(char **, u_int);
266 prs_inetaddr(char **, u_int32 *);
268 read_entry(FILE *, char *, u_int *);
274 * Vendor magic cookies for CMU and RFC1048
276 u_char vm_cmu[4] = VM_CMU;
277 u_char vm_rfc1048[4] = VM_RFC1048;
282 hash_tbl *hwhashtable;
283 hash_tbl *iphashtable;
284 hash_tbl *nmhashtable;
287 * Allocate hash tables for hardware address, ip address, and hostname
288 * (shared by bootpd and bootpef)
293 hwhashtable = hash_Init(HASHTABLESIZE);
294 iphashtable = hash_Init(HASHTABLESIZE);
295 nmhashtable = hash_Init(HASHTABLESIZE);
296 if (!(hwhashtable && iphashtable && nmhashtable)) {
297 report(LOG_ERR, "Unable to allocate hash tables.");
304 * Read bootptab database file. Avoid rereading the file if the
305 * write date hasn't changed since the last time we read it.
315 unsigned hashcode, buflen;
316 static char buffer[MAXENTRYLEN];
319 * Check the last modification time.
321 if (stat(bootptab, &st) < 0) {
322 report(LOG_ERR, "stat on \"%s\": %s",
323 bootptab, get_errmsg());
329 strcpy(timestr, ctime(&(st.st_mtime)));
330 /* zap the newline */
332 report(LOG_INFO, "bootptab mtime: %s",
337 (st.st_mtime == modtime) &&
340 * hasn't been modified or deleted yet.
345 report(LOG_INFO, "reading %s\"%s\"",
346 (modtime != 0L) ? "new " : "",
350 * Open bootptab file.
352 if ((fp = fopen(bootptab, "r")) == NULL) {
353 report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
357 * Record file modification time.
359 if (fstat(fileno(fp), &st) < 0) {
360 report(LOG_ERR, "fstat: %s", get_errmsg());
364 modtime = st.st_mtime;
367 * Entirely erase all hash tables.
369 hash_Reset(hwhashtable, free_host);
370 hash_Reset(iphashtable, free_host);
371 hash_Reset(nmhashtable, free_host);
376 buflen = sizeof(buffer);
377 read_entry(fp, buffer, &buflen);
378 if (buflen == 0) { /* More entries? */
381 hp = (struct host *) smalloc(sizeof(struct host));
382 bzero((char *) hp, sizeof(*hp));
383 /* the link count it zero */
386 * Get individual info
388 if (process_entry(hp, buffer) < 0) {
390 free_host((hash_datum *) hp);
394 * If this is not a dummy entry, and the IP or HW
395 * address is not yet set, try to get them here.
396 * Dummy entries have . as first char of name.
398 if (goodname(hp->hostname->string)) {
399 char *hn = hp->hostname->string;
401 if (hp->flags.iaddr == 0) {
402 if (lookup_ipa(hn, &value)) {
403 report(LOG_ERR, "can not get IP addr for %s", hn);
404 report(LOG_ERR, "(dummy names should start with '.')");
406 hp->iaddr.s_addr = value;
407 hp->flags.iaddr = TRUE;
410 /* Set default subnet mask. */
411 if (hp->flags.subnet_mask == 0) {
412 if (lookup_netmask(hp->iaddr.s_addr, &value)) {
413 report(LOG_ERR, "can not get netmask for %s", hn);
415 hp->subnet_mask.s_addr = value;
416 hp->flags.subnet_mask = TRUE;
420 if (hp->flags.iaddr) {
423 /* Register by HW addr if known. */
424 if (hp->flags.htype && hp->flags.haddr) {
425 /* We will either insert it or free it. */
427 hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
428 if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
429 report(LOG_NOTICE, "duplicate %s address: %s",
431 haddrtoa(hp->haddr, haddrlength(hp->htype)));
432 free_host((hash_datum *) hp);
436 /* Register by IP addr if known. */
437 if (hp->flags.iaddr) {
438 hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
439 if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
441 "hash_Insert() failed on IP address insertion");
443 /* Just inserted the host struct in a new hash list. */
447 /* Register by Name (always known) */
448 hashcode = hash_HashFunction((u_char *) hp->hostname->string,
449 strlen(hp->hostname->string));
450 if (hash_Insert(nmhashtable, hashcode, nullcmp,
451 hp->hostname->string, hp) < 0) {
453 "hash_Insert() failed on insertion of hostname: \"%s\"",
454 hp->hostname->string);
456 /* Just inserted the host struct in a new hash list. */
465 report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
466 nentries, nhosts, bootptab);
473 * Read an entire host entry from the file pointed to by "fp" and insert it
474 * into the memory pointed to by "buffer". Leading whitespace and comments
475 * starting with "#" are ignored (removed). Backslashes (\) always quote
476 * the next character except that newlines preceded by a backslash cause
477 * line-continuation onto the next line. The entry is terminated by a
478 * newline character which is not preceded by a backslash. Sequences
479 * surrounded by double quotes are taken literally (including newlines, but
482 * The "bufsiz" parameter points to an unsigned int which specifies the
483 * maximum permitted buffer size. Upon return, this value will be replaced
484 * with the actual length of the entry (not including the null terminator).
486 * This code is a little scary. . . . I don't like using gotos in C
487 * either, but I first wrote this as an FSM diagram and gotos seemed like
488 * the easiest way to implement it. Maybe later I'll clean it up.
492 read_entry(fp, buffer, bufsiz)
502 * Eat whitespace, blank lines, and comment lines.
507 goto done; /* Exit if end-of-file */
510 goto top; /* Skip over whitespace */
513 while (TRUE) { /* Eat comments after # */
516 goto done; /* Exit if end-of-file */
519 goto top; /* Try to read the next line */
523 ungetc(c, fp); /* Other character, push it back to reprocess it */
527 * Now we're actually reading a data entry. Get each character and
528 * assemble it into the data buffer, processing special characters like
529 * double quotes (") and backslashes (\).
537 goto done; /* Exit on EOF or newline */
539 c = fgetc(fp); /* Backslash, read a new character */
541 goto done; /* Exit on EOF */
543 *buffer++ = c; /* Store the literal character */
545 if (length < *bufsiz - 1) {
551 *buffer++ = '"'; /* Store double-quote */
553 if (length >= *bufsiz - 1) {
556 while (TRUE) { /* Special quote processing loop */
560 goto done; /* Exit on EOF . . . */
562 *buffer++ = '"';/* Store matching quote */
564 if (length < *bufsiz - 1) {
565 goto mainloop; /* And continue main loop */
570 if ((c = fgetc(fp)) < 0) { /* Backslash */
571 goto done; /* EOF. . . .*/
575 *buffer++ = c; /* Other character, store it */
577 if (length >= *bufsiz - 1) {
583 *buffer++ = c; /* Store colons */
585 if (length >= *bufsiz - 1) {
588 do { /* But remove whitespace after them */
590 if ((c < 0) || (c == '\n')) {
593 } while (isspace(c)); /* Skip whitespace */
595 if (c == '\\') { /* Backslash quotes next character */
601 goto top; /* Backslash-newline continuation */
604 /* FALLTHROUGH if "other" character */
606 *buffer++ = c; /* Store other characters */
608 if (length >= *bufsiz - 1) {
612 goto mainloop; /* Keep going */
615 *buffer = '\0'; /* Terminate string */
616 *bufsiz = length; /* Tell the caller its length */
622 * Parse out all the various tags and parameters in the host entry pointed
623 * to by "src". Stuff all the data into the appropriate fields of the
624 * host structure pointed to by "host". If there is any problem with the
625 * entry, an error message is reported via report(), no further processing
626 * is done, and -1 is returned. Successful calls return 0.
628 * (Some errors probably shouldn't be so completely fatal. . . .)
632 process_entry(host, src)
639 if (!host || *src == '\0') {
642 host->hostname = get_shared_string(&src);
644 /* Be more liberal for the benefit of dummy tag names. */
645 if (!goodname(host->hostname->string)) {
646 report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
647 del_string(host->hostname);
651 current_hostname = host->hostname->string;
654 retval = eval_symbol(&src, host);
655 if (retval == SUCCESS) {
659 if (retval == E_END_OF_ENTRY) {
660 /* The default subnet mask is set in readtab() */
663 /* Some kind of error. */
668 case E_UNKNOWN_SYMBOL:
669 msg = "unknown symbol";
672 msg = "bad INET address";
675 msg = "bad hardware address";
678 msg = "bad longword value";
681 msg = "bad HW address type";
684 msg = "bad pathname (need leading '/')";
690 msg = "unknown error";
693 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
694 current_hostname, current_tagname, msg);
701 * Macros for use in the function below:
704 /* Parse one INET address stored directly in MEMBER. */
705 #define PARSE_IA1(MEMBER) do \
707 if (optype == OP_BOOLEAN) \
708 return E_SYNTAX_ERROR; \
709 hp->flags.MEMBER = FALSE; \
710 if (optype == OP_ADDITION) { \
711 if (prs_inetaddr(symbol, &value) < 0) \
712 return E_BAD_IPADDR; \
713 hp->MEMBER.s_addr = value; \
714 hp->flags.MEMBER = TRUE; \
718 /* Parse a list of INET addresses pointed to by MEMBER */
719 #define PARSE_IAL(MEMBER) do \
721 if (optype == OP_BOOLEAN) \
722 return E_SYNTAX_ERROR; \
723 if (hp->flags.MEMBER) { \
724 hp->flags.MEMBER = FALSE; \
725 assert(hp->MEMBER); \
726 del_iplist(hp->MEMBER); \
729 if (optype == OP_ADDITION) { \
730 hp->MEMBER = get_addresses(symbol); \
731 if (hp->MEMBER == NULL) \
732 return E_SYNTAX_ERROR; \
733 hp->flags.MEMBER = TRUE; \
737 /* Parse a shared string pointed to by MEMBER */
738 #define PARSE_STR(MEMBER) do \
740 if (optype == OP_BOOLEAN) \
741 return E_SYNTAX_ERROR; \
742 if (hp->flags.MEMBER) { \
743 hp->flags.MEMBER = FALSE; \
744 assert(hp->MEMBER); \
745 del_string(hp->MEMBER); \
748 if (optype == OP_ADDITION) { \
749 hp->MEMBER = get_shared_string(symbol); \
750 if (hp->MEMBER == NULL) \
751 return E_SYNTAX_ERROR; \
752 hp->flags.MEMBER = TRUE; \
756 /* Parse an unsigned integer value for MEMBER */
757 #define PARSE_UINT(MEMBER) do \
759 if (optype == OP_BOOLEAN) \
760 return E_SYNTAX_ERROR; \
761 hp->flags.MEMBER = FALSE; \
762 if (optype == OP_ADDITION) { \
763 value = get_u_long(symbol); \
764 hp->MEMBER = value; \
765 hp->flags.MEMBER = TRUE; \
770 * Evaluate the two-character tag symbol pointed to by "symbol" and place
771 * the data in the structure pointed to by "hp". The pointer pointed to
772 * by "symbol" is updated to point past the source string (but may not
773 * point to the next tag entry).
775 * Obviously, this need a few more comments. . . .
778 eval_symbol(symbol, hp)
782 char tmpstr[MAXSTRINGLEN];
784 struct symbolmap *symbolptr;
789 int optype; /* Indicates boolean, addition, or deletion */
791 eat_whitespace(symbol);
793 /* Make sure this is set before returning. */
794 current_tagname[0] = (*symbol)[0];
795 current_tagname[1] = (*symbol)[1];
796 current_tagname[2] = 0;
798 if ((*symbol)[0] == '\0') {
799 return E_END_OF_ENTRY;
801 if ((*symbol)[0] == ':') {
804 if ((*symbol)[0] == 'T') { /* generic symbol */
806 value = get_u_long(symbol);
807 snprintf(current_tagname, sizeof(current_tagname),
809 eat_whitespace(symbol);
810 if ((*symbol)[0] != '=') {
811 return E_SYNTAX_ERROR;
814 if (!(hp->generic)) {
815 hp->generic = (struct shared_bindata *)
816 smalloc(sizeof(struct shared_bindata));
818 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
819 return E_SYNTAX_ERROR;
820 hp->flags.generic = TRUE;
824 * Determine the type of operation to be done on this symbol
826 switch ((*symbol)[2]) {
828 optype = OP_ADDITION;
831 optype = OP_DELETION;
838 return E_SYNTAX_ERROR;
841 symbolptr = symbol_list;
842 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
843 for (i = 0; i < numsymbols; i++) {
844 if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
845 ((symbolptr->symbol)[1] == (*symbol)[1])) {
850 if (i >= numsymbols) {
851 return E_UNKNOWN_SYMBOL;
854 * Skip past the = or @ character (to point to the data) if this
855 * isn't a boolean operation. For boolean operations, just skip
856 * over the two-character tag symbol (and nothing else. . . .).
858 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
860 eat_whitespace(symbol);
862 /* The cases below are in order by symbolcode value. */
863 switch (symbolptr->symbolcode) {
869 case SYM_COOKIE_SERVER:
870 PARSE_IAL(cookie_server);
873 case SYM_DOMAIN_SERVER:
874 PARSE_IAL(domain_server);
882 if (optype == OP_BOOLEAN)
883 return E_SYNTAX_ERROR;
884 hp->flags.haddr = FALSE;
885 if (optype == OP_ADDITION) {
886 /* Default the HW type to Ethernet */
887 if (hp->flags.htype == 0) {
888 hp->flags.htype = TRUE;
889 hp->htype = HTYPE_ETHERNET;
891 tmphaddr = prs_haddr(symbol, hp->htype);
894 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
895 hp->flags.haddr = TRUE;
904 if (optype == OP_BOOLEAN)
905 return E_SYNTAX_ERROR;
906 hp->flags.htype = FALSE;
907 if (optype == OP_ADDITION) {
908 value = 0L; /* Assume an illegal value */
909 eat_whitespace(symbol);
910 if (isdigit(**symbol)) {
911 value = get_u_long(symbol);
913 len = sizeof(tmpstr);
914 (void) get_string(symbol, tmpstr, &len);
916 numsymbols = sizeof(htnamemap) /
917 sizeof(struct htypename);
918 for (i = 0; i < numsymbols; i++) {
919 if (!strcmp(htnamemap[i].name, tmpstr)) {
923 if (i < numsymbols) {
924 value = htnamemap[i].htype;
927 if (value >= hwinfocnt) {
928 return E_BAD_HWATYPE;
930 hp->htype = (byte) (value & 0xFF);
931 hp->flags.htype = TRUE;
935 case SYM_IMPRESS_SERVER:
936 PARSE_IAL(impress_server);
944 PARSE_IAL(log_server);
948 PARSE_IAL(lpr_server);
951 case SYM_NAME_SERVER:
952 PARSE_IAL(name_server);
956 PARSE_IAL(rlp_server);
959 case SYM_SUBNET_MASK:
960 PARSE_IA1(subnet_mask);
963 case SYM_TIME_OFFSET:
964 if (optype == OP_BOOLEAN)
965 return E_SYNTAX_ERROR;
966 hp->flags.time_offset = FALSE;
967 if (optype == OP_ADDITION) {
968 len = sizeof(tmpstr);
969 (void) get_string(symbol, tmpstr, &len);
970 if (!strncmp(tmpstr, "auto", 4)) {
971 hp->time_offset = secondswest;
973 if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
974 return E_BAD_LONGWORD;
975 hp->time_offset = timeoff;
977 hp->flags.time_offset = TRUE;
981 case SYM_TIME_SERVER:
982 PARSE_IAL(time_server);
985 case SYM_VENDOR_MAGIC:
986 if (optype == OP_BOOLEAN)
987 return E_SYNTAX_ERROR;
988 hp->flags.vm_cookie = FALSE;
989 if (optype == OP_ADDITION) {
990 if (strncmp(*symbol, "auto", 4)) {
991 /* The string is not "auto" */
992 if (!strncmp(*symbol, "rfc", 3)) {
993 bcopy(vm_rfc1048, hp->vm_cookie, 4);
994 } else if (!strncmp(*symbol, "cmu", 3)) {
995 bcopy(vm_cmu, hp->vm_cookie, 4);
997 if (!isdigit(**symbol))
999 if (prs_inetaddr(symbol, &value) < 0)
1000 return E_BAD_IPADDR;
1001 bcopy(&value, hp->vm_cookie, 4);
1003 hp->flags.vm_cookie = TRUE;
1008 case SYM_SIMILAR_ENTRY:
1011 fill_defaults(hp, symbol);
1014 return E_SYNTAX_ERROR;
1018 case SYM_NAME_SWITCH:
1021 return E_SYNTAX_ERROR;
1023 hp->flags.send_name = FALSE;
1024 hp->flags.name_switch = FALSE;
1027 hp->flags.send_name = TRUE;
1028 hp->flags.name_switch = TRUE;
1036 if (!strncmp(*symbol, "auto", 4)) {
1037 hp->flags.bootsize = TRUE;
1038 hp->flags.bootsize_auto = TRUE;
1040 hp->bootsize = (unsigned int) get_u_long(symbol);
1041 hp->flags.bootsize = TRUE;
1042 hp->flags.bootsize_auto = FALSE;
1046 hp->flags.bootsize = FALSE;
1049 hp->flags.bootsize = TRUE;
1050 hp->flags.bootsize_auto = TRUE;
1055 case SYM_BOOT_SERVER:
1056 PARSE_IA1(bootserver);
1061 if ((hp->tftpdir != NULL) &&
1062 (hp->tftpdir->string[0] != '/'))
1063 return E_BAD_PATHNAME;
1067 PARSE_STR(dump_file);
1070 case SYM_DOMAIN_NAME:
1071 PARSE_STR(domain_name);
1074 case SYM_SWAP_SERVER:
1075 PARSE_IA1(swap_server);
1079 PARSE_STR(root_path);
1082 case SYM_EXTEN_FILE:
1083 PARSE_STR(exten_file);
1086 case SYM_REPLY_ADDR:
1087 PARSE_IA1(reply_addr);
1090 case SYM_NIS_DOMAIN:
1091 PARSE_STR(nis_domain);
1094 case SYM_NIS_SERVER:
1095 PARSE_IAL(nis_server);
1098 case SYM_NTP_SERVER:
1099 PARSE_IAL(ntp_server);
1102 #ifdef YORK_EX_OPTION
1104 PARSE_STR(exec_file);
1109 PARSE_UINT(msg_size);
1110 if (hp->msg_size < BP_MINPKTSZ ||
1111 hp->msg_size > MAX_MSG_SIZE)
1116 PARSE_UINT(min_wait);
1119 /* XXX - Add new tags here */
1122 return E_UNKNOWN_SYMBOL;
1124 } /* switch symbolcode */
1136 * Read a string from the buffer indirectly pointed to through "src" and
1137 * move it into the buffer pointed to by "dest". A pointer to the maximum
1138 * allowable length of the string (including null-terminator) is passed as
1139 * "length". The actual length of the string which was read is returned in
1140 * the unsigned integer pointed to by "length". This value is the same as
1141 * that which would be returned by applying the strlen() function on the
1142 * destination string (i.e the terminating null is not counted as a
1143 * character). Trailing whitespace is removed from the string. For
1144 * convenience, the function returns the new value of "dest".
1146 * The string is read until the maximum number of characters, an unquoted
1147 * colon (:), or a null character is read. The return string in "dest" is
1152 get_string(src, dest, length)
1156 int n, len, quoteflag;
1161 while ((n < len) && (**src)) {
1162 if (!quoteflag && (**src == ':')) {
1167 quoteflag = !quoteflag;
1170 if (**src == '\\') {
1176 *dest++ = *(*src)++;
1181 * Remove that troublesome trailing whitespace. . .
1183 while ((n > 0) && isspace(dest[-1])) {
1196 * Read the string indirectly pointed to by "src", update the caller's
1197 * pointer, and return a pointer to a malloc'ed shared_string structure
1198 * containing the string.
1200 * The string is read using the same rules as get_string() above.
1203 PRIVATE struct shared_string *
1204 get_shared_string(src)
1207 char retstring[MAXSTRINGLEN];
1208 struct shared_string *s;
1211 length = sizeof(retstring);
1212 (void) get_string(src, retstring, &length);
1214 s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1217 strcpy(s->string, retstring);
1225 * Load RFC1048 generic information directly into a memory buffer.
1227 * "src" indirectly points to the ASCII representation of the generic data.
1228 * "dest" points to a string structure which is updated to point to a new
1229 * string with the new data appended to the old string. The old string is
1232 * The given tag value is inserted with the new data.
1234 * The data may be represented as either a stream of hexadecimal numbers
1235 * representing bytes (any or all bytes may optionally start with '0x' and
1236 * be separated with periods ".") or as a quoted string of ASCII
1237 * characters (the quotes are required).
1241 process_generic(src, dest, tagvalue)
1243 struct shared_bindata **dest;
1246 byte tmpbuf[MAXBUFLEN];
1248 struct shared_bindata *bdata;
1249 u_int newlength, oldlength;
1252 *str++ = (tagvalue & 0xFF); /* Store tag value */
1253 str++; /* Skip over length field */
1254 if ((*src)[0] == '"') { /* ASCII data */
1255 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
1256 (void) get_string(src, (char *) str, &newlength);
1257 newlength++; /* null terminator */
1258 } else { /* Numeric data */
1260 while (newlength < sizeof(tmpbuf) - 2) {
1261 if (interp_byte(src, str++) < 0)
1269 if ((*src)[0] != ':')
1272 tmpbuf[1] = (newlength & 0xFF);
1273 oldlength = ((*dest)->length);
1274 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1275 + oldlength + newlength + 1);
1276 if (oldlength > 0) {
1277 bcopy((*dest)->data, bdata->data, oldlength);
1279 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1280 bdata->length = oldlength + newlength + 2;
1281 bdata->linkcount = 1;
1292 * Verify that the given string makes sense as a hostname (according to
1293 * Appendix 1, page 29 of RFC882).
1295 * Return TRUE for good names, FALSE otherwise.
1303 if (!isalpha(*hostname++)) { /* First character must be a letter */
1306 while (isalnum(*hostname) ||
1307 (*hostname == '-') ||
1308 (*hostname == '_') )
1310 hostname++; /* Alphanumeric or a hyphen */
1312 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
1315 if (*hostname == '\0') {/* Done? */
1318 } while (*hostname++ == '.'); /* Dot, loop for next label */
1320 return FALSE; /* If it's not a dot, lose */
1326 * Null compare function -- always returns FALSE so an element is always
1327 * inserted into a hash table (i.e. there is never a collision with an
1328 * existing element).
1333 hash_datum *d1, *d2;
1340 * Function for comparing a string with the hostname field of a host
1346 hash_datum *d1, *d2;
1348 char *name = (char *) d1; /* XXX - OK? */
1349 struct host *hp = (struct host *) d2;
1351 return !strcmp(name, hp->hostname->string);
1356 * Compare function to determine whether two hardware addresses are
1357 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1360 * If the hardware addresses of "host1" and "host2" are identical, but
1361 * they are on different IP subnets, this function returns FALSE.
1363 * This function is used when inserting elements into the hardware address
1369 hash_datum *d1, *d2;
1371 struct host *host1 = (struct host *) d1;
1372 struct host *host2 = (struct host *) d2;
1374 if (host1->htype != host2->htype) {
1377 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1380 /* XXX - Is the subnet_mask field set yet? */
1381 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1382 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1383 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1393 * Macros for use in the function below:
1396 #define DUP_COPY(MEMBER) do \
1398 if (!hp->flags.MEMBER) { \
1399 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1400 hp->MEMBER = hp2->MEMBER; \
1405 #define DUP_LINK(MEMBER) do \
1407 if (!hp->flags.MEMBER) { \
1408 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1409 assert(hp2->MEMBER); \
1410 hp->MEMBER = hp2->MEMBER; \
1411 (hp->MEMBER->linkcount)++; \
1417 * Process the "similar entry" symbol.
1419 * The host specified as the value of the "tc" symbol is used as a template
1420 * for the current host entry. Symbol values not explicitly set in the
1421 * current host entry are inferred from the template entry.
1424 fill_defaults(hp, src)
1428 unsigned int tlen, hashcode;
1430 char tstring[MAXSTRINGLEN];
1432 tlen = sizeof(tstring);
1433 (void) get_string(src, tstring, &tlen);
1434 hashcode = hash_HashFunction((u_char *) tstring, tlen);
1435 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1438 report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1442 DUP_LINK(cookie_server);
1443 DUP_LINK(domain_server);
1445 /* haddr not copied */
1449 DUP_LINK(impress_server);
1450 /* iaddr not copied */
1451 DUP_LINK(log_server);
1452 DUP_LINK(lpr_server);
1453 DUP_LINK(name_server);
1454 DUP_LINK(rlp_server);
1456 DUP_COPY(subnet_mask);
1457 DUP_COPY(time_offset);
1458 DUP_LINK(time_server);
1460 if (!hp->flags.vm_cookie) {
1461 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1462 bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1465 if (!hp->flags.name_switch) {
1466 if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1467 hp->flags.send_name = hp2->flags.send_name;
1470 if (!hp->flags.bootsize) {
1471 if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1472 hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1473 hp->bootsize = hp2->bootsize;
1476 DUP_COPY(bootserver);
1479 DUP_LINK(dump_file);
1480 DUP_LINK(domain_name);
1482 DUP_COPY(swap_server);
1483 DUP_LINK(root_path);
1484 DUP_LINK(exten_file);
1486 DUP_COPY(reply_addr);
1488 DUP_LINK(nis_domain);
1489 DUP_LINK(nis_server);
1490 DUP_LINK(ntp_server);
1492 #ifdef YORK_EX_OPTION
1493 DUP_LINK(exec_file);
1499 /* XXX - Add new tags here */
1510 * This function adjusts the caller's pointer to point just past the
1511 * first-encountered colon. If it runs into a null character, it leaves
1512 * the pointer pointing to it.
1522 while (*t && (*t != ':')) {
1535 * This function adjusts the caller's pointer to point to the first
1536 * non-whitespace character. If it runs into a null character, it leaves
1537 * the pointer pointing to it.
1547 while (*t && isspace(*t)) {
1556 * This function converts the given string to all lowercase.
1577 * In many of the functions which follow, a parameter such as "src" or
1578 * "symbol" is passed as a pointer to a pointer to something. This is
1579 * done for the purpose of letting the called function update the
1580 * caller's copy of the parameter (i.e. to effect call-by-reference
1581 * parameter passing). The value of the actual parameter is only used
1582 * to locate the real parameter of interest and then update this indirect
1585 * I'm sure somebody out there won't like this. . . .
1586 * (Yea, because it usually makes code slower... -gwr)
1593 * "src" points to a character pointer which points to an ASCII string of
1594 * whitespace-separated IP addresses. A pointer to an in_addr_list
1595 * structure containing the list of addresses is returned. NULL is
1596 * returned if no addresses were found at all. The pointer pointed to by
1597 * "src" is updated to point to the first non-address (illegal) character.
1600 PRIVATE struct in_addr_list *
1604 struct in_addr tmpaddrlist[MAXINADDRS];
1605 struct in_addr *address1, *address2;
1606 struct in_addr_list *result;
1607 unsigned addrcount, totalsize;
1609 address1 = tmpaddrlist;
1610 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1611 while (isspace(**src) || (**src == ',')) {
1614 if (!**src) { /* Quit if nothing more */
1617 if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1620 address1++; /* Point to next address slot */
1622 if (addrcount < 1) {
1625 totalsize = sizeof(struct in_addr_list)
1626 + (addrcount - 1) * sizeof(struct in_addr);
1627 result = (struct in_addr_list *) smalloc(totalsize);
1628 result->linkcount = 1;
1629 result->addrcount = addrcount;
1630 address1 = tmpaddrlist;
1631 address2 = result->addr;
1632 for (; addrcount > 0; addrcount--) {
1633 address2->s_addr = address1->s_addr;
1644 * prs_inetaddr(src, result)
1646 * "src" is a value-result parameter; the pointer it points to is updated
1647 * to point to the next data position. "result" points to an unsigned long
1648 * in which an address is returned.
1650 * This function parses the IP address string in ASCII "dot notation" pointed
1651 * to by (*src) and places the result (in network byte order) in the unsigned
1652 * long pointed to by "result". For malformed addresses, -1 is returned,
1653 * (*src) points to the first illegal character, and the unsigned long pointed
1654 * to by "result" is unchanged. Successful calls return 0.
1658 prs_inetaddr(src, result)
1662 char tmpstr[MAXSTRINGLEN];
1664 u_int32 parts[4], *pp;
1668 /* Leading alpha char causes IP addr lookup. */
1669 if (isalpha(**src)) {
1670 /* Lookup IP address. */
1673 while ((isalnum(*s) || (*s == '.') ||
1674 (*s == '-') || (*s == '_') ) &&
1675 (t < &tmpstr[MAXSTRINGLEN - 1]) )
1680 n = lookup_ipa(tmpstr, result);
1682 report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1687 * Parse an address in Internet format:
1689 * a.b.c (with c treated as 16-bits)
1690 * a.b (with b treated as 24 bits)
1694 /* If it's not a digit, return error. */
1695 if (!isdigit(**src))
1697 *pp++ = get_u_long(src);
1699 if (pp < (parts + 4)) {
1706 /* This is handled by the caller. */
1707 if (**src && !(isspace(**src) || (**src == ':'))) {
1713 * Construct the address according to
1714 * the number of parts specified.
1718 case 1: /* a -- 32 bits */
1721 case 2: /* a.b -- 8.24 bits */
1722 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1724 case 3: /* a.b.c -- 8.8.16 bits */
1725 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1726 (parts[2] & 0xFFFF);
1728 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1729 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1730 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1735 *result = htonl(value);
1742 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1743 * string. This string is interpreted as a hardware address and returned
1744 * as a pointer to the actual hardware address, represented as an array of
1747 * The ASCII string must have the proper number of digits for the specified
1748 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1749 * Two-digit sequences (bytes) may be separated with periods (.) and/or
1750 * prefixed with '0x' for readability, but this is not required.
1752 * For bad addresses, the pointer which "src" points to is updated to point
1753 * to the start of the first two-digit sequence which was bad, and the
1754 * function returns a NULL pointer.
1758 prs_haddr(src, htype)
1762 static byte haddr[MAXHADDRLEN];
1764 char tmpstr[MAXSTRINGLEN];
1769 hal = haddrlength(htype); /* Get length of this address type */
1771 report(LOG_ERR, "Invalid addr type for HW addr parse");
1774 tmplen = sizeof(tmpstr);
1775 get_string(src, tmpstr, &tmplen);
1778 /* If it's a valid host name, try to lookup the HW address. */
1780 /* Lookup Hardware Address for hostname. */
1781 if ((hap = lookup_hwa(p, htype)) != NULL)
1782 return hap; /* success */
1783 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1784 /* OK, assume it must be numeric. */
1788 while (hap < haddr + hal) {
1789 if ((*p == '.') || (*p == ':'))
1791 if (interp_byte(&p, hap++) < 0) {
1801 * "src" is a pointer to a character pointer which in turn points to a
1802 * hexadecimal ASCII representation of a byte. This byte is read, the
1803 * character pointer is updated, and the result is deposited into the
1804 * byte pointed to by "retbyte".
1806 * The usual '0x' notation is allowed but not required. The number must be
1807 * a two digit hexadecimal number. If the number is invalid, "src" and
1808 * "retbyte" are left untouched and -1 is returned as the function value.
1809 * Successful calls return 0.
1813 interp_byte(src, retbyte)
1819 if ((*src)[0] == '0' &&
1820 ((*src)[1] == 'x' ||
1821 (*src)[1] == 'X')) {
1822 (*src) += 2; /* allow 0x for hex, but don't require it */
1824 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1827 if (sscanf(*src, "%2x", &v) != 1) {
1831 *retbyte = (byte) (v & 0xFF);
1838 * The parameter "src" points to a character pointer which points to an
1839 * ASCII string representation of an unsigned number. The number is
1840 * returned as an unsigned long and the character pointer is updated to
1841 * point to the first illegal character.
1848 u_int32 value, base;
1852 * Collect number up to first illegal character. Values are specified
1853 * as for C: 0x=hex, 0=octal, other=decimal.
1861 if (**src == 'x' || **src == 'X') {
1865 while ((c = **src)) {
1867 value = (value * base) + (c - '0');
1871 if (base == 16 && isxdigit(c)) {
1872 value = (value << 4) + ((c & ~32) + 10 - 'A');
1884 * Routines for deletion of data associated with the main data structure.
1889 * Frees the entire host data structure given. Does nothing if the passed
1897 struct host *hostptr = (struct host *) hmp;
1898 if (hostptr == NULL)
1900 assert(hostptr->linkcount > 0);
1901 if (--(hostptr->linkcount))
1902 return; /* Still has references */
1903 del_iplist(hostptr->cookie_server);
1904 del_iplist(hostptr->domain_server);
1905 del_iplist(hostptr->gateway);
1906 del_iplist(hostptr->impress_server);
1907 del_iplist(hostptr->log_server);
1908 del_iplist(hostptr->lpr_server);
1909 del_iplist(hostptr->name_server);
1910 del_iplist(hostptr->rlp_server);
1911 del_iplist(hostptr->time_server);
1912 del_iplist(hostptr->nis_server);
1913 del_iplist(hostptr->ntp_server);
1916 * XXX - Add new tags here
1917 * (if the value is an IP list)
1920 del_string(hostptr->hostname);
1921 del_string(hostptr->homedir);
1922 del_string(hostptr->bootfile);
1923 del_string(hostptr->tftpdir);
1924 del_string(hostptr->root_path);
1925 del_string(hostptr->domain_name);
1926 del_string(hostptr->dump_file);
1927 del_string(hostptr->exten_file);
1928 del_string(hostptr->nis_domain);
1930 #ifdef YORK_EX_OPTION
1931 del_string(hostptr->exec_file);
1935 * XXX - Add new tags here
1936 * (if it is a shared string)
1939 del_bindata(hostptr->generic);
1940 free((char *) hostptr);
1946 * Decrements the linkcount on the given IP address data structure. If the
1947 * linkcount goes to zero, the memory associated with the data is freed.
1952 struct in_addr_list *iplist;
1955 if (!(--(iplist->linkcount))) {
1956 free((char *) iplist);
1964 * Decrements the linkcount on a string data structure. If the count
1965 * goes to zero, the memory associated with the string is freed. Does
1966 * nothing if the passed pointer is NULL.
1970 del_string(stringptr)
1971 struct shared_string *stringptr;
1974 if (!(--(stringptr->linkcount))) {
1975 free((char *) stringptr);
1983 * Decrements the linkcount on a shared_bindata data structure. If the
1984 * count goes to zero, the memory associated with the data is freed. Does
1985 * nothing if the passed pointer is NULL.
1989 del_bindata(dataptr)
1990 struct shared_bindata *dataptr;
1993 if (!(--(dataptr->linkcount))) {
1994 free((char *) dataptr);
2002 /* smalloc() -- safe malloc()
2004 * Always returns a valid pointer (if it returns at all). The allocated
2005 * memory is initialized to all zeros. If malloc() returns an error, a
2006 * message is printed using the report() function and the program aborts
2007 * with a status of 1.
2016 retvalue = malloc(nbytes);
2018 report(LOG_ERR, "malloc() failure -- exiting");
2021 bzero(retvalue, nbytes);
2027 * Compare function to determine whether two hardware addresses are
2028 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
2031 * This function is used when retrieving elements from the hardware address
2037 hash_datum *d1, *d2;
2039 struct host *host1 = (struct host *) d1;
2040 struct host *host2 = (struct host *) d2;
2042 if (host1->htype != host2->htype) {
2045 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2053 * Compare function for doing IP address hash table lookup.
2058 hash_datum *d1, *d2;
2060 struct host *host1 = (struct host *) d1;
2061 struct host *host2 = (struct host *) d2;
2063 return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2070 * c-argdecl-indent: 4
2071 * c-continued-statement-offset: 4
2072 * c-continued-brace-offset: -4
2073 * c-label-offset: -4