]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/libsmdb/smdb.c
Merge commit '850ef5ae11d69ea3381bd310f564f025fc8caea3'
[FreeBSD/FreeBSD.git] / contrib / sendmail / libsmdb / smdb.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: smdb.c,v 8.59 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 static bool     smdb_lockfile __P((int, int));
22
23 /*
24 **  SMDB_MALLOC_DATABASE -- Allocates a database structure.
25 **
26 **      Parameters:
27 **              None
28 **
29 **      Returns:
30 **              A pointer to an allocated SMDB_DATABASE structure or
31 **              NULL if it couldn't allocate the memory.
32 */
33
34 SMDB_DATABASE *
35 smdb_malloc_database()
36 {
37         SMDB_DATABASE *db;
38
39         db = (SMDB_DATABASE *) malloc(sizeof(SMDB_DATABASE));
40
41         if (db != NULL)
42                 (void) memset(db, '\0', sizeof(SMDB_DATABASE));
43
44         return db;
45 }
46
47 /*
48 **  SMDB_FREE_DATABASE -- Unallocates a database structure.
49 **
50 **      Parameters:
51 **              database -- a SMDB_DATABASE pointer to deallocate.
52 **
53 **      Returns:
54 **              None
55 */
56
57 void
58 smdb_free_database(database)
59         SMDB_DATABASE *database;
60 {
61         if (database != NULL)
62                 free(database);
63 }
64
65 /*
66 **  SMDB_LOCKFILE -- lock a file using flock or (shudder) fcntl locking
67 **
68 **      Parameters:
69 **              fd -- the file descriptor of the file.
70 **              type -- type of the lock.  Bits can be:
71 **                      LOCK_EX -- exclusive lock.
72 **                      LOCK_NB -- non-blocking.
73 **
74 **      Returns:
75 **              true if the lock was acquired.
76 **              false otherwise.
77 */
78
79 static bool
80 smdb_lockfile(fd, type)
81         int fd;
82         int type;
83 {
84         int i;
85         int save_errno;
86 #if !HASFLOCK
87         int action;
88         struct flock lfd;
89
90         (void) memset(&lfd, '\0', sizeof lfd);
91         if (bitset(LOCK_UN, type))
92                 lfd.l_type = F_UNLCK;
93         else if (bitset(LOCK_EX, type))
94                 lfd.l_type = F_WRLCK;
95         else
96                 lfd.l_type = F_RDLCK;
97
98         if (bitset(LOCK_NB, type))
99                 action = F_SETLK;
100         else
101                 action = F_SETLKW;
102
103         while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR)
104                 continue;
105         if (i >= 0)
106                 return true;
107         save_errno = errno;
108
109         /*
110         **  On SunOS, if you are testing using -oQ/tmp/mqueue or
111         **  -oA/tmp/aliases or anything like that, and /tmp is mounted
112         **  as type "tmp" (that is, served from swap space), the
113         **  previous fcntl will fail with "Invalid argument" errors.
114         **  Since this is fairly common during testing, we will assume
115         **  that this indicates that the lock is successfully grabbed.
116         */
117
118         if (save_errno == EINVAL)
119                 return true;
120
121         if (!bitset(LOCK_NB, type) ||
122             (save_errno != EACCES && save_errno != EAGAIN))
123         {
124 # if 0
125                 int omode = fcntl(fd, F_GETFL, NULL);
126                 int euid = (int) geteuid();
127
128                 syslog(LOG_ERR, "cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
129                        filename, ext, fd, type, omode, euid);
130 # endif /* 0 */
131                 errno = save_errno;
132                 return false;
133         }
134 #else /* !HASFLOCK */
135
136         while ((i = flock(fd, type)) < 0 && errno == EINTR)
137                 continue;
138         if (i >= 0)
139                 return true;
140         save_errno = errno;
141
142         if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK)
143         {
144 # if 0
145                 int omode = fcntl(fd, F_GETFL, NULL);
146                 int euid = (int) geteuid();
147
148                 syslog(LOG_ERR, "cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)",
149                        filename, ext, fd, type, omode, euid);
150 # endif /* 0 */
151                 errno = save_errno;
152                 return false;
153         }
154 #endif /* !HASFLOCK */
155         errno = save_errno;
156         return false;
157 }
158
159 /*
160 **  SMDB_OPEN_DATABASE -- Opens a database.
161 **
162 **      This opens a database. If type is SMDB_DEFAULT it tries to
163 **      use available DB types.  If a specific type is given it will
164 **      try to open a database of that type.
165 **
166 **      Parameters:
167 **              database -- A pointer to a SMDB_DATABASE pointer where the
168 **                         opened database will be stored. This should
169 **                         be unallocated.
170 **              db_name -- The name of the database to open. Do not include
171 **                        the file name extension.
172 **              mode -- The mode to set on the database file or files.
173 **              mode_mask -- Mode bits that must match on an opened database.
174 **              sff -- Flags to safefile.
175 **              type -- The type of database to open. Supported types
176 **                     vary depending on what was compiled in.
177 **              user_info -- Information on the user to use for file
178 **                          permissions.
179 **              params -- Params specific to the database being opened.
180 **                       Only supports some DB hash options right now
181 **                       (see smdb_db_open() for details).
182 **
183 **      Returns:
184 **              SMDBE_OK -- Success.
185 **              Anything else is an error. Look up more info about the
186 **              error in the comments for the specific open() used.
187 */
188
189 struct type2func_s
190 {
191         const char      *t2f_type;
192         smdb_open_func  *t2f_open_fun;
193 };
194 typedef struct type2func_s type2func_t;
195 static type2func_t type2func[] = {
196         { SMDB_TYPE_HASH, smdb_db_open  },
197         { SMDB_TYPE_BTREE, smdb_db_open },
198         { SMDB_TYPE_NDBM, smdb_ndbm_open},
199         { SMDB_TYPE_CDB, smdb_cdb_open },
200         { NULL, NULL }
201 };
202
203 int
204 smdb_open_database(database, db_name, mode, mode_mask, sff, type, user_info,
205                    params)
206         SMDB_DATABASE **database;
207         char *db_name;
208         int mode;
209         int mode_mask;
210         long sff;
211         SMDB_DBTYPE type;
212         SMDB_USER_INFO *user_info;
213         SMDB_DBPARAMS *params;
214 {
215         bool type_was_default;
216         int result, i;
217         const char *smdb_type;
218         smdb_open_func *smdb_open_fun;
219
220         result = SMDBE_UNSUPPORTED_DB_TYPE;
221         type_was_default = SMDB_IS_TYPE_DEFAULT(type);
222         for (i = 0; (smdb_type = type2func[i].t2f_type) != NULL; i++)
223         {
224                 if (!type_was_default && strcmp(type, smdb_type) != 0)
225                         continue;
226                 smdb_open_fun = type2func[i].t2f_open_fun;
227                 if (smdb_open_fun == NULL)
228                 {
229                         if (type_was_default)
230                                 continue;
231                         else
232                                 return SMDBE_UNSUPPORTED_DB_TYPE;
233                 }
234                 result = (*smdb_open_fun)(database, db_name, mode, mode_mask, sff,
235                                         (char *)smdb_type, user_info, params);
236                 if (!((result == ENOENT
237                         || result == EINVAL
238 #ifdef EFTYPE
239                         || result == EFTYPE
240 #endif
241                        )
242                     && type_was_default))
243                         goto ret;
244         }
245         return SMDBE_UNKNOWN_DB_TYPE;
246
247   ret:
248         return result;
249 }
250
251 /*
252 **  SMDB_ADD_EXTENSION -- Adds an extension to a file name.
253 **
254 **      Just adds a . followed by a string to a db_name if there
255 **      is room and the db_name does not already have that extension.
256 **
257 **      Parameters:
258 **              full_name -- The final file name.
259 **              max_full_name_len -- The max length for full_name.
260 **              db_name -- The name of the db.
261 **              extension -- The extension to add.
262 **
263 **      Returns:
264 **              SMDBE_OK -- Success.
265 **              Anything else is an error. Look up more info about the
266 **              error in the comments for the specific open() used.
267 */
268
269 int
270 smdb_add_extension(full_name, max_full_name_len, db_name, extension)
271         char *full_name;
272         int max_full_name_len;
273         char *db_name;
274         char *extension;
275 {
276         int extension_len;
277         int db_name_len;
278
279         if (full_name == NULL || db_name == NULL || extension == NULL)
280                 return SMDBE_INVALID_PARAMETER;
281
282         extension_len = strlen(extension);
283         db_name_len = strlen(db_name);
284
285         if (extension_len + db_name_len + 2 > max_full_name_len)
286                 return SMDBE_DB_NAME_TOO_LONG;
287
288         if (db_name_len < extension_len + 1 ||
289             db_name[db_name_len - extension_len - 1] != '.' ||
290             strcmp(&db_name[db_name_len - extension_len], extension) != 0)
291                 (void) sm_snprintf(full_name, max_full_name_len, "%s.%s",
292                                    db_name, extension);
293         else
294                 (void) sm_strlcpy(full_name, db_name, max_full_name_len);
295
296         return SMDBE_OK;
297 }
298 /*
299 **  SMDB_LOCK_FILE -- Locks the database file.
300 **
301 **      Locks the actual database file.
302 **
303 **      Parameters:
304 **              lock_fd -- The resulting descriptor for the locked file.
305 **              db_name -- The name of the database without extension.
306 **              mode -- The open mode.
307 **              sff -- Flags to safefile.
308 **              extension -- The extension for the file.
309 **
310 **      Returns:
311 **              SMDBE_OK -- Success, otherwise errno.
312 */
313
314 int
315 smdb_lock_file(lock_fd, db_name, mode, sff, extension)
316         int *lock_fd;
317         char *db_name;
318         int mode;
319         long sff;
320         char *extension;
321 {
322         int result;
323         char file_name[MAXPATHLEN];
324
325         result = smdb_add_extension(file_name, sizeof file_name, db_name,
326                                     extension);
327         if (result != SMDBE_OK)
328                 return result;
329
330         *lock_fd = safeopen(file_name, mode & ~O_TRUNC, DBMMODE, sff);
331         if (*lock_fd < 0)
332                 return errno;
333
334         return SMDBE_OK;
335 }
336
337 /*
338 **  SMDB_UNLOCK_FILE -- Unlocks a file - via close()
339 **
340 **      Parameters:
341 **              lock_fd -- The descriptor for the locked file.
342 **
343 **      Returns:
344 **              SMDBE_OK -- Success, otherwise errno.
345 */
346
347 int
348 smdb_unlock_file(lock_fd)
349         int lock_fd;
350 {
351         int result;
352
353         result = close(lock_fd);
354         if (result != 0)
355                 return errno;
356
357         return SMDBE_OK;
358 }
359 /*
360 **  SMDB_LOCK_MAP -- Locks a database.
361 **
362 **      Parameters:
363 **              database -- database description.
364 **              type -- type of the lock.  Bits can be:
365 **                      LOCK_EX -- exclusive lock.
366 **                      LOCK_NB -- non-blocking.
367 **
368 **      Returns:
369 **              SMDBE_OK -- Success, otherwise errno.
370 */
371
372 int
373 smdb_lock_map(database, type)
374         SMDB_DATABASE *database;
375         int type;
376 {
377         int fd;
378
379         fd = database->smdb_lockfd(database);
380         if (fd < 0)
381                 return SMDBE_NOT_FOUND;
382         if (!smdb_lockfile(fd, type))
383                 return SMDBE_LOCK_NOT_GRANTED;
384         return SMDBE_OK;
385 }
386 /*
387 **  SMDB_UNLOCK_MAP -- Unlocks a database
388 **
389 **      Parameters:
390 **              database -- database description.
391 **
392 **      Returns:
393 **              SMDBE_OK -- Success, otherwise errno.
394 */
395
396 int
397 smdb_unlock_map(database)
398         SMDB_DATABASE *database;
399 {
400         int fd;
401
402         fd = database->smdb_lockfd(database);
403         if (fd < 0)
404                 return SMDBE_NOT_FOUND;
405         if (!smdb_lockfile(fd, LOCK_UN))
406                 return SMDBE_LOCK_NOT_HELD;
407         return SMDBE_OK;
408 }
409 /*
410 **  SMDB_SETUP_FILE -- Gets db file ready for use.
411 **
412 **      Makes sure permissions on file are safe and creates it if it
413 **      doesn't exist.
414 **
415 **      Parameters:
416 **              db_name -- The name of the database without extension.
417 **              extension -- The extension.
418 **              sff -- Flags to safefile.
419 **              mode_mask -- Mode bits that must match.
420 **              user_info -- Information on the user to use for file
421 **                          permissions.
422 **              stat_info -- A place to put the stat info for the file.
423 **      Returns:
424 **              SMDBE_OK -- Success, otherwise errno.
425 */
426
427 int
428 smdb_setup_file(db_name, extension, mode_mask, sff, user_info, stat_info)
429         char *db_name;
430         char *extension;
431         int mode_mask;
432         long sff;
433         SMDB_USER_INFO *user_info;
434         struct stat *stat_info;
435 {
436         int st;
437         int result;
438         char db_file_name[MAXPATHLEN];
439
440         result = smdb_add_extension(db_file_name, sizeof db_file_name, db_name,
441                                     extension);
442         if (result != SMDBE_OK)
443                 return result;
444
445         st = safefile(db_file_name, user_info->smdbu_id,
446                       user_info->smdbu_group_id, user_info->smdbu_name,
447                       sff, mode_mask, stat_info);
448         if (st != 0)
449                 return st;
450
451         return SMDBE_OK;
452 }
453 /*
454 **  SMDB_FILECHANGED -- Checks to see if a file changed.
455 **
456 **      Compares the passed in stat_info with a current stat on
457 **      the passed in file descriptor. Check filechanged for
458 **      return values.
459 **
460 **      Parameters:
461 **              db_name -- The name of the database without extension.
462 **              extension -- The extension.
463 **              db_fd -- A file descriptor for the database file.
464 **              stat_info -- An old stat_info.
465 **      Returns:
466 **              SMDBE_OK -- Success, otherwise errno.
467 */
468
469 int
470 smdb_filechanged(db_name, extension, db_fd, stat_info)
471         char *db_name;
472         char *extension;
473         int db_fd;
474         struct stat *stat_info;
475 {
476         int result;
477         char db_file_name[MAXPATHLEN];
478
479         result = smdb_add_extension(db_file_name, sizeof db_file_name, db_name,
480                                     extension);
481         if (result != SMDBE_OK)
482                 return result;
483         return filechanged(db_file_name, db_fd, stat_info);
484 }
485
486 /*
487 **  SMDB_PRINT_AVAILABLE_TYPES -- Prints the names of the available types.
488 **
489 **      Parameters:
490 **              ext - also show extension?
491 **
492 **      Returns:
493 **              None
494 */
495
496 void
497 smdb_print_available_types(ext)
498         bool ext;
499 {
500 # define PEXT1  ((ext) ? ":" : "")
501 # define PEXT2(x)       ((ext) ? x : "")
502
503 #if NDBM
504         printf("%s%s%s\n", SMDB_TYPE_NDBM, PEXT1, PEXT2(SMNDB_DIR_FILE_EXTENSION));
505 #endif
506 #if NEWDB
507 /* # if SMDB1_FILE_EXTENSION == SMDB2_FILE_EXTENSION */
508         printf("%s%s%s\n", SMDB_TYPE_HASH, PEXT1, PEXT2(SMDB1_FILE_EXTENSION));
509         printf("%s%s%s\n", SMDB_TYPE_BTREE, PEXT1, PEXT2(SMDB1_FILE_EXTENSION));
510 #endif
511 #if CDB
512         printf("%s%s%s\n", SMDB_TYPE_CDB, PEXT1, PEXT2(SMCDB_FILE_EXTENSION));
513 #endif
514 #ifdef SMDB_TYPE_IMPL
515         printf("%s%s%s\n", SMDB_TYPE_IMPL, PEXT1, "");
516 #endif
517 }
518
519 /*
520 **  SMDB_IS_DB_TYPE -- Does a name match an available DB type?
521 **
522 **      Parameters:
523 **              type -- The name of the database type.
524 **
525 **      Returns:
526 **              true iff match
527 */
528
529 bool
530 smdb_is_db_type(db_type)
531         const char *db_type;
532 {
533 #if NDBM
534         if (strcmp(db_type, SMDB_TYPE_NDBM) == 0)
535                 return true;
536 #endif
537 #if NEWDB
538         if (strcmp(db_type, SMDB_TYPE_HASH) == 0)
539                 return true;
540         if (strcmp(db_type, SMDB_TYPE_BTREE) == 0)
541                 return true;
542 #endif
543 #if CDB
544         if (strcmp(db_type, SMDB_TYPE_CDB) == 0)
545                 return true;
546 #endif
547         return false;
548 }
549
550
551 /*
552 **  SMDB_DB_DEFINITION -- Given a database type, return database definition
553 **
554 **      Reads though a structure making an association with the database
555 **      type and the required cpp define from sendmail/README.
556 **      List size is dynamic and must be NULL terminated.
557 **
558 **      Parameters:
559 **              type -- The name of the database type.
560 **
561 **      Returns:
562 **              definition for type, otherwise NULL.
563 */
564
565 typedef struct
566 {
567         SMDB_DBTYPE type;
568         char *dbdef;
569 } dbtype;
570
571 static dbtype DatabaseDefs[] =
572 {
573         { SMDB_TYPE_HASH,       "NEWDB" },
574         { SMDB_TYPE_BTREE,      "NEWDB" },
575         { SMDB_TYPE_NDBM,       "NDBM"  },
576         { SMDB_TYPE_CDB,        "CDB"   },
577         { NULL,                 "OOPS"  }
578 };
579
580 char *
581 smdb_db_definition(type)
582         SMDB_DBTYPE type;
583 {
584         dbtype *ptr = DatabaseDefs;
585
586         while (ptr != NULL && ptr->type != NULL)
587         {
588                 if (strcmp(type, ptr->type) == 0)
589                         return ptr->dbdef;
590                 ptr++;
591         }
592         return NULL;
593 }