readfile.c revision 72640
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 72640 2001-02-18 10:25:42Z asmodai $ 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 '/')"; 7003229Spst case E_BAD_VALUE: 7013229Spst msg = "bad value"; 7023229Spst default: 7033229Spst msg = "unkown error"; 7043229Spst break; 7053229Spst } /* switch */ 7063229Spst report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s", 7073229Spst current_hostname, current_tagname, msg); 7083229Spst return -1; 7093229Spst } 7103229Spst} 7113229Spst 7123229Spst 7133229Spst/* 7143229Spst * Macros for use in the function below: 7153229Spst */ 7163229Spst 7173229Spst/* Parse one INET address stored directly in MEMBER. */ 7183229Spst#define PARSE_IA1(MEMBER) do \ 7193229Spst{ \ 7203229Spst if (optype == OP_BOOLEAN) \ 7213229Spst return E_SYNTAX_ERROR; \ 7223229Spst hp->flags.MEMBER = FALSE; \ 7233229Spst if (optype == OP_ADDITION) { \ 7243229Spst if (prs_inetaddr(symbol, &value) < 0) \ 7253229Spst return E_BAD_IPADDR; \ 7263229Spst hp->MEMBER.s_addr = value; \ 7273229Spst hp->flags.MEMBER = TRUE; \ 7283229Spst } \ 7293229Spst} while (0) 7303229Spst 7313229Spst/* Parse a list of INET addresses pointed to by MEMBER */ 7323229Spst#define PARSE_IAL(MEMBER) do \ 7333229Spst{ \ 7343229Spst if (optype == OP_BOOLEAN) \ 7353229Spst return E_SYNTAX_ERROR; \ 7363229Spst if (hp->flags.MEMBER) { \ 7373229Spst hp->flags.MEMBER = FALSE; \ 7383229Spst assert(hp->MEMBER); \ 7393229Spst del_iplist(hp->MEMBER); \ 7403229Spst hp->MEMBER = NULL; \ 7413229Spst } \ 7423229Spst if (optype == OP_ADDITION) { \ 7433229Spst hp->MEMBER = get_addresses(symbol); \ 7443229Spst if (hp->MEMBER == NULL) \ 7453229Spst return E_SYNTAX_ERROR; \ 7463229Spst hp->flags.MEMBER = TRUE; \ 7473229Spst } \ 7483229Spst} while (0) 7493229Spst 7503229Spst/* Parse a shared string pointed to by MEMBER */ 7513229Spst#define PARSE_STR(MEMBER) do \ 7523229Spst{ \ 7533229Spst if (optype == OP_BOOLEAN) \ 7543229Spst return E_SYNTAX_ERROR; \ 7553229Spst if (hp->flags.MEMBER) { \ 7563229Spst hp->flags.MEMBER = FALSE; \ 7573229Spst assert(hp->MEMBER); \ 7583229Spst del_string(hp->MEMBER); \ 7593229Spst hp->MEMBER = NULL; \ 7603229Spst } \ 7613229Spst if (optype == OP_ADDITION) { \ 7623229Spst hp->MEMBER = get_shared_string(symbol); \ 7633229Spst if (hp->MEMBER == NULL) \ 7643229Spst return E_SYNTAX_ERROR; \ 7653229Spst hp->flags.MEMBER = TRUE; \ 7663229Spst } \ 7673229Spst} while (0) 7683229Spst 76913572Spst/* Parse an unsigned integer value for MEMBER */ 77013572Spst#define PARSE_UINT(MEMBER) do \ 7713229Spst{ \ 7723229Spst if (optype == OP_BOOLEAN) \ 7733229Spst return E_SYNTAX_ERROR; \ 7743229Spst hp->flags.MEMBER = FALSE; \ 7753229Spst if (optype == OP_ADDITION) { \ 7763229Spst value = get_u_long(symbol); \ 7773229Spst hp->MEMBER = value; \ 7783229Spst hp->flags.MEMBER = TRUE; \ 7793229Spst } \ 7803229Spst} while (0) 7813229Spst 7823229Spst/* 7833229Spst * Evaluate the two-character tag symbol pointed to by "symbol" and place 7843229Spst * the data in the structure pointed to by "hp". The pointer pointed to 7853229Spst * by "symbol" is updated to point past the source string (but may not 7863229Spst * point to the next tag entry). 7873229Spst * 7883229Spst * Obviously, this need a few more comments. . . . 7893229Spst */ 7903229SpstPRIVATE int 7913229Spsteval_symbol(symbol, hp) 7923229Spst char **symbol; 7933229Spst struct host *hp; 7943229Spst{ 7953229Spst char tmpstr[MAXSTRINGLEN]; 7963229Spst byte *tmphaddr; 7973229Spst struct symbolmap *symbolptr; 7983229Spst u_int32 value; 7993229Spst int32 timeoff; 8003229Spst int i, numsymbols; 8013229Spst unsigned len; 8023229Spst int optype; /* Indicates boolean, addition, or deletion */ 8033229Spst 8043229Spst eat_whitespace(symbol); 8053229Spst 8063229Spst /* Make sure this is set before returning. */ 8073229Spst current_tagname[0] = (*symbol)[0]; 8083229Spst current_tagname[1] = (*symbol)[1]; 8093229Spst current_tagname[2] = 0; 8103229Spst 8113229Spst if ((*symbol)[0] == '\0') { 8123229Spst return E_END_OF_ENTRY; 8133229Spst } 8143229Spst if ((*symbol)[0] == ':') { 8153229Spst return SUCCESS; 8163229Spst } 8173229Spst if ((*symbol)[0] == 'T') { /* generic symbol */ 8183229Spst (*symbol)++; 8193229Spst value = get_u_long(symbol); 82031971Simp snprintf(current_tagname, sizeof(current_tagname), 82131971Simp "T%d", (int)value); 8223229Spst eat_whitespace(symbol); 8233229Spst if ((*symbol)[0] != '=') { 8243229Spst return E_SYNTAX_ERROR; 8253229Spst } 8263229Spst (*symbol)++; 8273229Spst if (!(hp->generic)) { 8283229Spst hp->generic = (struct shared_bindata *) 8293229Spst smalloc(sizeof(struct shared_bindata)); 8303229Spst } 8313229Spst if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF))) 8323229Spst return E_SYNTAX_ERROR; 8333229Spst hp->flags.generic = TRUE; 8343229Spst return SUCCESS; 8353229Spst } 8363229Spst /* 8373229Spst * Determine the type of operation to be done on this symbol 8383229Spst */ 8393229Spst switch ((*symbol)[2]) { 8403229Spst case '=': 8413229Spst optype = OP_ADDITION; 8423229Spst break; 8433229Spst case '@': 8443229Spst optype = OP_DELETION; 8453229Spst break; 8463229Spst case ':': 8473229Spst case '\0': 8483229Spst optype = OP_BOOLEAN; 8493229Spst break; 8503229Spst default: 8513229Spst return E_SYNTAX_ERROR; 8523229Spst } 8533229Spst 8543229Spst symbolptr = symbol_list; 8553229Spst numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap); 8563229Spst for (i = 0; i < numsymbols; i++) { 8573229Spst if (((symbolptr->symbol)[0] == (*symbol)[0]) && 8583229Spst ((symbolptr->symbol)[1] == (*symbol)[1])) { 8593229Spst break; 8603229Spst } 8613229Spst symbolptr++; 8623229Spst } 8633229Spst if (i >= numsymbols) { 8643229Spst return E_UNKNOWN_SYMBOL; 8653229Spst } 8663229Spst /* 8673229Spst * Skip past the = or @ character (to point to the data) if this 8683229Spst * isn't a boolean operation. For boolean operations, just skip 8693229Spst * over the two-character tag symbol (and nothing else. . . .). 8703229Spst */ 8713229Spst (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3; 8723229Spst 8733229Spst eat_whitespace(symbol); 8743229Spst 8753229Spst /* The cases below are in order by symbolcode value. */ 8763229Spst switch (symbolptr->symbolcode) { 8773229Spst 8783229Spst case SYM_BOOTFILE: 8793229Spst PARSE_STR(bootfile); 8803229Spst break; 8813229Spst 8823229Spst case SYM_COOKIE_SERVER: 8833229Spst PARSE_IAL(cookie_server); 8843229Spst break; 8853229Spst 8863229Spst case SYM_DOMAIN_SERVER: 8873229Spst PARSE_IAL(domain_server); 8883229Spst break; 8893229Spst 8903229Spst case SYM_GATEWAY: 8913229Spst PARSE_IAL(gateway); 8923229Spst break; 8933229Spst 8943229Spst case SYM_HWADDR: 8953229Spst if (optype == OP_BOOLEAN) 8963229Spst return E_SYNTAX_ERROR; 8973229Spst hp->flags.haddr = FALSE; 8983229Spst if (optype == OP_ADDITION) { 8993229Spst /* Default the HW type to Ethernet */ 9003229Spst if (hp->flags.htype == 0) { 9013229Spst hp->flags.htype = TRUE; 9023229Spst hp->htype = HTYPE_ETHERNET; 9033229Spst } 9043229Spst tmphaddr = prs_haddr(symbol, hp->htype); 9053229Spst if (!tmphaddr) 9063229Spst return E_BAD_HWADDR; 9073229Spst bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype)); 9083229Spst hp->flags.haddr = TRUE; 9093229Spst } 9103229Spst break; 9113229Spst 9123229Spst case SYM_HOMEDIR: 9133229Spst PARSE_STR(homedir); 9143229Spst break; 9153229Spst 9163229Spst case SYM_HTYPE: 9173229Spst if (optype == OP_BOOLEAN) 9183229Spst return E_SYNTAX_ERROR; 9193229Spst hp->flags.htype = FALSE; 9203229Spst if (optype == OP_ADDITION) { 9213229Spst value = 0L; /* Assume an illegal value */ 9223229Spst eat_whitespace(symbol); 9233229Spst if (isdigit(**symbol)) { 9243229Spst value = get_u_long(symbol); 9253229Spst } else { 9263229Spst len = sizeof(tmpstr); 9273229Spst (void) get_string(symbol, tmpstr, &len); 9283229Spst makelower(tmpstr); 9293229Spst numsymbols = sizeof(htnamemap) / 9303229Spst sizeof(struct htypename); 9313229Spst for (i = 0; i < numsymbols; i++) { 9323229Spst if (!strcmp(htnamemap[i].name, tmpstr)) { 9333229Spst break; 9343229Spst } 9353229Spst } 9363229Spst if (i < numsymbols) { 9373229Spst value = htnamemap[i].htype; 9383229Spst } 9393229Spst } 9403229Spst if (value >= hwinfocnt) { 9413229Spst return E_BAD_HWATYPE; 9423229Spst } 9433229Spst hp->htype = (byte) (value & 0xFF); 9443229Spst hp->flags.htype = TRUE; 9453229Spst } 9463229Spst break; 9473229Spst 9483229Spst case SYM_IMPRESS_SERVER: 9493229Spst PARSE_IAL(impress_server); 9503229Spst break; 9513229Spst 9523229Spst case SYM_IPADDR: 9533229Spst PARSE_IA1(iaddr); 9543229Spst break; 9553229Spst 9563229Spst case SYM_LOG_SERVER: 9573229Spst PARSE_IAL(log_server); 9583229Spst break; 9593229Spst 9603229Spst case SYM_LPR_SERVER: 9613229Spst PARSE_IAL(lpr_server); 9623229Spst break; 9633229Spst 9643229Spst case SYM_NAME_SERVER: 9653229Spst PARSE_IAL(name_server); 9663229Spst break; 9673229Spst 9683229Spst case SYM_RLP_SERVER: 9693229Spst PARSE_IAL(rlp_server); 9703229Spst break; 9713229Spst 9723229Spst case SYM_SUBNET_MASK: 9733229Spst PARSE_IA1(subnet_mask); 9743229Spst break; 9753229Spst 9763229Spst case SYM_TIME_OFFSET: 9773229Spst if (optype == OP_BOOLEAN) 9783229Spst return E_SYNTAX_ERROR; 9793229Spst hp->flags.time_offset = FALSE; 9803229Spst if (optype == OP_ADDITION) { 9813229Spst len = sizeof(tmpstr); 9823229Spst (void) get_string(symbol, tmpstr, &len); 9833229Spst if (!strncmp(tmpstr, "auto", 4)) { 9843229Spst hp->time_offset = secondswest; 9853229Spst } else { 98613572Spst if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1) 9873229Spst return E_BAD_LONGWORD; 9883229Spst hp->time_offset = timeoff; 9893229Spst } 9903229Spst hp->flags.time_offset = TRUE; 9913229Spst } 9923229Spst break; 9933229Spst 9943229Spst case SYM_TIME_SERVER: 9953229Spst PARSE_IAL(time_server); 9963229Spst break; 9973229Spst 9983229Spst case SYM_VENDOR_MAGIC: 9993229Spst if (optype == OP_BOOLEAN) 10003229Spst return E_SYNTAX_ERROR; 10013229Spst hp->flags.vm_cookie = FALSE; 10023229Spst if (optype == OP_ADDITION) { 10033229Spst if (strncmp(*symbol, "auto", 4)) { 10043229Spst /* The string is not "auto" */ 10053229Spst if (!strncmp(*symbol, "rfc", 3)) { 10063229Spst bcopy(vm_rfc1048, hp->vm_cookie, 4); 10073229Spst } else if (!strncmp(*symbol, "cmu", 3)) { 10083229Spst bcopy(vm_cmu, hp->vm_cookie, 4); 10093229Spst } else { 10103229Spst if (!isdigit(**symbol)) 10113229Spst return E_BAD_IPADDR; 10123229Spst if (prs_inetaddr(symbol, &value) < 0) 10133229Spst return E_BAD_IPADDR; 10143229Spst bcopy(&value, hp->vm_cookie, 4); 10153229Spst } 10163229Spst hp->flags.vm_cookie = TRUE; 10173229Spst } 10183229Spst } 10193229Spst break; 10203229Spst 10213229Spst case SYM_SIMILAR_ENTRY: 10223229Spst switch (optype) { 10233229Spst case OP_ADDITION: 10243229Spst fill_defaults(hp, symbol); 10253229Spst break; 10263229Spst default: 10273229Spst return E_SYNTAX_ERROR; 10283229Spst } 10293229Spst break; 10303229Spst 10313229Spst case SYM_NAME_SWITCH: 10323229Spst switch (optype) { 10333229Spst case OP_ADDITION: 10343229Spst return E_SYNTAX_ERROR; 10353229Spst case OP_DELETION: 10363229Spst hp->flags.send_name = FALSE; 10373229Spst hp->flags.name_switch = FALSE; 10383229Spst break; 10393229Spst case OP_BOOLEAN: 10403229Spst hp->flags.send_name = TRUE; 10413229Spst hp->flags.name_switch = TRUE; 10423229Spst break; 10433229Spst } 10443229Spst break; 10453229Spst 10463229Spst case SYM_BOOTSIZE: 10473229Spst switch (optype) { 10483229Spst case OP_ADDITION: 10493229Spst if (!strncmp(*symbol, "auto", 4)) { 10503229Spst hp->flags.bootsize = TRUE; 10513229Spst hp->flags.bootsize_auto = TRUE; 10523229Spst } else { 10533229Spst hp->bootsize = (unsigned int) get_u_long(symbol); 10543229Spst hp->flags.bootsize = TRUE; 10553229Spst hp->flags.bootsize_auto = FALSE; 10563229Spst } 10573229Spst break; 10583229Spst case OP_DELETION: 10593229Spst hp->flags.bootsize = FALSE; 10603229Spst break; 10613229Spst case OP_BOOLEAN: 10623229Spst hp->flags.bootsize = TRUE; 10633229Spst hp->flags.bootsize_auto = TRUE; 10643229Spst break; 10653229Spst } 10663229Spst break; 10673229Spst 10683229Spst case SYM_BOOT_SERVER: 10693229Spst PARSE_IA1(bootserver); 10703229Spst break; 10713229Spst 10723229Spst case SYM_TFTPDIR: 10733229Spst PARSE_STR(tftpdir); 10743229Spst if ((hp->tftpdir != NULL) && 10753229Spst (hp->tftpdir->string[0] != '/')) 10763229Spst return E_BAD_PATHNAME; 10773229Spst break; 10783229Spst 10793229Spst case SYM_DUMP_FILE: 10803229Spst PARSE_STR(dump_file); 10813229Spst break; 10823229Spst 10833229Spst case SYM_DOMAIN_NAME: 10843229Spst PARSE_STR(domain_name); 10853229Spst break; 10863229Spst 10873229Spst case SYM_SWAP_SERVER: 10883229Spst PARSE_IA1(swap_server); 10893229Spst break; 10903229Spst 10913229Spst case SYM_ROOT_PATH: 10923229Spst PARSE_STR(root_path); 10933229Spst break; 10943229Spst 10953229Spst case SYM_EXTEN_FILE: 10963229Spst PARSE_STR(exten_file); 10973229Spst break; 10983229Spst 10993229Spst case SYM_REPLY_ADDR: 11003229Spst PARSE_IA1(reply_addr); 11013229Spst break; 11023229Spst 11033229Spst case SYM_NIS_DOMAIN: 11043229Spst PARSE_STR(nis_domain); 11053229Spst break; 11063229Spst 11073229Spst case SYM_NIS_SERVER: 11083229Spst PARSE_IAL(nis_server); 11093229Spst break; 11103229Spst 11113229Spst case SYM_NTP_SERVER: 11123229Spst PARSE_IAL(ntp_server); 11133229Spst break; 11143229Spst 11153229Spst#ifdef YORK_EX_OPTION 11163229Spst case SYM_EXEC_FILE: 11173229Spst PARSE_STR(exec_file); 11183229Spst break; 11193229Spst#endif 11203229Spst 11213229Spst case SYM_MSG_SIZE: 112213572Spst PARSE_UINT(msg_size); 11233229Spst if (hp->msg_size < BP_MINPKTSZ || 11243229Spst hp->msg_size > MAX_MSG_SIZE) 11253229Spst return E_BAD_VALUE; 11263229Spst break; 11273229Spst 11283229Spst case SYM_MIN_WAIT: 112913572Spst PARSE_UINT(min_wait); 11303229Spst break; 11313229Spst 11323229Spst /* XXX - Add new tags here */ 11333229Spst 11343229Spst default: 11353229Spst return E_UNKNOWN_SYMBOL; 11363229Spst 11373229Spst } /* switch symbolcode */ 11383229Spst 11393229Spst return SUCCESS; 11403229Spst} 11413229Spst#undef PARSE_IA1 11423229Spst#undef PARSE_IAL 11433229Spst#undef PARSE_STR 11443229Spst 11453229Spst 11463229Spst 11473229Spst 11483229Spst/* 11493229Spst * Read a string from the buffer indirectly pointed to through "src" and 11503229Spst * move it into the buffer pointed to by "dest". A pointer to the maximum 11513229Spst * allowable length of the string (including null-terminator) is passed as 11523229Spst * "length". The actual length of the string which was read is returned in 11533229Spst * the unsigned integer pointed to by "length". This value is the same as 11543229Spst * that which would be returned by applying the strlen() function on the 11553229Spst * destination string (i.e the terminating null is not counted as a 11563229Spst * character). Trailing whitespace is removed from the string. For 11573229Spst * convenience, the function returns the new value of "dest". 11583229Spst * 11593229Spst * The string is read until the maximum number of characters, an unquoted 11603229Spst * colon (:), or a null character is read. The return string in "dest" is 11613229Spst * null-terminated. 11623229Spst */ 11633229Spst 11643229SpstPRIVATE char * 11653229Spstget_string(src, dest, length) 11663229Spst char **src, *dest; 11673229Spst unsigned *length; 11683229Spst{ 11693229Spst int n, len, quoteflag; 11703229Spst 11713229Spst quoteflag = FALSE; 11723229Spst n = 0; 11733229Spst len = *length - 1; 11743229Spst while ((n < len) && (**src)) { 11753229Spst if (!quoteflag && (**src == ':')) { 11763229Spst break; 11773229Spst } 11783229Spst if (**src == '"') { 11793229Spst (*src)++; 11803229Spst quoteflag = !quoteflag; 11813229Spst continue; 11823229Spst } 11833229Spst if (**src == '\\') { 11843229Spst (*src)++; 11853229Spst if (!**src) { 11863229Spst break; 11873229Spst } 11883229Spst } 11893229Spst *dest++ = *(*src)++; 11903229Spst n++; 11913229Spst } 11923229Spst 11933229Spst /* 11943229Spst * Remove that troublesome trailing whitespace. . . 11953229Spst */ 11963229Spst while ((n > 0) && isspace(dest[-1])) { 11973229Spst dest--; 11983229Spst n--; 11993229Spst } 12003229Spst 12013229Spst *dest = '\0'; 12023229Spst *length = n; 12033229Spst return dest; 12043229Spst} 12053229Spst 12063229Spst 12073229Spst 12083229Spst/* 12093229Spst * Read the string indirectly pointed to by "src", update the caller's 12103229Spst * pointer, and return a pointer to a malloc'ed shared_string structure 12113229Spst * containing the string. 12123229Spst * 12133229Spst * The string is read using the same rules as get_string() above. 12143229Spst */ 12153229Spst 12163229SpstPRIVATE struct shared_string * 12173229Spstget_shared_string(src) 12183229Spst char **src; 12193229Spst{ 12203229Spst char retstring[MAXSTRINGLEN]; 12213229Spst struct shared_string *s; 12223229Spst unsigned length; 12233229Spst 12243229Spst length = sizeof(retstring); 12253229Spst (void) get_string(src, retstring, &length); 12263229Spst 12273229Spst s = (struct shared_string *) smalloc(sizeof(struct shared_string) 12283229Spst + length); 12293229Spst s->linkcount = 1; 12303229Spst strcpy(s->string, retstring); 12313229Spst 12323229Spst return s; 12333229Spst} 12343229Spst 12353229Spst 12363229Spst 12373229Spst/* 12383229Spst * Load RFC1048 generic information directly into a memory buffer. 12393229Spst * 12403229Spst * "src" indirectly points to the ASCII representation of the generic data. 12413229Spst * "dest" points to a string structure which is updated to point to a new 12423229Spst * string with the new data appended to the old string. The old string is 12433229Spst * freed. 12443229Spst * 12453229Spst * The given tag value is inserted with the new data. 12463229Spst * 12473229Spst * The data may be represented as either a stream of hexadecimal numbers 12483229Spst * representing bytes (any or all bytes may optionally start with '0x' and 12493229Spst * be separated with periods ".") or as a quoted string of ASCII 12503229Spst * characters (the quotes are required). 12513229Spst */ 12523229Spst 12533229SpstPRIVATE int 12543229Spstprocess_generic(src, dest, tagvalue) 12553229Spst char **src; 12563229Spst struct shared_bindata **dest; 12573229Spst u_int tagvalue; 12583229Spst{ 12593229Spst byte tmpbuf[MAXBUFLEN]; 12603229Spst byte *str; 12613229Spst struct shared_bindata *bdata; 12623229Spst u_int newlength, oldlength; 12633229Spst 12643229Spst str = tmpbuf; 12653229Spst *str++ = (tagvalue & 0xFF); /* Store tag value */ 12663229Spst str++; /* Skip over length field */ 12673229Spst if ((*src)[0] == '"') { /* ASCII data */ 12683229Spst newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */ 12693229Spst (void) get_string(src, (char *) str, &newlength); 12703229Spst newlength++; /* null terminator */ 12713229Spst } else { /* Numeric data */ 12723229Spst newlength = 0; 12733229Spst while (newlength < sizeof(tmpbuf) - 2) { 12743229Spst if (interp_byte(src, str++) < 0) 12753229Spst break; 12763229Spst newlength++; 12773229Spst if (**src == '.') { 12783229Spst (*src)++; 12793229Spst } 12803229Spst } 12813229Spst } 12823229Spst if ((*src)[0] != ':') 12833229Spst return -1; 12843229Spst 12853229Spst tmpbuf[1] = (newlength & 0xFF); 12863229Spst oldlength = ((*dest)->length); 12873229Spst bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata) 12883229Spst + oldlength + newlength + 1); 12893229Spst if (oldlength > 0) { 12903229Spst bcopy((*dest)->data, bdata->data, oldlength); 12913229Spst } 12923229Spst bcopy(tmpbuf, bdata->data + oldlength, newlength + 2); 12933229Spst bdata->length = oldlength + newlength + 2; 12943229Spst bdata->linkcount = 1; 12953229Spst if (*dest) { 12963229Spst del_bindata(*dest); 12973229Spst } 12983229Spst *dest = bdata; 12993229Spst return 0; 13003229Spst} 13013229Spst 13023229Spst 13033229Spst 13043229Spst/* 13053229Spst * Verify that the given string makes sense as a hostname (according to 13063229Spst * Appendix 1, page 29 of RFC882). 13073229Spst * 13083229Spst * Return TRUE for good names, FALSE otherwise. 13093229Spst */ 13103229Spst 13113229SpstPRIVATE boolean 13123229Spstgoodname(hostname) 13133229Spst register char *hostname; 13143229Spst{ 13153229Spst do { 13163229Spst if (!isalpha(*hostname++)) { /* First character must be a letter */ 13173229Spst return FALSE; 13183229Spst } 13193229Spst while (isalnum(*hostname) || 13203229Spst (*hostname == '-') || 13213229Spst (*hostname == '_') ) 13223229Spst { 13233229Spst hostname++; /* Alphanumeric or a hyphen */ 13243229Spst } 13253229Spst if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */ 13263229Spst return FALSE; 13273229Spst } 13283229Spst if (*hostname == '\0') {/* Done? */ 13293229Spst return TRUE; 13303229Spst } 13313229Spst } while (*hostname++ == '.'); /* Dot, loop for next label */ 13323229Spst 13333229Spst return FALSE; /* If it's not a dot, lose */ 13343229Spst} 13353229Spst 13363229Spst 13373229Spst 13383229Spst/* 13393229Spst * Null compare function -- always returns FALSE so an element is always 13403229Spst * inserted into a hash table (i.e. there is never a collision with an 13413229Spst * existing element). 13423229Spst */ 13433229Spst 13443229SpstPRIVATE boolean 13453229Spstnullcmp(d1, d2) 13463229Spst hash_datum *d1, *d2; 13473229Spst{ 13483229Spst return FALSE; 13493229Spst} 13503229Spst 13513229Spst 13523229Spst/* 13533229Spst * Function for comparing a string with the hostname field of a host 13543229Spst * structure. 13553229Spst */ 13563229Spst 13573229Spstboolean 13583229Spstnmcmp(d1, d2) 13593229Spst hash_datum *d1, *d2; 13603229Spst{ 13613229Spst char *name = (char *) d1; /* XXX - OK? */ 13623229Spst struct host *hp = (struct host *) d2; 13633229Spst 13643229Spst return !strcmp(name, hp->hostname->string); 13653229Spst} 13663229Spst 13673229Spst 13683229Spst/* 13693229Spst * Compare function to determine whether two hardware addresses are 13703229Spst * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 13713229Spst * otherwise. 13723229Spst * 13733229Spst * If the hardware addresses of "host1" and "host2" are identical, but 13743229Spst * they are on different IP subnets, this function returns FALSE. 13753229Spst * 13763229Spst * This function is used when inserting elements into the hardware address 13773229Spst * hash table. 13783229Spst */ 13793229Spst 13803229SpstPRIVATE boolean 13813229Spsthwinscmp(d1, d2) 13823229Spst hash_datum *d1, *d2; 13833229Spst{ 13843229Spst struct host *host1 = (struct host *) d1; 13853229Spst struct host *host2 = (struct host *) d2; 13863229Spst 13873229Spst if (host1->htype != host2->htype) { 13883229Spst return FALSE; 13893229Spst } 13903229Spst if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 13913229Spst return FALSE; 13923229Spst } 13933229Spst /* XXX - Is the subnet_mask field set yet? */ 13943229Spst if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) { 13953229Spst if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) != 13963229Spst ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) 13973229Spst { 13983229Spst return FALSE; 13993229Spst } 14003229Spst } 14013229Spst return TRUE; 14023229Spst} 14033229Spst 14043229Spst 14053229Spst/* 14063229Spst * Macros for use in the function below: 14073229Spst */ 14083229Spst 14093229Spst#define DUP_COPY(MEMBER) do \ 14103229Spst{ \ 14113229Spst if (!hp->flags.MEMBER) { \ 14123229Spst if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 14133229Spst hp->MEMBER = hp2->MEMBER; \ 14143229Spst } \ 14153229Spst } \ 14163229Spst} while (0) 14173229Spst 14183229Spst#define DUP_LINK(MEMBER) do \ 14193229Spst{ \ 14203229Spst if (!hp->flags.MEMBER) { \ 14213229Spst if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \ 14223229Spst assert(hp2->MEMBER); \ 14233229Spst hp->MEMBER = hp2->MEMBER; \ 14243229Spst (hp->MEMBER->linkcount)++; \ 14253229Spst } \ 14263229Spst } \ 14273229Spst} while (0) 14283229Spst 14293229Spst/* 14303229Spst * Process the "similar entry" symbol. 14313229Spst * 14323229Spst * The host specified as the value of the "tc" symbol is used as a template 14333229Spst * for the current host entry. Symbol values not explicitly set in the 14343229Spst * current host entry are inferred from the template entry. 14353229Spst */ 14363229SpstPRIVATE void 14373229Spstfill_defaults(hp, src) 14383229Spst struct host *hp; 14393229Spst char **src; 14403229Spst{ 14413229Spst unsigned int tlen, hashcode; 14423229Spst struct host *hp2; 14433229Spst char tstring[MAXSTRINGLEN]; 14443229Spst 14453229Spst tlen = sizeof(tstring); 14463229Spst (void) get_string(src, tstring, &tlen); 14473229Spst hashcode = hash_HashFunction((u_char *) tstring, tlen); 14483229Spst hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring); 14493229Spst 14503229Spst if (hp2 == NULL) { 14513229Spst report(LOG_ERR, "can't find tc=\"%s\"", tstring); 14523229Spst return; 14533229Spst } 14543229Spst DUP_LINK(bootfile); 14553229Spst DUP_LINK(cookie_server); 14563229Spst DUP_LINK(domain_server); 14573229Spst DUP_LINK(gateway); 14583229Spst /* haddr not copied */ 14593229Spst DUP_LINK(homedir); 14603229Spst DUP_COPY(htype); 14613229Spst 14623229Spst DUP_LINK(impress_server); 14633229Spst /* iaddr not copied */ 14643229Spst DUP_LINK(log_server); 14653229Spst DUP_LINK(lpr_server); 14663229Spst DUP_LINK(name_server); 14673229Spst DUP_LINK(rlp_server); 14683229Spst 14693229Spst DUP_COPY(subnet_mask); 14703229Spst DUP_COPY(time_offset); 14713229Spst DUP_LINK(time_server); 14723229Spst 14733229Spst if (!hp->flags.vm_cookie) { 14743229Spst if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) { 14753229Spst bcopy(hp2->vm_cookie, hp->vm_cookie, 4); 14763229Spst } 14773229Spst } 14783229Spst if (!hp->flags.name_switch) { 14793229Spst if ((hp->flags.name_switch = hp2->flags.name_switch)) { 14803229Spst hp->flags.send_name = hp2->flags.send_name; 14813229Spst } 14823229Spst } 14833229Spst if (!hp->flags.bootsize) { 14843229Spst if ((hp->flags.bootsize = hp2->flags.bootsize)) { 14853229Spst hp->flags.bootsize_auto = hp2->flags.bootsize_auto; 14863229Spst hp->bootsize = hp2->bootsize; 14873229Spst } 14883229Spst } 14893229Spst DUP_COPY(bootserver); 14903229Spst 14913229Spst DUP_LINK(tftpdir); 14923229Spst DUP_LINK(dump_file); 14933229Spst DUP_LINK(domain_name); 14943229Spst 14953229Spst DUP_COPY(swap_server); 14963229Spst DUP_LINK(root_path); 14973229Spst DUP_LINK(exten_file); 14983229Spst 14993229Spst DUP_COPY(reply_addr); 15003229Spst 15013229Spst DUP_LINK(nis_domain); 15023229Spst DUP_LINK(nis_server); 15033229Spst DUP_LINK(ntp_server); 15043229Spst 15053229Spst#ifdef YORK_EX_OPTION 15063229Spst DUP_LINK(exec_file); 15073229Spst#endif 15083229Spst 15093229Spst DUP_COPY(msg_size); 15103229Spst DUP_COPY(min_wait); 15113229Spst 15123229Spst /* XXX - Add new tags here */ 15133229Spst 15143229Spst DUP_LINK(generic); 15153229Spst 15163229Spst} 15173229Spst#undef DUP_COPY 15183229Spst#undef DUP_LINK 15193229Spst 15203229Spst 15213229Spst 15223229Spst/* 15233229Spst * This function adjusts the caller's pointer to point just past the 15243229Spst * first-encountered colon. If it runs into a null character, it leaves 15253229Spst * the pointer pointing to it. 15263229Spst */ 15273229Spst 15283229SpstPRIVATE void 15293229Spstadjust(s) 15303229Spst char **s; 15313229Spst{ 15323229Spst register char *t; 15333229Spst 15343229Spst t = *s; 15353229Spst while (*t && (*t != ':')) { 15363229Spst t++; 15373229Spst } 15383229Spst if (*t) { 15393229Spst t++; 15403229Spst } 15413229Spst *s = t; 15423229Spst} 15433229Spst 15443229Spst 15453229Spst 15463229Spst 15473229Spst/* 15483229Spst * This function adjusts the caller's pointer to point to the first 15493229Spst * non-whitespace character. If it runs into a null character, it leaves 15503229Spst * the pointer pointing to it. 15513229Spst */ 15523229Spst 15533229SpstPRIVATE void 15543229Spsteat_whitespace(s) 15553229Spst char **s; 15563229Spst{ 15573229Spst register char *t; 15583229Spst 15593229Spst t = *s; 15603229Spst while (*t && isspace(*t)) { 15613229Spst t++; 15623229Spst } 15633229Spst *s = t; 15643229Spst} 15653229Spst 15663229Spst 15673229Spst 15683229Spst/* 15693229Spst * This function converts the given string to all lowercase. 15703229Spst */ 15713229Spst 15723229SpstPRIVATE void 15733229Spstmakelower(s) 15743229Spst char *s; 15753229Spst{ 15763229Spst while (*s) { 15773229Spst if (isupper(*s)) { 15783229Spst *s = tolower(*s); 15793229Spst } 15803229Spst s++; 15813229Spst } 15823229Spst} 15833229Spst 15843229Spst 15853229Spst 15863229Spst/* 15873229Spst * 15883229Spst * N O T E : 15893229Spst * 15903229Spst * In many of the functions which follow, a parameter such as "src" or 15913229Spst * "symbol" is passed as a pointer to a pointer to something. This is 15923229Spst * done for the purpose of letting the called function update the 15933229Spst * caller's copy of the parameter (i.e. to effect call-by-reference 15943229Spst * parameter passing). The value of the actual parameter is only used 15953229Spst * to locate the real parameter of interest and then update this indirect 15963229Spst * parameter. 15973229Spst * 15983229Spst * I'm sure somebody out there won't like this. . . . 15993229Spst * (Yea, because it usually makes code slower... -gwr) 16003229Spst * 16013229Spst */ 16023229Spst 16033229Spst 16043229Spst 16053229Spst/* 16063229Spst * "src" points to a character pointer which points to an ASCII string of 16073229Spst * whitespace-separated IP addresses. A pointer to an in_addr_list 16083229Spst * structure containing the list of addresses is returned. NULL is 16093229Spst * returned if no addresses were found at all. The pointer pointed to by 16103229Spst * "src" is updated to point to the first non-address (illegal) character. 16113229Spst */ 16123229Spst 16133229SpstPRIVATE struct in_addr_list * 16143229Spstget_addresses(src) 16153229Spst char **src; 16163229Spst{ 16173229Spst struct in_addr tmpaddrlist[MAXINADDRS]; 16183229Spst struct in_addr *address1, *address2; 16193229Spst struct in_addr_list *result; 16203229Spst unsigned addrcount, totalsize; 16213229Spst 16223229Spst address1 = tmpaddrlist; 16233229Spst for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) { 16243229Spst while (isspace(**src) || (**src == ',')) { 16253229Spst (*src)++; 16263229Spst } 16273229Spst if (!**src) { /* Quit if nothing more */ 16283229Spst break; 16293229Spst } 16303229Spst if (prs_inetaddr(src, &(address1->s_addr)) < 0) { 16313229Spst break; 16323229Spst } 16333229Spst address1++; /* Point to next address slot */ 16343229Spst } 16353229Spst if (addrcount < 1) { 16363229Spst result = NULL; 16373229Spst } else { 16383229Spst totalsize = sizeof(struct in_addr_list) 16393229Spst + (addrcount - 1) * sizeof(struct in_addr); 16403229Spst result = (struct in_addr_list *) smalloc(totalsize); 16413229Spst result->linkcount = 1; 16423229Spst result->addrcount = addrcount; 16433229Spst address1 = tmpaddrlist; 16443229Spst address2 = result->addr; 16453229Spst for (; addrcount > 0; addrcount--) { 16463229Spst address2->s_addr = address1->s_addr; 16473229Spst address1++; 16483229Spst address2++; 16493229Spst } 16503229Spst } 16513229Spst return result; 16523229Spst} 16533229Spst 16543229Spst 16553229Spst 16563229Spst/* 16573229Spst * prs_inetaddr(src, result) 16583229Spst * 16593229Spst * "src" is a value-result parameter; the pointer it points to is updated 16603229Spst * to point to the next data position. "result" points to an unsigned long 16613229Spst * in which an address is returned. 16623229Spst * 16633229Spst * This function parses the IP address string in ASCII "dot notation" pointed 16643229Spst * to by (*src) and places the result (in network byte order) in the unsigned 16653229Spst * long pointed to by "result". For malformed addresses, -1 is returned, 16663229Spst * (*src) points to the first illegal character, and the unsigned long pointed 16673229Spst * to by "result" is unchanged. Successful calls return 0. 16683229Spst */ 16693229Spst 16703229SpstPRIVATE int 16713229Spstprs_inetaddr(src, result) 16723229Spst char **src; 16733229Spst u_int32 *result; 16743229Spst{ 16753229Spst char tmpstr[MAXSTRINGLEN]; 16763229Spst register u_int32 value; 16773229Spst u_int32 parts[4], *pp; 16783229Spst int n; 16793229Spst char *s, *t; 16803229Spst 16813229Spst /* Leading alpha char causes IP addr lookup. */ 16823229Spst if (isalpha(**src)) { 16833229Spst /* Lookup IP address. */ 16843229Spst s = *src; 16853229Spst t = tmpstr; 16863229Spst while ((isalnum(*s) || (*s == '.') || 16873229Spst (*s == '-') || (*s == '_') ) && 16883229Spst (t < &tmpstr[MAXSTRINGLEN - 1]) ) 16893229Spst *t++ = *s++; 16903229Spst *t = '\0'; 16913229Spst *src = s; 16923229Spst 16933229Spst n = lookup_ipa(tmpstr, result); 16943229Spst if (n < 0) 16953229Spst report(LOG_ERR, "can not get IP addr for %s", tmpstr); 16963229Spst return n; 16973229Spst } 16983229Spst 16993229Spst /* 17003229Spst * Parse an address in Internet format: 17013229Spst * a.b.c.d 17023229Spst * a.b.c (with c treated as 16-bits) 17033229Spst * a.b (with b treated as 24 bits) 17043229Spst */ 17053229Spst pp = parts; 17063229Spst loop: 17073229Spst /* If it's not a digit, return error. */ 17083229Spst if (!isdigit(**src)) 17093229Spst return -1; 17103229Spst *pp++ = get_u_long(src); 17113229Spst if (**src == '.') { 17123229Spst if (pp < (parts + 4)) { 17133229Spst (*src)++; 17143229Spst goto loop; 17153229Spst } 17163229Spst return (-1); 17173229Spst } 17183229Spst#if 0 17193229Spst /* This is handled by the caller. */ 17203229Spst if (**src && !(isspace(**src) || (**src == ':'))) { 17213229Spst return (-1); 17223229Spst } 17233229Spst#endif 17243229Spst 17253229Spst /* 17263229Spst * Construct the address according to 17273229Spst * the number of parts specified. 17283229Spst */ 17293229Spst n = pp - parts; 17303229Spst switch (n) { 17313229Spst case 1: /* a -- 32 bits */ 17323229Spst value = parts[0]; 17333229Spst break; 17343229Spst case 2: /* a.b -- 8.24 bits */ 17353229Spst value = (parts[0] << 24) | (parts[1] & 0xFFFFFF); 17363229Spst break; 17373229Spst case 3: /* a.b.c -- 8.8.16 bits */ 17383229Spst value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 17393229Spst (parts[2] & 0xFFFF); 17403229Spst break; 17413229Spst case 4: /* a.b.c.d -- 8.8.8.8 bits */ 17423229Spst value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) | 17433229Spst ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF); 17443229Spst break; 17453229Spst default: 17463229Spst return (-1); 17473229Spst } 17483229Spst *result = htonl(value); 17493229Spst return (0); 17503229Spst} 17513229Spst 17523229Spst 17533229Spst 17543229Spst/* 17553229Spst * "src" points to a pointer which in turn points to a hexadecimal ASCII 17563229Spst * string. This string is interpreted as a hardware address and returned 17573229Spst * as a pointer to the actual hardware address, represented as an array of 17583229Spst * bytes. 17593229Spst * 17603229Spst * The ASCII string must have the proper number of digits for the specified 17613229Spst * hardware type (e.g. twelve digits for a 48-bit Ethernet address). 17623229Spst * Two-digit sequences (bytes) may be separated with periods (.) and/or 17633229Spst * prefixed with '0x' for readability, but this is not required. 17643229Spst * 17653229Spst * For bad addresses, the pointer which "src" points to is updated to point 17663229Spst * to the start of the first two-digit sequence which was bad, and the 17673229Spst * function returns a NULL pointer. 17683229Spst */ 17693229Spst 17703229SpstPRIVATE byte * 17713229Spstprs_haddr(src, htype) 17723229Spst char **src; 17733229Spst u_int htype; 17743229Spst{ 17753229Spst static byte haddr[MAXHADDRLEN]; 17763229Spst byte *hap; 17773229Spst char tmpstr[MAXSTRINGLEN]; 17783229Spst u_int tmplen; 17793229Spst unsigned hal; 17803229Spst char *p; 17813229Spst 17823229Spst hal = haddrlength(htype); /* Get length of this address type */ 17833229Spst if (hal <= 0) { 17843229Spst report(LOG_ERR, "Invalid addr type for HW addr parse"); 17853229Spst return NULL; 17863229Spst } 17873229Spst tmplen = sizeof(tmpstr); 17883229Spst get_string(src, tmpstr, &tmplen); 17893229Spst p = tmpstr; 17903229Spst 17913229Spst /* If it's a valid host name, try to lookup the HW address. */ 17923229Spst if (goodname(p)) { 17933229Spst /* Lookup Hardware Address for hostname. */ 17943229Spst if ((hap = lookup_hwa(p, htype)) != NULL) 17953229Spst return hap; /* success */ 17963229Spst report(LOG_ERR, "Add 0x prefix if hex value starts with A-F"); 17973229Spst /* OK, assume it must be numeric. */ 17983229Spst } 17993229Spst 18003229Spst hap = haddr; 18013229Spst while (hap < haddr + hal) { 180213572Spst if ((*p == '.') || (*p == ':')) 18033229Spst p++; 18043229Spst if (interp_byte(&p, hap++) < 0) { 18053229Spst return NULL; 18063229Spst } 18073229Spst } 18083229Spst return haddr; 18093229Spst} 18103229Spst 18113229Spst 18123229Spst 18133229Spst/* 18143229Spst * "src" is a pointer to a character pointer which in turn points to a 18153229Spst * hexadecimal ASCII representation of a byte. This byte is read, the 18163229Spst * character pointer is updated, and the result is deposited into the 18173229Spst * byte pointed to by "retbyte". 18183229Spst * 18193229Spst * The usual '0x' notation is allowed but not required. The number must be 18203229Spst * a two digit hexadecimal number. If the number is invalid, "src" and 18213229Spst * "retbyte" are left untouched and -1 is returned as the function value. 18223229Spst * Successful calls return 0. 18233229Spst */ 18243229Spst 18253229SpstPRIVATE int 18263229Spstinterp_byte(src, retbyte) 18273229Spst char **src; 18283229Spst byte *retbyte; 18293229Spst{ 18303229Spst int v; 18313229Spst 18323229Spst if ((*src)[0] == '0' && 18333229Spst ((*src)[1] == 'x' || 18343229Spst (*src)[1] == 'X')) { 18353229Spst (*src) += 2; /* allow 0x for hex, but don't require it */ 18363229Spst } 18373229Spst if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) { 18383229Spst return -1; 18393229Spst } 18403229Spst if (sscanf(*src, "%2x", &v) != 1) { 18413229Spst return -1; 18423229Spst } 18433229Spst (*src) += 2; 18443229Spst *retbyte = (byte) (v & 0xFF); 18453229Spst return 0; 18463229Spst} 18473229Spst 18483229Spst 18493229Spst 18503229Spst/* 18513229Spst * The parameter "src" points to a character pointer which points to an 18523229Spst * ASCII string representation of an unsigned number. The number is 18533229Spst * returned as an unsigned long and the character pointer is updated to 18543229Spst * point to the first illegal character. 18553229Spst */ 18563229Spst 18573229SpstPRIVATE u_int32 18583229Spstget_u_long(src) 18593229Spst char **src; 18603229Spst{ 18613229Spst register u_int32 value, base; 18623229Spst char c; 18633229Spst 18643229Spst /* 18653229Spst * Collect number up to first illegal character. Values are specified 18663229Spst * as for C: 0x=hex, 0=octal, other=decimal. 18673229Spst */ 18683229Spst value = 0; 18693229Spst base = 10; 18703229Spst if (**src == '0') { 18713229Spst base = 8; 18723229Spst (*src)++; 18733229Spst } 18743229Spst if (**src == 'x' || **src == 'X') { 18753229Spst base = 16; 18763229Spst (*src)++; 18773229Spst } 18783229Spst while ((c = **src)) { 18793229Spst if (isdigit(c)) { 18803229Spst value = (value * base) + (c - '0'); 18813229Spst (*src)++; 18823229Spst continue; 18833229Spst } 18843229Spst if (base == 16 && isxdigit(c)) { 18853229Spst value = (value << 4) + ((c & ~32) + 10 - 'A'); 18863229Spst (*src)++; 18873229Spst continue; 18883229Spst } 18893229Spst break; 18903229Spst } 18913229Spst return value; 18923229Spst} 18933229Spst 18943229Spst 18953229Spst 18963229Spst/* 18973229Spst * Routines for deletion of data associated with the main data structure. 18983229Spst */ 18993229Spst 19003229Spst 19013229Spst/* 19023229Spst * Frees the entire host data structure given. Does nothing if the passed 19033229Spst * pointer is NULL. 19043229Spst */ 19053229Spst 19063229SpstPRIVATE void 19073229Spstfree_host(hmp) 19083229Spst hash_datum *hmp; 19093229Spst{ 19103229Spst struct host *hostptr = (struct host *) hmp; 19113229Spst if (hostptr == NULL) 19123229Spst return; 19133229Spst assert(hostptr->linkcount > 0); 19143229Spst if (--(hostptr->linkcount)) 19153229Spst return; /* Still has references */ 19163229Spst del_iplist(hostptr->cookie_server); 19173229Spst del_iplist(hostptr->domain_server); 19183229Spst del_iplist(hostptr->gateway); 19193229Spst del_iplist(hostptr->impress_server); 19203229Spst del_iplist(hostptr->log_server); 19213229Spst del_iplist(hostptr->lpr_server); 19223229Spst del_iplist(hostptr->name_server); 19233229Spst del_iplist(hostptr->rlp_server); 19243229Spst del_iplist(hostptr->time_server); 19253229Spst del_iplist(hostptr->nis_server); 19263229Spst del_iplist(hostptr->ntp_server); 19273229Spst 19283229Spst /* 19293229Spst * XXX - Add new tags here 19303229Spst * (if the value is an IP list) 19313229Spst */ 19323229Spst 19333229Spst del_string(hostptr->hostname); 19343229Spst del_string(hostptr->homedir); 19353229Spst del_string(hostptr->bootfile); 19363229Spst del_string(hostptr->tftpdir); 19373229Spst del_string(hostptr->root_path); 19383229Spst del_string(hostptr->domain_name); 19393229Spst del_string(hostptr->dump_file); 19403229Spst del_string(hostptr->exten_file); 19413229Spst del_string(hostptr->nis_domain); 19423229Spst 19433229Spst#ifdef YORK_EX_OPTION 19443229Spst del_string(hostptr->exec_file); 19453229Spst#endif 19463229Spst 19473229Spst /* 19483229Spst * XXX - Add new tags here 19493229Spst * (if it is a shared string) 19503229Spst */ 19513229Spst 19523229Spst del_bindata(hostptr->generic); 19533229Spst free((char *) hostptr); 19543229Spst} 19553229Spst 19563229Spst 19573229Spst 19583229Spst/* 19593229Spst * Decrements the linkcount on the given IP address data structure. If the 19603229Spst * linkcount goes to zero, the memory associated with the data is freed. 19613229Spst */ 19623229Spst 19633229SpstPRIVATE void 19643229Spstdel_iplist(iplist) 19653229Spst struct in_addr_list *iplist; 19663229Spst{ 19673229Spst if (iplist) { 19683229Spst if (!(--(iplist->linkcount))) { 19693229Spst free((char *) iplist); 19703229Spst } 19713229Spst } 19723229Spst} 19733229Spst 19743229Spst 19753229Spst 19763229Spst/* 19773229Spst * Decrements the linkcount on a string data structure. If the count 19783229Spst * goes to zero, the memory associated with the string is freed. Does 19793229Spst * nothing if the passed pointer is NULL. 19803229Spst */ 19813229Spst 19823229SpstPRIVATE void 19833229Spstdel_string(stringptr) 19843229Spst struct shared_string *stringptr; 19853229Spst{ 19863229Spst if (stringptr) { 19873229Spst if (!(--(stringptr->linkcount))) { 19883229Spst free((char *) stringptr); 19893229Spst } 19903229Spst } 19913229Spst} 19923229Spst 19933229Spst 19943229Spst 19953229Spst/* 19963229Spst * Decrements the linkcount on a shared_bindata data structure. If the 19973229Spst * count goes to zero, the memory associated with the data is freed. Does 19983229Spst * nothing if the passed pointer is NULL. 19993229Spst */ 20003229Spst 20013229SpstPRIVATE void 20023229Spstdel_bindata(dataptr) 20033229Spst struct shared_bindata *dataptr; 20043229Spst{ 20053229Spst if (dataptr) { 20063229Spst if (!(--(dataptr->linkcount))) { 20073229Spst free((char *) dataptr); 20083229Spst } 20093229Spst } 20103229Spst} 20113229Spst 20123229Spst 20133229Spst 20143229Spst 20153229Spst/* smalloc() -- safe malloc() 20163229Spst * 20173229Spst * Always returns a valid pointer (if it returns at all). The allocated 20183229Spst * memory is initialized to all zeros. If malloc() returns an error, a 20193229Spst * message is printed using the report() function and the program aborts 20203229Spst * with a status of 1. 20213229Spst */ 20223229Spst 20233229SpstPRIVATE char * 20243229Spstsmalloc(nbytes) 20253229Spst unsigned nbytes; 20263229Spst{ 20273229Spst char *retvalue; 20283229Spst 20293229Spst retvalue = malloc(nbytes); 20303229Spst if (!retvalue) { 20313229Spst report(LOG_ERR, "malloc() failure -- exiting"); 20323229Spst exit(1); 20333229Spst } 20343229Spst bzero(retvalue, nbytes); 20353229Spst return retvalue; 20363229Spst} 20373229Spst 20383229Spst 20393229Spst/* 20403229Spst * Compare function to determine whether two hardware addresses are 20413229Spst * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE 20423229Spst * otherwise. 20433229Spst * 20443229Spst * This function is used when retrieving elements from the hardware address 20453229Spst * hash table. 20463229Spst */ 20473229Spst 20483229Spstboolean 20493229Spsthwlookcmp(d1, d2) 20503229Spst hash_datum *d1, *d2; 20513229Spst{ 20523229Spst struct host *host1 = (struct host *) d1; 20533229Spst struct host *host2 = (struct host *) d2; 20543229Spst 20553229Spst if (host1->htype != host2->htype) { 20563229Spst return FALSE; 20573229Spst } 20583229Spst if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) { 20593229Spst return FALSE; 20603229Spst } 20613229Spst return TRUE; 20623229Spst} 20633229Spst 20643229Spst 20653229Spst/* 20663229Spst * Compare function for doing IP address hash table lookup. 20673229Spst */ 20683229Spst 20693229Spstboolean 20703229Spstiplookcmp(d1, d2) 20713229Spst hash_datum *d1, *d2; 20723229Spst{ 20733229Spst struct host *host1 = (struct host *) d1; 20743229Spst struct host *host2 = (struct host *) d2; 20753229Spst 20763229Spst return (host1->iaddr.s_addr == host2->iaddr.s_addr); 20773229Spst} 20783229Spst 20793229Spst/* 20803229Spst * Local Variables: 20813229Spst * tab-width: 4 20823229Spst * c-indent-level: 4 20833229Spst * c-argdecl-indent: 4 20843229Spst * c-continued-statement-offset: 4 20853229Spst * c-continued-brace-offset: -4 20863229Spst * c-label-offset: -4 20873229Spst * c-brace-offset: 0 20883229Spst * End: 20893229Spst */ 2090