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