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