xref: /freebsd/contrib/sendmail/libsmdb/smdb1.c (revision c68eed82a3dcadf0c826e9e150f59769f4c44f24)
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>
11 SM_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 struct smdb_db1_struct
23 {
24 	DB	*smdb1_db;
25 	int	smdb1_lock_fd;
26 	bool	smdb1_cursor_in_use;
27 };
28 typedef struct smdb_db1_struct SMDB_DB1_DATABASE;
29 
30 struct smdb_db1_cursor
31 {
32 	SMDB_DB1_DATABASE	*db;
33 };
34 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR;
35 
36 static DBTYPE		smdb_type_to_db1_type __P((SMDB_DBTYPE));
37 static unsigned int	smdb_put_flags_to_db1_flags __P((SMDB_FLAG));
38 static int		smdb_cursor_get_flags_to_smdb1 __P((SMDB_FLAG));
39 static SMDB_DB1_DATABASE *smdb1_malloc_database __P((void));
40 static int		smdb1_close __P((SMDB_DATABASE *));
41 static int		smdb1_del __P((SMDB_DATABASE *, SMDB_DBENT *, unsigned int));
42 static int		smdb1_fd __P((SMDB_DATABASE *, int *));
43 static int		smdb1_lockfd __P((SMDB_DATABASE *));
44 static int		smdb1_get __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int));
45 static int		smdb1_put __P((SMDB_DATABASE *, SMDB_DBENT *, SMDB_DBENT *, unsigned int));
46 static int		smdb1_set_owner __P((SMDB_DATABASE *, uid_t, gid_t));
47 static int		smdb1_sync __P((SMDB_DATABASE *, unsigned int));
48 static int		smdb1_cursor_close __P((SMDB_CURSOR *));
49 static int		smdb1_cursor_del __P((SMDB_CURSOR *, unsigned int));
50 static int		smdb1_cursor_get __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG));
51 static int		smdb1_cursor_put __P((SMDB_CURSOR *, SMDB_DBENT *, SMDB_DBENT *, SMDB_FLAG));
52 static 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 
66 static DBTYPE
67 smdb_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 
96 static unsigned int
97 smdb_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 
123 static int
124 smdb_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 
150 static SMDB_DB1_DATABASE *
151 smdb1_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 
166 static int
167 smdb1_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 
184 static int
185 smdb1_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 
199 static int
200 smdb1_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 
213 static int
214 smdb1_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 
223 static int
224 smdb1_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 
251 static int
252 smdb1_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 
272 static int
273 smdb1_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 
295 static int
296 smdb1_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 
305 static int
306 smdb1_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 
321 static int
322 smdb1_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 
333 static int
334 smdb1_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 
363 static int
364 smdb1_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 
385 static int
386 smdb1_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 permissions 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 
445 int
446 smdb_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