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