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