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