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>
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)
66 #define HASHTABLESIZE 257 /* Hash table size (prime) */
68 /* Non-standard hardware address type (see bootp.h) */
69 #define HTYPE_DIRECT 0
71 /* Error codes returned by eval_symbol: */
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)
85 #define SYM_BOOTFILE 1
86 #define SYM_COOKIE_SERVER 2
87 #define SYM_DOMAIN_SERVER 3
92 #define SYM_IMPRESS_SERVER 8
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 */
121 #define OP_ADDITION 1 /* Operations on tags */
122 #define OP_DELETION 2
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 */
132 * Structure used to map a configuration-file symbol (such as "ds") to a
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];
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
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 */
172 {"hn", SYM_NAME_SWITCH},
174 {"im", SYM_IMPRESS_SERVER},
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},
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 */
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.
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}
227 * Externals and forward declarations.
236 extern boolean iplookcmp();
237 boolean nmcmp P((hash_datum *, hash_datum *));
242 del_string P((struct shared_string *));
244 del_bindata P((struct shared_bindata *));
246 del_iplist P((struct in_addr_list *));
248 eat_whitespace P((char **));
250 eval_symbol P((char **, struct host *));
252 fill_defaults P((struct host *, char **));
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 **));
260 get_string P((char **, char *, u_int *));
262 get_u_long P((char **));
264 goodname P((char *));
266 hwinscmp P((hash_datum *, hash_datum *));
268 interp_byte P((char **, byte *));
270 makelower P((char *));
272 nullcmp P((hash_datum *, hash_datum *));
274 process_entry P((struct host *, char *));
276 process_generic P((char **, struct shared_bindata **, u_int));
278 prs_haddr P((char **, u_int));
280 prs_inetaddr P((char **, u_int32 *));
282 read_entry P((FILE *, char *, u_int *));
290 * Vendor magic cookies for CMU and RFC1048
292 u_char vm_cmu[4] = VM_CMU;
293 u_char vm_rfc1048[4] = VM_RFC1048;
298 hash_tbl *hwhashtable;
299 hash_tbl *iphashtable;
300 hash_tbl *nmhashtable;
303 * Allocate hash tables for hardware address, ip address, and hostname
304 * (shared by bootpd and bootpef)
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.");
320 * Read bootptab database file. Avoid rereading the file if the
321 * write date hasn't changed since the last time we read it.
331 unsigned hashcode, buflen;
332 static char buffer[MAXENTRYLEN];
335 * Check the last modification time.
337 if (stat(bootptab, &st) < 0) {
338 report(LOG_ERR, "stat on \"%s\": %s",
339 bootptab, get_errmsg());
345 strcpy(timestr, ctime(&(st.st_mtime)));
346 /* zap the newline */
348 report(LOG_INFO, "bootptab mtime: %s",
353 (st.st_mtime == modtime) &&
356 * hasn't been modified or deleted yet.
361 report(LOG_INFO, "reading %s\"%s\"",
362 (modtime != 0L) ? "new " : "",
366 * Open bootptab file.
368 if ((fp = fopen(bootptab, "r")) == NULL) {
369 report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
373 * Record file modification time.
375 if (fstat(fileno(fp), &st) < 0) {
376 report(LOG_ERR, "fstat: %s", get_errmsg());
380 modtime = st.st_mtime;
383 * Entirely erase all hash tables.
385 hash_Reset(hwhashtable, free_host);
386 hash_Reset(iphashtable, free_host);
387 hash_Reset(nmhashtable, free_host);
392 buflen = sizeof(buffer);
393 read_entry(fp, buffer, &buflen);
394 if (buflen == 0) { /* More entries? */
397 hp = (struct host *) smalloc(sizeof(struct host));
398 bzero((char *) hp, sizeof(*hp));
399 /* the link count it zero */
402 * Get individual info
404 if (process_entry(hp, buffer) < 0) {
406 free_host((hash_datum *) hp);
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.
414 if (goodname(hp->hostname->string)) {
415 char *hn = hp->hostname->string;
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 '.')");
422 hp->iaddr.s_addr = value;
423 hp->flags.iaddr = TRUE;
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);
431 hp->subnet_mask.s_addr = value;
432 hp->flags.subnet_mask = TRUE;
436 if (hp->flags.iaddr) {
439 /* Register by HW addr if known. */
440 if (hp->flags.htype && hp->flags.haddr) {
441 /* We will either insert it or free it. */
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",
447 haddrtoa(hp->haddr, haddrlength(hp->htype)));
448 free_host((hash_datum *) hp);
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) {
457 "hash_Insert() failed on IP address insertion");
459 /* Just inserted the host struct in a new hash list. */
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) {
469 "hash_Insert() failed on insertion of hostname: \"%s\"",
470 hp->hostname->string);
472 /* Just inserted the host struct in a new hash list. */
481 report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
482 nentries, nhosts, bootptab);
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
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).
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.
508 read_entry(fp, buffer, bufsiz)
518 * Eat whitespace, blank lines, and comment lines.
523 goto done; /* Exit if end-of-file */
526 goto top; /* Skip over whitespace */
529 while (TRUE) { /* Eat comments after # */
532 goto done; /* Exit if end-of-file */
535 goto top; /* Try to read the next line */
539 ungetc(c, fp); /* Other character, push it back to reprocess it */
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 (\).
553 goto done; /* Exit on EOF or newline */
555 c = fgetc(fp); /* Backslash, read a new character */
557 goto done; /* Exit on EOF */
559 *buffer++ = c; /* Store the literal character */
561 if (length < *bufsiz - 1) {
567 *buffer++ = '"'; /* Store double-quote */
569 if (length >= *bufsiz - 1) {
572 while (TRUE) { /* Special quote processing loop */
576 goto done; /* Exit on EOF . . . */
578 *buffer++ = '"';/* Store matching quote */
580 if (length < *bufsiz - 1) {
581 goto mainloop; /* And continue main loop */
586 if ((c = fgetc(fp)) < 0) { /* Backslash */
587 goto done; /* EOF. . . .*/
588 } /* else fall through */
590 *buffer++ = c; /* Other character, store it */
592 if (length >= *bufsiz - 1) {
598 *buffer++ = c; /* Store colons */
600 if (length >= *bufsiz - 1) {
603 do { /* But remove whitespace after them */
605 if ((c < 0) || (c == '\n')) {
608 } while (isspace(c)); /* Skip whitespace */
610 if (c == '\\') { /* Backslash quotes next character */
616 goto top; /* Backslash-newline continuation */
619 /* fall through if "other" character */
621 *buffer++ = c; /* Store other characters */
623 if (length >= *bufsiz - 1) {
627 goto mainloop; /* Keep going */
630 *buffer = '\0'; /* Terminate string */
631 *bufsiz = length; /* Tell the caller its length */
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.
643 * (Some errors probably shouldn't be so completely fatal. . . .)
647 process_entry(host, src)
654 if (!host || *src == '\0') {
657 host->hostname = get_shared_string(&src);
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);
666 current_hostname = host->hostname->string;
669 retval = eval_symbol(&src, host);
670 if (retval == SUCCESS) {
674 if (retval == E_END_OF_ENTRY) {
675 /* The default subnet mask is set in readtab() */
678 /* Some kind of error. */
683 case E_UNKNOWN_SYMBOL:
684 msg = "unknown symbol";
687 msg = "bad INET address";
690 msg = "bad hardware address";
693 msg = "bad longword value";
696 msg = "bad HW address type";
699 msg = "bad pathname (need leading '/')";
703 msg = "unkown error";
706 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
707 current_hostname, current_tagname, msg);
714 * Macros for use in the function below:
717 /* Parse one INET address stored directly in MEMBER. */
718 #define PARSE_IA1(MEMBER) do \
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; \
731 /* Parse a list of INET addresses pointed to by MEMBER */
732 #define PARSE_IAL(MEMBER) do \
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); \
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; \
750 /* Parse a shared string pointed to by MEMBER */
751 #define PARSE_STR(MEMBER) do \
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); \
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; \
769 /* Parse an unsigned integer value for MEMBER */
770 #define PARSE_UINT(MEMBER) do \
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; \
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).
788 * Obviously, this need a few more comments. . . .
791 eval_symbol(symbol, hp)
795 char tmpstr[MAXSTRINGLEN];
797 struct symbolmap *symbolptr;
802 int optype; /* Indicates boolean, addition, or deletion */
804 eat_whitespace(symbol);
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;
811 if ((*symbol)[0] == '\0') {
812 return E_END_OF_ENTRY;
814 if ((*symbol)[0] == ':') {
817 if ((*symbol)[0] == 'T') { /* generic symbol */
819 value = get_u_long(symbol);
820 snprintf(current_tagname, sizeof(current_tagname),
822 eat_whitespace(symbol);
823 if ((*symbol)[0] != '=') {
824 return E_SYNTAX_ERROR;
827 if (!(hp->generic)) {
828 hp->generic = (struct shared_bindata *)
829 smalloc(sizeof(struct shared_bindata));
831 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
832 return E_SYNTAX_ERROR;
833 hp->flags.generic = TRUE;
837 * Determine the type of operation to be done on this symbol
839 switch ((*symbol)[2]) {
841 optype = OP_ADDITION;
844 optype = OP_DELETION;
851 return E_SYNTAX_ERROR;
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])) {
863 if (i >= numsymbols) {
864 return E_UNKNOWN_SYMBOL;
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. . . .).
871 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
873 eat_whitespace(symbol);
875 /* The cases below are in order by symbolcode value. */
876 switch (symbolptr->symbolcode) {
882 case SYM_COOKIE_SERVER:
883 PARSE_IAL(cookie_server);
886 case SYM_DOMAIN_SERVER:
887 PARSE_IAL(domain_server);
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;
904 tmphaddr = prs_haddr(symbol, hp->htype);
907 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
908 hp->flags.haddr = TRUE;
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);
926 len = sizeof(tmpstr);
927 (void) get_string(symbol, tmpstr, &len);
929 numsymbols = sizeof(htnamemap) /
930 sizeof(struct htypename);
931 for (i = 0; i < numsymbols; i++) {
932 if (!strcmp(htnamemap[i].name, tmpstr)) {
936 if (i < numsymbols) {
937 value = htnamemap[i].htype;
940 if (value >= hwinfocnt) {
941 return E_BAD_HWATYPE;
943 hp->htype = (byte) (value & 0xFF);
944 hp->flags.htype = TRUE;
948 case SYM_IMPRESS_SERVER:
949 PARSE_IAL(impress_server);
957 PARSE_IAL(log_server);
961 PARSE_IAL(lpr_server);
964 case SYM_NAME_SERVER:
965 PARSE_IAL(name_server);
969 PARSE_IAL(rlp_server);
972 case SYM_SUBNET_MASK:
973 PARSE_IA1(subnet_mask);
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;
986 if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
987 return E_BAD_LONGWORD;
988 hp->time_offset = timeoff;
990 hp->flags.time_offset = TRUE;
994 case SYM_TIME_SERVER:
995 PARSE_IAL(time_server);
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);
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);
1016 hp->flags.vm_cookie = TRUE;
1021 case SYM_SIMILAR_ENTRY:
1024 fill_defaults(hp, symbol);
1027 return E_SYNTAX_ERROR;
1031 case SYM_NAME_SWITCH:
1034 return E_SYNTAX_ERROR;
1036 hp->flags.send_name = FALSE;
1037 hp->flags.name_switch = FALSE;
1040 hp->flags.send_name = TRUE;
1041 hp->flags.name_switch = TRUE;
1049 if (!strncmp(*symbol, "auto", 4)) {
1050 hp->flags.bootsize = TRUE;
1051 hp->flags.bootsize_auto = TRUE;
1053 hp->bootsize = (unsigned int) get_u_long(symbol);
1054 hp->flags.bootsize = TRUE;
1055 hp->flags.bootsize_auto = FALSE;
1059 hp->flags.bootsize = FALSE;
1062 hp->flags.bootsize = TRUE;
1063 hp->flags.bootsize_auto = TRUE;
1068 case SYM_BOOT_SERVER:
1069 PARSE_IA1(bootserver);
1074 if ((hp->tftpdir != NULL) &&
1075 (hp->tftpdir->string[0] != '/'))
1076 return E_BAD_PATHNAME;
1080 PARSE_STR(dump_file);
1083 case SYM_DOMAIN_NAME:
1084 PARSE_STR(domain_name);
1087 case SYM_SWAP_SERVER:
1088 PARSE_IA1(swap_server);
1092 PARSE_STR(root_path);
1095 case SYM_EXTEN_FILE:
1096 PARSE_STR(exten_file);
1099 case SYM_REPLY_ADDR:
1100 PARSE_IA1(reply_addr);
1103 case SYM_NIS_DOMAIN:
1104 PARSE_STR(nis_domain);
1107 case SYM_NIS_SERVER:
1108 PARSE_IAL(nis_server);
1111 case SYM_NTP_SERVER:
1112 PARSE_IAL(ntp_server);
1115 #ifdef YORK_EX_OPTION
1117 PARSE_STR(exec_file);
1122 PARSE_UINT(msg_size);
1123 if (hp->msg_size < BP_MINPKTSZ ||
1124 hp->msg_size > MAX_MSG_SIZE)
1129 PARSE_UINT(min_wait);
1132 /* XXX - Add new tags here */
1135 return E_UNKNOWN_SYMBOL;
1137 } /* switch symbolcode */
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".
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
1165 get_string(src, dest, length)
1169 int n, len, quoteflag;
1174 while ((n < len) && (**src)) {
1175 if (!quoteflag && (**src == ':')) {
1180 quoteflag = !quoteflag;
1183 if (**src == '\\') {
1189 *dest++ = *(*src)++;
1194 * Remove that troublesome trailing whitespace. . .
1196 while ((n > 0) && isspace(dest[-1])) {
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.
1213 * The string is read using the same rules as get_string() above.
1216 PRIVATE struct shared_string *
1217 get_shared_string(src)
1220 char retstring[MAXSTRINGLEN];
1221 struct shared_string *s;
1224 length = sizeof(retstring);
1225 (void) get_string(src, retstring, &length);
1227 s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1230 strcpy(s->string, retstring);
1238 * Load RFC1048 generic information directly into a memory buffer.
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
1245 * The given tag value is inserted with the new data.
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).
1254 process_generic(src, dest, tagvalue)
1256 struct shared_bindata **dest;
1259 byte tmpbuf[MAXBUFLEN];
1261 struct shared_bindata *bdata;
1262 u_int newlength, oldlength;
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 */
1273 while (newlength < sizeof(tmpbuf) - 2) {
1274 if (interp_byte(src, str++) < 0)
1282 if ((*src)[0] != ':')
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);
1292 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1293 bdata->length = oldlength + newlength + 2;
1294 bdata->linkcount = 1;
1305 * Verify that the given string makes sense as a hostname (according to
1306 * Appendix 1, page 29 of RFC882).
1308 * Return TRUE for good names, FALSE otherwise.
1313 register char *hostname;
1316 if (!isalpha(*hostname++)) { /* First character must be a letter */
1319 while (isalnum(*hostname) ||
1320 (*hostname == '-') ||
1321 (*hostname == '_') )
1323 hostname++; /* Alphanumeric or a hyphen */
1325 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
1328 if (*hostname == '\0') {/* Done? */
1331 } while (*hostname++ == '.'); /* Dot, loop for next label */
1333 return FALSE; /* If it's not a dot, lose */
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).
1346 hash_datum *d1, *d2;
1353 * Function for comparing a string with the hostname field of a host
1359 hash_datum *d1, *d2;
1361 char *name = (char *) d1; /* XXX - OK? */
1362 struct host *hp = (struct host *) d2;
1364 return !strcmp(name, hp->hostname->string);
1369 * Compare function to determine whether two hardware addresses are
1370 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1373 * If the hardware addresses of "host1" and "host2" are identical, but
1374 * they are on different IP subnets, this function returns FALSE.
1376 * This function is used when inserting elements into the hardware address
1382 hash_datum *d1, *d2;
1384 struct host *host1 = (struct host *) d1;
1385 struct host *host2 = (struct host *) d2;
1387 if (host1->htype != host2->htype) {
1390 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
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)))
1406 * Macros for use in the function below:
1409 #define DUP_COPY(MEMBER) do \
1411 if (!hp->flags.MEMBER) { \
1412 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1413 hp->MEMBER = hp2->MEMBER; \
1418 #define DUP_LINK(MEMBER) do \
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)++; \
1430 * Process the "similar entry" symbol.
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.
1437 fill_defaults(hp, src)
1441 unsigned int tlen, hashcode;
1443 char tstring[MAXSTRINGLEN];
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);
1451 report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1455 DUP_LINK(cookie_server);
1456 DUP_LINK(domain_server);
1458 /* haddr not copied */
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);
1469 DUP_COPY(subnet_mask);
1470 DUP_COPY(time_offset);
1471 DUP_LINK(time_server);
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);
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;
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;
1489 DUP_COPY(bootserver);
1492 DUP_LINK(dump_file);
1493 DUP_LINK(domain_name);
1495 DUP_COPY(swap_server);
1496 DUP_LINK(root_path);
1497 DUP_LINK(exten_file);
1499 DUP_COPY(reply_addr);
1501 DUP_LINK(nis_domain);
1502 DUP_LINK(nis_server);
1503 DUP_LINK(ntp_server);
1505 #ifdef YORK_EX_OPTION
1506 DUP_LINK(exec_file);
1512 /* XXX - Add new tags here */
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.
1535 while (*t && (*t != ':')) {
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.
1560 while (*t && isspace(*t)) {
1569 * This function converts the given string to all lowercase.
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
1598 * I'm sure somebody out there won't like this. . . .
1599 * (Yea, because it usually makes code slower... -gwr)
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.
1613 PRIVATE struct in_addr_list *
1617 struct in_addr tmpaddrlist[MAXINADDRS];
1618 struct in_addr *address1, *address2;
1619 struct in_addr_list *result;
1620 unsigned addrcount, totalsize;
1622 address1 = tmpaddrlist;
1623 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1624 while (isspace(**src) || (**src == ',')) {
1627 if (!**src) { /* Quit if nothing more */
1630 if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1633 address1++; /* Point to next address slot */
1635 if (addrcount < 1) {
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;
1657 * prs_inetaddr(src, result)
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.
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.
1671 prs_inetaddr(src, result)
1675 char tmpstr[MAXSTRINGLEN];
1676 register u_int32 value;
1677 u_int32 parts[4], *pp;
1681 /* Leading alpha char causes IP addr lookup. */
1682 if (isalpha(**src)) {
1683 /* Lookup IP address. */
1686 while ((isalnum(*s) || (*s == '.') ||
1687 (*s == '-') || (*s == '_') ) &&
1688 (t < &tmpstr[MAXSTRINGLEN - 1]) )
1693 n = lookup_ipa(tmpstr, result);
1695 report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1700 * Parse an address in Internet format:
1702 * a.b.c (with c treated as 16-bits)
1703 * a.b (with b treated as 24 bits)
1707 /* If it's not a digit, return error. */
1708 if (!isdigit(**src))
1710 *pp++ = get_u_long(src);
1712 if (pp < (parts + 4)) {
1719 /* This is handled by the caller. */
1720 if (**src && !(isspace(**src) || (**src == ':'))) {
1726 * Construct the address according to
1727 * the number of parts specified.
1731 case 1: /* a -- 32 bits */
1734 case 2: /* a.b -- 8.24 bits */
1735 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1737 case 3: /* a.b.c -- 8.8.16 bits */
1738 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1739 (parts[2] & 0xFFFF);
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);
1748 *result = htonl(value);
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
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.
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.
1771 prs_haddr(src, htype)
1775 static byte haddr[MAXHADDRLEN];
1777 char tmpstr[MAXSTRINGLEN];
1782 hal = haddrlength(htype); /* Get length of this address type */
1784 report(LOG_ERR, "Invalid addr type for HW addr parse");
1787 tmplen = sizeof(tmpstr);
1788 get_string(src, tmpstr, &tmplen);
1791 /* If it's a valid host name, try to lookup the HW address. */
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. */
1801 while (hap < haddr + hal) {
1802 if ((*p == '.') || (*p == ':'))
1804 if (interp_byte(&p, hap++) < 0) {
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".
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.
1826 interp_byte(src, retbyte)
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 */
1837 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1840 if (sscanf(*src, "%2x", &v) != 1) {
1844 *retbyte = (byte) (v & 0xFF);
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.
1861 register u_int32 value, base;
1865 * Collect number up to first illegal character. Values are specified
1866 * as for C: 0x=hex, 0=octal, other=decimal.
1874 if (**src == 'x' || **src == 'X') {
1878 while ((c = **src)) {
1880 value = (value * base) + (c - '0');
1884 if (base == 16 && isxdigit(c)) {
1885 value = (value << 4) + ((c & ~32) + 10 - 'A');
1897 * Routines for deletion of data associated with the main data structure.
1902 * Frees the entire host data structure given. Does nothing if the passed
1910 struct host *hostptr = (struct host *) hmp;
1911 if (hostptr == NULL)
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);
1929 * XXX - Add new tags here
1930 * (if the value is an IP list)
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);
1943 #ifdef YORK_EX_OPTION
1944 del_string(hostptr->exec_file);
1948 * XXX - Add new tags here
1949 * (if it is a shared string)
1952 del_bindata(hostptr->generic);
1953 free((char *) hostptr);
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.
1965 struct in_addr_list *iplist;
1968 if (!(--(iplist->linkcount))) {
1969 free((char *) iplist);
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.
1983 del_string(stringptr)
1984 struct shared_string *stringptr;
1987 if (!(--(stringptr->linkcount))) {
1988 free((char *) stringptr);
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.
2002 del_bindata(dataptr)
2003 struct shared_bindata *dataptr;
2006 if (!(--(dataptr->linkcount))) {
2007 free((char *) dataptr);
2015 /* smalloc() -- safe malloc()
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.
2029 retvalue = malloc(nbytes);
2031 report(LOG_ERR, "malloc() failure -- exiting");
2034 bzero(retvalue, nbytes);
2040 * Compare function to determine whether two hardware addresses are
2041 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
2044 * This function is used when retrieving elements from the hardware address
2050 hash_datum *d1, *d2;
2052 struct host *host1 = (struct host *) d1;
2053 struct host *host2 = (struct host *) d2;
2055 if (host1->htype != host2->htype) {
2058 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2066 * Compare function for doing IP address hash table lookup.
2071 hash_datum *d1, *d2;
2073 struct host *host1 = (struct host *) d1;
2074 struct host *host2 = (struct host *) d2;
2076 return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2083 * c-argdecl-indent: 4
2084 * c-continued-statement-offset: 4
2085 * c-continued-brace-offset: -4
2086 * c-label-offset: -4