xref: /netbsd-src/usr.sbin/bootp/bootpef/bootpef.c (revision f7a3540ecf73535f4217ff5a1ae640ad21e02832)
15e9d01f2Sgwr /************************************************************************
25e9d01f2Sgwr           Copyright 1988, 1991 by Carnegie Mellon University
35e9d01f2Sgwr 
45e9d01f2Sgwr                           All Rights Reserved
55e9d01f2Sgwr 
65e9d01f2Sgwr Permission to use, copy, modify, and distribute this software and its
75e9d01f2Sgwr documentation for any purpose and without fee is hereby granted, provided
85e9d01f2Sgwr that the above copyright notice appear in all copies and that both that
95e9d01f2Sgwr copyright notice and this permission notice appear in supporting
105e9d01f2Sgwr documentation, and that the name of Carnegie Mellon University not be used
115e9d01f2Sgwr in advertising or publicity pertaining to distribution of the software
125e9d01f2Sgwr without specific, written prior permission.
135e9d01f2Sgwr 
145e9d01f2Sgwr CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
155e9d01f2Sgwr SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
165e9d01f2Sgwr IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
175e9d01f2Sgwr DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
185e9d01f2Sgwr PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
195e9d01f2Sgwr ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
205e9d01f2Sgwr SOFTWARE.
215e9d01f2Sgwr ************************************************************************/
225e9d01f2Sgwr 
239493bb79Slukem #include <sys/cdefs.h>
245e9d01f2Sgwr #ifndef lint
25*f7a3540eSsevan __RCSID("$NetBSD: bootpef.c,v 1.11 2017/05/04 16:26:09 sevan Exp $");
265e9d01f2Sgwr #endif
275e9d01f2Sgwr 
285e9d01f2Sgwr 
295e9d01f2Sgwr /*
305e9d01f2Sgwr  * bootpef - BOOTP Extension File generator
315e9d01f2Sgwr  *	Makes an "Extension File" for each host entry that
325e9d01f2Sgwr  *	defines an and Extension File. (See RFC1497, tag 18.)
335e9d01f2Sgwr  *
345e9d01f2Sgwr  * HISTORY
355e9d01f2Sgwr  *	See ./Changes
365e9d01f2Sgwr  *
375e9d01f2Sgwr  * BUGS
385e9d01f2Sgwr  *	See ./ToDo
395e9d01f2Sgwr  */
405e9d01f2Sgwr 
415e9d01f2Sgwr 
425e9d01f2Sgwr 
435e9d01f2Sgwr #include <stdarg.h>
445e9d01f2Sgwr 
455e9d01f2Sgwr #include <sys/types.h>
465e9d01f2Sgwr #include <sys/time.h>
475e9d01f2Sgwr 
485e9d01f2Sgwr #include <netinet/in.h>
495e9d01f2Sgwr #include <arpa/inet.h>			/* inet_ntoa */
505e9d01f2Sgwr 
515e9d01f2Sgwr #ifndef	NO_UNISTD
525e9d01f2Sgwr #include <unistd.h>
535e9d01f2Sgwr #endif
545e9d01f2Sgwr #include <stdlib.h>
555e9d01f2Sgwr #include <stdio.h>
565e9d01f2Sgwr #include <string.h>
57be45f4d0Stls #include <strings.h>
585e9d01f2Sgwr #include <errno.h>
595e9d01f2Sgwr #include <ctype.h>
605e9d01f2Sgwr #include <syslog.h>
615e9d01f2Sgwr 
625e9d01f2Sgwr #include "bootp.h"
635e9d01f2Sgwr #include "hash.h"
645e9d01f2Sgwr #include "hwaddr.h"
655e9d01f2Sgwr #include "bootpd.h"
665e9d01f2Sgwr #include "dovend.h"
675e9d01f2Sgwr #include "readfile.h"
685e9d01f2Sgwr #include "report.h"
695e9d01f2Sgwr #include "tzone.h"
705e9d01f2Sgwr #include "patchlevel.h"
715e9d01f2Sgwr 
725e9d01f2Sgwr #define	BUFFERSIZE   		0x4000
735e9d01f2Sgwr 
745e9d01f2Sgwr #ifndef CONFIG_FILE
755e9d01f2Sgwr #define CONFIG_FILE		"/etc/bootptab"
765e9d01f2Sgwr #endif
775e9d01f2Sgwr 
785e9d01f2Sgwr 
795e9d01f2Sgwr 
805e9d01f2Sgwr /*
815e9d01f2Sgwr  * Externals, forward declarations, and global variables
825e9d01f2Sgwr  */
835e9d01f2Sgwr 
84131109e4Swiz static void mktagfile(struct host *);
85dccf569eSjoerg __dead static void usage(void);
865e9d01f2Sgwr 
875e9d01f2Sgwr 
885e9d01f2Sgwr /*
895e9d01f2Sgwr  * General
905e9d01f2Sgwr  */
915e9d01f2Sgwr 
92c8f61d2bSxtraeme const char *progname;
935e9d01f2Sgwr char *chdir_path;
945e9d01f2Sgwr int debug = 0;					/* Debugging flag (level) */
955e9d01f2Sgwr byte *buffer;
965e9d01f2Sgwr 
975e9d01f2Sgwr /*
985e9d01f2Sgwr  * Globals below are associated with the bootp database file (bootptab).
995e9d01f2Sgwr  */
1005e9d01f2Sgwr 
101c8f61d2bSxtraeme const char *bootptab = CONFIG_FILE;
1025e9d01f2Sgwr 
1035e9d01f2Sgwr 
1045e9d01f2Sgwr /*
1055e9d01f2Sgwr  * Print "usage" message and exit
1065e9d01f2Sgwr  */
1075e9d01f2Sgwr static void
usage(void)108131109e4Swiz usage(void)
1095e9d01f2Sgwr {
1105e9d01f2Sgwr 	fprintf(stderr,
11175febfe0Shira 	    "usage: %s [-c chdir] [-d level] [-f configfile] [host ...]\n",
11275febfe0Shira 	    getprogname());
1135e9d01f2Sgwr 	fprintf(stderr, "\t -c n\tset current directory\n");
1145e9d01f2Sgwr 	fprintf(stderr, "\t -d n\tset debug level\n");
1155e9d01f2Sgwr 	fprintf(stderr, "\t -f n\tconfig file name\n");
1165e9d01f2Sgwr 	exit(1);
1175e9d01f2Sgwr }
1185e9d01f2Sgwr 
1195e9d01f2Sgwr 
1205e9d01f2Sgwr /*
1215e9d01f2Sgwr  * Initialization such as command-line processing is done and then the
1225e9d01f2Sgwr  * main server loop is started.
1235e9d01f2Sgwr  */
1249493bb79Slukem int
main(int argc,char ** argv)125131109e4Swiz main(int argc, char **argv)
1265e9d01f2Sgwr {
1275e9d01f2Sgwr 	struct host *hp;
1285e9d01f2Sgwr 	char *stmp;
1295e9d01f2Sgwr 	int n;
1305e9d01f2Sgwr 
1315e9d01f2Sgwr 	progname = strrchr(argv[0], '/');
1325e9d01f2Sgwr 	if (progname) progname++;
1335e9d01f2Sgwr 	else progname = argv[0];
1345e9d01f2Sgwr 
1355e9d01f2Sgwr 	/* Get work space for making tag 18 files. */
1365e9d01f2Sgwr 	buffer = (byte *) malloc(BUFFERSIZE);
1375e9d01f2Sgwr 	if (!buffer) {
1385e9d01f2Sgwr 		report(LOG_ERR, "malloc failed");
1395e9d01f2Sgwr 		exit(1);
1405e9d01f2Sgwr 	}
1415e9d01f2Sgwr 	/*
1425e9d01f2Sgwr 	 * Set defaults that might be changed by option switches.
1435e9d01f2Sgwr 	 */
1445e9d01f2Sgwr 	stmp = NULL;
1455e9d01f2Sgwr 
1465e9d01f2Sgwr 	/*
1475e9d01f2Sgwr 	 * Read switches.
1485e9d01f2Sgwr 	 */
1495e9d01f2Sgwr 	for (argc--, argv++; argc > 0; argc--, argv++) {
1505e9d01f2Sgwr 		if (argv[0][0] != '-')
1515e9d01f2Sgwr 			break;
1525e9d01f2Sgwr 		switch (argv[0][1]) {
1535e9d01f2Sgwr 
1545e9d01f2Sgwr 		case 'c':				/* chdir_path */
1555e9d01f2Sgwr 			if (argv[0][2]) {
1565e9d01f2Sgwr 				stmp = &(argv[0][2]);
1575e9d01f2Sgwr 			} else {
1585e9d01f2Sgwr 				argc--;
1595e9d01f2Sgwr 				argv++;
1605e9d01f2Sgwr 				stmp = argv[0];
1615e9d01f2Sgwr 			}
1625e9d01f2Sgwr 			if (!stmp || (stmp[0] != '/')) {
1635e9d01f2Sgwr 				fprintf(stderr,
1645e9d01f2Sgwr 						"bootpd: invalid chdir specification\n");
1655e9d01f2Sgwr 				break;
1665e9d01f2Sgwr 			}
1675e9d01f2Sgwr 			chdir_path = stmp;
1685e9d01f2Sgwr 			break;
1695e9d01f2Sgwr 
1705e9d01f2Sgwr 		case 'd':				/* debug */
1715e9d01f2Sgwr 			if (argv[0][2]) {
1725e9d01f2Sgwr 				stmp = &(argv[0][2]);
1735e9d01f2Sgwr 			} else if (argv[1] && argv[1][0] == '-') {
1745e9d01f2Sgwr 				/*
1755e9d01f2Sgwr 				 * Backwards-compatible behavior:
1765e9d01f2Sgwr 				 * no parameter, so just increment the debug flag.
1775e9d01f2Sgwr 				 */
1785e9d01f2Sgwr 				debug++;
1795e9d01f2Sgwr 				break;
1805e9d01f2Sgwr 			} else {
1815e9d01f2Sgwr 				argc--;
1825e9d01f2Sgwr 				argv++;
1835e9d01f2Sgwr 				stmp = argv[0];
1845e9d01f2Sgwr 			}
1855e9d01f2Sgwr 			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
1865e9d01f2Sgwr 				fprintf(stderr,
1875e9d01f2Sgwr 						"bootpd: invalid debug level\n");
1885e9d01f2Sgwr 				break;
1895e9d01f2Sgwr 			}
1905e9d01f2Sgwr 			debug = n;
1915e9d01f2Sgwr 			break;
1925e9d01f2Sgwr 
1935e9d01f2Sgwr 		case 'f':				/* config file */
1945e9d01f2Sgwr 			if (argv[0][2]) {
1955e9d01f2Sgwr 				stmp = &(argv[0][2]);
1965e9d01f2Sgwr 			} else {
1975e9d01f2Sgwr 				argc--;
1985e9d01f2Sgwr 				argv++;
1995e9d01f2Sgwr 				stmp = argv[0];
2005e9d01f2Sgwr 			}
2015e9d01f2Sgwr 			bootptab = stmp;
2025e9d01f2Sgwr 			break;
2035e9d01f2Sgwr 
2045e9d01f2Sgwr 		default:
2055e9d01f2Sgwr 			fprintf(stderr, "bootpd: unknown switch: -%c\n",
2065e9d01f2Sgwr 					argv[0][1]);
2075e9d01f2Sgwr 			usage();
2085e9d01f2Sgwr 			break;
2095e9d01f2Sgwr 		}
2105e9d01f2Sgwr 	}
2115e9d01f2Sgwr 
2125e9d01f2Sgwr 	/* Get the timezone. */
2135e9d01f2Sgwr 	tzone_init();
2145e9d01f2Sgwr 
2155e9d01f2Sgwr 	/* Allocate hash tables. */
2165e9d01f2Sgwr 	rdtab_init();
2175e9d01f2Sgwr 
2185e9d01f2Sgwr 	/*
2195e9d01f2Sgwr 	 * Read the bootptab file.
2205e9d01f2Sgwr 	 */
2215e9d01f2Sgwr 	readtab(1);					/* force read */
2225e9d01f2Sgwr 
2235e9d01f2Sgwr 	/* Set the cwd (i.e. to /tftpboot) */
2245e9d01f2Sgwr 	if (chdir_path) {
2255e9d01f2Sgwr 		if (chdir(chdir_path) < 0)
2265e9d01f2Sgwr 			report(LOG_ERR, "%s: chdir failed", chdir_path);
2275e9d01f2Sgwr 	}
2285e9d01f2Sgwr 	/* If there are host names on the command line, do only those. */
2295e9d01f2Sgwr 	if (argc > 0) {
2305e9d01f2Sgwr 		unsigned int tlen, hashcode;
2315e9d01f2Sgwr 
2325e9d01f2Sgwr 		while (argc) {
2335e9d01f2Sgwr 			tlen = strlen(argv[0]);
2345e9d01f2Sgwr 			hashcode = hash_HashFunction((u_char *)argv[0], tlen);
2355e9d01f2Sgwr 			hp = (struct host *) hash_Lookup(nmhashtable,
2365e9d01f2Sgwr 											 hashcode,
2375e9d01f2Sgwr 											 nmcmp, argv[0]);
2385e9d01f2Sgwr 			if (!hp) {
2395e9d01f2Sgwr 				printf("%s: no matching entry\n", argv[0]);
2405e9d01f2Sgwr 				exit(1);
2415e9d01f2Sgwr 			}
2425e9d01f2Sgwr 			if (!hp->flags.exten_file) {
2435e9d01f2Sgwr 				printf("%s: no extension file\n", argv[0]);
2445e9d01f2Sgwr 				exit(1);
2455e9d01f2Sgwr 			}
2465e9d01f2Sgwr 			mktagfile(hp);
2475e9d01f2Sgwr 			argv++;
2485e9d01f2Sgwr 			argc--;
2495e9d01f2Sgwr 		}
2505e9d01f2Sgwr 		exit(0);
2515e9d01f2Sgwr 	}
2525e9d01f2Sgwr 	/* No host names specified.  Do them all. */
2535e9d01f2Sgwr 	hp = (struct host *) hash_FirstEntry(nmhashtable);
2545e9d01f2Sgwr 	while (hp != NULL) {
2555e9d01f2Sgwr 		mktagfile(hp);
2565e9d01f2Sgwr 		hp = (struct host *) hash_NextEntry(nmhashtable);
2575e9d01f2Sgwr 	}
2589493bb79Slukem 	exit(0);
2595e9d01f2Sgwr }
2605e9d01f2Sgwr 
2615e9d01f2Sgwr 
2625e9d01f2Sgwr 
2635e9d01f2Sgwr /*
2645e9d01f2Sgwr  * Make a "TAG 18" file for this host.
2655e9d01f2Sgwr  * (Insert the RFC1497 options.)
2665e9d01f2Sgwr  */
2675e9d01f2Sgwr 
2685e9d01f2Sgwr static void
mktagfile(struct host * hp)269131109e4Swiz mktagfile(struct host *hp)
2705e9d01f2Sgwr {
2715e9d01f2Sgwr 	FILE *fp;
2725e9d01f2Sgwr 	int bytesleft, len;
2735e9d01f2Sgwr 	byte *vp;
2745e9d01f2Sgwr 
2755e9d01f2Sgwr 	if (!hp->flags.exten_file)
2765e9d01f2Sgwr 		return;
2775e9d01f2Sgwr 
2785e9d01f2Sgwr 	vp = buffer;
2795e9d01f2Sgwr 	bytesleft = BUFFERSIZE;
2805e9d01f2Sgwr 	bcopy(vm_rfc1048, vp, 4);	/* Copy in the magic cookie */
2815e9d01f2Sgwr 	vp += 4;
2825e9d01f2Sgwr 	bytesleft -= 4;
2835e9d01f2Sgwr 
2845e9d01f2Sgwr 	/*
2855e9d01f2Sgwr 	 * The "extension file" options are appended by the following
2865e9d01f2Sgwr 	 * function (which is shared with bootpd.c).
2875e9d01f2Sgwr 	 */
2885e9d01f2Sgwr 	len = dovend_rfc1497(hp, vp, bytesleft);
2895e9d01f2Sgwr 	vp += len;
2905e9d01f2Sgwr 	bytesleft -= len;
2915e9d01f2Sgwr 
2925e9d01f2Sgwr 	if (bytesleft < 1) {
2935e9d01f2Sgwr 		report(LOG_ERR, "%s: too much option data",
2945e9d01f2Sgwr 			   hp->exten_file->string);
2955e9d01f2Sgwr 		return;
2965e9d01f2Sgwr 	}
2975e9d01f2Sgwr 	*vp++ = TAG_END;
2985e9d01f2Sgwr 	bytesleft--;
2995e9d01f2Sgwr 
3005e9d01f2Sgwr 	/* Write the buffer to the extension file. */
3015e9d01f2Sgwr 	printf("Updating \"%s\"\n", hp->exten_file->string);
3025e9d01f2Sgwr 	if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
3035e9d01f2Sgwr 		report(LOG_ERR, "error opening \"%s\": %s",
3045e9d01f2Sgwr 			   hp->exten_file->string, get_errmsg());
3055e9d01f2Sgwr 		return;
3065e9d01f2Sgwr 	}
3075e9d01f2Sgwr 	len = vp - buffer;
3087affd655Slukem 	if ((size_t)len != fwrite(buffer, 1, len, fp)) {
3095e9d01f2Sgwr 		report(LOG_ERR, "write failed on \"%s\" : %s",
3105e9d01f2Sgwr 			   hp->exten_file->string, get_errmsg());
3115e9d01f2Sgwr 	}
3125e9d01f2Sgwr 	fclose(fp);
3135e9d01f2Sgwr 
3149493bb79Slukem } /* mktagfile */
3155e9d01f2Sgwr 
3165e9d01f2Sgwr /*
3175e9d01f2Sgwr  * Local Variables:
3185e9d01f2Sgwr  * tab-width: 4
3195e9d01f2Sgwr  * c-indent-level: 4
3205e9d01f2Sgwr  * c-argdecl-indent: 4
3215e9d01f2Sgwr  * c-continued-statement-offset: 4
3225e9d01f2Sgwr  * c-continued-brace-offset: -4
3235e9d01f2Sgwr  * c-label-offset: -4
3245e9d01f2Sgwr  * c-brace-offset: 0
3255e9d01f2Sgwr  * End:
3265e9d01f2Sgwr  */
327