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 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 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 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