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