144099b7bSPaul Traina /************************************************************************
244099b7bSPaul Traina Copyright 1988, 1991 by Carnegie Mellon University
344099b7bSPaul Traina
444099b7bSPaul Traina All Rights Reserved
544099b7bSPaul Traina
644099b7bSPaul Traina Permission to use, copy, modify, and distribute this software and its
744099b7bSPaul Traina documentation for any purpose and without fee is hereby granted, provided
844099b7bSPaul Traina that the above copyright notice appear in all copies and that both that
944099b7bSPaul Traina copyright notice and this permission notice appear in supporting
1044099b7bSPaul Traina documentation, and that the name of Carnegie Mellon University not be used
1144099b7bSPaul Traina in advertising or publicity pertaining to distribution of the software
1244099b7bSPaul Traina without specific, written prior permission.
1344099b7bSPaul Traina
1444099b7bSPaul Traina CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1544099b7bSPaul Traina SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1644099b7bSPaul Traina IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
1744099b7bSPaul Traina DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1844099b7bSPaul Traina PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1944099b7bSPaul Traina ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2044099b7bSPaul Traina SOFTWARE.
21148531efSWolfram Schneider
2244099b7bSPaul Traina ************************************************************************/
2344099b7bSPaul Traina
2444099b7bSPaul Traina /*
2544099b7bSPaul Traina * bootpef - BOOTP Extension File generator
2644099b7bSPaul Traina * Makes an "Extension File" for each host entry that
2744099b7bSPaul Traina * defines an and Extension File. (See RFC1497, tag 18.)
2844099b7bSPaul Traina *
2944099b7bSPaul Traina * HISTORY
3044099b7bSPaul Traina * See ./Changes
3144099b7bSPaul Traina *
3244099b7bSPaul Traina * BUGS
3344099b7bSPaul Traina * See ./ToDo
3444099b7bSPaul Traina */
3544099b7bSPaul Traina
3644099b7bSPaul Traina
3744099b7bSPaul Traina
3844099b7bSPaul Traina #include <stdarg.h>
3944099b7bSPaul Traina
4044099b7bSPaul Traina #include <sys/types.h>
4144099b7bSPaul Traina #include <sys/time.h>
4244099b7bSPaul Traina
4344099b7bSPaul Traina #include <netinet/in.h>
4444099b7bSPaul Traina #include <arpa/inet.h> /* inet_ntoa */
4544099b7bSPaul Traina
4644099b7bSPaul Traina #ifndef NO_UNISTD
4744099b7bSPaul Traina #include <unistd.h>
4844099b7bSPaul Traina #endif
4944099b7bSPaul Traina #include <stdlib.h>
5044099b7bSPaul Traina #include <stdio.h>
5144099b7bSPaul Traina #include <string.h>
5244099b7bSPaul Traina #include <errno.h>
5344099b7bSPaul Traina #include <ctype.h>
5444099b7bSPaul Traina #include <syslog.h>
5544099b7bSPaul Traina
5644099b7bSPaul Traina #include "bootp.h"
5744099b7bSPaul Traina #include "hash.h"
5844099b7bSPaul Traina #include "hwaddr.h"
5944099b7bSPaul Traina #include "bootpd.h"
6044099b7bSPaul Traina #include "dovend.h"
6144099b7bSPaul Traina #include "readfile.h"
6244099b7bSPaul Traina #include "report.h"
6344099b7bSPaul Traina #include "tzone.h"
6444099b7bSPaul Traina #include "patchlevel.h"
6544099b7bSPaul Traina
6644099b7bSPaul Traina #define BUFFERSIZE 0x4000
6744099b7bSPaul Traina
6844099b7bSPaul Traina #ifndef CONFIG_FILE
6944099b7bSPaul Traina #define CONFIG_FILE "/etc/bootptab"
7044099b7bSPaul Traina #endif
7144099b7bSPaul Traina
7244099b7bSPaul Traina
7344099b7bSPaul Traina
7444099b7bSPaul Traina /*
7544099b7bSPaul Traina * Externals, forward declarations, and global variables
7644099b7bSPaul Traina */
7744099b7bSPaul Traina
78f74779bdSAlfred Perlstein static void mktagfile(struct host *);
79*69c0fb2aSAlfonso Gregory static void usage(void) __dead2;
8044099b7bSPaul Traina
8144099b7bSPaul Traina /*
8244099b7bSPaul Traina * General
8344099b7bSPaul Traina */
8444099b7bSPaul Traina
8544099b7bSPaul Traina char *progname;
8644099b7bSPaul Traina char *chdir_path;
8744099b7bSPaul Traina int debug = 0; /* Debugging flag (level) */
8844099b7bSPaul Traina byte *buffer;
8944099b7bSPaul Traina
9044099b7bSPaul Traina /*
9144099b7bSPaul Traina * Globals below are associated with the bootp database file (bootptab).
9244099b7bSPaul Traina */
9344099b7bSPaul Traina
9444099b7bSPaul Traina char *bootptab = CONFIG_FILE;
9544099b7bSPaul Traina
9644099b7bSPaul Traina
9744099b7bSPaul Traina /*
9844099b7bSPaul Traina * Print "usage" message and exit
9944099b7bSPaul Traina */
10044099b7bSPaul Traina static void
usage(void)1018b356c88SJohn Baldwin usage(void)
10244099b7bSPaul Traina {
10344099b7bSPaul Traina fprintf(stderr,
10444099b7bSPaul Traina "usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
10544099b7bSPaul Traina fprintf(stderr, "\t -c n\tset current directory\n");
10644099b7bSPaul Traina fprintf(stderr, "\t -d n\tset debug level\n");
10744099b7bSPaul Traina fprintf(stderr, "\t -f n\tconfig file name\n");
10844099b7bSPaul Traina exit(1);
10944099b7bSPaul Traina }
11044099b7bSPaul Traina
11144099b7bSPaul Traina
11244099b7bSPaul Traina /*
11344099b7bSPaul Traina * Initialization such as command-line processing is done and then the
11444099b7bSPaul Traina * main server loop is started.
11544099b7bSPaul Traina */
11685966371SWarner Losh int
main(int argc,char ** argv)1178b356c88SJohn Baldwin main(int argc, char **argv)
11844099b7bSPaul Traina {
11944099b7bSPaul Traina struct host *hp;
12044099b7bSPaul Traina char *stmp;
12144099b7bSPaul Traina int n;
12244099b7bSPaul Traina
12344099b7bSPaul Traina progname = strrchr(argv[0], '/');
12444099b7bSPaul Traina if (progname) progname++;
12544099b7bSPaul Traina else progname = argv[0];
12644099b7bSPaul Traina
12744099b7bSPaul Traina /* Get work space for making tag 18 files. */
12844099b7bSPaul Traina buffer = (byte *) malloc(BUFFERSIZE);
12944099b7bSPaul Traina if (!buffer) {
13044099b7bSPaul Traina report(LOG_ERR, "malloc failed");
13144099b7bSPaul Traina exit(1);
13244099b7bSPaul Traina }
13344099b7bSPaul Traina /*
13444099b7bSPaul Traina * Set defaults that might be changed by option switches.
13544099b7bSPaul Traina */
13644099b7bSPaul Traina stmp = NULL;
13744099b7bSPaul Traina
13844099b7bSPaul Traina /*
13944099b7bSPaul Traina * Read switches.
14044099b7bSPaul Traina */
14144099b7bSPaul Traina for (argc--, argv++; argc > 0; argc--, argv++) {
14244099b7bSPaul Traina if (argv[0][0] != '-')
14344099b7bSPaul Traina break;
14444099b7bSPaul Traina switch (argv[0][1]) {
14544099b7bSPaul Traina
14644099b7bSPaul Traina case 'c': /* chdir_path */
14744099b7bSPaul Traina if (argv[0][2]) {
14844099b7bSPaul Traina stmp = &(argv[0][2]);
14944099b7bSPaul Traina } else {
15044099b7bSPaul Traina argc--;
15144099b7bSPaul Traina argv++;
15244099b7bSPaul Traina stmp = argv[0];
15344099b7bSPaul Traina }
15444099b7bSPaul Traina if (!stmp || (stmp[0] != '/')) {
15544099b7bSPaul Traina fprintf(stderr,
15644099b7bSPaul Traina "bootpd: invalid chdir specification\n");
15744099b7bSPaul Traina break;
15844099b7bSPaul Traina }
15944099b7bSPaul Traina chdir_path = stmp;
16044099b7bSPaul Traina break;
16144099b7bSPaul Traina
16244099b7bSPaul Traina case 'd': /* debug */
16344099b7bSPaul Traina if (argv[0][2]) {
16444099b7bSPaul Traina stmp = &(argv[0][2]);
16544099b7bSPaul Traina } else if (argv[1] && argv[1][0] == '-') {
16644099b7bSPaul Traina /*
16744099b7bSPaul Traina * Backwards-compatible behavior:
16844099b7bSPaul Traina * no parameter, so just increment the debug flag.
16944099b7bSPaul Traina */
17044099b7bSPaul Traina debug++;
17144099b7bSPaul Traina break;
17244099b7bSPaul Traina } else {
17344099b7bSPaul Traina argc--;
17444099b7bSPaul Traina argv++;
17544099b7bSPaul Traina stmp = argv[0];
17644099b7bSPaul Traina }
17744099b7bSPaul Traina if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
17844099b7bSPaul Traina fprintf(stderr,
17944099b7bSPaul Traina "bootpd: invalid debug level\n");
18044099b7bSPaul Traina break;
18144099b7bSPaul Traina }
18244099b7bSPaul Traina debug = n;
18344099b7bSPaul Traina break;
18444099b7bSPaul Traina
18544099b7bSPaul Traina case 'f': /* config file */
18644099b7bSPaul Traina if (argv[0][2]) {
18744099b7bSPaul Traina stmp = &(argv[0][2]);
18844099b7bSPaul Traina } else {
18944099b7bSPaul Traina argc--;
19044099b7bSPaul Traina argv++;
19144099b7bSPaul Traina stmp = argv[0];
19244099b7bSPaul Traina }
19344099b7bSPaul Traina bootptab = stmp;
19444099b7bSPaul Traina break;
19544099b7bSPaul Traina
19644099b7bSPaul Traina default:
19744099b7bSPaul Traina fprintf(stderr, "bootpd: unknown switch: -%c\n",
19844099b7bSPaul Traina argv[0][1]);
19944099b7bSPaul Traina usage();
20044099b7bSPaul Traina break;
20144099b7bSPaul Traina }
20244099b7bSPaul Traina }
20344099b7bSPaul Traina
20444099b7bSPaul Traina /* Get the timezone. */
20544099b7bSPaul Traina tzone_init();
20644099b7bSPaul Traina
20744099b7bSPaul Traina /* Allocate hash tables. */
20844099b7bSPaul Traina rdtab_init();
20944099b7bSPaul Traina
21044099b7bSPaul Traina /*
21144099b7bSPaul Traina * Read the bootptab file.
21244099b7bSPaul Traina */
21344099b7bSPaul Traina readtab(1); /* force read */
21444099b7bSPaul Traina
21544099b7bSPaul Traina /* Set the cwd (i.e. to /tftpboot) */
21644099b7bSPaul Traina if (chdir_path) {
21744099b7bSPaul Traina if (chdir(chdir_path) < 0)
21844099b7bSPaul Traina report(LOG_ERR, "%s: chdir failed", chdir_path);
21944099b7bSPaul Traina }
22044099b7bSPaul Traina /* If there are host names on the command line, do only those. */
22144099b7bSPaul Traina if (argc > 0) {
22244099b7bSPaul Traina unsigned int tlen, hashcode;
22344099b7bSPaul Traina
22444099b7bSPaul Traina while (argc) {
22544099b7bSPaul Traina tlen = strlen(argv[0]);
22644099b7bSPaul Traina hashcode = hash_HashFunction((u_char *)argv[0], tlen);
22744099b7bSPaul Traina hp = (struct host *) hash_Lookup(nmhashtable,
22844099b7bSPaul Traina hashcode,
22944099b7bSPaul Traina nmcmp, argv[0]);
23044099b7bSPaul Traina if (!hp) {
23144099b7bSPaul Traina printf("%s: no matching entry\n", argv[0]);
23244099b7bSPaul Traina exit(1);
23344099b7bSPaul Traina }
23444099b7bSPaul Traina if (!hp->flags.exten_file) {
23544099b7bSPaul Traina printf("%s: no extension file\n", argv[0]);
23644099b7bSPaul Traina exit(1);
23744099b7bSPaul Traina }
23844099b7bSPaul Traina mktagfile(hp);
23944099b7bSPaul Traina argv++;
24044099b7bSPaul Traina argc--;
24144099b7bSPaul Traina }
24244099b7bSPaul Traina exit(0);
24344099b7bSPaul Traina }
24444099b7bSPaul Traina /* No host names specified. Do them all. */
24544099b7bSPaul Traina hp = (struct host *) hash_FirstEntry(nmhashtable);
24644099b7bSPaul Traina while (hp != NULL) {
24744099b7bSPaul Traina mktagfile(hp);
24844099b7bSPaul Traina hp = (struct host *) hash_NextEntry(nmhashtable);
24944099b7bSPaul Traina }
25085966371SWarner Losh return (0);
25144099b7bSPaul Traina }
25244099b7bSPaul Traina
25344099b7bSPaul Traina
25444099b7bSPaul Traina
25544099b7bSPaul Traina /*
25644099b7bSPaul Traina * Make a "TAG 18" file for this host.
25744099b7bSPaul Traina * (Insert the RFC1497 options.)
25844099b7bSPaul Traina */
25944099b7bSPaul Traina
26044099b7bSPaul Traina static void
mktagfile(struct host * hp)2618b356c88SJohn Baldwin mktagfile(struct host *hp)
26244099b7bSPaul Traina {
26344099b7bSPaul Traina FILE *fp;
26444099b7bSPaul Traina int bytesleft, len;
26544099b7bSPaul Traina byte *vp;
26644099b7bSPaul Traina
26744099b7bSPaul Traina if (!hp->flags.exten_file)
26844099b7bSPaul Traina return;
26944099b7bSPaul Traina
27044099b7bSPaul Traina vp = buffer;
27144099b7bSPaul Traina bytesleft = BUFFERSIZE;
27244099b7bSPaul Traina bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
27344099b7bSPaul Traina vp += 4;
27444099b7bSPaul Traina bytesleft -= 4;
27544099b7bSPaul Traina
27644099b7bSPaul Traina /*
27744099b7bSPaul Traina * The "extension file" options are appended by the following
27844099b7bSPaul Traina * function (which is shared with bootpd.c).
27944099b7bSPaul Traina */
28044099b7bSPaul Traina len = dovend_rfc1497(hp, vp, bytesleft);
28144099b7bSPaul Traina vp += len;
28244099b7bSPaul Traina bytesleft -= len;
28344099b7bSPaul Traina
28444099b7bSPaul Traina if (bytesleft < 1) {
28544099b7bSPaul Traina report(LOG_ERR, "%s: too much option data",
28644099b7bSPaul Traina hp->exten_file->string);
28744099b7bSPaul Traina return;
28844099b7bSPaul Traina }
28944099b7bSPaul Traina *vp++ = TAG_END;
29044099b7bSPaul Traina bytesleft--;
29144099b7bSPaul Traina
29244099b7bSPaul Traina /* Write the buffer to the extension file. */
29344099b7bSPaul Traina printf("Updating \"%s\"\n", hp->exten_file->string);
29444099b7bSPaul Traina if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
29544099b7bSPaul Traina report(LOG_ERR, "error opening \"%s\": %s",
29644099b7bSPaul Traina hp->exten_file->string, get_errmsg());
29744099b7bSPaul Traina return;
29844099b7bSPaul Traina }
29944099b7bSPaul Traina len = vp - buffer;
30044099b7bSPaul Traina if (len != fwrite(buffer, 1, len, fp)) {
30144099b7bSPaul Traina report(LOG_ERR, "write failed on \"%s\" : %s",
30244099b7bSPaul Traina hp->exten_file->string, get_errmsg());
30344099b7bSPaul Traina }
30444099b7bSPaul Traina fclose(fp);
30544099b7bSPaul Traina
306e08ac58bSPaul Traina } /* mktagfile */
30744099b7bSPaul Traina
30844099b7bSPaul Traina /*
30944099b7bSPaul Traina * Local Variables:
31044099b7bSPaul Traina * tab-width: 4
31144099b7bSPaul Traina * c-indent-level: 4
31244099b7bSPaul Traina * c-argdecl-indent: 4
31344099b7bSPaul Traina * c-continued-statement-offset: 4
31444099b7bSPaul Traina * c-continued-brace-offset: -4
31544099b7bSPaul Traina * c-label-offset: -4
31644099b7bSPaul Traina * c-brace-offset: 0
31744099b7bSPaul Traina * End:
31844099b7bSPaul Traina */
319