15e9d01f2Sgwr /************************************************************************
25e9d01f2Sgwr Copyright 1988, 1991 by Carnegie Mellon University
35e9d01f2Sgwr
45e9d01f2Sgwr All Rights Reserved
55e9d01f2Sgwr
65e9d01f2Sgwr Permission to use, copy, modify, and distribute this software and its
75e9d01f2Sgwr documentation for any purpose and without fee is hereby granted, provided
85e9d01f2Sgwr that the above copyright notice appear in all copies and that both that
95e9d01f2Sgwr copyright notice and this permission notice appear in supporting
105e9d01f2Sgwr documentation, and that the name of Carnegie Mellon University not be used
115e9d01f2Sgwr in advertising or publicity pertaining to distribution of the software
125e9d01f2Sgwr without specific, written prior permission.
135e9d01f2Sgwr
145e9d01f2Sgwr CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
155e9d01f2Sgwr SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
165e9d01f2Sgwr IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
175e9d01f2Sgwr DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
185e9d01f2Sgwr PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
195e9d01f2Sgwr ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
205e9d01f2Sgwr SOFTWARE.
215e9d01f2Sgwr ************************************************************************/
225e9d01f2Sgwr
239493bb79Slukem #include <sys/cdefs.h>
245e9d01f2Sgwr #ifndef lint
25*f7a3540eSsevan __RCSID("$NetBSD: bootpef.c,v 1.11 2017/05/04 16:26:09 sevan Exp $");
265e9d01f2Sgwr #endif
275e9d01f2Sgwr
285e9d01f2Sgwr
295e9d01f2Sgwr /*
305e9d01f2Sgwr * bootpef - BOOTP Extension File generator
315e9d01f2Sgwr * Makes an "Extension File" for each host entry that
325e9d01f2Sgwr * defines an and Extension File. (See RFC1497, tag 18.)
335e9d01f2Sgwr *
345e9d01f2Sgwr * HISTORY
355e9d01f2Sgwr * See ./Changes
365e9d01f2Sgwr *
375e9d01f2Sgwr * BUGS
385e9d01f2Sgwr * See ./ToDo
395e9d01f2Sgwr */
405e9d01f2Sgwr
415e9d01f2Sgwr
425e9d01f2Sgwr
435e9d01f2Sgwr #include <stdarg.h>
445e9d01f2Sgwr
455e9d01f2Sgwr #include <sys/types.h>
465e9d01f2Sgwr #include <sys/time.h>
475e9d01f2Sgwr
485e9d01f2Sgwr #include <netinet/in.h>
495e9d01f2Sgwr #include <arpa/inet.h> /* inet_ntoa */
505e9d01f2Sgwr
515e9d01f2Sgwr #ifndef NO_UNISTD
525e9d01f2Sgwr #include <unistd.h>
535e9d01f2Sgwr #endif
545e9d01f2Sgwr #include <stdlib.h>
555e9d01f2Sgwr #include <stdio.h>
565e9d01f2Sgwr #include <string.h>
57be45f4d0Stls #include <strings.h>
585e9d01f2Sgwr #include <errno.h>
595e9d01f2Sgwr #include <ctype.h>
605e9d01f2Sgwr #include <syslog.h>
615e9d01f2Sgwr
625e9d01f2Sgwr #include "bootp.h"
635e9d01f2Sgwr #include "hash.h"
645e9d01f2Sgwr #include "hwaddr.h"
655e9d01f2Sgwr #include "bootpd.h"
665e9d01f2Sgwr #include "dovend.h"
675e9d01f2Sgwr #include "readfile.h"
685e9d01f2Sgwr #include "report.h"
695e9d01f2Sgwr #include "tzone.h"
705e9d01f2Sgwr #include "patchlevel.h"
715e9d01f2Sgwr
725e9d01f2Sgwr #define BUFFERSIZE 0x4000
735e9d01f2Sgwr
745e9d01f2Sgwr #ifndef CONFIG_FILE
755e9d01f2Sgwr #define CONFIG_FILE "/etc/bootptab"
765e9d01f2Sgwr #endif
775e9d01f2Sgwr
785e9d01f2Sgwr
795e9d01f2Sgwr
805e9d01f2Sgwr /*
815e9d01f2Sgwr * Externals, forward declarations, and global variables
825e9d01f2Sgwr */
835e9d01f2Sgwr
84131109e4Swiz static void mktagfile(struct host *);
85dccf569eSjoerg __dead static void usage(void);
865e9d01f2Sgwr
875e9d01f2Sgwr
885e9d01f2Sgwr /*
895e9d01f2Sgwr * General
905e9d01f2Sgwr */
915e9d01f2Sgwr
92c8f61d2bSxtraeme const char *progname;
935e9d01f2Sgwr char *chdir_path;
945e9d01f2Sgwr int debug = 0; /* Debugging flag (level) */
955e9d01f2Sgwr byte *buffer;
965e9d01f2Sgwr
975e9d01f2Sgwr /*
985e9d01f2Sgwr * Globals below are associated with the bootp database file (bootptab).
995e9d01f2Sgwr */
1005e9d01f2Sgwr
101c8f61d2bSxtraeme const char *bootptab = CONFIG_FILE;
1025e9d01f2Sgwr
1035e9d01f2Sgwr
1045e9d01f2Sgwr /*
1055e9d01f2Sgwr * Print "usage" message and exit
1065e9d01f2Sgwr */
1075e9d01f2Sgwr static void
usage(void)108131109e4Swiz usage(void)
1095e9d01f2Sgwr {
1105e9d01f2Sgwr fprintf(stderr,
11175febfe0Shira "usage: %s [-c chdir] [-d level] [-f configfile] [host ...]\n",
11275febfe0Shira getprogname());
1135e9d01f2Sgwr fprintf(stderr, "\t -c n\tset current directory\n");
1145e9d01f2Sgwr fprintf(stderr, "\t -d n\tset debug level\n");
1155e9d01f2Sgwr fprintf(stderr, "\t -f n\tconfig file name\n");
1165e9d01f2Sgwr exit(1);
1175e9d01f2Sgwr }
1185e9d01f2Sgwr
1195e9d01f2Sgwr
1205e9d01f2Sgwr /*
1215e9d01f2Sgwr * Initialization such as command-line processing is done and then the
1225e9d01f2Sgwr * main server loop is started.
1235e9d01f2Sgwr */
1249493bb79Slukem int
main(int argc,char ** argv)125131109e4Swiz main(int argc, char **argv)
1265e9d01f2Sgwr {
1275e9d01f2Sgwr struct host *hp;
1285e9d01f2Sgwr char *stmp;
1295e9d01f2Sgwr int n;
1305e9d01f2Sgwr
1315e9d01f2Sgwr progname = strrchr(argv[0], '/');
1325e9d01f2Sgwr if (progname) progname++;
1335e9d01f2Sgwr else progname = argv[0];
1345e9d01f2Sgwr
1355e9d01f2Sgwr /* Get work space for making tag 18 files. */
1365e9d01f2Sgwr buffer = (byte *) malloc(BUFFERSIZE);
1375e9d01f2Sgwr if (!buffer) {
1385e9d01f2Sgwr report(LOG_ERR, "malloc failed");
1395e9d01f2Sgwr exit(1);
1405e9d01f2Sgwr }
1415e9d01f2Sgwr /*
1425e9d01f2Sgwr * Set defaults that might be changed by option switches.
1435e9d01f2Sgwr */
1445e9d01f2Sgwr stmp = NULL;
1455e9d01f2Sgwr
1465e9d01f2Sgwr /*
1475e9d01f2Sgwr * Read switches.
1485e9d01f2Sgwr */
1495e9d01f2Sgwr for (argc--, argv++; argc > 0; argc--, argv++) {
1505e9d01f2Sgwr if (argv[0][0] != '-')
1515e9d01f2Sgwr break;
1525e9d01f2Sgwr switch (argv[0][1]) {
1535e9d01f2Sgwr
1545e9d01f2Sgwr case 'c': /* chdir_path */
1555e9d01f2Sgwr if (argv[0][2]) {
1565e9d01f2Sgwr stmp = &(argv[0][2]);
1575e9d01f2Sgwr } else {
1585e9d01f2Sgwr argc--;
1595e9d01f2Sgwr argv++;
1605e9d01f2Sgwr stmp = argv[0];
1615e9d01f2Sgwr }
1625e9d01f2Sgwr if (!stmp || (stmp[0] != '/')) {
1635e9d01f2Sgwr fprintf(stderr,
1645e9d01f2Sgwr "bootpd: invalid chdir specification\n");
1655e9d01f2Sgwr break;
1665e9d01f2Sgwr }
1675e9d01f2Sgwr chdir_path = stmp;
1685e9d01f2Sgwr break;
1695e9d01f2Sgwr
1705e9d01f2Sgwr case 'd': /* debug */
1715e9d01f2Sgwr if (argv[0][2]) {
1725e9d01f2Sgwr stmp = &(argv[0][2]);
1735e9d01f2Sgwr } else if (argv[1] && argv[1][0] == '-') {
1745e9d01f2Sgwr /*
1755e9d01f2Sgwr * Backwards-compatible behavior:
1765e9d01f2Sgwr * no parameter, so just increment the debug flag.
1775e9d01f2Sgwr */
1785e9d01f2Sgwr debug++;
1795e9d01f2Sgwr break;
1805e9d01f2Sgwr } else {
1815e9d01f2Sgwr argc--;
1825e9d01f2Sgwr argv++;
1835e9d01f2Sgwr stmp = argv[0];
1845e9d01f2Sgwr }
1855e9d01f2Sgwr if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
1865e9d01f2Sgwr fprintf(stderr,
1875e9d01f2Sgwr "bootpd: invalid debug level\n");
1885e9d01f2Sgwr break;
1895e9d01f2Sgwr }
1905e9d01f2Sgwr debug = n;
1915e9d01f2Sgwr break;
1925e9d01f2Sgwr
1935e9d01f2Sgwr case 'f': /* config file */
1945e9d01f2Sgwr if (argv[0][2]) {
1955e9d01f2Sgwr stmp = &(argv[0][2]);
1965e9d01f2Sgwr } else {
1975e9d01f2Sgwr argc--;
1985e9d01f2Sgwr argv++;
1995e9d01f2Sgwr stmp = argv[0];
2005e9d01f2Sgwr }
2015e9d01f2Sgwr bootptab = stmp;
2025e9d01f2Sgwr break;
2035e9d01f2Sgwr
2045e9d01f2Sgwr default:
2055e9d01f2Sgwr fprintf(stderr, "bootpd: unknown switch: -%c\n",
2065e9d01f2Sgwr argv[0][1]);
2075e9d01f2Sgwr usage();
2085e9d01f2Sgwr break;
2095e9d01f2Sgwr }
2105e9d01f2Sgwr }
2115e9d01f2Sgwr
2125e9d01f2Sgwr /* Get the timezone. */
2135e9d01f2Sgwr tzone_init();
2145e9d01f2Sgwr
2155e9d01f2Sgwr /* Allocate hash tables. */
2165e9d01f2Sgwr rdtab_init();
2175e9d01f2Sgwr
2185e9d01f2Sgwr /*
2195e9d01f2Sgwr * Read the bootptab file.
2205e9d01f2Sgwr */
2215e9d01f2Sgwr readtab(1); /* force read */
2225e9d01f2Sgwr
2235e9d01f2Sgwr /* Set the cwd (i.e. to /tftpboot) */
2245e9d01f2Sgwr if (chdir_path) {
2255e9d01f2Sgwr if (chdir(chdir_path) < 0)
2265e9d01f2Sgwr report(LOG_ERR, "%s: chdir failed", chdir_path);
2275e9d01f2Sgwr }
2285e9d01f2Sgwr /* If there are host names on the command line, do only those. */
2295e9d01f2Sgwr if (argc > 0) {
2305e9d01f2Sgwr unsigned int tlen, hashcode;
2315e9d01f2Sgwr
2325e9d01f2Sgwr while (argc) {
2335e9d01f2Sgwr tlen = strlen(argv[0]);
2345e9d01f2Sgwr hashcode = hash_HashFunction((u_char *)argv[0], tlen);
2355e9d01f2Sgwr hp = (struct host *) hash_Lookup(nmhashtable,
2365e9d01f2Sgwr hashcode,
2375e9d01f2Sgwr nmcmp, argv[0]);
2385e9d01f2Sgwr if (!hp) {
2395e9d01f2Sgwr printf("%s: no matching entry\n", argv[0]);
2405e9d01f2Sgwr exit(1);
2415e9d01f2Sgwr }
2425e9d01f2Sgwr if (!hp->flags.exten_file) {
2435e9d01f2Sgwr printf("%s: no extension file\n", argv[0]);
2445e9d01f2Sgwr exit(1);
2455e9d01f2Sgwr }
2465e9d01f2Sgwr mktagfile(hp);
2475e9d01f2Sgwr argv++;
2485e9d01f2Sgwr argc--;
2495e9d01f2Sgwr }
2505e9d01f2Sgwr exit(0);
2515e9d01f2Sgwr }
2525e9d01f2Sgwr /* No host names specified. Do them all. */
2535e9d01f2Sgwr hp = (struct host *) hash_FirstEntry(nmhashtable);
2545e9d01f2Sgwr while (hp != NULL) {
2555e9d01f2Sgwr mktagfile(hp);
2565e9d01f2Sgwr hp = (struct host *) hash_NextEntry(nmhashtable);
2575e9d01f2Sgwr }
2589493bb79Slukem exit(0);
2595e9d01f2Sgwr }
2605e9d01f2Sgwr
2615e9d01f2Sgwr
2625e9d01f2Sgwr
2635e9d01f2Sgwr /*
2645e9d01f2Sgwr * Make a "TAG 18" file for this host.
2655e9d01f2Sgwr * (Insert the RFC1497 options.)
2665e9d01f2Sgwr */
2675e9d01f2Sgwr
2685e9d01f2Sgwr static void
mktagfile(struct host * hp)269131109e4Swiz mktagfile(struct host *hp)
2705e9d01f2Sgwr {
2715e9d01f2Sgwr FILE *fp;
2725e9d01f2Sgwr int bytesleft, len;
2735e9d01f2Sgwr byte *vp;
2745e9d01f2Sgwr
2755e9d01f2Sgwr if (!hp->flags.exten_file)
2765e9d01f2Sgwr return;
2775e9d01f2Sgwr
2785e9d01f2Sgwr vp = buffer;
2795e9d01f2Sgwr bytesleft = BUFFERSIZE;
2805e9d01f2Sgwr bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
2815e9d01f2Sgwr vp += 4;
2825e9d01f2Sgwr bytesleft -= 4;
2835e9d01f2Sgwr
2845e9d01f2Sgwr /*
2855e9d01f2Sgwr * The "extension file" options are appended by the following
2865e9d01f2Sgwr * function (which is shared with bootpd.c).
2875e9d01f2Sgwr */
2885e9d01f2Sgwr len = dovend_rfc1497(hp, vp, bytesleft);
2895e9d01f2Sgwr vp += len;
2905e9d01f2Sgwr bytesleft -= len;
2915e9d01f2Sgwr
2925e9d01f2Sgwr if (bytesleft < 1) {
2935e9d01f2Sgwr report(LOG_ERR, "%s: too much option data",
2945e9d01f2Sgwr hp->exten_file->string);
2955e9d01f2Sgwr return;
2965e9d01f2Sgwr }
2975e9d01f2Sgwr *vp++ = TAG_END;
2985e9d01f2Sgwr bytesleft--;
2995e9d01f2Sgwr
3005e9d01f2Sgwr /* Write the buffer to the extension file. */
3015e9d01f2Sgwr printf("Updating \"%s\"\n", hp->exten_file->string);
3025e9d01f2Sgwr if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
3035e9d01f2Sgwr report(LOG_ERR, "error opening \"%s\": %s",
3045e9d01f2Sgwr hp->exten_file->string, get_errmsg());
3055e9d01f2Sgwr return;
3065e9d01f2Sgwr }
3075e9d01f2Sgwr len = vp - buffer;
3087affd655Slukem if ((size_t)len != fwrite(buffer, 1, len, fp)) {
3095e9d01f2Sgwr report(LOG_ERR, "write failed on \"%s\" : %s",
3105e9d01f2Sgwr hp->exten_file->string, get_errmsg());
3115e9d01f2Sgwr }
3125e9d01f2Sgwr fclose(fp);
3135e9d01f2Sgwr
3149493bb79Slukem } /* mktagfile */
3155e9d01f2Sgwr
3165e9d01f2Sgwr /*
3175e9d01f2Sgwr * Local Variables:
3185e9d01f2Sgwr * tab-width: 4
3195e9d01f2Sgwr * c-indent-level: 4
3205e9d01f2Sgwr * c-argdecl-indent: 4
3215e9d01f2Sgwr * c-continued-statement-offset: 4
3225e9d01f2Sgwr * c-continued-brace-offset: -4
3235e9d01f2Sgwr * c-label-offset: -4
3245e9d01f2Sgwr * c-brace-offset: 0
3255e9d01f2Sgwr * End:
3265e9d01f2Sgwr */
327