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