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