smdb1.c revision 363466
1/*
2** Copyright (c) 1999-2002, 2004, 2009 Proofpoint, Inc. and its suppliers.
3**	All rights reserved.
4**
5** By using this file, you agree to the terms and conditions set
6** forth in the LICENSE file which can be found at the top level of
7** the sendmail distribution.
8*/
9
10#include <sm/gen.h>
11SM_RCSID("@(#)$Id: smdb1.c,v 8.63 2013-11-22 20:51:49 ca Exp $")
12
13#include <unistd.h>
14#include <stdlib.h>
15#include <fcntl.h>
16
17#include <sendmail/sendmail.h>
18#include <libsmdb/smdb.h>
19
20#if (DB_VERSION_MAJOR == 1)
21
22struct smdb_db1_struct
23{
24	DB	*smdb1_db;
25	int	smdb1_lock_fd;
26	bool	smdb1_cursor_in_use;
27};
28typedef struct smdb_db1_struct SMDB_DB1_DATABASE;
29
30struct smdb_db1_cursor
31{
32	SMDB_DB1_DATABASE	*db;
33};
34typedef struct smdb_db1_cursor SMDB_DB1_CURSOR;
35
36static DBTYPE		smdb_type_to_db1_type __P((SMDB_DBTYPE));
37static unsigned int	smdb_put_flags_to_db1_flags __P((SMDB_FLAG));
38static int		smdb_cursor_get_flags_to_smdb1 __P((SMDB_FLAG));
39static SMDB_DB1_DATABASE *smdb1_malloc_database __P((void));
40static int		smdb1_close __P((SMDB_DATABASE *));
41static int		smdb1_del __P((SMDB_DATABASE *, SMDB_DBENT *, unsigned int));
42static int		smdb1_fd __P((SMDB_DATABASE *, int *));
43static int		smdb1_lockfd __P((SMDB_DATABASE *));
44static int		smdb1_get __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int));
45static int		smdb1_put __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int));
46static int		smdb1_set_owner __P((SMDB_DATABASE *, uid_t, gid_t));
47static int		smdb1_sync __P((SMDB_DATABASE *, unsigned int));
48static int		smdb1_cursor_close __P((SMDB_CURSOR *));
49static int		smdb1_cursor_del __P((SMDB_CURSOR *, unsigned int));
50static int		smdb1_cursor_get __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG));
51static int		smdb1_cursor_put __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG));
52static int		smdb1_cursor __P((SMDB_DATABASE *, SMDB_CURSOR **, unsigned int));
53
54/*
55**  SMDB_TYPE_TO_DB1_TYPE -- Translates smdb database type to db1 type.
56**
57**	Parameters:
58**		type -- The type to translate.
59**
60**	Returns:
61**		The DB1 type that corresponsds to the passed in SMDB type.
62**		Returns -1 if there is no equivalent type.
63**
64*/
65
66static DBTYPE
67smdb_type_to_db1_type(type)
68	SMDB_DBTYPE type;
69{
70	if (type == SMDB_TYPE_DEFAULT)
71		return DB_HASH;
72
73	if (SMDB_IS_TYPE_HASH(type))
74		return DB_HASH;
75
76	if (SMDB_IS_TYPE_BTREE(type))
77		return DB_BTREE;
78
79	/* Should never get here thanks to test in smdb_db_open() */
80	return DB_HASH;
81}
82/*
83**  SMDB_PUT_FLAGS_TO_DB1_FLAGS -- Translates smdb put flags to db1 put flags.
84**
85**	Parameters:
86**		flags -- The flags to translate.
87**
88**	Returns:
89**		The db1 flags that are equivalent to the smdb flags.
90**
91**	Notes:
92**		Any invalid flags are ignored.
93**
94*/
95
96static unsigned int
97smdb_put_flags_to_db1_flags(flags)
98	SMDB_FLAG flags;
99{
100	int return_flags;
101
102	return_flags = 0;
103
104	if (bitset(SMDBF_NO_OVERWRITE, flags))
105		return_flags |= R_NOOVERWRITE;
106
107	return return_flags;
108}
109/*
110**  SMDB_CURSOR_GET_FLAGS_TO_SMDB1
111**
112**	Parameters:
113**		flags -- The flags to translate.
114**
115**	Returns:
116**		The db1 flags that are equivalent to the smdb flags.
117**
118**	Notes:
119**		Returns -1 if we don't support the flag.
120**
121*/
122
123static int
124smdb_cursor_get_flags_to_smdb1(flags)
125	SMDB_FLAG flags;
126{
127	switch(flags)
128	{
129		case SMDB_CURSOR_GET_FIRST:
130			return R_FIRST;
131
132		case SMDB_CURSOR_GET_LAST:
133			return R_LAST;
134
135		case SMDB_CURSOR_GET_NEXT:
136			return R_NEXT;
137
138		case SMDB_CURSOR_GET_RANGE:
139			return R_CURSOR;
140
141		default:
142			return -1;
143	}
144}
145
146/*
147**  The rest of these functions correspond to the interface laid out in smdb.h.
148*/
149
150static SMDB_DB1_DATABASE *
151smdb1_malloc_database()
152{
153	SMDB_DB1_DATABASE *db1;
154
155	db1 = (SMDB_DB1_DATABASE *) malloc(sizeof(SMDB_DB1_DATABASE));
156
157	if (db1 != NULL)
158	{
159		db1->smdb1_lock_fd = -1;
160		db1->smdb1_cursor_in_use = false;
161	}
162
163	return db1;
164}
165
166static int
167smdb1_close(database)
168	SMDB_DATABASE *database;
169{
170	int result;
171	SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
172	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
173
174	result = db->close(db);
175	if (db1->smdb1_lock_fd != -1)
176		(void) close(db1->smdb1_lock_fd);
177
178	free(db1);
179	database->smdb_impl = NULL;
180
181	return result;
182}
183
184static int
185smdb1_del(database, key, flags)
186	SMDB_DATABASE *database;
187	SMDB_DBENT *key;
188	unsigned int flags;
189{
190	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
191	DBT dbkey;
192
193	(void) memset(&dbkey, '\0', sizeof dbkey);
194	dbkey.data = key->data;
195	dbkey.size = key->size;
196	return db->del(db, &dbkey, flags);
197}
198
199static int
200smdb1_fd(database, fd)
201	SMDB_DATABASE *database;
202	int *fd;
203{
204	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
205
206	*fd = db->fd(db);
207	if (*fd == -1)
208		return errno;
209
210	return SMDBE_OK;
211}
212
213static int
214smdb1_lockfd(database)
215	SMDB_DATABASE *database;
216{
217	SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
218
219	return db1->smdb1_lock_fd;
220}
221
222
223static int
224smdb1_get(database, key, data, flags)
225	SMDB_DATABASE *database;
226	SMDB_DBENT *key;
227	SMDB_DBENT *data;
228	unsigned int flags;
229{
230	int result;
231	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
232	DBT dbkey, dbdata;
233
234	(void) memset(&dbdata, '\0', sizeof dbdata);
235	(void) memset(&dbkey, '\0', sizeof dbkey);
236	dbkey.data = key->data;
237	dbkey.size = key->size;
238
239	result = db->get(db, &dbkey, &dbdata, flags);
240	if (result != 0)
241	{
242		if (result == 1)
243			return SMDBE_NOT_FOUND;
244		return errno;
245	}
246	data->data = dbdata.data;
247	data->size = dbdata.size;
248	return SMDBE_OK;
249}
250
251static int
252smdb1_put(database, key, data, flags)
253	SMDB_DATABASE *database;
254	SMDB_DBENT *key;
255	SMDB_DBENT *data;
256	unsigned int flags;
257{
258	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
259	DBT dbkey, dbdata;
260
261	(void) memset(&dbdata, '\0', sizeof dbdata);
262	(void) memset(&dbkey, '\0', sizeof dbkey);
263	dbkey.data = key->data;
264	dbkey.size = key->size;
265	dbdata.data = data->data;
266	dbdata.size = data->size;
267
268	return db->put(db, &dbkey, &dbdata,
269		       smdb_put_flags_to_db1_flags(flags));
270}
271
272static int
273smdb1_set_owner(database, uid, gid)
274	SMDB_DATABASE *database;
275	uid_t uid;
276	gid_t gid;
277{
278# if HASFCHOWN
279	int fd;
280	int result;
281	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
282
283	fd = db->fd(db);
284	if (fd == -1)
285		return errno;
286
287	result = fchown(fd, uid, gid);
288	if (result < 0)
289		return errno;
290# endif /* HASFCHOWN */
291
292	return SMDBE_OK;
293}
294
295static int
296smdb1_sync(database, flags)
297	SMDB_DATABASE *database;
298	unsigned int flags;
299{
300	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
301
302	return db->sync(db, flags);
303}
304
305static int
306smdb1_cursor_close(cursor)
307	SMDB_CURSOR *cursor;
308{
309	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
310	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
311
312	if (!db1->smdb1_cursor_in_use)
313		return SMDBE_NOT_A_VALID_CURSOR;
314
315	db1->smdb1_cursor_in_use = false;
316	free(cursor);
317
318	return SMDBE_OK;
319}
320
321static int
322smdb1_cursor_del(cursor, flags)
323	SMDB_CURSOR *cursor;
324	unsigned int flags;
325{
326	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
327	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
328	DB *db = db1->smdb1_db;
329
330	return db->del(db, NULL, R_CURSOR);
331}
332
333static int
334smdb1_cursor_get(cursor, key, value, flags)
335	SMDB_CURSOR *cursor;
336	SMDB_DBENT *key;
337	SMDB_DBENT *value;
338	SMDB_FLAG flags;
339{
340	int db1_flags;
341	int result;
342	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
343	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
344	DB *db = db1->smdb1_db;
345	DBT dbkey, dbdata;
346
347	(void) memset(&dbdata, '\0', sizeof dbdata);
348	(void) memset(&dbkey, '\0', sizeof dbkey);
349
350	db1_flags = smdb_cursor_get_flags_to_smdb1(flags);
351	result = db->seq(db, &dbkey, &dbdata, db1_flags);
352	if (result == -1)
353		return errno;
354	if (result == 1)
355		return SMDBE_LAST_ENTRY;
356	value->data = dbdata.data;
357	value->size = dbdata.size;
358	key->data = dbkey.data;
359	key->size = dbkey.size;
360	return SMDBE_OK;
361}
362
363static int
364smdb1_cursor_put(cursor, key, value, flags)
365	SMDB_CURSOR *cursor;
366	SMDB_DBENT *key;
367	SMDB_DBENT *value;
368	SMDB_FLAG flags;
369{
370	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
371	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
372	DB *db = db1->smdb1_db;
373	DBT dbkey, dbdata;
374
375	(void) memset(&dbdata, '\0', sizeof dbdata);
376	(void) memset(&dbkey, '\0', sizeof dbkey);
377	dbkey.data = key->data;
378	dbkey.size = key->size;
379	dbdata.data = value->data;
380	dbdata.size = value->size;
381
382	return db->put(db, &dbkey, &dbdata, R_CURSOR);
383}
384
385static int
386smdb1_cursor(database, cursor, flags)
387	SMDB_DATABASE *database;
388	SMDB_CURSOR **cursor;
389	unsigned int flags;
390{
391	SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
392	SMDB_CURSOR *cur;
393	SMDB_DB1_CURSOR *db1_cursor;
394
395	if (db1->smdb1_cursor_in_use)
396		return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
397
398	db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR));
399	if (db1_cursor == NULL)
400		return SMDBE_MALLOC;
401
402	cur = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
403	if (cur == NULL)
404	{
405		free(db1_cursor);
406		return SMDBE_MALLOC;
407	}
408
409	db1->smdb1_cursor_in_use = true;
410	db1_cursor->db = db1;
411	cur->smdbc_impl = db1_cursor;
412	cur->smdbc_close = smdb1_cursor_close;
413	cur->smdbc_del = smdb1_cursor_del;
414	cur->smdbc_get = smdb1_cursor_get;
415	cur->smdbc_put = smdb1_cursor_put;
416	*cursor = cur;
417
418	return SMDBE_OK;
419}
420/*
421**  SMDB_DB_OPEN -- Opens a db1 database.
422**
423**	Parameters:
424**		database -- An unallocated database pointer to a pointer.
425**		db_name -- The name of the database without extension.
426**		mode -- File permisions on the database if created.
427**		mode_mask -- Mode bits that must match on an existing database.
428**		sff -- Flags for safefile.
429**		type -- The type of database to open
430**			See smdb_type_to_db1_type for valid types.
431**		user_info -- Information on the user to use for file
432**			    permissions.
433**		db_params --
434**			An SMDB_DBPARAMS struct including params. These
435**			are processed according to the type of the
436**			database. Currently supported params (only for
437**			HASH type) are:
438**			   num_elements
439**			   cache_size
440**
441**	Returns:
442**		SMDBE_OK -- Success, otherwise errno.
443*/
444
445int
446smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
447	     db_params)
448	SMDB_DATABASE **database;
449	char *db_name;
450	int mode;
451	int mode_mask;
452	long sff;
453	SMDB_DBTYPE type;
454	SMDB_USER_INFO *user_info;
455	SMDB_DBPARAMS *db_params;
456{
457	bool lockcreated = false;
458	int db_fd;
459	int lock_fd;
460	int result;
461	void *params;
462	SMDB_DATABASE *smdb_db;
463	SMDB_DB1_DATABASE *db1;
464	DB *db;
465	HASHINFO hash_info;
466	BTREEINFO btree_info;
467	DBTYPE db_type;
468	struct stat stat_info;
469	char db_file_name[MAXPATHLEN];
470
471	if (type == NULL ||
472	    (!SMDB_IS_TYPE_HASH(type) && !SMDB_IS_TYPE_BTREE(type)
473	     ))
474		return SMDBE_UNKNOWN_DB_TYPE;
475
476	result = smdb_add_extension(db_file_name, sizeof db_file_name,
477				    db_name, SMDB1_FILE_EXTENSION);
478	if (result != SMDBE_OK)
479		return result;
480
481	result = smdb_setup_file(db_name, SMDB1_FILE_EXTENSION, mode_mask,
482				 sff, user_info, &stat_info);
483	if (result != SMDBE_OK)
484		return result;
485
486	if (stat_info.st_mode == ST_MODE_NOFILE &&
487	    bitset(mode, O_CREAT))
488		lockcreated = true;
489
490	lock_fd = -1;
491	result = smdb_lock_file(&lock_fd, db_name, mode, sff,
492				SMDB1_FILE_EXTENSION);
493	if (result != SMDBE_OK)
494		return result;
495
496	if (lockcreated)
497	{
498		mode |= O_TRUNC;
499		mode &= ~(O_CREAT|O_EXCL);
500	}
501
502	*database = NULL;
503
504	smdb_db = smdb_malloc_database();
505	db1 = smdb1_malloc_database();
506	if (smdb_db == NULL || db1 == NULL)
507	{
508		(void) smdb_unlock_file(lock_fd);
509		smdb_free_database(smdb_db);
510		free(db1);
511		return SMDBE_MALLOC;
512	}
513	db1->smdb1_lock_fd = lock_fd;
514
515	params = NULL;
516	if (db_params != NULL && SMDB_IS_TYPE_HASH(type))
517	{
518		(void) memset(&hash_info, '\0', sizeof hash_info);
519		hash_info.nelem = db_params->smdbp_num_elements;
520		hash_info.cachesize = db_params->smdbp_cache_size;
521		params = &hash_info;
522	}
523
524	if (db_params != NULL && SMDB_IS_TYPE_BTREE(type))
525	{
526		(void) memset(&btree_info, '\0', sizeof btree_info);
527		btree_info.cachesize = db_params->smdbp_cache_size;
528		if (db_params->smdbp_allow_dup)
529			btree_info.flags |= R_DUP;
530		params = &btree_info;
531	}
532
533	db_type = smdb_type_to_db1_type(type);
534	db = dbopen(db_file_name, mode, DBMMODE, db_type, params);
535	if (db != NULL)
536	{
537		db_fd = db->fd(db);
538		result = smdb_filechanged(db_name, SMDB1_FILE_EXTENSION, db_fd,
539					  &stat_info);
540	}
541	else
542	{
543		if (errno == 0)
544			result = SMDBE_BAD_OPEN;
545		else
546			result = errno;
547	}
548
549	if (result == SMDBE_OK)
550	{
551		/* Everything is ok. Setup driver */
552		db1->smdb1_db = db;
553
554		smdb_db->smdb_close = smdb1_close;
555		smdb_db->smdb_del = smdb1_del;
556		smdb_db->smdb_fd = smdb1_fd;
557		smdb_db->smdb_lockfd = smdb1_lockfd;
558		smdb_db->smdb_get = smdb1_get;
559		smdb_db->smdb_put = smdb1_put;
560		smdb_db->smdb_set_owner = smdb1_set_owner;
561		smdb_db->smdb_sync = smdb1_sync;
562		smdb_db->smdb_cursor = smdb1_cursor;
563		smdb_db->smdb_impl = db1;
564
565		*database = smdb_db;
566		return SMDBE_OK;
567	}
568
569	if (db != NULL)
570		(void) db->close(db);
571
572	/* Error opening database */
573	(void) smdb_unlock_file(db1->smdb1_lock_fd);
574	free(db1);
575	smdb_free_database(smdb_db);
576
577	return result;
578}
579
580#endif /* (DB_VERSION_MAJOR == 1) */
581