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