static void tlsmgr_prng_exch_event(int unused_event acl_unused, void *dummy) { const char *myname = "tlsmgr_prng_exch_event"; unsigned char randbyte; int next_period; struct acl_stat st; if (acl_msg_verbose) acl_msg_info("%s: update PRNG exchange file", myname); /* * Sanity check. If the PRNG exchange file was removed, there is no point * updating it further. Restart the process and update the new file. */ if (acl_fstat(rand_exch->fd.file, &st) < 0) acl_msg_fatal("%s: cannot fstat() the PRNG exchange file: %s", myname, acl_last_serror()); if (st.st_nlink == 0) { acl_msg_warn("%s: PRNG exchange file was removed -- exiting to reopen", myname); sleep(1); exit(0); } tls_prng_exch_update(rand_exch); /* * Make prediction difficult for outsiders and calculate the time for the * next execution randomly. */ RAND_bytes(&randbyte, 1); next_period = (var_tls_prng_exch_period * randbyte) / UCHAR_MAX; acl_event_request_timer(__eventp, tlsmgr_prng_exch_event, dummy, next_period, 0); }
int acl_unix_trigger(ACL_EVENT *event, const char *service, const char *buf, int len, int timeout) { const char *myname = "acl_unix_trigger"; struct ACL_UNIX_TRIGGER *up; ACL_SOCKET fd; if (acl_msg_verbose > 0) acl_msg_info("%s: service %s", myname, service); /* * Connect... */ if ((fd = acl_unix_connect(service, ACL_BLOCKING, timeout)) < 0) { if (acl_msg_verbose) acl_msg_warn("%s: connect to %s: %s", myname, service, strerror(errno)); return -1; } acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); /* * Stash away context. */ up = (struct ACL_UNIX_TRIGGER *) acl_mymalloc(sizeof(*up)); up->service = acl_mystrdup(service); up->stream = acl_vstream_fdopen(fd, O_RDWR, 4096, timeout, ACL_VSTREAM_TYPE_LISTEN_UNIX); /* * Write the request... */ if (acl_vstream_writen(up->stream, buf, len) < 0 || acl_vstream_writen(up->stream, "", 1) < 0) { if (acl_msg_verbose) acl_msg_warn("%s: write to %s: %s", myname, service, strerror(errno)); } /* * Wakeup when the peer disconnects, or when we lose patience. */ #ifdef __USE_TIMER if (timeout > 0) acl_event_request_timer(event, acl_unix_trigger_timer, (void *) up, (timeout + 100) * 1000000); acl_event_enable_read(event, up->stream, 0, acl_unix_trigger_event, (void *) up); #else if (timeout > 0) acl_event_enable_read(event, up->stream, timeout + 100, acl_unix_trigger_event, (void *) up); else acl_event_enable_read(event, up->stream, 0, acl_unix_trigger_event, (void *) up); #endif return 0; }
static void tlsmgr_cache_run_event(int unused_event acl_unused, void *ctx) { const char *myname = "tlsmgr_cache_run_event"; TLSMGR_SCACHE *cache = (TLSMGR_SCACHE *) ctx; /* * This routine runs when it is time for another TLS session cache scan. * Make sure this routine gets called again in the future. * * Don't start a new scan when the timer goes off while cache cleanup is * still in progress. */ if (cache->cache_info->verbose) acl_msg_info("%s: start TLS %s session cache cleanup", myname, cache->cache_label); if (cache->cache_active == 0) cache->cache_active = tls_scache_sequence(cache->cache_info, DICT_SEQ_FUN_FIRST, TLS_SCACHE_SEQUENCE_NOTHING); acl_event_request_timer(__eventp, tlsmgr_cache_run_event, (char *) cache, cache->cache_info->timeout, 0); }
static void tlsmgr_reseed_event(int unused_event acl_unused, void *dummy) { const char *myname = "tlsmgr_reseed_event"; int next_period; unsigned char randbyte; int must_exit = 0; /* * Reseed the internal PRNG from external source. Errors are recoverable. * We simply restart and reconnect without making a fuss. This is OK * because we do require that exchange file updates succeed. The exchange * file is the only entropy source that really matters in the long term. * * If the administrator specifies an external randomness source that we * could not open upon start-up, restart to see if we can open it now * (and log a nagging warning if we can't). */ if (*var_tls_rand_source) { /* * Source is a random device. */ if (rand_source_dev) { if (tls_prng_dev_read(rand_source_dev, var_tls_rand_bytes) <= 0) { acl_msg_info("%s: cannot read from entropy device %s: %s -- " "exiting to reopen", myname, DEV_PATH(var_tls_rand_source), acl_last_serror()); must_exit = 1; } } /* * Source is an EGD compatible socket. */ else if (rand_source_egd) { if (tls_prng_egd_read(rand_source_egd, var_tls_rand_bytes) <= 0) { acl_msg_info("%s: lost connection to EGD server %s -- " "exiting to reconnect", myname, EGD_PATH(var_tls_rand_source)); must_exit = 1; } } /* * Source is a regular file. Read the content once and close the * file. */ else if (rand_source_file) { if (tls_prng_file_read(rand_source_file, var_tls_rand_bytes) <= 0) acl_msg_warn("%s: cannot read from entropy file %s: %s", myname, var_tls_rand_source, acl_last_serror()); tls_prng_file_close(rand_source_file); rand_source_file = 0; var_tls_rand_source[0] = 0; } /* * Could not open the external source upon start-up. See if we can * open it this time. Save PRNG state before we exit. */ else { acl_msg_info("exiting to reopen external entropy source %s", var_tls_rand_source); must_exit = 1; } } /* * Save PRNG state in case we must exit. */ if (must_exit) { if (rand_exch) tls_prng_exch_update(rand_exch); sleep(1); acl_msg_info("exit now"); exit(0); } /* * Make prediction difficult for outsiders and calculate the time for the * next execution randomly. */ RAND_bytes(&randbyte, 1); next_period = (var_tls_reseed_period * randbyte) / UCHAR_MAX; acl_event_request_timer(__eventp, tlsmgr_reseed_event, dummy, next_period, 0); }
void acl_udp_server_request_timer(ACL_EVENT_NOTIFY_TIME timer_fn, void *arg, acl_int64 delay, int keep) { acl_event_request_timer(__event, timer_fn, arg, delay, keep); }
static void master_wakeup_timer_event(int type acl_unused, ACL_EVENT *event, void *context) { const char *myname = "master_wakeup_timer_event"; ACL_MASTER_SERV *serv = (ACL_MASTER_SERV *) context; static char wakeup = ACL_TRIGGER_REQ_WAKEUP; int status = 0; acl_assert(event == acl_var_master_global_event); /* * Don't wakeup services whose automatic wakeup feature was * turned off in the mean time. */ if (serv->wakeup_time == 0) return; /* * Don't wakeup services whose is ACL_MASTER_SERV_TYPE_SOCK */ if (serv->type == ACL_MASTER_SERV_TYPE_SOCK) return; /* * Don't wake up services that are throttled. Find out what * transport to use. We can't block here so we choose a short timeout. */ #define BRIEFLY 1 if (ACL_MASTER_THROTTLED(serv) == 0) { if (acl_msg_verbose) acl_msg_info("%s: service %s", myname, serv->name); switch (serv->type) { case ACL_MASTER_SERV_TYPE_INET: status = acl_inet_trigger(acl_var_master_global_event, serv->name, &wakeup, sizeof(wakeup), BRIEFLY); break; case ACL_MASTER_SERV_TYPE_UNIX: status = ACL_LOCAL_TRIGGER(acl_var_master_global_event, serv->name, &wakeup, sizeof(wakeup), BRIEFLY); break; /* * If someone compromises the postfix account then this must not * overwrite files outside the chroot jail. Countermeasures: * * - Limit the damage by accessing the FIFO as postfix not root. * * - Have fifo_trigger() call safe_open() so we won't follow * arbitrary hard/symlinks to files in/outside the chroot jail. * * - All non-chroot postfix-related files must be root owned (or * postfix check complains). * * - The postfix user and group ID must not be shared with other * applications (says the INSTALL documentation). * * Result of a discussion with Michael Tokarev, who received his * insights from Solar Designer, who tested Postfix with a kernel * module that is paranoid about open() calls. */ case ACL_MASTER_SERV_TYPE_FIFO: if (acl_var_master_limit_privilege) acl_set_eugid(acl_var_master_owner_uid, acl_var_master_owner_gid); status = acl_fifo_trigger(acl_var_master_global_event, serv->name, &wakeup, sizeof(wakeup), BRIEFLY); if (acl_var_master_limit_privilege) acl_set_ugid(getuid(), getgid()); break; default: acl_msg_panic("%s: unknown service type: %d", myname, serv->type); } if (status < 0) acl_msg_warn("%s: service %s: %s", myname, serv->name, strerror(errno)); } /* * Schedule another wakeup event. */ acl_event_request_timer(acl_var_master_global_event, master_wakeup_timer_event, (void *) serv, (acl_int64) serv->wakeup_time * 1000000, 0); }