2 ** Copyright (c) 2018 Proofpoint, Inc. and its suppliers.
3 ** All rights reserved.
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.
11 SM_RCSID("@(#)$Id: smcdb.c,v 8.55 2013-11-22 20:51:49 ca Exp $")
17 #include <sendmail/sendmail.h>
18 #include <libsmdb/smdb.h>
24 typedef struct cdb cdb_map_T, *cdb_map_P;
25 typedef struct cdb_make cdb_make_T, *cdb_make_P;
26 typedef union sm_cdbs_U sm_cdbs_T, *sm_cdbs_P;
29 cdb_map_T cdbs_cdb_rd;
30 cdb_make_T cdbs_cdb_wr;
33 struct smdb_cdb_database
42 typedef struct smdb_cdb_database SMDB_CDB_DATABASE;
44 /* static int smdb_type_to_cdb_type __P((SMDB_DBTYPE type)); */
45 static int cdb_error_to_smdb __P((int error));
46 static SMDB_CDB_DATABASE * smcdb_malloc_database __P((void));
47 static int smcdb_close __P((SMDB_DATABASE *database));
48 static int smcdb_del __P((SMDB_DATABASE *database, SMDB_DBENT *key, unsigned int flags));
49 static int smcdb_fd __P((SMDB_DATABASE *database, int *fd));
50 static int smcdb_lockfd __P((SMDB_DATABASE *database));
51 static int smcdb_get __P((SMDB_DATABASE *database, SMDB_DBENT *key, SMDB_DBENT *data, unsigned int flags));
52 static int smcdb_put __P((SMDB_DATABASE *database, SMDB_DBENT *key, SMDB_DBENT *data, unsigned int flags));
53 static int smcdb_set_owner __P((SMDB_DATABASE *database, uid_t uid, gid_t gid));
54 static int smcdb_sync __P((SMDB_DATABASE *database, unsigned int flags));
55 static int smcdb_cursor_close __P((SMDB_CURSOR *cursor));
56 static int smcdb_cursor_del __P((SMDB_CURSOR *cursor, SMDB_FLAG flags));
57 static int smcdb_cursor_get __P((SMDB_CURSOR *cursor, SMDB_DBENT *key, SMDB_DBENT *value, SMDB_FLAG flags));
58 static int smcdb_cursor_put __P((SMDB_CURSOR *cursor, SMDB_DBENT *key, SMDB_DBENT *value, SMDB_FLAG flags));
59 static int smcdb_cursor __P((SMDB_DATABASE *database, SMDB_CURSOR **cursor, SMDB_FLAG flags));
62 ** SMDB_TYPE_TO_CDB_TYPE -- Translates smdb database type to cdb type.
65 ** type -- The type to translate.
68 ** The CDB type that corresponsds to the passed in SMDB type.
69 ** Returns -1 if there is no equivalent type.
75 smdb_type_to_cdb_type(type)
83 ** CDB_ERROR_TO_SMDB -- Translates cdb errors to smdbe errors
86 ** error -- The error to translate.
89 ** The SMDBE error corresponding to the cdb error.
90 ** If we don't have a corresponding error, it returns error.
95 cdb_error_to_smdb(error)
113 smcdb_malloc_database()
115 SMDB_CDB_DATABASE *cdb;
117 cdb = (SMDB_CDB_DATABASE *) malloc(sizeof(SMDB_CDB_DATABASE));
119 cdb->smcdb_lock_fd = -1;
125 smcdb_close(database)
126 SMDB_DATABASE *database;
129 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
131 if (NULL == sm_cdbmap)
134 if (sm_cdbmap->cdbmap_create)
135 result = cdb_make_finish(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr);
137 fd = sm_cdbmap->cdbmap_fd;
141 sm_cdbmap->cdbmap_fd = -1;
145 database->smdb_impl = NULL;
151 smcdb_del(database, key, flags)
152 SMDB_DATABASE *database;
156 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
158 assert(sm_cdbmap != NULL);
163 smcdb_fd(database, fd)
164 SMDB_DATABASE *database;
167 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
168 return sm_cdbmap->cdbmap_fd;
172 smcdb_lockfd(database)
173 SMDB_DATABASE *database;
175 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
177 return sm_cdbmap->smcdb_lock_fd;
181 ** allocate/free: who does it: caller or callee?
182 ** If this code does it: the "last" entry will leak.
185 #define DBEALLOC(dbe, l) \
188 if ((dbe)->size > 0 && l > (dbe)->size) \
193 if ((dbe)->size == 0) \
195 (dbe)->data = malloc(l); \
196 if ((dbe)->data == NULL) \
197 return SMDBE_MALLOC; \
200 if (l > (dbe)->size) \
201 return SMDBE_MALLOC; /* XXX bogus */ \
206 smcdb_get(database, key, data, flags)
207 SMDB_DATABASE *database;
212 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
218 if (NULL == sm_cdbmap )
220 /* SM_ASSERT(!sm_cdbmap->cdbmap_create); */
222 /* need to lock access? single threaded access! */
223 ret = cdb_find(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
224 key->data, key->size);
227 l = cdb_datalen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
229 ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
231 cdb_datapos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd));
247 smcdb_put(database, key, data, flags)
248 SMDB_DATABASE *database;
254 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
256 assert(sm_cdbmap != NULL);
257 if (bitset(SMDBF_NO_OVERWRITE, flags))
258 cdb_flags = CDB_PUT_INSERT;
260 cdb_flags = CDB_PUT_REPLACE;
262 r = cdb_make_put(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr,
263 key->data, key->size, data->data, data->size,
267 if (bitset(SMDBF_NO_OVERWRITE, flags))
268 return SMDBE_DUPLICATE;
277 smcdb_set_owner(database, uid, gid)
278 SMDB_DATABASE *database;
285 SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
287 assert(sm_cdbmap != NULL);
288 fd = sm_cdbmap->cdbmap_fd;
291 result = fchown(fd, uid, gid);
295 # endif /* HASFCHOWN */
301 smcdb_sync(database, flags)
302 SMDB_DATABASE *database;
309 smcdb_cursor_close(cursor)
321 smcdb_cursor_del(cursor, flags)
329 smcdb_cursor_get(cursor, key, value, flags)
335 SMDB_CDB_DATABASE *sm_cdbmap;
340 sm_cdbmap = cursor->smdbc_impl;
341 ret = cdb_seqnext(&sm_cdbmap->smcdb_pos, &sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
343 return SMDBE_LAST_ENTRY;
345 return SMDBE_IO_ERROR;
347 l = cdb_keylen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
350 ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
352 cdb_keypos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd));
354 return SMDBE_IO_ERROR;
357 l = cdb_datalen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
360 ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
362 cdb_datapos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd));
364 return SMDBE_IO_ERROR;
371 smcdb_cursor_put(cursor, key, value, flags)
381 smcdb_cursor(database, cursor, flags)
382 SMDB_DATABASE *database;
383 SMDB_CURSOR **cursor;
387 SMDB_CDB_DATABASE *sm_cdbmap;
390 *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
394 sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
395 (*cursor)->smdbc_close = smcdb_cursor_close;
396 (*cursor)->smdbc_del = smcdb_cursor_del;
397 (*cursor)->smdbc_get = smcdb_cursor_get;
398 (*cursor)->smdbc_put = smcdb_cursor_put;
399 (*cursor)->smdbc_impl = sm_cdbmap;
401 cdb_seqinit(&sm_cdbmap->smcdb_pos, &sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
407 ** SMDB_DB_OPEN -- Opens a db database.
410 ** database -- An unallocated database pointer to a pointer.
411 ** db_name -- The name of the database without extension.
412 ** mode -- File permisions for a created database.
413 ** mode_mask -- Mode bits that must match on an opened database.
414 ** sff -- Flags for safefile.
415 ** type -- The type of database to open
416 ** See smdb_type_to_cdb_type for valid types.
417 ** user_info -- User information for file permissions.
419 ** An SMDB_DBPARAMS struct including params. These
420 ** are processed according to the type of the
421 ** database. Currently supported params (only for
427 ** SMDBE_OK -- Success, other errno:
428 ** SMDBE_MALLOC -- Cannot allocate memory.
429 ** SMDBE_BAD_OPEN -- db_open didn't return an error, but
430 ** somehow the DB pointer is NULL.
431 ** Anything else: translated error from cdb
435 smdb_cdb_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
436 SMDB_DATABASE **database;
442 SMDB_USER_INFO *user_info;
443 SMDB_DBPARAMS *db_params;
445 bool lockcreated = false;
449 SMDB_DATABASE *smdb_db;
450 SMDB_CDB_DATABASE *sm_cdbmap;
451 struct stat stat_info;
452 char db_file_name[MAXPATHLEN];
455 result = smdb_add_extension(db_file_name, sizeof db_file_name,
456 db_name, SMCDB_FILE_EXTENSION);
457 if (result != SMDBE_OK)
460 result = smdb_setup_file(db_name, SMCDB_FILE_EXTENSION,
461 mode_mask, sff, user_info, &stat_info);
462 if (result != SMDBE_OK)
467 if (stat_info.st_mode == ST_MODE_NOFILE &&
468 bitset(mode, O_CREAT))
471 result = smdb_lock_file(&lock_fd, db_name, mode, sff,
472 SMCDB_FILE_EXTENSION);
473 if (result != SMDBE_OK)
479 mode &= ~(O_CREAT|O_EXCL);
482 smdb_db = smdb_malloc_database();
483 sm_cdbmap = smcdb_malloc_database();
484 if (sm_cdbmap == NULL || smdb_db == NULL)
486 smdb_unlock_file(lock_fd);
487 smdb_free_database(smdb_db); /* ok to be NULL */
488 if (sm_cdbmap != NULL)
493 sm_cdbmap->smcdb_lock_fd = lock_fd;
498 if (bitset(O_CREAT, mode))
499 db_flags |= DB_CREATE;
500 if (bitset(O_TRUNC, mode))
501 db_flags |= DB_TRUNCATE;
502 if (mode == O_RDONLY)
503 db_flags |= DB_RDONLY;
504 SM_DB_FLAG_ADD(db_flags);
507 result = -1; /* smdb_db_open_internal(db_file_name, db_type, db_flags, db_params, &db); */
508 db_fd = open(db_file_name, mode, DBMMODE);
511 result = SMDBE_BAD_OPEN;
515 sm_cdbmap->cdbmap_create = (mode != O_RDONLY);
516 if (mode == O_RDONLY)
517 result = cdb_init(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd, db_fd);
519 result = cdb_make_start(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr, db_fd);
522 result = SMDBE_BAD_OPEN;
530 /* Try and narrow down on the problem */
532 result = cdb_error_to_smdb(result);
534 result = SMDBE_BAD_OPEN;
537 if (result == SMDBE_OK)
538 result = smdb_filechanged(db_name, SMCDB_FILE_EXTENSION, db_fd,
541 if (result == SMDBE_OK)
543 /* Everything is ok. Setup driver */
544 /* smdb_db->smcdb_db = sm_cdbmap; */
546 smdb_db->smdb_close = smcdb_close;
547 smdb_db->smdb_del = smcdb_del;
548 smdb_db->smdb_fd = smcdb_fd;
549 smdb_db->smdb_lockfd = smcdb_lockfd;
550 smdb_db->smdb_get = smcdb_get;
551 smdb_db->smdb_put = smcdb_put;
552 smdb_db->smdb_set_owner = smcdb_set_owner;
553 smdb_db->smdb_sync = smcdb_sync;
554 smdb_db->smdb_cursor = smcdb_cursor;
555 smdb_db->smdb_impl = sm_cdbmap;
563 if (sm_cdbmap != NULL)
568 smdb_unlock_file(sm_cdbmap->smcdb_lock_fd);
570 smdb_free_database(smdb_db);