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