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.
230 extern boolean iplookcmp();
231 boolean nmcmp(hash_datum *, hash_datum *);
236 del_string(struct shared_string *);
238 del_bindata(struct shared_bindata *);
240 del_iplist(struct in_addr_list *);
242 eat_whitespace(char **);
244 eval_symbol(char **, struct host *);
246 fill_defaults(struct host *, char **);
248 free_host(hash_datum *);
249 PRIVATE struct in_addr_list *
250 get_addresses(char **);
251 PRIVATE struct shared_string *
252 get_shared_string(char **);
254 get_string(char **, char *, u_int *);
260 hwinscmp(hash_datum *, hash_datum *);
262 interp_byte(char **, byte *);
266 nullcmp(hash_datum *, hash_datum *);
268 process_entry(struct host *, char *);
270 process_generic(char **, struct shared_bindata **, u_int);
272 prs_haddr(char **, u_int);
274 prs_inetaddr(char **, u_int32 *);
276 read_entry(FILE *, char *, u_int *);
282 * Vendor magic cookies for CMU and RFC1048
284 u_char vm_cmu[4] = VM_CMU;
285 u_char vm_rfc1048[4] = VM_RFC1048;
290 hash_tbl *hwhashtable;
291 hash_tbl *iphashtable;
292 hash_tbl *nmhashtable;
295 * Allocate hash tables for hardware address, ip address, and hostname
296 * (shared by bootpd and bootpef)
301 hwhashtable = hash_Init(HASHTABLESIZE);
302 iphashtable = hash_Init(HASHTABLESIZE);
303 nmhashtable = hash_Init(HASHTABLESIZE);
304 if (!(hwhashtable && iphashtable && nmhashtable)) {
305 report(LOG_ERR, "Unable to allocate hash tables.");
312 * Read bootptab database file. Avoid rereading the file if the
313 * write date hasn't changed since the last time we read it.
323 unsigned hashcode, buflen;
324 static char buffer[MAXENTRYLEN];
327 * Check the last modification time.
329 if (stat(bootptab, &st) < 0) {
330 report(LOG_ERR, "stat on \"%s\": %s",
331 bootptab, get_errmsg());
337 strcpy(timestr, ctime(&(st.st_mtime)));
338 /* zap the newline */
340 report(LOG_INFO, "bootptab mtime: %s",
345 (st.st_mtime == modtime) &&
348 * hasn't been modified or deleted yet.
353 report(LOG_INFO, "reading %s\"%s\"",
354 (modtime != 0L) ? "new " : "",
358 * Open bootptab file.
360 if ((fp = fopen(bootptab, "r")) == NULL) {
361 report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
365 * Record file modification time.
367 if (fstat(fileno(fp), &st) < 0) {
368 report(LOG_ERR, "fstat: %s", get_errmsg());
372 modtime = st.st_mtime;
375 * Entirely erase all hash tables.
377 hash_Reset(hwhashtable, free_host);
378 hash_Reset(iphashtable, free_host);
379 hash_Reset(nmhashtable, free_host);
384 buflen = sizeof(buffer);
385 read_entry(fp, buffer, &buflen);
386 if (buflen == 0) { /* More entries? */
389 hp = (struct host *) smalloc(sizeof(struct host));
390 bzero((char *) hp, sizeof(*hp));
391 /* the link count it zero */
394 * Get individual info
396 if (process_entry(hp, buffer) < 0) {
398 free_host((hash_datum *) hp);
402 * If this is not a dummy entry, and the IP or HW
403 * address is not yet set, try to get them here.
404 * Dummy entries have . as first char of name.
406 if (goodname(hp->hostname->string)) {
407 char *hn = hp->hostname->string;
409 if (hp->flags.iaddr == 0) {
410 if (lookup_ipa(hn, &value)) {
411 report(LOG_ERR, "can not get IP addr for %s", hn);
412 report(LOG_ERR, "(dummy names should start with '.')");
414 hp->iaddr.s_addr = value;
415 hp->flags.iaddr = TRUE;
418 /* Set default subnet mask. */
419 if (hp->flags.subnet_mask == 0) {
420 if (lookup_netmask(hp->iaddr.s_addr, &value)) {
421 report(LOG_ERR, "can not get netmask for %s", hn);
423 hp->subnet_mask.s_addr = value;
424 hp->flags.subnet_mask = TRUE;
428 if (hp->flags.iaddr) {
431 /* Register by HW addr if known. */
432 if (hp->flags.htype && hp->flags.haddr) {
433 /* We will either insert it or free it. */
435 hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
436 if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
437 report(LOG_NOTICE, "duplicate %s address: %s",
439 haddrtoa(hp->haddr, haddrlength(hp->htype)));
440 free_host((hash_datum *) hp);
444 /* Register by IP addr if known. */
445 if (hp->flags.iaddr) {
446 hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
447 if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
449 "hash_Insert() failed on IP address insertion");
451 /* Just inserted the host struct in a new hash list. */
455 /* Register by Name (always known) */
456 hashcode = hash_HashFunction((u_char *) hp->hostname->string,
457 strlen(hp->hostname->string));
458 if (hash_Insert(nmhashtable, hashcode, nullcmp,
459 hp->hostname->string, hp) < 0) {
461 "hash_Insert() failed on insertion of hostname: \"%s\"",
462 hp->hostname->string);
464 /* Just inserted the host struct in a new hash list. */
473 report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
474 nentries, nhosts, bootptab);
481 * Read an entire host entry from the file pointed to by "fp" and insert it
482 * into the memory pointed to by "buffer". Leading whitespace and comments
483 * starting with "#" are ignored (removed). Backslashes (\) always quote
484 * the next character except that newlines preceded by a backslash cause
485 * line-continuation onto the next line. The entry is terminated by a
486 * newline character which is not preceded by a backslash. Sequences
487 * surrounded by double quotes are taken literally (including newlines, but
490 * The "bufsiz" parameter points to an unsigned int which specifies the
491 * maximum permitted buffer size. Upon return, this value will be replaced
492 * with the actual length of the entry (not including the null terminator).
494 * This code is a little scary. . . . I don't like using gotos in C
495 * either, but I first wrote this as an FSM diagram and gotos seemed like
496 * the easiest way to implement it. Maybe later I'll clean it up.
500 read_entry(fp, buffer, bufsiz)
510 * Eat whitespace, blank lines, and comment lines.
515 goto done; /* Exit if end-of-file */
518 goto top; /* Skip over whitespace */
521 while (TRUE) { /* Eat comments after # */
524 goto done; /* Exit if end-of-file */
527 goto top; /* Try to read the next line */
531 ungetc(c, fp); /* Other character, push it back to reprocess it */
535 * Now we're actually reading a data entry. Get each character and
536 * assemble it into the data buffer, processing special characters like
537 * double quotes (") and backslashes (\).
545 goto done; /* Exit on EOF or newline */
547 c = fgetc(fp); /* Backslash, read a new character */
549 goto done; /* Exit on EOF */
551 *buffer++ = c; /* Store the literal character */
553 if (length < *bufsiz - 1) {
559 *buffer++ = '"'; /* Store double-quote */
561 if (length >= *bufsiz - 1) {
564 while (TRUE) { /* Special quote processing loop */
568 goto done; /* Exit on EOF . . . */
570 *buffer++ = '"';/* Store matching quote */
572 if (length < *bufsiz - 1) {
573 goto mainloop; /* And continue main loop */
578 if ((c = fgetc(fp)) < 0) { /* Backslash */
579 goto done; /* EOF. . . .*/
583 *buffer++ = c; /* Other character, store it */
585 if (length >= *bufsiz - 1) {
591 *buffer++ = c; /* Store colons */
593 if (length >= *bufsiz - 1) {
596 do { /* But remove whitespace after them */
598 if ((c < 0) || (c == '\n')) {
601 } while (isspace(c)); /* Skip whitespace */
603 if (c == '\\') { /* Backslash quotes next character */
609 goto top; /* Backslash-newline continuation */
612 /* FALLTHROUGH if "other" character */
614 *buffer++ = c; /* Store other characters */
616 if (length >= *bufsiz - 1) {
620 goto mainloop; /* Keep going */
623 *buffer = '\0'; /* Terminate string */
624 *bufsiz = length; /* Tell the caller its length */
630 * Parse out all the various tags and parameters in the host entry pointed
631 * to by "src". Stuff all the data into the appropriate fields of the
632 * host structure pointed to by "host". If there is any problem with the
633 * entry, an error message is reported via report(), no further processing
634 * is done, and -1 is returned. Successful calls return 0.
636 * (Some errors probably shouldn't be so completely fatal. . . .)
640 process_entry(host, src)
647 if (!host || *src == '\0') {
650 host->hostname = get_shared_string(&src);
652 /* Be more liberal for the benefit of dummy tag names. */
653 if (!goodname(host->hostname->string)) {
654 report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
655 del_string(host->hostname);
659 current_hostname = host->hostname->string;
662 retval = eval_symbol(&src, host);
663 if (retval == SUCCESS) {
667 if (retval == E_END_OF_ENTRY) {
668 /* The default subnet mask is set in readtab() */
671 /* Some kind of error. */
676 case E_UNKNOWN_SYMBOL:
677 msg = "unknown symbol";
680 msg = "bad INET address";
683 msg = "bad hardware address";
686 msg = "bad longword value";
689 msg = "bad HW address type";
692 msg = "bad pathname (need leading '/')";
698 msg = "unknown error";
701 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
702 current_hostname, current_tagname, msg);
709 * Macros for use in the function below:
712 /* Parse one INET address stored directly in MEMBER. */
713 #define PARSE_IA1(MEMBER) do \
715 if (optype == OP_BOOLEAN) \
716 return E_SYNTAX_ERROR; \
717 hp->flags.MEMBER = FALSE; \
718 if (optype == OP_ADDITION) { \
719 if (prs_inetaddr(symbol, &value) < 0) \
720 return E_BAD_IPADDR; \
721 hp->MEMBER.s_addr = value; \
722 hp->flags.MEMBER = TRUE; \
726 /* Parse a list of INET addresses pointed to by MEMBER */
727 #define PARSE_IAL(MEMBER) do \
729 if (optype == OP_BOOLEAN) \
730 return E_SYNTAX_ERROR; \
731 if (hp->flags.MEMBER) { \
732 hp->flags.MEMBER = FALSE; \
733 assert(hp->MEMBER); \
734 del_iplist(hp->MEMBER); \
737 if (optype == OP_ADDITION) { \
738 hp->MEMBER = get_addresses(symbol); \
739 if (hp->MEMBER == NULL) \
740 return E_SYNTAX_ERROR; \
741 hp->flags.MEMBER = TRUE; \
745 /* Parse a shared string pointed to by MEMBER */
746 #define PARSE_STR(MEMBER) do \
748 if (optype == OP_BOOLEAN) \
749 return E_SYNTAX_ERROR; \
750 if (hp->flags.MEMBER) { \
751 hp->flags.MEMBER = FALSE; \
752 assert(hp->MEMBER); \
753 del_string(hp->MEMBER); \
756 if (optype == OP_ADDITION) { \
757 hp->MEMBER = get_shared_string(symbol); \
758 if (hp->MEMBER == NULL) \
759 return E_SYNTAX_ERROR; \
760 hp->flags.MEMBER = TRUE; \
764 /* Parse an unsigned integer value for MEMBER */
765 #define PARSE_UINT(MEMBER) do \
767 if (optype == OP_BOOLEAN) \
768 return E_SYNTAX_ERROR; \
769 hp->flags.MEMBER = FALSE; \
770 if (optype == OP_ADDITION) { \
771 value = get_u_long(symbol); \
772 hp->MEMBER = value; \
773 hp->flags.MEMBER = TRUE; \
778 * Evaluate the two-character tag symbol pointed to by "symbol" and place
779 * the data in the structure pointed to by "hp". The pointer pointed to
780 * by "symbol" is updated to point past the source string (but may not
781 * point to the next tag entry).
783 * Obviously, this need a few more comments. . . .
786 eval_symbol(symbol, hp)
790 char tmpstr[MAXSTRINGLEN];
792 struct symbolmap *symbolptr;
797 int optype; /* Indicates boolean, addition, or deletion */
799 eat_whitespace(symbol);
801 /* Make sure this is set before returning. */
802 current_tagname[0] = (*symbol)[0];
803 current_tagname[1] = (*symbol)[1];
804 current_tagname[2] = 0;
806 if ((*symbol)[0] == '\0') {
807 return E_END_OF_ENTRY;
809 if ((*symbol)[0] == ':') {
812 if ((*symbol)[0] == 'T') { /* generic symbol */
814 value = get_u_long(symbol);
815 snprintf(current_tagname, sizeof(current_tagname),
817 eat_whitespace(symbol);
818 if ((*symbol)[0] != '=') {
819 return E_SYNTAX_ERROR;
822 if (!(hp->generic)) {
823 hp->generic = (struct shared_bindata *)
824 smalloc(sizeof(struct shared_bindata));
826 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
827 return E_SYNTAX_ERROR;
828 hp->flags.generic = TRUE;
832 * Determine the type of operation to be done on this symbol
834 switch ((*symbol)[2]) {
836 optype = OP_ADDITION;
839 optype = OP_DELETION;
846 return E_SYNTAX_ERROR;
849 symbolptr = symbol_list;
850 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
851 for (i = 0; i < numsymbols; i++) {
852 if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
853 ((symbolptr->symbol)[1] == (*symbol)[1])) {
858 if (i >= numsymbols) {
859 return E_UNKNOWN_SYMBOL;
862 * Skip past the = or @ character (to point to the data) if this
863 * isn't a boolean operation. For boolean operations, just skip
864 * over the two-character tag symbol (and nothing else. . . .).
866 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
868 eat_whitespace(symbol);
870 /* The cases below are in order by symbolcode value. */
871 switch (symbolptr->symbolcode) {
877 case SYM_COOKIE_SERVER:
878 PARSE_IAL(cookie_server);
881 case SYM_DOMAIN_SERVER:
882 PARSE_IAL(domain_server);
890 if (optype == OP_BOOLEAN)
891 return E_SYNTAX_ERROR;
892 hp->flags.haddr = FALSE;
893 if (optype == OP_ADDITION) {
894 /* Default the HW type to Ethernet */
895 if (hp->flags.htype == 0) {
896 hp->flags.htype = TRUE;
897 hp->htype = HTYPE_ETHERNET;
899 tmphaddr = prs_haddr(symbol, hp->htype);
902 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
903 hp->flags.haddr = TRUE;
912 if (optype == OP_BOOLEAN)
913 return E_SYNTAX_ERROR;
914 hp->flags.htype = FALSE;
915 if (optype == OP_ADDITION) {
916 value = 0L; /* Assume an illegal value */
917 eat_whitespace(symbol);
918 if (isdigit(**symbol)) {
919 value = get_u_long(symbol);
921 len = sizeof(tmpstr);
922 (void) get_string(symbol, tmpstr, &len);
924 numsymbols = sizeof(htnamemap) /
925 sizeof(struct htypename);
926 for (i = 0; i < numsymbols; i++) {
927 if (!strcmp(htnamemap[i].name, tmpstr)) {
931 if (i < numsymbols) {
932 value = htnamemap[i].htype;
935 if (value >= hwinfocnt) {
936 return E_BAD_HWATYPE;
938 hp->htype = (byte) (value & 0xFF);
939 hp->flags.htype = TRUE;
943 case SYM_IMPRESS_SERVER:
944 PARSE_IAL(impress_server);
952 PARSE_IAL(log_server);
956 PARSE_IAL(lpr_server);
959 case SYM_NAME_SERVER:
960 PARSE_IAL(name_server);
964 PARSE_IAL(rlp_server);
967 case SYM_SUBNET_MASK:
968 PARSE_IA1(subnet_mask);
971 case SYM_TIME_OFFSET:
972 if (optype == OP_BOOLEAN)
973 return E_SYNTAX_ERROR;
974 hp->flags.time_offset = FALSE;
975 if (optype == OP_ADDITION) {
976 len = sizeof(tmpstr);
977 (void) get_string(symbol, tmpstr, &len);
978 if (!strncmp(tmpstr, "auto", 4)) {
979 hp->time_offset = secondswest;
981 if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
982 return E_BAD_LONGWORD;
983 hp->time_offset = timeoff;
985 hp->flags.time_offset = TRUE;
989 case SYM_TIME_SERVER:
990 PARSE_IAL(time_server);
993 case SYM_VENDOR_MAGIC:
994 if (optype == OP_BOOLEAN)
995 return E_SYNTAX_ERROR;
996 hp->flags.vm_cookie = FALSE;
997 if (optype == OP_ADDITION) {
998 if (strncmp(*symbol, "auto", 4)) {
999 /* The string is not "auto" */
1000 if (!strncmp(*symbol, "rfc", 3)) {
1001 bcopy(vm_rfc1048, hp->vm_cookie, 4);
1002 } else if (!strncmp(*symbol, "cmu", 3)) {
1003 bcopy(vm_cmu, hp->vm_cookie, 4);
1005 if (!isdigit(**symbol))
1006 return E_BAD_IPADDR;
1007 if (prs_inetaddr(symbol, &value) < 0)
1008 return E_BAD_IPADDR;
1009 bcopy(&value, hp->vm_cookie, 4);
1011 hp->flags.vm_cookie = TRUE;
1016 case SYM_SIMILAR_ENTRY:
1019 fill_defaults(hp, symbol);
1022 return E_SYNTAX_ERROR;
1026 case SYM_NAME_SWITCH:
1029 return E_SYNTAX_ERROR;
1031 hp->flags.send_name = FALSE;
1032 hp->flags.name_switch = FALSE;
1035 hp->flags.send_name = TRUE;
1036 hp->flags.name_switch = TRUE;
1044 if (!strncmp(*symbol, "auto", 4)) {
1045 hp->flags.bootsize = TRUE;
1046 hp->flags.bootsize_auto = TRUE;
1048 hp->bootsize = (unsigned int) get_u_long(symbol);
1049 hp->flags.bootsize = TRUE;
1050 hp->flags.bootsize_auto = FALSE;
1054 hp->flags.bootsize = FALSE;
1057 hp->flags.bootsize = TRUE;
1058 hp->flags.bootsize_auto = TRUE;
1063 case SYM_BOOT_SERVER:
1064 PARSE_IA1(bootserver);
1069 if ((hp->tftpdir != NULL) &&
1070 (hp->tftpdir->string[0] != '/'))
1071 return E_BAD_PATHNAME;
1075 PARSE_STR(dump_file);
1078 case SYM_DOMAIN_NAME:
1079 PARSE_STR(domain_name);
1082 case SYM_SWAP_SERVER:
1083 PARSE_IA1(swap_server);
1087 PARSE_STR(root_path);
1090 case SYM_EXTEN_FILE:
1091 PARSE_STR(exten_file);
1094 case SYM_REPLY_ADDR:
1095 PARSE_IA1(reply_addr);
1098 case SYM_NIS_DOMAIN:
1099 PARSE_STR(nis_domain);
1102 case SYM_NIS_SERVER:
1103 PARSE_IAL(nis_server);
1106 case SYM_NTP_SERVER:
1107 PARSE_IAL(ntp_server);
1110 #ifdef YORK_EX_OPTION
1112 PARSE_STR(exec_file);
1117 PARSE_UINT(msg_size);
1118 if (hp->msg_size < BP_MINPKTSZ ||
1119 hp->msg_size > MAX_MSG_SIZE)
1124 PARSE_UINT(min_wait);
1127 /* XXX - Add new tags here */
1130 return E_UNKNOWN_SYMBOL;
1132 } /* switch symbolcode */
1144 * Read a string from the buffer indirectly pointed to through "src" and
1145 * move it into the buffer pointed to by "dest". A pointer to the maximum
1146 * allowable length of the string (including null-terminator) is passed as
1147 * "length". The actual length of the string which was read is returned in
1148 * the unsigned integer pointed to by "length". This value is the same as
1149 * that which would be returned by applying the strlen() function on the
1150 * destination string (i.e the terminating null is not counted as a
1151 * character). Trailing whitespace is removed from the string. For
1152 * convenience, the function returns the new value of "dest".
1154 * The string is read until the maximum number of characters, an unquoted
1155 * colon (:), or a null character is read. The return string in "dest" is
1160 get_string(src, dest, length)
1164 int n, len, quoteflag;
1169 while ((n < len) && (**src)) {
1170 if (!quoteflag && (**src == ':')) {
1175 quoteflag = !quoteflag;
1178 if (**src == '\\') {
1184 *dest++ = *(*src)++;
1189 * Remove that troublesome trailing whitespace. . .
1191 while ((n > 0) && isspace(dest[-1])) {
1204 * Read the string indirectly pointed to by "src", update the caller's
1205 * pointer, and return a pointer to a malloc'ed shared_string structure
1206 * containing the string.
1208 * The string is read using the same rules as get_string() above.
1211 PRIVATE struct shared_string *
1212 get_shared_string(src)
1215 char retstring[MAXSTRINGLEN];
1216 struct shared_string *s;
1219 length = sizeof(retstring);
1220 (void) get_string(src, retstring, &length);
1222 s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1225 strcpy(s->string, retstring);
1233 * Load RFC1048 generic information directly into a memory buffer.
1235 * "src" indirectly points to the ASCII representation of the generic data.
1236 * "dest" points to a string structure which is updated to point to a new
1237 * string with the new data appended to the old string. The old string is
1240 * The given tag value is inserted with the new data.
1242 * The data may be represented as either a stream of hexadecimal numbers
1243 * representing bytes (any or all bytes may optionally start with '0x' and
1244 * be separated with periods ".") or as a quoted string of ASCII
1245 * characters (the quotes are required).
1249 process_generic(src, dest, tagvalue)
1251 struct shared_bindata **dest;
1254 byte tmpbuf[MAXBUFLEN];
1256 struct shared_bindata *bdata;
1257 u_int newlength, oldlength;
1260 *str++ = (tagvalue & 0xFF); /* Store tag value */
1261 str++; /* Skip over length field */
1262 if ((*src)[0] == '"') { /* ASCII data */
1263 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
1264 (void) get_string(src, (char *) str, &newlength);
1265 newlength++; /* null terminator */
1266 } else { /* Numeric data */
1268 while (newlength < sizeof(tmpbuf) - 2) {
1269 if (interp_byte(src, str++) < 0)
1277 if ((*src)[0] != ':')
1280 tmpbuf[1] = (newlength & 0xFF);
1281 oldlength = ((*dest)->length);
1282 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1283 + oldlength + newlength + 1);
1284 if (oldlength > 0) {
1285 bcopy((*dest)->data, bdata->data, oldlength);
1287 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1288 bdata->length = oldlength + newlength + 2;
1289 bdata->linkcount = 1;
1300 * Verify that the given string makes sense as a hostname (according to
1301 * Appendix 1, page 29 of RFC882).
1303 * Return TRUE for good names, FALSE otherwise.
1311 if (!isalpha(*hostname++)) { /* First character must be a letter */
1314 while (isalnum(*hostname) ||
1315 (*hostname == '-') ||
1316 (*hostname == '_') )
1318 hostname++; /* Alphanumeric or a hyphen */
1320 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
1323 if (*hostname == '\0') {/* Done? */
1326 } while (*hostname++ == '.'); /* Dot, loop for next label */
1328 return FALSE; /* If it's not a dot, lose */
1334 * Null compare function -- always returns FALSE so an element is always
1335 * inserted into a hash table (i.e. there is never a collision with an
1336 * existing element).
1341 hash_datum *d1, *d2;
1348 * Function for comparing a string with the hostname field of a host
1354 hash_datum *d1, *d2;
1356 char *name = (char *) d1; /* XXX - OK? */
1357 struct host *hp = (struct host *) d2;
1359 return !strcmp(name, hp->hostname->string);
1364 * Compare function to determine whether two hardware addresses are
1365 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1368 * If the hardware addresses of "host1" and "host2" are identical, but
1369 * they are on different IP subnets, this function returns FALSE.
1371 * This function is used when inserting elements into the hardware address
1377 hash_datum *d1, *d2;
1379 struct host *host1 = (struct host *) d1;
1380 struct host *host2 = (struct host *) d2;
1382 if (host1->htype != host2->htype) {
1385 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1388 /* XXX - Is the subnet_mask field set yet? */
1389 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1390 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1391 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1401 * Macros for use in the function below:
1404 #define DUP_COPY(MEMBER) do \
1406 if (!hp->flags.MEMBER) { \
1407 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1408 hp->MEMBER = hp2->MEMBER; \
1413 #define DUP_LINK(MEMBER) do \
1415 if (!hp->flags.MEMBER) { \
1416 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1417 assert(hp2->MEMBER); \
1418 hp->MEMBER = hp2->MEMBER; \
1419 (hp->MEMBER->linkcount)++; \
1425 * Process the "similar entry" symbol.
1427 * The host specified as the value of the "tc" symbol is used as a template
1428 * for the current host entry. Symbol values not explicitly set in the
1429 * current host entry are inferred from the template entry.
1432 fill_defaults(hp, src)
1436 unsigned int tlen, hashcode;
1438 char tstring[MAXSTRINGLEN];
1440 tlen = sizeof(tstring);
1441 (void) get_string(src, tstring, &tlen);
1442 hashcode = hash_HashFunction((u_char *) tstring, tlen);
1443 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1446 report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1450 DUP_LINK(cookie_server);
1451 DUP_LINK(domain_server);
1453 /* haddr not copied */
1457 DUP_LINK(impress_server);
1458 /* iaddr not copied */
1459 DUP_LINK(log_server);
1460 DUP_LINK(lpr_server);
1461 DUP_LINK(name_server);
1462 DUP_LINK(rlp_server);
1464 DUP_COPY(subnet_mask);
1465 DUP_COPY(time_offset);
1466 DUP_LINK(time_server);
1468 if (!hp->flags.vm_cookie) {
1469 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1470 bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1473 if (!hp->flags.name_switch) {
1474 if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1475 hp->flags.send_name = hp2->flags.send_name;
1478 if (!hp->flags.bootsize) {
1479 if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1480 hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1481 hp->bootsize = hp2->bootsize;
1484 DUP_COPY(bootserver);
1487 DUP_LINK(dump_file);
1488 DUP_LINK(domain_name);
1490 DUP_COPY(swap_server);
1491 DUP_LINK(root_path);
1492 DUP_LINK(exten_file);
1494 DUP_COPY(reply_addr);
1496 DUP_LINK(nis_domain);
1497 DUP_LINK(nis_server);
1498 DUP_LINK(ntp_server);
1500 #ifdef YORK_EX_OPTION
1501 DUP_LINK(exec_file);
1507 /* XXX - Add new tags here */
1518 * This function adjusts the caller's pointer to point just past the
1519 * first-encountered colon. If it runs into a null character, it leaves
1520 * the pointer pointing to it.
1530 while (*t && (*t != ':')) {
1543 * This function adjusts the caller's pointer to point to the first
1544 * non-whitespace character. If it runs into a null character, it leaves
1545 * the pointer pointing to it.
1555 while (*t && isspace(*t)) {
1564 * This function converts the given string to all lowercase.
1585 * In many of the functions which follow, a parameter such as "src" or
1586 * "symbol" is passed as a pointer to a pointer to something. This is
1587 * done for the purpose of letting the called function update the
1588 * caller's copy of the parameter (i.e. to effect call-by-reference
1589 * parameter passing). The value of the actual parameter is only used
1590 * to locate the real parameter of interest and then update this indirect
1593 * I'm sure somebody out there won't like this. . . .
1594 * (Yea, because it usually makes code slower... -gwr)
1601 * "src" points to a character pointer which points to an ASCII string of
1602 * whitespace-separated IP addresses. A pointer to an in_addr_list
1603 * structure containing the list of addresses is returned. NULL is
1604 * returned if no addresses were found at all. The pointer pointed to by
1605 * "src" is updated to point to the first non-address (illegal) character.
1608 PRIVATE struct in_addr_list *
1612 struct in_addr tmpaddrlist[MAXINADDRS];
1613 struct in_addr *address1, *address2;
1614 struct in_addr_list *result;
1615 unsigned addrcount, totalsize;
1617 address1 = tmpaddrlist;
1618 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1619 while (isspace(**src) || (**src == ',')) {
1622 if (!**src) { /* Quit if nothing more */
1625 if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1628 address1++; /* Point to next address slot */
1630 if (addrcount < 1) {
1633 totalsize = sizeof(struct in_addr_list)
1634 + (addrcount - 1) * sizeof(struct in_addr);
1635 result = (struct in_addr_list *) smalloc(totalsize);
1636 result->linkcount = 1;
1637 result->addrcount = addrcount;
1638 address1 = tmpaddrlist;
1639 address2 = result->addr;
1640 for (; addrcount > 0; addrcount--) {
1641 address2->s_addr = address1->s_addr;
1652 * prs_inetaddr(src, result)
1654 * "src" is a value-result parameter; the pointer it points to is updated
1655 * to point to the next data position. "result" points to an unsigned long
1656 * in which an address is returned.
1658 * This function parses the IP address string in ASCII "dot notation" pointed
1659 * to by (*src) and places the result (in network byte order) in the unsigned
1660 * long pointed to by "result". For malformed addresses, -1 is returned,
1661 * (*src) points to the first illegal character, and the unsigned long pointed
1662 * to by "result" is unchanged. Successful calls return 0.
1666 prs_inetaddr(src, result)
1670 char tmpstr[MAXSTRINGLEN];
1672 u_int32 parts[4], *pp;
1676 /* Leading alpha char causes IP addr lookup. */
1677 if (isalpha(**src)) {
1678 /* Lookup IP address. */
1681 while ((isalnum(*s) || (*s == '.') ||
1682 (*s == '-') || (*s == '_') ) &&
1683 (t < &tmpstr[MAXSTRINGLEN - 1]) )
1688 n = lookup_ipa(tmpstr, result);
1690 report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1695 * Parse an address in Internet format:
1697 * a.b.c (with c treated as 16-bits)
1698 * a.b (with b treated as 24 bits)
1702 /* If it's not a digit, return error. */
1703 if (!isdigit(**src))
1705 *pp++ = get_u_long(src);
1707 if (pp < (parts + 4)) {
1714 /* This is handled by the caller. */
1715 if (**src && !(isspace(**src) || (**src == ':'))) {
1721 * Construct the address according to
1722 * the number of parts specified.
1726 case 1: /* a -- 32 bits */
1729 case 2: /* a.b -- 8.24 bits */
1730 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1732 case 3: /* a.b.c -- 8.8.16 bits */
1733 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1734 (parts[2] & 0xFFFF);
1736 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1737 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1738 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1743 *result = htonl(value);
1750 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1751 * string. This string is interpreted as a hardware address and returned
1752 * as a pointer to the actual hardware address, represented as an array of
1755 * The ASCII string must have the proper number of digits for the specified
1756 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1757 * Two-digit sequences (bytes) may be separated with periods (.) and/or
1758 * prefixed with '0x' for readability, but this is not required.
1760 * For bad addresses, the pointer which "src" points to is updated to point
1761 * to the start of the first two-digit sequence which was bad, and the
1762 * function returns a NULL pointer.
1766 prs_haddr(src, htype)
1770 static byte haddr[MAXHADDRLEN];
1772 char tmpstr[MAXSTRINGLEN];
1777 hal = haddrlength(htype); /* Get length of this address type */
1779 report(LOG_ERR, "Invalid addr type for HW addr parse");
1782 tmplen = sizeof(tmpstr);
1783 get_string(src, tmpstr, &tmplen);
1786 /* If it's a valid host name, try to lookup the HW address. */
1788 /* Lookup Hardware Address for hostname. */
1789 if ((hap = lookup_hwa(p, htype)) != NULL)
1790 return hap; /* success */
1791 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1792 /* OK, assume it must be numeric. */
1796 while (hap < haddr + hal) {
1797 if ((*p == '.') || (*p == ':'))
1799 if (interp_byte(&p, hap++) < 0) {
1809 * "src" is a pointer to a character pointer which in turn points to a
1810 * hexadecimal ASCII representation of a byte. This byte is read, the
1811 * character pointer is updated, and the result is deposited into the
1812 * byte pointed to by "retbyte".
1814 * The usual '0x' notation is allowed but not required. The number must be
1815 * a two digit hexadecimal number. If the number is invalid, "src" and
1816 * "retbyte" are left untouched and -1 is returned as the function value.
1817 * Successful calls return 0.
1821 interp_byte(src, retbyte)
1827 if ((*src)[0] == '0' &&
1828 ((*src)[1] == 'x' ||
1829 (*src)[1] == 'X')) {
1830 (*src) += 2; /* allow 0x for hex, but don't require it */
1832 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1835 if (sscanf(*src, "%2x", &v) != 1) {
1839 *retbyte = (byte) (v & 0xFF);
1846 * The parameter "src" points to a character pointer which points to an
1847 * ASCII string representation of an unsigned number. The number is
1848 * returned as an unsigned long and the character pointer is updated to
1849 * point to the first illegal character.
1856 u_int32 value, base;
1860 * Collect number up to first illegal character. Values are specified
1861 * as for C: 0x=hex, 0=octal, other=decimal.
1869 if (**src == 'x' || **src == 'X') {
1873 while ((c = **src)) {
1875 value = (value * base) + (c - '0');
1879 if (base == 16 && isxdigit(c)) {
1880 value = (value << 4) + ((c & ~32) + 10 - 'A');
1892 * Routines for deletion of data associated with the main data structure.
1897 * Frees the entire host data structure given. Does nothing if the passed
1905 struct host *hostptr = (struct host *) hmp;
1906 if (hostptr == NULL)
1908 assert(hostptr->linkcount > 0);
1909 if (--(hostptr->linkcount))
1910 return; /* Still has references */
1911 del_iplist(hostptr->cookie_server);
1912 del_iplist(hostptr->domain_server);
1913 del_iplist(hostptr->gateway);
1914 del_iplist(hostptr->impress_server);
1915 del_iplist(hostptr->log_server);
1916 del_iplist(hostptr->lpr_server);
1917 del_iplist(hostptr->name_server);
1918 del_iplist(hostptr->rlp_server);
1919 del_iplist(hostptr->time_server);
1920 del_iplist(hostptr->nis_server);
1921 del_iplist(hostptr->ntp_server);
1924 * XXX - Add new tags here
1925 * (if the value is an IP list)
1928 del_string(hostptr->hostname);
1929 del_string(hostptr->homedir);
1930 del_string(hostptr->bootfile);
1931 del_string(hostptr->tftpdir);
1932 del_string(hostptr->root_path);
1933 del_string(hostptr->domain_name);
1934 del_string(hostptr->dump_file);
1935 del_string(hostptr->exten_file);
1936 del_string(hostptr->nis_domain);
1938 #ifdef YORK_EX_OPTION
1939 del_string(hostptr->exec_file);
1943 * XXX - Add new tags here
1944 * (if it is a shared string)
1947 del_bindata(hostptr->generic);
1948 free((char *) hostptr);
1954 * Decrements the linkcount on the given IP address data structure. If the
1955 * linkcount goes to zero, the memory associated with the data is freed.
1960 struct in_addr_list *iplist;
1963 if (!(--(iplist->linkcount))) {
1964 free((char *) iplist);
1972 * Decrements the linkcount on a string data structure. If the count
1973 * goes to zero, the memory associated with the string is freed. Does
1974 * nothing if the passed pointer is NULL.
1978 del_string(stringptr)
1979 struct shared_string *stringptr;
1982 if (!(--(stringptr->linkcount))) {
1983 free((char *) stringptr);
1991 * Decrements the linkcount on a shared_bindata data structure. If the
1992 * count goes to zero, the memory associated with the data is freed. Does
1993 * nothing if the passed pointer is NULL.
1997 del_bindata(dataptr)
1998 struct shared_bindata *dataptr;
2001 if (!(--(dataptr->linkcount))) {
2002 free((char *) dataptr);
2010 /* smalloc() -- safe malloc()
2012 * Always returns a valid pointer (if it returns at all). The allocated
2013 * memory is initialized to all zeros. If malloc() returns an error, a
2014 * message is printed using the report() function and the program aborts
2015 * with a status of 1.
2024 retvalue = malloc(nbytes);
2026 report(LOG_ERR, "malloc() failure -- exiting");
2029 bzero(retvalue, nbytes);
2035 * Compare function to determine whether two hardware addresses are
2036 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
2039 * This function is used when retrieving elements from the hardware address
2045 hash_datum *d1, *d2;
2047 struct host *host1 = (struct host *) d1;
2048 struct host *host2 = (struct host *) d2;
2050 if (host1->htype != host2->htype) {
2053 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2061 * Compare function for doing IP address hash table lookup.
2066 hash_datum *d1, *d2;
2068 struct host *host1 = (struct host *) d1;
2069 struct host *host2 = (struct host *) d2;
2071 return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2078 * c-argdecl-indent: 4
2079 * c-continued-statement-offset: 4
2080 * c-continued-brace-offset: -4
2081 * c-label-offset: -4