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