1/*	$NetBSD: ypdb.c,v 1.10 2005/06/20 00:29:42 lukem Exp $	*/
2
3/*
4 * Copyright (c) 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Margo Seltzer.
10 *
11 * This code is derived from ndbm module of BSD4.4 db (hash) by
12 * Mats O Jansson
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
27 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
30 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40#ifndef lint
41__RCSID("$NetBSD: ypdb.c,v 1.10 2005/06/20 00:29:42 lukem Exp $");
42#endif
43
44#include <sys/param.h>
45#include <sys/types.h>
46
47#include <db.h>
48#include <err.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <unistd.h>
55
56#include <rpcsvc/yp.h>
57
58#include "ypdb.h"
59
60static DBM	*_ypdb_dbopen(const char *, int, mode_t);
61
62/*
63 * ypdb_open --
64 *	dbopen(3) file, read-only.
65 *	First ensure that file has a suffix of YPDB_SUFFIX.
66 *	Try opening as a DB_BTREE first, then DB_HASH.
67 *
68 * Returns:
69 *	*DBM on success
70 *	 NULL on failure
71 */
72
73DBM *
74ypdb_open(const char *file)
75{
76	char path[MAXPATHLEN];
77	const char *cp, *suffix;
78
79	cp = strrchr(file, '.');
80	if (cp != NULL && strcmp(cp, YPDB_SUFFIX) == 0)
81		suffix = "";
82	else
83		suffix = YPDB_SUFFIX;
84	if (strlen(file) + strlen(suffix) > (sizeof(path) - 1)) {
85		warnx("File name `%s' is too long", file);
86		return (NULL);
87	}
88	snprintf(path, sizeof(path), "%s%s", file, suffix);
89	return _ypdb_dbopen(path, O_RDONLY, 0444);
90}
91
92/*
93 * ypdb_mktemp --
94 *	Create a temporary file using mkstemp(3) based on the
95 *	template provided in file.
96 *	dbopen(3) file, read-write, 0644 (modified by umask(2)).
97 *	Try opening as a DB_BTREE first, then DB_HASH.
98 *	file won't have YPDB_SUFFIX.
99 *
100 * Returns:
101 *	*DBM on success; file now exists.
102 *	 NULL on failure
103 */
104
105DBM *
106ypdb_mktemp(char *file)
107{
108	int fd = -1;
109	DBM *db = NULL;
110	mode_t myumask;
111	int save_errno;
112
113	if ((fd = mkstemp(file)) == -1)
114		return NULL;
115
116	myumask = umask(0);
117	(void)umask(myumask);
118	if (fchmod(fd, 0644 & ~myumask) == -1)
119		goto bad;
120
121	(void) close(fd);
122	fd = -1;
123
124	if ((db = _ypdb_dbopen(file, O_RDWR, 0644)) == NULL)
125		goto bad;
126
127	return db;
128
129 bad:
130	save_errno = errno;
131	if (fd != 1)
132		(void) close(fd);
133	(void) unlink(file);
134	errno = save_errno;
135	return NULL;
136}
137
138/*
139 * _ypdb_dbopen --
140 *	dbopen(3) path with the flags & mode.
141 *	Try opening as a DB_BTREE first, then DB_HASH.
142 */
143
144static DBM *
145_ypdb_dbopen(const char *path, int flags, mode_t mode)
146{
147	DBM *db;
148	BTREEINFO info;
149
150		/* try our btree format first */
151	info.flags = 0;
152	info.cachesize = 0;
153	info.maxkeypage = 0;
154	info.minkeypage = 0;
155	info.psize = 0;
156	info.compare = NULL;
157	info.prefix = NULL;
158	info.lorder = 0;
159	db = (DBM *)dbopen(path, flags, mode, DB_BTREE, (void *)&info);
160	if (db != NULL || errno != EFTYPE)
161		return (db);
162
163		/* fallback to standard hash (for sendmail's aliases.db) */
164	db = (DBM *)dbopen(path, flags, mode, DB_HASH, NULL);
165	return (db);
166}
167
168/*
169 * ypdb_close --
170 *	Close the db
171 */
172
173void
174ypdb_close(DBM *db)
175{
176	(void)(db->close)(db);
177}
178
179/*
180 * Returns:
181 *	DATUM on success
182 *	NULL on failure
183 */
184
185datum
186ypdb_fetch(DBM *db, datum key)
187{
188	datum retkey;
189	DBT nk, nd;
190	int status;
191
192	nk.data = key.dptr;
193	nk.size = key.dsize;
194	status = (db->get)(db, &nk, &nd, 0);
195	if (status) {
196		retkey.dptr = NULL;
197		retkey.dsize = 0;
198	} else {
199		retkey.dptr = nd.data;
200		retkey.dsize = nd.size;
201	}
202	return (retkey);
203}
204
205/*
206 * Returns:
207 *	DATUM on success
208 *	NULL on failure
209 */
210
211datum
212ypdb_firstkey(DBM *db)
213{
214	int status;
215	datum retkey;
216	DBT nk, nd;
217
218	status = (db->seq)(db, &nk, &nd, R_FIRST);
219	if (status) {
220		retkey.dptr = NULL;
221		retkey.dsize = 0;
222	} else {
223		retkey.dptr = nk.data;
224		retkey.dsize = nk.size;
225	}
226	return (retkey);
227}
228
229/*
230 * Returns:
231 *	DATUM on success
232 *	NULL on failure
233 */
234
235datum
236ypdb_nextkey(DBM *db)
237{
238	int status;
239	datum retkey;
240	DBT nk, nd;
241
242	status = (db->seq)(db, &nk, &nd, R_NEXT);
243	if (status) {
244		retkey.dptr = NULL;
245		retkey.dsize = 0;
246	} else {
247		retkey.dptr = nk.data;
248		retkey.dsize = nk.size;
249	}
250	return (retkey);
251}
252
253/*
254 * Returns:
255 *	DATUM on success
256 *	NULL on failure
257 */
258
259datum
260ypdb_setkey(DBM *db, datum key)
261{
262	int status;
263	DBT nk, nd;
264
265	nk.data = key.dptr;
266	nk.size = key.dsize;
267	status = (db->seq)(db, &nk, &nd, R_CURSOR);
268	if (status) {
269		key.dptr = NULL;
270		key.dsize = 0;
271	}
272	return (key);
273}
274
275/*
276 * Returns:
277 *	 0 on success
278 *	<0 failure
279 */
280
281int
282ypdb_delete(DBM *db, datum key)
283{
284	int status;
285	DBT nk;
286
287	nk.data = key.dptr;
288	nk.size = key.dsize;
289	status = (db->del)(db, &nk, 0);
290	if (status)
291		return (-1);
292	else
293		return (0);
294}
295
296/*
297 * Returns:
298 *	 0 on success
299 *	<0 failure
300 *	 1 if YPDB_INSERT and entry exists
301 */
302
303int
304ypdb_store(DBM *db, datum key, datum content, int flags)
305{
306	DBT nk, nd;
307
308	if (key.dsize > YPMAXRECORD || content.dsize > YPMAXRECORD)
309		return -1;
310	nk.data = key.dptr;
311	nk.size = key.dsize;
312	nd.data = content.dptr;
313	nd.size = content.dsize;
314	return ((db->put)(db, &nk, &nd,
315	    (flags == YPDB_INSERT) ? R_NOOVERWRITE : 0));
316}
317