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