static void pre_jail_init(char *unused_name, char **unused_argv) { mode_t saved_mask; VSTRING *redirect; /* * Never, ever, get killed by a master signal, as that would corrupt the * database when we're in the middle of an update. */ setsid(); /* * Security: don't create root-owned files that contain untrusted data. * And don't create Postfix-owned files in root-owned directories, * either. We want a correct relationship between (file/directory) * ownership and (file/directory) content. * * XXX Non-root open can violate the principle of least surprise: Postfix * can't open an *SQL config file for database read-write access, even * though it can open that same control file for database read-only * access. * * The solution is to query a map type and obtain its properties before * opening it. A clean solution is to add a dict_info() API that is * similar to dict_open() except it returns properties (dict flags) only. * A pragmatic solution is to overload the existing API and have * dict_open() return a dummy map when given a null map name. * * However, the proxymap daemon has been opening *SQL maps as non-root for * years now without anyone complaining, let's not solve a problem that * doesn't exist. */ SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid); redirect = vstring_alloc(100); /* * Keep state in persistent (external) or volatile (internal) map. * * Start the cache cleanup thread after permanently dropping privileges. */ #define VERIFY_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE \ | DICT_FLAG_OPEN_LOCK | DICT_FLAG_UTF8_REQUEST) saved_mask = umask(022); verify_map = dict_cache_open(*var_verify_map ? data_redirect_map(redirect, var_verify_map) : "internal:verify", O_CREAT | O_RDWR, VERIFY_DICT_OPEN_FLAGS); (void) umask(saved_mask); /* * Clean up and restore privilege. */ vstring_free(redirect); RESTORE_SAVED_EUGID(); }
static void pre_jail_init(char *unused_name, char **unused_argv) { VSTRING *redirect; /* * Open read-only maps before dropping privilege, for consistency with * other Postfix daemons. */ psc_acl_pre_jail_init(var_mynetworks, VAR_PSC_ACL); if (*var_psc_acl) psc_acl = psc_acl_parse(var_psc_acl, VAR_PSC_ACL); /* Ignore smtpd_forbid_cmds lookup errors. Non-critical feature. */ if (*var_psc_forbid_cmds) psc_forbid_cmds = string_list_init(MATCH_FLAG_RETURN, var_psc_forbid_cmds); if (*var_psc_dnsbl_reply) psc_dnsbl_reply = dict_open(var_psc_dnsbl_reply, O_RDONLY, DICT_FLAG_DUP_WARN); /* * Never, ever, get killed by a master signal, as that would corrupt the * database when we're in the middle of an update. */ if (setsid() < 0) msg_warn("setsid: %m"); /* * Security: don't create root-owned files that contain untrusted data. * And don't create Postfix-owned files in root-owned directories, * either. We want a correct relationship between (file or directory) * ownership and (file or directory) content. To open files before going * to jail, temporarily drop root privileges. */ SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid); redirect = vstring_alloc(100); /* * Keep state in persistent external map. As a safety measure we sync the * database on each update. This hurts on LINUX file systems that sync * all dirty disk blocks whenever any application invokes fsync(). * * Start the cache maintenance pseudo thread after dropping privileges. */ #define PSC_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE | \ DICT_FLAG_OPEN_LOCK) if (*var_psc_cache_map) psc_cache_map = dict_cache_open(data_redirect_map(redirect, var_psc_cache_map), O_CREAT | O_RDWR, PSC_DICT_OPEN_FLAGS); /* * Clean up and restore privilege. */ vstring_free(redirect); RESTORE_SAVED_EUGID(); /* * Initialize the dummy SMTP engine. */ psc_smtpd_pre_jail_init(); }
static void tlsmgr_pre_init(char *unused_name, char **unused_argv) { char *path; struct timeval tv; TLSMGR_SCACHE *ent; VSTRING *redirect; HTABLE *dup_filter; const char *dup_label; /* * If nothing else works then at least this will get us a few bits of * entropy. * * XXX This is our first call into the OpenSSL library. We should find out * if this can be moved to the post-jail initialization phase, without * breaking compatibility with existing installations. */ GETTIMEOFDAY(&tv); tv.tv_sec ^= getpid(); RAND_seed(&tv, sizeof(struct timeval)); /* * Open the external entropy source. We will not be able to open it again * after we are sent to chroot jail, so we keep it open. Errors are not * fatal. The exchange file (see below) is the only entropy source that * really matters in the long run. * * Security note: we open the entropy source while privileged, but we don't * access the source until after we release privileges. This way, none of * the OpenSSL code gets to execute while we are privileged. */ if (*var_tls_rand_source) { /* * Source is a random device. */ if (!strncmp(var_tls_rand_source, DEV_PREF, DEV_PREF_LEN)) { path = DEV_PATH(var_tls_rand_source); rand_source_dev = tls_prng_dev_open(path, TLS_MGR_TIMEOUT); if (rand_source_dev == 0) msg_warn("cannot open entropy device %s: %m", path); } /* * Source is an EGD compatible socket. */ else if (!strncmp(var_tls_rand_source, EGD_PREF, EGD_PREF_LEN)) { path = EGD_PATH(var_tls_rand_source); rand_source_egd = tls_prng_egd_open(path, TLS_MGR_TIMEOUT); if (rand_source_egd == 0) msg_warn("cannot connect to EGD server %s: %m", path); } /* * Source is regular file. We read this only once. */ else { rand_source_file = tls_prng_file_open(var_tls_rand_source, TLS_MGR_TIMEOUT); } } else { msg_warn("no entropy source specified with parameter %s", VAR_TLS_RAND_SOURCE); msg_warn("encryption keys etc. may be predictable"); } /* * Security: don't create root-owned files that contain untrusted data. * And don't create Postfix-owned files in root-owned directories, * either. We want a correct relationship between (file/directory) * ownership and (file/directory) content. */ SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid); redirect = vstring_alloc(100); /* * Open the PRNG exchange file before going to jail, but don't use root * privileges. Start the exchange file read/update pseudo thread after * dropping privileges. */ if (*var_tls_rand_exch_name) { rand_exch = tls_prng_exch_open(data_redirect_file(redirect, var_tls_rand_exch_name)); if (rand_exch == 0) msg_fatal("cannot open PRNG exchange file %s: %m", var_tls_rand_exch_name); } /* * Open the session cache files and discard old information before going * to jail, but don't use root privilege. Start the cache maintenance * pseudo threads after dropping privileges. */ dup_filter = htable_create(sizeof(cache_table) / sizeof(cache_table[0])); for (ent = cache_table; ent->cache_label; ++ent) { /* Sanitize session timeout */ if (*ent->cache_timeout > 0) { if (*ent->cache_timeout < TLS_SESSION_LIFEMIN) *ent->cache_timeout = TLS_SESSION_LIFEMIN; } else { *ent->cache_timeout = 0; } /* External cache database disabled if timeout is non-positive */ if (*ent->cache_timeout > 0 && **ent->cache_db) { if ((dup_label = htable_find(dup_filter, *ent->cache_db)) != 0) msg_fatal("do not use the same TLS cache file %s for %s and %s", *ent->cache_db, dup_label, ent->cache_label); htable_enter(dup_filter, *ent->cache_db, ent->cache_label); ent->cache_info = tls_scache_open(data_redirect_map(redirect, *ent->cache_db), ent->cache_label, tls_log_mask(ent->log_param, *ent->log_level) & TLS_LOG_CACHE, *ent->cache_timeout); } } htable_free(dup_filter, (void (*) (char *)) 0); /* * Clean up and restore privilege. */ vstring_free(redirect); RESTORE_SAVED_EUGID(); }