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 * bootpef - BOOTP Extension File generator 283229Spst * Makes an "Extension File" for each host entry that 293229Spst * defines an and Extension File. (See RFC1497, tag 18.) 303229Spst * 313229Spst * HISTORY 323229Spst * See ./Changes 333229Spst * 343229Spst * BUGS 353229Spst * See ./ToDo 363229Spst */ 373229Spst 383229Spst 393229Spst 403229Spst#include <stdarg.h> 413229Spst 423229Spst#include <sys/types.h> 433229Spst#include <sys/time.h> 443229Spst 453229Spst#include <netinet/in.h> 463229Spst#include <arpa/inet.h> /* inet_ntoa */ 473229Spst 483229Spst#ifndef NO_UNISTD 493229Spst#include <unistd.h> 503229Spst#endif 513229Spst#include <stdlib.h> 523229Spst#include <stdio.h> 533229Spst#include <string.h> 543229Spst#include <errno.h> 553229Spst#include <ctype.h> 563229Spst#include <syslog.h> 573229Spst 583229Spst#ifndef USE_BFUNCS 593229Spst#include <memory.h> 603229Spst/* Yes, memcpy is OK here (no overlapped copies). */ 613229Spst#define bcopy(a,b,c) memcpy(b,a,c) 623229Spst#define bzero(p,l) memset(p,0,l) 633229Spst#define bcmp(a,b,c) memcmp(a,b,c) 643229Spst#endif 653229Spst 663229Spst#include "bootp.h" 673229Spst#include "hash.h" 683229Spst#include "hwaddr.h" 693229Spst#include "bootpd.h" 703229Spst#include "dovend.h" 713229Spst#include "readfile.h" 723229Spst#include "report.h" 733229Spst#include "tzone.h" 743229Spst#include "patchlevel.h" 753229Spst 763229Spst#define BUFFERSIZE 0x4000 773229Spst 783229Spst#ifndef CONFIG_FILE 793229Spst#define CONFIG_FILE "/etc/bootptab" 803229Spst#endif 813229Spst 823229Spst 833229Spst 843229Spst/* 853229Spst * Externals, forward declarations, and global variables 863229Spst */ 873229Spst 8897419Salfredstatic void mktagfile(struct host *); 8997419Salfredstatic void usage(void); 903229Spst 913229Spst/* 923229Spst * General 933229Spst */ 943229Spst 953229Spstchar *progname; 963229Spstchar *chdir_path; 973229Spstint debug = 0; /* Debugging flag (level) */ 983229Spstbyte *buffer; 993229Spst 1003229Spst/* 1013229Spst * Globals below are associated with the bootp database file (bootptab). 1023229Spst */ 1033229Spst 1043229Spstchar *bootptab = CONFIG_FILE; 1053229Spst 1063229Spst 1073229Spst/* 1083229Spst * Print "usage" message and exit 1093229Spst */ 1103229Spststatic void 1113229Spstusage() 1123229Spst{ 1133229Spst fprintf(stderr, 1143229Spst "usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n"); 1153229Spst fprintf(stderr, "\t -c n\tset current directory\n"); 1163229Spst fprintf(stderr, "\t -d n\tset debug level\n"); 1173229Spst fprintf(stderr, "\t -f n\tconfig file name\n"); 1183229Spst exit(1); 1193229Spst} 1203229Spst 1213229Spst 1223229Spst/* 1233229Spst * Initialization such as command-line processing is done and then the 1243229Spst * main server loop is started. 1253229Spst */ 12646078Simpint 1273229Spstmain(argc, argv) 1283229Spst int argc; 1293229Spst char **argv; 1303229Spst{ 1313229Spst struct host *hp; 1323229Spst char *stmp; 1333229Spst int n; 1343229Spst 1353229Spst progname = strrchr(argv[0], '/'); 1363229Spst if (progname) progname++; 1373229Spst else progname = argv[0]; 1383229Spst 1393229Spst /* Get work space for making tag 18 files. */ 1403229Spst buffer = (byte *) malloc(BUFFERSIZE); 1413229Spst if (!buffer) { 1423229Spst report(LOG_ERR, "malloc failed"); 1433229Spst exit(1); 1443229Spst } 1453229Spst /* 1463229Spst * Set defaults that might be changed by option switches. 1473229Spst */ 1483229Spst stmp = NULL; 1493229Spst 1503229Spst /* 1513229Spst * Read switches. 1523229Spst */ 1533229Spst for (argc--, argv++; argc > 0; argc--, argv++) { 1543229Spst if (argv[0][0] != '-') 1553229Spst break; 1563229Spst switch (argv[0][1]) { 1573229Spst 1583229Spst case 'c': /* chdir_path */ 1593229Spst if (argv[0][2]) { 1603229Spst stmp = &(argv[0][2]); 1613229Spst } else { 1623229Spst argc--; 1633229Spst argv++; 1643229Spst stmp = argv[0]; 1653229Spst } 1663229Spst if (!stmp || (stmp[0] != '/')) { 1673229Spst fprintf(stderr, 1683229Spst "bootpd: invalid chdir specification\n"); 1693229Spst break; 1703229Spst } 1713229Spst chdir_path = stmp; 1723229Spst break; 1733229Spst 1743229Spst case 'd': /* debug */ 1753229Spst if (argv[0][2]) { 1763229Spst stmp = &(argv[0][2]); 1773229Spst } else if (argv[1] && argv[1][0] == '-') { 1783229Spst /* 1793229Spst * Backwards-compatible behavior: 1803229Spst * no parameter, so just increment the debug flag. 1813229Spst */ 1823229Spst debug++; 1833229Spst break; 1843229Spst } else { 1853229Spst argc--; 1863229Spst argv++; 1873229Spst stmp = argv[0]; 1883229Spst } 1893229Spst if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 1903229Spst fprintf(stderr, 1913229Spst "bootpd: invalid debug level\n"); 1923229Spst break; 1933229Spst } 1943229Spst debug = n; 1953229Spst break; 1963229Spst 1973229Spst case 'f': /* config file */ 1983229Spst if (argv[0][2]) { 1993229Spst stmp = &(argv[0][2]); 2003229Spst } else { 2013229Spst argc--; 2023229Spst argv++; 2033229Spst stmp = argv[0]; 2043229Spst } 2053229Spst bootptab = stmp; 2063229Spst break; 2073229Spst 2083229Spst default: 2093229Spst fprintf(stderr, "bootpd: unknown switch: -%c\n", 2103229Spst argv[0][1]); 2113229Spst usage(); 2123229Spst break; 2133229Spst } 2143229Spst } 2153229Spst 2163229Spst /* Get the timezone. */ 2173229Spst tzone_init(); 2183229Spst 2193229Spst /* Allocate hash tables. */ 2203229Spst rdtab_init(); 2213229Spst 2223229Spst /* 2233229Spst * Read the bootptab file. 2243229Spst */ 2253229Spst readtab(1); /* force read */ 2263229Spst 2273229Spst /* Set the cwd (i.e. to /tftpboot) */ 2283229Spst if (chdir_path) { 2293229Spst if (chdir(chdir_path) < 0) 2303229Spst report(LOG_ERR, "%s: chdir failed", chdir_path); 2313229Spst } 2323229Spst /* If there are host names on the command line, do only those. */ 2333229Spst if (argc > 0) { 2343229Spst unsigned int tlen, hashcode; 2353229Spst 2363229Spst while (argc) { 2373229Spst tlen = strlen(argv[0]); 2383229Spst hashcode = hash_HashFunction((u_char *)argv[0], tlen); 2393229Spst hp = (struct host *) hash_Lookup(nmhashtable, 2403229Spst hashcode, 2413229Spst nmcmp, argv[0]); 2423229Spst if (!hp) { 2433229Spst printf("%s: no matching entry\n", argv[0]); 2443229Spst exit(1); 2453229Spst } 2463229Spst if (!hp->flags.exten_file) { 2473229Spst printf("%s: no extension file\n", argv[0]); 2483229Spst exit(1); 2493229Spst } 2503229Spst mktagfile(hp); 2513229Spst argv++; 2523229Spst argc--; 2533229Spst } 2543229Spst exit(0); 2553229Spst } 2563229Spst /* No host names specified. Do them all. */ 2573229Spst hp = (struct host *) hash_FirstEntry(nmhashtable); 2583229Spst while (hp != NULL) { 2593229Spst mktagfile(hp); 2603229Spst hp = (struct host *) hash_NextEntry(nmhashtable); 2613229Spst } 26246078Simp return (0); 2633229Spst} 2643229Spst 2653229Spst 2663229Spst 2673229Spst/* 2683229Spst * Make a "TAG 18" file for this host. 2693229Spst * (Insert the RFC1497 options.) 2703229Spst */ 2713229Spst 2723229Spststatic void 2733229Spstmktagfile(hp) 2743229Spst struct host *hp; 2753229Spst{ 2763229Spst FILE *fp; 2773229Spst int bytesleft, len; 2783229Spst byte *vp; 2793229Spst 2803229Spst if (!hp->flags.exten_file) 2813229Spst return; 2823229Spst 2833229Spst vp = buffer; 2843229Spst bytesleft = BUFFERSIZE; 2853229Spst bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */ 2863229Spst vp += 4; 2873229Spst bytesleft -= 4; 2883229Spst 2893229Spst /* 2903229Spst * The "extension file" options are appended by the following 2913229Spst * function (which is shared with bootpd.c). 2923229Spst */ 2933229Spst len = dovend_rfc1497(hp, vp, bytesleft); 2943229Spst vp += len; 2953229Spst bytesleft -= len; 2963229Spst 2973229Spst if (bytesleft < 1) { 2983229Spst report(LOG_ERR, "%s: too much option data", 2993229Spst hp->exten_file->string); 3003229Spst return; 3013229Spst } 3023229Spst *vp++ = TAG_END; 3033229Spst bytesleft--; 3043229Spst 3053229Spst /* Write the buffer to the extension file. */ 3063229Spst printf("Updating \"%s\"\n", hp->exten_file->string); 3073229Spst if ((fp = fopen(hp->exten_file->string, "w")) == NULL) { 3083229Spst report(LOG_ERR, "error opening \"%s\": %s", 3093229Spst hp->exten_file->string, get_errmsg()); 3103229Spst return; 3113229Spst } 3123229Spst len = vp - buffer; 3133229Spst if (len != fwrite(buffer, 1, len, fp)) { 3143229Spst report(LOG_ERR, "write failed on \"%s\" : %s", 3153229Spst hp->exten_file->string, get_errmsg()); 3163229Spst } 3173229Spst fclose(fp); 3183229Spst 31913572Spst} /* mktagfile */ 3203229Spst 3213229Spst/* 3223229Spst * Local Variables: 3233229Spst * tab-width: 4 3243229Spst * c-indent-level: 4 3253229Spst * c-argdecl-indent: 4 3263229Spst * c-continued-statement-offset: 4 3273229Spst * c-continued-brace-offset: -4 3283229Spst * c-label-offset: -4 3293229Spst * c-brace-offset: 0 3303229Spst * End: 3313229Spst */ 332