1 /*
2 ** Copyright (c) 1999-2002, 2004, 2009 Sendmail, 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>
11 SM_RCSID("@(#)$Id: smdb1.c,v 8.62 2009/11/12 23:04:18 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 
24 struct smdb_db1_struct
25 {
26 	DB	*smdb1_db;
27 	int	smdb1_lock_fd;
28 	bool	smdb1_cursor_in_use;
29 };
30 typedef struct smdb_db1_struct SMDB_DB1_DATABASE;
31 
32 struct smdb_db1_cursor
33 {
34 	SMDB_DB1_DATABASE	*db;
35 };
36 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR;
37 
38 static DBTYPE		smdb_type_to_db1_type __P((SMDB_DBTYPE));
39 static unsigned int	smdb_put_flags_to_db1_flags __P((SMDB_FLAG));
40 static int		smdb_cursor_get_flags_to_smdb1 __P((SMDB_FLAG));
41 static SMDB_DB1_DATABASE *smdb1_malloc_database __P((void));
42 static int		smdb1_close __P((SMDB_DATABASE *));
43 static int		smdb1_del __P((SMDB_DATABASE *, SMDB_DBENT *, unsigned int));
44 static int		smdb1_fd __P((SMDB_DATABASE *, int *));
45 static int		smdb1_lockfd __P((SMDB_DATABASE *));
46 static int		smdb1_get __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int));
47 static int		smdb1_put __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int));
48 static int		smdb1_set_owner __P((SMDB_DATABASE *, uid_t, gid_t));
49 static int		smdb1_sync __P((SMDB_DATABASE *, unsigned int));
50 static int		smdb1_cursor_close __P((SMDB_CURSOR *));
51 static int		smdb1_cursor_del __P((SMDB_CURSOR *, unsigned int));
52 static int		smdb1_cursor_get __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG));
53 static int		smdb1_cursor_put __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG));
54 static 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 
68 static DBTYPE
smdb_type_to_db1_type(type)69 smdb_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 
98 static unsigned int
smdb_put_flags_to_db1_flags(flags)99 smdb_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 
125 static int
smdb_cursor_get_flags_to_smdb1(flags)126 smdb_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 
152 static SMDB_DB1_DATABASE *
smdb1_malloc_database()153 smdb1_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 
168 static int
smdb1_close(database)169 smdb1_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 
186 static int
smdb1_del(database,key,flags)187 smdb1_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 
201 static int
smdb1_fd(database,fd)202 smdb1_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 
215 static int
smdb1_lockfd(database)216 smdb1_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 
225 static int
smdb1_get(database,key,data,flags)226 smdb1_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 
253 static int
smdb1_put(database,key,data,flags)254 smdb1_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 
274 static int
smdb1_set_owner(database,uid,gid)275 smdb1_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 
297 static int
smdb1_sync(database,flags)298 smdb1_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 
307 static int
smdb1_cursor_close(cursor)308 smdb1_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 
323 static int
smdb1_cursor_del(cursor,flags)324 smdb1_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 
335 static int
smdb1_cursor_get(cursor,key,value,flags)336 smdb1_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 
365 static int
smdb1_cursor_put(cursor,key,value,flags)366 smdb1_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 
387 static int
smdb1_cursor(database,cursor,flags)388 smdb1_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 
447 int
smdb_db_open(database,db_name,mode,mode_mask,sff,type,user_info,db_params)448 smdb_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