1/************************************************************************
2          Copyright 1988, 1991 by Carnegie Mellon University
3
4                          All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted, provided
8that the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation, and that the name of Carnegie Mellon University not be used
11in advertising or publicity pertaining to distribution of the software
12without specific, written prior permission.
13
14CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22************************************************************************/
23
24/*
25 * bootpef - BOOTP Extension File generator
26 *	Makes an "Extension File" for each host entry that
27 *	defines an and Extension File. (See RFC1497, tag 18.)
28 *
29 * HISTORY
30 *	See ./Changes
31 *
32 * BUGS
33 *	See ./ToDo
34 */
35
36
37
38#include <stdarg.h>
39
40#include <sys/types.h>
41#include <sys/time.h>
42
43#include <netinet/in.h>
44#include <arpa/inet.h>			/* inet_ntoa */
45
46#ifndef	NO_UNISTD
47#include <unistd.h>
48#endif
49#include <stdlib.h>
50#include <stdio.h>
51#include <string.h>
52#include <errno.h>
53#include <ctype.h>
54#include <syslog.h>
55
56#include "bootp.h"
57#include "hash.h"
58#include "hwaddr.h"
59#include "bootpd.h"
60#include "dovend.h"
61#include "readfile.h"
62#include "report.h"
63#include "tzone.h"
64#include "patchlevel.h"
65
66#define	BUFFERSIZE   		0x4000
67
68#ifndef CONFIG_FILE
69#define CONFIG_FILE		"/etc/bootptab"
70#endif
71
72
73
74/*
75 * Externals, forward declarations, and global variables
76 */
77
78static void mktagfile(struct host *);
79static void usage(void) __dead2;
80
81/*
82 * General
83 */
84
85char *progname;
86char *chdir_path;
87int debug = 0;					/* Debugging flag (level) */
88byte *buffer;
89
90/*
91 * Globals below are associated with the bootp database file (bootptab).
92 */
93
94char *bootptab = CONFIG_FILE;
95
96
97/*
98 * Print "usage" message and exit
99 */
100static void
101usage(void)
102{
103	fprintf(stderr,
104	   "usage:  $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
105	fprintf(stderr, "\t -c n\tset current directory\n");
106	fprintf(stderr, "\t -d n\tset debug level\n");
107	fprintf(stderr, "\t -f n\tconfig file name\n");
108	exit(1);
109}
110
111
112/*
113 * Initialization such as command-line processing is done and then the
114 * main server loop is started.
115 */
116int
117main(int argc, char **argv)
118{
119	struct host *hp;
120	char *stmp;
121	int n;
122
123	progname = strrchr(argv[0], '/');
124	if (progname) progname++;
125	else progname = argv[0];
126
127	/* Get work space for making tag 18 files. */
128	buffer = (byte *) malloc(BUFFERSIZE);
129	if (!buffer) {
130		report(LOG_ERR, "malloc failed");
131		exit(1);
132	}
133	/*
134	 * Set defaults that might be changed by option switches.
135	 */
136	stmp = NULL;
137
138	/*
139	 * Read switches.
140	 */
141	for (argc--, argv++; argc > 0; argc--, argv++) {
142		if (argv[0][0] != '-')
143			break;
144		switch (argv[0][1]) {
145
146		case 'c':				/* chdir_path */
147			if (argv[0][2]) {
148				stmp = &(argv[0][2]);
149			} else {
150				argc--;
151				argv++;
152				stmp = argv[0];
153			}
154			if (!stmp || (stmp[0] != '/')) {
155				fprintf(stderr,
156						"bootpd: invalid chdir specification\n");
157				break;
158			}
159			chdir_path = stmp;
160			break;
161
162		case 'd':				/* debug */
163			if (argv[0][2]) {
164				stmp = &(argv[0][2]);
165			} else if (argv[1] && argv[1][0] == '-') {
166				/*
167				 * Backwards-compatible behavior:
168				 * no parameter, so just increment the debug flag.
169				 */
170				debug++;
171				break;
172			} else {
173				argc--;
174				argv++;
175				stmp = argv[0];
176			}
177			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
178				fprintf(stderr,
179						"bootpd: invalid debug level\n");
180				break;
181			}
182			debug = n;
183			break;
184
185		case 'f':				/* config file */
186			if (argv[0][2]) {
187				stmp = &(argv[0][2]);
188			} else {
189				argc--;
190				argv++;
191				stmp = argv[0];
192			}
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