X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/f3ebb786e451da973560f1c9d8cdb151d25108b5..HEAD:/src/src/exim_dbutil.c diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 8b71a4140..f3123c80b 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2024 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* This single source file is used to compile three utility programs for @@ -16,11 +18,13 @@ maintaining Exim hints databases. In all cases, the first argument is the name of the spool directory. The second argument is the name of the database file. The available names are: - retry: retry delivery information - misc: miscellaneous hints data - wait-: message waiting information; is a transport name - callout: callout verification cache - tls: TLS session resumption cache + callout: callout verification cache + misc: miscellaneous hints data + ratelimit: record for ACL "ratelimit" condition + retry: etry delivery information + seen: imestamp records for ACL "seen" condition + tls: TLS session resumption cache + wait-: message waiting information; is a transport name There are a number of common subroutines, followed by three main programs, whose inclusion is controlled by -D on the compilation command. */ @@ -37,37 +41,47 @@ whose inclusion is controlled by -D on the compilation command. */ #define type_callout 4 #define type_ratelimit 5 #define type_tls 6 +#define type_seen 7 /* This is used by our cut-down dbfn_open(). */ uschar *spool_directory; +BOOL keyonly = FALSE; +BOOL utc = FALSE; -/************************************************* -* Berkeley DB error callback * -*************************************************/ +/******************************************************************************/ + /* dummies needed by Solaris build */ +void +millisleep(int msec) +{} +uschar * +readconf_printtime(int t) +{ return NULL; } +gstring * +string_catn(gstring * g, const uschar * s, int count) +{ 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; } -/* For Berkeley DB >= 2, we can define a function to be called in case of DB -errors. This should help with debugging strange DB problems, e.g. getting "File -exists" when you try to open a db file. The API changed at release 4.3. */ +struct global_flags f; +unsigned int log_selector[1]; +uschar * queue_name; +BOOL split_spool_directory; -#if defined(USE_DB) && defined(DB_VERSION_STRING) -void -#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) -dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg) -{ -dbenv = dbenv; -#else -dbfn_bdb_error_callback(const char *pfx, char *msg) -{ -#endif -pfx = pfx; -printf("Berkeley DB error: %s\n", msg); -} -#endif +/******************************************************************************/ /************************************************* @@ -79,7 +93,6 @@ SIGNAL_BOOL sigalrm_seen; void sigalrm_handler(int sig) { -sig = sig; /* Keep picky compilers happy */ sigalrm_seen = 1; } @@ -93,12 +106,31 @@ static void usage(uschar *name, uschar *options) { printf("Usage: exim_%s%s \n", name, options); -printf(" = retry | misc | wait- | callout | ratelimit | tls\n"); -exit(1); +printf(" = retry | misc | wait- | callout | ratelimit | tls | seen\n"); +exit(EXIT_FAILURE); } +/******************* +* Debug output * +*******************/ + +unsigned int debug_selector = 0; /* set -1 for debugging */ + +void +debug_printf(const char * fmt, ...) +{ +va_list ap; +va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); +} +void +debug_printf_indent(const char * fmt, ...) +{ +va_list ap; +va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); +} + /************************************************* * Sort out the command arguments * *************************************************/ @@ -109,20 +141,40 @@ second of them to be sure it is a known database name. */ static int check_args(int argc, uschar **argv, uschar *name, uschar *options) { -if (argc == 3) +uschar * aname = argv[optind + 1]; +if (argc - optind == 2) { - if (Ustrcmp(argv[2], "retry") == 0) return type_retry; - if (Ustrcmp(argv[2], "misc") == 0) return type_misc; - 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; + if (Ustrcmp(aname, "retry") == 0) return type_retry; + if (Ustrcmp(aname, "misc") == 0) return type_misc; + if (Ustrncmp(aname, "wait-", 5) == 0) return type_wait; + if (Ustrcmp(aname, "callout") == 0) return type_callout; + if (Ustrcmp(aname, "ratelimit") == 0) return type_ratelimit; + if (Ustrcmp(aname, "tls") == 0) return type_tls; + if (Ustrcmp(aname, "seen") == 0) return type_seen; } usage(name, options); return -1; /* Never obeyed */ } +FUNC_MAYBE_UNUSED +static void +options(int argc, uschar * argv[], uschar * name, const uschar * opts) +{ +int opt; + +opterr = 0; +while ((opt = getopt(argc, (char * const *)argv, CCS opts)) != -1) + switch (opt) + { + case 'k': keyonly = TRUE; break; + case 'z': utc = TRUE; break; + default: usage(name, US" [-z] [-k]"); + } +} + + + /************************************************* * Handle attempts to write the log * @@ -150,8 +202,6 @@ va_start(ap, format); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); -selector = selector; /* Keep picky compilers happy */ -flags = flags; } @@ -165,7 +215,7 @@ static uschar time_buffer[sizeof("09-xxx-1999 hh:mm:ss ")]; uschar * print_time(time_t t) { -struct tm *tmstr = localtime(&t); +struct tm *tmstr = utc ? gmtime(&t) : localtime(&t); Ustrftime(time_buffer, sizeof(time_buffer), "%d-%b-%Y %H:%M:%S", tmstr); return time_buffer; } @@ -179,8 +229,8 @@ return time_buffer; uschar * print_cache(int value) { -return (value == ccache_accept)? US"accept" : - (value == ccache_reject)? US"reject" : +return value == ccache_accept ? US"accept" : + value == ccache_reject ? US"reject" : US"unknown"; } @@ -240,7 +290,7 @@ the lock file. Arguments: name The single-component name of one of Exim's database files. - flags O_RDONLY or O_RDWR + flags O_RDONLY or O_RDWR, O_CREAT dbblock Points to an open_db block to be filled in. lof Unused. panic Unused @@ -251,78 +301,77 @@ Returns: NULL if the open failed, or the locking failed. */ open_db * -dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof, BOOL panic) +dbfn_open(const uschar * name, int flags, open_db * dbblock, + BOOL lof, BOOL panic) { int rc; struct flock lock_data; -BOOL read_only = flags == O_RDONLY; uschar * dirname, * filename; /* The first thing to do is to open a separate file on which to lock. This ensures that Exim has exclusive use of the database before it even tries to -open it. If there is a database, there should be a lock file in existence. */ +open it. If there is a database, there should be a lock file in existence; +if no lockfile we infer there is no database and error out. We open the +lockfile using the r/w mode requested for the DB, users lacking permission +for the DB access mode will error out here. */ -#ifdef COMPILE_UTILITY if ( asprintf(CSS &dirname, "%s/db", spool_directory) < 0 || asprintf(CSS &filename, "%s/%s.lockfile", dirname, name) < 0) return NULL; -#else -dirname = string_sprintf("%s/db", spool_directory); -filename = string_sprintf("%s/%s.lockfile", dirname, name); -#endif -dbblock->lockfd = Uopen(filename, flags, 0); -if (dbblock->lockfd < 0) +dbblock->readonly = (flags & (O_WRONLY|O_RDWR)) == O_RDONLY; +dbblock->lockfd = -1; +if (exim_lockfile_needed()) { - printf("** Failed to open database lock file %s: %s\n", filename, - strerror(errno)); - return NULL; - } + if ((dbblock->lockfd = Uopen(filename, flags, 0)) < 0) + { + printf("** Failed to open database lock file %s: %s\n", filename, + strerror(errno)); + return NULL; + } -/* Now we must get a lock on the opened lock file; do this with a blocking -lock that times out. */ + /* Now we must get a lock on the opened lock file; do this with a blocking + lock that times out. */ -lock_data.l_type = read_only ? F_RDLCK : F_WRLCK; -lock_data.l_whence = lock_data.l_start = lock_data.l_len = 0; + lock_data.l_type = dbblock->readonly ? F_RDLCK : F_WRLCK; + lock_data.l_whence = lock_data.l_start = lock_data.l_len = 0; -sigalrm_seen = FALSE; -os_non_restarting_signal(SIGALRM, sigalrm_handler); -ALARM(EXIMDB_LOCK_TIMEOUT); -rc = fcntl(dbblock->lockfd, F_SETLKW, &lock_data); -ALARM_CLR(0); + sigalrm_seen = FALSE; + os_non_restarting_signal(SIGALRM, sigalrm_handler); + ALARM(EXIMDB_LOCK_TIMEOUT); + rc = fcntl(dbblock->lockfd, F_SETLKW, &lock_data); + ALARM_CLR(0); -if (sigalrm_seen) errno = ETIMEDOUT; -if (rc < 0) - { - printf("** Failed to get %s lock for %s: %s", - flags & O_WRONLY ? "write" : "read", - filename, - errno == ETIMEDOUT ? "timed out" : strerror(errno)); - (void)close(dbblock->lockfd); - return NULL; - } + if (sigalrm_seen) errno = ETIMEDOUT; + if (rc < 0) + { + printf("** Failed to get %s lock for %s: %s", + dbblock->readonly ? "read" : "write", + filename, + errno == ETIMEDOUT ? "timed out" : strerror(errno)); + (void)close(dbblock->lockfd); + return NULL; + } -/* At this point we have an opened and locked separate lock file, that is, -exclusive access to the database, so we can go ahead and open it. */ + /* At this point we have an opened and locked separate lock file, that is, + exclusive access to the database, so we can go ahead and open it. */ + } -#ifdef COMPILE_UTILITY 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)); -if (!dbblock->dbptr) +if (!(dbblock->dbptr = dbblock->readonly && !exim_lockfile_needed() + ? exim_dbopen_multi(filename, dirname, flags, 0) + : exim_dbopen(filename, dirname, flags, 0))) { - printf("** Failed to open DBM file %s for %s:\n %s%s\n", filename, - read_only? "reading" : "writing", strerror(errno), - #ifdef USE_DB + printf("** Failed to open hintsdb file %s for %s: %s%s\n", filename, + dbblock->readonly ? "reading" : "writing", strerror(errno), +#ifdef USE_DB " (or Berkeley DB error while opening)" - #else +#else "" - #endif +#endif ); - (void)close(dbblock->lockfd); + if (dbblock->lockfd >= 0) (void)close(dbblock->lockfd); return NULL; } @@ -337,17 +386,22 @@ return dbblock; *************************************************/ /* Closing a file automatically unlocks it, so after closing the database, just -close the lock file. +close the lock file if there was one. Argument: a pointer to an open database block Returns: nothing */ void -dbfn_close(open_db *dbblock) +dbfn_close(open_db * dbp) { -EXIM_DBCLOSE(dbblock->dbptr); -(void)close(dbblock->lockfd); +if (dbp->readonly && !exim_lockfile_needed()) + exim_dbclose_multi(dbp->dbptr); +else + exim_dbclose(dbp->dbptr); + +if (dbp->lockfd >= 0) + (void) close(dbp->lockfd); } @@ -364,37 +418,40 @@ 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 */ void * -dbfn_read_with_length(open_db *dbblock, const uschar *key, int *length) +dbfn_read_with_length(open_db * dbblock, const uschar * key, int * length) { -void *yield; +void * yield; EXIM_DATUM key_datum, result_datum; int klen = Ustrlen(key) + 1; -uschar * key_copy = store_get(klen, is_tainted(key)); +uschar * key_copy = store_get(klen, key); +unsigned dlen; memcpy(key_copy, key, klen); -EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */ -EXIM_DATUM_INIT(result_datum); /* to be cleared before use. */ -EXIM_DATUM_DATA(key_datum) = CS key_copy; -EXIM_DATUM_SIZE(key_datum) = klen; +exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ +exim_datum_init(&result_datum); /* to be cleared before use. */ +exim_datum_data_set(&key_datum, key_copy); +exim_datum_size_set(&key_datum, klen); -if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL; +if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; /* 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); +dlen = exim_datum_size_get(&result_datum); +yield = store_get(dlen, GET_TAINTED); +memcpy(yield, exim_datum_data_get(&result_datum), dlen); +DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); +if (length) *length = dlen; -EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */ +exim_datum_free(&result_datum); /* Some DBM libs require freeing */ return yield; } @@ -423,18 +480,18 @@ 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, is_tainted(key)); +uschar * key_copy = store_get(klen, key); memcpy(key_copy, key, klen); gptr->time_stamp = time(NULL); -EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */ -EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */ -EXIM_DATUM_DATA(key_datum) = CS key_copy; -EXIM_DATUM_SIZE(key_datum) = klen; -EXIM_DATUM_DATA(value_datum) = CS ptr; -EXIM_DATUM_SIZE(value_datum) = length; -return EXIM_DBPUT(dbblock->dbptr, key_datum, value_datum); +exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ +exim_datum_init(&value_datum); /* to be cleared before use. */ +exim_datum_data_set(&key_datum, key_copy); +exim_datum_size_set(&key_datum, klen); +exim_datum_data_set(&value_datum, ptr); +exim_datum_size_set(&value_datum, length); +return exim_dbput(dbblock->dbptr, &key_datum, &value_datum); } @@ -455,14 +512,14 @@ int dbfn_delete(open_db *dbblock, const uschar *key) { int klen = Ustrlen(key) + 1; -uschar * key_copy = store_get(klen, is_tainted(key)); +uschar * key_copy = store_get(klen, key); +EXIM_DATUM key_datum; memcpy(key_copy, key, klen); -EXIM_DATUM key_datum; -EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require clearing */ -EXIM_DATUM_DATA(key_datum) = CS key_copy; -EXIM_DATUM_SIZE(key_datum) = klen; -return EXIM_DBDEL(dbblock->dbptr, key_datum); +exim_datum_init(&key_datum); /* Some DBM libraries require clearing */ +exim_datum_data_set(&key_datum, key_copy); +exim_datum_size_set(&key_datum, klen); +return exim_dbdel(dbblock->dbptr, &key_datum); } #endif /* EXIM_TIDYDB || EXIM_FIXDB */ @@ -482,7 +539,7 @@ Arguments: cursor a pointer to a pointer to a cursor anchor, for those dbm libraries that use the notion of a cursor -Returns: the next record from the file, or +Returns: the next *key* (nul-terminated) from the file, or NULL if there are no more */ @@ -491,21 +548,20 @@ 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 */ -if (start) EXIM_DBCREATE_CURSOR(dbblock->dbptr, cursor); +if (start) *cursor = exim_dbcreate_cursor(dbblock->dbptr); -EXIM_DATUM_INIT(key_datum); /* Some DBM libraries require the datum */ -EXIM_DATUM_INIT(value_datum); /* to be cleared before use. */ +exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ +exim_datum_init(&value_datum); /* to be cleared before use. */ -yield = (EXIM_DBSCAN(dbblock->dbptr, key_datum, value_datum, start, *cursor))? - US EXIM_DATUM_DATA(key_datum) : NULL; +yield = exim_dbscan(dbblock->dbptr, &key_datum, &value_datum, start, *cursor) + ? US exim_datum_data_get(&key_datum) : NULL; /* Some dbm require a termination */ -if (!yield) EXIM_DBDELETE_CURSOR(*cursor); +if (!yield) exim_dbdelete_cursor(*cursor); return yield; } #endif /* EXIM_DUMPDB || EXIM_TIDYDB */ @@ -528,12 +584,17 @@ EXIM_CURSOR *cursor; uschar **argv = USS cargv; uschar keybuffer[1024]; +store_init(); +options(argc, argv, US"dumpdb", US"kz"); + /* Check the arguments, and open the database */ -dbdata_type = check_args(argc, argv, US"dumpdb", US""); -spool_directory = argv[1]; -if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE))) - exit(1); +dbdata_type = check_args(argc, argv, US"dumpdb", US" [-z] [-k]"); +argc -= optind; argv += optind; +spool_directory = argv[0]; + +if (!(dbm = dbfn_open(argv[1], O_RDONLY, &dbblock, FALSE, TRUE))) + exit(EXIT_FAILURE); /* Scan the file, formatting the information for each entry. Note that data is returned in a malloc'ed block, in order that it be @@ -549,6 +610,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); dbdata_ratelimit *ratelimit; dbdata_ratelimit_unique *rate_unique; dbdata_tls_session *session; + dbdata_seen *seen; int count_bad = 0; int length; uschar *t; @@ -566,12 +628,13 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); } Ustrcpy(keybuffer, key); - if (!(value = dbfn_read_with_length(dbm, keybuffer, &length))) + if (keyonly) + printf(" %s\n", keybuffer); + else if (!(value = dbfn_read_with_length(dbm, keybuffer, &length))) fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record " "was not found in the file - something is wrong!\n", CS keybuffer); else - { /* Note: don't use print_time more than once in one statement, since it uses a single buffer. */ @@ -584,7 +647,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); print_time(retry->first_failed)); printf("%s ", print_time(retry->last_try)); printf("%s %s\n", print_time(retry->next_try), - (retry->expired)? "*" : ""); + retry->expired ? "*" : ""); break; case type_wait: @@ -593,6 +656,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, @@ -687,8 +751,12 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); session = (dbdata_tls_session *)value; printf(" %s %.*s\n", keybuffer, length, session->session); break; + + case type_seen: + seen = (dbdata_seen *)value; + printf("%s\t%s\n", keybuffer, print_time(seen->time_stamp)); + break; } - } store_reset(reset_point); } @@ -733,21 +801,29 @@ If the record name is omitted from (2) or (3), the previously used record name is re-used. */ -int main(int argc, char **cargv) +int +main(int argc, char **cargv) { int dbdata_type; uschar **argv = USS cargv; uschar buffer[256]; uschar name[256]; rmark reset_point; +uschar * aname; +store_init(); +options(argc, argv, US"fixdb", US"z"); name[0] = 0; /* No name set */ /* Sort out the database type, verify what we are working on and then process user requests */ -dbdata_type = check_args(argc, argv, US"fixdb", US""); -printf("Modifying Exim hints database %s/db/%s\n", argv[1], argv[2]); +dbdata_type = check_args(argc, argv, US"fixdb", US" [-z]"); +argc -= optind; argv += optind; +spool_directory = argv[0]; +aname = argv[1]; + +printf("Modifying Exim hints database %s/db/%s\n", spool_directory, aname); for(; (reset_point = store_mark()); store_reset(reset_point)) { @@ -794,9 +870,8 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) if (field[0] != 0) { int verify = 1; - spool_directory = argv[1]; - if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE, TRUE))) + if (!(dbm = dbfn_open(aname, O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) continue; if (Ustrcmp(field, "d") == 0) @@ -965,8 +1040,7 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) /* Handle a read request, or verify after an update. */ - spool_directory = argv[1]; - if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE))) + if (!(dbm = dbfn_open(aname, O_RDONLY, &dbblock, FALSE, TRUE))) continue; if (!(record = dbfn_read_with_length(dbm, name, &oldlength))) @@ -1096,7 +1170,8 @@ typedef struct key_item { } key_item; -int main(int argc, char **cargv) +int +main(int argc, char **cargv) { struct stat statbuf; int maxkeep = 30 * 24 * 60 * 60; @@ -1110,6 +1185,8 @@ uschar **argv = USS cargv; uschar buffer[256]; uschar *key; +store_init(); + /* Scan the options */ for (i = 1; i < argc; i++) @@ -1157,8 +1234,8 @@ 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, TRUE))) - exit(1); +if (!(dbm = dbfn_open(argv[2], O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) + exit(EXIT_FAILURE); /* Prepare for building file names */ @@ -1175,7 +1252,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), is_tainted(key)); + key_item * k = store_get(sizeof(key_item) + Ustrlen(key), key); k->next = keychain; keychain = k; Ustrcpy(k->key, key); @@ -1195,7 +1272,7 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) /* 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 */ @@ -1216,12 +1293,33 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) /* 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 @@ -1348,3 +1446,5 @@ return 0; #endif /* EXIM_TIDYDB */ /* End of exim_dbutil.c */ +/* vi: aw ai sw=2 +*/