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