void stats_connection_connect(struct stats_connection *conn, struct mail_user *user) { struct stats_user *suser = STATS_USER_CONTEXT(user); string_t *str = t_str_new(128); str_append(str, "CONNECT\t"); /* required fields */ str_append(str, guid_128_to_string(suser->session_guid)); str_append_c(str, '\t'); str_append_tabescaped(str, user->username); str_append_c(str, '\t'); str_append_tabescaped(str, user->service); str_printfa(str, "\t%s", my_pid); /* optional fields */ if (user->local_ip != NULL) { str_append(str, "\tlip="); str_append(str, net_ip2addr(user->local_ip)); } if (user->remote_ip != NULL) { str_append(str, "\trip="); str_append(str, net_ip2addr(user->remote_ip)); } str_append_c(str, '\n'); stats_connection_send(conn, str); }
static void login_proxy_cmd_list_reply(struct ipc_cmd *cmd, string_t *str, struct login_proxy *proxy) { unsigned int i, alt_count = array_count(&global_alt_usernames); str_truncate(str, 0); str_append_tabescaped(str, proxy->client->virtual_user); str_append_c(str, '\t'); i = 0; if (proxy->client->alt_usernames != NULL) { for (; proxy->client->alt_usernames[i] != NULL; i++) { str_append_tabescaped(str, proxy->client->alt_usernames[i]); str_append_c(str, '\t'); } i_assert(i <= alt_count); } for (; i < alt_count; i++) str_append_c(str, '\t'); str_printfa(str, "%s\t%s\t%s\t%u", login_binary->protocol, net_ip2addr(&proxy->client->ip), net_ip2addr(&proxy->ip), proxy->port); ipc_cmd_send(cmd, str_c(str)); }
static int client_input_status_dsyncs(struct doveadm_connection *client) { string_t *str = t_str_new(256); const ARRAY_TYPE(dsync_client) *clients; struct dsync_client *const *clientp; const char *username; clients = replicator_brain_get_dsync_clients(client->brain); array_foreach(clients, clientp) { username = dsync_client_get_username(*clientp); if (username != NULL) { str_append_tabescaped(str, username); str_append_c(str, '\t'); switch (dsync_client_get_type(*clientp)) { case DSYNC_TYPE_FULL: str_append(str, "full"); break; case DSYNC_TYPE_NORMAL: str_append(str, "normal"); break; case DSYNC_TYPE_INCREMENTAL: str_append(str, "incremental"); break; } } else { str_append(str, "\t-"); } str_append_c(str, '\t'); str_append_tabescaped(str, dsync_client_get_state(*clientp)); str_append_c(str, '\n'); }
static void verify_plain_callback(enum passdb_result result, struct auth_request *request) { struct auth_worker_client *client = request->context; string_t *str; if (request->failed && result == PASSDB_RESULT_OK) result = PASSDB_RESULT_PASSWORD_MISMATCH; str = t_str_new(128); str_printfa(str, "%u\t", request->id); if (result == PASSDB_RESULT_OK) str_append(str, "OK"); else str_printfa(str, "FAIL\t%d", result); if (result != PASSDB_RESULT_INTERNAL_FAILURE) { str_append_c(str, '\t'); str_append_tabescaped(str, request->user); str_append_c(str, '\t'); if (request->passdb_password != NULL) str_append_tabescaped(str, request->passdb_password); reply_append_extra_fields(str, request); } str_append_c(str, '\n'); auth_worker_send_reply(client, request, str); auth_request_unref(&request); auth_worker_client_check_throttle(client); auth_worker_client_unref(&client); }
void worker_connection_request(struct worker_connection *conn, const struct indexer_request *request, void *context) { i_assert(worker_connection_is_connected(conn)); i_assert(context != NULL); i_assert(request->index || request->optimize); if (conn->request_username == NULL) conn->request_username = i_strdup(request->username); else { i_assert(strcmp(conn->request_username, request->username) == 0); } aqueue_append(conn->request_queue, &context); T_BEGIN { string_t *str = t_str_new(128); str_append_tabescaped(str, request->username); str_append_c(str, '\t'); str_append_tabescaped(str, request->mailbox); str_append_c(str, '\t'); if (request->session_id != NULL) str_append_tabescaped(str, request->session_id); str_printfa(str, "\t%u\t", request->max_recent_msgs); if (request->index) str_append_c(str, 'i'); if (request->optimize) str_append_c(str, 'o'); str_append_c(str, '\n'); o_stream_nsend(conn->output, str_data(str), str_len(str)); } T_END; }
static void fts_queue_index(struct mailbox *box) { struct mail_user *user = box->storage->user; string_t *str = t_str_new(256); const char *path, *value; unsigned int max_recent_msgs; int fd; path = t_strconcat(user->set->base_dir, "/"INDEXER_SOCKET_NAME, NULL); fd = net_connect_unix(path); if (fd == -1) { i_error("net_connect_unix(%s) failed: %m", path); return; } value = mail_user_plugin_getenv(user, "fts_autoindex_max_recent_msgs"); if (value == NULL || str_to_uint(value, &max_recent_msgs) < 0) max_recent_msgs = 0; str_append(str, INDEXER_HANDSHAKE); str_append(str, "APPEND\t0\t"); str_append_tabescaped(str, user->username); str_append_c(str, '\t'); str_append_tabescaped(str, box->vname); str_printfa(str, "\t%u", max_recent_msgs); str_append_c(str, '\t'); str_append_tabescaped(str, box->storage->user->session_id); str_append_c(str, '\n'); if (write_full(fd, str_data(str), str_len(str)) < 0) i_error("write(%s) failed: %m", path); i_close_fd(&fd); }
static int client_export_iter_session(struct client *client) { struct client_export_cmd *cmd = client->cmd_export; struct mail_session *session = client->mail_session_iter; i_assert(cmd->level == MAIL_EXPORT_LEVEL_SESSION); mail_session_unref(&client->mail_session_iter); if (!cmd->header_sent) { o_stream_nsend_str(client->output, "session\tuser\tip\tservice\tpid\tconnected" "\tlast_update\tnum_cmds" MAIL_STATS_HEADER); cmd->header_sent = TRUE; } for (; session != NULL; session = session->stable_next) { if (client_is_busy(client)) break; if (!mail_export_filter_match_session(&cmd->filter, session)) continue; str_truncate(cmd->str, 0); T_BEGIN { str_append(cmd->str, guid_128_to_string(session->guid)); str_append_c(cmd->str, '\t'); str_append_tabescaped(cmd->str, session->user->name); str_append_c(cmd->str, '\t'); if (session->ip != NULL) { str_append(cmd->str, net_ip2addr(&session->ip->ip)); } str_append_c(cmd->str, '\t'); str_append_tabescaped(cmd->str, session->service); } T_END; str_printfa(cmd->str, "\t%ld", (long)session->pid); str_printfa(cmd->str, "\t%d", !session->disconnected); client_export_timeval(cmd->str, &session->last_update); str_printfa(cmd->str, "\t%u", session->num_cmds); client_export_mail_stats(cmd->str, &session->stats); str_append_c(cmd->str, '\n'); o_stream_nsend(client->output, str_data(cmd->str), str_len(cmd->str)); } if (session != NULL) { client->mail_session_iter = session; mail_session_ref(session); return 0; } return 1; }
static void auth_request_handler_reply_success_finish(struct auth_request *request) { struct auth_request_handler *handler = request->handler; string_t *str = t_str_new(128); if (request->last_penalty != 0 && auth_penalty != NULL) { /* reset penalty */ auth_penalty_update(auth_penalty, request, 0); } /* sanitize these fields, since the login code currently assumes they are exactly in this format. */ auth_fields_booleanize(request->extra_fields, "nologin"); auth_fields_booleanize(request->extra_fields, "proxy"); str_printfa(str, "OK\t%u\tuser="******"nologin") || auth_fields_exists(request->extra_fields, "proxy")) { /* this request doesn't have to wait for master process to pick it up. delete it */ auth_request_handler_remove(handler, request); } handler->callback(str_c(str), handler->context); }
static void lookup_credentials_callback(enum passdb_result result, const unsigned char *credentials, size_t size, struct auth_request *request) { struct auth_worker_client *client = request->context; string_t *str; if (request->failed && result == PASSDB_RESULT_OK) result = PASSDB_RESULT_PASSWORD_MISMATCH; str = t_str_new(128); str_printfa(str, "%u\t", request->id); if (result != PASSDB_RESULT_OK) str_printfa(str, "FAIL\t%d", result); else { str_append(str, "OK\t"); str_append_tabescaped(str, request->user); str_append_c(str, '\t'); if (request->credentials_scheme[0] != '\0') { str_printfa(str, "{%s.b64}", request->credentials_scheme); base64_encode(credentials, size, str); } else { i_assert(size == 0); } reply_append_extra_fields(str, request); } str_append_c(str, '\n'); auth_worker_send_reply(client, request, str); auth_request_unref(&request); auth_worker_client_check_throttle(client); auth_worker_client_unref(&client); }
static void lookup_user_callback(enum userdb_result result, struct auth_request *auth_request) { struct auth_worker_client *client = auth_request->context; string_t *str; str = t_str_new(128); str_printfa(str, "%u\t", auth_request->id); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_append(str, "FAIL\t"); break; case USERDB_RESULT_USER_UNKNOWN: str_append(str, "NOTFOUND\t"); break; case USERDB_RESULT_OK: str_append(str, "OK\t"); str_append_tabescaped(str, auth_request->user); str_append_c(str, '\t'); auth_fields_append(auth_request->userdb_reply, str, 0, 0); if (auth_request->userdb_lookup_tempfailed) str_append(str, "\ttempfail"); break; } str_append_c(str, '\n'); auth_worker_send_reply(client, auth_request, str); auth_request_unref(&auth_request); auth_worker_client_check_throttle(client); auth_worker_client_unref(&client); }
static int client_input_status(struct doveadm_connection *client, const char *const *args) { struct replicator_queue_iter *iter; struct replicator_user *user; const char *mask = args[0]; string_t *str = t_str_new(128); if (mask == NULL) return client_input_status_overview(client); iter = replicator_queue_iter_init(client->queue); while ((user = replicator_queue_iter_next(iter)) != NULL) { if (!wildcard_match(user->username, mask)) continue; str_truncate(str, 0); str_append_tabescaped(str, user->username); str_append_c(str, '\t'); str_append(str, replicator_priority_to_str(user->priority)); str_printfa(str, "\t%lld\t%lld\t%d\n", (long long)user->last_fast_sync, (long long)user->last_full_sync, user->last_sync_failed); o_stream_send(client->conn.output, str_data(str), str_len(str)); } replicator_queue_iter_deinit(&iter); o_stream_send(client->conn.output, "\n", 1); return 0; }
static int client_export_iter_command(struct client *client) { struct client_export_cmd *cmd = client->cmd_export; struct mail_command *command = client->mail_cmd_iter; i_assert(cmd->level == MAIL_EXPORT_LEVEL_COMMAND); mail_command_unref(&client->mail_cmd_iter); if (!cmd->header_sent) { o_stream_nsend_str(client->output, "cmd\targs\tsession\tuser\tlast_update"MAIL_STATS_HEADER); cmd->header_sent = TRUE; } for (; command != NULL; command = command->stable_next) { if (client_is_busy(client)) break; if (!mail_export_filter_match_session(&cmd->filter, command->session)) continue; str_truncate(cmd->str, 0); str_append_tabescaped(cmd->str, command->name); str_append_c(cmd->str, '\t'); str_append_tabescaped(cmd->str, command->args); str_append_c(cmd->str, '\t'); T_BEGIN { str_append(cmd->str, guid_128_to_string(command->session->guid)); str_append_c(cmd->str, '\t'); str_append_tabescaped(cmd->str, command->session->user->name); } T_END; client_export_timeval(cmd->str, &command->last_update); client_export_mail_stats(cmd->str, &command->stats); str_append_c(cmd->str, '\n'); o_stream_nsend(client->output, str_data(cmd->str), str_len(cmd->str)); } if (command != NULL) { client->mail_cmd_iter = command; mail_command_ref(command); return 0; } return 1; }
static void auth_str_add_keyvalue(string_t *dest, const char *key, const char *value) { str_append_c(dest, '\t'); str_append(dest, key); str_append_c(dest, '='); str_append_tabescaped(dest, value); }
static int replication_notify_sync(struct mail_user *user) { struct replication_user *ruser = REPLICATION_USER_CONTEXT(user); string_t *str; char buf[1024]; int fd; ssize_t ret; fd = net_connect_unix(ruser->socket_path); if (fd == -1) { i_error("net_connect_unix(%s) failed: %m", ruser->socket_path); return -1; } net_set_nonblock(fd, FALSE); /* <username> \t "sync" */ str = t_str_new(256); str_append_tabescaped(str, user->username); str_append(str, "\tsync\n"); alarm(ruser->sync_secs); if (write_full(fd, str_data(str), str_len(str)) < 0) { i_error("write(%s) failed: %m", ruser->socket_path); ret = -1; } else { /* + | - */ ret = read(fd, buf, sizeof(buf)); if (ret < 0) { if (errno != EINTR) { i_error("read(%s) failed: %m", ruser->socket_path); } else { i_warning("replication(%s): Sync failure: " "Timeout in %u secs", user->username, ruser->sync_secs); } } else if (ret == 0) { i_error("read(%s) failed: EOF", ruser->socket_path); ret = -1; } else if (buf[0] == '+') { /* success */ ret = 0; } else if (buf[0] == '-') { /* failure */ if (buf[ret-1] == '\n') ret--; i_warning("replication(%s): Sync failure: %s", user->username, t_strndup(buf+1, ret-1)); ret = -1; } else { i_warning("replication(%s): " "Remote sent invalid input: %s", user->username, t_strndup(buf, ret)); } } alarm(0); if (close(fd) < 0) i_error("close(%s) failed: %m", ruser->socket_path); return ret; }
static int replication_fifo_notify(struct mail_user *user, enum replication_priority priority) { string_t *str; ssize_t ret; if (fifo_failed) return -1; if (fifo_fd == -1) { fifo_fd = open(fifo_path, O_WRONLY | O_NONBLOCK); if (fifo_fd == -1) { i_error("open(%s) failed: %m", fifo_path); fifo_failed = TRUE; return -1; } } /* <username> \t <priority> */ str = t_str_new(256); str_append_tabescaped(str, user->username); str_append_c(str, '\t'); switch (priority) { case REPLICATION_PRIORITY_NONE: case REPLICATION_PRIORITY_SYNC: i_unreached(); case REPLICATION_PRIORITY_LOW: str_append(str, "low"); break; case REPLICATION_PRIORITY_HIGH: str_append(str, "high"); break; } str_append_c(str, '\n'); ret = write(fifo_fd, str_data(str), str_len(str)); i_assert(ret != 0); if (ret != (ssize_t)str_len(str)) { if (ret > 0) i_error("write(%s) wrote partial data", fifo_path); else if (errno == EAGAIN) { /* busy, try again later */ return 0; } else if (errno != EPIPE) { i_error("write(%s) failed: %m", fifo_path); } else { /* server was probably restarted, don't bother logging this. */ } if (close(fifo_fd) < 0) i_error("close(%s) failed: %m", fifo_path); fifo_fd = -1; return -1; } return 1; }
void passdb_blocking_verify_plain(struct auth_request *request) { string_t *str; str = t_str_new(128); str_printfa(str, "PASSV\t%u\t", request->passdb->passdb->id); str_append_tabescaped(str, request->mech_password); str_append_c(str, '\t'); auth_request_export(request, str); auth_request_ref(request); auth_worker_call(request->pool, request->user, str_c(str), verify_plain_callback, request); }
static void user_callback(enum userdb_result result, struct auth_request *auth_request) { struct auth_master_connection *conn = auth_request->master; string_t *str; const char *value; if (auth_request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; if (result == USERDB_RESULT_OK) { if (user_verify_restricted_uid(auth_request) < 0) result = USERDB_RESULT_INTERNAL_FAILURE; } str = t_str_new(128); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", auth_request->id); if (auth_request->userdb_lookup_tempfailed) { value = auth_fields_find(auth_request->userdb_reply, "reason"); if (value != NULL) str_printfa(str, "\treason=%s", value); } break; case USERDB_RESULT_USER_UNKNOWN: str_printfa(str, "NOTFOUND\t%u", auth_request->id); break; case USERDB_RESULT_OK: str_printfa(str, "USER\t%u\t", auth_request->id); str_append_tabescaped(str, auth_request->user); str_append_c(str, '\t'); auth_fields_append(auth_request->userdb_reply, str, AUTH_FIELD_FLAG_HIDDEN, 0); break; } if (conn->auth->set->debug) { i_debug("userdb out: %s", auth_master_reply_hide_passwords(conn, str_c(str))); } str_append_c(str, '\n'); o_stream_nsend(conn->output, str_data(str), str_len(str)); auth_request_unref(&auth_request); auth_master_connection_unref(&conn); }
static void auth_request_handler_auth_fail(struct auth_request_handler *handler, struct auth_request *request, const char *reason) { string_t *str = t_str_new(128); auth_request_log_info(request, request->mech->mech_name, "%s", reason); str_printfa(str, "FAIL\t%u\treason=", request->id); str_append_tabescaped(str, reason); handler->callback(str_c(str), handler->context); auth_request_handler_remove(handler, request); }
void passdb_blocking_lookup_credentials(struct auth_request *request) { string_t *str; str = t_str_new(128); str_printfa(str, "PASSL\t%u\t", request->passdb->passdb->id); str_append_tabescaped(str, request->credentials_scheme); str_append_c(str, '\t'); auth_request_export(request, str); auth_request_ref(request); auth_worker_call(request->pool, request->user, str_c(str), lookup_credentials_callback, request); }
static void dsync_replicator_notify(struct dsync_cmd_context *ctx, enum dsync_brain_sync_type sync_type, const char *state_str) { #define REPLICATOR_HANDSHAKE "VERSION\treplicator-doveadm-client\t1\t0\n" const char *path; string_t *str; int fd; path = t_strdup_printf("%s/replicator-doveadm", ctx->ctx.cur_mail_user->set->base_dir); fd = net_connect_unix(path); if (fd == -1) { if (errno == ECONNREFUSED || errno == ENOENT) { /* replicator not running on this server. ignore. */ return; } i_error("net_connect_unix(%s) failed: %m", path); return; } str = t_str_new(128); str_append(str, REPLICATOR_HANDSHAKE"NOTIFY\t"); str_append_tabescaped(str, ctx->ctx.cur_mail_user->username); str_append_c(str, '\t'); if (sync_type == DSYNC_BRAIN_SYNC_TYPE_FULL) str_append_c(str, 'f'); str_append_c(str, '\t'); str_append_tabescaped(str, state_str); str_append_c(str, '\n'); if (write_full(fd, str_data(str), str_len(str)) < 0) i_error("write(%s) failed: %m", path); /* we only wanted to notify replicator. we don't care enough about the answer to wait for it. */ if (close(fd) < 0) i_error("close(%s) failed: %m", path); }
const char *str_tabescape(const char *str) { string_t *tmp; const char *p; for (p = str; *p != '\0'; p++) { if (*p <= '\r') { tmp = t_str_new(128); str_append_n(tmp, str, p-str); str_append_tabescaped(tmp, p); return str_c(tmp); } } return str; }
void passdb_blocking_set_credentials(struct auth_request *request, const char *new_credentials) { string_t *str; str = t_str_new(128); str_printfa(str, "SETCRED\t%u\t", request->passdb->passdb->id); str_append_tabescaped(str, new_credentials); str_append_c(str, '\t'); auth_request_export(request, str); auth_request_ref(request); auth_worker_call(request->pool, request->user, str_c(str), set_credentials_callback, request); }
static void pass_callback_finish(struct auth_request *auth_request, enum passdb_result result) { struct auth_master_connection *conn = auth_request->master; string_t *str; str = t_str_new(128); switch (result) { case PASSDB_RESULT_OK: if (auth_request->failed || !auth_request->passdb_success) { str_printfa(str, "FAIL\t%u", auth_request->id); break; } str_printfa(str, "PASS\t%u\tuser="******"NOTFOUND\t%u", auth_request->id); break; case PASSDB_RESULT_NEXT: case PASSDB_RESULT_PASSWORD_MISMATCH: case PASSDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", auth_request->id); break; case PASSDB_RESULT_SCHEME_NOT_AVAILABLE: str_printfa(str, "FAIL\t%u\treason=Configured passdbs don't support credentials lookups", auth_request->id); break; } if (conn->auth->set->debug) i_debug("passdb out: %s", str_c(str)); str_append_c(str, '\n'); o_stream_nsend(conn->output, str_data(str), str_len(str)); auth_request_unref(&auth_request); auth_master_connection_unref(&conn); }
static void imap_hibernate_write_cmd(struct client *client, string_t *cmd, const buffer_t *state, int fd_notify) { struct stat peer_st; str_append_tabescaped(cmd, client->user->username); str_append_c(cmd, '\t'); str_append_tabescaped(cmd, client->user->set->mail_log_prefix); str_printfa(cmd, "\tidle_notify_interval=%u", client->set->imap_idle_notify_interval); if (fstat(client->fd_in, &peer_st) == 0) { str_printfa(cmd, "\tpeer_dev_major=%lu\tpeer_dev_minor=%lu\tpeer_ino=%llu", (unsigned long)major(peer_st.st_dev), (unsigned long)minor(peer_st.st_dev), (unsigned long long)peer_st.st_ino); } if (client->session_id != NULL) { str_append(cmd, "\tsession="); str_append_tabescaped(cmd, client->session_id); } if (client->user->local_ip != NULL) str_printfa(cmd, "\tlip=%s", net_ip2addr(client->user->local_ip)); if (client->user->remote_ip != NULL) str_printfa(cmd, "\trip=%s", net_ip2addr(client->user->remote_ip)); if (client->userdb_fields != NULL) { string_t *userdb_fields = t_str_new(256); unsigned int i; for (i = 0; client->userdb_fields[i] != NULL; i++) { if (i > 0) str_append_c(userdb_fields, '\t'); str_append_tabescaped(userdb_fields, client->userdb_fields[i]); } str_append(cmd, "\tuserdb_fields="); str_append_tabescaped(cmd, str_c(userdb_fields)); } if (client->user->uid != (uid_t)-1) str_printfa(cmd, "\tuid=%s", dec2str(client->user->uid)); if (client->user->gid != (gid_t)-1) str_printfa(cmd, "\tgid=%s", dec2str(client->user->gid)); str_append(cmd, "\tstats="); str_append_tabescaped(cmd, client_stats(client)); if (client->command_queue != NULL && strcasecmp(client->command_queue->name, "IDLE") == 0) str_append(cmd, "\tidle-cmd"); if (fd_notify != -1) str_append(cmd, "\tnotify_fd"); str_append(cmd, "\tstate="); base64_encode(state->data, state->used, cmd); str_append_c(cmd, '\n'); }
static int client_export_iter_domain(struct client *client) { struct client_export_cmd *cmd = client->cmd_export; struct mail_domain *domain = client->mail_domain_iter; i_assert(cmd->level == MAIL_EXPORT_LEVEL_DOMAIN); mail_domain_unref(&client->mail_domain_iter); if (!cmd->header_sent) { o_stream_nsend_str(client->output, "domain\treset_timestamp\tlast_update" "\tnum_logins\tnum_cmds\tnum_connected_sessions"MAIL_STATS_HEADER); cmd->header_sent = TRUE; } for (; domain != NULL; domain = domain->stable_next) { if (client_is_busy(client)) break; if (!mail_export_filter_match_domain(&cmd->filter, domain)) continue; str_truncate(cmd->str, 0); str_append_tabescaped(cmd->str, domain->name); str_printfa(cmd->str, "\t%ld", (long)domain->reset_timestamp); client_export_timeval(cmd->str, &domain->last_update); str_printfa(cmd->str, "\t%u\t%u\t%u", domain->num_logins, domain->num_cmds, domain->num_connected_sessions); client_export_mail_stats(cmd->str, &domain->stats); str_append_c(cmd->str, '\n'); o_stream_nsend(client->output, str_data(cmd->str), str_len(cmd->str)); } if (domain != NULL) { client->mail_domain_iter = domain; mail_domain_ref(domain); return 0; } return 1; }
static int client_export_iter_user(struct client *client) { struct client_export_cmd *cmd = client->cmd_export; struct mail_user *user = client->mail_user_iter; i_assert(cmd->level == MAIL_EXPORT_LEVEL_USER); mail_user_unref(&client->mail_user_iter); if (!cmd->header_sent) { o_stream_nsend_str(client->output, "user\treset_timestamp\tlast_update" "\tnum_logins\tnum_cmds"MAIL_STATS_HEADER); cmd->header_sent = TRUE; } for (; user != NULL; user = user->stable_next) { if (client_is_busy(client)) break; if (!mail_export_filter_match_user(&cmd->filter, user)) continue; str_truncate(cmd->str, 0); str_append_tabescaped(cmd->str, user->name); str_printfa(cmd->str, "\t%ld", (long)user->reset_timestamp); client_export_timeval(cmd->str, &user->last_update); str_printfa(cmd->str, "\t%u\t%u", user->num_logins, user->num_cmds); client_export_mail_stats(cmd->str, &user->stats); str_append_c(cmd->str, '\n'); o_stream_nsend(client->output, str_data(cmd->str), str_len(cmd->str)); } if (user != NULL) { client->mail_user_iter = user; mail_user_ref(user); return 0; } return 1; }
static void script_execute_finish(void) { const char *keys_str, *username, *const *keys, *value; string_t *reply = t_str_new(512); ssize_t ret; keys_str = getenv(ENV_USERDB_KEYS); if (keys_str == NULL) i_fatal(ENV_USERDB_KEYS" environment missing"); username = getenv("USER"); if (username == NULL) i_fatal("USER environment missing"); str_append(reply, username); for (keys = t_strsplit_spaces(keys_str, " "); *keys != NULL; keys++) { value = getenv(t_str_ucase(*keys)); if (value != NULL) { str_append_c(reply, '\t'); str_append_tabescaped(reply, t_strconcat(t_str_lcase(*keys), "=", value, NULL)); } } str_append_c(reply, '\n'); /* finish by sending the fd to the mail process */ ret = fd_send(SCRIPT_COMM_FD, STDOUT_FILENO, str_data(reply), str_len(reply)); if (ret == (ssize_t)str_len(reply)) { /* success */ } else { if (ret < 0) i_error("fd_send() failed: %m"); else i_error("fd_send() sent partial output"); /* exit with 0 even though we failed. non-0 exit just makes master log an unnecessary error. */ } }
static void userdb_callback(enum userdb_result result, struct auth_request *request) { struct auth_request_handler *handler = request->handler; string_t *str; const char *value; i_assert(request->state == AUTH_REQUEST_STATE_USERDB); auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); if (request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; str = t_str_new(128); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", request->id); if (request->userdb_lookup_tempfailed) { value = auth_fields_find(request->userdb_reply, "reason"); if (value != NULL) auth_str_add_keyvalue(str, "reason", value); } break; case USERDB_RESULT_USER_UNKNOWN: str_printfa(str, "NOTFOUND\t%u", request->id); break; case USERDB_RESULT_OK: str_printfa(str, "USER\t%u\t", request->id); str_append_tabescaped(str, request->user); auth_str_append_userdb_extra_fields(request, str); break; } handler->master_callback(str_c(str), request->master); auth_master_connection_unref(&request->master); auth_request_unref(&request); auth_request_handler_unref(&handler); }
static void service_dup_fds(struct service *service) { struct service_listener *const *listeners; ARRAY_TYPE(dup2) dups; string_t *listener_settings; int fd = MASTER_LISTEN_FD_FIRST; unsigned int i, count, socket_listener_count; /* stdin/stdout is already redirected to /dev/null. Other master fds should have been opened with fd_close_on_exec() so we don't have to worry about them. because the destination fd might be another one's source fd we have to be careful not to overwrite anything. dup() the fd when needed */ socket_listener_count = 0; listeners = array_get(&service->listeners, &count); t_array_init(&dups, count + 10); switch (service->type) { case SERVICE_TYPE_LOG: i_assert(fd == MASTER_LISTEN_FD_FIRST); services_log_dup2(&dups, service->list, fd, &socket_listener_count); fd += socket_listener_count; break; case SERVICE_TYPE_ANVIL: dup2_append(&dups, service_anvil_global->log_fdpass_fd[0], MASTER_ANVIL_LOG_FDPASS_FD); /* nonblocking anvil fd must be the first one. anvil treats it as the master's fd */ dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++); dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++); socket_listener_count += 2; break; default: break; } /* add listeners */ listener_settings = t_str_new(256); for (i = 0; i < count; i++) { if (listeners[i]->fd != -1) { str_truncate(listener_settings, 0); str_append_tabescaped(listener_settings, listeners[i]->name); if (listeners[i]->type == SERVICE_LISTENER_INET) { if (listeners[i]->set.inetset.set->ssl) str_append(listener_settings, "\tssl"); if (listeners[i]->set.inetset.set->haproxy) str_append(listener_settings, "\thaproxy"); } dup2_append(&dups, listeners[i]->fd, fd++); env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s", socket_listener_count, str_c(listener_settings))); socket_listener_count++; } } if (service->login_notify_fd != -1) { dup2_append(&dups, service->login_notify_fd, MASTER_LOGIN_NOTIFY_FD); } switch (service->type) { case SERVICE_TYPE_LOG: case SERVICE_TYPE_ANVIL: case SERVICE_TYPE_CONFIG: dup2_append(&dups, null_fd, MASTER_ANVIL_FD); break; case SERVICE_TYPE_UNKNOWN: case SERVICE_TYPE_LOGIN: case SERVICE_TYPE_STARTUP: dup2_append(&dups, service_anvil_global->blocking_fd[1], MASTER_ANVIL_FD); break; } dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD); if (service->type != SERVICE_TYPE_ANVIL) { dup2_append(&dups, service->list->master_dead_pipe_fd[1], MASTER_DEAD_FD); } else { dup2_append(&dups, global_master_dead_pipe_fd[1], MASTER_DEAD_FD); } if (service->type == SERVICE_TYPE_LOG) { /* keep stderr as-is. this is especially important when log_path=/dev/stderr, but might be helpful even in other situations for logging startup errors */ } else { /* set log file to stderr. dup2() here immediately so that we can set up logging to it without causing any log messages to be lost. */ i_assert(service->log_fd[1] != -1); env_put("LOG_SERVICE=1"); if (dup2(service->log_fd[1], STDERR_FILENO) < 0) i_fatal("dup2(log fd) failed: %m"); i_set_failure_internal(); } /* make sure we don't leak syslog fd. try to do it as late as possible, but also before dup2()s in case syslog fd is one of them. */ closelog(); if (dup2_array(&dups) < 0) i_fatal("service(%s): dup2s failed", service->set->name); i_assert(fd == MASTER_LISTEN_FD_FIRST + (int)socket_listener_count); env_put(t_strdup_printf("SOCKET_COUNT=%d", socket_listener_count)); }
int subsfile_set_subscribed(struct mailbox_list *list, const char *path, const char *temp_prefix, const char *name, bool set) { const struct mail_storage_settings *mail_set = list->mail_set; struct dotlock_settings dotlock_set; struct dotlock *dotlock; struct mailbox_permissions perm; const char *line, *dir, *fname, *escaped_name; struct istream *input = NULL; struct ostream *output; int fd_in, fd_out; enum mailbox_list_path_type type; bool found, changed = FALSE, failed = FALSE; unsigned int version = 2; if (strcasecmp(name, "INBOX") == 0) name = "INBOX"; memset(&dotlock_set, 0, sizeof(dotlock_set)); dotlock_set.use_excl_lock = mail_set->dotlock_use_excl; dotlock_set.nfs_flush = mail_set->mail_nfs_storage; dotlock_set.temp_prefix = temp_prefix; dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT; dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT; mailbox_list_get_root_permissions(list, &perm); fd_out = file_dotlock_open_group(&dotlock_set, path, 0, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin, &dotlock); if (fd_out == -1 && errno == ENOENT) { /* directory hasn't been created yet. */ type = list->set.control_dir != NULL ? MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR; fname = strrchr(path, '/'); if (fname != NULL) { dir = t_strdup_until(path, fname); if (mailbox_list_mkdir_root(list, dir, type) < 0) return -1; } fd_out = file_dotlock_open_group(&dotlock_set, path, 0, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin, &dotlock); } if (fd_out == -1) { if (errno == EAGAIN) { mailbox_list_set_error(list, MAIL_ERROR_TEMP, "Timeout waiting for subscription file lock"); } else { subswrite_set_syscall_error(list, "file_dotlock_open()", path); } return -1; } fd_in = nfs_safe_open(path, O_RDONLY); if (fd_in == -1 && errno != ENOENT) { subswrite_set_syscall_error(list, "open()", path); file_dotlock_delete(&dotlock); return -1; } if (fd_in != -1) { input = i_stream_create_fd_autoclose(&fd_in, list->mailbox_name_max_length+1); i_stream_set_return_partial_line(input, TRUE); subsfile_list_read_header(list, input, &version); } found = FALSE; output = o_stream_create_fd_file(fd_out, 0, FALSE); o_stream_cork(output); if (version >= 2) o_stream_send_str(output, version2_header); if (version < 2 || name[0] == '\0') escaped_name = name; else { const char *const *tmp; char separators[2]; string_t *str = t_str_new(64); separators[0] = mailbox_list_get_hierarchy_sep(list); separators[1] = '\0'; tmp = t_strsplit(name, separators); str_append_tabescaped(str, *tmp); for (tmp++; *tmp != NULL; tmp++) { str_append_c(str, '\t'); str_append_tabescaped(str, *tmp); } escaped_name = str_c(str); } if (input != NULL) { while ((line = next_line(list, path, input, &failed, FALSE)) != NULL) { if (strcmp(line, escaped_name) == 0) { found = TRUE; if (!set) { changed = TRUE; continue; } } o_stream_nsend_str(output, line); o_stream_nsend(output, "\n", 1); } i_stream_destroy(&input); } if (!failed && set && !found) { /* append subscription */ line = t_strconcat(escaped_name, "\n", NULL); o_stream_nsend_str(output, line); changed = TRUE; } if (changed && !failed) { if (o_stream_nfinish(output) < 0) { subswrite_set_syscall_error(list, "write()", path); failed = TRUE; } else if (mail_set->parsed_fsync_mode != FSYNC_MODE_NEVER) { if (fsync(fd_out) < 0) { subswrite_set_syscall_error(list, "fsync()", path); failed = TRUE; } } } else { o_stream_ignore_last_errors(output); } o_stream_destroy(&output); if (failed || !changed) { if (file_dotlock_delete(&dotlock) < 0) { subswrite_set_syscall_error(list, "file_dotlock_delete()", path); failed = TRUE; } } else { enum dotlock_replace_flags flags = DOTLOCK_REPLACE_FLAG_VERIFY_OWNER; if (file_dotlock_replace(&dotlock, flags) < 0) { subswrite_set_syscall_error(list, "file_dotlock_replace()", path); failed = TRUE; } } return failed ? -1 : (changed ? 1 : 0); }