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