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