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