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.10 2011/08/29 20:38:54 joerg 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 int main(int, char **); 87 88 89 /* 90 * General 91 */ 92 93 const char *progname; 94 char *chdir_path; 95 int debug = 0; /* Debugging flag (level) */ 96 byte *buffer; 97 98 /* 99 * Globals below are associated with the bootp database file (bootptab). 100 */ 101 102 const char *bootptab = CONFIG_FILE; 103 104 105 /* 106 * Print "usage" message and exit 107 */ 108 static void 109 usage(void) 110 { 111 fprintf(stderr, 112 "usage: %s [-c chdir] [-d level] [-f configfile] [host ...]\n", 113 getprogname()); 114 fprintf(stderr, "\t -c n\tset current directory\n"); 115 fprintf(stderr, "\t -d n\tset debug level\n"); 116 fprintf(stderr, "\t -f n\tconfig file name\n"); 117 exit(1); 118 } 119 120 121 /* 122 * Initialization such as command-line processing is done and then the 123 * main server loop is started. 124 */ 125 int 126 main(int argc, char **argv) 127 { 128 struct host *hp; 129 char *stmp; 130 int n; 131 132 progname = strrchr(argv[0], '/'); 133 if (progname) progname++; 134 else progname = argv[0]; 135 136 /* Get work space for making tag 18 files. */ 137 buffer = (byte *) malloc(BUFFERSIZE); 138 if (!buffer) { 139 report(LOG_ERR, "malloc failed"); 140 exit(1); 141 } 142 /* 143 * Set defaults that might be changed by option switches. 144 */ 145 stmp = NULL; 146 147 /* 148 * Read switches. 149 */ 150 for (argc--, argv++; argc > 0; argc--, argv++) { 151 if (argv[0][0] != '-') 152 break; 153 switch (argv[0][1]) { 154 155 case 'c': /* chdir_path */ 156 if (argv[0][2]) { 157 stmp = &(argv[0][2]); 158 } else { 159 argc--; 160 argv++; 161 stmp = argv[0]; 162 } 163 if (!stmp || (stmp[0] != '/')) { 164 fprintf(stderr, 165 "bootpd: invalid chdir specification\n"); 166 break; 167 } 168 chdir_path = stmp; 169 break; 170 171 case 'd': /* debug */ 172 if (argv[0][2]) { 173 stmp = &(argv[0][2]); 174 } else if (argv[1] && argv[1][0] == '-') { 175 /* 176 * Backwards-compatible behavior: 177 * no parameter, so just increment the debug flag. 178 */ 179 debug++; 180 break; 181 } else { 182 argc--; 183 argv++; 184 stmp = argv[0]; 185 } 186 if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 187 fprintf(stderr, 188 "bootpd: invalid debug level\n"); 189 break; 190 } 191 debug = n; 192 break; 193 194 case 'f': /* config file */ 195 if (argv[0][2]) { 196 stmp = &(argv[0][2]); 197 } else { 198 argc--; 199 argv++; 200 stmp = argv[0]; 201 } 202 bootptab = stmp; 203 break; 204 205 default: 206 fprintf(stderr, "bootpd: unknown switch: -%c\n", 207 argv[0][1]); 208 usage(); 209 break; 210 } 211 } 212 213 /* Get the timezone. */ 214 tzone_init(); 215 216 /* Allocate hash tables. */ 217 rdtab_init(); 218 219 /* 220 * Read the bootptab file. 221 */ 222 readtab(1); /* force read */ 223 224 /* Set the cwd (i.e. to /tftpboot) */ 225 if (chdir_path) { 226 if (chdir(chdir_path) < 0) 227 report(LOG_ERR, "%s: chdir failed", chdir_path); 228 } 229 /* If there are host names on the command line, do only those. */ 230 if (argc > 0) { 231 unsigned int tlen, hashcode; 232 233 while (argc) { 234 tlen = strlen(argv[0]); 235 hashcode = hash_HashFunction((u_char *)argv[0], tlen); 236 hp = (struct host *) hash_Lookup(nmhashtable, 237 hashcode, 238 nmcmp, argv[0]); 239 if (!hp) { 240 printf("%s: no matching entry\n", argv[0]); 241 exit(1); 242 } 243 if (!hp->flags.exten_file) { 244 printf("%s: no extension file\n", argv[0]); 245 exit(1); 246 } 247 mktagfile(hp); 248 argv++; 249 argc--; 250 } 251 exit(0); 252 } 253 /* No host names specified. Do them all. */ 254 hp = (struct host *) hash_FirstEntry(nmhashtable); 255 while (hp != NULL) { 256 mktagfile(hp); 257 hp = (struct host *) hash_NextEntry(nmhashtable); 258 } 259 exit(0); 260 } 261 262 263 264 /* 265 * Make a "TAG 18" file for this host. 266 * (Insert the RFC1497 options.) 267 */ 268 269 static void 270 mktagfile(struct host *hp) 271 { 272 FILE *fp; 273 int bytesleft, len; 274 byte *vp; 275 276 if (!hp->flags.exten_file) 277 return; 278 279 vp = buffer; 280 bytesleft = BUFFERSIZE; 281 bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */ 282 vp += 4; 283 bytesleft -= 4; 284 285 /* 286 * The "extension file" options are appended by the following 287 * function (which is shared with bootpd.c). 288 */ 289 len = dovend_rfc1497(hp, vp, bytesleft); 290 vp += len; 291 bytesleft -= len; 292 293 if (bytesleft < 1) { 294 report(LOG_ERR, "%s: too much option data", 295 hp->exten_file->string); 296 return; 297 } 298 *vp++ = TAG_END; 299 bytesleft--; 300 301 /* Write the buffer to the extension file. */ 302 printf("Updating \"%s\"\n", hp->exten_file->string); 303 if ((fp = fopen(hp->exten_file->string, "w")) == NULL) { 304 report(LOG_ERR, "error opening \"%s\": %s", 305 hp->exten_file->string, get_errmsg()); 306 return; 307 } 308 len = vp - buffer; 309 if ((size_t)len != fwrite(buffer, 1, len, fp)) { 310 report(LOG_ERR, "write failed on \"%s\" : %s", 311 hp->exten_file->string, get_errmsg()); 312 } 313 fclose(fp); 314 315 } /* mktagfile */ 316 317 /* 318 * Local Variables: 319 * tab-width: 4 320 * c-indent-level: 4 321 * c-argdecl-indent: 4 322 * c-continued-statement-offset: 4 323 * c-continued-brace-offset: -4 324 * c-label-offset: -4 325 * c-brace-offset: 0 326 * End: 327 */ 328