X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/6b1bf31e4494f50bab891890aefcc9a9161eba01..5c161fa615ab4a2d40170fedd71d1b9a7f079ff6:/src/src/dbfn.c diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 25c1a3fba..a37271f36 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.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. */ @@ -72,6 +73,7 @@ Arguments: dbblock Points to an open_db block to be filled in. lof If TRUE, write to the log for actual open failures (locking failures are always logged). + panic If TRUE, panic on failure to create the db directory Returns: NULL if the open failed, or the locking failed. After locking failures, errno is zero. @@ -85,7 +87,7 @@ moment I haven't changed them. */ 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, save_errno; BOOL read_only = flags == O_RDONLY; @@ -114,14 +116,14 @@ snprintf(CS filename, sizeof(filename), "%s/%s.lockfile", dirname, name); if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0) { created = TRUE; - (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, TRUE); + (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, panic); dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE); } if (dbblock->lockfd < 0) { log_write(0, LOG_MAIN, "%s", - string_open_failed(errno, "database lock file %s", filename)); + string_open_failed("database lock file %s", filename)); errno = 0; /* Indicates locking failure */ DEBUG(D_hints_lookup) acl_level--; return NULL; @@ -137,9 +139,9 @@ DEBUG(D_hints_lookup|D_retry|D_route|D_deliver) debug_printf_indent("locking %s\n", filename); sigalrm_seen = FALSE; -alarm(EXIMDB_LOCK_TIMEOUT); +ALARM(EXIMDB_LOCK_TIMEOUT); rc = fcntl(dbblock->lockfd, F_SETLKW, &lock_data); -alarm(0); +ALARM_CLR(0); if (sigalrm_seen) errno = ETIMEDOUT; if (rc < 0) @@ -193,26 +195,29 @@ but creation of the database file failed. */ if (created && geteuid() == root_uid) { - DIR *dd; - struct dirent *ent; + DIR * dd; uschar *lastname = Ustrrchr(filename, '/') + 1; int namelen = Ustrlen(name); *lastname = 0; - dd = opendir(CS filename); - while ((ent = readdir(dd))) - if (Ustrncmp(ent->d_name, name, namelen) == 0) - { - struct stat statbuf; - Ustrcpy(lastname, ent->d_name); - if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid) - { - DEBUG(D_hints_lookup) debug_printf_indent("ensuring %s is owned by exim\n", filename); - if (Uchown(filename, exim_uid, exim_gid)) - DEBUG(D_hints_lookup) debug_printf_indent("failed setting %s to owned by exim\n", filename); - } - } + if ((dd = exim_opendir(filename))) + for (struct dirent *ent; ent = readdir(dd); ) + if (Ustrncmp(ent->d_name, name, namelen) == 0) + { + struct stat statbuf; + /* Filenames from readdir() are trusted, + so use a taint-nonchecking copy */ + strcpy(CS lastname, CCS ent->d_name); + if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid) + { + DEBUG(D_hints_lookup) + debug_printf_indent("ensuring %s is owned by exim\n", filename); + if (exim_chown(filename, exim_uid, exim_gid)) + DEBUG(D_hints_lookup) + debug_printf_indent("failed setting %s to owned by exim\n", filename); + } + } closedir(dd); } @@ -223,12 +228,13 @@ exist. */ if (!dbblock->dbptr) { + errno = save_errno; if (lof && save_errno != ENOENT) - log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s", + log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s", filename)); else DEBUG(D_hints_lookup) - debug_printf_indent("%s\n", CS string_open_failed(save_errno, "DB file %s", + debug_printf_indent("%s\n", CS string_open_failed("DB file %s", filename)); (void)close(dbblock->lockfd); errno = save_errno; @@ -302,7 +308,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); @@ -315,7 +321,10 @@ 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 the data store could have been tainted. Properly, we should +store the taint status 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); @@ -346,7 +355,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); @@ -380,7 +389,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)); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key); @@ -415,7 +424,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 */ DEBUG(D_hints_lookup) debug_printf_indent("dbfn_scan\n"); @@ -536,7 +544,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) } start = clock(); - odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE); + odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE, TRUE); stop = clock(); if (odb)