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 43 44 #include <stdarg.h> 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 <strings.h> 59 #include <errno.h> 60 #include <ctype.h> 61 #include <syslog.h> 62 63 #include "bootp.h" 64 #include "hash.h" 65 #include "hwaddr.h" 66 #include "bootpd.h" 67 #include "dovend.h" 68 #include "readfile.h" 69 #include "report.h" 70 #include "tzone.h" 71 #include "patchlevel.h" 72 73 #define BUFFERSIZE 0x4000 74 75 #ifndef CONFIG_FILE 76 #define CONFIG_FILE "/etc/bootptab" 77 #endif 78 79 81 82 /* 83 * Externals, forward declarations, and global variables 84 */ 85 86 static void mktagfile(struct host *); 87 __dead static void usage(void); 88 89 90 /* 91 * General 92 */ 93 94 const char *progname; 95 char *chdir_path; 96 int debug = 0; /* Debugging flag (level) */ 97 byte *buffer; 98 99 /* 100 * Globals below are associated with the bootp database file (bootptab). 101 */ 102 103 const char *bootptab = CONFIG_FILE; 104 105 107 /* 108 * Print "usage" message and exit 109 */ 110 static void 111 usage(void) 112 { 113 fprintf(stderr, 114 "usage: %s [-c chdir] [-d level] [-f configfile] [host ...]\n", 115 getprogname()); 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 exit(0); 262 } 263 264 266 267 /* 268 * Make a "TAG 18" file for this host. 269 * (Insert the RFC1497 options.) 270 */ 271 272 static void 273 mktagfile(struct host *hp) 274 { 275 FILE *fp; 276 int bytesleft, len; 277 byte *vp; 278 279 if (!hp->flags.exten_file) 280 return; 281 282 vp = buffer; 283 bytesleft = BUFFERSIZE; 284 bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */ 285 vp += 4; 286 bytesleft -= 4; 287 288 /* 289 * The "extension file" options are appended by the following 290 * function (which is shared with bootpd.c). 291 */ 292 len = dovend_rfc1497(hp, vp, bytesleft); 293 vp += len; 294 bytesleft -= len; 295 296 if (bytesleft < 1) { 297 report(LOG_ERR, "%s: too much option data", 298 hp->exten_file->string); 299 return; 300 } 301 *vp++ = TAG_END; 302 bytesleft--; 303 304 /* Write the buffer to the extension file. */ 305 printf("Updating \"%s\"\n", hp->exten_file->string); 306 if ((fp = fopen(hp->exten_file->string, "w")) == NULL) { 307 report(LOG_ERR, "error opening \"%s\": %s", 308 hp->exten_file->string, get_errmsg()); 309 return; 310 } 311 len = vp - buffer; 312 if ((size_t)len != fwrite(buffer, 1, len, fp)) { 313 report(LOG_ERR, "write failed on \"%s\" : %s", 314 hp->exten_file->string, get_errmsg()); 315 } 316 fclose(fp); 317 318 } /* mktagfile */ 319 320 /* 321 * Local Variables: 322 * tab-width: 4 323 * c-indent-level: 4 324 * c-argdecl-indent: 4 325 * c-continued-statement-offset: 4 326 * c-continued-brace-offset: -4 327 * c-label-offset: -4 328 * c-brace-offset: 0 329 * End: 330 */ 331