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