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