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