]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/libsmdb/smcdb.c
Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for details
[FreeBSD/FreeBSD.git] / contrib / sendmail / libsmdb / smcdb.c
1 /*
2 **  Copyright (c) 2018 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: smcdb.c,v 8.55 2013-11-22 20:51:49 ca Exp $")
12
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16
17 #include <sendmail/sendmail.h>
18 #include <libsmdb/smdb.h>
19
20 #if CDB
21 #include <assert.h>
22 #include <cdb.h>
23
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;
27 union sm_cdbs_U
28 {
29         cdb_map_T        cdbs_cdb_rd;
30         cdb_make_T       cdbs_cdb_wr;
31 };
32
33 struct smdb_cdb_database
34 {
35         sm_cdbs_T       cdbmap_map;
36         int             cdbmap_fd;
37         int             smcdb_lock_fd;
38         bool            cdbmap_create;
39         unsigned        smcdb_pos;
40         int             smcdb_n;
41 };
42 typedef struct smdb_cdb_database SMDB_CDB_DATABASE;
43
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));
60
61 /*
62 **  SMDB_TYPE_TO_CDB_TYPE -- Translates smdb database type to cdb type.
63 **
64 **      Parameters:
65 **              type -- The type to translate.
66 **
67 **      Returns:
68 **              The CDB type that corresponsds to the passed in SMDB type.
69 **              Returns -1 if there is no equivalent type.
70 **
71 */
72
73 #if 0
74 static int
75 smdb_type_to_cdb_type(type)
76         SMDB_DBTYPE type;
77 {
78         return 0;       /* XXX */
79 }
80 #endif
81
82 /*
83 **  CDB_ERROR_TO_SMDB -- Translates cdb errors to smdbe errors
84 **
85 **      Parameters:
86 **              error -- The error to translate.
87 **
88 **      Returns:
89 **              The SMDBE error corresponding to the cdb error.
90 **              If we don't have a corresponding error, it returns error.
91 **
92 */
93
94 static int
95 cdb_error_to_smdb(error)
96         int error;
97 {
98         int result;
99
100         switch (error)
101         {
102                 case 0:
103                         result = SMDBE_OK;
104                         break;
105
106                 default:
107                         result = error;
108         }
109         return result;
110 }
111
112 SMDB_CDB_DATABASE *
113 smcdb_malloc_database()
114 {
115         SMDB_CDB_DATABASE *cdb;
116
117         cdb = (SMDB_CDB_DATABASE *) malloc(sizeof(SMDB_CDB_DATABASE));
118         if (cdb != NULL)
119                 cdb->smcdb_lock_fd = -1;
120
121         return cdb;
122 }
123
124 static int
125 smcdb_close(database)
126         SMDB_DATABASE *database;
127 {
128         int result, fd;
129         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
130
131         if (NULL == sm_cdbmap)
132                 return -1;
133         result = 0;
134         if (sm_cdbmap->cdbmap_create)
135                 result = cdb_make_finish(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr);
136
137         fd = sm_cdbmap->cdbmap_fd;
138         if (fd >= 0)
139         {
140                 close(fd);
141                 sm_cdbmap->cdbmap_fd = -1;
142         }
143
144         free(sm_cdbmap);
145         database->smdb_impl = NULL;
146
147         return result;
148 }
149
150 static int
151 smcdb_del(database, key, flags)
152         SMDB_DATABASE *database;
153         SMDB_DBENT *key;
154         unsigned int flags;
155 {
156         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
157
158         assert(sm_cdbmap != NULL);
159         return -1;
160 }
161
162 static int
163 smcdb_fd(database, fd)
164         SMDB_DATABASE *database;
165         int *fd;
166 {
167         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
168         return sm_cdbmap->cdbmap_fd;
169 }
170
171 static int
172 smcdb_lockfd(database)
173         SMDB_DATABASE *database;
174 {
175         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
176
177         return sm_cdbmap->smcdb_lock_fd;
178 }
179
180 /*
181 **  allocate/free: who does it: caller or callee?
182 **  If this code does it: the "last" entry will leak.
183 */
184
185 #define DBEALLOC(dbe, l)        \
186         do      \
187         {       \
188                 if ((dbe)->size > 0 && l > (dbe)->size) \
189                 {       \
190                         free((dbe)->data);      \
191                         (dbe)->size = 0;        \
192                 }       \
193                 if ((dbe)->size == 0)   \
194                 {       \
195                         (dbe)->data = malloc(l);        \
196                         if ((dbe)->data == NULL)        \
197                                 return SMDBE_MALLOC;    \
198                         (dbe)->size = l;        \
199                 }       \
200                 if (l > (dbe)->size)    \
201                         return SMDBE_MALLOC;    /* XXX bogus */ \
202         } while (0)
203
204
205 static int
206 smcdb_get(database, key, data, flags)
207         SMDB_DATABASE *database;
208         SMDB_DBENT *key;
209         SMDB_DBENT *data;
210         unsigned int flags;
211 {
212         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
213         size_t l;
214         int ret;
215
216         ret = SM_SUCCESS;
217
218         if (NULL == sm_cdbmap )
219                 return -1;
220         /* SM_ASSERT(!sm_cdbmap->cdbmap_create); */
221
222         /* need to lock access? single threaded access! */
223         ret = cdb_find(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
224                         key->data, key->size);
225         if (ret > 0)
226         {
227                 l = cdb_datalen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
228                 DBEALLOC(data, l);
229                 ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
230                                 data->data, l,
231                                 cdb_datapos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd));
232                 if (ret < 0)
233                         ret = -1;
234                 else
235                 {
236                         data->size = l;
237                         ret = SM_SUCCESS;
238                 }
239         }
240         else
241                 ret = -1;
242
243         return ret;
244 }
245
246 static int
247 smcdb_put(database, key, data, flags)
248         SMDB_DATABASE *database;
249         SMDB_DBENT *key;
250         SMDB_DBENT *data;
251         unsigned int flags;
252 {
253         int r, cdb_flags;
254         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
255
256         assert(sm_cdbmap != NULL);
257         if (bitset(SMDBF_NO_OVERWRITE, flags))
258                 cdb_flags = CDB_PUT_INSERT;
259         else
260                 cdb_flags = CDB_PUT_REPLACE;
261
262         r = cdb_make_put(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr,
263                         key->data, key->size, data->data, data->size,
264                         cdb_flags);
265         if (r > 0)
266         {
267                 if (bitset(SMDBF_NO_OVERWRITE, flags))
268                         return SMDBE_DUPLICATE;
269                 else
270                         return SMDBE_OK;
271         }
272         return r;
273 }
274
275
276 static int
277 smcdb_set_owner(database, uid, gid)
278         SMDB_DATABASE *database;
279         uid_t uid;
280         gid_t gid;
281 {
282 # if HASFCHOWN
283         int fd;
284         int result;
285         SMDB_CDB_DATABASE *sm_cdbmap = (SMDB_CDB_DATABASE *) database->smdb_impl;
286
287         assert(sm_cdbmap != NULL);
288         fd = sm_cdbmap->cdbmap_fd;
289         if (fd >= 0)
290         {
291                 result = fchown(fd, uid, gid);
292                 if (result < 0)
293                         return errno;
294         }
295 # endif /* HASFCHOWN */
296
297         return SMDBE_OK;
298 }
299
300 static int
301 smcdb_sync(database, flags)
302         SMDB_DATABASE *database;
303         unsigned int flags;
304 {
305         return 0;
306 }
307
308 static int
309 smcdb_cursor_close(cursor)
310         SMDB_CURSOR *cursor;
311 {
312         int ret;
313
314         ret = SMDBE_OK;
315         if (cursor != NULL)
316                 free(cursor);
317         return ret;
318 }
319
320 static int
321 smcdb_cursor_del(cursor, flags)
322         SMDB_CURSOR *cursor;
323         SMDB_FLAG flags;
324 {
325         return -1;
326 }
327
328 static int
329 smcdb_cursor_get(cursor, key, value, flags)
330         SMDB_CURSOR *cursor;
331         SMDB_DBENT *key;
332         SMDB_DBENT *value;
333         SMDB_FLAG flags;
334 {
335         SMDB_CDB_DATABASE *sm_cdbmap;
336         size_t l;
337         int ret;
338
339         ret = SMDBE_OK;
340         sm_cdbmap = cursor->smdbc_impl;
341         ret = cdb_seqnext(&sm_cdbmap->smcdb_pos, &sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
342         if (ret == 0)
343                 return SMDBE_LAST_ENTRY;
344         if (ret < 0)
345                 return SMDBE_IO_ERROR;
346
347         l = cdb_keylen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
348         DBEALLOC(key, l);
349
350         ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
351                         key->data, l,
352                         cdb_keypos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd));
353         if (ret < 0)
354                 return SMDBE_IO_ERROR;
355         key->size = l;
356
357         l = cdb_datalen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
358
359         DBEALLOC(value, l);
360         ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd,
361                         value->data, l,
362                         cdb_datapos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd));
363         if (ret < 0)
364                 return SMDBE_IO_ERROR;
365         value->size = l;
366
367         return SMDBE_OK;
368 }
369
370 static int
371 smcdb_cursor_put(cursor, key, value, flags)
372         SMDB_CURSOR *cursor;
373         SMDB_DBENT *key;
374         SMDB_DBENT *value;
375         SMDB_FLAG flags;
376 {
377         return -1;
378 }
379
380 static int
381 smcdb_cursor(database, cursor, flags)
382         SMDB_DATABASE *database;
383         SMDB_CURSOR **cursor;
384         SMDB_FLAG flags;
385 {
386         int result;
387         SMDB_CDB_DATABASE *sm_cdbmap;
388
389         result = SMDBE_OK;
390         *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
391         if (*cursor == NULL)
392                 return SMDBE_MALLOC;
393
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;
400
401         cdb_seqinit(&sm_cdbmap->smcdb_pos, &sm_cdbmap->cdbmap_map.cdbs_cdb_rd);
402
403         return result;
404 }
405
406 /*
407 **  SMDB_DB_OPEN -- Opens a db database.
408 **
409 **      Parameters:
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.
418 **              db_params --
419 **                      An SMDB_DBPARAMS struct including params. These
420 **                      are processed according to the type of the
421 **                      database. Currently supported params (only for
422 **                      HASH type) are:
423 **                         num_elements
424 **                         cache_size
425 **
426 **      Returns:
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
432 */
433
434 int
435 smdb_cdb_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
436         SMDB_DATABASE **database;
437         char *db_name;
438         int mode;
439         int mode_mask;
440         long sff;
441         SMDB_DBTYPE type;
442         SMDB_USER_INFO *user_info;
443         SMDB_DBPARAMS *db_params;
444 {
445         bool lockcreated = false;
446         int result;
447         int lock_fd;
448         int db_fd;
449         SMDB_DATABASE *smdb_db;
450         SMDB_CDB_DATABASE *sm_cdbmap;
451         struct stat stat_info;
452         char db_file_name[MAXPATHLEN];
453
454         *database = NULL;
455         result = smdb_add_extension(db_file_name, sizeof db_file_name,
456                                     db_name, SMCDB_FILE_EXTENSION);
457         if (result != SMDBE_OK)
458                 return result;
459
460         result = smdb_setup_file(db_name, SMCDB_FILE_EXTENSION,
461                                  mode_mask, sff, user_info, &stat_info);
462         if (result != SMDBE_OK)
463                 return result;
464
465         lock_fd = -1;
466
467         if (stat_info.st_mode == ST_MODE_NOFILE &&
468             bitset(mode, O_CREAT))
469                 lockcreated = true;
470
471         result = smdb_lock_file(&lock_fd, db_name, mode, sff,
472                                 SMCDB_FILE_EXTENSION);
473         if (result != SMDBE_OK)
474                 return result;
475
476         if (lockcreated)
477         {
478                 mode |= O_TRUNC;
479                 mode &= ~(O_CREAT|O_EXCL);
480         }
481
482         smdb_db = smdb_malloc_database();
483         sm_cdbmap = smcdb_malloc_database();
484         if (sm_cdbmap == NULL || smdb_db == NULL)
485         {
486                 smdb_unlock_file(lock_fd);
487                 smdb_free_database(smdb_db);    /* ok to be NULL */
488                 if (sm_cdbmap != NULL)
489                         free(sm_cdbmap);
490                 return SMDBE_MALLOC;
491         }
492
493         sm_cdbmap->smcdb_lock_fd = lock_fd;
494
495 #if 0
496         db = NULL;
497         db_flags = 0;
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);
505 #endif
506
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);
509         if (db_fd == -1)
510         {
511                 result = SMDBE_BAD_OPEN;
512                 goto error;
513         }
514
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);
518         else
519                 result = cdb_make_start(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr, db_fd);
520         if (result != 0)
521         {
522                 result = SMDBE_BAD_OPEN;
523                 goto error;
524         }
525
526         if (result == 0)
527                 result = SMDBE_OK;
528         else
529         {
530                 /* Try and narrow down on the problem */
531                 if (result != 0)
532                         result = cdb_error_to_smdb(result);
533                 else
534                         result = SMDBE_BAD_OPEN;
535         }
536
537         if (result == SMDBE_OK)
538                 result = smdb_filechanged(db_name, SMCDB_FILE_EXTENSION, db_fd,
539                                           &stat_info);
540
541         if (result == SMDBE_OK)
542         {
543                 /* Everything is ok. Setup driver */
544                 /* smdb_db->smcdb_db = sm_cdbmap; */
545
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;
556
557                 *database = smdb_db;
558
559                 return SMDBE_OK;
560         }
561
562   error:
563         if (sm_cdbmap != NULL)
564         {
565                 /* close */
566         }
567
568         smdb_unlock_file(sm_cdbmap->smcdb_lock_fd);
569         free(sm_cdbmap);
570         smdb_free_database(smdb_db);
571
572         return result;
573 }
574
575 #endif /* CDB */