1238106Sdes/************************************************************************
2238106Sdes          Copyright 1988, 1991 by Carnegie Mellon University
3238106Sdes
4238106Sdes                          All Rights Reserved
5238106Sdes
6238106SdesPermission to use, copy, modify, and distribute this software and its
7238106Sdesdocumentation for any purpose and without fee is hereby granted, provided
8238106Sdesthat the above copyright notice appear in all copies and that both that
9238106Sdescopyright notice and this permission notice appear in supporting
10238106Sdesdocumentation, and that the name of Carnegie Mellon University not be used
11238106Sdesin advertising or publicity pertaining to distribution of the software
12238106Sdeswithout specific, written prior permission.
13238106Sdes
14238106SdesCARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15238106SdesSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16238106SdesIN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17238106SdesDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18238106SdesPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19238106SdesACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20238106SdesSOFTWARE.
21238106Sdes
22238106Sdes************************************************************************/
23238106Sdes
24238106Sdes/*
25238106Sdes * bootpef - BOOTP Extension File generator
26238106Sdes *	Makes an "Extension File" for each host entry that
27238106Sdes *	defines an and Extension File. (See RFC1497, tag 18.)
28238106Sdes *
29238106Sdes * HISTORY
30238106Sdes *	See ./Changes
31238106Sdes *
32238106Sdes * BUGS
33238106Sdes *	See ./ToDo
34238106Sdes */
35238106Sdes
36238106Sdes
37238106Sdes
38238106Sdes#include <stdarg.h>
39238106Sdes
40238106Sdes#include <sys/types.h>
41238106Sdes#include <sys/time.h>
42238106Sdes
43238106Sdes#include <netinet/in.h>
44238106Sdes#include <arpa/inet.h>			/* inet_ntoa */
45238106Sdes
46238106Sdes#ifndef	NO_UNISTD
47238106Sdes#include <unistd.h>
48238106Sdes#endif
49238106Sdes#include <stdlib.h>
50238106Sdes#include <stdio.h>
51238106Sdes#include <string.h>
52238106Sdes#include <errno.h>
53238106Sdes#include <ctype.h>
54238106Sdes#include <syslog.h>
55238106Sdes
56238106Sdes#include "bootp.h"
57238106Sdes#include "hash.h"
58238106Sdes#include "hwaddr.h"
59238106Sdes#include "bootpd.h"
60238106Sdes#include "dovend.h"
61238106Sdes#include "readfile.h"
62238106Sdes#include "report.h"
63238106Sdes#include "tzone.h"
64238106Sdes#include "patchlevel.h"
65238106Sdes
66238106Sdes#define	BUFFERSIZE   		0x4000
67238106Sdes
68238106Sdes#ifndef CONFIG_FILE
69238106Sdes#define CONFIG_FILE		"/etc/bootptab"
70238106Sdes#endif
71238106Sdes
72238106Sdes
73238106Sdes
74238106Sdes/*
75238106Sdes * Externals, forward declarations, and global variables
76238106Sdes */
77238106Sdes
78238106Sdesstatic void mktagfile(struct host *);
79238106Sdesstatic void usage(void) __dead2;
80238106Sdes
81238106Sdes/*
82238106Sdes * General
83238106Sdes */
84238106Sdes
85238106Sdeschar *progname;
86238106Sdeschar *chdir_path;
87238106Sdesint debug = 0;					/* Debugging flag (level) */
88238106Sdesbyte *buffer;
89238106Sdes
90238106Sdes/*
91238106Sdes * Globals below are associated with the bootp database file (bootptab).
92238106Sdes */
93238106Sdes
94238106Sdeschar *bootptab = CONFIG_FILE;
95238106Sdes
96238106Sdes
97238106Sdes/*
98238106Sdes * Print "usage" message and exit
99238106Sdes */
100238106Sdesstatic void
101238106Sdesusage(void)
102238106Sdes{
103238106Sdes	fprintf(stderr,
104238106Sdes	   "usage:  $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
105238106Sdes	fprintf(stderr, "\t -c n\tset current directory\n");
106238106Sdes	fprintf(stderr, "\t -d n\tset debug level\n");
107238106Sdes	fprintf(stderr, "\t -f n\tconfig file name\n");
108238106Sdes	exit(1);
109238106Sdes}
110238106Sdes
111238106Sdes
112238106Sdes/*
113238106Sdes * Initialization such as command-line processing is done and then the
114238106Sdes * main server loop is started.
115238106Sdes */
116238106Sdesint
117238106Sdesmain(int argc, char **argv)
118238106Sdes{
119238106Sdes	struct host *hp;
120238106Sdes	char *stmp;
121238106Sdes	int n;
122238106Sdes
123238106Sdes	progname = strrchr(argv[0], '/');
124238106Sdes	if (progname) progname++;
125238106Sdes	else progname = argv[0];
126238106Sdes
127238106Sdes	/* Get work space for making tag 18 files. */
128238106Sdes	buffer = (byte *) malloc(BUFFERSIZE);
129238106Sdes	if (!buffer) {
130238106Sdes		report(LOG_ERR, "malloc failed");
131238106Sdes		exit(1);
132238106Sdes	}
133238106Sdes	/*
134238106Sdes	 * Set defaults that might be changed by option switches.
135238106Sdes	 */
136238106Sdes	stmp = NULL;
137238106Sdes
138238106Sdes	/*
139238106Sdes	 * Read switches.
140238106Sdes	 */
141238106Sdes	for (argc--, argv++; argc > 0; argc--, argv++) {
142238106Sdes		if (argv[0][0] != '-')
143238106Sdes			break;
144238106Sdes		switch (argv[0][1]) {
145238106Sdes
146238106Sdes		case 'c':				/* chdir_path */
147238106Sdes			if (argv[0][2]) {
148238106Sdes				stmp = &(argv[0][2]);
149238106Sdes			} else {
150238106Sdes				argc--;
151238106Sdes				argv++;
152238106Sdes				stmp = argv[0];
153238106Sdes			}
154238106Sdes			if (!stmp || (stmp[0] != '/')) {
155238106Sdes				fprintf(stderr,
156238106Sdes						"bootpd: invalid chdir specification\n");
157238106Sdes				break;
158238106Sdes			}
159238106Sdes			chdir_path = stmp;
160238106Sdes			break;
161238106Sdes
162238106Sdes		case 'd':				/* debug */
163238106Sdes			if (argv[0][2]) {
164238106Sdes				stmp = &(argv[0][2]);
165238106Sdes			} else if (argv[1] && argv[1][0] == '-') {
166238106Sdes				/*
167238106Sdes				 * Backwards-compatible behavior:
168238106Sdes				 * no parameter, so just increment the debug flag.
169238106Sdes				 */
170238106Sdes				debug++;
171238106Sdes				break;
172238106Sdes			} else {
173238106Sdes				argc--;
174238106Sdes				argv++;
175238106Sdes				stmp = argv[0];
176238106Sdes			}
177238106Sdes			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
178238106Sdes				fprintf(stderr,
179238106Sdes						"bootpd: invalid debug level\n");
180238106Sdes				break;
181238106Sdes			}
182238106Sdes			debug = n;
183238106Sdes			break;
184238106Sdes
185238106Sdes		case 'f':				/* config file */
186238106Sdes			if (argv[0][2]) {
187238106Sdes				stmp = &(argv[0][2]);
188238106Sdes			} else {
189238106Sdes				argc--;
190238106Sdes				argv++;
191238106Sdes				stmp = argv[0];
192238106Sdes			}
193			bootptab = stmp;
194			break;
195
196		default:
197			fprintf(stderr, "bootpd: unknown switch: -%c\n",
198					argv[0][1]);
199			usage();
200			break;
201		}
202	}
203
204	/* Get the timezone. */
205	tzone_init();
206
207	/* Allocate hash tables. */
208	rdtab_init();
209
210	/*
211	 * Read the bootptab file.
212	 */
213	readtab(1);					/* force read */
214
215	/* Set the cwd (i.e. to /tftpboot) */
216	if (chdir_path) {
217		if (chdir(chdir_path) < 0)
218			report(LOG_ERR, "%s: chdir failed", chdir_path);
219	}
220	/* If there are host names on the command line, do only those. */
221	if (argc > 0) {
222		unsigned int tlen, hashcode;
223
224		while (argc) {
225			tlen = strlen(argv[0]);
226			hashcode = hash_HashFunction((u_char *)argv[0], tlen);
227			hp = (struct host *) hash_Lookup(nmhashtable,
228											 hashcode,
229											 nmcmp, argv[0]);
230			if (!hp) {
231				printf("%s: no matching entry\n", argv[0]);
232				exit(1);
233			}
234			if (!hp->flags.exten_file) {
235				printf("%s: no extension file\n", argv[0]);
236				exit(1);
237			}
238			mktagfile(hp);
239			argv++;
240			argc--;
241		}
242		exit(0);
243	}
244	/* No host names specified.  Do them all. */
245	hp = (struct host *) hash_FirstEntry(nmhashtable);
246	while (hp != NULL) {
247		mktagfile(hp);
248		hp = (struct host *) hash_NextEntry(nmhashtable);
249	}
250	return (0);
251}
252
253
254
255/*
256 * Make a "TAG 18" file for this host.
257 * (Insert the RFC1497 options.)
258 */
259
260static void
261mktagfile(struct host *hp)
262{
263	FILE *fp;
264	int bytesleft, len;
265	byte *vp;
266
267	if (!hp->flags.exten_file)
268		return;
269
270	vp = buffer;
271	bytesleft = BUFFERSIZE;
272	bcopy(vm_rfc1048, vp, 4);	/* Copy in the magic cookie */
273	vp += 4;
274	bytesleft -= 4;
275
276	/*
277	 * The "extension file" options are appended by the following
278	 * function (which is shared with bootpd.c).
279	 */
280	len = dovend_rfc1497(hp, vp, bytesleft);
281	vp += len;
282	bytesleft -= len;
283
284	if (bytesleft < 1) {
285		report(LOG_ERR, "%s: too much option data",
286			   hp->exten_file->string);
287		return;
288	}
289	*vp++ = TAG_END;
290	bytesleft--;
291
292	/* Write the buffer to the extension file. */
293	printf("Updating \"%s\"\n", hp->exten_file->string);
294	if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
295		report(LOG_ERR, "error opening \"%s\": %s",
296			   hp->exten_file->string, get_errmsg());
297		return;
298	}
299	len = vp - buffer;
300	if (len != fwrite(buffer, 1, len, fp)) {
301		report(LOG_ERR, "write failed on \"%s\" : %s",
302			   hp->exten_file->string, get_errmsg());
303	}
304	fclose(fp);
305
306} /* mktagfile */
307
308/*
309 * Local Variables:
310 * tab-width: 4
311 * c-indent-level: 4
312 * c-argdecl-indent: 4
313 * c-continued-statement-offset: 4
314 * c-continued-brace-offset: -4
315 * c-label-offset: -4
316 * c-brace-offset: 0
317 * End:
318 */
319