xref: /freebsd/libexec/bootpd/tools/bootpef/bootpef.c (revision e08ac58bbe2be2817736b8f4b32c75f8d55359df)
144099b7bSPaul Traina /************************************************************************
244099b7bSPaul Traina           Copyright 1988, 1991 by Carnegie Mellon University
344099b7bSPaul Traina 
444099b7bSPaul Traina                           All Rights Reserved
544099b7bSPaul Traina 
644099b7bSPaul Traina Permission to use, copy, modify, and distribute this software and its
744099b7bSPaul Traina documentation for any purpose and without fee is hereby granted, provided
844099b7bSPaul Traina that the above copyright notice appear in all copies and that both that
944099b7bSPaul Traina copyright notice and this permission notice appear in supporting
1044099b7bSPaul Traina documentation, and that the name of Carnegie Mellon University not be used
1144099b7bSPaul Traina in advertising or publicity pertaining to distribution of the software
1244099b7bSPaul Traina without specific, written prior permission.
1344099b7bSPaul Traina 
1444099b7bSPaul Traina CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1544099b7bSPaul Traina SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1644099b7bSPaul Traina IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
1744099b7bSPaul Traina DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1844099b7bSPaul Traina PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1944099b7bSPaul Traina ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2044099b7bSPaul Traina SOFTWARE.
2144099b7bSPaul Traina ************************************************************************/
2244099b7bSPaul Traina 
2344099b7bSPaul Traina /*
2444099b7bSPaul Traina  * bootpef - BOOTP Extension File generator
2544099b7bSPaul Traina  *	Makes an "Extension File" for each host entry that
2644099b7bSPaul Traina  *	defines an and Extension File. (See RFC1497, tag 18.)
2744099b7bSPaul Traina  *
2844099b7bSPaul Traina  * HISTORY
2944099b7bSPaul Traina  *	See ./Changes
3044099b7bSPaul Traina  *
3144099b7bSPaul Traina  * BUGS
3244099b7bSPaul Traina  *	See ./ToDo
3344099b7bSPaul Traina  */
3444099b7bSPaul Traina 
3544099b7bSPaul Traina 
3644099b7bSPaul Traina 
3744099b7bSPaul Traina #ifdef	__STDC__
3844099b7bSPaul Traina #include <stdarg.h>
3944099b7bSPaul Traina #else
4044099b7bSPaul Traina #include <varargs.h>
4144099b7bSPaul Traina #endif
4244099b7bSPaul Traina 
4344099b7bSPaul Traina #include <sys/types.h>
4444099b7bSPaul Traina #include <sys/time.h>
4544099b7bSPaul Traina 
4644099b7bSPaul Traina #include <netinet/in.h>
4744099b7bSPaul Traina #include <arpa/inet.h>			/* inet_ntoa */
4844099b7bSPaul Traina 
4944099b7bSPaul Traina #ifndef	NO_UNISTD
5044099b7bSPaul Traina #include <unistd.h>
5144099b7bSPaul Traina #endif
5244099b7bSPaul Traina #include <stdlib.h>
5344099b7bSPaul Traina #include <stdio.h>
5444099b7bSPaul Traina #include <string.h>
5544099b7bSPaul Traina #include <errno.h>
5644099b7bSPaul Traina #include <ctype.h>
5744099b7bSPaul Traina #include <syslog.h>
5844099b7bSPaul Traina 
5944099b7bSPaul Traina #ifndef	USE_BFUNCS
6044099b7bSPaul Traina #include <memory.h>
6144099b7bSPaul Traina /* Yes, memcpy is OK here (no overlapped copies). */
6244099b7bSPaul Traina #define bcopy(a,b,c)    memcpy(b,a,c)
6344099b7bSPaul Traina #define bzero(p,l)      memset(p,0,l)
6444099b7bSPaul Traina #define bcmp(a,b,c)     memcmp(a,b,c)
6544099b7bSPaul Traina #endif
6644099b7bSPaul Traina 
6744099b7bSPaul Traina #include "bootp.h"
6844099b7bSPaul Traina #include "hash.h"
6944099b7bSPaul Traina #include "hwaddr.h"
7044099b7bSPaul Traina #include "bootpd.h"
7144099b7bSPaul Traina #include "dovend.h"
7244099b7bSPaul Traina #include "readfile.h"
7344099b7bSPaul Traina #include "report.h"
7444099b7bSPaul Traina #include "tzone.h"
7544099b7bSPaul Traina #include "patchlevel.h"
7644099b7bSPaul Traina 
7744099b7bSPaul Traina #define	BUFFERSIZE   		0x4000
7844099b7bSPaul Traina 
7944099b7bSPaul Traina #ifndef CONFIG_FILE
8044099b7bSPaul Traina #define CONFIG_FILE		"/etc/bootptab"
8144099b7bSPaul Traina #endif
8244099b7bSPaul Traina 
8344099b7bSPaul Traina 
8444099b7bSPaul Traina 
8544099b7bSPaul Traina /*
8644099b7bSPaul Traina  * Externals, forward declarations, and global variables
8744099b7bSPaul Traina  */
8844099b7bSPaul Traina 
8944099b7bSPaul Traina #ifdef	__STDC__
9044099b7bSPaul Traina #define P(args) args
9144099b7bSPaul Traina #else
9244099b7bSPaul Traina #define P(args) ()
9344099b7bSPaul Traina #endif
9444099b7bSPaul Traina 
9544099b7bSPaul Traina static void mktagfile P((struct host *));
9644099b7bSPaul Traina static void usage P((void));
9744099b7bSPaul Traina 
9844099b7bSPaul Traina #undef P
9944099b7bSPaul Traina 
10044099b7bSPaul Traina 
10144099b7bSPaul Traina /*
10244099b7bSPaul Traina  * General
10344099b7bSPaul Traina  */
10444099b7bSPaul Traina 
10544099b7bSPaul Traina char *progname;
10644099b7bSPaul Traina char *chdir_path;
10744099b7bSPaul Traina int debug = 0;					/* Debugging flag (level) */
10844099b7bSPaul Traina byte *buffer;
10944099b7bSPaul Traina 
11044099b7bSPaul Traina /*
11144099b7bSPaul Traina  * Globals below are associated with the bootp database file (bootptab).
11244099b7bSPaul Traina  */
11344099b7bSPaul Traina 
11444099b7bSPaul Traina char *bootptab = CONFIG_FILE;
11544099b7bSPaul Traina 
11644099b7bSPaul Traina 
11744099b7bSPaul Traina /*
11844099b7bSPaul Traina  * Print "usage" message and exit
11944099b7bSPaul Traina  */
12044099b7bSPaul Traina static void
12144099b7bSPaul Traina usage()
12244099b7bSPaul Traina {
12344099b7bSPaul Traina 	fprintf(stderr,
12444099b7bSPaul Traina 	   "usage:  $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
12544099b7bSPaul Traina 	fprintf(stderr, "\t -c n\tset current directory\n");
12644099b7bSPaul Traina 	fprintf(stderr, "\t -d n\tset debug level\n");
12744099b7bSPaul Traina 	fprintf(stderr, "\t -f n\tconfig file name\n");
12844099b7bSPaul Traina 	exit(1);
12944099b7bSPaul Traina }
13044099b7bSPaul Traina 
13144099b7bSPaul Traina 
13244099b7bSPaul Traina /*
13344099b7bSPaul Traina  * Initialization such as command-line processing is done and then the
13444099b7bSPaul Traina  * main server loop is started.
13544099b7bSPaul Traina  */
13644099b7bSPaul Traina void
13744099b7bSPaul Traina main(argc, argv)
13844099b7bSPaul Traina 	int argc;
13944099b7bSPaul Traina 	char **argv;
14044099b7bSPaul Traina {
14144099b7bSPaul Traina 	struct host *hp;
14244099b7bSPaul Traina 	char *stmp;
14344099b7bSPaul Traina 	int n;
14444099b7bSPaul Traina 
14544099b7bSPaul Traina 	progname = strrchr(argv[0], '/');
14644099b7bSPaul Traina 	if (progname) progname++;
14744099b7bSPaul Traina 	else progname = argv[0];
14844099b7bSPaul Traina 
14944099b7bSPaul Traina 	/* Get work space for making tag 18 files. */
15044099b7bSPaul Traina 	buffer = (byte *) malloc(BUFFERSIZE);
15144099b7bSPaul Traina 	if (!buffer) {
15244099b7bSPaul Traina 		report(LOG_ERR, "malloc failed");
15344099b7bSPaul Traina 		exit(1);
15444099b7bSPaul Traina 	}
15544099b7bSPaul Traina 	/*
15644099b7bSPaul Traina 	 * Set defaults that might be changed by option switches.
15744099b7bSPaul Traina 	 */
15844099b7bSPaul Traina 	stmp = NULL;
15944099b7bSPaul Traina 
16044099b7bSPaul Traina 	/*
16144099b7bSPaul Traina 	 * Read switches.
16244099b7bSPaul Traina 	 */
16344099b7bSPaul Traina 	for (argc--, argv++; argc > 0; argc--, argv++) {
16444099b7bSPaul Traina 		if (argv[0][0] != '-')
16544099b7bSPaul Traina 			break;
16644099b7bSPaul Traina 		switch (argv[0][1]) {
16744099b7bSPaul Traina 
16844099b7bSPaul Traina 		case 'c':				/* chdir_path */
16944099b7bSPaul Traina 			if (argv[0][2]) {
17044099b7bSPaul Traina 				stmp = &(argv[0][2]);
17144099b7bSPaul Traina 			} else {
17244099b7bSPaul Traina 				argc--;
17344099b7bSPaul Traina 				argv++;
17444099b7bSPaul Traina 				stmp = argv[0];
17544099b7bSPaul Traina 			}
17644099b7bSPaul Traina 			if (!stmp || (stmp[0] != '/')) {
17744099b7bSPaul Traina 				fprintf(stderr,
17844099b7bSPaul Traina 						"bootpd: invalid chdir specification\n");
17944099b7bSPaul Traina 				break;
18044099b7bSPaul Traina 			}
18144099b7bSPaul Traina 			chdir_path = stmp;
18244099b7bSPaul Traina 			break;
18344099b7bSPaul Traina 
18444099b7bSPaul Traina 		case 'd':				/* debug */
18544099b7bSPaul Traina 			if (argv[0][2]) {
18644099b7bSPaul Traina 				stmp = &(argv[0][2]);
18744099b7bSPaul Traina 			} else if (argv[1] && argv[1][0] == '-') {
18844099b7bSPaul Traina 				/*
18944099b7bSPaul Traina 				 * Backwards-compatible behavior:
19044099b7bSPaul Traina 				 * no parameter, so just increment the debug flag.
19144099b7bSPaul Traina 				 */
19244099b7bSPaul Traina 				debug++;
19344099b7bSPaul Traina 				break;
19444099b7bSPaul Traina 			} else {
19544099b7bSPaul Traina 				argc--;
19644099b7bSPaul Traina 				argv++;
19744099b7bSPaul Traina 				stmp = argv[0];
19844099b7bSPaul Traina 			}
19944099b7bSPaul Traina 			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
20044099b7bSPaul Traina 				fprintf(stderr,
20144099b7bSPaul Traina 						"bootpd: invalid debug level\n");
20244099b7bSPaul Traina 				break;
20344099b7bSPaul Traina 			}
20444099b7bSPaul Traina 			debug = n;
20544099b7bSPaul Traina 			break;
20644099b7bSPaul Traina 
20744099b7bSPaul Traina 		case 'f':				/* config file */
20844099b7bSPaul Traina 			if (argv[0][2]) {
20944099b7bSPaul Traina 				stmp = &(argv[0][2]);
21044099b7bSPaul Traina 			} else {
21144099b7bSPaul Traina 				argc--;
21244099b7bSPaul Traina 				argv++;
21344099b7bSPaul Traina 				stmp = argv[0];
21444099b7bSPaul Traina 			}
21544099b7bSPaul Traina 			bootptab = stmp;
21644099b7bSPaul Traina 			break;
21744099b7bSPaul Traina 
21844099b7bSPaul Traina 		default:
21944099b7bSPaul Traina 			fprintf(stderr, "bootpd: unknown switch: -%c\n",
22044099b7bSPaul Traina 					argv[0][1]);
22144099b7bSPaul Traina 			usage();
22244099b7bSPaul Traina 			break;
22344099b7bSPaul Traina 		}
22444099b7bSPaul Traina 	}
22544099b7bSPaul Traina 
22644099b7bSPaul Traina 	/* Get the timezone. */
22744099b7bSPaul Traina 	tzone_init();
22844099b7bSPaul Traina 
22944099b7bSPaul Traina 	/* Allocate hash tables. */
23044099b7bSPaul Traina 	rdtab_init();
23144099b7bSPaul Traina 
23244099b7bSPaul Traina 	/*
23344099b7bSPaul Traina 	 * Read the bootptab file.
23444099b7bSPaul Traina 	 */
23544099b7bSPaul Traina 	readtab(1);					/* force read */
23644099b7bSPaul Traina 
23744099b7bSPaul Traina 	/* Set the cwd (i.e. to /tftpboot) */
23844099b7bSPaul Traina 	if (chdir_path) {
23944099b7bSPaul Traina 		if (chdir(chdir_path) < 0)
24044099b7bSPaul Traina 			report(LOG_ERR, "%s: chdir failed", chdir_path);
24144099b7bSPaul Traina 	}
24244099b7bSPaul Traina 	/* If there are host names on the command line, do only those. */
24344099b7bSPaul Traina 	if (argc > 0) {
24444099b7bSPaul Traina 		unsigned int tlen, hashcode;
24544099b7bSPaul Traina 
24644099b7bSPaul Traina 		while (argc) {
24744099b7bSPaul Traina 			tlen = strlen(argv[0]);
24844099b7bSPaul Traina 			hashcode = hash_HashFunction((u_char *)argv[0], tlen);
24944099b7bSPaul Traina 			hp = (struct host *) hash_Lookup(nmhashtable,
25044099b7bSPaul Traina 											 hashcode,
25144099b7bSPaul Traina 											 nmcmp, argv[0]);
25244099b7bSPaul Traina 			if (!hp) {
25344099b7bSPaul Traina 				printf("%s: no matching entry\n", argv[0]);
25444099b7bSPaul Traina 				exit(1);
25544099b7bSPaul Traina 			}
25644099b7bSPaul Traina 			if (!hp->flags.exten_file) {
25744099b7bSPaul Traina 				printf("%s: no extension file\n", argv[0]);
25844099b7bSPaul Traina 				exit(1);
25944099b7bSPaul Traina 			}
26044099b7bSPaul Traina 			mktagfile(hp);
26144099b7bSPaul Traina 			argv++;
26244099b7bSPaul Traina 			argc--;
26344099b7bSPaul Traina 		}
26444099b7bSPaul Traina 		exit(0);
26544099b7bSPaul Traina 	}
26644099b7bSPaul Traina 	/* No host names specified.  Do them all. */
26744099b7bSPaul Traina 	hp = (struct host *) hash_FirstEntry(nmhashtable);
26844099b7bSPaul Traina 	while (hp != NULL) {
26944099b7bSPaul Traina 		mktagfile(hp);
27044099b7bSPaul Traina 		hp = (struct host *) hash_NextEntry(nmhashtable);
27144099b7bSPaul Traina 	}
27244099b7bSPaul Traina }
27344099b7bSPaul Traina 
27444099b7bSPaul Traina 
27544099b7bSPaul Traina 
27644099b7bSPaul Traina /*
27744099b7bSPaul Traina  * Make a "TAG 18" file for this host.
27844099b7bSPaul Traina  * (Insert the RFC1497 options.)
27944099b7bSPaul Traina  */
28044099b7bSPaul Traina 
28144099b7bSPaul Traina static void
28244099b7bSPaul Traina mktagfile(hp)
28344099b7bSPaul Traina 	struct host *hp;
28444099b7bSPaul Traina {
28544099b7bSPaul Traina 	FILE *fp;
28644099b7bSPaul Traina 	int bytesleft, len;
28744099b7bSPaul Traina 	byte *vp;
28844099b7bSPaul Traina 
28944099b7bSPaul Traina 	if (!hp->flags.exten_file)
29044099b7bSPaul Traina 		return;
29144099b7bSPaul Traina 
29244099b7bSPaul Traina 	vp = buffer;
29344099b7bSPaul Traina 	bytesleft = BUFFERSIZE;
29444099b7bSPaul Traina 	bcopy(vm_rfc1048, vp, 4);	/* Copy in the magic cookie */
29544099b7bSPaul Traina 	vp += 4;
29644099b7bSPaul Traina 	bytesleft -= 4;
29744099b7bSPaul Traina 
29844099b7bSPaul Traina 	/*
29944099b7bSPaul Traina 	 * The "extension file" options are appended by the following
30044099b7bSPaul Traina 	 * function (which is shared with bootpd.c).
30144099b7bSPaul Traina 	 */
30244099b7bSPaul Traina 	len = dovend_rfc1497(hp, vp, bytesleft);
30344099b7bSPaul Traina 	vp += len;
30444099b7bSPaul Traina 	bytesleft -= len;
30544099b7bSPaul Traina 
30644099b7bSPaul Traina 	if (bytesleft < 1) {
30744099b7bSPaul Traina 		report(LOG_ERR, "%s: too much option data",
30844099b7bSPaul Traina 			   hp->exten_file->string);
30944099b7bSPaul Traina 		return;
31044099b7bSPaul Traina 	}
31144099b7bSPaul Traina 	*vp++ = TAG_END;
31244099b7bSPaul Traina 	bytesleft--;
31344099b7bSPaul Traina 
31444099b7bSPaul Traina 	/* Write the buffer to the extension file. */
31544099b7bSPaul Traina 	printf("Updating \"%s\"\n", hp->exten_file->string);
31644099b7bSPaul Traina 	if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
31744099b7bSPaul Traina 		report(LOG_ERR, "error opening \"%s\": %s",
31844099b7bSPaul Traina 			   hp->exten_file->string, get_errmsg());
31944099b7bSPaul Traina 		return;
32044099b7bSPaul Traina 	}
32144099b7bSPaul Traina 	len = vp - buffer;
32244099b7bSPaul Traina 	if (len != fwrite(buffer, 1, len, fp)) {
32344099b7bSPaul Traina 		report(LOG_ERR, "write failed on \"%s\" : %s",
32444099b7bSPaul Traina 			   hp->exten_file->string, get_errmsg());
32544099b7bSPaul Traina 	}
32644099b7bSPaul Traina 	fclose(fp);
32744099b7bSPaul Traina 
328e08ac58bSPaul Traina } /* mktagfile */
32944099b7bSPaul Traina 
33044099b7bSPaul Traina /*
33144099b7bSPaul Traina  * Local Variables:
33244099b7bSPaul Traina  * tab-width: 4
33344099b7bSPaul Traina  * c-indent-level: 4
33444099b7bSPaul Traina  * c-argdecl-indent: 4
33544099b7bSPaul Traina  * c-continued-statement-offset: 4
33644099b7bSPaul Traina  * c-continued-brace-offset: -4
33744099b7bSPaul Traina  * c-label-offset: -4
33844099b7bSPaul Traina  * c-brace-offset: 0
33944099b7bSPaul Traina  * End:
34044099b7bSPaul Traina  */
341