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
usage(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
main(int argc,char ** argv)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
mktagfile(struct host * hp)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