xref: /freebsd/contrib/sendmail/libsmdb/smdb2.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
1 /*
2 ** Copyright (c) 1999-2001 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 #ifndef lint
11 static char id[] = "@(#)$Id: smdb2.c,v 8.53.2.1.2.7 2001/02/14 04:07:24 gshapiro Exp $";
12 #endif /* ! lint */
13 
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 
18 
19 #include <sendmail/sendmail.h>
20 #include <libsmdb/smdb.h>
21 
22 #if (DB_VERSION_MAJOR >= 2)
23 
24 # define SMDB2_FILE_EXTENSION "db"
25 
26 struct smdb_db2_database
27 {
28 	DB	*smdb2_db;
29 	int	smdb2_lock_fd;
30 };
31 typedef struct smdb_db2_database SMDB_DB2_DATABASE;
32 
33 /*
34 **  SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type.
35 **
36 **	Parameters:
37 **		type -- The type to translate.
38 **
39 **	Returns:
40 **		The DB2 type that corresponsds to the passed in SMDB type.
41 **		Returns -1 if there is no equivalent type.
42 **
43 */
44 
45 DBTYPE
46 smdb_type_to_db2_type(type)
47 	SMDB_DBTYPE type;
48 {
49 	if (type == SMDB_TYPE_DEFAULT)
50 		return DB_HASH;
51 
52 	if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
53 		return DB_HASH;
54 
55 	if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
56 		return DB_BTREE;
57 
58 	return DB_UNKNOWN;
59 }
60 
61 
62 /*
63 **  DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors
64 **
65 **	Parameters:
66 **		error -- The error to translate.
67 **
68 **	Returns:
69 **		The SMDBE error corresponding to the db2 error.
70 **		If we don't have a corresponding error, it returs errno.
71 **
72 */
73 
74 int
75 db2_error_to_smdb(error)
76 	int error;
77 {
78 	int result;
79 
80 	switch (error)
81 	{
82 # ifdef DB_INCOMPLETE
83 		case DB_INCOMPLETE:
84 			result = SMDBE_INCOMPLETE;
85 			break;
86 # endif /* DB_INCOMPLETE */
87 
88 # ifdef DB_NOTFOUND
89 		case DB_NOTFOUND:
90 			result = SMDBE_NOT_FOUND;
91 			break;
92 # endif /* DB_NOTFOUND */
93 
94 # ifdef DB_KEYEMPTY
95 		case DB_KEYEMPTY:
96 			result = SMDBE_KEY_EMPTY;
97 			break;
98 # endif /* DB_KEYEMPTY */
99 
100 # ifdef DB_KEYEXIST
101 		case DB_KEYEXIST:
102 			result = SMDBE_KEY_EXIST;
103 			break;
104 # endif /* DB_KEYEXIST */
105 
106 # ifdef DB_LOCK_DEADLOCK
107 		case DB_LOCK_DEADLOCK:
108 			result = SMDBE_LOCK_DEADLOCK;
109 			break;
110 # endif /* DB_LOCK_DEADLOCK */
111 
112 # ifdef DB_LOCK_NOTGRANTED
113 		case DB_LOCK_NOTGRANTED:
114 			result = SMDBE_LOCK_NOT_GRANTED;
115 			break;
116 # endif /* DB_LOCK_NOTGRANTED */
117 
118 # ifdef DB_LOCK_NOTHELD
119 		case DB_LOCK_NOTHELD:
120 			result = SMDBE_LOCK_NOT_HELD;
121 			break;
122 # endif /* DB_LOCK_NOTHELD */
123 
124 # ifdef DB_RUNRECOVERY
125 		case DB_RUNRECOVERY:
126 			result = SMDBE_RUN_RECOVERY;
127 			break;
128 # endif /* DB_RUNRECOVERY */
129 
130 # ifdef DB_OLD_VERSION
131 		case DB_OLD_VERSION:
132 			result = SMDBE_OLD_VERSION;
133 			break;
134 # endif /* DB_OLD_VERSION */
135 
136 		case 0:
137 			result = SMDBE_OK;
138 			break;
139 
140 		default:
141 			result = error;
142 	}
143 	return result;
144 }
145 
146 /*
147 **  SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags.
148 **
149 **	Parameters:
150 **		flags -- The flags to translate.
151 **
152 **	Returns:
153 **		The db2 flags that are equivalent to the smdb flags.
154 **
155 **	Notes:
156 **		Any invalid flags are ignored.
157 **
158 */
159 
160 u_int
161 smdb_put_flags_to_db2_flags(flags)
162 	SMDB_FLAG flags;
163 {
164 	int return_flags;
165 
166 	return_flags = 0;
167 
168 	if (bitset(SMDBF_NO_OVERWRITE, flags))
169 		return_flags |= DB_NOOVERWRITE;
170 
171 	return return_flags;
172 }
173 
174 /*
175 **  SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2
176 **	getflags.
177 **
178 **	Parameters:
179 **		flags -- The flags to translate.
180 **
181 **	Returns:
182 **		The db2 flags that are equivalent to the smdb flags.
183 **
184 **	Notes:
185 **		-1 is returned if flag is unknown.
186 **
187 */
188 
189 int
190 smdb_cursor_get_flags_to_db2(flags)
191 	SMDB_FLAG flags;
192 {
193 	switch (flags)
194 	{
195 		case SMDB_CURSOR_GET_FIRST:
196 			return DB_FIRST;
197 
198 		case SMDB_CURSOR_GET_LAST:
199 			return DB_LAST;
200 
201 		case SMDB_CURSOR_GET_NEXT:
202 			return DB_NEXT;
203 
204 		case SMDB_CURSOR_GET_RANGE:
205 			return DB_SET_RANGE;
206 
207 		default:
208 			return -1;
209 	}
210 }
211 
212 SMDB_DB2_DATABASE *
213 smdb2_malloc_database()
214 {
215 	SMDB_DB2_DATABASE *db2;
216 
217 	db2 = (SMDB_DB2_DATABASE *) malloc(sizeof(SMDB_DB2_DATABASE));
218 	if (db2 != NULL)
219 		db2->smdb2_lock_fd = -1;
220 
221 	return db2;
222 }
223 
224 
225 /*
226 ** Except for smdb_db_open, the rest of these function correspond to the
227 ** interface laid out in smdb.h.
228 */
229 
230 int
231 smdb2_close(database)
232 	SMDB_DATABASE *database;
233 {
234 	SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
235 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
236 
237 	if (db2->smdb2_lock_fd != -1)
238 		close(db2->smdb2_lock_fd);
239 
240 	free(db2);
241 	database->smdb_impl = NULL;
242 
243 	return db2_error_to_smdb(db->close(db, 0));
244 }
245 
246 int
247 smdb2_del(database, key, flags)
248 	SMDB_DATABASE *database;
249 	SMDB_DBENT *key;
250 	u_int flags;
251 {
252 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
253 	DBT dbkey;
254 
255 	memset(&dbkey, '\0', sizeof dbkey);
256 	dbkey.data = key->data;
257 	dbkey.size = key->size;
258 	return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags));
259 }
260 
261 int
262 smdb2_fd(database, fd)
263 	SMDB_DATABASE *database;
264 	int *fd;
265 {
266 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
267 
268 	return db2_error_to_smdb(db->fd(db, fd));
269 }
270 
271 int
272 smdb2_lockfd(database)
273 	SMDB_DATABASE *database;
274 {
275 	SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
276 
277 	return db2->smdb2_lock_fd;
278 }
279 
280 
281 int
282 smdb2_get(database, key, data, flags)
283 	SMDB_DATABASE *database;
284 	SMDB_DBENT *key;
285 	SMDB_DBENT *data;
286 	u_int flags;
287 {
288 	int result;
289 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
290 	DBT dbkey, dbdata;
291 
292 	memset(&dbdata, '\0', sizeof dbdata);
293 	memset(&dbkey, '\0', sizeof dbkey);
294 	dbkey.data = key->data;
295 	dbkey.size = key->size;
296 
297 	result = db->get(db, NULL, &dbkey, &dbdata, flags);
298 	data->data = dbdata.data;
299 	data->size = dbdata.size;
300 	return db2_error_to_smdb(result);
301 }
302 
303 int
304 smdb2_put(database, key, data, flags)
305 	SMDB_DATABASE *database;
306 	SMDB_DBENT *key;
307 	SMDB_DBENT *data;
308 	u_int flags;
309 {
310 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
311 	DBT dbkey, dbdata;
312 
313 	memset(&dbdata, '\0', sizeof dbdata);
314 	memset(&dbkey, '\0', sizeof dbkey);
315 	dbkey.data = key->data;
316 	dbkey.size = key->size;
317 	dbdata.data = data->data;
318 	dbdata.size = data->size;
319 
320 	return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata,
321 					 smdb_put_flags_to_db2_flags(flags)));
322 }
323 
324 
325 int
326 smdb2_set_owner(database, uid, gid)
327 	SMDB_DATABASE *database;
328 	uid_t uid;
329 	gid_t gid;
330 {
331 # if HASFCHOWN
332 	int fd;
333 	int result;
334 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
335 
336 	result = db->fd(db, &fd);
337 	if (result != 0)
338 		return result;
339 
340 	result = fchown(fd, uid, gid);
341 	if (result < 0)
342 		return errno;
343 # endif /* HASFCHOWN */
344 
345 	return SMDBE_OK;
346 }
347 
348 int
349 smdb2_sync(database, flags)
350 	SMDB_DATABASE *database;
351 	u_int flags;
352 {
353 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
354 
355 	return db2_error_to_smdb(db->sync(db, flags));
356 }
357 
358 int
359 smdb2_cursor_close(cursor)
360 	SMDB_CURSOR *cursor;
361 {
362 	int ret;
363 	DBC *dbc = (DBC *) cursor->smdbc_impl;
364 
365 	ret = db2_error_to_smdb(dbc->c_close(dbc));
366 	free(cursor);
367 	return ret;
368 }
369 
370 int
371 smdb2_cursor_del(cursor, flags)
372 	SMDB_CURSOR *cursor;
373 	SMDB_FLAG flags;
374 {
375 	DBC *dbc = (DBC *) cursor->smdbc_impl;
376 
377 	return db2_error_to_smdb(dbc->c_del(dbc, 0));
378 }
379 
380 int
381 smdb2_cursor_get(cursor, key, value, flags)
382 	SMDB_CURSOR *cursor;
383 	SMDB_DBENT *key;
384 	SMDB_DBENT *value;
385 	SMDB_FLAG flags;
386 {
387 	int db2_flags;
388 	int result;
389 	DBC *dbc = (DBC *) cursor->smdbc_impl;
390 	DBT dbkey, dbdata;
391 
392 	memset(&dbdata, '\0', sizeof dbdata);
393 	memset(&dbkey, '\0', sizeof dbkey);
394 
395 	db2_flags = smdb_cursor_get_flags_to_db2(flags);
396 	result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags);
397 	if (result == DB_NOTFOUND)
398 		return SMDBE_LAST_ENTRY;
399 	key->data = dbkey.data;
400 	key->size = dbkey.size;
401 	value->data = dbdata.data;
402 	value->size = dbdata.size;
403 	return db2_error_to_smdb(result);
404 }
405 
406 int
407 smdb2_cursor_put(cursor, key, value, flags)
408 	SMDB_CURSOR *cursor;
409 	SMDB_DBENT *key;
410 	SMDB_DBENT *value;
411 	SMDB_FLAG flags;
412 {
413 	DBC *dbc = (DBC *) cursor->smdbc_impl;
414 	DBT dbkey, dbdata;
415 
416 	memset(&dbdata, '\0', sizeof dbdata);
417 	memset(&dbkey, '\0', sizeof dbkey);
418 	dbkey.data = key->data;
419 	dbkey.size = key->size;
420 	dbdata.data = value->data;
421 	dbdata.size = value->size;
422 
423 	return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0));
424 }
425 
426 int
427 smdb2_cursor(database, cursor, flags)
428 	SMDB_DATABASE *database;
429 	SMDB_CURSOR **cursor;
430 	SMDB_FLAG flags;
431 {
432 	int result;
433 	DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
434 	DBC *db2_cursor;
435 
436 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
437 	result = db->cursor(db, NULL, &db2_cursor, 0);
438 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
439 	result = db->cursor(db, NULL, &db2_cursor);
440 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
441 	if (result != 0)
442 		return db2_error_to_smdb(result);
443 
444 	*cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
445 	if (*cursor == NULL)
446 		return SMDBE_MALLOC;
447 
448 	(*cursor)->smdbc_close = smdb2_cursor_close;
449 	(*cursor)->smdbc_del = smdb2_cursor_del;
450 	(*cursor)->smdbc_get = smdb2_cursor_get;
451 	(*cursor)->smdbc_put = smdb2_cursor_put;
452 	(*cursor)->smdbc_impl = db2_cursor;
453 
454 	return SMDBE_OK;
455 }
456 
457 # if DB_VERSION_MAJOR == 2
458 static int
459 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
460 	char *db_name;
461 	DBTYPE db_type;
462 	int db_flags;
463 	SMDB_DBPARAMS *db_params;
464 	DB **db;
465 {
466 	void *params;
467 	DB_INFO db_info;
468 
469 	params = NULL;
470 	memset(&db_info, '\0', sizeof db_info);
471 	if (db_params != NULL)
472 	{
473 		db_info.db_cachesize = db_params->smdbp_cache_size;
474 		if (db_type == DB_HASH)
475 			db_info.h_nelem = db_params->smdbp_num_elements;
476 		if (db_params->smdbp_allow_dup)
477 			db_info.flags |= DB_DUP;
478 		params = &db_info;
479 	}
480 	return db_open(db_name, db_type, db_flags, 0644, NULL, params, db);
481 }
482 # endif /* DB_VERSION_MAJOR == 2 */
483 
484 # if DB_VERSION_MAJOR > 2
485 static int
486 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
487 	char *db_name;
488 	DBTYPE db_type;
489 	int db_flags;
490 	SMDB_DBPARAMS *db_params;
491 	DB **db;
492 {
493 	int result;
494 
495 	result = db_create(db, NULL, 0);
496 	if (result != 0 || *db == NULL)
497 		return result;
498 
499 	if (db_params != NULL)
500 	{
501 		result = (*db)->set_cachesize(*db, 0,
502 					      db_params->smdbp_cache_size, 0);
503 		if (result != 0)
504 		{
505 			(void) (*db)->close((*db), 0);
506 			*db = NULL;
507 			return db2_error_to_smdb(result);
508 		}
509 		if (db_type == DB_HASH)
510 		{
511 			result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements);
512 			if (result != 0)
513 			{
514 				(void) (*db)->close(*db, 0);
515 				*db = NULL;
516 				return db2_error_to_smdb(result);
517 			}
518 		}
519 		if (db_params->smdbp_allow_dup)
520 		{
521 			result = (*db)->set_flags(*db, DB_DUP);
522 			if (result != 0)
523 			{
524 				(void) (*db)->close(*db, 0);
525 				*db = NULL;
526 				return db2_error_to_smdb(result);
527 			}
528 		}
529 	}
530 
531 	result = (*db)->open(*db, db_name, NULL, db_type, db_flags, 0644);
532 	if (result != 0)
533 	{
534 		(void) (*db)->close(*db, 0);
535 		*db = NULL;
536 	}
537 	return db2_error_to_smdb(result);
538 }
539 # endif /* DB_VERSION_MAJOR > 2 */
540 /*
541 **  SMDB_DB_OPEN -- Opens a db database.
542 **
543 **	Parameters:
544 **		database -- An unallocated database pointer to a pointer.
545 **		db_name -- The name of the database without extension.
546 **		mode -- File permisions for a created database.
547 **		mode_mask -- Mode bits that must match on an opened database.
548 **		sff -- Flags for safefile.
549 **		type -- The type of database to open
550 **			See smdb_type_to_db2_type for valid types.
551 **		user_info -- User information for file permissions.
552 **		db_params --
553 **			An SMDB_DBPARAMS struct including params. These
554 **			are processed according to the type of the
555 **			database. Currently supported params (only for
556 **			HASH type) are:
557 **			   num_elements
558 **			   cache_size
559 **
560 **	Returns:
561 **		SMDBE_OK -- Success, other errno:
562 **		SMDBE_MALLOC -- Cannot allocate memory.
563 **		SMDBE_BAD_OPEN -- db_open didn't return an error, but
564 **				 somehow the DB pointer is NULL.
565 **		Anything else: translated error from db2
566 */
567 
568 int
569 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
570 	SMDB_DATABASE **database;
571 	char *db_name;
572 	int mode;
573 	int mode_mask;
574 	long sff;
575 	SMDB_DBTYPE type;
576 	SMDB_USER_INFO *user_info;
577 	SMDB_DBPARAMS *db_params;
578 {
579 	bool lockcreated = FALSE;
580 	int result;
581 	int db_flags;
582 	int lock_fd;
583 	int db_fd;
584 	SMDB_DATABASE *smdb_db;
585 	SMDB_DB2_DATABASE *db2;
586 	DB *db;
587 	DBTYPE db_type;
588 	struct stat stat_info;
589 	char db_file_name[SMDB_MAX_NAME_LEN];
590 
591 	*database = NULL;
592 
593 	result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN,
594 				    db_name, SMDB2_FILE_EXTENSION);
595 	if (result != SMDBE_OK)
596 		return result;
597 
598 	result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION,
599 				 mode_mask, sff, user_info, &stat_info);
600 	if (result != SMDBE_OK)
601 		return result;
602 
603 	lock_fd = -1;
604 
605 	if (stat_info.st_mode == ST_MODE_NOFILE &&
606 	    bitset(mode, O_CREAT))
607 		lockcreated = TRUE;
608 
609 	result = smdb_lock_file(&lock_fd, db_name, mode, sff,
610 				SMDB2_FILE_EXTENSION);
611 	if (result != SMDBE_OK)
612 		return result;
613 
614 	if (lockcreated)
615 	{
616 		mode |= O_TRUNC;
617 		mode &= ~(O_CREAT|O_EXCL);
618 	}
619 
620 	smdb_db = smdb_malloc_database();
621 	if (smdb_db == NULL)
622 		return SMDBE_MALLOC;
623 
624 	db2 = smdb2_malloc_database();
625 	if (db2 == NULL)
626 		return SMDBE_MALLOC;
627 
628 	db2->smdb2_lock_fd = lock_fd;
629 
630 	db_type = smdb_type_to_db2_type(type);
631 
632 	db = NULL;
633 
634 	db_flags = 0;
635 	if (bitset(O_CREAT, mode))
636 		db_flags |= DB_CREATE;
637 	if (bitset(O_TRUNC, mode))
638 		db_flags |= DB_TRUNCATE;
639 	if (mode == O_RDONLY)
640 		db_flags |= DB_RDONLY;
641 # if !HASFLOCK && defined(DB_FCNTL_LOCKING)
642 	db_flags |= DB_FCNTL_LOCKING;
643 # endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
644 
645 	result = smdb_db_open_internal(db_file_name, db_type,
646 				       db_flags, db_params, &db);
647 
648 	if (result == 0 && db != NULL)
649 	{
650 		result = db->fd(db, &db_fd);
651 		if (result == 0)
652 			result = SMDBE_OK;
653 	}
654 	else
655 	{
656 		/* Try and narrow down on the problem */
657 		if (result != 0)
658 			result = db2_error_to_smdb(result);
659 		else
660 			result = SMDBE_BAD_OPEN;
661 	}
662 
663 	if (result == SMDBE_OK)
664 		result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd,
665 					  &stat_info);
666 
667 	if (result == SMDBE_OK)
668 	{
669 		/* Everything is ok. Setup driver */
670 		db2->smdb2_db = db;
671 
672 		smdb_db->smdb_close = smdb2_close;
673 		smdb_db->smdb_del = smdb2_del;
674 		smdb_db->smdb_fd = smdb2_fd;
675 		smdb_db->smdb_lockfd = smdb2_lockfd;
676 		smdb_db->smdb_get = smdb2_get;
677 		smdb_db->smdb_put = smdb2_put;
678 		smdb_db->smdb_set_owner = smdb2_set_owner;
679 		smdb_db->smdb_sync = smdb2_sync;
680 		smdb_db->smdb_cursor = smdb2_cursor;
681 		smdb_db->smdb_impl = db2;
682 
683 		*database = smdb_db;
684 
685 		return SMDBE_OK;
686 	}
687 
688 	if (db != NULL)
689 		db->close(db, 0);
690 
691 	smdb_unlock_file(db2->smdb2_lock_fd);
692 	free(db2);
693 	smdb_free_database(smdb_db);
694 
695 	return result;
696 }
697 
698 #endif /* (DB_VERSION_MAJOR >= 2) */
699