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