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