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