Remove duplicate line and add missing MLINK.
[dragonfly.git] / libexec / bootpd / readfile.c
blob9426065fe153f1076ad5a2b0e9f04c033cba3a7b
1 /************************************************************************
2 Copyright 1988, 1991 by Carnegie Mellon University
4 All Rights Reserved
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.
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.
22 $FreeBSD: src/libexec/bootpd/readfile.c,v 1.6.2.2 2001/10/14 21:25:02 iedowse Exp $
23 $DragonFly: src/libexec/bootpd/readfile.c,v 1.2 2003/06/17 04:27:07 dillon Exp $
25 ************************************************************************/
28 * bootpd configuration file reading code.
30 * The routines in this file deal with reading, interpreting, and storing
31 * the information found in the bootpd configuration file (usually
32 * /etc/bootptab).
36 #include <sys/errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/file.h>
40 #include <sys/time.h>
41 #include <netinet/in.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <assert.h>
48 #include <syslog.h>
50 #ifndef USE_BFUNCS
51 #include <memory.h>
52 /* Yes, memcpy is OK here (no overlapped copies). */
53 #define bcopy(a,b,c) memcpy(b,a,c)
54 #define bzero(p,l) memset(p,0,l)
55 #define bcmp(a,b,c) memcmp(a,b,c)
56 #endif
58 #include "bootp.h"
59 #include "hash.h"
60 #include "hwaddr.h"
61 #include "lookup.h"
62 #include "readfile.h"
63 #include "report.h"
64 #include "tzone.h"
65 #include "bootpd.h"
67 #define HASHTABLESIZE 257 /* Hash table size (prime) */
69 /* Non-standard hardware address type (see bootp.h) */
70 #define HTYPE_DIRECT 0
72 /* Error codes returned by eval_symbol: */
73 #define SUCCESS 0
74 #define E_END_OF_ENTRY (-1)
75 #define E_SYNTAX_ERROR (-2)
76 #define E_UNKNOWN_SYMBOL (-3)
77 #define E_BAD_IPADDR (-4)
78 #define E_BAD_HWADDR (-5)
79 #define E_BAD_LONGWORD (-6)
80 #define E_BAD_HWATYPE (-7)
81 #define E_BAD_PATHNAME (-8)
82 #define E_BAD_VALUE (-9)
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 #define SYM_MSG_SIZE 34
119 #define SYM_MIN_WAIT 35
120 /* XXX - Add new tags here */
122 #define OP_ADDITION 1 /* Operations on tags */
123 #define OP_DELETION 2
124 #define OP_BOOLEAN 3
126 #define MAXINADDRS 16 /* Max size of an IP address list */
127 #define MAXBUFLEN 256 /* Max temp buffer space */
128 #define MAXENTRYLEN 2048 /* Max size of an entire entry */
133 * Structure used to map a configuration-file symbol (such as "ds") to a
134 * unique integer.
137 struct symbolmap {
138 char *symbol;
139 int symbolcode;
143 struct htypename {
144 char *name;
145 byte htype;
149 PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
150 PRIVATE int nentries; /* Total number of entries */
151 PRIVATE int32 modtime = 0; /* Last modification time of bootptab */
152 PRIVATE char *current_hostname; /* Name of the current entry. */
153 PRIVATE char current_tagname[8];
156 * List of symbolic names used in the bootptab file. The order and actual
157 * values of the symbol codes (SYM_. . .) are unimportant, but they must
158 * all be unique.
161 PRIVATE struct symbolmap symbol_list[] = {
162 {"bf", SYM_BOOTFILE},
163 {"bs", SYM_BOOTSIZE},
164 {"cs", SYM_COOKIE_SERVER},
165 {"df", SYM_DUMP_FILE},
166 {"dn", SYM_DOMAIN_NAME},
167 {"ds", SYM_DOMAIN_SERVER},
168 {"ef", SYM_EXTEN_FILE},
169 {"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */
170 {"gw", SYM_GATEWAY},
171 {"ha", SYM_HWADDR},
172 {"hd", SYM_HOMEDIR},
173 {"hn", SYM_NAME_SWITCH},
174 {"ht", SYM_HTYPE},
175 {"im", SYM_IMPRESS_SERVER},
176 {"ip", SYM_IPADDR},
177 {"lg", SYM_LOG_SERVER},
178 {"lp", SYM_LPR_SERVER},
179 {"ms", SYM_MSG_SIZE},
180 {"mw", SYM_MIN_WAIT},
181 {"ns", SYM_NAME_SERVER},
182 {"nt", SYM_NTP_SERVER},
183 {"ra", SYM_REPLY_ADDR},
184 {"rl", SYM_RLP_SERVER},
185 {"rp", SYM_ROOT_PATH},
186 {"sa", SYM_BOOT_SERVER},
187 {"sm", SYM_SUBNET_MASK},
188 {"sw", SYM_SWAP_SERVER},
189 {"tc", SYM_SIMILAR_ENTRY},
190 {"td", SYM_TFTPDIR},
191 {"to", SYM_TIME_OFFSET},
192 {"ts", SYM_TIME_SERVER},
193 {"vm", SYM_VENDOR_MAGIC},
194 {"yd", SYM_NIS_DOMAIN},
195 {"ys", SYM_NIS_SERVER},
196 /* XXX - Add new tags here */
201 * List of symbolic names for hardware types. Name translates into
202 * hardware type code listed with it. Names must begin with a letter
203 * and must be all lowercase. This is searched linearly, so put
204 * commonly-used entries near the beginning.
207 PRIVATE struct htypename htnamemap[] = {
208 {"ethernet", HTYPE_ETHERNET},
209 {"ethernet3", HTYPE_EXP_ETHERNET},
210 {"ether", HTYPE_ETHERNET},
211 {"ether3", HTYPE_EXP_ETHERNET},
212 {"ieee802", HTYPE_IEEE802},
213 {"tr", HTYPE_IEEE802},
214 {"token-ring", HTYPE_IEEE802},
215 {"pronet", HTYPE_PRONET},
216 {"chaos", HTYPE_CHAOS},
217 {"arcnet", HTYPE_ARCNET},
218 {"ax.25", HTYPE_AX25},
219 {"direct", HTYPE_DIRECT},
220 {"serial", HTYPE_DIRECT},
221 {"slip", HTYPE_DIRECT},
222 {"ppp", HTYPE_DIRECT}
228 * Externals and forward declarations.
231 #ifdef __STDC__
232 #define P(args) args
233 #else
234 #define P(args) ()
235 #endif
237 extern boolean iplookcmp();
238 boolean nmcmp P((hash_datum *, hash_datum *));
240 PRIVATE void
241 adjust P((char **));
242 PRIVATE void
243 del_string P((struct shared_string *));
244 PRIVATE void
245 del_bindata P((struct shared_bindata *));
246 PRIVATE void
247 del_iplist P((struct in_addr_list *));
248 PRIVATE void
249 eat_whitespace P((char **));
250 PRIVATE int
251 eval_symbol P((char **, struct host *));
252 PRIVATE void
253 fill_defaults P((struct host *, char **));
254 PRIVATE void
255 free_host P((hash_datum *));
256 PRIVATE struct in_addr_list *
257 get_addresses P((char **));
258 PRIVATE struct shared_string *
259 get_shared_string P((char **));
260 PRIVATE char *
261 get_string P((char **, char *, u_int *));
262 PRIVATE u_int32
263 get_u_long P((char **));
264 PRIVATE boolean
265 goodname P((char *));
266 PRIVATE boolean
267 hwinscmp P((hash_datum *, hash_datum *));
268 PRIVATE int
269 interp_byte P((char **, byte *));
270 PRIVATE void
271 makelower P((char *));
272 PRIVATE boolean
273 nullcmp P((hash_datum *, hash_datum *));
274 PRIVATE int
275 process_entry P((struct host *, char *));
276 PRIVATE int
277 process_generic P((char **, struct shared_bindata **, u_int));
278 PRIVATE byte *
279 prs_haddr P((char **, u_int));
280 PRIVATE int
281 prs_inetaddr P((char **, u_int32 *));
282 PRIVATE void
283 read_entry P((FILE *, char *, u_int *));
284 PRIVATE char *
285 smalloc P((u_int));
287 #undef P
291 * Vendor magic cookies for CMU and RFC1048
293 u_char vm_cmu[4] = VM_CMU;
294 u_char vm_rfc1048[4] = VM_RFC1048;
297 * Main hash tables
299 hash_tbl *hwhashtable;
300 hash_tbl *iphashtable;
301 hash_tbl *nmhashtable;
304 * Allocate hash tables for hardware address, ip address, and hostname
305 * (shared by bootpd and bootpef)
307 void
308 rdtab_init()
310 hwhashtable = hash_Init(HASHTABLESIZE);
311 iphashtable = hash_Init(HASHTABLESIZE);
312 nmhashtable = hash_Init(HASHTABLESIZE);
313 if (!(hwhashtable && iphashtable && nmhashtable)) {
314 report(LOG_ERR, "Unable to allocate hash tables.");
315 exit(1);
321 * Read bootptab database file. Avoid rereading the file if the
322 * write date hasn't changed since the last time we read it.
325 void
326 readtab(force)
327 int force;
329 struct host *hp;
330 FILE *fp;
331 struct stat st;
332 unsigned hashcode, buflen;
333 static char buffer[MAXENTRYLEN];
336 * Check the last modification time.
338 if (stat(bootptab, &st) < 0) {
339 report(LOG_ERR, "stat on \"%s\": %s",
340 bootptab, get_errmsg());
341 return;
343 #ifdef DEBUG
344 if (debug > 3) {
345 char timestr[28];
346 strcpy(timestr, ctime(&(st.st_mtime)));
347 /* zap the newline */
348 timestr[24] = '\0';
349 report(LOG_INFO, "bootptab mtime: %s",
350 timestr);
352 #endif
353 if ((force == 0) &&
354 (st.st_mtime == modtime) &&
355 st.st_nlink) {
357 * hasn't been modified or deleted yet.
359 return;
361 if (debug)
362 report(LOG_INFO, "reading %s\"%s\"",
363 (modtime != 0L) ? "new " : "",
364 bootptab);
367 * Open bootptab file.
369 if ((fp = fopen(bootptab, "r")) == NULL) {
370 report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
371 return;
374 * Record file modification time.
376 if (fstat(fileno(fp), &st) < 0) {
377 report(LOG_ERR, "fstat: %s", get_errmsg());
378 fclose(fp);
379 return;
381 modtime = st.st_mtime;
384 * Entirely erase all hash tables.
386 hash_Reset(hwhashtable, free_host);
387 hash_Reset(iphashtable, free_host);
388 hash_Reset(nmhashtable, free_host);
390 nhosts = 0;
391 nentries = 0;
392 while (TRUE) {
393 buflen = sizeof(buffer);
394 read_entry(fp, buffer, &buflen);
395 if (buflen == 0) { /* More entries? */
396 break;
398 hp = (struct host *) smalloc(sizeof(struct host));
399 bzero((char *) hp, sizeof(*hp));
400 /* the link count it zero */
403 * Get individual info
405 if (process_entry(hp, buffer) < 0) {
406 hp->linkcount = 1;
407 free_host((hash_datum *) hp);
408 continue;
411 * If this is not a dummy entry, and the IP or HW
412 * address is not yet set, try to get them here.
413 * Dummy entries have . as first char of name.
415 if (goodname(hp->hostname->string)) {
416 char *hn = hp->hostname->string;
417 u_int32 value;
418 if (hp->flags.iaddr == 0) {
419 if (lookup_ipa(hn, &value)) {
420 report(LOG_ERR, "can not get IP addr for %s", hn);
421 report(LOG_ERR, "(dummy names should start with '.')");
422 } else {
423 hp->iaddr.s_addr = value;
424 hp->flags.iaddr = TRUE;
427 /* Set default subnet mask. */
428 if (hp->flags.subnet_mask == 0) {
429 if (lookup_netmask(hp->iaddr.s_addr, &value)) {
430 report(LOG_ERR, "can not get netmask for %s", hn);
431 } else {
432 hp->subnet_mask.s_addr = value;
433 hp->flags.subnet_mask = TRUE;
437 if (hp->flags.iaddr) {
438 nhosts++;
440 /* Register by HW addr if known. */
441 if (hp->flags.htype && hp->flags.haddr) {
442 /* We will either insert it or free it. */
443 hp->linkcount++;
444 hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
445 if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
446 report(LOG_NOTICE, "duplicate %s address: %s",
447 netname(hp->htype),
448 haddrtoa(hp->haddr, haddrlength(hp->htype)));
449 free_host((hash_datum *) hp);
450 continue;
453 /* Register by IP addr if known. */
454 if (hp->flags.iaddr) {
455 hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
456 if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
457 report(LOG_ERR,
458 "hash_Insert() failed on IP address insertion");
459 } else {
460 /* Just inserted the host struct in a new hash list. */
461 hp->linkcount++;
464 /* Register by Name (always known) */
465 hashcode = hash_HashFunction((u_char *) hp->hostname->string,
466 strlen(hp->hostname->string));
467 if (hash_Insert(nmhashtable, hashcode, nullcmp,
468 hp->hostname->string, hp) < 0) {
469 report(LOG_ERR,
470 "hash_Insert() failed on insertion of hostname: \"%s\"",
471 hp->hostname->string);
472 } else {
473 /* Just inserted the host struct in a new hash list. */
474 hp->linkcount++;
477 nentries++;
480 fclose(fp);
481 if (debug)
482 report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
483 nentries, nhosts, bootptab);
484 return;
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 preceded by a backslash cause
494 * line-continuation onto the next line. The entry is terminated by a
495 * newline character which is not preceded by a backslash. Sequences
496 * surrounded by double quotes are taken literally (including newlines, but
497 * not backslashes).
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).
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.
508 PRIVATE void
509 read_entry(fp, buffer, bufsiz)
510 FILE *fp;
511 char *buffer;
512 unsigned *bufsiz;
514 int c, length;
516 length = 0;
519 * Eat whitespace, blank lines, and comment lines.
521 top:
522 c = fgetc(fp);
523 if (c < 0) {
524 goto done; /* Exit if end-of-file */
526 if (isspace(c)) {
527 goto top; /* Skip over whitespace */
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 */
535 if (c == '\n') {
536 goto top; /* Try to read the next line */
540 ungetc(c, fp); /* Other character, push it back to reprocess it */
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 (\).
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 */
560 *buffer++ = c; /* Store the literal character */
561 length++;
562 if (length < *bufsiz - 1) {
563 goto mainloop;
564 } else {
565 goto done;
567 case '"':
568 *buffer++ = '"'; /* Store double-quote */
569 length++;
570 if (length >= *bufsiz - 1) {
571 goto done;
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;
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;
598 case ':':
599 *buffer++ = c; /* Store colons */
600 length++;
601 if (length >= *bufsiz - 1) {
602 goto done;
604 do { /* But remove whitespace after them */
605 c = fgetc(fp);
606 if ((c < 0) || (c == '\n')) {
607 goto done;
609 } while (isspace(c)); /* Skip whitespace */
611 if (c == '\\') { /* Backslash quotes next character */
612 c = fgetc(fp);
613 if (c < 0) {
614 goto done;
616 if (c == '\n') {
617 goto top; /* Backslash-newline continuation */
620 /* fall through if "other" character */
621 default:
622 *buffer++ = c; /* Store other characters */
623 length++;
624 if (length >= *bufsiz - 1) {
625 goto done;
628 goto mainloop; /* Keep going */
630 done:
631 *buffer = '\0'; /* Terminate string */
632 *bufsiz = length; /* Tell the caller its length */
638 * Parse out all the various tags and parameters in the host entry pointed
639 * to by "src". Stuff all the data into the appropriate fields of the
640 * host structure pointed to by "host". If there is any problem with the
641 * entry, an error message is reported via report(), no further processing
642 * is done, and -1 is returned. Successful calls return 0.
644 * (Some errors probably shouldn't be so completely fatal. . . .)
647 PRIVATE int
648 process_entry(host, src)
649 struct host *host;
650 char *src;
652 int retval;
653 char *msg;
655 if (!host || *src == '\0') {
656 return -1;
658 host->hostname = get_shared_string(&src);
659 #if 0
660 /* Be more liberal for the benefit of dummy tag names. */
661 if (!goodname(host->hostname->string)) {
662 report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
663 del_string(host->hostname);
664 return -1;
666 #endif
667 current_hostname = host->hostname->string;
668 adjust(&src);
669 while (TRUE) {
670 retval = eval_symbol(&src, host);
671 if (retval == SUCCESS) {
672 adjust(&src);
673 continue;
675 if (retval == E_END_OF_ENTRY) {
676 /* The default subnet mask is set in readtab() */
677 return 0;
679 /* Some kind of error. */
680 switch (retval) {
681 case E_SYNTAX_ERROR:
682 msg = "bad syntax";
683 break;
684 case E_UNKNOWN_SYMBOL:
685 msg = "unknown symbol";
686 break;
687 case E_BAD_IPADDR:
688 msg = "bad INET address";
689 break;
690 case E_BAD_HWADDR:
691 msg = "bad hardware address";
692 break;
693 case E_BAD_LONGWORD:
694 msg = "bad longword value";
695 break;
696 case E_BAD_HWATYPE:
697 msg = "bad HW address type";
698 break;
699 case E_BAD_PATHNAME:
700 msg = "bad pathname (need leading '/')";
701 break;
702 case E_BAD_VALUE:
703 msg = "bad value";
704 break;
705 default:
706 msg = "unknown error";
707 break;
708 } /* switch */
709 report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
710 current_hostname, current_tagname, msg);
711 return -1;
717 * Macros for use in the function below:
720 /* Parse one INET address stored directly in MEMBER. */
721 #define PARSE_IA1(MEMBER) do \
723 if (optype == OP_BOOLEAN) \
724 return E_SYNTAX_ERROR; \
725 hp->flags.MEMBER = FALSE; \
726 if (optype == OP_ADDITION) { \
727 if (prs_inetaddr(symbol, &value) < 0) \
728 return E_BAD_IPADDR; \
729 hp->MEMBER.s_addr = value; \
730 hp->flags.MEMBER = TRUE; \
732 } while (0)
734 /* Parse a list of INET addresses pointed to by MEMBER */
735 #define PARSE_IAL(MEMBER) do \
737 if (optype == OP_BOOLEAN) \
738 return E_SYNTAX_ERROR; \
739 if (hp->flags.MEMBER) { \
740 hp->flags.MEMBER = FALSE; \
741 assert(hp->MEMBER); \
742 del_iplist(hp->MEMBER); \
743 hp->MEMBER = NULL; \
745 if (optype == OP_ADDITION) { \
746 hp->MEMBER = get_addresses(symbol); \
747 if (hp->MEMBER == NULL) \
748 return E_SYNTAX_ERROR; \
749 hp->flags.MEMBER = TRUE; \
751 } while (0)
753 /* Parse a shared string pointed to by MEMBER */
754 #define PARSE_STR(MEMBER) do \
756 if (optype == OP_BOOLEAN) \
757 return E_SYNTAX_ERROR; \
758 if (hp->flags.MEMBER) { \
759 hp->flags.MEMBER = FALSE; \
760 assert(hp->MEMBER); \
761 del_string(hp->MEMBER); \
762 hp->MEMBER = NULL; \
764 if (optype == OP_ADDITION) { \
765 hp->MEMBER = get_shared_string(symbol); \
766 if (hp->MEMBER == NULL) \
767 return E_SYNTAX_ERROR; \
768 hp->flags.MEMBER = TRUE; \
770 } while (0)
772 /* Parse an unsigned integer value for MEMBER */
773 #define PARSE_UINT(MEMBER) do \
775 if (optype == OP_BOOLEAN) \
776 return E_SYNTAX_ERROR; \
777 hp->flags.MEMBER = FALSE; \
778 if (optype == OP_ADDITION) { \
779 value = get_u_long(symbol); \
780 hp->MEMBER = value; \
781 hp->flags.MEMBER = TRUE; \
783 } while (0)
786 * Evaluate the two-character tag symbol pointed to by "symbol" and place
787 * the data in the structure pointed to by "hp". The pointer pointed to
788 * by "symbol" is updated to point past the source string (but may not
789 * point to the next tag entry).
791 * Obviously, this need a few more comments. . . .
793 PRIVATE int
794 eval_symbol(symbol, hp)
795 char **symbol;
796 struct host *hp;
798 char tmpstr[MAXSTRINGLEN];
799 byte *tmphaddr;
800 struct symbolmap *symbolptr;
801 u_int32 value;
802 int32 timeoff;
803 int i, numsymbols;
804 unsigned len;
805 int optype; /* Indicates boolean, addition, or deletion */
807 eat_whitespace(symbol);
809 /* Make sure this is set before returning. */
810 current_tagname[0] = (*symbol)[0];
811 current_tagname[1] = (*symbol)[1];
812 current_tagname[2] = 0;
814 if ((*symbol)[0] == '\0') {
815 return E_END_OF_ENTRY;
817 if ((*symbol)[0] == ':') {
818 return SUCCESS;
820 if ((*symbol)[0] == 'T') { /* generic symbol */
821 (*symbol)++;
822 value = get_u_long(symbol);
823 snprintf(current_tagname, sizeof(current_tagname),
824 "T%d", (int)value);
825 eat_whitespace(symbol);
826 if ((*symbol)[0] != '=') {
827 return E_SYNTAX_ERROR;
829 (*symbol)++;
830 if (!(hp->generic)) {
831 hp->generic = (struct shared_bindata *)
832 smalloc(sizeof(struct shared_bindata));
834 if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
835 return E_SYNTAX_ERROR;
836 hp->flags.generic = TRUE;
837 return SUCCESS;
840 * Determine the type of operation to be done on this symbol
842 switch ((*symbol)[2]) {
843 case '=':
844 optype = OP_ADDITION;
845 break;
846 case '@':
847 optype = OP_DELETION;
848 break;
849 case ':':
850 case '\0':
851 optype = OP_BOOLEAN;
852 break;
853 default:
854 return E_SYNTAX_ERROR;
857 symbolptr = symbol_list;
858 numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
859 for (i = 0; i < numsymbols; i++) {
860 if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
861 ((symbolptr->symbol)[1] == (*symbol)[1])) {
862 break;
864 symbolptr++;
866 if (i >= numsymbols) {
867 return E_UNKNOWN_SYMBOL;
870 * Skip past the = or @ character (to point to the data) if this
871 * isn't a boolean operation. For boolean operations, just skip
872 * over the two-character tag symbol (and nothing else. . . .).
874 (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
876 eat_whitespace(symbol);
878 /* The cases below are in order by symbolcode value. */
879 switch (symbolptr->symbolcode) {
881 case SYM_BOOTFILE:
882 PARSE_STR(bootfile);
883 break;
885 case SYM_COOKIE_SERVER:
886 PARSE_IAL(cookie_server);
887 break;
889 case SYM_DOMAIN_SERVER:
890 PARSE_IAL(domain_server);
891 break;
893 case SYM_GATEWAY:
894 PARSE_IAL(gateway);
895 break;
897 case SYM_HWADDR:
898 if (optype == OP_BOOLEAN)
899 return E_SYNTAX_ERROR;
900 hp->flags.haddr = FALSE;
901 if (optype == OP_ADDITION) {
902 /* Default the HW type to Ethernet */
903 if (hp->flags.htype == 0) {
904 hp->flags.htype = TRUE;
905 hp->htype = HTYPE_ETHERNET;
907 tmphaddr = prs_haddr(symbol, hp->htype);
908 if (!tmphaddr)
909 return E_BAD_HWADDR;
910 bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
911 hp->flags.haddr = TRUE;
913 break;
915 case SYM_HOMEDIR:
916 PARSE_STR(homedir);
917 break;
919 case SYM_HTYPE:
920 if (optype == OP_BOOLEAN)
921 return E_SYNTAX_ERROR;
922 hp->flags.htype = FALSE;
923 if (optype == OP_ADDITION) {
924 value = 0L; /* Assume an illegal value */
925 eat_whitespace(symbol);
926 if (isdigit(**symbol)) {
927 value = get_u_long(symbol);
928 } else {
929 len = sizeof(tmpstr);
930 (void) get_string(symbol, tmpstr, &len);
931 makelower(tmpstr);
932 numsymbols = sizeof(htnamemap) /
933 sizeof(struct htypename);
934 for (i = 0; i < numsymbols; i++) {
935 if (!strcmp(htnamemap[i].name, tmpstr)) {
936 break;
939 if (i < numsymbols) {
940 value = htnamemap[i].htype;
943 if (value >= hwinfocnt) {
944 return E_BAD_HWATYPE;
946 hp->htype = (byte) (value & 0xFF);
947 hp->flags.htype = TRUE;
949 break;
951 case SYM_IMPRESS_SERVER:
952 PARSE_IAL(impress_server);
953 break;
955 case SYM_IPADDR:
956 PARSE_IA1(iaddr);
957 break;
959 case SYM_LOG_SERVER:
960 PARSE_IAL(log_server);
961 break;
963 case SYM_LPR_SERVER:
964 PARSE_IAL(lpr_server);
965 break;
967 case SYM_NAME_SERVER:
968 PARSE_IAL(name_server);
969 break;
971 case SYM_RLP_SERVER:
972 PARSE_IAL(rlp_server);
973 break;
975 case SYM_SUBNET_MASK:
976 PARSE_IA1(subnet_mask);
977 break;
979 case SYM_TIME_OFFSET:
980 if (optype == OP_BOOLEAN)
981 return E_SYNTAX_ERROR;
982 hp->flags.time_offset = FALSE;
983 if (optype == OP_ADDITION) {
984 len = sizeof(tmpstr);
985 (void) get_string(symbol, tmpstr, &len);
986 if (!strncmp(tmpstr, "auto", 4)) {
987 hp->time_offset = secondswest;
988 } else {
989 if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
990 return E_BAD_LONGWORD;
991 hp->time_offset = timeoff;
993 hp->flags.time_offset = TRUE;
995 break;
997 case SYM_TIME_SERVER:
998 PARSE_IAL(time_server);
999 break;
1001 case SYM_VENDOR_MAGIC:
1002 if (optype == OP_BOOLEAN)
1003 return E_SYNTAX_ERROR;
1004 hp->flags.vm_cookie = FALSE;
1005 if (optype == OP_ADDITION) {
1006 if (strncmp(*symbol, "auto", 4)) {
1007 /* The string is not "auto" */
1008 if (!strncmp(*symbol, "rfc", 3)) {
1009 bcopy(vm_rfc1048, hp->vm_cookie, 4);
1010 } else if (!strncmp(*symbol, "cmu", 3)) {
1011 bcopy(vm_cmu, hp->vm_cookie, 4);
1012 } else {
1013 if (!isdigit(**symbol))
1014 return E_BAD_IPADDR;
1015 if (prs_inetaddr(symbol, &value) < 0)
1016 return E_BAD_IPADDR;
1017 bcopy(&value, hp->vm_cookie, 4);
1019 hp->flags.vm_cookie = TRUE;
1022 break;
1024 case SYM_SIMILAR_ENTRY:
1025 switch (optype) {
1026 case OP_ADDITION:
1027 fill_defaults(hp, symbol);
1028 break;
1029 default:
1030 return E_SYNTAX_ERROR;
1032 break;
1034 case SYM_NAME_SWITCH:
1035 switch (optype) {
1036 case OP_ADDITION:
1037 return E_SYNTAX_ERROR;
1038 case OP_DELETION:
1039 hp->flags.send_name = FALSE;
1040 hp->flags.name_switch = FALSE;
1041 break;
1042 case OP_BOOLEAN:
1043 hp->flags.send_name = TRUE;
1044 hp->flags.name_switch = TRUE;
1045 break;
1047 break;
1049 case SYM_BOOTSIZE:
1050 switch (optype) {
1051 case OP_ADDITION:
1052 if (!strncmp(*symbol, "auto", 4)) {
1053 hp->flags.bootsize = TRUE;
1054 hp->flags.bootsize_auto = TRUE;
1055 } else {
1056 hp->bootsize = (unsigned int) get_u_long(symbol);
1057 hp->flags.bootsize = TRUE;
1058 hp->flags.bootsize_auto = FALSE;
1060 break;
1061 case OP_DELETION:
1062 hp->flags.bootsize = FALSE;
1063 break;
1064 case OP_BOOLEAN:
1065 hp->flags.bootsize = TRUE;
1066 hp->flags.bootsize_auto = TRUE;
1067 break;
1069 break;
1071 case SYM_BOOT_SERVER:
1072 PARSE_IA1(bootserver);
1073 break;
1075 case SYM_TFTPDIR:
1076 PARSE_STR(tftpdir);
1077 if ((hp->tftpdir != NULL) &&
1078 (hp->tftpdir->string[0] != '/'))
1079 return E_BAD_PATHNAME;
1080 break;
1082 case SYM_DUMP_FILE:
1083 PARSE_STR(dump_file);
1084 break;
1086 case SYM_DOMAIN_NAME:
1087 PARSE_STR(domain_name);
1088 break;
1090 case SYM_SWAP_SERVER:
1091 PARSE_IA1(swap_server);
1092 break;
1094 case SYM_ROOT_PATH:
1095 PARSE_STR(root_path);
1096 break;
1098 case SYM_EXTEN_FILE:
1099 PARSE_STR(exten_file);
1100 break;
1102 case SYM_REPLY_ADDR:
1103 PARSE_IA1(reply_addr);
1104 break;
1106 case SYM_NIS_DOMAIN:
1107 PARSE_STR(nis_domain);
1108 break;
1110 case SYM_NIS_SERVER:
1111 PARSE_IAL(nis_server);
1112 break;
1114 case SYM_NTP_SERVER:
1115 PARSE_IAL(ntp_server);
1116 break;
1118 #ifdef YORK_EX_OPTION
1119 case SYM_EXEC_FILE:
1120 PARSE_STR(exec_file);
1121 break;
1122 #endif
1124 case SYM_MSG_SIZE:
1125 PARSE_UINT(msg_size);
1126 if (hp->msg_size < BP_MINPKTSZ ||
1127 hp->msg_size > MAX_MSG_SIZE)
1128 return E_BAD_VALUE;
1129 break;
1131 case SYM_MIN_WAIT:
1132 PARSE_UINT(min_wait);
1133 break;
1135 /* XXX - Add new tags here */
1137 default:
1138 return E_UNKNOWN_SYMBOL;
1140 } /* switch symbolcode */
1142 return SUCCESS;
1144 #undef PARSE_IA1
1145 #undef PARSE_IAL
1146 #undef PARSE_STR
1152 * Read a string from the buffer indirectly pointed to through "src" and
1153 * move it into the buffer pointed to by "dest". A pointer to the maximum
1154 * allowable length of the string (including null-terminator) is passed as
1155 * "length". The actual length of the string which was read is returned in
1156 * the unsigned integer pointed to by "length". This value is the same as
1157 * that which would be returned by applying the strlen() function on the
1158 * destination string (i.e the terminating null is not counted as a
1159 * character). Trailing whitespace is removed from the string. For
1160 * convenience, the function returns the new value of "dest".
1162 * The string is read until the maximum number of characters, an unquoted
1163 * colon (:), or a null character is read. The return string in "dest" is
1164 * null-terminated.
1167 PRIVATE char *
1168 get_string(src, dest, length)
1169 char **src, *dest;
1170 unsigned *length;
1172 int n, len, quoteflag;
1174 quoteflag = FALSE;
1175 n = 0;
1176 len = *length - 1;
1177 while ((n < len) && (**src)) {
1178 if (!quoteflag && (**src == ':')) {
1179 break;
1181 if (**src == '"') {
1182 (*src)++;
1183 quoteflag = !quoteflag;
1184 continue;
1186 if (**src == '\\') {
1187 (*src)++;
1188 if (!**src) {
1189 break;
1192 *dest++ = *(*src)++;
1193 n++;
1197 * Remove that troublesome trailing whitespace. . .
1199 while ((n > 0) && isspace(dest[-1])) {
1200 dest--;
1201 n--;
1204 *dest = '\0';
1205 *length = n;
1206 return dest;
1212 * Read the string indirectly pointed to by "src", update the caller's
1213 * pointer, and return a pointer to a malloc'ed shared_string structure
1214 * containing the string.
1216 * The string is read using the same rules as get_string() above.
1219 PRIVATE struct shared_string *
1220 get_shared_string(src)
1221 char **src;
1223 char retstring[MAXSTRINGLEN];
1224 struct shared_string *s;
1225 unsigned length;
1227 length = sizeof(retstring);
1228 (void) get_string(src, retstring, &length);
1230 s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1231 + length);
1232 s->linkcount = 1;
1233 strcpy(s->string, retstring);
1235 return s;
1241 * Load RFC1048 generic information directly into a memory buffer.
1243 * "src" indirectly points to the ASCII representation of the generic data.
1244 * "dest" points to a string structure which is updated to point to a new
1245 * string with the new data appended to the old string. The old string is
1246 * freed.
1248 * The given tag value is inserted with the new data.
1250 * The data may be represented as either a stream of hexadecimal numbers
1251 * representing bytes (any or all bytes may optionally start with '0x' and
1252 * be separated with periods ".") or as a quoted string of ASCII
1253 * characters (the quotes are required).
1256 PRIVATE int
1257 process_generic(src, dest, tagvalue)
1258 char **src;
1259 struct shared_bindata **dest;
1260 u_int tagvalue;
1262 byte tmpbuf[MAXBUFLEN];
1263 byte *str;
1264 struct shared_bindata *bdata;
1265 u_int newlength, oldlength;
1267 str = tmpbuf;
1268 *str++ = (tagvalue & 0xFF); /* Store tag value */
1269 str++; /* Skip over length field */
1270 if ((*src)[0] == '"') { /* ASCII data */
1271 newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
1272 (void) get_string(src, (char *) str, &newlength);
1273 newlength++; /* null terminator */
1274 } else { /* Numeric data */
1275 newlength = 0;
1276 while (newlength < sizeof(tmpbuf) - 2) {
1277 if (interp_byte(src, str++) < 0)
1278 break;
1279 newlength++;
1280 if (**src == '.') {
1281 (*src)++;
1285 if ((*src)[0] != ':')
1286 return -1;
1288 tmpbuf[1] = (newlength & 0xFF);
1289 oldlength = ((*dest)->length);
1290 bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1291 + oldlength + newlength + 1);
1292 if (oldlength > 0) {
1293 bcopy((*dest)->data, bdata->data, oldlength);
1295 bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1296 bdata->length = oldlength + newlength + 2;
1297 bdata->linkcount = 1;
1298 if (*dest) {
1299 del_bindata(*dest);
1301 *dest = bdata;
1302 return 0;
1308 * Verify that the given string makes sense as a hostname (according to
1309 * Appendix 1, page 29 of RFC882).
1311 * Return TRUE for good names, FALSE otherwise.
1314 PRIVATE boolean
1315 goodname(hostname)
1316 register char *hostname;
1318 do {
1319 if (!isalpha(*hostname++)) { /* First character must be a letter */
1320 return FALSE;
1322 while (isalnum(*hostname) ||
1323 (*hostname == '-') ||
1324 (*hostname == '_') )
1326 hostname++; /* Alphanumeric or a hyphen */
1328 if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
1329 return FALSE;
1331 if (*hostname == '\0') {/* Done? */
1332 return TRUE;
1334 } while (*hostname++ == '.'); /* Dot, loop for next label */
1336 return FALSE; /* If it's not a dot, lose */
1342 * Null compare function -- always returns FALSE so an element is always
1343 * inserted into a hash table (i.e. there is never a collision with an
1344 * existing element).
1347 PRIVATE boolean
1348 nullcmp(d1, d2)
1349 hash_datum *d1, *d2;
1351 return FALSE;
1356 * Function for comparing a string with the hostname field of a host
1357 * structure.
1360 boolean
1361 nmcmp(d1, d2)
1362 hash_datum *d1, *d2;
1364 char *name = (char *) d1; /* XXX - OK? */
1365 struct host *hp = (struct host *) d2;
1367 return !strcmp(name, hp->hostname->string);
1372 * Compare function to determine whether two hardware addresses are
1373 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1374 * otherwise.
1376 * If the hardware addresses of "host1" and "host2" are identical, but
1377 * they are on different IP subnets, this function returns FALSE.
1379 * This function is used when inserting elements into the hardware address
1380 * hash table.
1383 PRIVATE boolean
1384 hwinscmp(d1, d2)
1385 hash_datum *d1, *d2;
1387 struct host *host1 = (struct host *) d1;
1388 struct host *host2 = (struct host *) d2;
1390 if (host1->htype != host2->htype) {
1391 return FALSE;
1393 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1394 return FALSE;
1396 /* XXX - Is the subnet_mask field set yet? */
1397 if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1398 if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1399 ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1401 return FALSE;
1404 return TRUE;
1409 * Macros for use in the function below:
1412 #define DUP_COPY(MEMBER) do \
1414 if (!hp->flags.MEMBER) { \
1415 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1416 hp->MEMBER = hp2->MEMBER; \
1419 } while (0)
1421 #define DUP_LINK(MEMBER) do \
1423 if (!hp->flags.MEMBER) { \
1424 if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1425 assert(hp2->MEMBER); \
1426 hp->MEMBER = hp2->MEMBER; \
1427 (hp->MEMBER->linkcount)++; \
1430 } while (0)
1433 * Process the "similar entry" symbol.
1435 * The host specified as the value of the "tc" symbol is used as a template
1436 * for the current host entry. Symbol values not explicitly set in the
1437 * current host entry are inferred from the template entry.
1439 PRIVATE void
1440 fill_defaults(hp, src)
1441 struct host *hp;
1442 char **src;
1444 unsigned int tlen, hashcode;
1445 struct host *hp2;
1446 char tstring[MAXSTRINGLEN];
1448 tlen = sizeof(tstring);
1449 (void) get_string(src, tstring, &tlen);
1450 hashcode = hash_HashFunction((u_char *) tstring, tlen);
1451 hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1453 if (hp2 == NULL) {
1454 report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1455 return;
1457 DUP_LINK(bootfile);
1458 DUP_LINK(cookie_server);
1459 DUP_LINK(domain_server);
1460 DUP_LINK(gateway);
1461 /* haddr not copied */
1462 DUP_LINK(homedir);
1463 DUP_COPY(htype);
1465 DUP_LINK(impress_server);
1466 /* iaddr not copied */
1467 DUP_LINK(log_server);
1468 DUP_LINK(lpr_server);
1469 DUP_LINK(name_server);
1470 DUP_LINK(rlp_server);
1472 DUP_COPY(subnet_mask);
1473 DUP_COPY(time_offset);
1474 DUP_LINK(time_server);
1476 if (!hp->flags.vm_cookie) {
1477 if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1478 bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1481 if (!hp->flags.name_switch) {
1482 if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1483 hp->flags.send_name = hp2->flags.send_name;
1486 if (!hp->flags.bootsize) {
1487 if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1488 hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1489 hp->bootsize = hp2->bootsize;
1492 DUP_COPY(bootserver);
1494 DUP_LINK(tftpdir);
1495 DUP_LINK(dump_file);
1496 DUP_LINK(domain_name);
1498 DUP_COPY(swap_server);
1499 DUP_LINK(root_path);
1500 DUP_LINK(exten_file);
1502 DUP_COPY(reply_addr);
1504 DUP_LINK(nis_domain);
1505 DUP_LINK(nis_server);
1506 DUP_LINK(ntp_server);
1508 #ifdef YORK_EX_OPTION
1509 DUP_LINK(exec_file);
1510 #endif
1512 DUP_COPY(msg_size);
1513 DUP_COPY(min_wait);
1515 /* XXX - Add new tags here */
1517 DUP_LINK(generic);
1520 #undef DUP_COPY
1521 #undef DUP_LINK
1526 * This function adjusts the caller's pointer to point just past the
1527 * first-encountered colon. If it runs into a null character, it leaves
1528 * the pointer pointing to it.
1531 PRIVATE void
1532 adjust(s)
1533 char **s;
1535 register char *t;
1537 t = *s;
1538 while (*t && (*t != ':')) {
1539 t++;
1541 if (*t) {
1542 t++;
1544 *s = t;
1551 * This function adjusts the caller's pointer to point to the first
1552 * non-whitespace character. If it runs into a null character, it leaves
1553 * the pointer pointing to it.
1556 PRIVATE void
1557 eat_whitespace(s)
1558 char **s;
1560 register char *t;
1562 t = *s;
1563 while (*t && isspace(*t)) {
1564 t++;
1566 *s = t;
1572 * This function converts the given string to all lowercase.
1575 PRIVATE void
1576 makelower(s)
1577 char *s;
1579 while (*s) {
1580 if (isupper(*s)) {
1581 *s = tolower(*s);
1583 s++;
1591 * N O T E :
1593 * In many of the functions which follow, a parameter such as "src" or
1594 * "symbol" is passed as a pointer to a pointer to something. This is
1595 * done for the purpose of letting the called function update the
1596 * caller's copy of the parameter (i.e. to effect call-by-reference
1597 * parameter passing). The value of the actual parameter is only used
1598 * to locate the real parameter of interest and then update this indirect
1599 * parameter.
1601 * I'm sure somebody out there won't like this. . . .
1602 * (Yea, because it usually makes code slower... -gwr)
1609 * "src" points to a character pointer which points to an ASCII string of
1610 * whitespace-separated IP addresses. A pointer to an in_addr_list
1611 * structure containing the list of addresses is returned. NULL is
1612 * returned if no addresses were found at all. The pointer pointed to by
1613 * "src" is updated to point to the first non-address (illegal) character.
1616 PRIVATE struct in_addr_list *
1617 get_addresses(src)
1618 char **src;
1620 struct in_addr tmpaddrlist[MAXINADDRS];
1621 struct in_addr *address1, *address2;
1622 struct in_addr_list *result;
1623 unsigned addrcount, totalsize;
1625 address1 = tmpaddrlist;
1626 for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1627 while (isspace(**src) || (**src == ',')) {
1628 (*src)++;
1630 if (!**src) { /* Quit if nothing more */
1631 break;
1633 if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1634 break;
1636 address1++; /* Point to next address slot */
1638 if (addrcount < 1) {
1639 result = NULL;
1640 } else {
1641 totalsize = sizeof(struct in_addr_list)
1642 + (addrcount - 1) * sizeof(struct in_addr);
1643 result = (struct in_addr_list *) smalloc(totalsize);
1644 result->linkcount = 1;
1645 result->addrcount = addrcount;
1646 address1 = tmpaddrlist;
1647 address2 = result->addr;
1648 for (; addrcount > 0; addrcount--) {
1649 address2->s_addr = address1->s_addr;
1650 address1++;
1651 address2++;
1654 return result;
1660 * prs_inetaddr(src, result)
1662 * "src" is a value-result parameter; the pointer it points to is updated
1663 * to point to the next data position. "result" points to an unsigned long
1664 * in which an address is returned.
1666 * This function parses the IP address string in ASCII "dot notation" pointed
1667 * to by (*src) and places the result (in network byte order) in the unsigned
1668 * long pointed to by "result". For malformed addresses, -1 is returned,
1669 * (*src) points to the first illegal character, and the unsigned long pointed
1670 * to by "result" is unchanged. Successful calls return 0.
1673 PRIVATE int
1674 prs_inetaddr(src, result)
1675 char **src;
1676 u_int32 *result;
1678 char tmpstr[MAXSTRINGLEN];
1679 register u_int32 value;
1680 u_int32 parts[4], *pp;
1681 int n;
1682 char *s, *t;
1684 /* Leading alpha char causes IP addr lookup. */
1685 if (isalpha(**src)) {
1686 /* Lookup IP address. */
1687 s = *src;
1688 t = tmpstr;
1689 while ((isalnum(*s) || (*s == '.') ||
1690 (*s == '-') || (*s == '_') ) &&
1691 (t < &tmpstr[MAXSTRINGLEN - 1]) )
1692 *t++ = *s++;
1693 *t = '\0';
1694 *src = s;
1696 n = lookup_ipa(tmpstr, result);
1697 if (n < 0)
1698 report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1699 return n;
1703 * Parse an address in Internet format:
1704 * a.b.c.d
1705 * a.b.c (with c treated as 16-bits)
1706 * a.b (with b treated as 24 bits)
1708 pp = parts;
1709 loop:
1710 /* If it's not a digit, return error. */
1711 if (!isdigit(**src))
1712 return -1;
1713 *pp++ = get_u_long(src);
1714 if (**src == '.') {
1715 if (pp < (parts + 4)) {
1716 (*src)++;
1717 goto loop;
1719 return (-1);
1721 #if 0
1722 /* This is handled by the caller. */
1723 if (**src && !(isspace(**src) || (**src == ':'))) {
1724 return (-1);
1726 #endif
1729 * Construct the address according to
1730 * the number of parts specified.
1732 n = pp - parts;
1733 switch (n) {
1734 case 1: /* a -- 32 bits */
1735 value = parts[0];
1736 break;
1737 case 2: /* a.b -- 8.24 bits */
1738 value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1739 break;
1740 case 3: /* a.b.c -- 8.8.16 bits */
1741 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1742 (parts[2] & 0xFFFF);
1743 break;
1744 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1745 value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1746 ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1747 break;
1748 default:
1749 return (-1);
1751 *result = htonl(value);
1752 return (0);
1758 * "src" points to a pointer which in turn points to a hexadecimal ASCII
1759 * string. This string is interpreted as a hardware address and returned
1760 * as a pointer to the actual hardware address, represented as an array of
1761 * bytes.
1763 * The ASCII string must have the proper number of digits for the specified
1764 * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1765 * Two-digit sequences (bytes) may be separated with periods (.) and/or
1766 * prefixed with '0x' for readability, but this is not required.
1768 * For bad addresses, the pointer which "src" points to is updated to point
1769 * to the start of the first two-digit sequence which was bad, and the
1770 * function returns a NULL pointer.
1773 PRIVATE byte *
1774 prs_haddr(src, htype)
1775 char **src;
1776 u_int htype;
1778 static byte haddr[MAXHADDRLEN];
1779 byte *hap;
1780 char tmpstr[MAXSTRINGLEN];
1781 u_int tmplen;
1782 unsigned hal;
1783 char *p;
1785 hal = haddrlength(htype); /* Get length of this address type */
1786 if (hal <= 0) {
1787 report(LOG_ERR, "Invalid addr type for HW addr parse");
1788 return NULL;
1790 tmplen = sizeof(tmpstr);
1791 get_string(src, tmpstr, &tmplen);
1792 p = tmpstr;
1794 /* If it's a valid host name, try to lookup the HW address. */
1795 if (goodname(p)) {
1796 /* Lookup Hardware Address for hostname. */
1797 if ((hap = lookup_hwa(p, htype)) != NULL)
1798 return hap; /* success */
1799 report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1800 /* OK, assume it must be numeric. */
1803 hap = haddr;
1804 while (hap < haddr + hal) {
1805 if ((*p == '.') || (*p == ':'))
1806 p++;
1807 if (interp_byte(&p, hap++) < 0) {
1808 return NULL;
1811 return haddr;
1817 * "src" is a pointer to a character pointer which in turn points to a
1818 * hexadecimal ASCII representation of a byte. This byte is read, the
1819 * character pointer is updated, and the result is deposited into the
1820 * byte pointed to by "retbyte".
1822 * The usual '0x' notation is allowed but not required. The number must be
1823 * a two digit hexadecimal number. If the number is invalid, "src" and
1824 * "retbyte" are left untouched and -1 is returned as the function value.
1825 * Successful calls return 0.
1828 PRIVATE int
1829 interp_byte(src, retbyte)
1830 char **src;
1831 byte *retbyte;
1833 int v;
1835 if ((*src)[0] == '0' &&
1836 ((*src)[1] == 'x' ||
1837 (*src)[1] == 'X')) {
1838 (*src) += 2; /* allow 0x for hex, but don't require it */
1840 if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1841 return -1;
1843 if (sscanf(*src, "%2x", &v) != 1) {
1844 return -1;
1846 (*src) += 2;
1847 *retbyte = (byte) (v & 0xFF);
1848 return 0;
1854 * The parameter "src" points to a character pointer which points to an
1855 * ASCII string representation of an unsigned number. The number is
1856 * returned as an unsigned long and the character pointer is updated to
1857 * point to the first illegal character.
1860 PRIVATE u_int32
1861 get_u_long(src)
1862 char **src;
1864 register u_int32 value, base;
1865 char c;
1868 * Collect number up to first illegal character. Values are specified
1869 * as for C: 0x=hex, 0=octal, other=decimal.
1871 value = 0;
1872 base = 10;
1873 if (**src == '0') {
1874 base = 8;
1875 (*src)++;
1877 if (**src == 'x' || **src == 'X') {
1878 base = 16;
1879 (*src)++;
1881 while ((c = **src)) {
1882 if (isdigit(c)) {
1883 value = (value * base) + (c - '0');
1884 (*src)++;
1885 continue;
1887 if (base == 16 && isxdigit(c)) {
1888 value = (value << 4) + ((c & ~32) + 10 - 'A');
1889 (*src)++;
1890 continue;
1892 break;
1894 return value;
1900 * Routines for deletion of data associated with the main data structure.
1905 * Frees the entire host data structure given. Does nothing if the passed
1906 * pointer is NULL.
1909 PRIVATE void
1910 free_host(hmp)
1911 hash_datum *hmp;
1913 struct host *hostptr = (struct host *) hmp;
1914 if (hostptr == NULL)
1915 return;
1916 assert(hostptr->linkcount > 0);
1917 if (--(hostptr->linkcount))
1918 return; /* Still has references */
1919 del_iplist(hostptr->cookie_server);
1920 del_iplist(hostptr->domain_server);
1921 del_iplist(hostptr->gateway);
1922 del_iplist(hostptr->impress_server);
1923 del_iplist(hostptr->log_server);
1924 del_iplist(hostptr->lpr_server);
1925 del_iplist(hostptr->name_server);
1926 del_iplist(hostptr->rlp_server);
1927 del_iplist(hostptr->time_server);
1928 del_iplist(hostptr->nis_server);
1929 del_iplist(hostptr->ntp_server);
1932 * XXX - Add new tags here
1933 * (if the value is an IP list)
1936 del_string(hostptr->hostname);
1937 del_string(hostptr->homedir);
1938 del_string(hostptr->bootfile);
1939 del_string(hostptr->tftpdir);
1940 del_string(hostptr->root_path);
1941 del_string(hostptr->domain_name);
1942 del_string(hostptr->dump_file);
1943 del_string(hostptr->exten_file);
1944 del_string(hostptr->nis_domain);
1946 #ifdef YORK_EX_OPTION
1947 del_string(hostptr->exec_file);
1948 #endif
1951 * XXX - Add new tags here
1952 * (if it is a shared string)
1955 del_bindata(hostptr->generic);
1956 free((char *) hostptr);
1962 * Decrements the linkcount on the given IP address data structure. If the
1963 * linkcount goes to zero, the memory associated with the data is freed.
1966 PRIVATE void
1967 del_iplist(iplist)
1968 struct in_addr_list *iplist;
1970 if (iplist) {
1971 if (!(--(iplist->linkcount))) {
1972 free((char *) iplist);
1980 * Decrements the linkcount on a string data structure. If the count
1981 * goes to zero, the memory associated with the string is freed. Does
1982 * nothing if the passed pointer is NULL.
1985 PRIVATE void
1986 del_string(stringptr)
1987 struct shared_string *stringptr;
1989 if (stringptr) {
1990 if (!(--(stringptr->linkcount))) {
1991 free((char *) stringptr);
1999 * Decrements the linkcount on a shared_bindata data structure. If the
2000 * count goes to zero, the memory associated with the data is freed. Does
2001 * nothing if the passed pointer is NULL.
2004 PRIVATE void
2005 del_bindata(dataptr)
2006 struct shared_bindata *dataptr;
2008 if (dataptr) {
2009 if (!(--(dataptr->linkcount))) {
2010 free((char *) dataptr);
2018 /* smalloc() -- safe malloc()
2020 * Always returns a valid pointer (if it returns at all). The allocated
2021 * memory is initialized to all zeros. If malloc() returns an error, a
2022 * message is printed using the report() function and the program aborts
2023 * with a status of 1.
2026 PRIVATE char *
2027 smalloc(nbytes)
2028 unsigned nbytes;
2030 char *retvalue;
2032 retvalue = malloc(nbytes);
2033 if (!retvalue) {
2034 report(LOG_ERR, "malloc() failure -- exiting");
2035 exit(1);
2037 bzero(retvalue, nbytes);
2038 return retvalue;
2043 * Compare function to determine whether two hardware addresses are
2044 * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
2045 * otherwise.
2047 * This function is used when retrieving elements from the hardware address
2048 * hash table.
2051 boolean
2052 hwlookcmp(d1, d2)
2053 hash_datum *d1, *d2;
2055 struct host *host1 = (struct host *) d1;
2056 struct host *host2 = (struct host *) d2;
2058 if (host1->htype != host2->htype) {
2059 return FALSE;
2061 if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2062 return FALSE;
2064 return TRUE;
2069 * Compare function for doing IP address hash table lookup.
2072 boolean
2073 iplookcmp(d1, d2)
2074 hash_datum *d1, *d2;
2076 struct host *host1 = (struct host *) d1;
2077 struct host *host2 = (struct host *) d2;
2079 return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2083 * Local Variables:
2084 * tab-width: 4
2085 * c-indent-level: 4
2086 * c-argdecl-indent: 4
2087 * c-continued-statement-offset: 4
2088 * c-continued-brace-offset: -4
2089 * c-label-offset: -4
2090 * c-brace-offset: 0
2091 * End: