static int dbox_file_read_header(struct dbox_file *file) { const char *line; unsigned int hdr_size; int ret; i_stream_seek(file->input, 0); line = i_stream_read_next_line(file->input); if (line == NULL) { if (file->input->stream_errno == 0) { dbox_file_set_corrupted(file, "EOF while reading file header"); return 0; } dbox_file_set_syscall_error(file, "read()"); return -1; } hdr_size = file->input->v_offset; T_BEGIN { ret = dbox_file_parse_header(file, line) < 0 ? 0 : 1; } T_END; if (ret > 0) file->file_header_size = hdr_size; return ret; }
static void pop3c_client_prelogin_input(struct pop3c_client *client) { const char *line, *errstr; i_assert(client->state != POP3C_CLIENT_STATE_DONE); /* we need to read as much as we can with SSL streams to avoid hanging */ while ((line = i_stream_read_next_line(client->input)) != NULL) { if (pop3c_client_prelogin_input_line(client, line) < 0) { pop3c_client_disconnect(client); return; } } if (client->input->closed || client->input->eof || client->input->stream_errno != 0) { /* disconnected */ if (client->ssl_iostream == NULL) { i_error("pop3c(%s): Server disconnected unexpectedly", client->set.host); } else { errstr = ssl_iostream_get_last_error(client->ssl_iostream); if (errstr == NULL) { errstr = client->input->stream_errno == 0 ? "EOF" : strerror(client->input->stream_errno); } i_error("pop3c(%s): Server disconnected: %s", client->set.host, errstr); } pop3c_client_disconnect(client); } }
static int mdbox_file_metadata_copy(struct dbox_file *file, struct ostream *output) { struct dbox_metadata_header meta_hdr; const char *line; size_t buf_size; int ret; if ((ret = mdbox_file_read_metadata_hdr(file, &meta_hdr)) <= 0) return ret; o_stream_nsend(output, &meta_hdr, sizeof(meta_hdr)); buf_size = i_stream_get_max_buffer_size(file->input); /* use unlimited line length for metadata */ i_stream_set_max_buffer_size(file->input, (size_t)-1); while ((line = i_stream_read_next_line(file->input)) != NULL) { if (*line == '\0') { /* end of metadata */ break; } o_stream_nsend_str(output, line); o_stream_nsend(output, "\n", 1); } i_stream_set_max_buffer_size(file->input, buf_size); if (line == NULL) { dbox_file_set_corrupted(file, "missing end-of-metadata line"); return 0; } o_stream_nsend(output, "\n", 1); return 1; }
static void dump_msg_metadata(struct istream *input) { struct dbox_metadata_header hdr; const unsigned char *data; size_t size; const char *line; /* verify magic */ if (i_stream_read_bytes(input, &data, &size, sizeof(hdr)) <= 0) { i_fatal("dbox missing metadata at %"PRIuUOFF_T, input->v_offset); } memcpy(&hdr, data, sizeof(hdr)); if (memcmp(hdr.magic_post, DBOX_MAGIC_POST, sizeof(hdr.magic_post)) != 0) i_fatal("dbox wrong post-magic at %"PRIuUOFF_T, input->v_offset); i_stream_skip(input, sizeof(hdr)); /* dump the metadata */ for (;;) { if ((line = i_stream_read_next_line(input)) == NULL) i_fatal("dbox metadata ended unexpectedly at EOF"); if (*line == '\0') break; switch (*line) { case DBOX_METADATA_GUID: printf("msg.guid = %s\n", line + 1); break; case DBOX_METADATA_POP3_UIDL: printf("msg.pop3-uidl = %s\n", line + 1); break; case DBOX_METADATA_POP3_ORDER: printf("msg.pop3-order = %s\n", line + 1); break; case DBOX_METADATA_RECEIVED_TIME: dump_timestamp(input, "msg.received", line + 1); break; case DBOX_METADATA_PHYSICAL_SIZE: (void)dump_size(input, "msg.physical-size", line + 1); break; case DBOX_METADATA_VIRTUAL_SIZE: (void)dump_size(input, "msg.virtual-size", line + 1); break; case DBOX_METADATA_EXT_REF: printf("msg.ext-ref = %s\n", line + 1); break; case DBOX_METADATA_ORIG_MAILBOX: printf("msg.orig-mailbox = %s\n", line + 1); break; case DBOX_METADATA_OLDV1_EXPUNGED: case DBOX_METADATA_OLDV1_FLAGS: case DBOX_METADATA_OLDV1_KEYWORDS: case DBOX_METADATA_OLDV1_SAVE_TIME: case DBOX_METADATA_OLDV1_SPACE: printf("msg.obsolete-%c = %s\n", *line, line + 1); break; } } }
static int metadata_header_read(struct metawrap_istream *mstream) { char *line, *p; while ((line = i_stream_read_next_line(mstream->istream.parent)) != NULL) { if (*line == '\0') { mstream->callback(NULL, NULL, mstream->context); return 1; } p = strchr(line, ':'); if (p == NULL) { io_stream_set_error(&mstream->istream.iostream, "Metadata header line is missing ':'"); mstream->istream.istream.stream_errno = EINVAL; return -1; } *p++ = '\0'; mstream->callback(line, p, mstream->context); } if (mstream->istream.parent->eof) { mstream->istream.istream.stream_errno = mstream->istream.parent->stream_errno; mstream->istream.istream.eof = TRUE; return -1; } i_assert(!mstream->istream.parent->blocking); return 0; }
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 cmd_dump_imapzlib(int argc ATTR_UNUSED, char *argv[]) { struct istream *input, *input2; const unsigned char *data; size_t size; const char *line; int fd; fd = open(argv[1], O_RDONLY); if (fd < 0) i_fatal("open(%s) failed: %m", argv[1]); input = i_stream_create_fd(fd, 1024*32, TRUE); while ((line = i_stream_read_next_line(input)) != NULL) { /* skip tag */ printf("%s\r\n", line); while (*line != ' ' && *line != '\0') line++; if (*line == '\0') continue; line++; if (strcmp(line, "OK Begin compression.") == 0 || strcasecmp(line, "COMPRESS DEFLATE") == 0) break; } input2 = i_stream_create_deflate(input, TRUE); i_stream_unref(&input); while (i_stream_read_data(input2, &data, &size, 0) != -1) { fwrite(data, 1, size, stdout); i_stream_skip(input2, size); } i_stream_unref(&input2); fflush(stdout); }
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 void lmtp_client_input(struct lmtp_client *client) { const char *line; int ret; lmtp_client_ref(client); o_stream_cork(client->output); while ((line = i_stream_read_next_line(client->input)) != NULL) { T_BEGIN { ret = lmtp_client_input_line(client, line); } T_END; if (ret < 0) { o_stream_uncork(client->output); lmtp_client_unref(&client); return; } if (ret > 0) str_truncate(client->input_multiline, 0); } if (client->input->stream_errno == ENOBUFS) { lmtp_client_fail(client, "501 5.5.4 Command reply line too long"); } else if (client->input->stream_errno != 0) { errno = client->input->stream_errno; i_error("lmtp client: read() failed: %m"); lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE " (read failure)"); } else if (client->input->eof) { lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE " (disconnected in input)"); } o_stream_uncork(client->output); lmtp_client_unref(&client); }
static void penalty_lookup(struct penalty_context *ctx) { #define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n" #define ANVIL_CMD ANVIL_HANDSHAKE"PENALTY-DUMP\n" struct istream *input; const char *line; int fd; fd = doveadm_connect(ctx->anvil_path); net_set_nonblock(fd, FALSE); if (write(fd, ANVIL_CMD, strlen(ANVIL_CMD)) < 0) i_fatal("write(%s) failed: %m", ctx->anvil_path); input = i_stream_create_fd_autoclose(&fd, (size_t)-1); while ((line = i_stream_read_next_line(input)) != NULL) { if (*line == '\0') break; T_BEGIN { struct penalty_line penalty_line; penalty_parse_line(line, &penalty_line); penalty_print_line(ctx, &penalty_line); } T_END; } if (input->stream_errno != 0) i_fatal("read(%s) failed: %m", ctx->anvil_path); i_stream_destroy(&input); }
static void dbox_file_copy_metadata(struct dbox_file *file, struct ostream *output, bool *have_guid_r) { const char *line; uoff_t prev_offset = file->input->v_offset; *have_guid_r = FALSE; while ((line = i_stream_read_next_line(file->input)) != NULL) { if (*line == DBOX_METADATA_OLDV1_SPACE || *line == '\0') { /* end of metadata */ return; } if (*line < 32) { /* broken - possibly a new pre-magic block */ i_stream_seek(file->input, prev_offset); return; } if (*line == DBOX_METADATA_VIRTUAL_SIZE) { /* it may be wrong - recreate it */ continue; } if (*line == DBOX_METADATA_GUID) *have_guid_r = TRUE; o_stream_send_str(output, line); o_stream_send_str(output, "\n"); } }
int pop3c_sync_get_uidls(struct pop3c_mailbox *mbox) { ARRAY_TYPE(const_string) uidls; struct istream *input; const char *error, *cline; char *line, *p; unsigned int seq, line_seq; if (mbox->msg_uidls != NULL) return 0; if ((pop3c_client_get_capabilities(mbox->client) & POP3C_CAPABILITY_UIDL) == 0) { mail_storage_set_error(mbox->box.storage, MAIL_ERROR_NOTPOSSIBLE, "UIDLs not supported by server"); return -1; } if (pop3c_client_cmd_stream(mbox->client, "UIDL\r\n", &input, &error) < 0) { mail_storage_set_critical(mbox->box.storage, "UIDL failed: %s", error); return -1; } mbox->uidl_pool = pool_alloconly_create("POP3 UIDLs", 1024*32); p_array_init(&uidls, mbox->uidl_pool, 64); seq = 0; while ((line = i_stream_read_next_line(input)) != NULL) { seq++; p = strchr(line, ' '); if (p == NULL) { mail_storage_set_critical(mbox->box.storage, "Invalid UIDL line: %s", line); break; } *p++ = '\0'; if (str_to_uint(line, &line_seq) < 0 || line_seq != seq) { mail_storage_set_critical(mbox->box.storage, "Unexpected UIDL seq: %s != %u", line, seq); break; } cline = p_strdup(mbox->uidl_pool, p); array_append(&uidls, &cline, 1); } i_stream_destroy(&input); if (line != NULL) { pool_unref(&mbox->uidl_pool); return -1; } if (seq == 0) { /* make msg_uidls non-NULL */ array_append_zero(&uidls); } mbox->msg_uidls = array_idx(&uidls, 0); mbox->msg_count = seq; return 0; }
static void client_connection_input(struct client_connection *conn) { const char *line; bool ok = TRUE; int ret; if (!conn->handshaked) { if ((line = i_stream_read_next_line(conn->input)) == NULL) { if (conn->input->eof || conn->input->stream_errno != 0) client_connection_destroy(&conn); return; } if (!version_string_verify(line, "doveadm-server", DOVEADM_SERVER_PROTOCOL_VERSION_MAJOR)) { i_error("doveadm client not compatible with this server " "(mixed old and new binaries?)"); client_connection_destroy(&conn); return; } conn->handshaked = TRUE; } if (!conn->authenticated) { if ((ret = client_connection_authenticate(conn)) <= 0) { if (ret < 0) { o_stream_nsend(conn->output, "-\n", 2); client_connection_destroy(&conn); } return; } o_stream_nsend(conn->output, "+\n", 2); conn->authenticated = TRUE; } while (ok && (line = i_stream_read_next_line(conn->input)) != NULL) { T_BEGIN { char **args; args = p_strsplit(pool_datastack_create(), line, "\t"); ok = client_handle_command(conn, args); } T_END; } if (conn->input->eof || conn->input->stream_errno != 0 || !ok) client_connection_destroy(&conn); }
int pop3c_sync_get_sizes(struct pop3c_mailbox *mbox) { struct istream *input; const char *error; char *line, *p; unsigned int seq, line_seq; i_assert(mbox->msg_sizes == NULL); if (mbox->msg_uidls == NULL) { if (pop3c_sync_get_uidls(mbox) < 0) return -1; } if (mbox->msg_count == 0) { mbox->msg_sizes = i_new(uoff_t, 1); return 0; } if (pop3c_client_cmd_stream(mbox->client, "LIST\r\n", &input, &error) < 0) { mail_storage_set_critical(mbox->box.storage, "LIST failed: %s", error); return -1; } mbox->msg_sizes = i_new(uoff_t, mbox->msg_count); seq = 0; while ((line = i_stream_read_next_line(input)) != NULL) { if (++seq > mbox->msg_count) { mail_storage_set_critical(mbox->box.storage, "Too much data in LIST: %s", line); break; } p = strchr(line, ' '); if (p == NULL) { mail_storage_set_critical(mbox->box.storage, "Invalid LIST line: %s", line); break; } *p++ = '\0'; if (str_to_uint(line, &line_seq) < 0 || line_seq != seq) { mail_storage_set_critical(mbox->box.storage, "Unexpected LIST seq: %s != %u", line, seq); break; } if (str_to_uoff(p, &mbox->msg_sizes[seq-1]) < 0) { mail_storage_set_critical(mbox->box.storage, "Invalid LIST size: %s", p); break; } } i_stream_destroy(&input); if (line != NULL) { i_free_and_null(mbox->msg_sizes); return -1; } return 0; }
static const char * file_lock_find_proc_locks(int lock_fd ATTR_UNUSED) { /* do anything except Linux support this? don't bother trying it for OSes we don't know about. */ #ifdef __linux__ static bool have_proc_locks = TRUE; struct stat st; char node_buf[MAX_INT_STRLEN*3 + 2 + 1]; struct istream *input; const char *line, *lock_type = ""; pid_t pid = 0; int fd; if (!have_proc_locks) return FALSE; if (fstat(lock_fd, &st) < 0) return ""; i_snprintf(node_buf, sizeof(node_buf), "%02x:%02x:%llu", major(st.st_dev), minor(st.st_dev), (unsigned long long)st.st_ino); fd = open("/proc/locks", O_RDONLY); if (fd == -1) { have_proc_locks = FALSE; return ""; } input = i_stream_create_fd_autoclose(&fd, 512); while (pid == 0 && (line = i_stream_read_next_line(input)) != NULL) T_BEGIN { const char *const *args = t_strsplit_spaces(line, " "); /* number: FLOCK/POSIX ADVISORY READ/WRITE pid major:minor:inode region-start region-end */ if (str_array_length(args) < 8) continue; if (strcmp(args[5], node_buf) == 0) { lock_type = strcmp(args[3], "READ") == 0 ? "READ" : "WRITE"; if (str_to_pid(args[4], &pid) < 0) pid = 0; } } T_END; i_stream_destroy(&input); if (pid == 0) { /* not found */ return ""; } if (pid == getpid()) return " (BUG: lock is held by our own process)"; return t_strdup_printf(" (%s lock held by pid %ld)", lock_type, (long)pid); #else return ""; #endif }
static void cmd_director_status(int argc, char *argv[]) { struct director_context *ctx; const char *line, *const *args; ctx = cmd_director_init(argc, argv, "a:t:", cmd_director_status); if (argv[optind] != NULL) { cmd_director_status_user(ctx, argv+optind); return; } doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); doveadm_print_header_simple("mail server ip"); doveadm_print_header_simple("tag"); doveadm_print_header_simple("vhosts"); doveadm_print_header_simple("state"); doveadm_print_header("state-changed", "state changed", 0); doveadm_print_header_simple("users"); director_send(ctx, "HOST-LIST\n"); while ((line = i_stream_read_next_line(ctx->input)) != NULL) { if (*line == '\0') break; T_BEGIN { unsigned int arg_count; time_t ts; args = t_strsplit_tab(line); arg_count = str_array_length(args); if (arg_count >= 6) { /* ip vhosts users tag updown updown-ts */ doveadm_print(args[0]); doveadm_print(args[3]); doveadm_print(args[1]); doveadm_print(args[4][0] == 'D' ? "down" : "up"); if (str_to_time(args[5], &ts) < 0 || ts <= 0) doveadm_print("-"); else doveadm_print(unixdate2str(ts)); doveadm_print(args[2]); } } T_END; } if (line == NULL) { i_error("Director disconnected unexpectedly"); doveadm_exit_code = EX_TEMPFAIL; } director_disconnect(ctx); }
static int client_connection_authenticate(struct client_connection *conn) { const char *line, *pass; buffer_t *plain; const unsigned char *data; size_t size; if ((line = i_stream_read_next_line(conn->input)) == NULL) { if (conn->input->eof) return -1; return 0; } if (*conn->set->doveadm_password == '\0') { i_error("doveadm_password not set, " "remote authentication disabled"); return -1; } /* FIXME: some day we should probably let auth process do this and support all kinds of authentication */ if (strncmp(line, "PLAIN\t", 6) != 0) { i_error("doveadm client attempted non-PLAIN authentication"); return -1; } plain = buffer_create_dynamic(pool_datastack_create(), 128); if (base64_decode(line + 6, strlen(line + 6), NULL, plain) < 0) { i_error("doveadm client sent invalid base64 auth PLAIN data"); return -1; } data = plain->data; size = plain->used; if (size < 10 || data[0] != '\0' || memcmp(data+1, "doveadm", 7) != 0 || data[8] != '\0') { i_error("doveadm client didn't authenticate as 'doveadm'"); return -1; } pass = t_strndup(data + 9, size - 9); if (strcmp(pass, conn->set->doveadm_password) != 0) { i_error("doveadm client authenticated with wrong password"); return -1; } return 1; }
static void dns_client_input(struct dns_client *client) { const char *line; int ret = 0; o_stream_cork(client->output); while ((line = i_stream_read_next_line(client->input)) != NULL) { if (dns_client_input_line(client, line) < 0) { ret = -1; break; } } o_stream_uncork(client->output); if (client->input->eof || client->input->stream_errno != 0 || ret < 0) dns_client_destroy(&client); }
static void pop3c_client_input_reply(struct pop3c_client *client) { i_assert(client->state == POP3C_CLIENT_STATE_DONE); if (client->to != NULL) timeout_reset(client->to); client->input_line = i_stream_read_next_line(client->input); if (client->input_line != NULL) io_loop_stop(current_ioloop); else if (client->input->closed || client->input->eof || client->input->stream_errno != 0) { /* disconnected */ i_error("pop3c(%s): Server disconnected unexpectedly", client->set.host); pop3c_client_disconnect(client); io_loop_stop(current_ioloop); } }
static int fts_indexer_input(struct fts_indexer_context *ctx) { const char *line; int percentage; while ((line = i_stream_read_next_line(ctx->input)) != NULL) { /* initial reply: <tag> \t OK following: <tag> \t <percentage> */ if (strncmp(line, "1\t", 2) != 0) { i_error("indexer sent invalid reply: %s", line); return -1; } line += 2; if (strcmp(line, "OK") == 0) continue; if (str_to_int(line, &percentage) < 0 || percentage > 100) { i_error("indexer sent invalid percentage: %s", line); return -1; } if (percentage < 0) { /* indexing failed */ i_error("indexer failed to index mailbox %s", ctx->box->vname); return -1; } ctx->percentage = percentage; if (percentage == 100) { /* finished */ return 1; } } if (ctx->input->stream_errno != 0) { i_error("indexer read(%s) failed: %s", i_stream_get_name(ctx->input), i_stream_get_error(ctx->input)); return -1; } if (ctx->input->eof) { i_error("indexer disconnected unexpectedly"); return -1; } return 0; }
static unsigned int dump_file_hdr(struct istream *input) { const char *line, *const *arg, *version; unsigned int msg_hdr_size = 0; if ((line = i_stream_read_next_line(input)) == NULL) i_fatal("Empty file"); arg = t_strsplit(line, " "); /* check version */ version = *arg; if (version == NULL || !str_is_numeric(version, ' ')) i_fatal("%s is not a dbox file", i_stream_get_name(input)); if (strcmp(version, "2") != 0) i_fatal("Unsupported dbox file version %s", version); arg++; for (; *arg != NULL; arg++) { switch (**arg) { case DBOX_HEADER_MSG_HEADER_SIZE: msg_hdr_size = hex2dec((const void *)(*arg + 1), strlen(*arg + 1)); if (msg_hdr_size == 0) { i_fatal("Invalid msg_header_size header: %s", *arg + 1); } printf("file.msg_header_size = %u\n", msg_hdr_size); break; case DBOX_HEADER_CREATE_STAMP: dump_timestamp(input, "file.create_stamp", *arg + 1); break; default: printf("file.unknown-%c = %s\n", **arg, *arg + 1); break; } } if (msg_hdr_size == 0) i_fatal("Missing msg_header_size in file header"); return msg_hdr_size; }
static void lmtp_client_input(struct lmtp_client *client) { const char *line; lmtp_client_ref(client); while ((line = i_stream_read_next_line(client->input)) != NULL) { if (lmtp_client_input_line(client, line) < 0) { lmtp_client_unref(&client); return; } } if (client->input->stream_errno != 0) { errno = client->input->stream_errno; i_error("lmtp client: read() failed: %m"); lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE " (read failure)"); } else if (client->input->eof) { lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE " (disconnected in input)"); } lmtp_client_unref(&client); }
static int proxy_client_worker_read_line(struct proxy_client_dsync_worker *worker, const char **line_r) { if (worker->worker.failed) return -1; *line_r = i_stream_read_next_line(worker->input); if (*line_r == NULL) { if (worker->input->stream_errno != 0) { errno = worker->input->stream_errno; i_error("read() from worker server failed: %m"); dsync_worker_set_failure(&worker->worker); return -1; } if (worker->input->eof) { if (!worker->finished) i_error("read() from worker server failed: EOF"); dsync_worker_set_failure(&worker->worker); return -1; } } if (*line_r == NULL) return 0; if (!worker->handshake_received) { if (strcmp(*line_r, DSYNC_PROXY_SERVER_GREETING_LINE) != 0) { i_error("Invalid server handshake: %s", *line_r); dsync_worker_set_failure(&worker->worker); return -1; } worker->handshake_received = TRUE; return proxy_client_worker_read_line(worker, line_r); } return 1; }
static int acl_backend_vfile_acllist_read(struct acl_backend_vfile *backend) { struct acl_backend_vfile_acllist acllist; struct istream *input; struct stat st; const char *path, *line, *p; int fd, ret = 0; backend->acllist_last_check = ioloop_time; if (!acl_list_get_path(backend, &path)) { /* we're never going to build acllist for this namespace. */ acllist_clear(backend, 0); return 0; } if (backend->acllist_mtime != 0) { /* see if the file's mtime has changed */ if (stat(path, &st) < 0) { if (errno == ENOENT) backend->acllist_mtime = 0; else i_error("stat(%s) failed: %m", path); return -1; } if (st.st_mtime == backend->acllist_mtime) return 0; } fd = open(path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) { backend->acllist_mtime = 0; return -1; } i_error("open(%s) failed: %m", path); return -1; } if (fstat(fd, &st) < 0) { i_error("fstat(%s) failed: %m", path); i_close_fd(&fd); return -1; } backend->acllist_mtime = st.st_mtime; acllist_clear(backend, st.st_size); input = i_stream_create_fd(fd, (size_t)-1, FALSE); while ((line = i_stream_read_next_line(input)) != NULL) { acllist.mtime = 0; for (p = line; *p >= '0' && *p <= '9'; p++) acllist.mtime = acllist.mtime * 10 + (*p - '0'); if (p == line || *p != ' ' || p[1] == '\0') { i_error("Broken acllist file: %s", path); i_unlink_if_exists(path); i_close_fd(&fd); return -1; } acllist.name = p_strdup(backend->acllist_pool, p + 1); array_append(&backend->acllist, &acllist, 1); } if (input->stream_errno != 0) ret = -1; i_stream_destroy(&input); if (close(fd) < 0) i_error("close(%s) failed: %m", path); return ret; }
bool settings_read_i(const char *path, const char *section, settings_callback_t *callback, settings_section_callback_t *sect_callback, void *context, const char **error_r) { /* pretty horrible code, but v2.0 will have this rewritten anyway.. */ struct input_stack root, *input; const char *errormsg, *next_section, *name, *last_section_path = NULL; char *line, *key, *p, quote; string_t *full_line; size_t len; int fd, last_section_line = 0, skip, sections, root_section; fd = open(path, O_RDONLY); if (fd < 0) { *error_r = t_strdup_printf( "Can't open configuration file %s: %m", path); return FALSE; } if (section == NULL) { skip = 0; next_section = NULL; } else { skip = 1; next_section = t_strcut(section, '/'); } memset(&root, 0, sizeof(root)); root.path = path; input = &root; full_line = t_str_new(512); sections = 0; root_section = 0; errormsg = NULL; input->input = i_stream_create_fd_autoclose(&fd, (size_t)-1); i_stream_set_return_partial_line(input->input, TRUE); prevfile: while ((line = i_stream_read_next_line(input->input)) != NULL) { input->linenum++; /* @UNSAFE: line is modified */ /* skip whitespace */ while (IS_WHITE(*line)) line++; /* ignore comments or empty lines */ if (*line == '#' || *line == '\0') continue; /* strip away comments. pretty kludgy way really.. */ for (p = line; *p != '\0'; p++) { if (*p == '\'' || *p == '"') { quote = *p; for (p++; *p != quote && *p != '\0'; p++) { if (*p == '\\' && p[1] != '\0') p++; } if (*p == '\0') break; } else if (*p == '#') { if (!IS_WHITE(p[-1])) { i_warning("Configuration file %s line %u: " "Ambiguous '#' character in line, treating it as comment. " "Add a space before it to remove this warning.", input->path, input->linenum); } *p = '\0'; break; } } /* remove whitespace from end of line */ len = strlen(line); while (IS_WHITE(line[len-1])) len--; line[len] = '\0'; if (len > 0 && line[len-1] == '\\') { /* continues in next line */ len--; while (IS_WHITE(line[len-1])) len--; str_append_n(full_line, line, len); str_append_c(full_line, ' '); continue; } if (str_len(full_line) > 0) { str_append(full_line, line); line = str_c_modifiable(full_line); } /* a) key = value b) section_type [section_name] { c) } */ key = line; while (!IS_WHITE(*line) && *line != '\0' && *line != '=') line++; if (IS_WHITE(*line)) { *line++ = '\0'; while (IS_WHITE(*line)) line++; } if (strcmp(key, "!include_try") == 0 || strcmp(key, "!include") == 0) { if (settings_include(fix_relative_path(line, input), &input, strcmp(key, "!include_try") == 0, &errormsg) == 0) goto prevfile; } else if (*line == '=') { /* a) */ *line++ = '\0'; while (IS_WHITE(*line)) line++; len = strlen(line); if (len > 0 && ((*line == '"' && line[len-1] == '"') || (*line == '\'' && line[len-1] == '\''))) { line[len-1] = '\0'; line = str_unescape(line+1); } errormsg = skip ? NULL : callback(key, line, context); } else if (strcmp(key, "}") != 0 || *line != '\0') { /* b) + errors */ line[-1] = '\0'; if (*line == '{') name = ""; else { name = line; while (!IS_WHITE(*line) && *line != '\0') line++; if (*line != '\0') { *line++ = '\0'; while (IS_WHITE(*line)) line++; } } if (*line != '{') errormsg = "Expecting '='"; else { sections++; if (next_section != NULL && strcmp(next_section, name) == 0) { section += strlen(next_section); if (*section == '\0') { skip = 0; next_section = NULL; root_section = sections; } else { i_assert(*section == '/'); section++; next_section = t_strcut(section, '/'); } } if (skip > 0) skip++; else { skip = sect_callback == NULL ? 1 : !sect_callback(key, name, context, &errormsg); if (errormsg != NULL && last_section_line != 0) { errormsg = t_strdup_printf( SECTION_ERRORMSG, errormsg, last_section_path, last_section_line); } } last_section_path = input->path; last_section_line = input->linenum; } } else { /* c) */ if (sections == 0) errormsg = "Unexpected '}'"; else { if (skip > 0) skip--; else { i_assert(sect_callback != NULL); sect_callback(NULL, NULL, context, &errormsg); if (root_section == sections && errormsg == NULL) { /* we found the section, now quit */ break; } } last_section_path = input->path; last_section_line = input->linenum; sections--; } } if (errormsg != NULL) { *error_r = t_strdup_printf( "Error in configuration file %s line %d: %s", input->path, input->linenum, errormsg); break; } str_truncate(full_line, 0); } i_stream_destroy(&input->input); input = input->prev; if (line == NULL && input != NULL) goto prevfile; return errormsg == NULL; }
static int maildir_keywords_sync(struct maildir_keywords *mk) { struct istream *input; struct stat st; char *line, *p, *new_name; const char **strp; unsigned int idx; int fd; /* Remember that we rely on uidlist file locking in here. That's why we rely on stat()'s timestamp and don't bother handling ESTALE errors. */ if (mk->storage->set->mail_nfs_storage) { /* file is updated only by replacing it, no need to flush attribute cache */ nfs_flush_file_handle_cache(mk->path); } if (nfs_safe_stat(mk->path, &st) < 0) { if (errno == ENOENT) { maildir_keywords_clear(mk); mk->synced = TRUE; return 0; } mail_storage_set_critical(mk->storage, "stat(%s) failed: %m", mk->path); return -1; } if (st.st_mtime == mk->synced_mtime) { /* hasn't changed */ mk->synced = TRUE; return 0; } mk->synced_mtime = st.st_mtime; fd = open(mk->path, O_RDONLY); if (fd == -1) { if (errno == ENOENT) { maildir_keywords_clear(mk); mk->synced = TRUE; return 0; } mail_storage_set_critical(mk->storage, "open(%s) failed: %m", mk->path); return -1; } maildir_keywords_clear(mk); input = i_stream_create_fd(fd, 1024, FALSE); while ((line = i_stream_read_next_line(input)) != NULL) { p = strchr(line, ' '); if (p == NULL) { /* note that when converting .customflags file this case happens in the first line. */ continue; } *p++ = '\0'; if (str_to_uint(line, &idx) < 0 || idx >= MAILDIR_MAX_KEYWORDS || *p == '\0') { /* shouldn't happen */ continue; } /* save it */ new_name = p_strdup(mk->pool, p); hash_table_insert(mk->hash, new_name, POINTER_CAST(idx + 1)); strp = array_idx_modifiable(&mk->list, idx); *strp = new_name; } i_stream_destroy(&input); if (close(fd) < 0) { mail_storage_set_critical(mk->storage, "close(%s) failed: %m", mk->path); return -1; } mk->synced = TRUE; return 0; }
static int passwd_file_open(struct passwd_file *pw, bool startup, const char **error_r) { const char *no_args = NULL; struct istream *input; const char *line; struct stat st; time_t start_time, end_time; unsigned int time_secs; int fd; fd = open(pw->path, O_RDONLY); if (fd == -1) { if (errno == EACCES) *error_r = eacces_error_get("open", pw->path); else { *error_r = t_strdup_printf("open(%s) failed: %m", pw->path); } return -1; } if (fstat(fd, &st) != 0) { *error_r = t_strdup_printf("fstat(%s) failed: %m", pw->path); i_close_fd(&fd); return -1; } pw->fd = fd; pw->stamp = st.st_mtime; pw->size = st.st_size; pw->pool = pool_alloconly_create(MEMPOOL_GROWING"passwd_file", 10240); hash_table_create(&pw->users, pw->pool, 0, str_hash, strcmp); start_time = time(NULL); input = i_stream_create_fd(pw->fd, (size_t)-1, FALSE); i_stream_set_return_partial_line(input, TRUE); while ((line = i_stream_read_next_line(input)) != NULL) { if (*line == '\0' || *line == ':' || *line == '#') continue; /* no username or comment */ T_BEGIN { const char *const *args = t_strsplit(line, ":"); if (args[1] != NULL) { /* at least username+password */ passwd_file_add(pw, args[0], args[1], args+2); } else { /* only username */ passwd_file_add(pw, args[0], NULL, &no_args); } } T_END; } i_stream_destroy(&input); end_time = time(NULL); time_secs = end_time - start_time; if ((time_secs > PARSE_TIME_STARTUP_WARN_SECS && startup) || (time_secs > PARSE_TIME_RELOAD_WARN_SECS && !startup)) { i_warning("passwd-file %s: Reading %u users took %u secs", pw->path, hash_table_count(pw->users), time_secs); } else if (pw->db->debug) { i_debug("passwd-file %s: Read %u users in %u secs", pw->path, hash_table_count(pw->users), time_secs); } return 0; }
static void server_connection_input(struct server_connection *conn) { const unsigned char *data; size_t size; const char *line; int exit_code; if (!conn->handshaked) { if ((line = i_stream_read_next_line(conn->input)) == NULL) { if (conn->input->eof || conn->input->stream_errno != 0) { server_log_disconnect_error(conn); server_connection_destroy(&conn); } return; } conn->handshaked = TRUE; if (strcmp(line, "+") == 0) server_connection_authenticated(conn); else if (strcmp(line, "-") == 0) { if (server_connection_authenticate(conn) < 0) { server_connection_destroy(&conn); return; } return; } else { i_error("doveadm server sent invalid handshake: %s", line); server_connection_destroy(&conn); return; } } if (i_stream_read(conn->input) < 0) { /* disconnected */ server_log_disconnect_error(conn); server_connection_destroy(&conn); return; } if (!conn->authenticated) { if ((line = i_stream_next_line(conn->input)) == NULL) return; if (strcmp(line, "+") == 0) server_connection_authenticated(conn); else { i_error("doveadm authentication failed (%s)", line+1); server_connection_destroy(&conn); return; } } data = i_stream_get_data(conn->input, &size); if (size == 0) return; switch (conn->state) { case SERVER_REPLY_STATE_DONE: i_error("doveadm server sent unexpected input"); server_connection_destroy(&conn); return; case SERVER_REPLY_STATE_PRINT: server_handle_input(conn, data, size); if (conn->state != SERVER_REPLY_STATE_RET) break; /* fall through */ case SERVER_REPLY_STATE_RET: line = i_stream_next_line(conn->input); if (line == NULL) return; if (line[0] == '+') server_connection_callback(conn, 0, ""); else if (line[0] == '-') { line++; if (strcmp(line, "NOUSER") == 0) exit_code = EX_NOUSER; else if (str_to_int(line, &exit_code) < 0) { /* old doveadm-server */ exit_code = EX_TEMPFAIL; } server_connection_callback(conn, exit_code, line); } else { i_error("doveadm server sent broken input " "(expected cmd reply): %s", line); server_connection_destroy(&conn); break; } if (conn->callback == NULL) { /* we're finished, close the connection */ server_connection_destroy(&conn); } break; } }
static int acl_backend_vfile_read(struct acl_object *aclobj, bool global, const char *path, struct acl_vfile_validity *validity, bool try_retry, bool *is_dir_r) { struct istream *input; struct stat st; struct acl_rights rights; const char *line, *error; unsigned int linenum; int fd, ret = 0; *is_dir_r = FALSE; fd = nfs_safe_open(path, O_RDONLY); if (fd == -1) { if (errno == ENOENT || errno == ENOTDIR) { if (aclobj->backend->debug) i_debug("acl vfile: file %s not found", path); validity->last_mtime = ACL_VFILE_VALIDITY_MTIME_NOTFOUND; } else if (errno == EACCES) { if (aclobj->backend->debug) i_debug("acl vfile: no access to file %s", path); acl_object_remove_all_access(aclobj); validity->last_mtime = ACL_VFILE_VALIDITY_MTIME_NOACCESS; } else { i_error("open(%s) failed: %m", path); return -1; } validity->last_size = 0; validity->last_read_time = ioloop_time; return 1; } if (fstat(fd, &st) < 0) { if (errno == ESTALE && try_retry) { i_close_fd(&fd); return 0; } i_error("fstat(%s) failed: %m", path); i_close_fd(&fd); return -1; } if (S_ISDIR(st.st_mode)) { /* we opened a directory. */ *is_dir_r = TRUE; i_close_fd(&fd); return 0; } if (aclobj->backend->debug) i_debug("acl vfile: reading file %s", path); input = i_stream_create_fd(fd, (size_t)-1, FALSE); i_stream_set_return_partial_line(input, TRUE); linenum = 1; while ((line = i_stream_read_next_line(input)) != NULL) { T_BEGIN { ret = acl_rights_parse_line(line, aclobj->rights_pool, &rights, &error); rights.global = global; if (ret < 0) { i_error("ACL file %s line %u: %s", path, linenum, error); } else { array_append(&aclobj->rights, &rights, 1); } } T_END; if (ret < 0) break; linenum++; } if (ret < 0) { /* parsing failure */ } else if (input->stream_errno != 0) { if (input->stream_errno == ESTALE && try_retry) ret = 0; else { ret = -1; i_error("read(%s) failed: %m", path); } } else { if (fstat(fd, &st) < 0) { if (errno == ESTALE && try_retry) ret = 0; else { ret = -1; i_error("fstat(%s) failed: %m", path); } } else { ret = 1; validity->last_read_time = ioloop_time; validity->last_mtime = st.st_mtime; validity->last_size = st.st_size; } } i_stream_unref(&input); if (close(fd) < 0) { if (errno == ESTALE && try_retry) return 0; i_error("close(%s) failed: %m", path); return -1; } return ret; }