1 /************************************************************************
2           Copyright 1988, 1991 by Carnegie Mellon University
3 
4                           All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted, provided
8 that the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation, and that the name of Carnegie Mellon University not be used
11 in advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
13 
14 CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22  $FreeBSD: src/libexec/bootpd/tools/bootpef/bootpef.c,v 1.6 1999/08/28 00:09:24 peter Exp $
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 
88 static void mktagfile(struct host *);
89 static void usage(void);
90 
91 
92 /*
93  * General
94  */
95 
96 char *progname;
97 char *chdir_path;
98 int debug = 0;					/* Debugging flag (level) */
99 byte *buffer;
100 
101 /*
102  * Globals below are associated with the bootp database file (bootptab).
103  */
104 
105 char *bootptab = CONFIG_FILE;
106 
107 
108 /*
109  * Print "usage" message and exit
110  */
111 static void
112 usage(void)
113 {
114 	fprintf(stderr,
115 	   "usage:  $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
116 	fprintf(stderr, "\t -c n\tset current directory\n");
117 	fprintf(stderr, "\t -d n\tset debug level\n");
118 	fprintf(stderr, "\t -f n\tconfig file name\n");
119 	exit(1);
120 }
121 
122 
123 /*
124  * Initialization such as command-line processing is done and then the
125  * main server loop is started.
126  */
127 int
128 main(int argc, char **argv)
129 {
130 	struct host *hp;
131 	char *stmp;
132 	int n;
133 
134 	progname = strrchr(argv[0], '/');
135 	if (progname) progname++;
136 	else progname = argv[0];
137 
138 	/* Get work space for making tag 18 files. */
139 	buffer = (byte *) malloc(BUFFERSIZE);
140 	if (!buffer) {
141 		report(LOG_ERR, "malloc failed");
142 		exit(1);
143 	}
144 	/*
145 	 * Set defaults that might be changed by option switches.
146 	 */
147 	stmp = NULL;
148 
149 	/*
150 	 * Read switches.
151 	 */
152 	for (argc--, argv++; argc > 0; argc--, argv++) {
153 		if (argv[0][0] != '-')
154 			break;
155 		switch (argv[0][1]) {
156 
157 		case 'c':				/* chdir_path */
158 			if (argv[0][2]) {
159 				stmp = &(argv[0][2]);
160 			} else {
161 				argc--;
162 				argv++;
163 				stmp = argv[0];
164 			}
165 			if (!stmp || (stmp[0] != '/')) {
166 				fprintf(stderr,
167 						"bootpd: invalid chdir specification\n");
168 				break;
169 			}
170 			chdir_path = stmp;
171 			break;
172 
173 		case 'd':				/* debug */
174 			if (argv[0][2]) {
175 				stmp = &(argv[0][2]);
176 			} else if (argv[1] && argv[1][0] == '-') {
177 				/*
178 				 * Backwards-compatible behavior:
179 				 * no parameter, so just increment the debug flag.
180 				 */
181 				debug++;
182 				break;
183 			} else {
184 				argc--;
185 				argv++;
186 				stmp = argv[0];
187 			}
188 			if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
189 				fprintf(stderr,
190 						"bootpd: invalid debug level\n");
191 				break;
192 			}
193 			debug = n;
194 			break;
195 
196 		case 'f':				/* config file */
197 			if (argv[0][2]) {
198 				stmp = &(argv[0][2]);
199 			} else {
200 				argc--;
201 				argv++;
202 				stmp = argv[0];
203 			}
204 			bootptab = stmp;
205 			break;
206 
207 		default:
208 			fprintf(stderr, "bootpd: unknown switch: -%c\n",
209 					argv[0][1]);
210 			usage();
211 			break;
212 		}
213 	}
214 
215 	/* Get the timezone. */
216 	tzone_init();
217 
218 	/* Allocate hash tables. */
219 	rdtab_init();
220 
221 	/*
222 	 * Read the bootptab file.
223 	 */
224 	readtab(1);					/* force read */
225 
226 	/* Set the cwd (i.e. to /tftpboot) */
227 	if (chdir_path) {
228 		if (chdir(chdir_path) < 0)
229 			report(LOG_ERR, "%s: chdir failed", chdir_path);
230 	}
231 	/* If there are host names on the command line, do only those. */
232 	if (argc > 0) {
233 		unsigned int tlen, hashcode;
234 
235 		while (argc) {
236 			tlen = strlen(argv[0]);
237 			hashcode = hash_HashFunction((u_char *)argv[0], tlen);
238 			hp = (struct host *) hash_Lookup(nmhashtable,
239 											 hashcode,
240 											 nmcmp, argv[0]);
241 			if (!hp) {
242 				printf("%s: no matching entry\n", argv[0]);
243 				exit(1);
244 			}
245 			if (!hp->flags.exten_file) {
246 				printf("%s: no extension file\n", argv[0]);
247 				exit(1);
248 			}
249 			mktagfile(hp);
250 			argv++;
251 			argc--;
252 		}
253 		exit(0);
254 	}
255 	/* No host names specified.  Do them all. */
256 	hp = (struct host *) hash_FirstEntry(nmhashtable);
257 	while (hp != NULL) {
258 		mktagfile(hp);
259 		hp = (struct host *) hash_NextEntry(nmhashtable);
260 	}
261 	return (0);
262 }
263 
264 
265 
266 /*
267  * Make a "TAG 18" file for this host.
268  * (Insert the RFC1497 options.)
269  */
270 
271 static void
272 mktagfile(struct host *hp)
273 {
274 	FILE *fp;
275 	int bytesleft, len;
276 	byte *vp;
277 
278 	if (!hp->flags.exten_file)
279 		return;
280 
281 	vp = buffer;
282 	bytesleft = BUFFERSIZE;
283 	bcopy(vm_rfc1048, vp, 4);	/* Copy in the magic cookie */
284 	vp += 4;
285 	bytesleft -= 4;
286 
287 	/*
288 	 * The "extension file" options are appended by the following
289 	 * function (which is shared with bootpd.c).
290 	 */
291 	len = dovend_rfc1497(hp, vp, bytesleft);
292 	vp += len;
293 	bytesleft -= len;
294 
295 	if (bytesleft < 1) {
296 		report(LOG_ERR, "%s: too much option data",
297 			   hp->exten_file->string);
298 		return;
299 	}
300 	*vp++ = TAG_END;
301 	bytesleft--;
302 
303 	/* Write the buffer to the extension file. */
304 	printf("Updating \"%s\"\n", hp->exten_file->string);
305 	if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
306 		report(LOG_ERR, "error opening \"%s\": %s",
307 			   hp->exten_file->string, get_errmsg());
308 		return;
309 	}
310 	len = vp - buffer;
311 	if (len != fwrite(buffer, 1, len, fp)) {
312 		report(LOG_ERR, "write failed on \"%s\" : %s",
313 			   hp->exten_file->string, get_errmsg());
314 	}
315 	fclose(fp);
316 
317 } /* mktagfile */
318