]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/libsmdb/smndbm.c
Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for details
[FreeBSD/FreeBSD.git] / contrib / sendmail / libsmdb / smndbm.c
1 /*
2 ** Copyright (c) 1999-2002 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: smndbm.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 #ifdef NDBM
21
22 # define SMNDB_PAG_FILE_EXTENSION "pag"
23
24 struct smdb_dbm_database_struct
25 {
26         DBM     *smndbm_dbm;
27         int     smndbm_lock_fd;
28         bool    smndbm_cursor_in_use;
29 };
30 typedef struct smdb_dbm_database_struct SMDB_DBM_DATABASE;
31
32 struct smdb_dbm_cursor_struct
33 {
34         SMDB_DBM_DATABASE       *smndbmc_db;
35         datum                   smndbmc_current_key;
36 };
37 typedef struct smdb_dbm_cursor_struct SMDB_DBM_CURSOR;
38
39 /*
40 **  SMDB_PUT_FLAGS_TO_NDBM_FLAGS -- Translates smdb put flags to ndbm put flags.
41 **
42 **      Parameters:
43 **              flags -- The flags to translate.
44 **
45 **      Returns:
46 **              The ndbm flags that are equivalent to the smdb flags.
47 **
48 **      Notes:
49 **              Any invalid flags are ignored.
50 **
51 */
52
53 int
54 smdb_put_flags_to_ndbm_flags(flags)
55         SMDB_FLAG flags;
56 {
57         int return_flags;
58
59         return_flags = 0;
60         if (bitset(SMDBF_NO_OVERWRITE, flags))
61                 return_flags = DBM_INSERT;
62         else
63                 return_flags = DBM_REPLACE;
64
65         return return_flags;
66 }
67
68 /*
69 **  Except for smdb_ndbm_open, the rest of these function correspond to the
70 **  interface laid out in smdb.h.
71 */
72
73 SMDB_DBM_DATABASE *
74 smdbm_malloc_database()
75 {
76         SMDB_DBM_DATABASE *db;
77
78         db = (SMDB_DBM_DATABASE *) malloc(sizeof(SMDB_DBM_DATABASE));
79         if (db != NULL)
80         {
81                 db->smndbm_dbm = NULL;
82                 db->smndbm_lock_fd = -1;
83                 db->smndbm_cursor_in_use = false;
84         }
85
86         return db;
87 }
88
89 int
90 smdbm_close(database)
91         SMDB_DATABASE *database;
92 {
93         SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
94         DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
95
96         dbm_close(dbm);
97         if (db->smndbm_lock_fd != -1)
98                 close(db->smndbm_lock_fd);
99
100         free(db);
101         database->smdb_impl = NULL;
102
103         return SMDBE_OK;
104 }
105
106 int
107 smdbm_del(database, key, flags)
108         SMDB_DATABASE *database;
109         SMDB_DBENT *key;
110         unsigned int flags;
111 {
112         int result;
113         DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
114         datum dbkey;
115
116         (void) memset(&dbkey, '\0', sizeof dbkey);
117         dbkey.dptr = key->data;
118         dbkey.dsize = key->size;
119
120         errno = 0;
121         result = dbm_delete(dbm, dbkey);
122         if (result != 0)
123         {
124                 int save_errno = errno;
125
126                 if (dbm_error(dbm))
127                         return SMDBE_IO_ERROR;
128
129                 if (save_errno != 0)
130                         return save_errno;
131
132                 return SMDBE_NOT_FOUND;
133         }
134         return SMDBE_OK;
135 }
136
137 int
138 smdbm_fd(database, fd)
139         SMDB_DATABASE *database;
140         int *fd;
141 {
142         DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
143
144         *fd = dbm_dirfno(dbm);
145         if (*fd <= 0)
146                 return EINVAL;
147
148         return SMDBE_OK;
149 }
150
151 int
152 smdbm_lockfd(database)
153         SMDB_DATABASE *database;
154 {
155         SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
156
157         return db->smndbm_lock_fd;
158 }
159
160 int
161 smdbm_get(database, key, data, flags)
162         SMDB_DATABASE *database;
163         SMDB_DBENT *key;
164         SMDB_DBENT *data;
165         unsigned int flags;
166 {
167         DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
168         datum dbkey, dbdata;
169
170         (void) memset(&dbkey, '\0', sizeof dbkey);
171         (void) memset(&dbdata, '\0', sizeof dbdata);
172         dbkey.dptr = key->data;
173         dbkey.dsize = key->size;
174
175         errno = 0;
176         dbdata = dbm_fetch(dbm, dbkey);
177         if (dbdata.dptr == NULL)
178         {
179                 int save_errno = errno;
180
181                 if (dbm_error(dbm))
182                         return SMDBE_IO_ERROR;
183
184                 if (save_errno != 0)
185                         return save_errno;
186
187                 return SMDBE_NOT_FOUND;
188         }
189         data->data = dbdata.dptr;
190         data->size = dbdata.dsize;
191         return SMDBE_OK;
192 }
193
194 int
195 smdbm_put(database, key, data, flags)
196         SMDB_DATABASE *database;
197         SMDB_DBENT *key;
198         SMDB_DBENT *data;
199         unsigned int flags;
200 {
201         int result;
202         int save_errno;
203         DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
204         datum dbkey, dbdata;
205
206         (void) memset(&dbkey, '\0', sizeof dbkey);
207         (void) memset(&dbdata, '\0', sizeof dbdata);
208         dbkey.dptr = key->data;
209         dbkey.dsize = key->size;
210         dbdata.dptr = data->data;
211         dbdata.dsize = data->size;
212
213         errno = 0;
214         result = dbm_store(dbm, dbkey, dbdata,
215                            smdb_put_flags_to_ndbm_flags(flags));
216         switch (result)
217         {
218           case 1:
219                 return SMDBE_DUPLICATE;
220
221           case 0:
222                 return SMDBE_OK;
223
224           default:
225                 save_errno = errno;
226
227                 if (dbm_error(dbm))
228                         return SMDBE_IO_ERROR;
229
230                 if (save_errno != 0)
231                         return save_errno;
232
233                 return SMDBE_IO_ERROR;
234         }
235         /* NOTREACHED */
236 }
237
238 int
239 smndbm_set_owner(database, uid, gid)
240         SMDB_DATABASE *database;
241         uid_t uid;
242         gid_t gid;
243 {
244 # if HASFCHOWN
245         int fd;
246         int result;
247         DBM *dbm = ((SMDB_DBM_DATABASE *) database->smdb_impl)->smndbm_dbm;
248
249         fd = dbm_dirfno(dbm);
250         if (fd <= 0)
251                 return EINVAL;
252
253         result = fchown(fd, uid, gid);
254         if (result < 0)
255                 return errno;
256
257         fd = dbm_pagfno(dbm);
258         if (fd <= 0)
259                 return EINVAL;
260
261         result = fchown(fd, uid, gid);
262         if (result < 0)
263                 return errno;
264 # endif /* HASFCHOWN */
265
266         return SMDBE_OK;
267 }
268
269 int
270 smdbm_sync(database, flags)
271         SMDB_DATABASE *database;
272         unsigned int flags;
273 {
274         return SMDBE_UNSUPPORTED;
275 }
276
277 int
278 smdbm_cursor_close(cursor)
279         SMDB_CURSOR *cursor;
280 {
281         SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
282         SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
283
284         if (!db->smndbm_cursor_in_use)
285                 return SMDBE_NOT_A_VALID_CURSOR;
286
287         db->smndbm_cursor_in_use = false;
288         free(dbm_cursor);
289         free(cursor);
290
291         return SMDBE_OK;
292 }
293
294 int
295 smdbm_cursor_del(cursor, flags)
296         SMDB_CURSOR *cursor;
297         unsigned int flags;
298 {
299         int result;
300         SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
301         SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
302         DBM *dbm = db->smndbm_dbm;
303
304         errno = 0;
305         result = dbm_delete(dbm, dbm_cursor->smndbmc_current_key);
306         if (result != 0)
307         {
308                 int save_errno = errno;
309
310                 if (dbm_error(dbm))
311                         return SMDBE_IO_ERROR;
312
313                 if (save_errno != 0)
314                         return save_errno;
315
316                 return SMDBE_NOT_FOUND;
317         }
318         return SMDBE_OK;
319 }
320
321 int
322 smdbm_cursor_get(cursor, key, value, flags)
323         SMDB_CURSOR *cursor;
324         SMDB_DBENT *key;
325         SMDB_DBENT *value;
326         SMDB_FLAG flags;
327 {
328         SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
329         SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
330         DBM *dbm = db->smndbm_dbm;
331         datum dbkey, dbdata;
332
333         (void) memset(&dbkey, '\0', sizeof dbkey);
334         (void) memset(&dbdata, '\0', sizeof dbdata);
335
336         if (flags == SMDB_CURSOR_GET_RANGE)
337                 return SMDBE_UNSUPPORTED;
338
339         if (dbm_cursor->smndbmc_current_key.dptr == NULL)
340         {
341                 dbm_cursor->smndbmc_current_key = dbm_firstkey(dbm);
342                 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
343                 {
344                         if (dbm_error(dbm))
345                                 return SMDBE_IO_ERROR;
346                         return SMDBE_LAST_ENTRY;
347                 }
348         }
349         else
350         {
351                 dbm_cursor->smndbmc_current_key = dbm_nextkey(dbm);
352                 if (dbm_cursor->smndbmc_current_key.dptr == NULL)
353                 {
354                         if (dbm_error(dbm))
355                                 return SMDBE_IO_ERROR;
356                         return SMDBE_LAST_ENTRY;
357                 }
358         }
359
360         errno = 0;
361         dbdata = dbm_fetch(dbm, dbm_cursor->smndbmc_current_key);
362         if (dbdata.dptr == NULL)
363         {
364                 int save_errno = errno;
365
366                 if (dbm_error(dbm))
367                         return SMDBE_IO_ERROR;
368
369                 if (save_errno != 0)
370                         return save_errno;
371
372                 return SMDBE_NOT_FOUND;
373         }
374         value->data = dbdata.dptr;
375         value->size = dbdata.dsize;
376         key->data = dbm_cursor->smndbmc_current_key.dptr;
377         key->size = dbm_cursor->smndbmc_current_key.dsize;
378
379         return SMDBE_OK;
380 }
381
382 int
383 smdbm_cursor_put(cursor, key, value, flags)
384         SMDB_CURSOR *cursor;
385         SMDB_DBENT *key;
386         SMDB_DBENT *value;
387         SMDB_FLAG flags;
388 {
389         int result;
390         int save_errno;
391         SMDB_DBM_CURSOR *dbm_cursor = (SMDB_DBM_CURSOR *) cursor->smdbc_impl;
392         SMDB_DBM_DATABASE *db = dbm_cursor->smndbmc_db;
393         DBM *dbm = db->smndbm_dbm;
394         datum dbdata;
395
396         (void) memset(&dbdata, '\0', sizeof dbdata);
397         dbdata.dptr = value->data;
398         dbdata.dsize = value->size;
399
400         errno = 0;
401         result = dbm_store(dbm, dbm_cursor->smndbmc_current_key, dbdata,
402                            smdb_put_flags_to_ndbm_flags(flags));
403         switch (result)
404         {
405           case 1:
406                 return SMDBE_DUPLICATE;
407
408           case 0:
409                 return SMDBE_OK;
410
411           default:
412                 save_errno = errno;
413
414                 if (dbm_error(dbm))
415                         return SMDBE_IO_ERROR;
416
417                 if (save_errno != 0)
418                         return save_errno;
419
420                 return SMDBE_IO_ERROR;
421         }
422         /* NOTREACHED */
423 }
424
425 int
426 smdbm_cursor(database, cursor, flags)
427         SMDB_DATABASE *database;
428         SMDB_CURSOR **cursor;
429         SMDB_FLAG flags;
430 {
431         SMDB_DBM_DATABASE *db = (SMDB_DBM_DATABASE *) database->smdb_impl;
432         SMDB_CURSOR *cur;
433         SMDB_DBM_CURSOR *dbm_cursor;
434
435         if (db->smndbm_cursor_in_use)
436                 return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
437
438         db->smndbm_cursor_in_use = true;
439         dbm_cursor = (SMDB_DBM_CURSOR *) malloc(sizeof(SMDB_DBM_CURSOR));
440         if (dbm_cursor == NULL)
441                 return SMDBE_MALLOC;
442         dbm_cursor->smndbmc_db = db;
443         dbm_cursor->smndbmc_current_key.dptr = NULL;
444         dbm_cursor->smndbmc_current_key.dsize = 0;
445
446         cur = (SMDB_CURSOR*) malloc(sizeof(SMDB_CURSOR));
447         if (cur == NULL)
448         {
449                 free(dbm_cursor);
450                 return SMDBE_MALLOC;
451         }
452
453         cur->smdbc_impl = dbm_cursor;
454         cur->smdbc_close = smdbm_cursor_close;
455         cur->smdbc_del = smdbm_cursor_del;
456         cur->smdbc_get = smdbm_cursor_get;
457         cur->smdbc_put = smdbm_cursor_put;
458         *cursor = cur;
459
460         return SMDBE_OK;
461 }
462 /*
463 **  SMDB_NDBM_OPEN -- Opens a ndbm database.
464 **
465 **      Parameters:
466 **              database -- An unallocated database pointer to a pointer.
467 **              db_name -- The name of the database without extension.
468 **              mode -- File permisions on a created database.
469 **              mode_mask -- Mode bits that much match on an opened database.
470 **              sff -- Flags to safefile.
471 **              type -- The type of database to open.
472 **                      Only SMDB_NDBM is supported.
473 **              user_info -- Information on the user to use for file
474 **                          permissions.
475 **              db_params -- No params are supported.
476 **
477 **      Returns:
478 **              SMDBE_OK -- Success, otherwise errno:
479 **              SMDBE_MALLOC -- Cannot allocate memory.
480 **              SMDBE_UNSUPPORTED -- The type is not supported.
481 **              SMDBE_GDBM_IS_BAD -- We have detected GDBM and we don't
482 **                                  like it.
483 **              SMDBE_BAD_OPEN -- dbm_open failed and errno was not set.
484 **              Anything else: errno
485 */
486
487 int
488 smdb_ndbm_open(database, db_name, mode, mode_mask, sff, type, user_info,
489                db_params)
490         SMDB_DATABASE **database;
491         char *db_name;
492         int mode;
493         int mode_mask;
494         long sff;
495         SMDB_DBTYPE type;
496         SMDB_USER_INFO *user_info;
497         SMDB_DBPARAMS *db_params;
498 {
499         bool lockcreated = false;
500         int result;
501         int lock_fd;
502         SMDB_DATABASE *smdb_db;
503         SMDB_DBM_DATABASE *db;
504         DBM *dbm = NULL;
505         struct stat dir_stat_info;
506         struct stat pag_stat_info;
507
508         result = SMDBE_OK;
509         *database = NULL;
510
511         if (type == NULL)
512                 return SMDBE_UNKNOWN_DB_TYPE;
513
514         result = smdb_setup_file(db_name, SMNDB_DIR_FILE_EXTENSION, mode_mask,
515                                  sff, user_info, &dir_stat_info);
516         if (result != SMDBE_OK)
517                 return result;
518
519         result = smdb_setup_file(db_name, SMNDB_PAG_FILE_EXTENSION, mode_mask,
520                                  sff, user_info, &pag_stat_info);
521         if (result != SMDBE_OK)
522                 return result;
523
524         if ((dir_stat_info.st_mode == ST_MODE_NOFILE ||
525              pag_stat_info.st_mode == ST_MODE_NOFILE) &&
526             bitset(mode, O_CREAT))
527                 lockcreated = true;
528
529         lock_fd = -1;
530         result = smdb_lock_file(&lock_fd, db_name, mode, sff,
531                                 SMNDB_DIR_FILE_EXTENSION);
532         if (result != SMDBE_OK)
533                 return result;
534
535         if (lockcreated)
536         {
537                 int pag_fd;
538
539                 /* Need to pre-open the .pag file as well with O_EXCL */
540                 result = smdb_lock_file(&pag_fd, db_name, mode, sff,
541                                         SMNDB_PAG_FILE_EXTENSION);
542                 if (result != SMDBE_OK)
543                 {
544                         (void) close(lock_fd);
545                         return result;
546                 }
547                 (void) close(pag_fd);
548
549                 mode |= O_TRUNC;
550                 mode &= ~(O_CREAT|O_EXCL);
551         }
552
553         smdb_db = smdb_malloc_database();
554         if (smdb_db == NULL)
555                 result = SMDBE_MALLOC;
556
557         db = smdbm_malloc_database();
558         if (db == NULL)
559                 result = SMDBE_MALLOC;
560
561         /* Try to open database */
562         if (result == SMDBE_OK)
563         {
564                 db->smndbm_lock_fd = lock_fd;
565
566                 errno = 0;
567                 dbm = dbm_open(db_name, mode, DBMMODE);
568                 if (dbm == NULL)
569                 {
570                         if (errno == 0)
571                                 result = SMDBE_BAD_OPEN;
572                         else
573                                 result = errno;
574                 }
575                 db->smndbm_dbm = dbm;
576         }
577
578         /* Check for GDBM */
579         if (result == SMDBE_OK)
580         {
581                 if (dbm_dirfno(dbm) == dbm_pagfno(dbm))
582                         result = SMDBE_GDBM_IS_BAD;
583         }
584
585         /* Check for filechanged */
586         if (result == SMDBE_OK)
587         {
588                 result = smdb_filechanged(db_name, SMNDB_DIR_FILE_EXTENSION,
589                                           dbm_dirfno(dbm), &dir_stat_info);
590                 if (result == SMDBE_OK)
591                 {
592                         result = smdb_filechanged(db_name,
593                                                   SMNDB_PAG_FILE_EXTENSION,
594                                                   dbm_pagfno(dbm),
595                                                   &pag_stat_info);
596                 }
597         }
598
599         /* XXX Got to get fchown stuff in here */
600
601         /* Setup driver if everything is ok */
602         if (result == SMDBE_OK)
603         {
604                 *database = smdb_db;
605
606                 smdb_db->smdb_close = smdbm_close;
607                 smdb_db->smdb_del = smdbm_del;
608                 smdb_db->smdb_fd = smdbm_fd;
609                 smdb_db->smdb_lockfd = smdbm_lockfd;
610                 smdb_db->smdb_get = smdbm_get;
611                 smdb_db->smdb_put = smdbm_put;
612                 smdb_db->smdb_set_owner = smndbm_set_owner;
613                 smdb_db->smdb_sync = smdbm_sync;
614                 smdb_db->smdb_cursor = smdbm_cursor;
615
616                 smdb_db->smdb_impl = db;
617
618                 return SMDBE_OK;
619         }
620
621         /* If we're here, something bad happened, clean up */
622         if (dbm != NULL)
623                 dbm_close(dbm);
624
625         smdb_unlock_file(db->smndbm_lock_fd);
626         free(db);
627         smdb_free_database(smdb_db);
628
629         return result;
630 }
631 #endif /* NDBM */