X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/d7978c0f8af20ff4c3f770589b1bb81568aecff3..fc96555ab63243de9d468325aeaaa14cd77b9943:/src/src/exim_dbutil.c diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index a0514f009..7ca7a3073 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -20,6 +21,7 @@ argument is the name of the database file. The available names are: misc: miscellaneous hints data wait-: message waiting information; is a transport name callout: callout verification cache + tls: TLS session resumption cache There are a number of common subroutines, followed by three main programs, whose inclusion is controlled by -D on the compilation command. */ @@ -35,6 +37,7 @@ whose inclusion is controlled by -D on the compilation command. */ #define type_misc 3 #define type_callout 4 #define type_ratelimit 5 +#define type_tls 6 /* This is used by our cut-down dbfn_open(). */ @@ -42,6 +45,32 @@ whose inclusion is controlled by -D on the compilation command. */ uschar *spool_directory; +/******************************************************************************/ + /* dummies needed by Solaris build */ +void +millisleep(int msec) +{} +uschar * +readconf_printtime(int t) +{ return NULL; } +gstring * +string_vformat_trc(gstring * g, const uschar * func, unsigned line, + unsigned size_limit, unsigned flags, const char *format, va_list ap) +{ return NULL; } +uschar * +string_sprintf_trc(const char * fmt, const uschar * func, unsigned line, ...) +{ return NULL; } +BOOL +string_format_trc(uschar * buf, int len, const uschar * func, unsigned line, + const char * fmt, ...) +{ return FALSE; } + +struct global_flags f; +unsigned int log_selector[1]; +uschar * queue_name; +BOOL split_spool_directory; +/******************************************************************************/ + /************************************************* * Berkeley DB error callback * @@ -77,7 +106,6 @@ SIGNAL_BOOL sigalrm_seen; void sigalrm_handler(int sig) { -sig = sig; /* Keep picky compilers happy */ sigalrm_seen = 1; } @@ -91,7 +119,7 @@ static void usage(uschar *name, uschar *options) { printf("Usage: exim_%s%s \n", name, options); -printf(" = retry | misc | wait- | callout | ratelimit\n"); +printf(" = retry | misc | wait- | callout | ratelimit | tls\n"); exit(1); } @@ -114,6 +142,7 @@ if (argc == 3) if (Ustrncmp(argv[2], "wait-", 5) == 0) return type_wait; if (Ustrcmp(argv[2], "callout") == 0) return type_callout; if (Ustrcmp(argv[2], "ratelimit") == 0) return type_ratelimit; + if (Ustrcmp(argv[2], "tls") == 0) return type_tls; } usage(name, options); return -1; /* Never obeyed */ @@ -147,8 +176,6 @@ va_start(ap, format); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); -selector = selector; /* Keep picky compilers happy */ -flags = flags; } @@ -240,6 +267,7 @@ Arguments: flags O_RDONLY or O_RDWR dbblock Points to an open_db block to be filled in. lof Unused. + panic Unused Returns: NULL if the open failed, or the locking failed. On success, dbblock is returned. This contains the dbm pointer and @@ -247,7 +275,7 @@ Returns: NULL if the open failed, or the locking failed. */ open_db * -dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof) +dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof, BOOL panic) { int rc; struct flock lock_data; @@ -306,7 +334,7 @@ if (asprintf(CSS &filename, "%s/%s", dirname, name) < 0) return NULL; #else filename = string_sprintf("%s/%s", dirname, name); #endif -EXIM_DBOPEN(filename, dirname, flags, 0, &(dbblock->dbptr)); +EXIM_DBOPEN(filename, dirname, flags, 0, &dbblock->dbptr); if (!dbblock->dbptr) { @@ -360,7 +388,7 @@ pick out the timestamps, etc., do the copying centrally here. Arguments: dbblock a pointer to an open database block key the key of the record to be read - length where to put the length (or NULL if length not wanted) + length where to put the length (or NULL if length not wanted). Includes overhead. Returns: a pointer to the retrieved record, or NULL if the record is not found @@ -372,7 +400,7 @@ dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length) void *yield; EXIM_DATUM key_datum, result_datum; int klen = Ustrlen(key) + 1; -uschar * key_copy = store_get(klen); +uschar * key_copy = store_get(klen, is_tainted(key)); memcpy(key_copy, key, klen); @@ -383,9 +411,12 @@ EXIM_DATUM_SIZE(key_datum) = klen; if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL; -yield = store_get(EXIM_DATUM_SIZE(result_datum)); +/* Assume for now that anything stored could have been tainted. Properly +we should store the taint status along with the data. */ + +yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE); memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum)); -if (length != NULL) *length = EXIM_DATUM_SIZE(result_datum); +if (length) *length = EXIM_DATUM_SIZE(result_datum); EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */ return yield; @@ -416,7 +447,7 @@ dbfn_write(open_db *dbblock, const uschar *key, void *ptr, int length) EXIM_DATUM key_datum, value_datum; dbdata_generic *gptr = (dbdata_generic *)ptr; int klen = Ustrlen(key) + 1; -uschar * key_copy = store_get(klen); +uschar * key_copy = store_get(klen, is_tainted(key)); memcpy(key_copy, key, klen); gptr->time_stamp = time(NULL); @@ -448,7 +479,7 @@ int dbfn_delete(open_db *dbblock, const uschar *key) { int klen = Ustrlen(key) + 1; -uschar * key_copy = store_get(klen); +uschar * key_copy = store_get(klen, is_tainted(key)); memcpy(key_copy, key, klen); EXIM_DATUM key_datum; @@ -484,7 +515,6 @@ dbfn_scan(open_db *dbblock, BOOL start, EXIM_CURSOR **cursor) { EXIM_DATUM key_datum, value_datum; uschar *yield; -value_datum = value_datum; /* dummy; not all db libraries use this */ /* Some dbm require an initialization */ @@ -525,7 +555,7 @@ uschar keybuffer[1024]; dbdata_type = check_args(argc, argv, US"dumpdb", US""); spool_directory = argv[1]; -if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE))) +if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE))) exit(1); /* Scan the file, formatting the information for each entry. Note @@ -541,11 +571,13 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); dbdata_callout_cache *callout; dbdata_ratelimit *ratelimit; dbdata_ratelimit_unique *rate_unique; + dbdata_tls_session *session; int count_bad = 0; int length; uschar *t; uschar name[MESSAGE_ID_LENGTH + 1]; void *value; + rmark reset_point = store_mark(); /* Keep a copy of the key separate, as in some DBM's the pointer is into data which might change. */ @@ -584,6 +616,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); t = wait->text; name[MESSAGE_ID_LENGTH] = 0; + /* Leave corrupt records alone */ if (wait->count > WAIT_NAME_MAX) { fprintf(stderr, @@ -673,9 +706,14 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); keybuffer); } break; + + case type_tls: + session = (dbdata_tls_session *)value; + printf(" %s %.*s\n", keybuffer, length, session->session); + break; } - store_reset(value); } + store_reset(reset_point); } dbfn_close(dbm); @@ -725,7 +763,7 @@ int dbdata_type; uschar **argv = USS cargv; uschar buffer[256]; uschar name[256]; -void *reset_point = store_get(0); +rmark reset_point; name[0] = 0; /* No name set */ @@ -735,7 +773,7 @@ user requests */ dbdata_type = check_args(argc, argv, US"fixdb", US""); printf("Modifying Exim hints database %s/db/%s\n", argv[1], argv[2]); -for(;;) +for(; (reset_point = store_mark()); store_reset(reset_point)) { open_db dbblock; open_db *dbm; @@ -745,12 +783,11 @@ for(;;) dbdata_callout_cache *callout; dbdata_ratelimit *ratelimit; dbdata_ratelimit_unique *rate_unique; + dbdata_tls_session *session; int oldlength; uschar *t; uschar field[256], value[256]; - store_reset(reset_point); - printf("> "); if (Ufgets(buffer, 256, stdin) == NULL) break; @@ -783,7 +820,7 @@ for(;;) int verify = 1; spool_directory = argv[1]; - if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE))) + if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE, TRUE))) continue; if (Ustrcmp(field, "d") == 0) @@ -925,6 +962,10 @@ for(;;) break; } break; + + case type_tls: + printf("Can't change contents of tls database record\n"); + break; } dbfn_write(dbm, name, record, oldlength); @@ -949,7 +990,7 @@ for(;;) /* Handle a read request, or verify after an update. */ spool_directory = argv[1]; - if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE))) + if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE))) continue; if (!(record = dbfn_read_with_length(dbm, name, &oldlength))) @@ -1036,6 +1077,12 @@ for(;;) printf("5 add element to filter\n"); } break; + + case type_tls: + session = (dbdata_tls_session *)value; + printf("0 time stamp: %s\n", print_time(session->time_stamp)); + printf("1 session: .%s\n", session->session); + break; } } @@ -1079,7 +1126,7 @@ struct stat statbuf; int maxkeep = 30 * 24 * 60 * 60; int dbdata_type, i, oldest, path_len; key_item *keychain = NULL; -void *reset_point; +rmark reset_point; open_db dbblock; open_db *dbm; EXIM_CURSOR *cursor; @@ -1134,7 +1181,7 @@ oldest = time(NULL) - maxkeep; printf("Tidying Exim hints database %s/db/%s\n", argv[1], argv[2]); spool_directory = argv[1]; -if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE))) +if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE, TRUE))) exit(1); /* Prepare for building file names */ @@ -1152,7 +1199,7 @@ for (key = dbfn_scan(dbm, TRUE, &cursor); key; key = dbfn_scan(dbm, FALSE, &cursor)) { - key_item *k = store_get(sizeof(key_item) + Ustrlen(key)); + key_item *k = store_get(sizeof(key_item) + Ustrlen(key), is_tainted(key)); k->next = keychain; keychain = k; Ustrcpy(k->key, key); @@ -1161,13 +1208,10 @@ for (key = dbfn_scan(dbm, TRUE, &cursor); /* Now scan the collected keys and operate on the records, resetting the store each time round. */ -reset_point = store_get(0); - -while (keychain) +for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) { dbdata_generic *value; - store_reset(reset_point); key = keychain->key; keychain = keychain->next; value = dbfn_read_with_length(dbm, key, NULL); @@ -1175,7 +1219,7 @@ while (keychain) /* A continuation record may have been deleted or renamed already, so non-existence is not serious. */ - if (value == NULL) continue; + if (!value) continue; /* Delete if too old */ @@ -1196,12 +1240,33 @@ while (keychain) /* Leave corrupt records alone */ + if (wait->time_stamp > time(NULL)) + { + printf("**** Data for '%s' corrupted\n time in future: %s\n", + key, print_time(((dbdata_generic *)value)->time_stamp)); + continue; + } if (wait->count > WAIT_NAME_MAX) { - printf("**** Data for %s corrupted\n count=%d=0x%x max=%d\n", + printf("**** Data for '%s' corrupted\n count=%d=0x%x max=%d\n", key, wait->count, wait->count, WAIT_NAME_MAX); continue; } + if (wait->sequence > WAIT_CONT_MAX) + { + printf("**** Data for '%s' corrupted\n sequence=%d=0x%x max=%d\n", + key, wait->sequence, wait->sequence, WAIT_CONT_MAX); + continue; + } + + /* Record over 1 year old; just remove it */ + + if (wait->time_stamp < time(NULL) - 365*24*60*60) + { + dbfn_delete(dbm, key); + printf("deleted %s (too old)\n", key); + continue; + } /* Loop for renamed continuation records. For each message id, check to see if the message exists, and if not, remove its entry