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