readfile.c revision 84119
13229Spst/************************************************************************ 23229Spst Copyright 1988, 1991 by Carnegie Mellon University 33229Spst 43229Spst All Rights Reserved 53229Spst 63229SpstPermission to use, copy, modify, and distribute this software and its 73229Spstdocumentation for any purpose and without fee is hereby granted, provided 83229Spstthat the above copyright notice appear in all copies and that both that 93229Spstcopyright notice and this permission notice appear in supporting 103229Spstdocumentation, and that the name of Carnegie Mellon University not be used 113229Spstin advertising or publicity pertaining to distribution of the software 123229Spstwithout specific, written prior permission. 133229Spst 143229SpstCARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 153229SpstSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 163229SpstIN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 173229SpstDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 183229SpstPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 193229SpstACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 203229SpstSOFTWARE. 2118471Swosch 2250476Speter $FreeBSD: head/libexec/bootpd/readfile.c 84119 2001-09-29 10:31:28Z iedowse $ 2318471Swosch 243229Spst************************************************************************/ 253229Spst 263229Spst/* 273229Spst * bootpd configuration file reading code. 283229Spst * 293229Spst * The routines in this file deal with reading, interpreting, and storing 303229Spst * the information found in the bootpd configuration file (usually 313229Spst * /etc/bootptab). 323229Spst */ 333229Spst 343229Spst 353229Spst#include <sys/errno.h> 363229Spst#include <sys/types.h> 373229Spst#include <sys/stat.h> 383229Spst#include <sys/file.h> 393229Spst#include <sys/time.h> 403229Spst#include <netinet/in.h> 413229Spst 423229Spst#include <stdlib.h> 433229Spst#include <stdio.h> 443229Spst#include <string.h> 453229Spst#include <ctype.h> 463229Spst#include <assert.h> 473229Spst#include <syslog.h> 483229Spst 493229Spst#ifndef USE_BFUNCS 503229Spst#include <memory.h> 513229Spst/* Yes, memcpy is OK here (no overlapped copies). */ 523229Spst#define bcopy(a,b,c) memcpy(b,a,c) 533229Spst#define bzero(p,l) memset(p,0,l) 543229Spst#define bcmp(a,b,c) memcmp(a,b,c) 553229Spst#endif 563229Spst 573229Spst#include "bootp.h" 583229Spst#include "hash.h" 593229Spst#include "hwaddr.h" 603229Spst#include "lookup.h" 613229Spst#include "readfile.h" 623229Spst#include "report.h" 633229Spst#include "tzone.h" 643229Spst#include "bootpd.h" 653229Spst 663229Spst#define HASHTABLESIZE 257 /* Hash table size (prime) */ 673229Spst 683229Spst/* Non-standard hardware address type (see bootp.h) */ 693229Spst#define HTYPE_DIRECT 0 703229Spst 713229Spst/* Error codes returned by eval_symbol: */ 723229Spst#define SUCCESS 0 733229Spst#define E_END_OF_ENTRY (-1) 743229Spst#define E_SYNTAX_ERROR (-2) 753229Spst#define E_UNKNOWN_SYMBOL (-3) 763229Spst#define E_BAD_IPADDR (-4) 773229Spst#define E_BAD_HWADDR (-5) 783229Spst#define E_BAD_LONGWORD (-6) 793229Spst#define E_BAD_HWATYPE (-7) 803229Spst#define E_BAD_PATHNAME (-8) 813229Spst#define E_BAD_VALUE (-9) 823229Spst 833229Spst/* Tag idendities. */ 843229Spst#define SYM_NULL 0 853229Spst#define SYM_BOOTFILE 1 863229Spst#define SYM_COOKIE_SERVER 2 873229Spst#define SYM_DOMAIN_SERVER 3 883229Spst#define SYM_GATEWAY 4 893229Spst#define SYM_HWADDR 5 903229Spst#define SYM_HOMEDIR 6 913229Spst#define SYM_HTYPE 7 923229Spst#define SYM_IMPRESS_SERVER 8 933229Spst#define SYM_IPADDR 9 943229Spst#define SYM_LOG_SERVER 10 953229Spst#define SYM_LPR_SERVER 11 963229Spst#define SYM_NAME_SERVER 12 973229Spst#define SYM_RLP_SERVER 13 983229Spst#define SYM_SUBNET_MASK 14 993229Spst#define SYM_TIME_OFFSET 15 1003229Spst#define SYM_TIME_SERVER 16 1013229Spst#define SYM_VENDOR_MAGIC 17 1023229Spst#define SYM_SIMILAR_ENTRY 18 1033229Spst#define SYM_NAME_SWITCH 19 1043229Spst#define SYM_BOOTSIZE 20 1053229Spst#define SYM_BOOT_SERVER 22 1063229Spst#define SYM_TFTPDIR 23 1073229Spst#define SYM_DUMP_FILE 24 1083229Spst#define SYM_DOMAIN_NAME 25 1093229Spst#define SYM_SWAP_SERVER 26 1103229Spst#define SYM_ROOT_PATH 27 1113229Spst#define SYM_EXTEN_FILE 28 1123229Spst#define SYM_REPLY_ADDR 29 1133229Spst#define SYM_NIS_DOMAIN 30 /* RFC 1533 */ 1143229Spst#define SYM_NIS_SERVER 31 /* RFC 1533 */ 1153229Spst#define SYM_NTP_SERVER 32 /* RFC 1533 */ 1163229Spst#define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */ 1173229Spst#define SYM_MSG_SIZE 34 1183229Spst#define SYM_MIN_WAIT 35 1193229Spst/* XXX - Add new tags here */ 1203229Spst 1213229Spst#define OP_ADDITION 1 /* Operations on tags */ 1223229Spst#define OP_DELETION 2 1233229Spst#define OP_BOOLEAN 3 1243229Spst 1253229Spst#define MAXINADDRS 16 /* Max size of an IP address list */ 1263229Spst#define MAXBUFLEN 256 /* Max temp buffer space */ 1273229Spst#define MAXENTRYLEN 2048 /* Max size of an entire entry */ 1283229Spst 1293229Spst 1303229Spst 1313229Spst/* 1323229Spst * Structure used to map a configuration-file symbol (such as "ds") to a 1333229Spst * unique integer. 1343229Spst */ 1353229Spst 1363229Spststruct symbolmap { 1373229Spst char *symbol; 1383229Spst int symbolcode; 1393229Spst}; 1403229Spst 1413229Spst 1423229Spststruct htypename { 1433229Spst char *name; 1443229Spst byte htype; 1453229Spst}; 1463229Spst 1473229Spst 1483229SpstPRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */ 1493229SpstPRIVATE int nentries; /* Total number of entries */ 1503229SpstPRIVATE int32 modtime = 0; /* Last modification time of bootptab */ 1513229SpstPRIVATE char *current_hostname; /* Name of the current entry. */ 1523229SpstPRIVATE char current_tagname[8]; 1533229Spst 1543229Spst/* 1553229Spst * List of symbolic names used in the bootptab file. The order and actual 1563229Spst * values of the symbol codes (SYM_. . .) are unimportant, but they must 1573229Spst * all be unique. 1583229Spst */ 1593229Spst 1603229SpstPRIVATE struct symbolmap symbol_list[] = { 1613229Spst {"bf", SYM_BOOTFILE}, 1623229Spst {"bs", SYM_BOOTSIZE}, 1633229Spst {"cs", SYM_COOKIE_SERVER}, 1643229Spst {"df", SYM_DUMP_FILE}, 1653229Spst {"dn", SYM_DOMAIN_NAME}, 1663229Spst {"ds", SYM_DOMAIN_SERVER}, 1673229Spst {"ef", SYM_EXTEN_FILE}, 1683229Spst {"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */ 1693229Spst {"gw", SYM_GATEWAY}, 1703229Spst {"ha", SYM_HWADDR}, 1713229Spst {"hd", SYM_HOMEDIR}, 1723229Spst {"hn", SYM_NAME_SWITCH}, 1733229Spst {"ht", SYM_HTYPE}, 1743229Spst {"im", SYM_IMPRESS_SERVER}, 1753229Spst {"ip", SYM_IPADDR}, 1763229Spst {"lg", SYM_LOG_SERVER}, 1773229Spst {"lp", SYM_LPR_SERVER}, 1783229Spst {"ms", SYM_MSG_SIZE}, 1793229Spst {"mw", SYM_MIN_WAIT}, 1803229Spst {"ns", SYM_NAME_SERVER}, 1813229Spst {"nt", SYM_NTP_SERVER}, 1823229Spst {"ra", SYM_REPLY_ADDR}, 1833229Spst {"rl", SYM_RLP_SERVER}, 1843229Spst {"rp", SYM_ROOT_PATH}, 1853229Spst {"sa", SYM_BOOT_SERVER}, 1863229Spst {"sm", SYM_SUBNET_MASK}, 1873229Spst {"sw", SYM_SWAP_SERVER}, 1883229Spst {"tc", SYM_SIMILAR_ENTRY}, 1893229Spst {"td", SYM_TFTPDIR}, 1903229Spst {"to", SYM_TIME_OFFSET}, 1913229Spst {"ts", SYM_TIME_SERVER}, 1923229Spst {"vm", SYM_VENDOR_MAGIC}, 1933229Spst {"yd", SYM_NIS_DOMAIN}, 1943229Spst {"ys", SYM_NIS_SERVER}, 1953229Spst /* XXX - Add new tags here */ 1963229Spst}; 1973229Spst 1983229Spst 1993229Spst/* 2003229Spst * List of symbolic names for hardware types. Name translates into 2013229Spst * hardware type code listed with it. Names must begin with a letter 2023229Spst * and must be all lowercase. This is searched linearly, so put 2033229Spst * commonly-used entries near the beginning. 2043229Spst */ 2053229Spst 2063229SpstPRIVATE struct htypename htnamemap[] = { 2073229Spst {"ethernet", HTYPE_ETHERNET}, 2083229Spst {"ethernet3", HTYPE_EXP_ETHERNET}, 2093229Spst {"ether", HTYPE_ETHERNET}, 2103229Spst {"ether3", HTYPE_EXP_ETHERNET}, 2113229Spst {"ieee802", HTYPE_IEEE802}, 2123229Spst {"tr", HTYPE_IEEE802}, 2133229Spst {"token-ring", HTYPE_IEEE802}, 2143229Spst {"pronet", HTYPE_PRONET}, 2153229Spst {"chaos", HTYPE_CHAOS}, 2163229Spst {"arcnet", HTYPE_ARCNET}, 2173229Spst {"ax.25", HTYPE_AX25}, 2183229Spst {"direct", HTYPE_DIRECT}, 2193229Spst {"serial", HTYPE_DIRECT}, 2203229Spst {"slip", HTYPE_DIRECT}, 2213229Spst {"ppp", HTYPE_DIRECT} 2223229Spst}; 2233229Spst 2243229Spst 2253229Spst 2263229Spst/* 2273229Spst * Externals and forward declarations. 2283229Spst */ 2293229Spst 2303229Spst#ifdef __STDC__ 2313229Spst#define P(args) args 2323229Spst#else 2333229Spst#define P(args) () 2343229Spst#endif 2353229Spst 2363229Spstextern boolean iplookcmp(); 2373229Spstboolean nmcmp P((hash_datum *, hash_datum *)); 2383229Spst 2393229SpstPRIVATE void 2403229Spst adjust P((char **)); 2413229SpstPRIVATE void 2423229Spst del_string P((struct shared_string *)); 2433229SpstPRIVATE void 2443229Spst del_bindata P((struct shared_bindata *)); 2453229SpstPRIVATE void 2463229Spst del_iplist P((struct in_addr_list *)); 2473229SpstPRIVATE void 2483229Spst eat_whitespace P((char **)); 2493229SpstPRIVATE int 2503229Spst eval_symbol P((char **, struct host *)); 2513229SpstPRIVATE void 2523229Spst fill_defaults P((struct host *, char **)); 2533229SpstPRIVATE void 2543229Spst free_host P((hash_datum *)); 2553229SpstPRIVATE struct in_addr_list * 2563229Spst get_addresses P((char **)); 2573229SpstPRIVATE struct shared_string * 2583229Spst get_shared_string P((char **)); 2593229SpstPRIVATE char * 2603229Spst get_string P((char **, char *, u_int *)); 2613229SpstPRIVATE u_int32 2623229Spst get_u_long P((char **)); 2633229SpstPRIVATE boolean 2643229Spst goodname P((char *)); 2653229SpstPRIVATE boolean 2663229Spst hwinscmp P((hash_datum *, hash_datum *)); 2673229SpstPRIVATE int 2683229Spst interp_byte P((char **, byte *)); 2693229SpstPRIVATE void 2703229Spst makelower P((char *)); 2713229SpstPRIVATE boolean 2723229Spst nullcmp P((hash_datum *, hash_datum *)); 2733229SpstPRIVATE int 2743229Spst process_entry P((struct host *, char *)); 2753229SpstPRIVATE int 2763229Spst process_generic P((char **, struct shared_bindata **, u_int)); 2773229SpstPRIVATE byte * 2783229Spst prs_haddr P((char **, u_int)); 2793229SpstPRIVATE int 2803229Spst prs_inetaddr P((char **, u_int32 *)); 2813229SpstPRIVATE void 2823229Spst read_entry P((FILE *, char *, u_int *)); 2833229SpstPRIVATE char * 2843229Spst smalloc P((u_int)); 2853229Spst 2863229Spst#undef P 2873229Spst 2883229Spst 2893229Spst/* 2903229Spst * Vendor magic cookies for CMU and RFC1048 2913229Spst */ 2923229Spstu_char vm_cmu[4] = VM_CMU; 2933229Spstu_char vm_rfc1048[4] = VM_RFC1048; 2943229Spst 2953229Spst/* 2963229Spst * Main hash tables 2973229Spst */ 2983229Spsthash_tbl *hwhashtable; 2993229Spsthash_tbl *iphashtable; 3003229Spsthash_tbl *nmhashtable; 3013229Spst 3023229Spst/* 3033229Spst * Allocate hash tables for hardware address, ip address, and hostname 3043229Spst * (shared by bootpd and bootpef) 3053229Spst */ 3063229Spstvoid 3073229Spstrdtab_init() 3083229Spst{ 3093229Spst hwhashtable = hash_Init(HASHTABLESIZE); 3103229Spst iphashtable = hash_Init(HASHTABLESIZE); 3113229Spst nmhashtable = hash_Init(HASHTABLESIZE); 3123229Spst if (!(hwhashtable && iphashtable && nmhashtable)) { 3133229Spst report(LOG_ERR, "Unable to allocate hash tables."); 3143229Spst exit(1); 3153229Spst } 3163229Spst} 3173229Spst 3183229Spst 3193229Spst/* 3203229Spst * Read bootptab database file. Avoid rereading the file if the 3213229Spst * write date hasn't changed since the last time we read it. 3223229Spst */ 3233229Spst 3243229Spstvoid 3253229Spstreadtab(force) 3263229Spst int force; 3273229Spst{ 3283229Spst struct host *hp; 3293229Spst FILE *fp; 3303229Spst struct stat st; 3313229Spst unsigned hashcode, buflen; 3323229Spst static char buffer[MAXENTRYLEN]; 3333229Spst 3343229Spst /* 3353229Spst * Check the last modification time. 3363229Spst */ 3373229Spst if (stat(bootptab, &st) < 0) { 3383229Spst report(LOG_ERR, "stat on \"%s\": %s", 3393229Spst bootptab, get_errmsg()); 3403229Spst return; 3413229Spst } 3423229Spst#ifdef DEBUG 3433229Spst if (debug > 3) { 3443229Spst char timestr[28]; 3453229Spst strcpy(timestr, ctime(&(st.st_mtime))); 3463229Spst /* zap the newline */ 3473229Spst timestr[24] = '\0'; 3483229Spst report(LOG_INFO, "bootptab mtime: %s", 3493229Spst timestr); 3503229Spst } 3513229Spst#endif 3523229Spst if ((force == 0) && 3533229Spst (st.st_mtime == modtime) && 3543229Spst st.st_nlink) { 3553229Spst /* 3563229Spst * hasn't been modified or deleted yet. 3573229Spst */ 3583229Spst return; 3593229Spst } 3603229Spst if (debug) 3613229Spst report(LOG_INFO, "reading %s\"%s\"", 3623229Spst (modtime != 0L) ? "new " : "", 3633229Spst bootptab); 3643229Spst 3653229Spst /* 3663229Spst * Open bootptab file. 3673229Spst */ 3683229Spst if ((fp = fopen(bootptab, "r")) == NULL) { 3693229Spst report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg()); 3703229Spst return; 3713229Spst } 3723229Spst /* 3733229Spst * Record file modification time. 3743229Spst */ 3753229Spst if (fstat(fileno(fp), &st) < 0) { 3763229Spst report(LOG_ERR, "fstat: %s", get_errmsg()); 3773229Spst fclose(fp); 3783229Spst return; 3793229Spst } 3803229Spst modtime = st.st_mtime; 3813229Spst 3823229Spst /* 3833229Spst * Entirely erase all hash tables. 3843229Spst */ 3853229Spst hash_Reset(hwhashtable, free_host); 3863229Spst hash_Reset(iphashtable, free_host); 3873229Spst hash_Reset(nmhashtable, free_host); 3883229Spst 3893229Spst nhosts = 0; 3903229Spst nentries = 0; 3913229Spst while (TRUE) { 3923229Spst buflen = sizeof(buffer); 3933229Spst read_entry(fp, buffer, &buflen); 3943229Spst if (buflen == 0) { /* More entries? */ 3953229Spst break; 3963229Spst } 3973229Spst hp = (struct host *) smalloc(sizeof(struct host)); 3983229Spst bzero((char *) hp, sizeof(*hp)); 3993229Spst /* the link count it zero */ 4003229Spst 4013229Spst /* 4023229Spst * Get individual info 4033229Spst */ 4043229Spst if (process_entry(hp, buffer) < 0) { 4053229Spst hp->linkcount = 1; 4063229Spst free_host((hash_datum *) hp); 4073229Spst continue; 4083229Spst } 4093229Spst /* 4103229Spst * If this is not a dummy entry, and the IP or HW 4113229Spst * address is not yet set, try to get them here. 4123229Spst * Dummy entries have . as first char of name. 4133229Spst */ 4143229Spst if (goodname(hp->hostname->string)) { 4153229Spst char *hn = hp->hostname->string; 4163229Spst u_int32 value; 4173229Spst if (hp->flags.iaddr == 0) { 4183229Spst if (lookup_ipa(hn, &value)) { 4193229Spst report(LOG_ERR, "can not get IP addr for %s", hn); 4203229Spst report(LOG_ERR, "(dummy names should start with '.')"); 4213229Spst } else { 4223229Spst hp->iaddr.s_addr = value; 4233229Spst hp->flags.iaddr = TRUE; 4243229Spst } 4253229Spst } 4263229Spst /* Set default subnet mask. */ 4273229Spst if (hp->flags.subnet_mask == 0) { 4283229Spst if (lookup_netmask(hp->iaddr.s_addr, &value)) { 4293229Spst report(LOG_ERR, "can not get netmask for %s", hn); 4303229Spst } else { 4313229Spst hp->subnet_mask.s_addr = value; 4323229Spst hp->flags.subnet_mask = TRUE; 4333229Spst } 4343229Spst } 4353229Spst } 4363229Spst if (hp->flags.iaddr) { 4373229Spst nhosts++; 4383229Spst } 4393229Spst /* Register by HW addr if known. */ 4403229Spst if (hp->flags.htype && hp->flags.haddr) { 4413229Spst /* We will either insert it or free it. */ 4423229Spst hp->linkcount++; 4433229Spst hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype)); 4443229Spst if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) { 4453229Spst report(LOG_NOTICE, "duplicate %s address: %s", 4463229Spst netname(hp->htype), 44713572Spst haddrtoa(hp->haddr, haddrlength(hp->htype))); 4483229Spst free_host((hash_datum *) hp); 4493229Spst continue; 4503229Spst } 4513229Spst } 4523229Spst /* Register by IP addr if known. */ 4533229Spst if (hp->flags.iaddr) { 4543229Spst hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4); 4553229Spst if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) { 4563229Spst report(LOG_ERR, 4573229Spst "hash_Insert() failed on IP address insertion"); 4583229Spst } else { 4593229Spst /* Just inserted the host struct in a new hash list. */ 4603229Spst hp->linkcount++; 4613229Spst } 4623229Spst } 4633229Spst /* Register by Name (always known) */ 4643229Spst hashcode = hash_HashFunction((u_char *) hp->hostname->string, 4653229Spst strlen(hp->hostname->string)); 4663229Spst if (hash_Insert(nmhashtable, hashcode, nullcmp, 4673229Spst hp->hostname->string, hp) < 0) { 4683229Spst report(LOG_ERR, 4693229Spst "hash_Insert() failed on insertion of hostname: \"%s\"", 4703229Spst hp->hostname->string); 4713229Spst } else { 4723229Spst /* Just inserted the host struct in a new hash list. */ 4733229Spst hp->linkcount++; 4743229Spst } 4753229Spst 4763229Spst nentries++; 4773229Spst } 4783229Spst 4793229Spst fclose(fp); 4803229Spst if (debug) 4813229Spst report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"", 4823229Spst nentries, nhosts, bootptab); 4833229Spst return; 4843229Spst} 4853229Spst 4863229Spst 4873229Spst 4883229Spst/* 4893229Spst * Read an entire host entry from the file pointed to by "fp" and insert it 4903229Spst * into the memory pointed to by "buffer". Leading whitespace and comments 4913229Spst * starting with "#" are ignored (removed). Backslashes (\) always quote 49272640Sasmodai * the next character except that newlines preceded by a backslash cause 4933229Spst * line-continuation onto the next line. The entry is terminated by a 49472640Sasmodai * newline character which is not preceded by a backslash. Sequences 4953229Spst * surrounded by double quotes are taken literally (including newlines, but 4963229Spst * not backslashes). 4973229Spst * 4983229Spst * The "bufsiz" parameter points to an unsigned int which specifies the 4993229Spst * maximum permitted buffer size. Upon return, this value will be replaced 5003229Spst * with the actual length of the entry (not including the null terminator). 5013229Spst * 5023229Spst * This code is a little scary. . . . I don't like using gotos in C 5033229Spst * either, but I first wrote this as an FSM diagram and gotos seemed like 5043229Spst * the easiest way to implement it. Maybe later I'll clean it up. 5053229Spst */ 5063229Spst 5073229SpstPRIVATE void 5083229Spstread_entry(fp, buffer, bufsiz) 5093229Spst FILE *fp; 5103229Spst char *buffer; 5113229Spst unsigned *bufsiz; 5123229Spst{ 5133229Spst int c, length; 5143229Spst 5153229Spst length = 0; 5163229Spst 5173229Spst /* 5183229Spst * Eat whitespace, blank lines, and comment lines. 5193229Spst */ 5203229Spst top: 5213229Spst c = fgetc(fp); 5223229Spst if (c < 0) { 5233229Spst goto done; /* Exit if end-of-file */ 5243229Spst } 5253229Spst if (isspace(c)) { 5263229Spst goto top; /* Skip over whitespace */ 5273229Spst } 5283229Spst if (c == '#') { 5293229Spst while (TRUE) { /* Eat comments after # */ 5303229Spst c = fgetc(fp); 5313229Spst if (c < 0) { 5323229Spst goto done; /* Exit if end-of-file */ 5333229Spst } 5343229Spst if (c == '\n') { 5353229Spst goto top; /* Try to read the next line */ 5363229Spst } 5373229Spst } 5383229Spst } 5393229Spst ungetc(c, fp); /* Other character, push it back to reprocess it */ 5403229Spst 5413229Spst 5423229Spst /* 5433229Spst * Now we're actually reading a data entry. Get each character and 5443229Spst * assemble it into the data buffer, processing special characters like 5453229Spst * double quotes (") and backslashes (\). 5463229Spst */ 5473229Spst 5483229Spst mainloop: 5493229Spst c = fgetc(fp); 5503229Spst switch (c) { 5513229Spst case EOF: 5523229Spst case '\n': 5533229Spst goto done; /* Exit on EOF or newline */ 5543229Spst case '\\': 5553229Spst c = fgetc(fp); /* Backslash, read a new character */ 5563229Spst if (c < 0) { 5573229Spst goto done; /* Exit on EOF */ 5583229Spst } 5593229Spst *buffer++ = c; /* Store the literal character */ 5603229Spst length++; 5613229Spst if (length < *bufsiz - 1) { 5623229Spst goto mainloop; 5633229Spst } else { 5643229Spst goto done; 5653229Spst } 5663229Spst case '"': 5673229Spst *buffer++ = '"'; /* Store double-quote */ 5683229Spst length++; 5693229Spst if (length >= *bufsiz - 1) { 5703229Spst goto done; 5713229Spst } 5723229Spst while (TRUE) { /* Special quote processing loop */ 5733229Spst c = fgetc(fp); 5743229Spst switch (c) { 5753229Spst case EOF: 5763229Spst goto done; /* Exit on EOF . . . */ 5773229Spst case '"': 5783229Spst *buffer++ = '"';/* Store matching quote */ 5793229Spst length++; 5803229Spst if (length < *bufsiz - 1) { 5813229Spst goto mainloop; /* And continue main loop */ 5823229Spst } else { 5833229Spst goto done; 5843229Spst } 5853229Spst case '\\': 5863229Spst if ((c = fgetc(fp)) < 0) { /* Backslash */ 5873229Spst goto done; /* EOF. . . .*/ 5883229Spst } /* else fall through */ 5893229Spst default: 5903229Spst *buffer++ = c; /* Other character, store it */ 5913229Spst length++; 5923229Spst if (length >= *bufsiz - 1) { 5933229Spst goto done; 5943229Spst } 5953229Spst } 5963229Spst } 5973229Spst case ':': 5983229Spst *buffer++ = c; /* Store colons */ 5993229Spst length++; 6003229Spst if (length >= *bufsiz - 1) { 6013229Spst goto done; 6023229Spst } 6033229Spst do { /* But remove whitespace after them */ 6043229Spst c = fgetc(fp); 6053229Spst if ((c < 0) || (c == '\n')) { 6063229Spst goto done; 6073229Spst } 6083229Spst } while (isspace(c)); /* Skip whitespace */ 6093229Spst 6103229Spst if (c == '\\') { /* Backslash quotes next character */ 6113229Spst c = fgetc(fp); 6123229Spst if (c < 0) { 6133229Spst goto done; 6143229Spst } 6153229Spst if (c == '\n') { 6163229Spst goto top; /* Backslash-newline continuation */ 6173229Spst } 6183229Spst } 6193229Spst /* fall through if "other" character */ 6203229Spst default: 6213229Spst *buffer++ = c; /* Store other characters */ 6223229Spst length++; 6233229Spst if (length >= *bufsiz - 1) { 6243229Spst goto done; 6253229Spst } 6263229Spst } 6273229Spst goto mainloop; /* Keep going */ 6283229Spst 6293229Spst done: 6303229Spst *buffer = '\0'; /* Terminate string */ 6313229Spst *bufsiz = length; /* Tell the caller its length */ 6323229Spst} 6333229Spst 6343229Spst 6353229Spst 6363229Spst/* 6373229Spst * Parse out all the various tags and parameters in the host entry pointed 6383229Spst * to by "src". Stuff all the data into the appropriate fields of the 6393229Spst * host structure pointed to by "host". If there is any problem with the 6403229Spst * entry, an error message is reported via report(), no further processing 6413229Spst * is done, and -1 is returned. Successful calls return 0. 6423229Spst * 6433229Spst * (Some errors probably shouldn't be so completely fatal. . . .) 6443229Spst */ 6453229Spst 6463229SpstPRIVATE int 6473229Spstprocess_entry(host, src) 6483229Spst struct host *host; 6493229Spst char *src; 6503229Spst{ 6513229Spst int retval; 6523229Spst char *msg; 6533229Spst 6543229Spst if (!host || *src == '\0') { 6553229Spst return -1; 6563229Spst } 6573229Spst host->hostname = get_shared_string(&src); 6583229Spst#if 0 6593229Spst /* Be more liberal for the benefit of dummy tag names. */ 6603229Spst if (!goodname(host->hostname->string)) { 6613229Spst report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string); 6623229Spst del_string(host->hostname); 6633229Spst return -1; 6643229Spst } 6653229Spst#endif 6663229Spst current_hostname = host->hostname->string; 6673229Spst adjust(&src); 6683229Spst while (TRUE) { 6693229Spst retval = eval_symbol(&src, host); 6703229Spst if (retval == SUCCESS) { 6713229Spst adjust(&src); 6723229Spst continue; 6733229Spst } 6743229Spst if (retval == E_END_OF_ENTRY) { 6753229Spst /* The default subnet mask is set in readtab() */ 6763229Spst return 0; 6773229Spst } 6783229Spst /* Some kind of error. */ 6793229Spst switch (retval) { 6803229Spst case E_SYNTAX_ERROR: 6813229Spst msg = "bad syntax"; 6823229Spst break; 6833229Spst case E_UNKNOWN_SYMBOL: 6843229Spst msg = "unknown symbol"; 6853229Spst break; 6863229Spst case E_BAD_IPADDR: 6873229Spst msg = "bad INET address"; 6883229Spst break; 6893229Spst case E_BAD_HWADDR: 6903229Spst msg = "bad hardware address"; 6913229Spst break; 6923229Spst case E_BAD_LONGWORD: 6933229Spst msg = "bad longword value"; 6943229Spst break; 6953229Spst case E_BAD_HWATYPE: 6963229Spst msg = "bad HW address type"; 6973229Spst break; 6983229Spst case E_BAD_PATHNAME: 6993229Spst msg = "bad pathname (need leading '/')"; 70084119Siedowse break; 7013229Spst case E_BAD_VALUE: 7023229Spst msg = "bad value"; 70384119Siedowse break; 7043229Spst default: 70584119Siedowse msg = "unknown error"; 7063229Spst break; 7073229Spst } /* switch */ 7083229Spst report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s", 7093229Spst current_hostname, current_tagname, msg); 7103229Spst return -1; 7113229Spst } 7123229Spst} 7133229Spst 7143229Spst 7153229Spst/* 7163229Spst * Macros for use in the function below: 7173229Spst */ 7183229Spst 7193229Spst/* Parse one INET address stored directly in MEMBER. */ 7203229Spst#define PARSE_IA1(MEMBER) do \ 7213229Spst{ \ 7223229Spst if (optype == OP_BOOLEAN) \ 7233229Spst return E_SYNTAX_ERROR; \ 7243229Spst hp->flags.MEMBER = FALSE; \ 7253229Spst if (optype == OP_ADDITION) { \ 7263229Spst if (prs_inetaddr(symbol, &value) < 0) \ 7273229Spst return E_BAD_IPADDR; \ 7283229Spst hp->MEMBER.s_addr = value; \ 7293229Spst hp->flags.MEMBER = TRUE; \ 7303229Spst } \ 7313229Spst} while (0) 7323229Spst 7333229Spst/* Parse a list of INET addresses pointed to by MEMBER */ 7343229Spst#define PARSE_IAL(MEMBER) do \ 7353229Spst{ \ 7363229Spst if (optype == OP_BOOLEAN) \ 7373229Spst return E_SYNTAX_ERROR; \ 7383229Spst if (hp->flags.MEMBER) { \ 7393229Spst hp->flags.MEMBER = FALSE; \ 7403229Spst assert(hp->MEMBER); \ 7413229Spst del_iplist(hp->MEMBER); \ 7423229Spst hp->MEMBER = NULL; \ 7433229Spst } \ 7443229Spst if (optype == OP_ADDITION) { \ 7453229Spst hp->MEMBER = get_addresses(symbol); \ 7463229Spst if (hp->MEMBER == NULL) \ 7473229Spst return E_SYNTAX_ERROR; \ 7483229Spst hp->flags.MEMBER = TRUE; \ 7493229Spst } \ 7503229Spst} while (0) 7513229Spst 7523229Spst/* Parse a shared string pointed to by MEMBER */ 7533229Spst#define PARSE_STR(MEMBER) do \ 7543229Spst{ \ 7553229Spst if (optype == OP_BOOLEAN) \ 7563229Spst return E_SYNTAX_ERROR; \ 7573229Spst if (hp->flags.MEMBER) { \ 7583229Spst hp->flags.MEMBER = FALSE; \ 7593229Spst assert(hp->MEMBER); \ 7603229Spst del_string(hp->MEMBER); \ 7613229Spst hp->MEMBER = NULL; \ 7623229Spst } \ 7633229Spst if (optype == OP_ADDITION) { \ 7643229Spst hp->MEMBER = get_shared_string(symbol); \ 7653229Spst if (hp->MEMBER == NULL) \ 7663229Spst return E_SYNTAX_ERROR; \ 7673229Spst hp->flags.MEMBER = TRUE; \ 7683229Spst } \ 7693229Spst} while (0) 7703229Spst 77113572Spst/* Parse an unsigned integer value for MEMBER */ 77213572Spst#define PARSE_UINT(MEMBER) do \ 7733229Spst{ \ 7743229Spst if (optype == OP_BOOLEAN) \ 7753229Spst return E_SYNTAX_ERROR; \ 7763229Spst hp->flags.MEMBER = FALSE; \ 7773229Spst if (optype == OP_ADDITION) { \ 7783229Spst value = get_u_long(symbol); \ 7793229Spst hp->MEMBER = value; \ 7803229Spst hp->flags.MEMBER = TRUE; \ 7813229Spst } \ 7823229Spst} while (0) 7833229Spst 7843229Spst/* 7853229Spst * Evaluate the two-character tag symbol pointed to by "symbol" and place 7863229Spst * the data in the structure pointed to by "hp". The pointer pointed to 7873229Spst * by "symbol" is updated to point past the source string (but may not 7883229Spst * point to the next tag entry). 7893229Spst * 7903229Spst * Obviously, this need a few more comments. . . . 7913229Spst */ 7923229SpstPRIVATE int 7933229Spsteval_symbol(symbol, hp) 7943229Spst char **symbol; 7953229Spst struct host *hp; 7963229Spst{ 7973229Spst char tmpstr[MAXSTRINGLEN]; 7983229Spst byte *tmphaddr; 7993229Spst struct symbolmap *symbolptr; 8003229Spst u_int32 value; 8013229Spst int32 timeoff; 8023229Spst int i, numsymbols; 8033229Spst unsigned len; 8043229Spst int optype; /* Indicates boolean, addition, or deletion */ 8053229Spst 8063229Spst eat_whitespace(symbol); 8073229Spst 8083229Spst /* Make sure this is set before returning. */ 8093229Spst current_tagname[0] = (*symbol)[0]; 8103229Spst current_tagname[1] = (*symbol)[1]; 8113229Spst current_tagname[2] = 0; 8123229Spst 8133229Spst if ((*symbol)[0] == '\0') { 8143229Spst return E_END_OF_ENTRY; 8153229Spst } 8163229Spst if ((*symbol)[0] == ':') { 8173229Spst return SUCCESS; 8183229Spst } 8193229Spst if ((*symbol)[0] == 'T') { /* generic symbol */ 8203229Spst (*symbol)++; 8213229Spst value = get_u_long(symbol); 82231971Simp snprintf(current_tagname, sizeof(current_tagname), 82331971Simp "T%d", (int)value); 8243229Spst eat_whitespace(symbol); 8253229Spst if ((*symbol)[0] != '=') { 8263229Spst return E_SYNTAX_ERROR; 8273229Spst } 8283229Spst (*symbol)++; 8293229Spst if (!(hp->generic)) { 8303229Spst hp->generic = (struct shared_bindata *) 8313229Spst smalloc(sizeof(struct shared_bindata)); 8323229Spst } 8333229Spst if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF))) 8343229Spst return E_SYNTAX_ERROR; 8353229Spst hp->flags.generic = TRUE; 8363229Spst return SUCCESS; 8373229Spst } 8383229Spst /* 8393229Spst * Determine the type of operation to be done on this symbol 8403229Spst */ 8413229Spst switch ((*symbol)[2]) { 8423229Spst case '=': 8433229Spst optype = OP_ADDITION; 8443229Spst break; 8453229Spst case '@': 8463229Spst optype = OP_DELETION; 8473229Spst break; 8483229Spst case ':': 8493229Spst case '\0': 8503229Spst optype = OP_BOOLEAN; 8513229Spst break; 8523229Spst default: 8533229Spst return E_SYNTAX_ERROR; 8543229Spst } 8553229Spst 8563229Spst symbolptr = symbol_list; 8573229Spst numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap); 8583229Spst for (i = 0; i < numsymbols; i++) { 8593229Spst if (((symbolptr->symbol)[0] == (*symbol)[0]) && 8603229Spst ((symbolptr->symbol)[1] == (*symbol)[1])) { 8613229Spst break; 8623229Spst } 8633229Spst symbolptr++; 8643229Spst } 8653229Spst if (i >= numsymbols) { 8663229Spst return E_UNKNOWN_SYMBOL; 8673229Spst } 8683229Spst /* 8693229Spst * Skip past the = or @ character (to point to the data) if this 8703229Spst * isn't a boolean operation. For boolean operations, just skip 8713229Spst * over the two-character tag symbol (and nothing else. . . .). 8723229Spst */ 8733229Spst (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3; 8743229Spst 8753229Spst eat_whitespace(symbol); 8763229Spst 8773229Spst /* The cases below are in order by symbolcode value. */ 8783229Spst switch (symbolptr->symbolcode) { 8793229Spst 8803229Spst case SYM_BOOTFILE: 8813229Spst PARSE_STR(bootfile); 8823229Spst break; 8833229Spst 8843229Spst case SYM_COOKIE_SERVER: 8853229Spst PARSE_IAL(cookie_server); 8863229Spst break; 8873229Spst 8883229Spst case SYM_DOMAIN_SERVER: 8893229Spst PARSE_IAL(domain_server); 8903229Spst break; 8913229Spst 8923229Spst case SYM_GATEWAY: 8933229Spst PARSE_IAL(gateway); 8943229Spst break; 8953229Spst 8963229Spst case SYM_HWADDR: 8973229Spst if (optype == OP_BOOLEAN) 8983229Spst return E_SYNTAX_ERROR; 8993229Spst hp->flags.haddr = FALSE; 9003229Spst if (optype == OP_ADDITION) { 9013229Spst /* Default the HW type to Ethernet */ 9023229Spst if (hp->flags.htype == 0) { 9033229Spst hp->flags.htype = TRUE; 9043229Spst hp->htype = HTYPE_ETHERNET; 9053229Spst } 9063229Spst tmphaddr = prs_haddr(symbol, hp->htype); 9073229Spst if (!tmphaddr) 9083229Spst return E_BAD_HWADDR; 9093229Spst bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype)); 9103229Spst hp->flags.haddr = TRUE; 9113229Spst } 9123229Spst break; 9133229Spst 9143229Spst case SYM_HOMEDIR: 9153229Spst PARSE_STR(homedir); 9163229Spst break; 9173229Spst 9183229Spst case SYM_HTYPE: 9193229Spst if (optype == OP_BOOLEAN) 9203229Spst return E_SYNTAX_ERROR; 9213229Spst hp->flags.htype = FALSE; 9223229Spst if (optype == OP_ADDITION) { 9233229Spst value = 0L; /* Assume an illegal value */ 9243229Spst eat_whitespace(symbol); 9253229Spst if (isdigit(**symbol)) { 9263229Spst value = get_u_long(symbol); 9273229Spst } else { 9283229Spst len = sizeof(tmpstr); 9293229Spst (void) get_string(symbol, tmpstr, &len); 9303229Spst makelower(tmpstr); 9313229Spst numsymbols = sizeof(htnamemap) / 9323229Spst sizeof(struct htypename); 9333229Spst for (i = 0; i < numsymbols; i++) { 9343229Spst if (!strcmp(htnamemap[i].name, tmpstr)) { 9353229Spst break; 9363229Spst } 9373229Spst } 9383229Spst if (i < numsymbols) { 9393229Spst value = htnamemap[i].htype; 9403229Spst } 9413229Spst } 9423229Spst if (value >= hwinfocnt) { 9433229Spst return E_BAD_HWATYPE; 9443229Spst } 9453229Spst hp->htype = (byte) (value & 0xFF); 9463229Spst hp->flags.htype = TRUE; 9473229Spst } 9483229Spst break; 9493229Spst 9503229Spst case SYM_IMPRESS_SERVER: 9513229Spst PARSE_IAL(impress_server); 9523229Spst break; 9533229Spst 9543229Spst case SYM_IPADDR: 9553229Spst PARSE_IA1(iaddr); 9563229Spst break; 9573229Spst 9583229Spst case SYM_LOG_SERVER: 9593229Spst PARSE_IAL(log_server); 9603229Spst break; 9613229Spst 9623229Spst case SYM_LPR_SERVER: 9633229Spst PARSE_IAL(lpr_server); 9643229Spst break; 9653229Spst 9663229Spst case SYM_NAME_SERVER: 9673229Spst PARSE_IAL(name_server); 9683229Spst break; 9693229Spst 9703229Spst case SYM_RLP_SERVER: 9713229Spst PARSE_IAL(rlp_server); 9723229Spst break; 9733229Spst 9743229Spst case SYM_SUBNET_MASK: 9753229Spst PARSE_IA1(subnet_mask); 9763229Spst break; 9773229Spst 9783229Spst case SYM_TIME_OFFSET: 9793229Spst if (optype == OP_BOOLEAN) 9803229Spst return E_SYNTAX_ERROR; 9813229Spst hp->flags.time_offset = FALSE; 9823229Spst if (optype == OP_ADDITION) { 9833229Spst len = sizeof(tmpstr); 9843229Spst (void) get_string(symbol, tmpstr, &len); 9853229Spst if (!strncmp(tmpstr, "auto", 4)) { 9863229Spst hp->time_offset = secondswest; 9873229Spst } else { 98813572Spst if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1) 9893229Spst return E_BAD_LONGWORD; 9903229Spst hp->time_offset = timeoff; 9913229Spst } 9923229Spst hp->flags.time_offset = TRUE; 9933229Spst } 9943229Spst break; 9953229Spst 9963229Spst case SYM_TIME_SERVER: 9973229Spst PARSE_IAL(time_server); 9983229Spst break; 9993229Spst 10003229Spst case SYM_VENDOR_MAGIC: 10013229Spst if (optype == OP_BOOLEAN) 10023229Spst return E_SYNTAX_ERROR; 10033229Spst hp->flags.vm_cookie = FALSE; 10043229Spst if (optype == OP_ADDITION) { 10053229Spst if (strncmp(*symbol, "auto", 4)) { 10063229Spst /* The string is not "auto" */ 10073229Spst if (!strncmp(*symbol, "rfc", 3)) { 10083229Spst bcopy(vm_rfc1048, hp->vm_cookie, 4); 10093229Spst } else if (!strncmp(*symbol, "cmu", 3)) { 10103229Spst bcopy(vm_cmu, hp->vm_cookie, 4); 10113229Spst } else { 10123229Spst if (!isdigit(**symbol)) 10133229Spst return E_BAD_IPADDR; 10143229Spst if (prs_inetaddr(symbol, &value) < 0) 10153229Spst return E_BAD_IPADDR; 10163229Spst bcopy(&value, hp->vm_cookie, 4); 10173229Spst } 10183229Spst hp->flags.vm_cookie = TRUE; 10193229Spst } 10203229Spst } 10213229Spst break; 10223229Spst 10233229Spst case SYM_SIMILAR_ENTRY: 10243229Spst switch (optype) { 10253229Spst case OP_ADDITION: 10263229Spst fill_defaults(hp, symbol); 10273229Spst break; 10283229Spst default: 10293229Spst return E_SYNTAX_ERROR; 10303229Spst } 10313229Spst break; 10323229Spst 10333229Spst case SYM_NAME_SWITCH: 10343229Spst switch (optype) { 10353229Spst case OP_ADDITION: 10363229Spst return E_SYNTAX_ERROR; 10373229Spst case OP_DELETION: 10383229Spst hp->flags.send_name = FALSE; 10393229Spst hp->flags.name_switch = FALSE; 10403229Spst break; 10413229Spst case OP_BOOLEAN: 10423229Spst hp->flags.send_name = TRUE; 10433229Spst hp->flags.name_switch = TRUE; 10443229Spst break; 10453229Spst } 10463229Spst break; 10473229Spst 10483229Spst case SYM_BOOTSIZE: 10493229Spst switch (optype) { 10503229Spst case OP_ADDITION: 10513229Spst if (!strncmp(*symbol, "auto", 4)) { 10523229Spst hp->flags.bootsize = TRUE; 10533229Spst hp->flags.bootsize_auto = TRUE; 10543229Spst } else { 10553229Spst hp->bootsize = (unsigned int) get_u_long(symbol); 10563229Spst hp->flags.bootsize = TRUE; 10573229Spst hp->flags.bootsize_auto = FALSE; 10583229Spst } 10593229Spst break; 10603229Spst case OP_DELETION: 10613229Spst hp->flags.bootsize = FALSE; 10623229Spst break; 10633229Spst case OP_BOOLEAN: 10643229Spst hp->flags.bootsize = TRUE; 10653229Spst hp->flags.bootsize_auto = TRUE; 10663229Spst break; 10673229Spst } 10683229Spst break; 10693229Spst 10703229Spst case SYM_BOOT_SERVER: 10713229Spst PARSE_IA1(bootserver); 10723229Spst break; 10733229Spst 10743229Spst case SYM_TFTPDIR: 10753229Spst PARSE_STR(tftpdir); 10763229Spst if ((hp->tftpdir != NULL) && 10773229Spst (hp->tftpdir->string[0] != '/')) 10783229Spst return E_BAD_PATHNAME; 10793229Spst break; 10803229Spst 10813229Spst case SYM_DUMP_FILE: 10823229Spst PARSE_STR(dump_file); 10833229Spst break; 10843229Spst 10853229Spst case SYM_DOMAIN_NAME: 10863229Spst PARSE_STR(domain_name); 10873229Spst break; 10883229Spst 10893229Spst case SYM_SWAP_SERVER: 10903229Spst PARSE_IA1(swap_server); 10913229Spst break; 10923229Spst 10933229Spst case SYM_ROOT_PATH: 10943229Spst PARSE_STR(root_path); 10953229Spst break; 10963229Spst 10973229Spst case SYM_EXTEN_FILE: 10983229Spst PARSE_STR(exten_file); 10993229Spst break; 11003229Spst 11013229Spst case SYM_REPLY_ADDR: 11023229Spst PARSE_IA1(reply_addr); 11033229Spst break; 11043229Spst 11053229Spst case SYM_NIS_DOMAIN: 11063229Spst PARSE_STR(nis_domain); 11073229Spst break; 11083229Spst 11093229Spst case SYM_NIS_SERVER: 11103229Spst PARSE_IAL(nis_server); 11113229Spst break; 11123229Spst 11133229Spst case SYM_NTP_SERVER: 11143229Spst PARSE_IAL(ntp_server); 11153229Spst break; 11163229Spst 11173229Spst#ifdef YORK_EX_OPTION 11183229Spst case SYM_EXEC_FILE: 11193229Spst PARSE_STR(exec_file); 11203229Spst break; 11213229Spst#endif 11223229Spst 11233229Spst case SYM_MSG_SIZE: 112413572Spst PARSE_UINT(msg_size); 11253229Spst if (hp->msg_size < BP_MINPKTSZ || 11263229Spst hp->msg_size > MAX_MSG_SIZE) 11273229Spst return E_BAD_VALUE; 11283229Spst break; 11293229Spst 11303229Spst case SYM_MIN_WAIT: 113113572Spst PARSE_UINT(min_wait); 11323229Spst break; 11333229Spst 11343229Spst /* XXX - Add new tags here */ 11353229Spst 11363229Spst default: 11373229Spst return E_UNKNOWN_SYMBOL; 11383229Spst 11393229Spst } /* switch symbolcode */ 11403229Spst 11413229Spst return SUCCESS; 11423229Spst} 11433229Spst#undef PARSE_IA1 11443229Spst#undef PARSE_IAL 11453229Spst#undef PARSE_STR 11463229Spst 11473229Spst 11483229Spst 11493229Spst 11503229Spst/* 11513229Spst * Read a string from the buffer indirectly pointed to through "src" and 11523229Spst * move it into the buffer pointed to by "dest". A pointer to the maximum 11533229Spst * allowable length of the string (including null-terminator) is passed as 11543229Spst * "length". The actual length of the string which was read is returned in 11553229Spst * the unsigned integer pointed to by "length". This value is the same as 11563229Spst * that which would be returned by applying the strlen() function on the 11573229Spst * destination string (i.e the terminating null is not counted as a 11583229Spst * character). Trailing whitespace is removed from the string. For 11593229Spst * convenience, the function returns the new value of "dest". 11603229Spst * 11613229Spst * The string is read until the maximum number of characters, an unquoted 11623229Spst * colon (:), or a null character is read. The return string in "dest" is 11633229Spst * null-terminated. 11643229Spst */ 11653229Spst 11663229SpstPRIVATE char * 11673229Spstget_string(src, dest, length) 11683229Spst char **src, *dest; 11693229Spst unsigned *length; 11703229Spst{ 11713229Spst int n, len, quoteflag; 11723229Spst 11733229Spst quoteflag = FALSE; 11743229Spst n = 0; 11753229Spst len = *length - 1; 11763229Spst while ((n < len) && (**src)) { 11773229Spst if (!quoteflag && (**src == ':')) { 11783229Spst break; 11793229Spst } 11803229Spst if (**src == '"') { 11813229Spst (*src)++; 11823229Spst quoteflag = !quoteflag; 11833229Spst continue; 11843229Spst } 11853229Spst if (**src == '\\') { 11863229Spst (*src)++; 11873229Spst if (!**src) { 11883229Spst break; 11893229Spst } 11903229Spst } 11913229Spst *dest++ = *(*src)++; 11923229Spst n++; 11933229Spst } 11943229Spst 11953229Spst /* 11963229Spst * Remove that troublesome trailing whitespace. . . 11973229Spst */ 11983229Spst while ((n > 0) && isspace(dest[-1])) { 11993229Spst dest--; 12003229Spst n--; 12013229Spst } 12023229Spst 12033229Spst *dest = '\0'; 12043229Spst *length = n; 12053229Spst return dest; 12063229Spst} 12073229Spst 12083229Spst 12093229Spst 12103229Spst/* 12113229Spst * Read the string indirectly pointed to by "src", update the caller's 12123229Spst * pointer, and return a pointer to a malloc'ed shared_string structure 12133229Spst * containing the string. 12143229Spst * 12153229Spst * The string is read using the same rules as get_string() above. 12163229Spst */ 12173229Spst 12183229SpstPRIVATE struct shared_string * 12193229Spstget_shared_string(src) 12203229Spst char **src; 12213229Spst{ 12223229Spst char retstring[MAXSTRINGLEN]; 12233229Spst struct shared_string *s; 12243229Spst unsigned length; 12253229Spst 12263229Spst length = sizeof(retstring); 12273229Spst (void) get_string(src, retstring, &length); 12283229Spst 12293229Spst s = (struct shared_string *) smalloc(sizeof(struct shared_string) 12303229Spst + length); 12313229Spst s->linkcount = 1; 12323229Spst strcpy(s->string, retstring); 12333229Spst 12343229Spst return s; 12353229Spst} 12363229Spst 12373229Spst 12383229Spst 12393229Spst/* 12403229Spst * Load RFC1048 generic information directly into a memory buffer. 12413229Spst * 12423229Spst * "src" indirectly points to the ASCII representation of the generic data. 12433229Spst * "dest" points to a string structure which is updated to point to a new 12443229Spst * string with the new data appended to the old string. The old string is 12453229Spst * freed. 12463229Spst * 12473229Spst * The given tag value is inserted with the new data. 12483229Spst * 12493229Spst * The data may be represented as either a stream of hexadecimal numbers 12503229Spst * representing bytes (any or all bytes may optionally start with '0x' and 12513229Spst * be separated with periods ".") or as a quoted string of ASCII 12523229Spst * characters (the quotes are required). 12533229Spst */ 12543229Spst 12553229SpstPRIVATE int 12563229Spstprocess_generic(src, dest, tagvalue) 12573229Spst char **src; 12583229Spst struct shared_bindata **dest; 12593229Spst u_int tagvalue; 12603229Spst{ 12613229Spst byte tmpbuf[MAXBUFLEN]; 12623229Spst byte *str; 12633229Spst struct shared_bindata *bdata; 12643229Spst u_int newlength, oldlength; 12653229Spst 12663229Spst str = tmpbuf; 12673229Spst *str++ = (tagvalue & 0xFF); /* Store tag value */ 12683229Spst str++; /* Skip over length field */ 12693229Spst if ((*src)[0] == '"') { /* ASCII data */ 12703229Spst newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */ 12713229Spst (void) get_string(src, (char *) str, &newlength); 12723229Spst newlength++; /* null terminator */ 12733229Spst } else { /* Numeric data */ 12743229Spst newlength = 0; 12753229Spst while (newlength < sizeof(tmpbuf) - 2) { 12763229Spst if (interp_byte(src, str++) < 0) 12773229Spst break; 12783229Spst newlength++; 12793229Spst if (**src == '.') { 12803229Spst (*src)++; 12813229Spst } 12823229Spst } 12833229Spst } 12843229Spst if ((*src)[0] != ':') 12853229Spst return -1; 12863229Spst 12873229Spst tmpbuf[1] = (newlength & 0xFF); 12883229Spst oldlength = ((*dest)->length); 12893229Spst bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata) 12903229Spst + oldlength + newlength + 1); 12913229Spst if (oldlength > 0) { 12923229Spst bcopy((*dest)->data, bdata->data, oldlength); 12933229Spst } 12943229Spst bcopy(tmpbuf, bdata->data + oldlength, newlength + 2); 12953229Spst bdata->length = oldlength + newlength + 2; 12963229Spst bdata->linkcount = 1; 12973229Spst if (*dest) { 12983229Spst del_bindata(*dest); 12993229Spst } 13003229Spst *dest = bdata; 13013229Spst return 0; 13023229Spst} 13033229Spst 13043229Spst 13053229Spst 13063229Spst/* 13073229Spst * Verify that the given string makes sense as a hostname (according to 13083229Spst * Appendix 1, page 29 of RFC882). 13093229Spst * 13103229Spst * Return TRUE for good names, FALSE otherwise. 13113229Spst */ 13123229Spst 13133229SpstPRIVATE boolean 13143229Spstgoodname(hostname) 13153229Spst register char *hostname; 13163229Spst{ 13173229Spst do { 13183229Spst if (!isalpha(*hostname++)) { /* First character must be a letter */ 13193229Spst return FALSE; 13203229Spst } 13213229Spst while (isalnum(*hostname) || 13223229Spst (*hostname == '-') || 13233229Spst (*hostname == '_') ) 13243229Spst { 13253229Spst hostname++; /* Alphanumeric or a hyphen */ 13263229Spst } 13273229Spst if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */ 13283229Spst return FALSE; 13293229Spst } 13303229Spst if (*hostname == '\0') {/* Done? */ 13313229Spst return TRUE; 13323229Spst } 13333229Spst } while (*hostname++ == '.'); /* Dot, loop for next label */ 13343229Spst 13353229Spst return FALSE; /* If it's not a dot, lose */ 13363229Spst} 13373229Spst 13383229Spst 13393229Spst 13403229Spst/* 13413229Spst * Null compare function -- always returns FALSE so an element is always 13423229Spst * inserted into a hash table (i.e. there is never a collision with an 13433229Spst * existing element). 13443229Spst */ 13453229Spst 13463229SpstPRIVATE boolean 13473229Spstnullcmp(d1, d2) 13483229Spst hash_datum *d1, *d2; 13493229Spst{ 13503229Spst return FALSE; 13513229Spst} 13523229Spst 13533229Spst 13543229Spst/* 13553229Spst * Function for comparing a string with the hostname field of a host 13563229Spst * structure. 13573229Spst */ 13583229Spst 13593229Spstboolean 13603229Spstnmcmp(d1, d2) 13613229Spst hash_datum *d1, *d2; 13623229Spst{ 13633229Spst char *name = (char *) d1; /* XXX - OK? */ 13643229Spst struct host *hp = (struct host *) d2; 13653229Spst 13663229Spst return !strcmp(name, hp->hostname->string); 13673229Spst} 13683229Spst 13693229Spst 13703229Spst/* 13713229Spst * Compare function to determine whether two hardware addresses are 13723229Spst * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 13733229Spst * otherwise. 13743229Spst * 13753229Spst * If the hardware addresses of "host1" and "host2" are identical, but 13763229Spst * they are on different IP subnets, this function returns FALSE. 13773229Spst * 13783229Spst * This function is used when inserting elements into the hardware address 13793229Spst * hash table. 13803229Spst */ 13813229Spst 13823229SpstPRIVATE boolean 13833229Spsthwinscmp(d1, d2) 13843229Spst hash_datum *d1, *d2; 13853229Spst{ 13863229Spst struct host *host1 = (struct host *) d1; 13873229Spst struct host *host2 = (struct host *) d2; 13883229Spst 13893229Spst if (host1->htype != host2->htype) { 13903229Spst return FALSE; 13913229Spst } 13923229Spst if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 13933229Spst return FALSE; 13943229Spst } 13953229Spst /* XXX - Is the subnet_mask field set yet? */ 13963229Spst if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) { 13973229Spst if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) != 13983229Spst ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) 13993229Spst { 14003229Spst return FALSE; 14013229Spst } 14023229Spst } 14033229Spst return TRUE; 14043229Spst} 14053229Spst 14063229Spst 14073229Spst/* 14083229Spst * Macros for use in the function below: 14093229Spst */ 14103229Spst 14113229Spst#define DUP_COPY(MEMBER) do \ 14123229Spst{ \ 14133229Spst if (!hp->flags.MEMBER) { \ 14143229Spst if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 14153229Spst hp->MEMBER = hp2->MEMBER; \ 14163229Spst } \ 14173229Spst } \ 14183229Spst} while (0) 14193229Spst 14203229Spst#define DUP_LINK(MEMBER) do \ 14213229Spst{ \ 14223229Spst if (!hp->flags.MEMBER) { \ 14233229Spst if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 14243229Spst assert(hp2->MEMBER); \ 14253229Spst hp->MEMBER = hp2->MEMBER; \ 14263229Spst (hp->MEMBER->linkcount)++; \ 14273229Spst } \ 14283229Spst } \ 14293229Spst} while (0) 14303229Spst 14313229Spst/* 14323229Spst * Process the "similar entry" symbol. 14333229Spst * 14343229Spst * The host specified as the value of the "tc" symbol is used as a template 14353229Spst * for the current host entry. Symbol values not explicitly set in the 14363229Spst * current host entry are inferred from the template entry. 14373229Spst */ 14383229SpstPRIVATE void 14393229Spstfill_defaults(hp, src) 14403229Spst struct host *hp; 14413229Spst char **src; 14423229Spst{ 14433229Spst unsigned int tlen, hashcode; 14443229Spst struct host *hp2; 14453229Spst char tstring[MAXSTRINGLEN]; 14463229Spst 14473229Spst tlen = sizeof(tstring); 14483229Spst (void) get_string(src, tstring, &tlen); 14493229Spst hashcode = hash_HashFunction((u_char *) tstring, tlen); 14503229Spst hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring); 14513229Spst 14523229Spst if (hp2 == NULL) { 14533229Spst report(LOG_ERR, "can't find tc=\"%s\"", tstring); 14543229Spst return; 14553229Spst } 14563229Spst DUP_LINK(bootfile); 14573229Spst DUP_LINK(cookie_server); 14583229Spst DUP_LINK(domain_server); 14593229Spst DUP_LINK(gateway); 14603229Spst /* haddr not copied */ 14613229Spst DUP_LINK(homedir); 14623229Spst DUP_COPY(htype); 14633229Spst 14643229Spst DUP_LINK(impress_server); 14653229Spst /* iaddr not copied */ 14663229Spst DUP_LINK(log_server); 14673229Spst DUP_LINK(lpr_server); 14683229Spst DUP_LINK(name_server); 14693229Spst DUP_LINK(rlp_server); 14703229Spst 14713229Spst DUP_COPY(subnet_mask); 14723229Spst DUP_COPY(time_offset); 14733229Spst DUP_LINK(time_server); 14743229Spst 14753229Spst if (!hp->flags.vm_cookie) { 14763229Spst if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) { 14773229Spst bcopy(hp2->vm_cookie, hp->vm_cookie, 4); 14783229Spst } 14793229Spst } 14803229Spst if (!hp->flags.name_switch) { 14813229Spst if ((hp->flags.name_switch = hp2->flags.name_switch)) { 14823229Spst hp->flags.send_name = hp2->flags.send_name; 14833229Spst } 14843229Spst } 14853229Spst if (!hp->flags.bootsize) { 14863229Spst if ((hp->flags.bootsize = hp2->flags.bootsize)) { 14873229Spst hp->flags.bootsize_auto = hp2->flags.bootsize_auto; 14883229Spst hp->bootsize = hp2->bootsize; 14893229Spst } 14903229Spst } 14913229Spst DUP_COPY(bootserver); 14923229Spst 14933229Spst DUP_LINK(tftpdir); 14943229Spst DUP_LINK(dump_file); 14953229Spst DUP_LINK(domain_name); 14963229Spst 14973229Spst DUP_COPY(swap_server); 14983229Spst DUP_LINK(root_path); 14993229Spst DUP_LINK(exten_file); 15003229Spst 15013229Spst DUP_COPY(reply_addr); 15023229Spst 15033229Spst DUP_LINK(nis_domain); 15043229Spst DUP_LINK(nis_server); 15053229Spst DUP_LINK(ntp_server); 15063229Spst 15073229Spst#ifdef YORK_EX_OPTION 15083229Spst DUP_LINK(exec_file); 15093229Spst#endif 15103229Spst 15113229Spst DUP_COPY(msg_size); 15123229Spst DUP_COPY(min_wait); 15133229Spst 15143229Spst /* XXX - Add new tags here */ 15153229Spst 15163229Spst DUP_LINK(generic); 15173229Spst 15183229Spst} 15193229Spst#undef DUP_COPY 15203229Spst#undef DUP_LINK 15213229Spst 15223229Spst 15233229Spst 15243229Spst/* 15253229Spst * This function adjusts the caller's pointer to point just past the 15263229Spst * first-encountered colon. If it runs into a null character, it leaves 15273229Spst * the pointer pointing to it. 15283229Spst */ 15293229Spst 15303229SpstPRIVATE void 15313229Spstadjust(s) 15323229Spst char **s; 15333229Spst{ 15343229Spst register char *t; 15353229Spst 15363229Spst t = *s; 15373229Spst while (*t && (*t != ':')) { 15383229Spst t++; 15393229Spst } 15403229Spst if (*t) { 15413229Spst t++; 15423229Spst } 15433229Spst *s = t; 15443229Spst} 15453229Spst 15463229Spst 15473229Spst 15483229Spst 15493229Spst/* 15503229Spst * This function adjusts the caller's pointer to point to the first 15513229Spst * non-whitespace character. If it runs into a null character, it leaves 15523229Spst * the pointer pointing to it. 15533229Spst */ 15543229Spst 15553229SpstPRIVATE void 15563229Spsteat_whitespace(s) 15573229Spst char **s; 15583229Spst{ 15593229Spst register char *t; 15603229Spst 15613229Spst t = *s; 15623229Spst while (*t && isspace(*t)) { 15633229Spst t++; 15643229Spst } 15653229Spst *s = t; 15663229Spst} 15673229Spst 15683229Spst 15693229Spst 15703229Spst/* 15713229Spst * This function converts the given string to all lowercase. 15723229Spst */ 15733229Spst 15743229SpstPRIVATE void 15753229Spstmakelower(s) 15763229Spst char *s; 15773229Spst{ 15783229Spst while (*s) { 15793229Spst if (isupper(*s)) { 15803229Spst *s = tolower(*s); 15813229Spst } 15823229Spst s++; 15833229Spst } 15843229Spst} 15853229Spst 15863229Spst 15873229Spst 15883229Spst/* 15893229Spst * 15903229Spst * N O T E : 15913229Spst * 15923229Spst * In many of the functions which follow, a parameter such as "src" or 15933229Spst * "symbol" is passed as a pointer to a pointer to something. This is 15943229Spst * done for the purpose of letting the called function update the 15953229Spst * caller's copy of the parameter (i.e. to effect call-by-reference 15963229Spst * parameter passing). The value of the actual parameter is only used 15973229Spst * to locate the real parameter of interest and then update this indirect 15983229Spst * parameter. 15993229Spst * 16003229Spst * I'm sure somebody out there won't like this. . . . 16013229Spst * (Yea, because it usually makes code slower... -gwr) 16023229Spst * 16033229Spst */ 16043229Spst 16053229Spst 16063229Spst 16073229Spst/* 16083229Spst * "src" points to a character pointer which points to an ASCII string of 16093229Spst * whitespace-separated IP addresses. A pointer to an in_addr_list 16103229Spst * structure containing the list of addresses is returned. NULL is 16113229Spst * returned if no addresses were found at all. The pointer pointed to by 16123229Spst * "src" is updated to point to the first non-address (illegal) character. 16133229Spst */ 16143229Spst 16153229SpstPRIVATE struct in_addr_list * 16163229Spstget_addresses(src) 16173229Spst char **src; 16183229Spst{ 16193229Spst struct in_addr tmpaddrlist[MAXINADDRS]; 16203229Spst struct in_addr *address1, *address2; 16213229Spst struct in_addr_list *result; 16223229Spst unsigned addrcount, totalsize; 16233229Spst 16243229Spst address1 = tmpaddrlist; 16253229Spst for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) { 16263229Spst while (isspace(**src) || (**src == ',')) { 16273229Spst (*src)++; 16283229Spst } 16293229Spst if (!**src) { /* Quit if nothing more */ 16303229Spst break; 16313229Spst } 16323229Spst if (prs_inetaddr(src, &(address1->s_addr)) < 0) { 16333229Spst break; 16343229Spst } 16353229Spst address1++; /* Point to next address slot */ 16363229Spst } 16373229Spst if (addrcount < 1) { 16383229Spst result = NULL; 16393229Spst } else { 16403229Spst totalsize = sizeof(struct in_addr_list) 16413229Spst + (addrcount - 1) * sizeof(struct in_addr); 16423229Spst result = (struct in_addr_list *) smalloc(totalsize); 16433229Spst result->linkcount = 1; 16443229Spst result->addrcount = addrcount; 16453229Spst address1 = tmpaddrlist; 16463229Spst address2 = result->addr; 16473229Spst for (; addrcount > 0; addrcount--) { 16483229Spst address2->s_addr = address1->s_addr; 16493229Spst address1++; 16503229Spst address2++; 16513229Spst } 16523229Spst } 16533229Spst return result; 16543229Spst} 16553229Spst 16563229Spst 16573229Spst 16583229Spst/* 16593229Spst * prs_inetaddr(src, result) 16603229Spst * 16613229Spst * "src" is a value-result parameter; the pointer it points to is updated 16623229Spst * to point to the next data position. "result" points to an unsigned long 16633229Spst * in which an address is returned. 16643229Spst * 16653229Spst * This function parses the IP address string in ASCII "dot notation" pointed 16663229Spst * to by (*src) and places the result (in network byte order) in the unsigned 16673229Spst * long pointed to by "result". For malformed addresses, -1 is returned, 16683229Spst * (*src) points to the first illegal character, and the unsigned long pointed 16693229Spst * to by "result" is unchanged. Successful calls return 0. 16703229Spst */ 16713229Spst 16723229SpstPRIVATE int 16733229Spstprs_inetaddr(src, result) 16743229Spst char **src; 16753229Spst u_int32 *result; 16763229Spst{ 16773229Spst char tmpstr[MAXSTRINGLEN]; 16783229Spst register u_int32 value; 16793229Spst u_int32 parts[4], *pp; 16803229Spst int n; 16813229Spst char *s, *t; 16823229Spst 16833229Spst /* Leading alpha char causes IP addr lookup. */ 16843229Spst if (isalpha(**src)) { 16853229Spst /* Lookup IP address. */ 16863229Spst s = *src; 16873229Spst t = tmpstr; 16883229Spst while ((isalnum(*s) || (*s == '.') || 16893229Spst (*s == '-') || (*s == '_') ) && 16903229Spst (t < &tmpstr[MAXSTRINGLEN - 1]) ) 16913229Spst *t++ = *s++; 16923229Spst *t = '\0'; 16933229Spst *src = s; 16943229Spst 16953229Spst n = lookup_ipa(tmpstr, result); 16963229Spst if (n < 0) 16973229Spst report(LOG_ERR, "can not get IP addr for %s", tmpstr); 16983229Spst return n; 16993229Spst } 17003229Spst 17013229Spst /* 17023229Spst * Parse an address in Internet format: 17033229Spst * a.b.c.d 17043229Spst * a.b.c (with c treated as 16-bits) 17053229Spst * a.b (with b treated as 24 bits) 17063229Spst */ 17073229Spst pp = parts; 17083229Spst loop: 17093229Spst /* If it's not a digit, return error. */ 17103229Spst if (!isdigit(**src)) 17113229Spst return -1; 17123229Spst *pp++ = get_u_long(src); 17133229Spst if (**src == '.') { 17143229Spst if (pp < (parts + 4)) { 17153229Spst (*src)++; 17163229Spst goto loop; 17173229Spst } 17183229Spst return (-1); 17193229Spst } 17203229Spst#if 0 17213229Spst /* This is handled by the caller. */ 17223229Spst if (**src && !(isspace(**src) || (**src == ':'))) { 17233229Spst return (-1); 17243229Spst } 17253229Spst#endif 17263229Spst 17273229Spst /* 17283229Spst * Construct the address according to 17293229Spst * the number of parts specified. 17303229Spst */ 17313229Spst n = pp - parts; 17323229Spst switch (n) { 17333229Spst case 1: /* a -- 32 bits */ 17343229Spst value = parts[0]; 17353229Spst break; 17363229Spst case 2: /* a.b -- 8.24 bits */ 17373229Spst value = (parts[0] << 24) | (parts[1] & 0xFFFFFF); 17383229Spst break; 17393229Spst case 3: /* a.b.c -- 8.8.16 bits */ 17403229Spst value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 17413229Spst (parts[2] & 0xFFFF); 17423229Spst break; 17433229Spst case 4: /* a.b.c.d -- 8.8.8.8 bits */ 17443229Spst value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 17453229Spst ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF); 17463229Spst break; 17473229Spst default: 17483229Spst return (-1); 17493229Spst } 17503229Spst *result = htonl(value); 17513229Spst return (0); 17523229Spst} 17533229Spst 17543229Spst 17553229Spst 17563229Spst/* 17573229Spst * "src" points to a pointer which in turn points to a hexadecimal ASCII 17583229Spst * string. This string is interpreted as a hardware address and returned 17593229Spst * as a pointer to the actual hardware address, represented as an array of 17603229Spst * bytes. 17613229Spst * 17623229Spst * The ASCII string must have the proper number of digits for the specified 17633229Spst * hardware type (e.g. twelve digits for a 48-bit Ethernet address). 17643229Spst * Two-digit sequences (bytes) may be separated with periods (.) and/or 17653229Spst * prefixed with '0x' for readability, but this is not required. 17663229Spst * 17673229Spst * For bad addresses, the pointer which "src" points to is updated to point 17683229Spst * to the start of the first two-digit sequence which was bad, and the 17693229Spst * function returns a NULL pointer. 17703229Spst */ 17713229Spst 17723229SpstPRIVATE byte * 17733229Spstprs_haddr(src, htype) 17743229Spst char **src; 17753229Spst u_int htype; 17763229Spst{ 17773229Spst static byte haddr[MAXHADDRLEN]; 17783229Spst byte *hap; 17793229Spst char tmpstr[MAXSTRINGLEN]; 17803229Spst u_int tmplen; 17813229Spst unsigned hal; 17823229Spst char *p; 17833229Spst 17843229Spst hal = haddrlength(htype); /* Get length of this address type */ 17853229Spst if (hal <= 0) { 17863229Spst report(LOG_ERR, "Invalid addr type for HW addr parse"); 17873229Spst return NULL; 17883229Spst } 17893229Spst tmplen = sizeof(tmpstr); 17903229Spst get_string(src, tmpstr, &tmplen); 17913229Spst p = tmpstr; 17923229Spst 17933229Spst /* If it's a valid host name, try to lookup the HW address. */ 17943229Spst if (goodname(p)) { 17953229Spst /* Lookup Hardware Address for hostname. */ 17963229Spst if ((hap = lookup_hwa(p, htype)) != NULL) 17973229Spst return hap; /* success */ 17983229Spst report(LOG_ERR, "Add 0x prefix if hex value starts with A-F"); 17993229Spst /* OK, assume it must be numeric. */ 18003229Spst } 18013229Spst 18023229Spst hap = haddr; 18033229Spst while (hap < haddr + hal) { 180413572Spst if ((*p == '.') || (*p == ':')) 18053229Spst p++; 18063229Spst if (interp_byte(&p, hap++) < 0) { 18073229Spst return NULL; 18083229Spst } 18093229Spst } 18103229Spst return haddr; 18113229Spst} 18123229Spst 18133229Spst 18143229Spst 18153229Spst/* 18163229Spst * "src" is a pointer to a character pointer which in turn points to a 18173229Spst * hexadecimal ASCII representation of a byte. This byte is read, the 18183229Spst * character pointer is updated, and the result is deposited into the 18193229Spst * byte pointed to by "retbyte". 18203229Spst * 18213229Spst * The usual '0x' notation is allowed but not required. The number must be 18223229Spst * a two digit hexadecimal number. If the number is invalid, "src" and 18233229Spst * "retbyte" are left untouched and -1 is returned as the function value. 18243229Spst * Successful calls return 0. 18253229Spst */ 18263229Spst 18273229SpstPRIVATE int 18283229Spstinterp_byte(src, retbyte) 18293229Spst char **src; 18303229Spst byte *retbyte; 18313229Spst{ 18323229Spst int v; 18333229Spst 18343229Spst if ((*src)[0] == '0' && 18353229Spst ((*src)[1] == 'x' || 18363229Spst (*src)[1] == 'X')) { 18373229Spst (*src) += 2; /* allow 0x for hex, but don't require it */ 18383229Spst } 18393229Spst if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) { 18403229Spst return -1; 18413229Spst } 18423229Spst if (sscanf(*src, "%2x", &v) != 1) { 18433229Spst return -1; 18443229Spst } 18453229Spst (*src) += 2; 18463229Spst *retbyte = (byte) (v & 0xFF); 18473229Spst return 0; 18483229Spst} 18493229Spst 18503229Spst 18513229Spst 18523229Spst/* 18533229Spst * The parameter "src" points to a character pointer which points to an 18543229Spst * ASCII string representation of an unsigned number. The number is 18553229Spst * returned as an unsigned long and the character pointer is updated to 18563229Spst * point to the first illegal character. 18573229Spst */ 18583229Spst 18593229SpstPRIVATE u_int32 18603229Spstget_u_long(src) 18613229Spst char **src; 18623229Spst{ 18633229Spst register u_int32 value, base; 18643229Spst char c; 18653229Spst 18663229Spst /* 18673229Spst * Collect number up to first illegal character. Values are specified 18683229Spst * as for C: 0x=hex, 0=octal, other=decimal. 18693229Spst */ 18703229Spst value = 0; 18713229Spst base = 10; 18723229Spst if (**src == '0') { 18733229Spst base = 8; 18743229Spst (*src)++; 18753229Spst } 18763229Spst if (**src == 'x' || **src == 'X') { 18773229Spst base = 16; 18783229Spst (*src)++; 18793229Spst } 18803229Spst while ((c = **src)) { 18813229Spst if (isdigit(c)) { 18823229Spst value = (value * base) + (c - '0'); 18833229Spst (*src)++; 18843229Spst continue; 18853229Spst } 18863229Spst if (base == 16 && isxdigit(c)) { 18873229Spst value = (value << 4) + ((c & ~32) + 10 - 'A'); 18883229Spst (*src)++; 18893229Spst continue; 18903229Spst } 18913229Spst break; 18923229Spst } 18933229Spst return value; 18943229Spst} 18953229Spst 18963229Spst 18973229Spst 18983229Spst/* 18993229Spst * Routines for deletion of data associated with the main data structure. 19003229Spst */ 19013229Spst 19023229Spst 19033229Spst/* 19043229Spst * Frees the entire host data structure given. Does nothing if the passed 19053229Spst * pointer is NULL. 19063229Spst */ 19073229Spst 19083229SpstPRIVATE void 19093229Spstfree_host(hmp) 19103229Spst hash_datum *hmp; 19113229Spst{ 19123229Spst struct host *hostptr = (struct host *) hmp; 19133229Spst if (hostptr == NULL) 19143229Spst return; 19153229Spst assert(hostptr->linkcount > 0); 19163229Spst if (--(hostptr->linkcount)) 19173229Spst return; /* Still has references */ 19183229Spst del_iplist(hostptr->cookie_server); 19193229Spst del_iplist(hostptr->domain_server); 19203229Spst del_iplist(hostptr->gateway); 19213229Spst del_iplist(hostptr->impress_server); 19223229Spst del_iplist(hostptr->log_server); 19233229Spst del_iplist(hostptr->lpr_server); 19243229Spst del_iplist(hostptr->name_server); 19253229Spst del_iplist(hostptr->rlp_server); 19263229Spst del_iplist(hostptr->time_server); 19273229Spst del_iplist(hostptr->nis_server); 19283229Spst del_iplist(hostptr->ntp_server); 19293229Spst 19303229Spst /* 19313229Spst * XXX - Add new tags here 19323229Spst * (if the value is an IP list) 19333229Spst */ 19343229Spst 19353229Spst del_string(hostptr->hostname); 19363229Spst del_string(hostptr->homedir); 19373229Spst del_string(hostptr->bootfile); 19383229Spst del_string(hostptr->tftpdir); 19393229Spst del_string(hostptr->root_path); 19403229Spst del_string(hostptr->domain_name); 19413229Spst del_string(hostptr->dump_file); 19423229Spst del_string(hostptr->exten_file); 19433229Spst del_string(hostptr->nis_domain); 19443229Spst 19453229Spst#ifdef YORK_EX_OPTION 19463229Spst del_string(hostptr->exec_file); 19473229Spst#endif 19483229Spst 19493229Spst /* 19503229Spst * XXX - Add new tags here 19513229Spst * (if it is a shared string) 19523229Spst */ 19533229Spst 19543229Spst del_bindata(hostptr->generic); 19553229Spst free((char *) hostptr); 19563229Spst} 19573229Spst 19583229Spst 19593229Spst 19603229Spst/* 19613229Spst * Decrements the linkcount on the given IP address data structure. If the 19623229Spst * linkcount goes to zero, the memory associated with the data is freed. 19633229Spst */ 19643229Spst 19653229SpstPRIVATE void 19663229Spstdel_iplist(iplist) 19673229Spst struct in_addr_list *iplist; 19683229Spst{ 19693229Spst if (iplist) { 19703229Spst if (!(--(iplist->linkcount))) { 19713229Spst free((char *) iplist); 19723229Spst } 19733229Spst } 19743229Spst} 19753229Spst 19763229Spst 19773229Spst 19783229Spst/* 19793229Spst * Decrements the linkcount on a string data structure. If the count 19803229Spst * goes to zero, the memory associated with the string is freed. Does 19813229Spst * nothing if the passed pointer is NULL. 19823229Spst */ 19833229Spst 19843229SpstPRIVATE void 19853229Spstdel_string(stringptr) 19863229Spst struct shared_string *stringptr; 19873229Spst{ 19883229Spst if (stringptr) { 19893229Spst if (!(--(stringptr->linkcount))) { 19903229Spst free((char *) stringptr); 19913229Spst } 19923229Spst } 19933229Spst} 19943229Spst 19953229Spst 19963229Spst 19973229Spst/* 19983229Spst * Decrements the linkcount on a shared_bindata data structure. If the 19993229Spst * count goes to zero, the memory associated with the data is freed. Does 20003229Spst * nothing if the passed pointer is NULL. 20013229Spst */ 20023229Spst 20033229SpstPRIVATE void 20043229Spstdel_bindata(dataptr) 20053229Spst struct shared_bindata *dataptr; 20063229Spst{ 20073229Spst if (dataptr) { 20083229Spst if (!(--(dataptr->linkcount))) { 20093229Spst free((char *) dataptr); 20103229Spst } 20113229Spst } 20123229Spst} 20133229Spst 20143229Spst 20153229Spst 20163229Spst 20173229Spst/* smalloc() -- safe malloc() 20183229Spst * 20193229Spst * Always returns a valid pointer (if it returns at all). The allocated 20203229Spst * memory is initialized to all zeros. If malloc() returns an error, a 20213229Spst * message is printed using the report() function and the program aborts 20223229Spst * with a status of 1. 20233229Spst */ 20243229Spst 20253229SpstPRIVATE char * 20263229Spstsmalloc(nbytes) 20273229Spst unsigned nbytes; 20283229Spst{ 20293229Spst char *retvalue; 20303229Spst 20313229Spst retvalue = malloc(nbytes); 20323229Spst if (!retvalue) { 20333229Spst report(LOG_ERR, "malloc() failure -- exiting"); 20343229Spst exit(1); 20353229Spst } 20363229Spst bzero(retvalue, nbytes); 20373229Spst return retvalue; 20383229Spst} 20393229Spst 20403229Spst 20413229Spst/* 20423229Spst * Compare function to determine whether two hardware addresses are 20433229Spst * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 20443229Spst * otherwise. 20453229Spst * 20463229Spst * This function is used when retrieving elements from the hardware address 20473229Spst * hash table. 20483229Spst */ 20493229Spst 20503229Spstboolean 20513229Spsthwlookcmp(d1, d2) 20523229Spst hash_datum *d1, *d2; 20533229Spst{ 20543229Spst struct host *host1 = (struct host *) d1; 20553229Spst struct host *host2 = (struct host *) d2; 20563229Spst 20573229Spst if (host1->htype != host2->htype) { 20583229Spst return FALSE; 20593229Spst } 20603229Spst if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 20613229Spst return FALSE; 20623229Spst } 20633229Spst return TRUE; 20643229Spst} 20653229Spst 20663229Spst 20673229Spst/* 20683229Spst * Compare function for doing IP address hash table lookup. 20693229Spst */ 20703229Spst 20713229Spstboolean 20723229Spstiplookcmp(d1, d2) 20733229Spst hash_datum *d1, *d2; 20743229Spst{ 20753229Spst struct host *host1 = (struct host *) d1; 20763229Spst struct host *host2 = (struct host *) d2; 20773229Spst 20783229Spst return (host1->iaddr.s_addr == host2->iaddr.s_addr); 20793229Spst} 20803229Spst 20813229Spst/* 20823229Spst * Local Variables: 20833229Spst * tab-width: 4 20843229Spst * c-indent-level: 4 20853229Spst * c-argdecl-indent: 4 20863229Spst * c-continued-statement-offset: 4 20873229Spst * c-continued-brace-offset: -4 20883229Spst * c-label-offset: -4 20893229Spst * c-brace-offset: 0 20903229Spst * End: 20913229Spst */ 2092