*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
misc: miscellaneous hints data
wait-<t>: message waiting information; <t> 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. */
#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(). */
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;
+
+
+/* These introduced by the taintwarn handling */
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+BOOL allow_insecure_tainted_data;
+#endif
+
+/******************************************************************************/
+
/*************************************************
* Berkeley DB error callback *
void
sigalrm_handler(int sig)
{
-sig = sig; /* Keep picky compilers happy */
sigalrm_seen = 1;
}
usage(uschar *name, uschar *options)
{
printf("Usage: exim_%s%s <spool-directory> <database-name>\n", name, options);
-printf(" <database-name> = retry | misc | wait-<transport-name> | callout | ratelimit\n");
+printf(" <database-name> = retry | misc | wait-<transport-name> | callout | ratelimit | tls\n");
exit(1);
}
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 */
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
-selector = selector; /* Keep picky compilers happy */
-flags = flags;
}
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
*/
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;
#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)
{
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 *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);
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;
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);
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;
{
EXIM_DATUM key_datum, value_datum;
uschar *yield;
-value_datum = value_datum; /* dummy; not all db libraries use this */
/* Some dbm require an initialization */
uschar **argv = USS cargv;
uschar keybuffer[1024];
+store_init();
+
/* 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)))
+if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE)))
exit(1);
/* Scan the file, formatting the information for each entry. Note
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. */
t = wait->text;
name[MESSAGE_ID_LENGTH] = 0;
+ /* Leave corrupt records alone */
if (wait->count > WAIT_NAME_MAX)
{
fprintf(stderr,
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);
uschar **argv = USS cargv;
uschar buffer[256];
uschar name[256];
-void *reset_point = store_get(0);
+rmark reset_point;
+store_init();
name[0] = 0; /* No name set */
/* Sort out the database type, verify what we are working on and then process
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;
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;
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)
break;
}
break;
+
+ case type_tls:
+ printf("Can't change contents of tls database record\n");
+ break;
}
dbfn_write(dbm, name, record, oldlength);
/* 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)))
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;
}
}
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;
uschar buffer[256];
uschar *key;
+store_init();
+
/* Scan the options */
for (i = 1; i < argc; i++)
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 */
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);
/* 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);
/* 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 */
/* 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