static int fts_filter_stopwords_read_list(struct fts_filter_stopwords *filter, const char **error_r) { struct istream *input; const char *line, **words, *path; int ret = 0; path = t_strdup_printf(STOPWORDS_FILE_FORMAT, filter->stopwords_dir, filter->lang->name); input = i_stream_create_file(path, IO_BLOCK_SIZE); while ((line = i_stream_read_next_line(input)) != NULL) T_BEGIN { line = t_strcut(line, STOPWORDS_COMMENT_CHAR1); line = t_strcut(line, STOPWORDS_COMMENT_CHAR2); words = t_strsplit_spaces(line, " \t"); for (; *words != NULL; words++) { const char *word = p_strdup(filter->pool, *words); hash_table_insert(filter->stopwords, word, word); } } T_END; if (input->stream_errno != 0) { *error_r = t_strdup_printf("Failed to read stopword list %s: %s", path, i_stream_get_error(input)); ret = -1; } i_stream_destroy(&input); return ret; }
static const struct var_expand_table * get_var_expand_table(struct master_service *service, struct mail_storage_service_user *user, const struct mail_storage_service_input *input, const struct mail_storage_service_privileges *priv) { static struct var_expand_table static_tab[] = { { 'u', NULL, "user" }, { 'n', NULL, "username" }, { 'd', NULL, "domain" }, { 's', NULL, "service" }, { 'l', NULL, "lip" }, { 'r', NULL, "rip" }, { 'p', NULL, "pid" }, { 'i', NULL, "uid" }, { '\0', NULL, "gid" }, { '\0', NULL, "session" }, { '\0', NULL, "auth_user" }, { '\0', NULL, "auth_username" }, { '\0', NULL, "auth_domain" }, { '\0', NULL, NULL } }; struct var_expand_table *tab; tab = t_malloc(sizeof(static_tab)); memcpy(tab, static_tab, sizeof(static_tab)); tab[0].value = input->username; tab[1].value = t_strcut(input->username, '@'); tab[2].value = strchr(input->username, '@'); if (tab[2].value != NULL) tab[2].value++; tab[3].value = service->name; tab[4].value = net_ip2addr(&input->local_ip); tab[5].value = net_ip2addr(&input->remote_ip); tab[6].value = my_pid; tab[7].value = priv == NULL ? NULL : dec2str(priv->uid == (uid_t)-1 ? geteuid() : priv->uid); tab[8].value = priv == NULL ? NULL : dec2str(priv->gid == (gid_t)-1 ? getegid() : priv->gid); tab[9].value = input->session_id; if (user == NULL || user->auth_user == NULL) { tab[10].value = tab[0].value; tab[11].value = tab[1].value; tab[12].value = tab[2].value; } else { tab[10].value = user->auth_user; tab[11].value = t_strcut(user->auth_user, '@'); tab[12].value = strchr(user->auth_user, '@'); } return tab; }
static void passwd_file_iterate_next(struct userdb_iterate_context *_ctx) { struct passwd_file_userdb_iterate_context *ctx = (struct passwd_file_userdb_iterate_context *)_ctx; const char *line, *p; if (ctx->input == NULL) line = NULL; else { while ((line = i_stream_read_next_line(ctx->input)) != NULL) { if (*line == '\0' || *line == ':' || *line == '#') continue; /* no username or comment */ if (ctx->skip_passdb_entries && ((p = strchr(line, ':')) == NULL || strchr(p+1, ':') == NULL)) { /* only passdb info */ continue; } break; } if (line == NULL && ctx->input->stream_errno != 0) { i_error("read(%s) failed: %m", ctx->path); _ctx->failed = TRUE; } } if (line == NULL) _ctx->callback(NULL, _ctx->context); else T_BEGIN { _ctx->callback(t_strcut(line, ':'), _ctx->context); } T_END; }
static void stats_metric_settings_to_query(const struct stats_metric_settings *set, struct event_filter_query *query_r) { i_zero(query_r); /* generate fields for event filter */ if (array_is_created(&set->filter)) { struct event_filter_field *filter_fields; const char *const *filters; unsigned int i, count; filters = array_get(&set->filter, &count); i_assert(count % 2 == 0); count /= 2; filter_fields = t_new(struct event_filter_field, count + 1); for (i = 0; i < count; i++) { filter_fields[i].key = filters[i*2]; filter_fields[i].value = filters[i*2+1]; } query_r->fields = filter_fields; } /* add query to the event filter */ query_r->categories = t_strsplit_spaces(set->categories, " "); query_r->name = set->event_name; query_r->source_filename = t_strcut(set->source_location, ':'); query_r->source_linenum = set->parsed_source_linenum; }
static const char *distro_get(void) { static const char *files[] = { "", "/etc/redhat-release", "", "/etc/SuSE-release", "", "/etc/mandriva-release", "", "/etc/fedora-release", "", "/etc/sourcemage-release", "", "/etc/slackware-version", "", "/etc/gentoo-release", "Debian ", "/etc/debian_version", NULL }; const char *name; unsigned int i; if (lsb_distro_get("/etc/lsb-release", &name)) return name; for (i = 0; files[i] != NULL; i += 2) { if (readfile(files[i+1], &name)) { return t_strconcat(files[i], t_strcut(name, '\n'), NULL); } } return ""; }
static bool maildir_expunge_is_valid_guid(struct maildir_index_sync_context *ctx, uint32_t uid, const char *filename, guid_128_t expunged_guid_128) { guid_128_t guid_128; const char *guid; if (guid_128_is_empty(expunged_guid_128)) { /* no GUID associated with expunge */ return TRUE; } T_BEGIN { guid = maildir_uidlist_lookup_ext(ctx->mbox->uidlist, uid, MAILDIR_UIDLIST_REC_EXT_GUID); if (guid == NULL) guid = t_strcut(filename, ':'); mail_generate_guid_128_hash(guid, guid_128); } T_END; if (memcmp(guid_128, expunged_guid_128, sizeof(guid_128)) == 0) return TRUE; mail_storage_set_critical(&ctx->mbox->storage->storage, "Mailbox %s: Expunged GUID mismatch for UID %u: %s vs %s", ctx->mbox->box.vname, ctx->uid, guid_128_to_string(guid_128), guid_128_to_string(expunged_guid_128)); return FALSE; }
static void client_send_login_reply(struct imap_client *client, string_t *str, const char *line) { const char *capability; bool tagged_capability; capability = client->proxy_backend_capability; tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0; if (tagged_capability) capability = t_strcut(line + 12, ']'); if (client->client_ignores_capability_resp_code && capability != NULL) { /* client has used CAPABILITY command, so it didn't understand the capabilities in the banner. send the backend's untagged CAPABILITY reply and hope that the client understands it */ str_printfa(str, "* CAPABILITY %s\r\n", capability); } str_append(str, client->cmd_tag); str_append(str, " OK "); if (!client->client_ignores_capability_resp_code && !tagged_capability && capability != NULL) { str_printfa(str, "[CAPABILITY %s] ", capability); if (*line == '[') { /* we need to send the capability. skip over this resp-code */ while (*line != ']' && *line != '\0') line++; if (*line == ' ') line++; } } str_append(str, line); str_append(str, "\r\n"); }
static int cmd_user_input(const char *auth_socket_path, const struct authtest_input *input, const char *show_field, bool userdb) { const char *lookup_name = userdb ? "userdb lookup" : "passdb lookup"; struct auth_master_connection *conn; pool_t pool; const char *username, *const *fields, *p; int ret; if (auth_socket_path == NULL) { auth_socket_path = t_strconcat(doveadm_settings->base_dir, "/auth-userdb", NULL); } pool = pool_alloconly_create("auth master lookup", 1024); conn = auth_master_init(auth_socket_path, 0); if (userdb) { ret = auth_master_user_lookup(conn, input->username, &input->info, pool, &username, &fields); } else { ret = auth_master_pass_lookup(conn, input->username, &input->info, pool, &fields); } if (ret < 0) { if (fields[0] == NULL) i_error("%s failed for %s", lookup_name, input->username); else { i_error("%s failed for %s: %s", lookup_name, input->username, fields[0]); } } else if (ret == 0) { fprintf(show_field == NULL ? stdout : stderr, "%s: user %s doesn't exist\n", lookup_name, input->username); } else if (show_field != NULL) { unsigned int show_field_len = strlen(show_field); for (; *fields; fields++) { if (strncmp(*fields, show_field, show_field_len) == 0 && (*fields)[show_field_len] == '=') printf("%s\n", *fields + show_field_len + 1); } } else { printf("%s: %s\n", userdb ? "userdb" : "passdb", input->username); for (; *fields; fields++) { p = strchr(*fields, '='); if (p == NULL) printf(" %-10s\n", *fields); else { printf(" %-10s: %s\n", t_strcut(*fields, '='), p + 1); } } } auth_master_deinit(&conn); return ret; }
static void login_host_callback(const struct ip_addr *ip, const char *errormsg, void *context) { struct login_host_request *request = context; struct director *dir = request->conn->dir; const char *line, *line_params; unsigned int secs; if (ip != NULL) { secs = dir->set->director_user_expire / 2; line = t_strdup_printf("%s\thost=%s\tproxy_refresh=%u", request->line, net_ip2addr(ip), secs); } else { if (strncmp(request->line, "OK\t", 3) == 0) line_params = request->line + 3; else if (strncmp(request->line, "PASS\t", 5) == 0) line_params = request->line + 5; else i_panic("BUG: Unexpected line: %s", request->line); i_error("director: User %s host lookup failed: %s", request->username, errormsg); line = t_strconcat("FAIL\t", t_strcut(line_params, '\t'), "\ttemp", NULL); } login_connection_send_line(request->conn, line); login_connection_unref(&request->conn); i_free(request->username); i_free(request->line); i_free(request); }
static int proxy_input_banner(struct imap_client *client, struct ostream *output, const char *line) { const char *const *capabilities = NULL; string_t *str; int ret; if (!str_begins(line, "* OK ")) { client_log_err(&client->common, t_strdup_printf( "proxy: Remote returned invalid banner: %s", str_sanitize(line, 160))); return -1; } str = t_str_new(128); if (str_begins(line + 5, "[CAPABILITY ")) { capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " "); if (str_array_icase_find(capabilities, "SASL-IR")) client->proxy_sasl_ir = TRUE; if (str_array_icase_find(capabilities, "LOGINDISABLED")) client->proxy_logindisabled = TRUE; i_free(client->proxy_backend_capability); client->proxy_backend_capability = i_strdup(t_strcut(line + 5 + 12, ']')); if (str_array_icase_find(capabilities, "ID") && !client->common.proxy_not_trusted) { client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_ID; proxy_write_id(client, str); if (client->common.proxy_nopipelining) { /* write login or starttls after I OK */ o_stream_nsend(output, str_data(str), str_len(str)); return 0; } } } if ((ret = proxy_write_starttls(client, str)) < 0) { return -1; } else if (ret == 0) { if (proxy_write_login(client, str) < 0) return -1; } o_stream_nsend(output, str_data(str), str_len(str)); return 0; }
static int proxy_input_banner(struct imap_client *client, struct ostream *output, const char *line) { enum login_proxy_ssl_flags ssl_flags; const char *const *capabilities = NULL; string_t *str; if (strncmp(line, "* OK ", 5) != 0) { client_log_err(&client->common, t_strdup_printf( "proxy: Remote returned invalid banner: %s", str_sanitize(line, 160))); return -1; } str = t_str_new(128); if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) { capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " "); if (str_array_icase_find(capabilities, "ID")) proxy_write_id(client, str); if (str_array_icase_find(capabilities, "SASL-IR")) client->proxy_sasl_ir = TRUE; if (str_array_icase_find(capabilities, "LOGINDISABLED")) client->proxy_logindisabled = TRUE; i_free(client->proxy_backend_capability); client->proxy_backend_capability = i_strdup(t_strcut(line + 5 + 12, ']')); } ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy); if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) { if (capabilities != NULL && !str_array_icase_find(capabilities, "STARTTLS")) { client_log_err(&client->common, "proxy: Remote doesn't support STARTTLS"); return -1; } str_append(str, "S STARTTLS\r\n"); } else { if (proxy_write_login(client, str) < 0) return -1; } o_stream_nsend(output, str_data(str), str_len(str)); return 0; }
static bool proxy_client_worker_next_msg_get(struct proxy_client_dsync_worker *worker, const struct proxy_client_request *request, const char *line) { enum dsync_msg_get_result result = DSYNC_MSG_GET_RESULT_FAILED; const char *p, *error; uint32_t uid; p_clear(worker->msg_get_pool); switch (line[0]) { case '1': /* ok */ if (line[1] != '\t') break; line += 2; if ((p = strchr(line, '\t')) == NULL) break; uid = strtoul(t_strcut(line, '\t'), NULL, 10); line = p + 1; if (uid != request->uid) { i_error("msg-get returned invalid uid: %u != %u", uid, request->uid); proxy_client_fail(worker); return FALSE; } if (dsync_proxy_msg_static_import(worker->msg_get_pool, line, &worker->msg_get_data, &error) < 0) { i_error("Invalid msg-get static input: %s", error); proxy_client_fail(worker); return FALSE; } worker->msg_get_data.input = i_stream_create_dot(worker->input, FALSE); i_stream_set_destroy_callback(worker->msg_get_data.input, proxy_client_worker_msg_get_done, worker); io_remove(&worker->io); result = DSYNC_MSG_GET_RESULT_SUCCESS; break; case '0': /* expunged */ result = DSYNC_MSG_GET_RESULT_EXPUNGED; break; default: /* failure */ break; } request->callback.get(result, &worker->msg_get_data, request->context); return worker->io != NULL && worker->msg_get_data.input == NULL; }
static void auth_server_connection_input(struct auth_server_connection *conn) { struct istream *input; const char *line, *error; int ret; switch (i_stream_read(conn->input)) { case 0: return; case -1: /* disconnected */ error = conn->input->stream_errno != 0 ? strerror(conn->input->stream_errno) : "EOF"; auth_server_connection_reconnect(conn, error); return; case -2: /* buffer full - can't happen unless auth is buggy */ i_error("BUG: Auth server sent us more than %d bytes of data", AUTH_SERVER_CONN_MAX_LINE_LENGTH); auth_server_connection_disconnect(conn, "buffer full"); return; } if (!conn->version_received) { line = i_stream_next_line(conn->input); if (line == NULL) return; /* make sure the major version matches */ if (strncmp(line, "VERSION\t", 8) != 0 || !str_uint_equals(t_strcut(line + 8, '\t'), AUTH_CLIENT_PROTOCOL_MAJOR_VERSION)) { i_error("Authentication server not compatible with " "this client (mixed old and new binaries?)"); auth_server_connection_disconnect(conn, "incompatible server"); return; } conn->version_received = TRUE; } input = conn->input; i_stream_ref(input); while ((line = i_stream_next_line(input)) != NULL && !input->closed) { T_BEGIN { ret = auth_server_connection_input_line(conn, line); } T_END; if (ret < 0) { auth_server_connection_disconnect(conn, t_strdup_printf( "Received broken input: %s", line)); break; } } i_stream_unref(&input); }
static int cmd_user_input(struct auth_master_connection *conn, const struct authtest_input *input, const char *show_field, bool userdb) { const char *lookup_name = userdb ? "userdb lookup" : "passdb lookup"; pool_t pool; const char *updated_username = NULL, *const *fields, *p; int ret; pool = pool_alloconly_create("auth master lookup", 1024); if (userdb) { ret = auth_master_user_lookup(conn, input->username, &input->info, pool, &updated_username, &fields); } else { ret = auth_master_pass_lookup(conn, input->username, &input->info, pool, &fields); } if (ret < 0) { if (fields[0] == NULL) i_error("%s failed for %s", lookup_name, input->username); else { i_error("%s failed for %s: %s", lookup_name, input->username, fields[0]); } ret = -1; } else if (ret == 0) { fprintf(show_field == NULL ? stdout : stderr, "%s: user %s doesn't exist\n", lookup_name, input->username); } else if (show_field != NULL) { unsigned int show_field_len = strlen(show_field); for (; *fields; fields++) { if (strncmp(*fields, show_field, show_field_len) == 0 && (*fields)[show_field_len] == '=') printf("%s\n", *fields + show_field_len + 1); } } else { printf("%s: %s\n", userdb ? "userdb" : "passdb", input->username); if (updated_username != NULL) printf(" %-10s: %s\n", "user", updated_username); for (; *fields; fields++) { p = strchr(*fields, '='); if (p == NULL) printf(" %-10s\n", *fields); else { printf(" %-10s: %s\n", t_strcut(*fields, '='), p + 1); } } } return ret; }
bool password_scheme_is_alias(const char *scheme1, const char *scheme2) { const struct password_scheme *s1 = NULL, *s2 = NULL; if (*scheme1 == '\0' || *scheme2 == '\0') return FALSE; scheme1 = t_strcut(scheme1, '.'); scheme2 = t_strcut(scheme2, '.'); if (strcasecmp(scheme1, scheme2) == 0) return TRUE; s1 = hash_table_lookup(password_schemes, scheme1); s2 = hash_table_lookup(password_schemes, scheme2); /* if they've the same generate function, they're equivalent */ return s1 != NULL && s2 != NULL && s1->password_generate == s2->password_generate; }
static int pop3c_mail_get_stream(struct mail *_mail, bool get_body, struct message_size *hdr_size, struct message_size *body_size, struct istream **stream_r) { struct index_mail *mail = (struct index_mail *)_mail; struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box; enum pop3c_capability capa; const char *name, *cmd, *error; struct istream *input; if (get_body && mail->data.stream != NULL) { name = i_stream_get_name(mail->data.stream); if (strncmp(name, "RETR", 4) == 0) { /* we've fetched the body */ } else if (strncmp(name, "TOP", 3) == 0) { /* we've fetched the header, but we need the body now too */ index_mail_close_streams(mail); } else { i_panic("Unexpected POP3 stream name: %s", name); } } if (mail->data.stream == NULL) { capa = pop3c_client_get_capabilities(mbox->client); if (get_body || (capa & POP3C_CAPABILITY_TOP) == 0) { cmd = t_strdup_printf("RETR %u\r\n", _mail->seq); get_body = TRUE; } else { cmd = t_strdup_printf("TOP %u 0\r\n", _mail->seq); } if (pop3c_client_cmd_stream(mbox->client, cmd, &input, &error) < 0) { mail_storage_set_error(mbox->box.storage, !pop3c_client_is_connected(mbox->client) ? MAIL_ERROR_TEMP : MAIL_ERROR_EXPUNGED, error); return -1; } mail->data.stream = input; if (mail->mail.v.istream_opened != NULL) { if (mail->mail.v.istream_opened(_mail, &mail->data.stream) < 0) { index_mail_close_streams(mail); return -1; } } i_stream_set_name(mail->data.stream, t_strcut(cmd, '\r')); if (get_body) pop3c_mail_cache_size(mail); } return index_mail_init_stream(mail, hdr_size, body_size, stream_r); }
static void get_var_expand_users(struct var_expand_table *tab, const char *user) { unsigned int i; tab[0].value = user; tab[1].value = t_strcut(user, '@'); tab[2].value = strchr(user, '@'); if (tab[2].value != NULL) tab[2].value++; for (i = 0; i < 3; i++) tab[i].value = str_sanitize(tab[i].value, 80); }
static void env_put_extra_fields(const char *extra_fields) { const char *const *tmp; const char *key, *p; for (tmp = t_strsplit(extra_fields, "\t"); *tmp != NULL; tmp++) { key = t_str_ucase(t_strcut(*tmp, '=')); p = strchr(*tmp, '='); if (p == NULL) env_put(t_strconcat(key, "=1", NULL)); else env_put(t_strconcat(key, p, NULL)); } }
static const char *filesystem_get(const char *mail_location) { struct mountpoint mp; const char *path; path = strchr(mail_location, ':'); if (path == NULL) path = mail_location; else path = t_strcut(path + 1, ':'); if (*path == '~') { /* we don't know where users' home dirs are */ return ""; } path = t_strcut(path, '%'); if (strlen(path) <= 1) return ""; /* all in all it seems we can support only /<path>/%u style location */ if (mountpoint_get(path, pool_datastack_create(), &mp) < 0) return ""; return mp.type == NULL ? "" : mp.type; }
const char *mail_storage_service_fields_var_expand(const char *data, const char *const *fields) { const char *field_name = t_strcut(data, ':'); unsigned int i, field_name_len; if (fields == NULL) return field_get_default(data); field_name_len = strlen(field_name); for (i = 0; fields[i] != NULL; i++) { if (strncmp(fields[i], field_name, field_name_len) == 0 && fields[i][field_name_len] == '=') return fields[i] + field_name_len+1; } return field_get_default(data); }
struct acl_backend * acl_backend_init(const char *data, struct mailbox_list *list, const char *acl_username, const char *const *groups, bool owner) { struct mail_user *user = mailbox_list_get_user(list); struct acl_backend *backend; unsigned int i, group_count; if (user->mail_debug) { i_debug("acl: initializing backend with data: %s", data); i_debug("acl: acl username = %s", acl_username); i_debug("acl: owner = %d", owner ? 1 : 0); } group_count = str_array_length(groups); if (strncmp(data, "vfile:", 6) == 0) data += 6; else if (strcmp(data, "vfile") == 0) data = ""; else i_fatal("Unknown ACL backend: %s", t_strcut(data, ':')); backend = acl_backend_vfile.alloc(); backend->debug = user->mail_debug; backend->v = acl_backend_vfile; backend->list = list; backend->username = p_strdup(backend->pool, acl_username); backend->owner = owner; backend->globals_only = mail_user_plugin_getenv_bool(user, "acl_globals_only"); if (group_count > 0) { backend->group_count = group_count; backend->groups = p_new(backend->pool, const char *, group_count); for (i = 0; i < group_count; i++) { backend->groups[i] = p_strdup(backend->pool, groups[i]); if (user->mail_debug) i_debug("acl: group added: %s", groups[i]); } i_qsort(backend->groups, group_count, sizeof(const char *), i_strcmp_p); }
static void login_host_callback(const struct ip_addr *ip, const char *hostname, const char *errormsg, void *context) { struct login_host_request *request = context; struct director *dir = request->conn->dir; const char *line, *line_params; unsigned int secs; if (ip == NULL) { if (strncmp(request->line, "OK\t", 3) == 0) line_params = request->line + 3; else if (strncmp(request->line, "PASS\t", 5) == 0) line_params = request->line + 5; else i_panic("BUG: Unexpected line: %s", request->line); i_error("director: User %s host lookup failed: %s", request->username, errormsg); line = t_strconcat("FAIL\t", t_strcut(line_params, '\t'), "\ttemp", NULL); } else if (request->director_proxy_maybe && login_host_request_is_self(request, ip)) { line = request->line; } else { string_t *str = t_str_new(64); secs = dir->set->director_user_expire / 2; str_printfa(str, "%s\tproxy_refresh=%u\t", request->line, secs); if (hostname == NULL || hostname[0] == '\0') str_printfa(str, "host=%s", net_ip2addr(ip)); else { str_printfa(str, "host=%s\thostip=%s", hostname, net_ip2addr(ip)); } line = str_c(str); } login_connection_send_line(request->conn, line); login_connection_unref(&request->conn); i_free(request->username); i_free(request->line); i_free(request); }
static void auth_worker_send_reply(struct auth_worker_client *client, struct auth_request *request, string_t *str) { time_t cmd_duration = time(NULL) - client->cmd_start; const char *p; if (worker_restart_request) o_stream_nsend_str(client->output, "RESTART\n"); o_stream_nsend(client->output, str_data(str), str_len(str)); if (o_stream_nfinish(client->output) < 0 && request != NULL && cmd_duration > AUTH_WORKER_WARN_DISCONNECTED_LONG_CMD_SECS) { p = strchr(str_c(str), '\t'); p = p == NULL ? "BUG" : t_strcut(p+1, '\t'); i_warning("Auth master disconnected us while handling " "request for %s for %ld secs (result=%s)", request->user, (long)cmd_duration, p); } }
static int master_service_apply_config_overrides(struct master_service *service, struct setting_parser_context *parser, const char **error_r) { const char *const *overrides; unsigned int i, count; overrides = array_get(&service->config_overrides, &count); for (i = 0; i < count; i++) { if (settings_parse_line(parser, overrides[i]) < 0) { *error_r = t_strdup_printf( "Invalid -o parameter %s: %s", overrides[i], settings_parser_get_error(parser)); return -1; } settings_parse_set_key_expandeded(parser, service->set_pool, t_strcut(overrides[i], '=')); } return 0; }
static void proxy_write_id(struct imap_client *client, string_t *str) { i_assert(client->common.proxy_ttl > 1); str_append(str, "I ID ("); if (client->common.client_id != NULL && str_len(client->common.client_id) > 0) { str_append_str(str, client->common.client_id); str_append_c(str, ' '); } str_printfa(str, "\"x-session-id\" \"%s\" " "\"x-originating-ip\" \"%s\" " "\"x-originating-port\" \"%u\" " "\"x-connected-ip\" \"%s\" " "\"x-connected-port\" \"%u\" " "\"x-proxy-ttl\" \"%u\"", client_get_session_id(&client->common), net_ip2addr(&client->common.ip), client->common.remote_port, net_ip2addr(&client->common.local_ip), client->common.local_port, client->common.proxy_ttl - 1); /* append any forward_ variables to request */ for(const char *const *ptr = client->common.auth_passdb_args; *ptr != NULL; ptr++) { if (strncasecmp(*ptr, "forward_", 8) == 0) { const char *key = t_strconcat("x-forward-", t_strcut((*ptr)+8, '='), NULL); const char *val = i_strchr_to_next(*ptr, '='); str_append_c(str, ' '); imap_append_string(str, key); str_append_c(str, ' '); imap_append_nstring(str, val); } } str_append(str, ")\r\n"); }
static bool lsb_distro_get(const char *path, const char **name_r) { const char *data, *const *p, *str, *end; if (!readfile(path, &data)) return FALSE; for (p = t_strsplit(data, "\n"); *p != NULL; p++) { if (strncmp(*p, "DISTRIB_DESCRIPTION=", 20) == 0) break; } if (*p == NULL) return FALSE; str = t_strcut(*p + 20, '\n'); if (*str != '"') *name_r = str; else { end = strrchr(++str, '"'); *name_r = str_unescape(p_strdup_until(unsafe_data_stack_pool, str, end)); } return TRUE; }
static bool client_exec_script(struct master_service_connection *conn) { ARRAY_TYPE(const_string) envs; const char *const *args; string_t *input; void *buf; size_t prev_size, scanpos; bool header_complete = FALSE, noreply = FALSE; ssize_t ret; int status; pid_t pid; net_set_nonblock(conn->fd, FALSE); input = t_buffer_create(IO_BLOCK_SIZE); /* Input contains: VERSION .. <lf> [alarm=<secs> <lf>] "noreply" | "-" (or anything really) <lf> arg 1 <lf> arg 2 <lf> ... <lf> DATA This is quite a horrible protocol. If alarm is specified, it MUST be before "noreply". If "noreply" isn't given, something other string (typically "-") must be given which is eaten away. */ alarm(SCRIPT_READ_TIMEOUT_SECS); scanpos = 1; while (!header_complete) { const unsigned char *pos, *end; prev_size = input->used; buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE); /* peek in socket input buffer */ ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK); if (ret <= 0) { buffer_set_used_size(input, prev_size); if (strchr(str_c(input), '\n') != NULL) script_verify_version(t_strcut(str_c(input), '\n')); if (ret < 0) i_fatal("recv(MSG_PEEK) failed: %m"); i_fatal("recv(MSG_PEEK) failed: disconnected"); } /* scan for final \n\n */ pos = CONST_PTR_OFFSET(input->data, scanpos); end = CONST_PTR_OFFSET(input->data, prev_size + ret); for (; pos < end; pos++) { if (pos[-1] == '\n' && pos[0] == '\n') { header_complete = TRUE; pos++; break; } } scanpos = pos - (const unsigned char *)input->data; /* read data for real (up to and including \n\n) */ ret = recv(conn->fd, buf, scanpos-prev_size, 0); if (prev_size+ret != scanpos) { if (ret < 0) i_fatal("recv() failed: %m"); if (ret == 0) i_fatal("recv() failed: disconnected"); i_fatal("recv() failed: size of definitive recv() differs from peek"); } buffer_set_used_size(input, scanpos); } alarm(0); /* drop the last two LFs */ buffer_set_used_size(input, scanpos-2); args = t_strsplit(str_c(input), "\n"); script_verify_version(*args); args++; t_array_init(&envs, 16); if (*args != NULL) { const char *p; if (str_begins(*args, "alarm=")) { unsigned int seconds; if (str_to_uint(*args + 6, &seconds) < 0) i_fatal("invalid alarm option"); alarm(seconds); args++; } while (str_begins(*args, "env_")) { const char *envname, *env; env = t_str_tabunescape(*args+4); p = strchr(env, '='); if (p == NULL) i_fatal("invalid environment variable"); envname = t_strdup_until(*args+4, p); if (str_array_find(accepted_envs, envname)) array_append(&envs, &env, 1); args++; } if (strcmp(*args, "noreply") == 0) { noreply = TRUE; } if (**args == '\0') i_fatal("empty options"); args++; } array_append_zero(&envs); if (noreply) { /* no need to fork and check exit status */ exec_child(conn, args, array_idx(&envs, 0)); i_unreached(); } if ((pid = fork()) == (pid_t)-1) { i_error("fork() failed: %m"); return FALSE; } if (pid == 0) { /* child */ exec_child(conn, args, array_idx(&envs, 0)); i_unreached(); } /* parent */ /* check script exit status */ if (waitpid(pid, &status, 0) < 0) { i_error("waitpid() failed: %m"); return FALSE; } else if (WIFEXITED(status)) { ret = WEXITSTATUS(status); if (ret != 0) { i_error("Script terminated abnormally, exit status %d", (int)ret); return FALSE; } } else if (WIFSIGNALED(status)) { i_error("Script terminated abnormally, signal %d", WTERMSIG(status)); return FALSE; } else if (WIFSTOPPED(status)) { i_fatal("Script stopped, signal %d", WSTOPSIG(status)); return FALSE; } else { i_fatal("Script terminated abnormally, return status %d", status); return FALSE; } return TRUE; }
static void master_login_auth_input(struct master_login_auth *auth) { const char *line; bool ret; switch (i_stream_read(auth->input)) { case 0: return; case -1: /* disconnected. stop accepting new connections, because in default configuration we no longer have permissions to connect back to auth-master */ master_service_stop_new_connections(master_service); master_login_auth_disconnect(auth); return; case -2: /* buffer full */ i_error("Auth server sent us too long line"); master_login_auth_disconnect(auth); return; } if (!auth->version_received) { line = i_stream_next_line(auth->input); if (line == NULL) return; /* make sure the major version matches */ if (strncmp(line, "VERSION\t", 8) != 0 || !str_uint_equals(t_strcut(line + 8, '\t'), AUTH_MASTER_PROTOCOL_MAJOR_VERSION)) { i_error("Authentication server not compatible with " "master process (mixed old and new binaries?)"); master_login_auth_disconnect(auth); return; } auth->version_received = TRUE; } if (!auth->spid_received) { line = i_stream_next_line(auth->input); if (line == NULL) return; if (strncmp(line, "SPID\t", 5) != 0 || str_to_pid(line + 5, &auth->auth_server_pid) < 0) { i_error("Authentication server didn't " "send valid SPID as expected: %s", line); master_login_auth_disconnect(auth); return; } auth->spid_received = TRUE; master_login_auth_check_spids(auth); } auth->refcount++; while ((line = i_stream_next_line(auth->input)) != NULL) { if (strncmp(line, "USER\t", 5) == 0) ret = master_login_auth_input_user(auth, line + 5); else if (strncmp(line, "NOTFOUND\t", 9) == 0) ret = master_login_auth_input_notfound(auth, line + 9); else if (strncmp(line, "FAIL\t", 5) == 0) ret = master_login_auth_input_fail(auth, line + 5); else ret = TRUE; if (!ret || auth->input == NULL) { master_login_auth_disconnect(auth); break; } } master_login_auth_unref(&auth); }
static void auth_input_line(const char *line, void *context) { struct login_connection *conn = context; struct login_host_request *request, temp_request; const char *const *args, *line_params, *username = NULL, *tag = ""; bool proxy = FALSE, host = FALSE; if (line == NULL) { /* auth connection died -> kill also this login connection */ login_connection_deinit(&conn); return; } if (conn->type != LOGIN_CONNECTION_TYPE_USERDB && strncmp(line, "OK\t", 3) == 0) line_params = line + 3; else if (conn->type == LOGIN_CONNECTION_TYPE_USERDB && strncmp(line, "PASS\t", 5) == 0) line_params = line + 5; else { login_connection_send_line(conn, line); return; } /* OK <id> [<parameters>] */ args = t_strsplit_tab(line_params); if (*args != NULL) { /* we should always get here, but in case we don't just forward as-is and let login process handle the error. */ args++; } memset(&temp_request, 0, sizeof(temp_request)); for (; *args != NULL; args++) { if (strncmp(*args, "proxy", 5) == 0 && ((*args)[5] == '=' || (*args)[5] == '\0')) proxy = TRUE; else if (strncmp(*args, "host=", 5) == 0) host = TRUE; else if (strncmp(*args, "lip=", 4) == 0) { if (net_addr2ip((*args) + 4, &temp_request.local_ip) < 0) i_error("auth sent invalid lip field: %s", (*args) + 6); } else if (strncmp(*args, "lport=", 6) == 0) { if (str_to_uint((*args) + 6, &temp_request.local_port) < 0) i_error("auth sent invalid lport field: %s", (*args) + 6); } else if (strncmp(*args, "port=", 5) == 0) { if (str_to_uint((*args) + 5, &temp_request.dest_port) < 0) i_error("auth sent invalid port field: %s", (*args) + 6); } else if (strncmp(*args, "destuser="******"director_tag=", 13) == 0) tag = *args + 13; else if (strncmp(*args, "director_proxy_maybe", 20) == 0 && ((*args)[20] == '=' || (*args)[20] == '\0')) temp_request.director_proxy_maybe = TRUE; else if (strncmp(*args, "user=", 5) == 0) { if (username == NULL) username = *args + 5; } } if ((!proxy && !temp_request.director_proxy_maybe) || host || username == NULL) { login_connection_send_line(conn, line); return; } if (*conn->dir->set->master_user_separator != '\0') { /* with master user logins we still want to use only the login username */ username = t_strcut(username, *conn->dir->set->master_user_separator); } /* we need to add the host. the lookup might be asynchronous */ request = i_new(struct login_host_request, 1); *request = temp_request; request->conn = conn; request->line = i_strdup(line); request->username = i_strdup(username); conn->refcount++; director_request(conn->dir, username, tag, login_host_callback, request); }
static int set_line(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, const char *line) { struct setting_parser_context *set_parser = user->set_parser; bool mail_debug; const char *key, *orig_key, *append_value = NULL; unsigned int len; int ret; mail_debug = mail_user_set_get_mail_debug(user->user_info, user->user_set); if (strchr(line, '=') == NULL) line = t_strconcat(line, "=yes", NULL); orig_key = key = t_strcut(line, '='); len = strlen(key); if (len > 0 && key[len-1] == '+') { /* key+=value */ append_value = line + len + 1; key = t_strndup(key, len-1); } if (!settings_parse_is_valid_key(set_parser, key)) { /* assume it's a plugin setting */ key = t_strconcat("plugin/", key, NULL); line = t_strconcat("plugin/", line, NULL); } if (master_service_set_has_config_override(ctx->service, key)) { /* this setting was already overridden with -o parameter */ if (mail_debug) { i_debug("Ignoring overridden (-o) userdb setting: %s", key); } return 1; } if (append_value != NULL) { const void *value; enum setting_type type; value = settings_parse_get_value(set_parser, key, &type); if (type == SET_STR) { const char *const *strp = value; line = t_strdup_printf("%s=%s%s", key, *strp, append_value); } else { i_error("Ignoring %s userdb setting. " "'+' can only be used for strings.", orig_key); } } ret = settings_parse_line(set_parser, line); if (mail_debug && ret >= 0) { if (strstr(key, "pass") != NULL) { /* possibly a password field (e.g. imapc_password). hide the value. */ line = t_strconcat(key, "=<hidden>", NULL); } i_debug(ret == 0 ? "Unknown userdb setting: %s" : "Added userdb setting: %s", line); } return ret; }