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 $FreeBSD$
23
24************************************************************************/
25
26/*
27 * bootpef - BOOTP Extension File generator
28 *	Makes an "Extension File" for each host entry that
29 *	defines an and Extension File. (See RFC1497, tag 18.)
30 *
31 * HISTORY
32 *	See ./Changes
33 *
34 * BUGS
35 *	See ./ToDo
36 */
37
38
39
40#include <stdarg.h>
41
42#include <sys/types.h>
43#include <sys/time.h>
44
45#include <netinet/in.h>
46#include <arpa/inet.h>			/* inet_ntoa */
47
48#ifndef	NO_UNISTD
49#include <unistd.h>
50#endif
51#include <stdlib.h>
52#include <stdio.h>
53#include <string.h>
54#include <errno.h>
55#include <ctype.h>
56#include <syslog.h>
57
58#ifndef	USE_BFUNCS
59#include <memory.h>
60/* Yes, memcpy is OK here (no overlapped copies). */
61#define bcopy(a,b,c)    memcpy(b,a,c)
62#define bzero(p,l)      memset(p,0,l)
63#define bcmp(a,b,c)     memcmp(a,b,c)
64#endif
65
66#include "bootp.h"
67#include "hash.h"
68#include "hwaddr.h"
69#include "bootpd.h"
70#include "dovend.h"
71#include "readfile.h"
72#include "report.h"
73#include "tzone.h"
74#include "patchlevel.h"
75
76#define	BUFFERSIZE   		0x4000
77
78#ifndef CONFIG_FILE
79#define CONFIG_FILE		"/etc/bootptab"
80#endif
81
82
83
84/*
85 * Externals, forward declarations, and global variables
86 */
87
88static void mktagfile(struct host *);
89static void usage(void);
90
91/*
92 * General
93 */
94
95char *progname;
96char *chdir_path;
97int debug = 0;					/* Debugging flag (level) */
98byte *buffer;
99
100/*
101 * Globals below are associated with the bootp database file (bootptab).
102 */
103
104char *bootptab = CONFIG_FILE;
105
106
107/*
108 * Print "usage" message and exit
109 */
110static void
111usage()
112{
113	fprintf(stderr,
114	   "usage:  $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
115	fprintf(stderr, "\t -c n\tset current directory\n");
116	fprintf(stderr, "\t -d n\tset debug level\n");
117	fprintf(stderr, "\t -f n\tconfig file name\n");
118	exit(1);
119}
120
121
122/*
123 * Initialization such as command-line processing is done and then the
124 * main server loop is started.
125 */
126int
127main(argc, argv)
128	int argc;
129	char **argv;
130{
131	struct host *hp;
132	char *stmp;
133	int n;
134
135	progname = strrchr(argv[0], '/');
136	if (progname) progname++;
137	else progname = argv[0];
138
139	/* Get work space for making tag 18 files. */
140	buffer = (byte *) malloc(BUFFERSIZE);
141	if (!buffer) {
142		report(LOG_ERR, "malloc failed");
143		exit(1);
144	}
145	/*
146	 * Set defaults that might be changed by option switches.
147	 */
148	stmp = NULL;
149
150	/*
151	 * Read switches.
152	 */
153	for (argc--, argv++; argc > 0; argc--, argv++) {
154		if (argv[0][0] != '-')
155			break;
156		switch (argv[0][1]) {
157
158		case 'c':				/* chdir_path */
159			if (argv[0][2]) {
160				stmp = &(argv[0][2]);
161			} else {
162				argc--;
163				argv++;
164				stmp = argv[0];
165			}
166			if (!stmp || (stmp[0] != '/')) {
167				fprintf(stderr,
168						"bootpd: invalid chdir specification\n");
169				break;
170			}
171			chdir_path = stmp;
172			break;
173
174		case 'd':				/* debug */
175			if (argv[0][2]) {
176				stmp = &(argv[0][2]);
177			} else if (argv[1] && argv[1][0] == '-') {
178				/*
179				 * Backwards-compatible behavior:
180				 * no parameter, so just increment the debug flag.
181				 */
182				debug++;
183				break;
184			} else {
185				argc--;
186				argv++;
187				stmp = argv[0];
188			}
189			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
190				fprintf(stderr,
191						"bootpd: invalid debug level\n");
192				break;
193			}
194			debug = n;
195			break;
196
197		case 'f':				/* config file */
198			if (argv[0][2]) {
199				stmp = &(argv[0][2]);
200			} else {
201				argc--;
202				argv++;
203				stmp = argv[0];
204			}
205			bootptab = stmp;
206			break;
207
208		default:
209			fprintf(stderr, "bootpd: unknown switch: -%c\n",
210					argv[0][1]);
211			usage();
212			break;
213		}
214	}
215
216	/* Get the timezone. */
217	tzone_init();
218
219	/* Allocate hash tables. */
220	rdtab_init();
221
222	/*
223	 * Read the bootptab file.
224	 */
225	readtab(1);					/* force read */
226
227	/* Set the cwd (i.e. to /tftpboot) */
228	if (chdir_path) {
229		if (chdir(chdir_path) < 0)
230			report(LOG_ERR, "%s: chdir failed", chdir_path);
231	}
232	/* If there are host names on the command line, do only those. */
233	if (argc > 0) {
234		unsigned int tlen, hashcode;
235
236		while (argc) {
237			tlen = strlen(argv[0]);
238			hashcode = hash_HashFunction((u_char *)argv[0], tlen);
239			hp = (struct host *) hash_Lookup(nmhashtable,
240											 hashcode,
241											 nmcmp, argv[0]);
242			if (!hp) {
243				printf("%s: no matching entry\n", argv[0]);
244				exit(1);
245			}
246			if (!hp->flags.exten_file) {
247				printf("%s: no extension file\n", argv[0]);
248				exit(1);
249			}
250			mktagfile(hp);
251			argv++;
252			argc--;
253		}
254		exit(0);
255	}
256	/* No host names specified.  Do them all. */
257	hp = (struct host *) hash_FirstEntry(nmhashtable);
258	while (hp != NULL) {
259		mktagfile(hp);
260		hp = (struct host *) hash_NextEntry(nmhashtable);
261	}
262	return (0);
263}
264
265
266
267/*
268 * Make a "TAG 18" file for this host.
269 * (Insert the RFC1497 options.)
270 */
271
272static void
273mktagfile(hp)
274	struct host *hp;
275{
276	FILE *fp;
277	int bytesleft, len;
278	byte *vp;
279
280	if (!hp->flags.exten_file)
281		return;
282
283	vp = buffer;
284	bytesleft = BUFFERSIZE;
285	bcopy(vm_rfc1048, vp, 4);	/* Copy in the magic cookie */
286	vp += 4;
287	bytesleft -= 4;
288
289	/*
290	 * The "extension file" options are appended by the following
291	 * function (which is shared with bootpd.c).
292	 */
293	len = dovend_rfc1497(hp, vp, bytesleft);
294	vp += len;
295	bytesleft -= len;
296
297	if (bytesleft < 1) {
298		report(LOG_ERR, "%s: too much option data",
299			   hp->exten_file->string);
300		return;
301	}
302	*vp++ = TAG_END;
303	bytesleft--;
304
305	/* Write the buffer to the extension file. */
306	printf("Updating \"%s\"\n", hp->exten_file->string);
307	if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
308		report(LOG_ERR, "error opening \"%s\": %s",
309			   hp->exten_file->string, get_errmsg());
310		return;
311	}
312	len = vp - buffer;
313	if (len != fwrite(buffer, 1, len, fp)) {
314		report(LOG_ERR, "write failed on \"%s\" : %s",
315			   hp->exten_file->string, get_errmsg());
316	}
317	fclose(fp);
318
319} /* mktagfile */
320
321/*
322 * Local Variables:
323 * tab-width: 4
324 * c-indent-level: 4
325 * c-argdecl-indent: 4
326 * c-continued-statement-offset: 4
327 * c-continued-brace-offset: -4
328 * c-label-offset: -4
329 * c-brace-offset: 0
330 * End:
331 */
332