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