readfile.c revision 1.19 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.19 2011/10/07 10:06:39 joerg 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 break;
690 case E_BAD_VALUE:
691 msg = "bad value";
692 break;
693 default:
694 msg = "unknown error";
695 break;
696 } /* switch */
697 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
698 current_hostname, current_tagname, msg);
699 return -1;
700 }
701 }
702
703
705 /*
706 * Macros for use in the function below:
707 */
708
709 /* Parse one INET address stored directly in MEMBER. */
710 #define PARSE_IA1(MEMBER) do \
711 { \
712 if (optype == OP_BOOLEAN) \
713 return E_SYNTAX_ERROR; \
714 hp->flags.MEMBER = FALSE; \
715 if (optype == OP_ADDITION) { \
716 if (prs_inetaddr(symbol, &value) < 0) \
717 return E_BAD_IPADDR; \
718 hp->MEMBER.s_addr = value; \
719 hp->flags.MEMBER = TRUE; \
720 } \
721 } while (0)
722
723 /* Parse a list of INET addresses pointed to by MEMBER */
724 #define PARSE_IAL(MEMBER) do \
725 { \
726 if (optype == OP_BOOLEAN) \
727 return E_SYNTAX_ERROR; \
728 if (hp->flags.MEMBER) { \
729 hp->flags.MEMBER = FALSE; \
730 assert(hp->MEMBER); \
731 del_iplist(hp->MEMBER); \
732 hp->MEMBER = NULL; \
733 } \
734 if (optype == OP_ADDITION) { \
735 hp->MEMBER = get_addresses(symbol); \
736 if (hp->MEMBER == NULL) \
737 return E_SYNTAX_ERROR; \
738 hp->flags.MEMBER = TRUE; \
739 } \
740 } while (0)
741
742 /* Parse a shared string pointed to by MEMBER */
743 #define PARSE_STR(MEMBER) do \
744 { \
745 if (optype == OP_BOOLEAN) \
746 return E_SYNTAX_ERROR; \
747 if (hp->flags.MEMBER) { \
748 hp->flags.MEMBER = FALSE; \
749 assert(hp->MEMBER); \
750 del_string(hp->MEMBER); \
751 hp->MEMBER = NULL; \
752 } \
753 if (optype == OP_ADDITION) { \
754 hp->MEMBER = get_shared_string(symbol); \
755 if (hp->MEMBER == NULL) \
756 return E_SYNTAX_ERROR; \
757 hp->flags.MEMBER = TRUE; \
758 } \
759 } while (0)
760
761 /* Parse an integer value for MEMBER */
762 #define PARSE_INT(MEMBER) do \
763 { \
764 if (optype == OP_BOOLEAN) \
765 return E_SYNTAX_ERROR; \
766 hp->flags.MEMBER = FALSE; \
767 if (optype == OP_ADDITION) { \
768 value = get_u_long(symbol); \
769 hp->MEMBER = value; \
770 hp->flags.MEMBER = TRUE; \
771 } \
772 } while (0)
773
774 /*
775 * Evaluate the two-character tag symbol pointed to by "symbol" and place
776 * the data in the structure pointed to by "hp". The pointer pointed to
777 * by "symbol" is updated to point past the source string (but may not
778 * point to the next tag entry).
779 *
780 * Obviously, this need a few more comments. . . .
781 */
782 PRIVATE int
783 eval_symbol(char **symbol, struct host *hp)
784 {
785 char tmpstr[MAXSTRINGLEN];
786 byte *tmphaddr;
787 struct symbolmap *symbolptr;
788 u_int32 value;
789 int32 ltimeoff;
790 int i, numsymbols;
791 unsigned len;
792 int optype; /* Indicates boolean, addition, or deletion */
793
794 eat_whitespace(symbol);
795
796 /* Make sure this is set before returning. */
797 current_tagname[0] = (*symbol)[0];
798 current_tagname[1] = (*symbol)[1];
799 current_tagname[2] = 0;
800
801 if ((*symbol)[0] == '\0') {
802 return E_END_OF_ENTRY;
803 }
804 if ((*symbol)[0] == ':') {
805 return SUCCESS;
806 }
807 if ((*symbol)[0] == 'T') { /* generic symbol */
808 (*symbol)++;
809 value = get_u_long(symbol);
810 snprintf(current_tagname, sizeof(current_tagname),
811 "T%d", value);
812 eat_whitespace(symbol);
813 if ((*symbol)[0] != '=') {
814 return E_SYNTAX_ERROR;
815 }
816 (*symbol)++;
817 if (!(hp->generic)) {
818 hp->generic = (struct shared_bindata *)
819 smalloc(sizeof(struct shared_bindata));
820 }
821 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
822 return E_SYNTAX_ERROR;
823 hp->flags.generic = TRUE;
824 return SUCCESS;
825 }
826 /*
827 * Determine the type of operation to be done on this symbol
828 */
829 switch ((*symbol)[2]) {
830 case '=':
831 optype = OP_ADDITION;
832 break;
833 case '@':
834 optype = OP_DELETION;
835 break;
836 case ':':
837 case '\0':
838 optype = OP_BOOLEAN;
839 break;
840 default:
841 return E_SYNTAX_ERROR;
842 }
843
844 symbolptr = symbol_list;
845 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
846 for (i = 0; i < numsymbols; i++) {
847 if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
848 ((symbolptr->symbol)[1] == (*symbol)[1])) {
849 break;
850 }
851 symbolptr++;
852 }
853 if (i >= numsymbols) {
854 return E_UNKNOWN_SYMBOL;
855 }
856 /*
857 * Skip past the = or @ character (to point to the data) if this
858 * isn't a boolean operation. For boolean operations, just skip
859 * over the two-character tag symbol (and nothing else. . . .).
860 */
861 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
862
863 eat_whitespace(symbol);
864
865 /* The cases below are in order by symbolcode value. */
866 switch (symbolptr->symbolcode) {
867
868 case SYM_BOOTFILE:
869 PARSE_STR(bootfile);
870 break;
871
872 case SYM_COOKIE_SERVER:
873 PARSE_IAL(cookie_server);
874 break;
875
876 case SYM_DOMAIN_SERVER:
877 PARSE_IAL(domain_server);
878 break;
879
880 case SYM_GATEWAY:
881 PARSE_IAL(gateway);
882 break;
883
884 case SYM_HWADDR:
885 if (optype == OP_BOOLEAN)
886 return E_SYNTAX_ERROR;
887 hp->flags.haddr = FALSE;
888 if (optype == OP_ADDITION) {
889 /* Default the HW type to Ethernet */
890 if (hp->flags.htype == 0) {
891 hp->flags.htype = TRUE;
892 hp->htype = HTYPE_ETHERNET;
893 }
894 tmphaddr = prs_haddr(symbol, hp->htype);
895 if (!tmphaddr)
896 return E_BAD_HWADDR;
897 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
898 hp->flags.haddr = TRUE;
899 }
900 break;
901
902 case SYM_HOMEDIR:
903 PARSE_STR(homedir);
904 break;
905
906 case SYM_HTYPE:
907 if (optype == OP_BOOLEAN)
908 return E_SYNTAX_ERROR;
909 hp->flags.htype = FALSE;
910 if (optype == OP_ADDITION) {
911 value = 0L; /* Assume an illegal value */
912 eat_whitespace(symbol);
913 if (isdigit((unsigned char)**symbol)) {
914 value = get_u_long(symbol);
915 } else {
916 len = sizeof(tmpstr);
917 (void) get_string(symbol, tmpstr, &len);
918 makelower(tmpstr);
919 numsymbols = sizeof(htnamemap) /
920 sizeof(struct htypename);
921 for (i = 0; i < numsymbols; i++) {
922 if (!strcmp(htnamemap[i].name, tmpstr)) {
923 break;
924 }
925 }
926 if (i < numsymbols) {
927 value = htnamemap[i].htype;
928 }
929 }
930 if (value >= hwinfocnt) {
931 return E_BAD_HWATYPE;
932 }
933 hp->htype = (byte) (value & 0xFF);
934 hp->flags.htype = TRUE;
935 }
936 break;
937
938 case SYM_IMPRESS_SERVER:
939 PARSE_IAL(impress_server);
940 break;
941
942 case SYM_IPADDR:
943 PARSE_IA1(iaddr);
944 break;
945
946 case SYM_LOG_SERVER:
947 PARSE_IAL(log_server);
948 break;
949
950 case SYM_LPR_SERVER:
951 PARSE_IAL(lpr_server);
952 break;
953
954 case SYM_NAME_SERVER:
955 PARSE_IAL(name_server);
956 break;
957
958 case SYM_RLP_SERVER:
959 PARSE_IAL(rlp_server);
960 break;
961
962 case SYM_SUBNET_MASK:
963 PARSE_IA1(subnet_mask);
964 break;
965
966 case SYM_TIME_OFFSET:
967 if (optype == OP_BOOLEAN)
968 return E_SYNTAX_ERROR;
969 hp->flags.time_offset = FALSE;
970 if (optype == OP_ADDITION) {
971 len = sizeof(tmpstr);
972 (void) get_string(symbol, tmpstr, &len);
973 if (!strncmp(tmpstr, "auto", 4)) {
974 hp->time_offset = secondswest;
975 } else {
976 if (sscanf(tmpstr, "%d", <imeoff) != 1)
977 return E_BAD_LONGWORD;
978 hp->time_offset = ltimeoff;
979 }
980 hp->flags.time_offset = TRUE;
981 }
982 break;
983
984 case SYM_TIME_SERVER:
985 PARSE_IAL(time_server);
986 break;
987
988 case SYM_VENDOR_MAGIC:
989 if (optype == OP_BOOLEAN)
990 return E_SYNTAX_ERROR;
991 hp->flags.vm_cookie = FALSE;
992 if (optype == OP_ADDITION) {
993 if (strncmp(*symbol, "auto", 4)) {
994 /* The string is not "auto" */
995 if (!strncmp(*symbol, "rfc", 3)) {
996 bcopy(vm_rfc1048, hp->vm_cookie, 4);
997 } else if (!strncmp(*symbol, "cmu", 3)) {
998 bcopy(vm_cmu, hp->vm_cookie, 4);
999 } else {
1000 if (!isdigit((unsigned char)**symbol))
1001 return E_BAD_IPADDR;
1002 if (prs_inetaddr(symbol, &value) < 0)
1003 return E_BAD_IPADDR;
1004 bcopy(&value, hp->vm_cookie, 4);
1005 }
1006 hp->flags.vm_cookie = TRUE;
1007 }
1008 }
1009 break;
1010
1011 case SYM_SIMILAR_ENTRY:
1012 switch (optype) {
1013 case OP_ADDITION:
1014 fill_defaults(hp, symbol);
1015 break;
1016 default:
1017 return E_SYNTAX_ERROR;
1018 }
1019 break;
1020
1021 case SYM_NAME_SWITCH:
1022 switch (optype) {
1023 case OP_ADDITION:
1024 return E_SYNTAX_ERROR;
1025 case OP_DELETION:
1026 hp->flags.send_name = FALSE;
1027 hp->flags.name_switch = FALSE;
1028 break;
1029 case OP_BOOLEAN:
1030 hp->flags.send_name = TRUE;
1031 hp->flags.name_switch = TRUE;
1032 break;
1033 }
1034 break;
1035
1036 case SYM_BOOTSIZE:
1037 switch (optype) {
1038 case OP_ADDITION:
1039 if (!strncmp(*symbol, "auto", 4)) {
1040 hp->flags.bootsize = TRUE;
1041 hp->flags.bootsize_auto = TRUE;
1042 } else {
1043 hp->bootsize = (unsigned int) get_u_long(symbol);
1044 hp->flags.bootsize = TRUE;
1045 hp->flags.bootsize_auto = FALSE;
1046 }
1047 break;
1048 case OP_DELETION:
1049 hp->flags.bootsize = FALSE;
1050 break;
1051 case OP_BOOLEAN:
1052 hp->flags.bootsize = TRUE;
1053 hp->flags.bootsize_auto = TRUE;
1054 break;
1055 }
1056 break;
1057
1058 case SYM_BOOT_SERVER:
1059 PARSE_IA1(bootserver);
1060 break;
1061
1062 case SYM_TFTPDIR:
1063 PARSE_STR(tftpdir);
1064 if ((hp->tftpdir != NULL) &&
1065 (hp->tftpdir->string[0] != '/'))
1066 return E_BAD_PATHNAME;
1067 break;
1068
1069 case SYM_DUMP_FILE:
1070 PARSE_STR(dump_file);
1071 break;
1072
1073 case SYM_DOMAIN_NAME:
1074 PARSE_STR(domain_name);
1075 break;
1076
1077 case SYM_SWAP_SERVER:
1078 PARSE_IA1(swap_server);
1079 break;
1080
1081 case SYM_ROOT_PATH:
1082 PARSE_STR(root_path);
1083 break;
1084
1085 case SYM_EXTEN_FILE:
1086 PARSE_STR(exten_file);
1087 break;
1088
1089 case SYM_REPLY_ADDR:
1090 PARSE_IA1(reply_addr);
1091 break;
1092
1093 case SYM_NIS_DOMAIN:
1094 PARSE_STR(nis_domain);
1095 break;
1096
1097 case SYM_NIS_SERVER:
1098 PARSE_IAL(nis_server);
1099 break;
1100
1101 case SYM_NTP_SERVER:
1102 PARSE_IAL(ntp_server);
1103 break;
1104
1105 #ifdef YORK_EX_OPTION
1106 case SYM_EXEC_FILE:
1107 PARSE_STR(exec_file);
1108 break;
1109 #endif
1110
1111 case SYM_MSG_SIZE:
1112 PARSE_INT(msg_size);
1113 if (hp->msg_size < BP_MINPKTSZ ||
1114 hp->msg_size > MAX_MSG_SIZE)
1115 return E_BAD_VALUE;
1116 break;
1117
1118 case SYM_MIN_WAIT:
1119 PARSE_INT(min_wait);
1120 if (hp->min_wait == 0)
1121 return E_BAD_VALUE;
1122 break;
1123
1124 /* XXX - Add new tags here */
1125
1126 default:
1127 return E_UNKNOWN_SYMBOL;
1128
1129 } /* switch symbolcode */
1130
1131 return SUCCESS;
1132 }
1133 #undef PARSE_IA1
1134 #undef PARSE_IAL
1135 #undef PARSE_STR
1136
1137
1139
1140
1141 /*
1142 * Read a string from the buffer indirectly pointed to through "src" and
1143 * move it into the buffer pointed to by "dest". A pointer to the maximum
1144 * allowable length of the string (including null-terminator) is passed as
1145 * "length". The actual length of the string which was read is returned in
1146 * the unsigned integer pointed to by "length". This value is the same as
1147 * that which would be returned by applying the strlen() function on the
1148 * destination string (i.e the terminating null is not counted as a
1149 * character). Trailing whitespace is removed from the string. For
1150 * convenience, the function returns the new value of "dest".
1151 *
1152 * The string is read until the maximum number of characters, an unquoted
1153 * colon (:), or a null character is read. The return string in "dest" is
1154 * null-terminated.
1155 */
1156
1157 PRIVATE char *
1158 get_string(char **src, char *dest, unsigned int *length)
1159 {
1160 int n, len, quoteflag;
1161
1162 quoteflag = FALSE;
1163 n = 0;
1164 len = *length - 1;
1165 while ((n < len) && (**src)) {
1166 if (!quoteflag && (**src == ':')) {
1167 break;
1168 }
1169 if (**src == '"') {
1170 (*src)++;
1171 quoteflag = !quoteflag;
1172 continue;
1173 }
1174 if (**src == '\\') {
1175 (*src)++;
1176 if (!**src) {
1177 break;
1178 }
1179 }
1180 *dest++ = *(*src)++;
1181 n++;
1182 }
1183
1184 /*
1185 * Remove that troublesome trailing whitespace. . .
1186 */
1187 while ((n > 0) && isspace((unsigned char)dest[-1])) {
1188 dest--;
1189 n--;
1190 }
1191
1192 *dest = '\0';
1193 *length = n;
1194 return dest;
1195 }
1196
1197
1199
1200 /*
1201 * Read the string indirectly pointed to by "src", update the caller's
1202 * pointer, and return a pointer to a malloc'ed shared_string structure
1203 * containing the string.
1204 *
1205 * The string is read using the same rules as get_string() above.
1206 */
1207
1208 PRIVATE struct shared_string *
1209 get_shared_string(char **src)
1210 {
1211 char retstring[MAXSTRINGLEN];
1212 struct shared_string *s;
1213 unsigned length;
1214
1215 length = sizeof(retstring);
1216 (void) get_string(src, retstring, &length);
1217
1218 s = (struct shared_string *) smalloc(sizeof(struct shared_string) +
1219 length + 1);
1220 s->linkcount = 1;
1221 memcpy(s->string, retstring, length + 1);
1222
1223 return s;
1224 }
1225
1226
1228
1229 /*
1230 * Load RFC1048 generic information directly into a memory buffer.
1231 *
1232 * "src" indirectly points to the ASCII representation of the generic data.
1233 * "dest" points to a string structure which is updated to point to a new
1234 * string with the new data appended to the old string. The old string is
1235 * freed.
1236 *
1237 * The given tag value is inserted with the new data.
1238 *
1239 * The data may be represented as either a stream of hexadecimal numbers
1240 * representing bytes (any or all bytes may optionally start with '0x' and
1241 * be separated with periods ".") or as a quoted string of ASCII
1242 * characters (the quotes are required).
1243 */
1244
1245 PRIVATE int
1246 process_generic(char **src, struct shared_bindata **dest, u_int tagvalue)
1247 {
1248 byte tmpbuf[MAXBUFLEN];
1249 byte *str;
1250 struct shared_bindata *bdata;
1251 u_int newlength, oldlength;
1252
1253 str = tmpbuf;
1254 *str++ = (tagvalue & 0xFF); /* Store tag value */
1255 str++; /* Skip over length field */
1256 if ((*src)[0] == '"') { /* ASCII data */
1257 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
1258 (void) get_string(src, (char *) str, &newlength);
1259 /* Do NOT include the terminating null. */
1260 } else { /* Numeric data */
1261 newlength = 0;
1262 while (newlength < sizeof(tmpbuf) - 2) {
1263 if (interp_byte(src, str++) < 0)
1264 break;
1265 newlength++;
1266 if (**src == '.') {
1267 (*src)++;
1268 }
1269 }
1270 }
1271 if ((*src)[0] != ':')
1272 return -1;
1273
1274 tmpbuf[1] = (newlength & 0xFF);
1275 oldlength = ((*dest)->length);
1276 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1277 + oldlength + newlength + 1);
1278 if (oldlength > 0) {
1279 bcopy((*dest)->data, bdata->data, oldlength);
1280 }
1281 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1282 bdata->length = oldlength + newlength + 2;
1283 bdata->linkcount = 1;
1284 del_bindata(*dest);
1285 *dest = bdata;
1286 return 0;
1287 }
1288
1289
1291
1292 /*
1293 * Verify that the given string makes sense as a hostname (according to
1294 * Appendix 1, page 29 of RFC882).
1295 *
1296 * Return TRUE for good names, FALSE otherwise.
1297 */
1298
1299 PRIVATE boolean
1300 goodname(char *hostname)
1301 {
1302 do {
1303 if (!isalpha((unsigned char)*hostname++)) { /* First character must be a letter */
1304 return FALSE;
1305 }
1306 while (isalnum((unsigned char)*hostname) ||
1307 (*hostname == '-') ||
1308 (*hostname == '_') )
1309 {
1310 hostname++; /* Alphanumeric or a hyphen */
1311 }
1312 if (!isalnum((unsigned char)hostname[-1])) { /* Last must be alphanumeric */
1313 return FALSE;
1314 }
1315 if (*hostname == '\0') {/* Done? */
1316 return TRUE;
1317 }
1318 } while (*hostname++ == '.'); /* Dot, loop for next label */
1319
1320 return FALSE; /* If it's not a dot, lose */
1321 }
1322
1323
1325
1326 /*
1327 * Null compare function -- always returns FALSE so an element is always
1328 * inserted into a hash table (i.e. there is never a collision with an
1329 * existing element).
1330 */
1331
1332 PRIVATE boolean
1333 nullcmp(hash_datum *d1, hash_datum *d2)
1334 {
1335 return FALSE;
1336 }
1337
1338
1339 /*
1340 * Function for comparing a string with the hostname field of a host
1341 * structure.
1342 */
1343
1344 boolean
1345 nmcmp(hash_datum *d1, hash_datum *d2)
1346 {
1347 char *name = (char *) d1; /* XXX - OK? */
1348 struct host *hp = (struct host *) d2;
1349
1350 return !strcmp(name, hp->hostname->string);
1351 }
1352
1353
1354 /*
1355 * Compare function to determine whether two hardware addresses are
1356 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1357 * otherwise.
1358 *
1359 * If the hardware addresses of "host1" and "host2" are identical, but
1360 * they are on different IP subnets, this function returns FALSE.
1361 *
1362 * This function is used when inserting elements into the hardware address
1363 * hash table.
1364 */
1365
1366 PRIVATE boolean
1367 hwinscmp(hash_datum *d1, hash_datum *d2)
1368 {
1369 struct host *host1 = (struct host *) d1;
1370 struct host *host2 = (struct host *) d2;
1371
1372 if (host1->htype != host2->htype) {
1373 return FALSE;
1374 }
1375 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1376 return FALSE;
1377 }
1378 /* XXX - Is the subnet_mask field set yet? */
1379 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1380 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1381 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1382 {
1383 return FALSE;
1384 }
1385 }
1386 return TRUE;
1387 }
1388
1389
1391 /*
1392 * Macros for use in the function below:
1393 */
1394
1395 #define DUP_COPY(MEMBER) do \
1396 { \
1397 if (!hp->flags.MEMBER) { \
1398 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1399 hp->MEMBER = hp2->MEMBER; \
1400 } \
1401 } \
1402 } while (0)
1403
1404 #define DUP_LINK(MEMBER) do \
1405 { \
1406 if (!hp->flags.MEMBER) { \
1407 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1408 assert(hp2->MEMBER); \
1409 hp->MEMBER = hp2->MEMBER; \
1410 (hp->MEMBER->linkcount)++; \
1411 } \
1412 } \
1413 } while (0)
1414
1415 /*
1416 * Process the "similar entry" symbol.
1417 *
1418 * The host specified as the value of the "tc" symbol is used as a template
1419 * for the current host entry. Symbol values not explicitly set in the
1420 * current host entry are inferred from the template entry.
1421 */
1422 PRIVATE void
1423 fill_defaults(struct host *hp, char **src)
1424 {
1425 unsigned int tlen, hashcode;
1426 struct host *hp2;
1427 char tstring[MAXSTRINGLEN];
1428
1429 tlen = sizeof(tstring);
1430 (void) get_string(src, tstring, &tlen);
1431 hashcode = hash_HashFunction((u_char *) tstring, tlen);
1432 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1433
1434 if (hp2 == NULL) {
1435 report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1436 return;
1437 }
1438 DUP_LINK(bootfile);
1439 DUP_LINK(cookie_server);
1440 DUP_LINK(domain_server);
1441 DUP_LINK(gateway);
1442 /* haddr not copied */
1443 DUP_LINK(homedir);
1444 DUP_COPY(htype);
1445
1446 DUP_LINK(impress_server);
1447 /* iaddr not copied */
1448 DUP_LINK(log_server);
1449 DUP_LINK(lpr_server);
1450 DUP_LINK(name_server);
1451 DUP_LINK(rlp_server);
1452
1453 DUP_COPY(subnet_mask);
1454 DUP_COPY(time_offset);
1455 DUP_LINK(time_server);
1456
1457 if (!hp->flags.vm_cookie) {
1458 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1459 bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1460 }
1461 }
1462 if (!hp->flags.name_switch) {
1463 if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1464 hp->flags.send_name = hp2->flags.send_name;
1465 }
1466 }
1467 if (!hp->flags.bootsize) {
1468 if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1469 hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1470 hp->bootsize = hp2->bootsize;
1471 }
1472 }
1473 DUP_COPY(bootserver);
1474
1475 DUP_LINK(tftpdir);
1476 DUP_LINK(dump_file);
1477 DUP_LINK(domain_name);
1478
1479 DUP_COPY(swap_server);
1480 DUP_LINK(root_path);
1481 DUP_LINK(exten_file);
1482
1483 DUP_COPY(reply_addr);
1484
1485 DUP_LINK(nis_domain);
1486 DUP_LINK(nis_server);
1487 DUP_LINK(ntp_server);
1488
1489 #ifdef YORK_EX_OPTION
1490 DUP_LINK(exec_file);
1491 #endif
1492
1493 DUP_COPY(msg_size);
1494 DUP_COPY(min_wait);
1495
1496 /* XXX - Add new tags here */
1497
1498 DUP_LINK(generic);
1499
1500 }
1501 #undef DUP_COPY
1502 #undef DUP_LINK
1503
1504
1506
1507 /*
1508 * This function adjusts the caller's pointer to point just past the
1509 * first-encountered colon. If it runs into a null character, it leaves
1510 * the pointer pointing to it.
1511 */
1512
1513 PRIVATE void
1514 adjust(char **s)
1515 {
1516 char *t;
1517
1518 t = *s;
1519 while (*t && (*t != ':')) {
1520 t++;
1521 }
1522 if (*t) {
1523 t++;
1524 }
1525 *s = t;
1526 }
1527
1528
1529
1530
1531 /*
1532 * This function adjusts the caller's pointer to point to the first
1533 * non-whitespace character. If it runs into a null character, it leaves
1534 * the pointer pointing to it.
1535 */
1536
1537 PRIVATE void
1538 eat_whitespace(char **s)
1539 {
1540 char *t;
1541
1542 t = *s;
1543 while (*t && isspace((unsigned char)*t)) {
1544 t++;
1545 }
1546 *s = t;
1547 }
1548
1549
1550
1551 /*
1552 * This function converts the given string to all lowercase.
1553 */
1554
1555 PRIVATE void
1556 makelower(char *s)
1557 {
1558 while (*s) {
1559 if (isupper((unsigned char)*s)) {
1560 *s = tolower((unsigned char)*s);
1561 }
1562 s++;
1563 }
1564 }
1565
1566
1568
1569 /*
1570 *
1571 * N O T E :
1572 *
1573 * In many of the functions which follow, a parameter such as "src" or
1574 * "symbol" is passed as a pointer to a pointer to something. This is
1575 * done for the purpose of letting the called function update the
1576 * caller's copy of the parameter (i.e. to effect call-by-reference
1577 * parameter passing). The value of the actual parameter is only used
1578 * to locate the real parameter of interest and then update this indirect
1579 * parameter.
1580 *
1581 * I'm sure somebody out there won't like this. . . .
1582 * (Yea, because it usually makes code slower... -gwr)
1583 *
1584 */
1585
1586
1588
1589 /*
1590 * "src" points to a character pointer which points to an ASCII string of
1591 * whitespace-separated IP addresses. A pointer to an in_addr_list
1592 * structure containing the list of addresses is returned. NULL is
1593 * returned if no addresses were found at all. The pointer pointed to by
1594 * "src" is updated to point to the first non-address (illegal) character.
1595 */
1596
1597 PRIVATE struct in_addr_list *
1598 get_addresses(char **src)
1599 {
1600 struct in_addr tmpaddrlist[MAXINADDRS];
1601 struct in_addr *address1, *address2;
1602 struct in_addr_list *result;
1603 unsigned addrcount, totalsize;
1604
1605 address1 = tmpaddrlist;
1606 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1607 while (isspace((unsigned char)**src) || (**src == ',')) {
1608 (*src)++;
1609 }
1610 if (!**src) { /* Quit if nothing more */
1611 break;
1612 }
1613 if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1614 break;
1615 }
1616 address1++; /* Point to next address slot */
1617 }
1618 if (addrcount < 1) {
1619 result = NULL;
1620 } else {
1621 totalsize = sizeof(struct in_addr_list)
1622 + (addrcount - 1) * sizeof(struct in_addr);
1623 result = (struct in_addr_list *) smalloc(totalsize);
1624 result->linkcount = 1;
1625 result->addrcount = addrcount;
1626 address1 = tmpaddrlist;
1627 address2 = result->addr;
1628 for (; addrcount > 0; addrcount--) {
1629 address2->s_addr = address1->s_addr;
1630 address1++;
1631 address2++;
1632 }
1633 }
1634 return result;
1635 }
1636
1637
1639
1640 /*
1641 * prs_inetaddr(src, result)
1642 *
1643 * "src" is a value-result parameter; the pointer it points to is updated
1644 * to point to the next data position. "result" points to an unsigned long
1645 * in which an address is returned.
1646 *
1647 * This function parses the IP address string in ASCII "dot notation" pointed
1648 * to by (*src) and places the result (in network byte order) in the unsigned
1649 * long pointed to by "result". For malformed addresses, -1 is returned,
1650 * (*src) points to the first illegal character, and the unsigned long pointed
1651 * to by "result" is unchanged. Successful calls return 0.
1652 */
1653
1654 PRIVATE int
1655 prs_inetaddr(char **src, u_int32 *result)
1656 {
1657 char tmpstr[MAXSTRINGLEN];
1658 u_int32 value;
1659 u_int32 parts[4], *pp;
1660 int n;
1661 char *s, *t;
1662
1663 #if 1 /* XXX - experimental */
1664 /* Leading alpha char causes IP addr lookup. */
1665 if (isalpha((unsigned char)**src)) {
1666 /* Lookup IP address. */
1667 s = *src;
1668 t = tmpstr;
1669 while ((isalnum((unsigned char)*s) || (*s == '.') ||
1670 (*s == '-') || (*s == '_') ) &&
1671 (t < &tmpstr[MAXSTRINGLEN - 1]) )
1672 *t++ = *s++;
1673 *t = '\0';
1674 *src = s;
1675
1676 n = lookup_ipa(tmpstr, result);
1677 if (n < 0)
1678 report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1679 return n;
1680 }
1681 #endif
1682
1683 /*
1684 * Parse an address in Internet format:
1685 * a.b.c.d
1686 * a.b.c (with c treated as 16-bits)
1687 * a.b (with b treated as 24 bits)
1688 */
1689 pp = parts;
1690 loop:
1691 /* If it's not a digit, return error. */
1692 if (!isdigit((unsigned char)**src))
1693 return -1;
1694 *pp++ = get_u_long(src);
1695 if (**src == '.') {
1696 if (pp < (parts + 4)) {
1697 (*src)++;
1698 goto loop;
1699 }
1700 return (-1);
1701 }
1702 #if 0
1703 /* This is handled by the caller. */
1704 if (**src && !((unsigned char)isspace(**src) || (**src == ':'))) {
1705 return (-1);
1706 }
1707 #endif
1708
1709 /*
1710 * Construct the address according to
1711 * the number of parts specified.
1712 */
1713 n = pp - parts;
1714 switch (n) {
1715 case 1: /* a -- 32 bits */
1716 value = parts[0];
1717 break;
1718 case 2: /* a.b -- 8.24 bits */
1719 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1720 break;
1721 case 3: /* a.b.c -- 8.8.16 bits */
1722 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1723 (parts[2] & 0xFFFF);
1724 break;
1725 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1726 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1727 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1728 break;
1729 default:
1730 return (-1);
1731 }
1732 *result = htonl(value);
1733 return (0);
1734 }
1735
1736
1738
1739 /*
1740 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1741 * string. This string is interpreted as a hardware address and returned
1742 * as a pointer to the actual hardware address, represented as an array of
1743 * bytes.
1744 *
1745 * The ASCII string must have the proper number of digits for the specified
1746 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1747 * Two-digit sequences (bytes) may be separated with periods (.) and/or
1748 * prefixed with '0x' for readability, but this is not required.
1749 *
1750 * For bad addresses, the pointer which "src" points to is updated to point
1751 * to the start of the first two-digit sequence which was bad, and the
1752 * function returns a NULL pointer.
1753 */
1754
1755 PRIVATE byte *
1756 prs_haddr(char **src, u_int htype)
1757 {
1758 static byte haddr[MAXHADDRLEN];
1759 byte *hap;
1760 char tmpstr[MAXSTRINGLEN];
1761 u_int tmplen;
1762 unsigned hal;
1763 char *p;
1764
1765 hal = haddrlength(htype); /* Get length of this address type */
1766 if (hal <= 0) {
1767 report(LOG_ERR, "Invalid addr type for HW addr parse");
1768 return NULL;
1769 }
1770 tmplen = sizeof(tmpstr);
1771 get_string(src, tmpstr, &tmplen);
1772 p = tmpstr;
1773
1774 #if 1 /* XXX - experimental */
1775 /* If it's a valid host name, try to lookup the HW address. */
1776 if (goodname(p)) {
1777 /* Lookup Hardware Address for hostname. */
1778 if ((hap = lookup_hwa(p, htype)) != NULL)
1779 return hap; /* success */
1780 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1781 /* OK, assume it must be numeric. */
1782 }
1783 #endif
1784
1785 hap = haddr;
1786 while (hap < haddr + hal) {
1787 if ((*p == '.') || (*p == ':'))
1788 p++;
1789 if (interp_byte(&p, hap++) < 0) {
1790 return NULL;
1791 }
1792 }
1793 return haddr;
1794 }
1795
1796
1798
1799 /*
1800 * "src" is a pointer to a character pointer which in turn points to a
1801 * hexadecimal ASCII representation of a byte. This byte is read, the
1802 * character pointer is updated, and the result is deposited into the
1803 * byte pointed to by "retbyte".
1804 *
1805 * The usual '0x' notation is allowed but not required. The number must be
1806 * a two digit hexadecimal number. If the number is invalid, "src" and
1807 * "retbyte" are left untouched and -1 is returned as the function value.
1808 * Successful calls return 0.
1809 */
1810
1811 PRIVATE int
1812 interp_byte(char **src, byte *retbyte)
1813 {
1814 int v;
1815
1816 if ((*src)[0] == '0' &&
1817 ((*src)[1] == 'x' ||
1818 (*src)[1] == 'X')) {
1819 (*src) += 2; /* allow 0x for hex, but don't require it */
1820 }
1821 if (!isxdigit((unsigned char)(*src)[0]) || !isxdigit((unsigned char)(*src)[1])) {
1822 return -1;
1823 }
1824 if (sscanf(*src, "%2x", &v) != 1) {
1825 return -1;
1826 }
1827 (*src) += 2;
1828 *retbyte = (byte) (v & 0xFF);
1829 return 0;
1830 }
1831
1832
1834
1835 /*
1836 * The parameter "src" points to a character pointer which points to an
1837 * ASCII string representation of an unsigned number. The number is
1838 * returned as an unsigned long and the character pointer is updated to
1839 * point to the first illegal character.
1840 */
1841
1842 PRIVATE u_int32
1843 get_u_long(char **src)
1844 {
1845 u_int32 value, base;
1846 char c;
1847
1848 /*
1849 * Collect number up to first illegal character. Values are specified
1850 * as for C: 0x=hex, 0=octal, other=decimal.
1851 */
1852 value = 0;
1853 base = 10;
1854 if (**src == '0') {
1855 base = 8;
1856 (*src)++;
1857 }
1858 if (**src == 'x' || **src == 'X') {
1859 base = 16;
1860 (*src)++;
1861 }
1862 while ((c = **src)) {
1863 if (isdigit((unsigned char)c)) {
1864 value = (value * base) + (c - '0');
1865 (*src)++;
1866 continue;
1867 }
1868 if (base == 16 && isxdigit((unsigned char)c)) {
1869 value = (value << 4) + ((c & ~32) + 10 - 'A');
1870 (*src)++;
1871 continue;
1872 }
1873 break;
1874 }
1875 return value;
1876 }
1877
1878
1880
1881 /*
1882 * Routines for deletion of data associated with the main data structure.
1883 */
1884
1885
1886 /*
1887 * Frees the entire host data structure given. Does nothing if the passed
1888 * pointer is NULL.
1889 */
1890
1891 PRIVATE void
1892 free_host(hash_datum *hmp)
1893 {
1894 struct host *hostptr = (struct host *) hmp;
1895 if (hostptr == NULL)
1896 return;
1897 assert(hostptr->linkcount > 0);
1898 if (--(hostptr->linkcount))
1899 return; /* Still has references */
1900 del_iplist(hostptr->cookie_server);
1901 del_iplist(hostptr->domain_server);
1902 del_iplist(hostptr->gateway);
1903 del_iplist(hostptr->impress_server);
1904 del_iplist(hostptr->log_server);
1905 del_iplist(hostptr->lpr_server);
1906 del_iplist(hostptr->name_server);
1907 del_iplist(hostptr->rlp_server);
1908 del_iplist(hostptr->time_server);
1909 del_iplist(hostptr->nis_server);
1910 del_iplist(hostptr->ntp_server);
1911
1912 /*
1913 * XXX - Add new tags here
1914 * (if the value is an IP list)
1915 */
1916
1917 del_string(hostptr->hostname);
1918 del_string(hostptr->homedir);
1919 del_string(hostptr->bootfile);
1920 del_string(hostptr->tftpdir);
1921 del_string(hostptr->root_path);
1922 del_string(hostptr->domain_name);
1923 del_string(hostptr->dump_file);
1924 del_string(hostptr->exten_file);
1925 del_string(hostptr->nis_domain);
1926
1927 #ifdef YORK_EX_OPTION
1928 del_string(hostptr->exec_file);
1929 #endif
1930
1931 /*
1932 * XXX - Add new tags here
1933 * (if it is a shared string)
1934 */
1935
1936 del_bindata(hostptr->generic);
1937 free((char *) hostptr);
1938 }
1939
1940
1942
1943 /*
1944 * Decrements the linkcount on the given IP address data structure. If the
1945 * linkcount goes to zero, the memory associated with the data is freed.
1946 */
1947
1948 PRIVATE void
1949 del_iplist(struct in_addr_list *iplist)
1950 {
1951 if (iplist) {
1952 if (!(--(iplist->linkcount))) {
1953 free((char *) iplist);
1954 }
1955 }
1956 }
1957
1958
1959
1960 /*
1961 * Decrements the linkcount on a string data structure. If the count
1962 * goes to zero, the memory associated with the string is freed. Does
1963 * nothing if the passed pointer is NULL.
1964 */
1965
1966 PRIVATE void
1967 del_string(struct shared_string *stringptr)
1968 {
1969 if (stringptr) {
1970 if (!(--(stringptr->linkcount))) {
1971 free((char *) stringptr);
1972 }
1973 }
1974 }
1975
1976
1977
1978 /*
1979 * Decrements the linkcount on a shared_bindata data structure. If the
1980 * count goes to zero, the memory associated with the data is freed. Does
1981 * nothing if the passed pointer is NULL.
1982 */
1983
1984 PRIVATE void
1985 del_bindata(struct shared_bindata *dataptr)
1986 {
1987 if (dataptr) {
1988 if (!(--(dataptr->linkcount))) {
1989 free((char *) dataptr);
1990 }
1991 }
1992 }
1993
1994
1996
1997
1998 /* smalloc() -- safe malloc()
1999 *
2000 * Always returns a valid pointer (if it returns at all). The allocated
2001 * memory is initialized to all zeros. If malloc() returns an error, a
2002 * message is printed using the report() function and the program aborts
2003 * with a status of 1.
2004 */
2005
2006 PRIVATE char *
2007 smalloc(unsigned int nbytes)
2008 {
2009 char *retvalue;
2010
2011 retvalue = malloc(nbytes);
2012 if (!retvalue) {
2013 report(LOG_ERR, "malloc() failure -- exiting");
2014 exit(1);
2015 }
2016 bzero(retvalue, nbytes);
2017 return retvalue;
2018 }
2019
2020
2022 /*
2023 * Compare function to determine whether two hardware addresses are
2024 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
2025 * otherwise.
2026 *
2027 * This function is used when retrieving elements from the hardware address
2028 * hash table.
2029 */
2030
2031 boolean
2032 hwlookcmp(hash_datum *d1, hash_datum *d2)
2033 {
2034 struct host *host1 = (struct host *) d1;
2035 struct host *host2 = (struct host *) d2;
2036
2037 if (host1->htype != host2->htype) {
2038 return FALSE;
2039 }
2040 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2041 return FALSE;
2042 }
2043 return TRUE;
2044 }
2045
2046
2047 /*
2048 * Compare function for doing IP address hash table lookup.
2049 */
2050
2051 boolean
2052 iplookcmp(hash_datum *d1, hash_datum *d2)
2053 {
2054 struct host *host1 = (struct host *) d1;
2055 struct host *host2 = (struct host *) d2;
2056
2057 return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2058 }
2059
2060 /*
2061 * Local Variables:
2062 * tab-width: 4
2063 * c-indent-level: 4
2064 * c-argdecl-indent: 4
2065 * c-continued-statement-offset: 4
2066 * c-continued-brace-offset: -4
2067 * c-label-offset: -4
2068 * c-brace-offset: 0
2069 * End:
2070 */
2071