1 1.1 gwr /************************************************************************ 2 1.1 gwr Copyright 1988, 1991 by Carnegie Mellon University 3 1.1 gwr 4 1.1 gwr All Rights Reserved 5 1.1 gwr 6 1.1 gwr Permission to use, copy, modify, and distribute this software and its 7 1.1 gwr documentation for any purpose and without fee is hereby granted, provided 8 1.1 gwr that the above copyright notice appear in all copies and that both that 9 1.1 gwr copyright notice and this permission notice appear in supporting 10 1.1 gwr documentation, and that the name of Carnegie Mellon University not be used 11 1.1 gwr in advertising or publicity pertaining to distribution of the software 12 1.1 gwr without specific, written prior permission. 13 1.1 gwr 14 1.1 gwr CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 15 1.1 gwr SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 16 1.1 gwr IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 17 1.1 gwr DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 1.1 gwr PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 1.1 gwr ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 1.1 gwr SOFTWARE. 21 1.1 gwr ************************************************************************/ 22 1.1 gwr 23 1.4 lukem #include <sys/cdefs.h> 24 1.1 gwr #ifndef lint 25 1.11 sevan __RCSID("$NetBSD: bootpef.c,v 1.11 2017/05/04 16:26:09 sevan Exp $"); 26 1.1 gwr #endif 27 1.1 gwr 28 1.1 gwr 29 1.1 gwr /* 30 1.1 gwr * bootpef - BOOTP Extension File generator 31 1.1 gwr * Makes an "Extension File" for each host entry that 32 1.1 gwr * defines an and Extension File. (See RFC1497, tag 18.) 33 1.1 gwr * 34 1.1 gwr * HISTORY 35 1.1 gwr * See ./Changes 36 1.1 gwr * 37 1.1 gwr * BUGS 38 1.1 gwr * See ./ToDo 39 1.1 gwr */ 40 1.1 gwr 41 1.1 gwr 43 1.1 gwr 44 1.1 gwr #include <stdarg.h> 45 1.1 gwr 46 1.1 gwr #include <sys/types.h> 47 1.1 gwr #include <sys/time.h> 48 1.1 gwr 49 1.1 gwr #include <netinet/in.h> 50 1.1 gwr #include <arpa/inet.h> /* inet_ntoa */ 51 1.1 gwr 52 1.1 gwr #ifndef NO_UNISTD 53 1.1 gwr #include <unistd.h> 54 1.1 gwr #endif 55 1.1 gwr #include <stdlib.h> 56 1.1 gwr #include <stdio.h> 57 1.7 tls #include <string.h> 58 1.1 gwr #include <strings.h> 59 1.1 gwr #include <errno.h> 60 1.1 gwr #include <ctype.h> 61 1.1 gwr #include <syslog.h> 62 1.1 gwr 63 1.1 gwr #include "bootp.h" 64 1.1 gwr #include "hash.h" 65 1.1 gwr #include "hwaddr.h" 66 1.1 gwr #include "bootpd.h" 67 1.1 gwr #include "dovend.h" 68 1.1 gwr #include "readfile.h" 69 1.1 gwr #include "report.h" 70 1.1 gwr #include "tzone.h" 71 1.1 gwr #include "patchlevel.h" 72 1.1 gwr 73 1.1 gwr #define BUFFERSIZE 0x4000 74 1.1 gwr 75 1.1 gwr #ifndef CONFIG_FILE 76 1.1 gwr #define CONFIG_FILE "/etc/bootptab" 77 1.1 gwr #endif 78 1.1 gwr 79 1.1 gwr 81 1.1 gwr 82 1.1 gwr /* 83 1.1 gwr * Externals, forward declarations, and global variables 84 1.5 wiz */ 85 1.10 joerg 86 1.1 gwr static void mktagfile(struct host *); 87 1.1 gwr __dead static void usage(void); 88 1.1 gwr 89 1.1 gwr 90 1.1 gwr /* 91 1.1 gwr * General 92 1.8 xtraeme */ 93 1.1 gwr 94 1.1 gwr const char *progname; 95 1.1 gwr char *chdir_path; 96 1.1 gwr int debug = 0; /* Debugging flag (level) */ 97 1.1 gwr byte *buffer; 98 1.1 gwr 99 1.1 gwr /* 100 1.1 gwr * Globals below are associated with the bootp database file (bootptab). 101 1.8 xtraeme */ 102 1.1 gwr 103 1.1 gwr const char *bootptab = CONFIG_FILE; 104 1.1 gwr 105 1.1 gwr 107 1.1 gwr /* 108 1.5 wiz * Print "usage" message and exit 109 1.1 gwr */ 110 1.1 gwr static void 111 1.6 hira usage(void) 112 1.6 hira { 113 1.1 gwr fprintf(stderr, 114 1.1 gwr "usage: %s [-c chdir] [-d level] [-f configfile] [host ...]\n", 115 1.1 gwr getprogname()); 116 1.1 gwr fprintf(stderr, "\t -c n\tset current directory\n"); 117 1.1 gwr fprintf(stderr, "\t -d n\tset debug level\n"); 118 1.1 gwr fprintf(stderr, "\t -f n\tconfig file name\n"); 119 1.1 gwr exit(1); 120 1.1 gwr } 121 1.1 gwr 122 1.1 gwr 123 1.1 gwr /* 124 1.4 lukem * Initialization such as command-line processing is done and then the 125 1.5 wiz * main server loop is started. 126 1.1 gwr */ 127 1.1 gwr int 128 1.1 gwr main(int argc, char **argv) 129 1.1 gwr { 130 1.1 gwr struct host *hp; 131 1.1 gwr char *stmp; 132 1.1 gwr int n; 133 1.1 gwr 134 1.1 gwr progname = strrchr(argv[0], '/'); 135 1.1 gwr if (progname) progname++; 136 1.1 gwr else progname = argv[0]; 137 1.1 gwr 138 1.1 gwr /* Get work space for making tag 18 files. */ 139 1.1 gwr buffer = (byte *) malloc(BUFFERSIZE); 140 1.1 gwr if (!buffer) { 141 1.1 gwr report(LOG_ERR, "malloc failed"); 142 1.1 gwr exit(1); 143 1.1 gwr } 144 1.1 gwr /* 145 1.1 gwr * Set defaults that might be changed by option switches. 146 1.1 gwr */ 147 1.1 gwr stmp = NULL; 148 1.1 gwr 149 1.1 gwr /* 150 1.1 gwr * Read switches. 151 1.1 gwr */ 152 1.1 gwr for (argc--, argv++; argc > 0; argc--, argv++) { 153 1.1 gwr if (argv[0][0] != '-') 154 1.1 gwr break; 155 1.1 gwr switch (argv[0][1]) { 156 1.1 gwr 157 1.1 gwr case 'c': /* chdir_path */ 158 1.1 gwr if (argv[0][2]) { 159 1.1 gwr stmp = &(argv[0][2]); 160 1.1 gwr } else { 161 1.1 gwr argc--; 162 1.1 gwr argv++; 163 1.1 gwr stmp = argv[0]; 164 1.1 gwr } 165 1.1 gwr if (!stmp || (stmp[0] != '/')) { 166 1.1 gwr fprintf(stderr, 167 1.1 gwr "bootpd: invalid chdir specification\n"); 168 1.1 gwr break; 169 1.1 gwr } 170 1.1 gwr chdir_path = stmp; 171 1.1 gwr break; 172 1.1 gwr 173 1.1 gwr case 'd': /* debug */ 174 1.1 gwr if (argv[0][2]) { 175 1.1 gwr stmp = &(argv[0][2]); 176 1.1 gwr } else if (argv[1] && argv[1][0] == '-') { 177 1.1 gwr /* 178 1.1 gwr * Backwards-compatible behavior: 179 1.1 gwr * no parameter, so just increment the debug flag. 180 1.1 gwr */ 181 1.1 gwr debug++; 182 1.1 gwr break; 183 1.1 gwr } else { 184 1.1 gwr argc--; 185 1.1 gwr argv++; 186 1.1 gwr stmp = argv[0]; 187 1.1 gwr } 188 1.1 gwr if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) { 189 1.1 gwr fprintf(stderr, 190 1.1 gwr "bootpd: invalid debug level\n"); 191 1.1 gwr break; 192 1.1 gwr } 193 1.1 gwr debug = n; 194 1.1 gwr break; 195 1.1 gwr 196 1.1 gwr case 'f': /* config file */ 197 1.1 gwr if (argv[0][2]) { 198 1.1 gwr stmp = &(argv[0][2]); 199 1.1 gwr } else { 200 1.1 gwr argc--; 201 1.1 gwr argv++; 202 1.1 gwr stmp = argv[0]; 203 1.1 gwr } 204 1.1 gwr bootptab = stmp; 205 1.1 gwr break; 206 1.1 gwr 207 1.1 gwr default: 208 1.1 gwr fprintf(stderr, "bootpd: unknown switch: -%c\n", 209 1.1 gwr argv[0][1]); 210 1.1 gwr usage(); 211 1.1 gwr break; 212 1.1 gwr } 213 1.1 gwr } 214 1.1 gwr 215 1.1 gwr /* Get the timezone. */ 216 1.1 gwr tzone_init(); 217 1.1 gwr 218 1.1 gwr /* Allocate hash tables. */ 219 1.1 gwr rdtab_init(); 220 1.1 gwr 221 1.1 gwr /* 222 1.1 gwr * Read the bootptab file. 223 1.1 gwr */ 224 1.1 gwr readtab(1); /* force read */ 225 1.1 gwr 226 1.1 gwr /* Set the cwd (i.e. to /tftpboot) */ 227 1.1 gwr if (chdir_path) { 228 1.1 gwr if (chdir(chdir_path) < 0) 229 1.1 gwr report(LOG_ERR, "%s: chdir failed", chdir_path); 230 1.1 gwr } 231 1.1 gwr /* If there are host names on the command line, do only those. */ 232 1.1 gwr if (argc > 0) { 233 1.1 gwr unsigned int tlen, hashcode; 234 1.1 gwr 235 1.1 gwr while (argc) { 236 1.1 gwr tlen = strlen(argv[0]); 237 1.1 gwr hashcode = hash_HashFunction((u_char *)argv[0], tlen); 238 1.1 gwr hp = (struct host *) hash_Lookup(nmhashtable, 239 1.1 gwr hashcode, 240 1.1 gwr nmcmp, argv[0]); 241 1.1 gwr if (!hp) { 242 1.1 gwr printf("%s: no matching entry\n", argv[0]); 243 1.1 gwr exit(1); 244 1.1 gwr } 245 1.1 gwr if (!hp->flags.exten_file) { 246 1.1 gwr printf("%s: no extension file\n", argv[0]); 247 1.1 gwr exit(1); 248 1.1 gwr } 249 1.1 gwr mktagfile(hp); 250 1.1 gwr argv++; 251 1.1 gwr argc--; 252 1.1 gwr } 253 1.1 gwr exit(0); 254 1.1 gwr } 255 1.1 gwr /* No host names specified. Do them all. */ 256 1.1 gwr hp = (struct host *) hash_FirstEntry(nmhashtable); 257 1.1 gwr while (hp != NULL) { 258 1.4 lukem mktagfile(hp); 259 1.1 gwr hp = (struct host *) hash_NextEntry(nmhashtable); 260 1.1 gwr } 261 1.1 gwr exit(0); 262 1.1 gwr } 263 1.1 gwr 264 1.1 gwr 266 1.1 gwr 267 1.1 gwr /* 268 1.1 gwr * Make a "TAG 18" file for this host. 269 1.5 wiz * (Insert the RFC1497 options.) 270 1.1 gwr */ 271 1.1 gwr 272 1.1 gwr static void 273 1.1 gwr mktagfile(struct host *hp) 274 1.1 gwr { 275 1.1 gwr FILE *fp; 276 1.1 gwr int bytesleft, len; 277 1.1 gwr byte *vp; 278 1.1 gwr 279 1.1 gwr if (!hp->flags.exten_file) 280 1.1 gwr return; 281 1.1 gwr 282 1.1 gwr vp = buffer; 283 1.1 gwr bytesleft = BUFFERSIZE; 284 1.1 gwr bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */ 285 1.1 gwr vp += 4; 286 1.1 gwr bytesleft -= 4; 287 1.1 gwr 288 1.1 gwr /* 289 1.1 gwr * The "extension file" options are appended by the following 290 1.1 gwr * function (which is shared with bootpd.c). 291 1.1 gwr */ 292 1.1 gwr len = dovend_rfc1497(hp, vp, bytesleft); 293 1.1 gwr vp += len; 294 1.1 gwr bytesleft -= len; 295 1.1 gwr 296 1.1 gwr if (bytesleft < 1) { 297 1.1 gwr report(LOG_ERR, "%s: too much option data", 298 1.1 gwr hp->exten_file->string); 299 1.1 gwr return; 300 1.1 gwr } 301 1.1 gwr *vp++ = TAG_END; 302 1.1 gwr bytesleft--; 303 1.1 gwr 304 1.1 gwr /* Write the buffer to the extension file. */ 305 1.1 gwr printf("Updating \"%s\"\n", hp->exten_file->string); 306 1.1 gwr if ((fp = fopen(hp->exten_file->string, "w")) == NULL) { 307 1.1 gwr report(LOG_ERR, "error opening \"%s\": %s", 308 1.9 lukem hp->exten_file->string, get_errmsg()); 309 1.1 gwr return; 310 1.1 gwr } 311 1.1 gwr len = vp - buffer; 312 1.1 gwr if ((size_t)len != fwrite(buffer, 1, len, fp)) { 313 1.1 gwr report(LOG_ERR, "write failed on \"%s\" : %s", 314 1.4 lukem hp->exten_file->string, get_errmsg()); 315 1.1 gwr } 316 1.1 gwr fclose(fp); 317 1.1 gwr 318 1.1 gwr } /* mktagfile */ 319 1.1 gwr 320 1.1 gwr /* 321 1.1 gwr * Local Variables: 322 1.1 gwr * tab-width: 4 323 1.1 gwr * c-indent-level: 4 324 1.1 gwr * c-argdecl-indent: 4 325 1.1 gwr * c-continued-statement-offset: 4 326 1.1 gwr * c-continued-brace-offset: -4 327 * c-label-offset: -4 328 * c-brace-offset: 0 329 * End: 330 */ 331