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