1/*
2 * Copyright (c) 1995, 1996
3 *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/10/usr.sbin/yp_mkdb/yp_mkdb.c 364084 2020-08-10 17:35:58Z dim $");
35
36#include <err.h>
37#include <fcntl.h>
38#include <limits.h>
39#include <stdint.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <time.h>
44#include <unistd.h>
45#include <rpc/rpc.h>
46#include <rpcsvc/yp.h>
47#include <sys/param.h>
48#include <sys/types.h>
49#include <sys/stat.h>
50#include "yp_extern.h"
51#include "ypxfr_extern.h"
52
53char *yp_dir = "";	/* No particular default needed. */
54int _rpcpmstart = 0;
55int debug = 1;
56
57static void
58usage(void)
59{
60	fprintf(stderr, "%s\n%s\n%s\n%s\n",
61	"usage: yp_mkdb -c",
62	"       yp_mkdb -u dbname",
63	"       yp_mkdb [-c] [-b] [-s] [-f] [-i inputfile] [-o outputfile]",
64	"               [-d domainname ] [-m mastername] inputfile dbname");
65	exit(1);
66}
67
68#define PERM_SECURE (S_IRUSR|S_IWUSR)
69
70static DB *
71open_db(char *path, int flags)
72{
73	extern HASHINFO openinfo;
74
75	return(dbopen(path, flags, PERM_SECURE, DB_HASH, &openinfo));
76}
77
78static void
79unwind(char *map)
80{
81	DB *dbp;
82	DBT key, data;
83
84	dbp = open_db(map, O_RDONLY);
85
86	if (dbp == NULL)
87		err(1, "open_db(%s) failed", map);
88
89	key.data = NULL;
90	while (yp_next_record(dbp, &key, &data, 1, 1) == YP_TRUE)
91		printf("%.*s %.*s\n", (int)key.size, (char *)key.data,
92		    (int)data.size, (char *)data.data);
93
94	(void)(dbp->close)(dbp);
95	return;
96}
97
98int
99main(int argc, char *argv[])
100{
101	int ch;
102	int un = 0;
103	int clear = 0;
104	int filter_plusminus = 0;
105	char *infile = NULL;
106	char *map = NULL;
107	char *domain = NULL;
108	char *infilename = NULL;
109	char *outfilename = NULL;
110	char *mastername = NULL;
111	int interdom = 0;
112	int secure = 0;
113	DB *dbp;
114	DBT key, data;
115	char buf[10240];
116	char *keybuf, *datbuf;
117	FILE *ifp;
118	char hname[MAXHOSTNAMELEN + 2];
119
120	while ((ch = getopt(argc, argv, "uhcbsfd:i:o:m:")) != -1) {
121		switch (ch) {
122		case 'f':
123			filter_plusminus++;
124			break;
125		case 'u':
126			un++;
127			break;
128		case 'c':
129			clear++;
130			break;
131		case 'b':
132			interdom++;
133			break;
134		case 's':
135			secure++;
136			break;
137		case 'd':
138			domain = optarg;
139			break;
140		case 'i':
141			infilename = optarg;
142			break;
143		case 'o':
144			outfilename = optarg;
145			break;
146		case 'm':
147			mastername = optarg;
148			break;
149		case 'h':
150		default:
151			usage();
152			break;
153		}
154	}
155
156	argc -= optind;
157	argv += optind;
158
159	if (un) {
160		map = argv[0];
161		if (map == NULL)
162			usage();
163		unwind(map);
164		exit(0);
165
166	}
167
168	infile = argv[0];
169	map = argv[1];
170
171	if (infile == NULL || map == NULL) {
172		if (clear)
173			goto doclear;
174		usage();
175	}
176
177	if (mastername == NULL) {
178		if (gethostname((char *)&hname, sizeof(hname)) == -1)
179			err(1, "gethostname() failed");
180		mastername = (char *)&hname;
181	}
182
183	/*
184	 * Note that while we can read from stdin, we can't
185	 * write to stdout; the db library doesn't let you
186	 * write to a file stream like that.
187	 */
188
189	if (!strcmp(infile, "-")) {
190		ifp = stdin;
191	} else {
192		if ((ifp = fopen(infile, "r")) == NULL)
193			err(1, "failed to open %s", infile);
194	}
195
196	if ((dbp = open_db(map, O_RDWR|O_EXLOCK|O_EXCL|O_CREAT)) == NULL)
197		err(1, "open_db(%s) failed", map);
198
199	if (interdom) {
200		key.data = "YP_INTERDOMAIN";
201		key.size = sizeof("YP_INTERDOMAIN") - 1;
202		data.data = "";
203		data.size = 0;
204		yp_put_record(dbp, &key, &data, 0);
205	}
206
207	if (secure) {
208		key.data = "YP_SECURE";
209		key.size = sizeof("YP_SECURE") - 1;
210		data.data = "";
211		data.size = 0;
212		yp_put_record(dbp, &key, &data, 0);
213	}
214
215	key.data = "YP_MASTER_NAME";
216	key.size = sizeof("YP_MASTER_NAME") - 1;
217	data.data = mastername;
218	data.size = strlen(mastername);
219	yp_put_record(dbp, &key, &data, 0);
220
221	key.data = "YP_LAST_MODIFIED";
222	key.size = sizeof("YP_LAST_MODIFIED") - 1;
223	snprintf(buf, sizeof(buf), "%jd", (intmax_t)time(NULL));
224	data.data = (char *)&buf;
225	data.size = strlen(buf);
226	yp_put_record(dbp, &key, &data, 0);
227
228	if (infilename) {
229		key.data = "YP_INPUT_FILE";
230		key.size = sizeof("YP_INPUT_FILE") - 1;
231		data.data = infilename;
232		data.size = strlen(infilename);
233		yp_put_record(dbp, &key, &data, 0);
234	}
235
236	if (outfilename) {
237		key.data = "YP_OUTPUT_FILE";
238		key.size = sizeof("YP_OUTPUT_FILE") - 1;
239		data.data = outfilename;
240		data.size = strlen(outfilename);
241		yp_put_record(dbp, &key, &data, 0);
242	}
243
244	if (domain) {
245		key.data = "YP_DOMAIN_NAME";
246		key.size = sizeof("YP_DOMAIN_NAME") - 1;
247		data.data = domain;
248		data.size = strlen(domain);
249		yp_put_record(dbp, &key, &data, 0);
250	}
251
252	while (fgets((char *)&buf, sizeof(buf), ifp)) {
253		char *sep = NULL;
254		int rval;
255
256		/* NUL terminate */
257		if ((sep = strchr(buf, '\n')))
258			*sep = '\0';
259
260		/* handle backslash line continuations */
261		while (buf[strlen(buf) - 1] == '\\') {
262			fgets((char *)&buf[strlen(buf) - 1],
263					sizeof(buf) - strlen(buf), ifp);
264			if ((sep = strchr(buf, '\n')))
265				*sep = '\0';
266		}
267
268		/* find the separation between the key and data */
269		if ((sep = strpbrk(buf, " \t")) == NULL) {
270			warnx("bad input -- no white space: %s", buf);
271			continue;
272		}
273
274		/* separate the strings */
275		keybuf = (char *)&buf;
276		datbuf = sep + 1;
277		*sep = '\0';
278
279		/* set datbuf to start at first non-whitespace character */
280		while (*datbuf == ' ' || *datbuf == '\t')
281			datbuf++;
282
283		/* Check for silliness. */
284		if (filter_plusminus) {
285			if  (*keybuf == '+' || *keybuf == '-' ||
286			     *datbuf == '+' || *datbuf == '-') {
287				warnx("bad character at "
288				    "start of line: %s", buf);
289				continue;
290			}
291		}
292
293		if (strlen(keybuf) > YPMAXRECORD) {
294			warnx("key too long: %s", keybuf);
295			continue;
296		}
297
298		if (!strlen(keybuf)) {
299			warnx("no key -- check source file for blank lines");
300			continue;
301		}
302
303		if (strlen(datbuf) > YPMAXRECORD) {
304			warnx("data too long: %s", datbuf);
305			continue;
306		}
307
308		key.data = keybuf;
309		key.size = strlen(keybuf);
310		data.data = datbuf;
311		data.size = strlen(datbuf);
312
313		if ((rval = yp_put_record(dbp, &key, &data, 0)) != YP_TRUE) {
314			switch (rval) {
315			case YP_FALSE:
316				warnx("duplicate key '%s' - skipping", keybuf);
317				break;
318			case YP_BADDB:
319			default:
320				err(1,"failed to write new record - exiting");
321				break;
322			}
323		}
324
325	}
326
327	(void)(dbp->close)(dbp);
328
329doclear:
330
331	if (clear) {
332		char in = 0;
333		char *out = NULL;
334		int stat;
335		if ((stat = callrpc("localhost", YPPROG,YPVERS, YPPROC_CLEAR,
336			(xdrproc_t)xdr_void, &in,
337			(xdrproc_t)xdr_void, out)) != RPC_SUCCESS) {
338			warnx("failed to send 'clear' to local ypserv: %s",
339				clnt_sperrno((enum clnt_stat) stat));
340		}
341	}
342
343	exit(0);
344}
345