static void io_loop_handle_timeouts_real(struct ioloop *ioloop) { struct priorityq_item *item; struct timeval tv, tv_call; unsigned int t_id; if (gettimeofday(&ioloop_timeval, NULL) < 0) i_fatal("gettimeofday(): %m"); /* Don't bother comparing usecs. */ if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) { /* time moved backwards */ io_loops_timeouts_update(-(long)(ioloop_time - ioloop_timeval.tv_sec)); ioloop->time_moved_callback(ioloop_time, ioloop_timeval.tv_sec); /* the callback may have slept, so check the time again. */ if (gettimeofday(&ioloop_timeval, NULL) < 0) i_fatal("gettimeofday(): %m"); } else if (unlikely(ioloop_timeval.tv_sec > ioloop->next_max_time)) { io_loops_timeouts_update(ioloop_timeval.tv_sec - ioloop->next_max_time); /* time moved forwards */ ioloop->time_moved_callback(ioloop->next_max_time, ioloop_timeval.tv_sec); } ioloop_time = ioloop_timeval.tv_sec; tv_call = ioloop_timeval; while ((item = priorityq_peek(ioloop->timeouts)) != NULL) { struct timeout *timeout = (struct timeout *)item; /* use tv_call to make sure we don't get to infinite loop in case callbacks update ioloop_timeval. */ if (timeout_get_wait_time(timeout, &tv, &tv_call) > 0) break; /* update timeout's next_run and reposition it in the queue */ timeout_reset_timeval(timeout, &tv_call); if (timeout->log != NULL) { ioloop->cur_log = timeout->log; io_loop_log_ref(ioloop->cur_log); i_set_failure_prefix(timeout->log->prefix); } t_id = t_push(); timeout->callback(timeout->context); if (t_pop() != t_id) { i_panic("Leaked a t_pop() call in timeout handler %p", (void *)timeout->callback); } if (ioloop->cur_log != NULL) { io_loop_log_unref(&ioloop->cur_log); i_set_failure_prefix(ioloop->default_log_prefix); } } }
static int cmd_dsync_server_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) { struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; struct dsync_ibc *ibc; struct dsync_brain *brain; string_t *temp_prefix, *state_str = NULL; enum dsync_brain_sync_type sync_type; const char *name; if (_ctx->conn != NULL) { /* doveadm-server connection. start with a success reply. after that follows the regular dsync protocol. */ ctx->fd_in = ctx->fd_out = -1; ctx->input = _ctx->conn->input; ctx->output = _ctx->conn->output; o_stream_nsend(ctx->output, "\n+\n", 3); i_set_failure_prefix("dsync-server(%s): ", user->username); name = i_stream_get_name(ctx->input); } else { /* the log messages go via stderr to the remote dsync, so the names are reversed */ i_set_failure_prefix("dsync-remote(%s): ", user->username); name = "local"; } doveadm_user_init_dsync(user); temp_prefix = t_str_new(64); mail_user_set_get_temp_prefix(temp_prefix, user->set); ibc = cmd_dsync_icb_stream_init(ctx, name, str_c(temp_prefix)); brain = dsync_brain_slave_init(user, ibc, FALSE); io_loop_run(current_ioloop); if (ctx->replicator_notify) { state_str = t_str_new(128); dsync_brain_get_state(brain, state_str); } sync_type = dsync_brain_get_sync_type(brain); if (dsync_brain_deinit(&brain) < 0) _ctx->exit_code = EX_TEMPFAIL; dsync_ibc_deinit(&ibc); if (_ctx->conn != NULL) { /* make sure nothing more is written by the generic doveadm connection code */ o_stream_close(_ctx->conn->output); } if (ctx->replicator_notify && _ctx->exit_code == 0) dsync_replicator_notify(ctx, sync_type, str_c(state_str)); return _ctx->exit_code == 0 ? 0 : -1; }
int mail_storage_service_next(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, struct mail_user **mail_user_r) { char *old_log_prefix = i_strdup(i_get_failure_prefix()); int ret; mail_storage_service_set_log_prefix(ctx, user->user_set, user, &user->input, NULL); i_set_failure_prefix("%s", old_log_prefix); ret = mail_storage_service_next_real(ctx, user, mail_user_r); if ((user->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) != 0) i_set_failure_prefix("%s", old_log_prefix); i_free(old_log_prefix); return ret; }
static void client_destroy(struct client *client) { char **app; i_set_failure_prefix("imap-urlauth[%s](%s): ", my_pid, client->access_user); if (client->url != NULL) { /* deinitialize url */ i_stream_close(client->input); o_stream_close(client->output); (void)client_run_url(client); i_assert(client->url == NULL); } imap_urlauth_worker_client_count--; DLLIST_REMOVE(&imap_urlauth_worker_clients, client); if (client->urlauth_ctx != NULL) imap_urlauth_deinit(&client->urlauth_ctx); if (client->mail_user != NULL) mail_user_unref(&client->mail_user); if (client->io != NULL) io_remove(&client->io); if (client->ctrl_io != NULL) io_remove(&client->ctrl_io); if (client->to_idle != NULL) timeout_remove(&client->to_idle); if (client->input != NULL) i_stream_destroy(&client->input); if (client->output != NULL) o_stream_destroy(&client->output); if (client->ctrl_input != NULL) i_stream_destroy(&client->ctrl_input); if (client->ctrl_output != NULL) o_stream_destroy(&client->ctrl_output); if (client->fd_in >= 0) net_disconnect(client->fd_in); if (client->fd_out >= 0 && client->fd_in != client->fd_out) net_disconnect(client->fd_out); if (client->fd_ctrl >= 0) net_disconnect(client->fd_ctrl); if (client->service_user != NULL) mail_storage_service_user_free(&client->service_user); i_free(client->access_user); array_foreach_modifiable(&client->access_apps, app) i_free(*app); array_free(&client->access_apps); i_free(client); imap_urlauth_worker_refresh_proctitle(); master_service_client_connection_destroyed(master_service); }
int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, struct mail_storage_service_user **user_r, const char **error_r) { char *old_log_prefix = i_strdup(i_get_failure_prefix()); bool update_log_prefix; int ret; if (io_loop_get_current_context(current_ioloop) == NULL) { /* no user yet. log prefix should be just "imap:" or something equally unhelpful. we don't know the proper log format yet, but initialize it to something better until we know it. */ const char *session_id = input->session_id != NULL ? input->session_id : (input->session_id_prefix != NULL ? input->session_id_prefix : NULL); i_set_failure_prefix("%s(%s%s,%s)", master_service_get_name(ctx->service), input->username, session_id == NULL ? "" : t_strdup_printf(",%s", session_id), input->remote_ip.family == 0 ? "" : t_strdup_printf(",%s", net_ip2addr(&input->remote_ip))); update_log_prefix = TRUE; } else { /* we might be here because we're doing a user lookup for a shared user. the log prefix is likely already usable, so just append our own without replacing the whole thing. */ i_set_failure_prefix("%suser-lookup(%s)", old_log_prefix, input->username); update_log_prefix = FALSE; } ret = mail_storage_service_lookup_real(ctx, input, update_log_prefix, user_r, error_r); i_set_failure_prefix("%s", old_log_prefix); i_free(old_log_prefix); return ret; }
static void mail_storage_service_set_log_prefix(struct mail_storage_service_ctx *ctx, const struct mail_user_settings *user_set, struct mail_storage_service_user *user, const struct mail_storage_service_input *input, const struct mail_storage_service_privileges *priv) { string_t *str; str = t_str_new(256); mail_storage_service_var_expand(ctx, str, user_set->mail_log_prefix, user, input, priv); i_set_failure_prefix("%s", str_c(str)); }
static struct client * client_create_standalone(const char *access_user, const char *const *access_applications, int fd_in, int fd_out, bool debug) { struct client *client; /* always use nonblocking I/O */ net_set_nonblock(fd_in, TRUE); net_set_nonblock(fd_out, TRUE); client = i_new(struct client, 1); i_array_init(&client->access_apps, 16); client->fd_in = fd_in; client->fd_out = fd_out; client->fd_ctrl = -1; if (access_user != NULL && *access_user != '\0') client->access_user = i_strdup(access_user); else { client->access_user = i_strdup("anonymous"); client->access_anonymous = TRUE; } if (access_applications != NULL) { const char *const *apps = access_applications; for (; *apps != NULL; apps++) { char *app = i_strdup(*apps); array_append(&client->access_apps, &app, 1); } } client->debug = debug; client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE); client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE); client->io = io_add(fd_in, IO_READ, client_input, client); client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS, client_idle_timeout, client); o_stream_set_flush_callback(client->output, client_output, client); imap_urlauth_worker_client_count++; DLLIST_PREPEND(&imap_urlauth_worker_clients, client); i_set_failure_prefix("imap-urlauth[%s](%s): ", my_pid, client->access_user); return client; }
struct client_connection * client_connection_create(int fd, int listen_fd, bool ssl) { struct client_connection *conn; const char *ip; pool_t pool; pool = pool_alloconly_create("doveadm client", 1024*16); conn = p_new(pool, struct client_connection, 1); conn->pool = pool; conn->fd = fd; conn->io = io_add(fd, IO_READ, client_connection_input, conn); conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(conn->output, TRUE); (void)net_getsockname(fd, &conn->local_ip, &conn->local_port); (void)net_getpeername(fd, &conn->remote_ip, &conn->remote_port); i_stream_set_name(conn->input, net_ip2addr(&conn->remote_ip)); o_stream_set_name(conn->output, net_ip2addr(&conn->remote_ip)); ip = net_ip2addr(&conn->remote_ip); if (ip[0] != '\0') i_set_failure_prefix("doveadm(%s): ", ip); if (client_connection_read_settings(conn) < 0) { client_connection_destroy(&conn); return NULL; } if (ssl) { if (client_connection_init_ssl(conn) < 0) { client_connection_destroy(&conn); return NULL; } } client_connection_send_auth_handshake(conn, listen_fd); return conn; }
void mail_storage_service_io_deactivate(struct mail_storage_service_ctx *ctx) { i_set_failure_prefix("%s", ctx->default_log_prefix); }
void mail_storage_service_io_deactivate_user(struct mail_storage_service_user *user) { i_set_failure_prefix("%s", user->service_ctx->default_log_prefix); }
void mail_storage_service_io_activate_user(struct mail_storage_service_user *user) { i_set_failure_prefix("%s", user->log_prefix); }
static void cmd_dsync_run_remote(struct mail_user *user) { i_set_failure_prefix("dsync-local(%s): ", user->username); io_loop_run(current_ioloop); }
static int cmd_dsync_run_local(struct dsync_cmd_context *ctx, struct mail_user *user, struct dsync_brain *brain, struct dsync_ibc *ibc2, bool *changes_during_sync_r) { struct dsync_brain *brain2; struct mail_user *user2; struct setting_parser_context *set_parser; const char *set_line, *location; bool brain1_running, brain2_running, changed1, changed2; int ret; if (ctx->local_location_from_arg) location = ctx->ctx.args[0]; else { i_assert(ctx->local_location != NULL); location = ctx->local_location; } i_set_failure_prefix("dsync(%s): ", user->username); /* update mail_location and create another user for the second location. */ set_parser = mail_storage_service_user_get_settings_parser(ctx->ctx.cur_service_user); set_line = t_strconcat("mail_location=", location, NULL); if (settings_parse_line(set_parser, set_line) < 0) i_unreached(); ret = mail_storage_service_next(ctx->ctx.storage_service, ctx->ctx.cur_service_user, &user2); if (ret < 0) { ctx->ctx.exit_code = ret == -1 ? EX_TEMPFAIL : EX_CONFIG; return -1; } doveadm_user_init_dsync(user2); if (mail_namespaces_get_root_sep(user->namespaces) != mail_namespaces_get_root_sep(user2->namespaces)) { i_error("Mail locations must use the same " "virtual mailbox hierarchy separator " "(specify separator for the default namespace)"); ctx->ctx.exit_code = EX_CONFIG; mail_user_unref(&user2); return -1; } if (paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_MAILBOX) && paths_are_equal(user, user2, MAILBOX_LIST_PATH_TYPE_INDEX)) { i_error("Both source and destination mail_location " "points to same directory: %s", mailbox_list_get_root_forced(user->namespaces->list, MAILBOX_LIST_PATH_TYPE_MAILBOX)); ctx->ctx.exit_code = EX_CONFIG; mail_user_unref(&user2); return -1; } brain2 = dsync_brain_slave_init(user2, ibc2, TRUE); mail_user_unref(&user2); brain1_running = brain2_running = TRUE; changed1 = changed2 = TRUE; while (brain1_running || brain2_running) { if (dsync_brain_has_failed(brain) || dsync_brain_has_failed(brain2)) break; i_assert(changed1 || changed2); brain1_running = dsync_brain_run(brain, &changed1); brain2_running = dsync_brain_run(brain2, &changed2); } *changes_during_sync_r = dsync_brain_has_unexpected_changes(brain2); if (dsync_brain_deinit(&brain2) < 0) { ctx->ctx.exit_code = EX_TEMPFAIL; return -1; } return 0; }
static void client_ctrl_input(struct client *client) { const char *const *args; const char *line; int ret; timeout_reset(client->to_idle); if (client->fd_in == -1 || client->fd_out == -1) { if ((ret = client_ctrl_read_fds(client)) <= 0) { if (ret < 0) client_abort(client, "FD Transfer failed"); return; } } switch (i_stream_read(client->ctrl_input)) { case -1: /* disconnected */ client_destroy(client); return; case -2: /* line too long, kill it */ client_abort(client, "Control session aborted: Input line too long"); return; } if (!client->version_received) { if ((line = i_stream_next_line(client->ctrl_input)) == NULL) return; if (!version_string_verify(line, "imap-urlauth-worker", IMAP_URLAUTH_WORKER_PROTOCOL_MAJOR_VERSION)) { i_error("imap-urlauth-worker client not compatible with this server " "(mixed old and new binaries?) %s", line); client_abort(client, "Control session aborted: Version mismatch"); return; } client->version_received = TRUE; if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) { client_destroy(client); return; } } if (client->access_received) { client_abort(client, "Control session aborted: Unexpected input"); return; } if ((line = i_stream_next_line(client->ctrl_input)) == NULL) return; args = t_strsplit_tabescaped(line); if (*args == NULL || strcmp(*args, "ACCESS") != 0) { i_error("Invalid control command: %s", str_sanitize(line, 80)); client_abort(client, "Control session aborted: Invalid command"); return; } args++; if (*args == NULL) { i_error("Invalid ACCESS command: %s", str_sanitize(line, 80)); client_abort(client, "Control session aborted: Invalid command"); return; } i_assert(client->access_user == NULL); if (**args != '\0') { client->access_user = i_strdup(*args); client->access_anonymous = FALSE; } else { client->access_user = i_strdup("anonymous"); client->access_anonymous = TRUE; } i_set_failure_prefix("imap-urlauth[%s](%s): ", my_pid, client->access_user); args++; while (*args != NULL) { /* debug */ if (strcasecmp(*args, "debug") == 0) { client->debug = TRUE; /* apps=<access-application>[,<access-application,...] */ } else if (strncasecmp(*args, "apps=", 5) == 0 && (*args)[5] != '\0') { const char *const *apps = t_strsplit(*args+5, ","); while (*apps != NULL) { char *app = i_strdup(*apps); array_append(&client->access_apps, &app, 1); if (client->debug) { i_debug("User %s has URLAUTH %s access", client->access_user, app); } apps++; } } else { i_error("Invalid ACCESS parameter: %s", str_sanitize(*args, 80)); client_abort(client, "Control session aborted: Invalid command"); return; } args++; } client->access_received = TRUE; if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) { client_destroy(client); return; } client->input = i_stream_create_fd(client->fd_in, MAX_INBUF_SIZE, FALSE); client->output = o_stream_create_fd(client->fd_out, (size_t)-1, FALSE); client->io = io_add(client->fd_in, IO_READ, client_input, client); o_stream_set_flush_callback(client->output, client_output, client); if (client->debug) { i_debug("Worker activated for access by user %s", client->access_user); } }
static int client_handle_user_command(struct client *client, const char *cmd, const char *const *args, const char **error_r) { struct mail_storage_service_input input; struct imap_urlauth_worker_settings *set; struct mail_storage_service_user *user; struct imap_urlauth_config config; struct mail_user *mail_user; const char *error; unsigned int count; int ret; /* "USER\t"<username> */ *error_r = NULL; /* check command syntax */ if (strcmp(cmd, "USER") != 0) { *error_r = t_strconcat("Unknown or inappropriate command: ", cmd, NULL); return -1; } if (args[0] == NULL || args[1] != NULL) { *error_r = "USER: Invalid number of parameters"; return -1; } /* lookup user */ memset(&input, 0, sizeof(input)); input.module = "imap-urlauth-worker"; input.service = "imap-urlauth-worker"; input.username = args[0]; if (client->debug) i_debug("Looking up user %s", input.username); ret = mail_storage_service_lookup_next(storage_service, &input, &user, &mail_user, &error); if (ret < 0) { i_error("Failed to lookup user %s: %s", input.username, error); client_abort(client, "Session aborted: Failed to lookup user"); return 0; } else if (ret == 0) { if (client->debug) i_debug("User %s doesn't exist", input.username); client_send_line(client, "NO"); timeout_remove(&client->to_delay); return 1; } client->debug = mail_user->mail_debug = client->debug || mail_user->mail_debug; /* drop privileges */ restrict_access_allow_coredumps(TRUE); set = mail_storage_service_user_get_set(user)[1]; settings_var_expand(&imap_urlauth_worker_setting_parser_info, set, mail_user->pool, mail_user_var_expand_table(mail_user)); if (set->verbose_proctitle) { verbose_proctitle = TRUE; imap_urlauth_worker_refresh_proctitle(); } client->service_user = user; client->mail_user = mail_user; client->set = set; if (client->debug) { i_debug("Found user account `%s' on behalf of user `%s'", mail_user->username, client->access_user); } /* initialize urlauth context */ if (*set->imap_urlauth_host == '\0') { i_error("imap_urlauth_host setting is not configured for user %s", mail_user->username); client_send_line(client, "NO"); client_abort(client, "Session aborted: URLAUTH not configured"); return 0; } memset(&config, 0, sizeof(config)); config.url_host = set->imap_urlauth_host; config.url_port = set->imap_urlauth_port; config.access_user = client->access_user; config.access_anonymous = client->access_anonymous; config.access_applications = (const void *)array_get(&client->access_apps, &count); client->urlauth_ctx = imap_urlauth_init(client->mail_user, &config); if (client->debug) { i_debug("Providing access to user account `%s' on behalf of `%s'", mail_user->username, client->access_user); } i_set_failure_prefix("imap-urlauth[%s](%s->%s): ", my_pid, client->access_user, mail_user->username); client_send_line(client, "OK"); return 1; }