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