From 6f0cf81a03a04e1454d0421d6bc7db1104adafe5 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Wed, 11 Aug 2010 18:20:41 +0200 Subject: [PATCH] Improved and simplified file error handling - Administrators now get properly notified about uncompiled global scripts and the inability of the sieve plugin to store global binaries. - Improved binary load/save error handling and fixed a few smal bugs. - Simplified ManageSieve error handling. --- TODO | 10 +- src/lib-sieve-tool/sieve-tool.c | 5 +- src/lib-sieve/plugins/include/cmd-include.c | 6 +- .../plugins/include/ext-include-common.c | 4 +- src/lib-sieve/sieve-binary-file.c | 279 +++++++++++------- src/lib-sieve/sieve-binary-private.h | 3 +- src/lib-sieve/sieve-binary.c | 31 +- src/lib-sieve/sieve-binary.h | 18 +- src/lib-sieve/sieve-common.h | 6 +- src/lib-sieve/sieve-lexer.c | 7 +- src/lib-sieve/sieve-lexer.h | 3 +- src/lib-sieve/sieve-parser.c | 5 +- src/lib-sieve/sieve-parser.h | 3 +- src/lib-sieve/sieve-script-private.h | 2 +- src/lib-sieve/sieve-script.c | 129 ++++---- src/lib-sieve/sieve-script.h | 7 +- src/lib-sieve/sieve-types.h | 29 ++ src/lib-sieve/sieve.c | 156 ++++++---- src/lib-sieve/sieve.h | 55 ++-- src/lib-sievestorage/Makefile.am | 1 - src/lib-sievestorage/sieve-storage-error.h | 32 -- src/lib-sievestorage/sieve-storage-list.c | 20 +- src/lib-sievestorage/sieve-storage-private.h | 6 +- src/lib-sievestorage/sieve-storage-quota.c | 6 +- src/lib-sievestorage/sieve-storage-save.c | 36 ++- src/lib-sievestorage/sieve-storage-script.c | 147 +++++---- src/lib-sievestorage/sieve-storage-script.h | 10 +- src/lib-sievestorage/sieve-storage.c | 31 +- src/lib-sievestorage/sieve-storage.h | 5 +- src/managesieve/cmd-deletescript.c | 10 +- src/managesieve/cmd-getscript.c | 53 ++-- src/managesieve/cmd-putscript.c | 2 +- src/managesieve/cmd-renamescript.c | 10 +- src/managesieve/cmd-setactive.c | 12 +- src/managesieve/managesieve-client.c | 20 +- src/plugins/lda-sieve/lda-sieve-plugin.c | 178 ++++++----- src/sieve-tools/sieve-test.c | 4 +- src/sieve-tools/sievec.c | 4 +- src/sieve-tools/sieved.c | 2 +- src/testsuite/testsuite-binary.c | 6 +- src/testsuite/testsuite-script.c | 4 +- src/testsuite/testsuite.c | 2 +- 42 files changed, 746 insertions(+), 613 deletions(-) delete mode 100644 src/lib-sievestorage/sieve-storage-error.h diff --git a/TODO b/TODO index 0b54d5b21..b99887f61 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,8 @@ Current activities: +* Improve error handling and logging + - Avoid reporting user-caused errors to the master log. + - Review logging and error handling; add more warning/info/debug messages where useful. * Cleanup the test suite - Make uniform command implementations - Cleanup test scripts @@ -7,13 +10,6 @@ Current activities: Next (in order of descending priority/precedence): * Update man pages to match style of Dovecot man pages. -* Improve error handling and logging - - Detect permission errors when writing global script binaries and advise the - administrator on using sievec to precompile the scripts. - - Avoid reporting user-caused errors to the master log. - - Review logging and error handling; add more warning/info/debug messages where useful. - - Improve logging of script execution (particularly what is currently executed; - a promptly compiled script or the stored binary). * Update include extension to latest draft: - Implement required ManageSieve behavior * Unfinished new extensions: diff --git a/src/lib-sieve-tool/sieve-tool.c b/src/lib-sieve-tool/sieve-tool.c index a1a0cb0bf..746c1a3f4 100644 --- a/src/lib-sieve-tool/sieve-tool.c +++ b/src/lib-sieve-tool/sieve-tool.c @@ -516,11 +516,11 @@ struct sieve_binary *sieve_tool_script_compile ehandler = sieve_stderr_ehandler_create(0); sieve_error_handler_accept_infolog(ehandler, TRUE); - if ( (sbin = sieve_compile(svinst, filename, name, ehandler)) == NULL ) + if ( (sbin = sieve_compile(svinst, filename, name, ehandler, NULL)) == NULL ) i_error("failed to compile sieve script '%s'", filename); sieve_error_handler_unref(&ehandler); - + return sbin; } @@ -540,6 +540,7 @@ struct sieve_binary *sieve_tool_script_open sieve_error_handler_unref(&ehandler); + sieve_save(sbin, NULL, FALSE, NULL); return sbin; } diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c index c36f31e5b..dd915b44c 100644 --- a/src/lib-sieve/plugins/include/cmd-include.c +++ b/src/lib-sieve/plugins/include/cmd-include.c @@ -202,7 +202,7 @@ static bool cmd_include_validate (struct cmd_include_context_data *) cmd->data; struct sieve_script *script; const char *script_path, *script_name; - bool exists = TRUE; + enum sieve_error error = TRUE; /* Check argument */ if ( !sieve_validate_positional_argument @@ -247,10 +247,10 @@ static bool cmd_include_validate /* Create script object */ script = sieve_script_create_in_directory (this_ext->svinst, script_path, script_name, - sieve_validator_error_handler(valdtr), &exists); + sieve_validator_error_handler(valdtr), &error); if ( script == NULL ) { - if ( !exists ) { + if ( error == SIEVE_ERROR_NOT_FOUND ) { sieve_argument_validate_error(valdtr, arg, "included %s script '%s' does not exist", ext_include_script_location_name(ctx_data->location), diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index 336685a2c..a1bcf839c 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -456,7 +456,7 @@ bool ext_include_generate_include (binctx, script, location, inc_block); /* Parse */ - if ( (ast = sieve_parse(script, ehandler)) == NULL ) { + if ( (ast = sieve_parse(script, ehandler, NULL)) == NULL ) { sieve_command_generate_error(gentr, cmd, "failed to parse included script '%s'", str_sanitize(script_name, 80)); return FALSE; @@ -466,7 +466,7 @@ bool ext_include_generate_include (void)ext_include_create_ast_context(this_ext, ast, cmd->ast_node->ast); /* Validate */ - if ( !sieve_validate(ast, ehandler) ) { + if ( !sieve_validate(ast, ehandler, NULL) ) { sieve_command_generate_error(gentr, cmd, "failed to validate included script '%s'", str_sanitize(script_name, 80)); diff --git a/src/lib-sieve/sieve-binary-file.c b/src/lib-sieve/sieve-binary-file.c index 47ab4c955..4e59058f8 100644 --- a/src/lib-sieve/sieve-binary-file.c +++ b/src/lib-sieve/sieve-binary-file.c @@ -66,9 +66,13 @@ struct sieve_binary_block_header { static inline bool _save_skip(struct ostream *stream, size_t size) { - if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) + if ( (o_stream_seek(stream, stream->offset + size)) <= 0 ) { + sieve_sys_error("binary save: failed to skip output stream " + "to position %"PRIuUOFF_T": %s", stream->offset + size, + strerror(stream->stream_errno)); return FALSE; - + } + return TRUE; } @@ -77,8 +81,12 @@ static inline bool _save_skip_aligned { uoff_t aligned_offset = SIEVE_BINARY_ALIGN(stream->offset); - if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) + if ( (o_stream_seek(stream, aligned_offset + size)) <= 0 ) { + sieve_sys_error("binary save: failed to skip output stream " + "to position %"PRIuUOFF_T": %s", aligned_offset + size, + strerror(stream->stream_errno)); return FALSE; + } if ( offset != NULL ) *offset = aligned_offset; @@ -95,8 +103,11 @@ static bool _save_full(struct ostream *stream, const void *data, size_t size) while ( bytes_left > 0 ) { ssize_t ret; - if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) + if ( (ret=o_stream_send(stream, pdata, bytes_left)) <= 0 ) { + sieve_sys_error("binary save: failed to write %"PRIuSIZE_T" bytes " + "to output stream: %s", bytes_left, strerror(stream->stream_errno)); return FALSE; + } pdata = PTR_OFFSET(pdata, ret); bytes_left -= ret; @@ -169,8 +180,7 @@ static bool _save_block_index_record header.offset = block->offset; if ( !_save_full(stream, &header, sizeof(header)) ) { - sieve_sys_error("failed to save block index header %d: %m", id); - + sieve_sys_error("binary save: failed to save block index header %d", id); return FALSE; } @@ -206,7 +216,7 @@ static bool _sieve_binary_save header.blocks = blk_count; if ( !_save_aligned(stream, &header, sizeof(header), NULL) ) { - sieve_sys_error("failed to save binary header: %m"); + sieve_sys_error("binary save: failed to save header"); return FALSE; } @@ -251,69 +261,100 @@ static bool _sieve_binary_save return TRUE; } -bool sieve_binary_save -(struct sieve_binary *sbin, const char *path) +int sieve_binary_save +(struct sieve_binary *sbin, const char *path, bool update, + enum sieve_error *error_r) { - bool result = TRUE; + int result, fd; string_t *temp_path; struct ostream *stream; - int fd; mode_t save_mode = sbin->script == NULL ? 0600 : sieve_script_permissions(sbin->script); + + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NONE; /* Use default path if none is specified */ if ( path == NULL ) { if ( sbin->script == NULL ) { - sieve_sys_error("cannot determine default binary save path " + sieve_sys_error("binary save: cannot determine default path " "with missing script object"); - return FALSE; + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_POSSIBLE; + return -1; } path = sieve_script_binpath(sbin->script); } + /* Check whether saving is necessary */ + if ( !update && sbin->path != NULL && strcmp(sbin->path, path) == 0 ) { + if ( sbin->svinst->debug ) { + sieve_sys_debug("binary save: not saving binary %s, " + "because it is already stored", path); + } + return 0; + } + /* Open it as temp file first, as not to overwrite an existing just yet */ temp_path = t_str_new(256); str_append(temp_path, path); + str_append_c(temp_path, '.'); fd = safe_mkstemp_hostpid(temp_path, save_mode, (uid_t)-1, (gid_t)-1); if ( fd < 0 ) { if ( errno == EACCES ) { - sieve_sys_error("failed to save binary temporary file: %s", + sieve_sys_error("binary save: failed to create temporary file: %s", eacces_error_get_creating("open", str_c(temp_path))); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NO_PERM; } else { - sieve_sys_error("failed to save binary temporary file: " + sieve_sys_error("binary save: failed to create temporary file: " "open(%s) failed: %m", str_c(temp_path)); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; } - return FALSE; + return -1; } /* Save binary */ + result = 1; stream = o_stream_create_fd(fd, 0, FALSE); - result = _sieve_binary_save(sbin, stream); + if ( !_sieve_binary_save(sbin, stream) ) { + result = -1; + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; + } o_stream_destroy(&stream); /* Close saved binary */ if ( close(fd) < 0 ) { - sieve_sys_error("failed to close saved binary temporary file: " + sieve_sys_error("binary save: failed to close temporary file: " "close(fd=%s) failed: %m", str_c(temp_path)); } /* Replace any original binary atomically */ if ( result && (rename(str_c(temp_path), path) < 0) ) { if ( errno == EACCES ) { - sieve_sys_error("failed to replace existing binary: %s", - eacces_error_get_creating("rename", path)); + sieve_sys_error("binary save: failed to save binary: %s", + eacces_error_get_creating("rename", path)); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NO_PERM; } else { - sieve_sys_error("failed to replace existing binary: " + sieve_sys_error("binary save: failed to save binary: " "rename(%s, %s) failed: %m", str_c(temp_path), path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; } - result = FALSE; + result = -1; } - if ( !result ) { + if ( result < 0 ) { /* Get rid of temp output (if any) */ - (void) unlink(str_c(temp_path)); + if ( unlink(str_c(temp_path)) < 0 && errno != ENOENT ) { + sieve_sys_error("binary save: failed to clean up after error: " + "unlink(%s) failed: %m", str_c(temp_path)); + } } else { - if ( sbin->path == NULL || strcmp(sbin->path, path) != 0 ) { + if ( sbin->path == NULL ) { sbin->path = p_strdup(sbin->pool, path); } } @@ -326,37 +367,57 @@ bool sieve_binary_save */ bool sieve_binary_file_open - (struct sieve_binary_file *file, const char *path) +(struct sieve_binary_file *file, const char *path, enum sieve_error *error_r) { int fd; + bool result = TRUE; struct stat st; + + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NONE; if ( (fd=open(path, O_RDONLY)) < 0 ) { - if ( errno != ENOENT ) { - if ( errno == EACCES ) { - sieve_sys_error("failed to open binary: %s", - eacces_error_get("open", path)); - } else { - sieve_sys_error("failed to open binary: " - "open(%s) failed: %m", path); - } + switch ( errno ) { + case ENOENT: + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_FOUND; + break; + case EACCES: + sieve_sys_error("binary open: failed to open: %s", + eacces_error_get("open", path)); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NO_PERM; + break; + default: + sieve_sys_error("binary open: failed to open: " + "open(%s) failed: %m", path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; + break; } return FALSE; } if ( fstat(fd, &st) < 0 ) { if ( errno != ENOENT ) { - sieve_sys_error("failed to open binary: " - "fstat(fd=%s) failed: %m", path); + sieve_sys_error("binary open: fstat(fd=%s) failed: %m", path); } - return FALSE; + result = FALSE; } - if ( !S_ISREG(st.st_mode) ) { - sieve_sys_error("binary %s is not a regular file", path); - return FALSE; + if ( result && !S_ISREG(st.st_mode) ) { + sieve_sys_error("binary open: %s is not a regular file", path); + result = FALSE; } + if ( !result ) { + if ( close(fd) < 0 ) { + sieve_sys_error("binary open: close(fd=%s) failed after error: %m", + path); + } + return FALSE; + } + file->fd = fd; file->st = st; @@ -367,7 +428,7 @@ void sieve_binary_file_close(struct sieve_binary_file **file) { if ( (*file)->fd != -1 ) { if ( close((*file)->fd) < 0 ) { - sieve_sys_error("failed to close opened binary: " + sieve_sys_error("binary close: failed to close: " "close(fd=%s) failed: %m", (*file)->path); } } @@ -505,7 +566,8 @@ static bool _file_lazy_read /* Seek to the correct position */ if ( *offset != file->offset && lseek(file->fd, *offset, SEEK_SET) == (off_t) -1 ) { - sieve_sys_error("failed to seek(fd, %lld, SEEK_SET) in binary %s: %m", + sieve_sys_error("binary read:" + "failed to seek(fd, %lld, SEEK_SET) in binary %s: %m", (long long) *offset, file->path); return FALSE; } @@ -514,10 +576,12 @@ static bool _file_lazy_read while (insize > 0) { if ( (ret=read(file->fd, indata, insize)) <= 0 ) { if ( ret == 0 ) - sieve_sys_error("binary %s is truncated (more data expected)", + sieve_sys_error( + "binary read: binary %s is truncated (more data expected)", file->path); else - sieve_sys_error("failed to read from binary %s: %m", file->path); + sieve_sys_error( + "binary read: failed to read from binary %s: %m", file->path); break; } @@ -561,7 +625,8 @@ static buffer_t *_file_lazy_load_buffer return NULL; } -static struct sieve_binary_file *_file_lazy_open(const char *path) +static struct sieve_binary_file *_file_lazy_open +(const char *path, enum sieve_error *error_r) { pool_t pool; struct sieve_binary_file *file; @@ -573,7 +638,7 @@ static struct sieve_binary_file *_file_lazy_open(const char *path) file->load_data = _file_lazy_load_data; file->load_buffer = _file_lazy_load_buffer; - if ( !sieve_binary_file_open(file, path) ) { + if ( !sieve_binary_file_open(file, path, error_r) ) { pool_unref(&pool); return NULL; } @@ -598,20 +663,24 @@ bool sieve_binary_load_block LOAD_HEADER(sbin, &offset, const struct sieve_binary_block_header); if ( header == NULL ) { - sieve_sys_error - ("block %d of loaded binary %s is truncated", id, sbin->path); + sieve_sys_error( + "binary load: binary %s is corrupt: " + "failed to read header of block %d", sbin->path, id); return FALSE; } if ( header->id != id ) { - sieve_sys_error("block %d of loaded binary %s has unexpected id %d", id, - sbin->path, header->id); + sieve_sys_error( + "binary load: binary %s is corrupt: " + "header of block %d has non-matching id %d", + sbin->path, id, header->id); return FALSE; } sblock->data = sbin->file->load_buffer(sbin->file, &offset, header->size); if ( sblock->data == NULL ) { - sieve_sys_error("block %d of loaded binary %s has invalid size %d", + sieve_sys_error( + "binary load: failed to read block %d of binary %s (size=%d)", id, sbin->path, header->size); return FALSE; } @@ -619,7 +688,7 @@ bool sieve_binary_load_block return TRUE; } -static bool _load_block_index_record +static bool _read_block_index_record (struct sieve_binary *sbin, off_t *offset, unsigned int id) { const struct sieve_binary_block_index *record = @@ -627,14 +696,16 @@ static bool _load_block_index_record struct sieve_binary_block *block; if ( record == NULL ) { - sieve_sys_error("failed to read index record for block %d in binary %s", - id, sbin->path); + sieve_sys_error( + "binary open: binary %s is corrupt: " + "failed to load block index record %d", sbin->path, id); return FALSE; } if ( record->id != id ) { - sieve_sys_error("block index record %d of loaded binary %s " - "has unexpected id %d", id, sbin->path, record->id); + sieve_sys_error( + "binary open: binary %s is corrupt: " + "block index record %d has unexpected id %d", sbin->path, id, record->id); return FALSE; } @@ -645,7 +716,7 @@ static bool _load_block_index_record return TRUE; } -static bool _sieve_binary_load_extensions(struct sieve_binary_block *sblock) +static bool _read_extensions(struct sieve_binary_block *sblock) { struct sieve_binary *sbin = sblock->sbin; sieve_size_t offset = 0; @@ -664,7 +735,8 @@ static bool _sieve_binary_load_extensions(struct sieve_binary_block *sblock) ext = sieve_extension_get_by_name(sbin->svinst, str_c(extension)); if ( ext == NULL ) { - sieve_sys_error("loaded binary %s requires unknown extension '%s'", + sieve_sys_error( + "binary open: binary %s requires unknown extension '%s'", sbin->path, str_sanitize(str_c(extension), 128)); result = FALSE; } else { @@ -694,28 +766,48 @@ static bool _sieve_binary_open(struct sieve_binary *sbin) T_BEGIN { header = LOAD_HEADER(sbin, &offset, const struct sieve_binary_header); + /* Check header presence */ if ( header == NULL ) { - sieve_sys_error("opened binary %s is not even large enough " - "to contain a header.", sbin->path); + sieve_sys_error("binary_open: file %s is not large enough " + "to contain the header.", sbin->path); result = FALSE; + /* Check header validity */ } else if ( header->magic != SIEVE_BINARY_MAGIC ) { if ( header->magic != SIEVE_BINARY_MAGIC_OTHER_ENDIAN ) - sieve_sys_error("opened binary %s has corrupted header (0x%08x)", - sbin->path, header->magic); + sieve_sys_error("binary_open: binary %s has corrupted header " + "(0x%08x) or it is not a Sieve binary", sbin->path, header->magic); + else if ( sbin->svinst->debug ) + sieve_sys_debug("binary open: binary %s stored " + "with in different endian format " + "(automatically fixed when re-compiled)", + sbin->path); result = FALSE; + /* Check binary version */ } else if ( result && ( header->version_major != SIEVE_BINARY_VERSION_MAJOR || header->version_minor != SIEVE_BINARY_VERSION_MINOR ) ) { /* Binary is of different version. Caller will have to recompile */ + + if ( sbin->svinst->debug ) { + sieve_sys_debug("binary open: binary %s stored " + "with different binary version %d.%d " + "(!= %d.%d; automatically fixed when re-compiled)", sbin->path, + (int) header->version_major, header->version_minor, + SIEVE_BINARY_VERSION_MAJOR, SIEVE_BINARY_VERSION_MINOR); + } result = FALSE; + /* Check block content */ } else if ( result && header->blocks == 0 ) { - sieve_sys_error("opened binary %s contains no blocks", sbin->path); + sieve_sys_error( + "binary open: binary %s is corrupt: it contains no blocks", + sbin->path); result = FALSE; + /* Valid */ } else { blk_count = header->blocks; } @@ -727,10 +819,7 @@ static bool _sieve_binary_open(struct sieve_binary *sbin) for ( i = 0; i < blk_count && result; i++ ) { T_BEGIN { - if ( !_load_block_index_record(sbin, &offset, i) ) { - sieve_sys_error( - "block index record %d of opened binary %s is corrupt", - i, sbin->path); + if ( !_read_block_index_record(sbin, &offset, i) ) { result = FALSE; } } T_END; @@ -745,8 +834,9 @@ static bool _sieve_binary_open(struct sieve_binary *sbin) if ( ext_block == NULL ) { result = FALSE; } else { - if ( !_sieve_binary_load_extensions(ext_block) ) { - sieve_sys_error("extension block of opened binary %s is corrupt", + if ( !_read_extensions(ext_block) ) { + sieve_sys_error("binary open: binary %s is corrupt: " + "failed to load extension block", sbin->path); result = FALSE; } @@ -756,31 +846,9 @@ static bool _sieve_binary_open(struct sieve_binary *sbin) return result; } -static bool _sieve_binary_load(struct sieve_binary *sbin) -{ - bool result = TRUE; - unsigned int i, blk_count; - - blk_count = array_count(&sbin->blocks); - if ( blk_count == 1 ) { - /* Binary is empty */ - return TRUE; - } - - /* Load the other blocks */ - - for ( i = 0; result && i < blk_count; i++ ) { - T_BEGIN { - if ( sieve_binary_block_get(sbin, i) == NULL ) - result = FALSE; - } T_END; - } - - return result; -} - struct sieve_binary *sieve_binary_open -(struct sieve_instance *svinst, const char *path, struct sieve_script *script) +(struct sieve_instance *svinst, const char *path, struct sieve_script *script, + enum sieve_error *error_r) { struct sieve_binary_extension_reg *const *regs; unsigned int ext_count, i; @@ -790,8 +858,7 @@ struct sieve_binary *sieve_binary_open i_assert( script == NULL || sieve_script_svinst(script) == svinst ); //file = _file_memory_open(path); - file = _file_lazy_open(path); - if ( file == NULL ) + if ( (file=_file_lazy_open(path, error_r)) == NULL ) return NULL; /* Create binary object */ @@ -801,6 +868,8 @@ struct sieve_binary *sieve_binary_open if ( !_sieve_binary_open(sbin) ) { sieve_binary_unref(&sbin); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_VALID; return NULL; } @@ -814,6 +883,10 @@ struct sieve_binary *sieve_binary_open if ( binext != NULL && binext->binary_open != NULL && !binext->binary_open(regs[i]->extension, sbin, regs[i]->context) ) { /* Extension thinks its corrupt */ + + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_VALID; + sieve_binary_unref(&sbin); return NULL; } @@ -821,19 +894,3 @@ struct sieve_binary *sieve_binary_open return sbin; } - -bool sieve_binary_load(struct sieve_binary *sbin) -{ - i_assert(sbin->file != NULL); - - /* - if ( sbin->file->load != NULL && !sbin->file->load(sbin->file) ) - return FALSE; */ - - if ( !_sieve_binary_load(sbin) ) { - /* Failed to interpret binary header and/or block structure */ - return FALSE; - } - - return TRUE; -} diff --git a/src/lib-sieve/sieve-binary-private.h b/src/lib-sieve/sieve-binary-private.h index c63cacb8d..97e08d3b2 100644 --- a/src/lib-sieve/sieve-binary-private.h +++ b/src/lib-sieve/sieve-binary-private.h @@ -22,7 +22,6 @@ struct sieve_binary_file { int fd; off_t offset; - bool (*load)(struct sieve_binary_file *file); const void *(*load_data) (struct sieve_binary_file *file, off_t *offset, size_t size); buffer_t *(*load_buffer) @@ -30,7 +29,7 @@ struct sieve_binary_file { }; bool sieve_binary_file_open - (struct sieve_binary_file *file, const char *path); + (struct sieve_binary_file *file, const char *path, enum sieve_error *error_r); void sieve_binary_file_close(struct sieve_binary_file **file); /* diff --git a/src/lib-sieve/sieve-binary.c b/src/lib-sieve/sieve-binary.c index 3f5631159..bf695be6a 100644 --- a/src/lib-sieve/sieve-binary.c +++ b/src/lib-sieve/sieve-binary.c @@ -142,6 +142,24 @@ const char *sieve_binary_path(struct sieve_binary *sbin) return sbin->path; } +bool sieve_binary_saved(struct sieve_binary *sbin) +{ + return ( sbin->path != NULL ); +} + +bool sieve_binary_loaded(struct sieve_binary *sbin) +{ + return ( sbin->file != NULL ); +} + +const char *sieve_binary_source(struct sieve_binary *sbin) +{ + if ( sbin->script != NULL && (sbin->path == NULL || sbin->file == NULL) ) + return sieve_script_path(sbin->script); + + return sbin->path; +} + struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin) { return sbin->svinst; @@ -156,16 +174,12 @@ bool sieve_binary_script_newer const char *sieve_binary_script_name(struct sieve_binary *sbin) { - struct sieve_script *script = sieve_binary_script(sbin); - - return ( script == NULL ? NULL : sieve_script_name(script) ); + return ( sbin->script == NULL ? NULL : sieve_script_name(sbin->script) ); } const char *sieve_binary_script_path(struct sieve_binary *sbin) { - struct sieve_script *script = sieve_binary_script(sbin); - - return ( script == NULL ? NULL : sieve_script_path(script) ); + return ( sbin->script == NULL ? NULL : sieve_script_path(sbin->script) ); } /* @@ -215,11 +229,8 @@ static bool sieve_binary_block_fetch(struct sieve_binary_block *sblock) if ( sbin->file ) { /* Try to acces the block in the binary on disk (apperently we were lazy) */ - if ( !sieve_binary_load_block(sblock) || sblock->data == NULL ) { - sieve_sys_error("block %d of loaded binary %s is corrupt", - sblock->id, sbin->path); + if ( !sieve_binary_load_block(sblock) || sblock->data == NULL ) return FALSE; - } } else { sblock->data = buffer_create_dynamic(sbin->pool, 64); return TRUE; diff --git a/src/lib-sieve/sieve-binary.h b/src/lib-sieve/sieve-binary.h index ae3b93314..3d63282d6 100644 --- a/src/lib-sieve/sieve-binary.h +++ b/src/lib-sieve/sieve-binary.h @@ -30,15 +30,19 @@ void sieve_binary_unref(struct sieve_binary **sbin); */ pool_t sieve_binary_pool(struct sieve_binary *sbin); -struct sieve_script *sieve_binary_script(struct sieve_binary *sbin); +struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin); const char *sieve_binary_path(struct sieve_binary *sbin); +struct sieve_script *sieve_binary_script(struct sieve_binary *sbin); + bool sieve_binary_script_newer (struct sieve_binary *sbin, struct sieve_script *script); -struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin); - const char *sieve_binary_script_name(struct sieve_binary *sbin); const char *sieve_binary_script_path(struct sieve_binary *sbin); +const char *sieve_binary_source(struct sieve_binary *sbin); +bool sieve_binary_loaded(struct sieve_binary *sbin); +bool sieve_binary_saved(struct sieve_binary *sbin); + /* * Activation after code generation */ @@ -49,8 +53,9 @@ void sieve_binary_activate(struct sieve_binary *sbin); * Saving the binary */ -bool sieve_binary_save - (struct sieve_binary *sbin, const char *path); +int sieve_binary_save +(struct sieve_binary *sbin, const char *path, bool update, + enum sieve_error *error_r); /* * Loading the binary @@ -58,9 +63,8 @@ bool sieve_binary_save struct sieve_binary *sieve_binary_open (struct sieve_instance *svinst, const char *path, - struct sieve_script *script); + struct sieve_script *script, enum sieve_error *error_r); bool sieve_binary_up_to_date(struct sieve_binary *sbin); -bool sieve_binary_load(struct sieve_binary *sbin); /* * Block management diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index dab8d5d77..db4209e10 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -141,9 +141,11 @@ struct sieve_plugin; /* sieve.c */ struct sieve_ast *sieve_parse - (struct sieve_script *script, struct sieve_error_handler *ehandler); + (struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r); bool sieve_validate - (struct sieve_ast *ast, struct sieve_error_handler *ehandler); + (struct sieve_ast *ast, struct sieve_error_handler *ehandler, + enum sieve_error *error_r); /* * Sieve engine instance diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c index 9e8b0a655..f6633604e 100644 --- a/src/lib-sieve/sieve-lexer.c +++ b/src/lib-sieve/sieve-lexer.c @@ -61,7 +61,8 @@ struct sieve_lexical_scanner { }; const struct sieve_lexer *sieve_lexer_create -(struct sieve_script *script, struct sieve_error_handler *ehandler) +(struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { pool_t pool; struct sieve_lexical_scanner *scanner; @@ -70,7 +71,7 @@ const struct sieve_lexer *sieve_lexer_create const struct stat *st; /* Open script as stream */ - stream = sieve_script_open(script, NULL); + stream = sieve_script_open(script, error_r); if ( stream == NULL ) return NULL; @@ -81,6 +82,8 @@ const struct sieve_lexer *sieve_lexer_create sieve_error(ehandler, sieve_script_name(script), "sieve script is too large (max %"PRIuSIZE_T" bytes)", svinst->max_script_size); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_POSSIBLE; return NULL; } diff --git a/src/lib-sieve/sieve-lexer.h b/src/lib-sieve/sieve-lexer.h index b96e9a821..8ae52baf8 100644 --- a/src/lib-sieve/sieve-lexer.h +++ b/src/lib-sieve/sieve-lexer.h @@ -59,7 +59,8 @@ struct sieve_lexer { }; const struct sieve_lexer *sieve_lexer_create - (struct sieve_script *script, struct sieve_error_handler *ehandler); + (struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r); void sieve_lexer_free(const struct sieve_lexer **lexer); /* diff --git a/src/lib-sieve/sieve-parser.c b/src/lib-sieve/sieve-parser.c index cc638b6fd..2e0f8cb95 100644 --- a/src/lib-sieve/sieve-parser.c +++ b/src/lib-sieve/sieve-parser.c @@ -45,12 +45,13 @@ struct sieve_parser { }; struct sieve_parser *sieve_parser_create -(struct sieve_script *script, struct sieve_error_handler *ehandler) +(struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { struct sieve_parser *parser; const struct sieve_lexer *lexer; - lexer = sieve_lexer_create(script, ehandler); + lexer = sieve_lexer_create(script, ehandler, error_r); if ( lexer != NULL ) { pool_t pool = pool_alloconly_create("sieve_parser", 4096); diff --git a/src/lib-sieve/sieve-parser.h b/src/lib-sieve/sieve-parser.h index 6c5e149e9..d0ab19f64 100644 --- a/src/lib-sieve/sieve-parser.h +++ b/src/lib-sieve/sieve-parser.h @@ -11,7 +11,8 @@ struct sieve_parser; struct sieve_parser *sieve_parser_create - (struct sieve_script *script, struct sieve_error_handler *ehandler); + (struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r); void sieve_parser_free(struct sieve_parser **parser); bool sieve_parser_run(struct sieve_parser *parser, struct sieve_ast **ast); diff --git a/src/lib-sieve/sieve-script-private.h b/src/lib-sieve/sieve-script-private.h index 47d2d4c8d..aef0d759a 100644 --- a/src/lib-sieve/sieve-script-private.h +++ b/src/lib-sieve/sieve-script-private.h @@ -38,6 +38,6 @@ struct sieve_script { struct sieve_script *sieve_script_init (struct sieve_script *script, struct sieve_instance *svinst, const char *path, const char *name, struct sieve_error_handler *ehandler, - bool *exists_r); + enum sieve_error *error_r); #endif /* __SIEVE_SCRIPT_PRIVATE_H */ diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c index 1832dc9a7..cd2c28f68 100644 --- a/src/lib-sieve/sieve-script.c +++ b/src/lib-sieve/sieve-script.c @@ -112,6 +112,39 @@ static inline const char *_sieve_scriptfile_from_name(const char *name) return name; } +/* + * Common error handling + */ + +static void sieve_script_handle_file_error +(struct sieve_instance *svinst, const char *path, const char *name, + struct sieve_error_handler *ehandler, enum sieve_error *error_r) +{ + switch ( errno ) { + case ENOENT: + if ( error_r == NULL ) + sieve_error(ehandler, name, "sieve script does not exist"); + else { + if ( svinst->debug ) + sieve_sys_debug("script file %s not found", t_abspath(path)); + *error_r = SIEVE_ERROR_NOT_FOUND; + } + break; + case EACCES: + sieve_critical(ehandler, name, + "failed to stat sieve script: %s", + eacces_error_get("stat", path)); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NO_PERM; + break; + default: + sieve_critical(ehandler, name, + "failed to stat sieve script: stat(%s) failed: %m", path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; + break; + } +} /* * Script object @@ -120,7 +153,7 @@ static inline const char *_sieve_scriptfile_from_name(const char *name) struct sieve_script *sieve_script_init (struct sieve_script *script, struct sieve_instance *svinst, const char *path, const char *name, struct sieve_error_handler *ehandler, - bool *exists_r) + enum sieve_error *error_r) { int ret; pool_t pool; @@ -128,8 +161,8 @@ struct sieve_script *sieve_script_init struct stat lnk_st; const char *filename, *dirpath, *basename, *binpath; - if ( exists_r != NULL ) - *exists_r = TRUE; + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NONE; T_BEGIN { @@ -162,25 +195,7 @@ struct sieve_script *sieve_script_init /* First obtain stat data from the system */ if ( (ret=lstat(path, &st)) < 0 ) { - switch ( errno ) { - case ENOENT: - if ( exists_r == NULL ) { - sieve_error(ehandler, basename, "sieve script does not exist"); - if ( svinst->debug ) - sieve_sys_debug("script file %s not found", t_abspath(path)); - } else - *exists_r = FALSE; - break; - case EACCES: - sieve_critical(ehandler, basename, - "failed to stat sieve script: %s", - eacces_error_get("lstat", path)); - break; - default: - sieve_critical(ehandler, basename, - "failed to stat sieve script: lstat(%s) failed: %m", path); - } - + sieve_script_handle_file_error(svinst, path, basename, ehandler, error_r); script = NULL; ret = 1; @@ -189,34 +204,18 @@ struct sieve_script *sieve_script_init lnk_st = st; /* Only create/init the object if it stat()s without problems */ - if (S_ISLNK(st.st_mode)) { - if ( (ret=stat(path, &st)) < 0 ) { - switch ( errno ) { - case ENOENT: - if ( exists_r == NULL ) - sieve_error(ehandler, basename, "sieve script does not exist"); - else - *exists_r = FALSE; - break; - case EACCES: - sieve_critical(ehandler, basename, - "failed to stat sieve script: %s", - eacces_error_get("stat", path)); - break; - default: - sieve_critical(ehandler, basename, - "failed to stat sieve script: stat(%s) failed: %m", path); - break; - } - - script = NULL; - ret = 1; - } + if ( S_ISLNK(st.st_mode) && (ret=stat(path, &st)) < 0 ) { + sieve_script_handle_file_error + (svinst, path, basename, ehandler, error_r); + script = NULL; + ret = 1; } if ( ret == 0 && !S_ISREG(st.st_mode) ) { sieve_critical(ehandler, basename, "sieve script file '%s' is not a regular file.", path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_POSSIBLE; script = NULL; ret = 1; } @@ -256,14 +255,14 @@ struct sieve_script *sieve_script_init struct sieve_script *sieve_script_create (struct sieve_instance *svinst, const char *path, const char *name, - struct sieve_error_handler *ehandler, bool *exists_r) + struct sieve_error_handler *ehandler, enum sieve_error *error_r) { - return sieve_script_init(NULL, svinst, path, name, ehandler, exists_r); + return sieve_script_init(NULL, svinst, path, name, ehandler, error_r); } struct sieve_script *sieve_script_create_in_directory (struct sieve_instance *svinst, const char *dirpath, const char *name, - struct sieve_error_handler *ehandler, bool *exists_r) + struct sieve_error_handler *ehandler, enum sieve_error *error_r) { const char *path; @@ -274,7 +273,7 @@ struct sieve_script *sieve_script_create_in_directory path = t_strconcat(dirpath, "/", _sieve_scriptfile_from_name(name), NULL); - return sieve_script_init(NULL, svinst, path, name, ehandler, exists_r); + return sieve_script_init(NULL, svinst, path, name, ehandler, error_r); } void sieve_script_ref(struct sieve_script *script) @@ -348,47 +347,35 @@ size_t sieve_script_size(const struct sieve_script *script) */ struct istream *sieve_script_open -(struct sieve_script *script, bool *deleted_r) +(struct sieve_script *script, enum sieve_error *error_r) { int fd; struct stat st; struct istream *result; - if ( deleted_r != NULL ) - *deleted_r = FALSE; + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NONE; if ( (fd=open(script->path, O_RDONLY)) < 0 ) { - switch( errno ) { - case ENOENT: - if ( deleted_r == NULL ) - /* Not supposed to occur, create() does stat already */ - sieve_error(script->ehandler, script->basename, - "sieve script does not exist"); - else - *deleted_r = TRUE; - break; - case EACCES: - sieve_critical(script->ehandler, script->path, - "failed to open sieve script: %s", - eacces_error_get("open", script->path)); - break; - default: - sieve_critical(script->ehandler, script->path, - "failed to open sieve script: open(%s) failed: %m", script->path); - break; - } + sieve_script_handle_file_error + (script->svinst, script->path, script->basename, script->ehandler, + error_r); return NULL; } if ( fstat(fd, &st) != 0 ) { sieve_critical(script->ehandler, script->path, "failed to open sieve script: fstat(fd=%s) failed: %m", script->path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; result = NULL; } else { /* Re-check the file type just to be sure */ if ( !S_ISREG(st.st_mode) ) { sieve_critical(script->ehandler, script->path, "sieve script file '%s' is not a regular file", script->path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_POSSIBLE; result = NULL; } else { result = script->stream = diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h index eed50263c..e6d1515c5 100644 --- a/src/lib-sieve/sieve-script.h +++ b/src/lib-sieve/sieve-script.h @@ -23,11 +23,11 @@ struct sieve_script; struct sieve_script *sieve_script_create (struct sieve_instance *svinst, const char *path, const char *name, - struct sieve_error_handler *ehandler, bool *exists_r); + struct sieve_error_handler *ehandler, enum sieve_error *error_r); struct sieve_script *sieve_script_create_in_directory (struct sieve_instance *svinst, const char *dirpath, const char *name, - struct sieve_error_handler *ehandler, bool *exists_r); + struct sieve_error_handler *ehandler, enum sieve_error *error_r); void sieve_script_ref(struct sieve_script *script); void sieve_script_unref(struct sieve_script **script); @@ -57,7 +57,8 @@ size_t sieve_script_size(const struct sieve_script *script); * Stream management */ -struct istream *sieve_script_open(struct sieve_script *script, bool *deleted_r); +struct istream *sieve_script_open + (struct sieve_script *script, enum sieve_error *error_r); void sieve_script_close(struct sieve_script *script); uoff_t sieve_script_get_size(const struct sieve_script *script); diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index 205a0e0e6..3ed8d5bb9 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -31,6 +31,35 @@ struct sieve_environment { const char *(*get_setting)(void *context, const char *identifier); }; +/* + * Errors + */ + +enum sieve_error { + SIEVE_ERROR_NONE = 0, + + /* Temporary internal error */ + SIEVE_ERROR_TEMP_FAIL, + /* It's not possible to do the wanted operation */ + SIEVE_ERROR_NOT_POSSIBLE, + /* Invalid parameters (eg. script name not valid) */ + SIEVE_ERROR_BAD_PARAMS, + /* No permission to do the request */ + SIEVE_ERROR_NO_PERM, + /* Out of disk space */ + SIEVE_ERROR_NO_SPACE, + /* Out of disk space */ + SIEVE_ERROR_NO_QUOTA, + /* Item (e.g. script or binary) cannot be found */ + SIEVE_ERROR_NOT_FOUND, + /* Item (e.g. script or binary) already exists */ + SIEVE_ERROR_EXISTS, + /* Referenced item (e.g. script or binary) is not valid or currupt */ + SIEVE_ERROR_NOT_VALID, + /* Not allowed to perform the operation because the item is in active use */ + SIEVE_ERROR_ACTIVE +}; + /* * Message data * diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 93e8bfb70..bf70ef8e0 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -118,41 +118,58 @@ const char *sieve_get_capabilities */ struct sieve_ast *sieve_parse -(struct sieve_script *script, struct sieve_error_handler *ehandler) +(struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { struct sieve_parser *parser; struct sieve_ast *ast = NULL; /* Parse */ - if ( (parser = sieve_parser_create(script, ehandler)) == NULL ) + if ( (parser = sieve_parser_create(script, ehandler, error_r)) == NULL ) return NULL; - if ( !sieve_parser_run(parser, &ast) || sieve_get_errors(ehandler) > 0 ) { + if ( !sieve_parser_run(parser, &ast) ) { ast = NULL; } else sieve_ast_ref(ast); sieve_parser_free(&parser); + + if ( error_r != NULL ) { + if ( ast == NULL ) + *error_r = SIEVE_ERROR_NOT_VALID; + else + *error_r = SIEVE_ERROR_NONE; + } return ast; } bool sieve_validate -(struct sieve_ast *ast, struct sieve_error_handler *ehandler) +(struct sieve_ast *ast, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { bool result = TRUE; struct sieve_validator *validator = sieve_validator_create(ast, ehandler); - if ( !sieve_validator_run(validator) || sieve_get_errors(ehandler) > 0 ) + if ( !sieve_validator_run(validator) ) result = FALSE; sieve_validator_free(&validator); + + if ( error_r != NULL ) { + if ( !result ) + *error_r = SIEVE_ERROR_NOT_VALID; + else + *error_r = SIEVE_ERROR_NONE; + } return result; } static struct sieve_binary *sieve_generate -(struct sieve_ast *ast, struct sieve_error_handler *ehandler) +(struct sieve_ast *ast, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { struct sieve_generator *generator = sieve_generator_create(ast, ehandler); struct sieve_binary *sbin = NULL; @@ -161,6 +178,13 @@ static struct sieve_binary *sieve_generate sieve_generator_free(&generator); + if ( error_r != NULL ) { + if ( sbin == NULL ) + *error_r = SIEVE_ERROR_NOT_VALID; + else + *error_r = SIEVE_ERROR_NONE; + } + return sbin; } @@ -169,19 +193,20 @@ static struct sieve_binary *sieve_generate */ struct sieve_binary *sieve_compile_script -(struct sieve_script *script, struct sieve_error_handler *ehandler) +(struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { struct sieve_ast *ast; - struct sieve_binary *sbin; - + struct sieve_binary *sbin; + /* Parse */ - if ( (ast = sieve_parse(script, ehandler)) == NULL ) { + if ( (ast = sieve_parse(script, ehandler, error_r)) == NULL ) { sieve_error(ehandler, sieve_script_name(script), "parse failed"); return NULL; } /* Validate */ - if ( !sieve_validate(ast, ehandler) ) { + if ( !sieve_validate(ast, ehandler, error_r) ) { sieve_error(ehandler, sieve_script_name(script), "validation failed"); sieve_ast_unref(&ast); @@ -189,31 +214,35 @@ struct sieve_binary *sieve_compile_script } /* Generate */ - if ( (sbin=sieve_generate(ast, ehandler)) == NULL ) { + if ( (sbin=sieve_generate(ast, ehandler, error_r)) == NULL ) { sieve_error(ehandler, sieve_script_name(script), "code generation failed"); sieve_ast_unref(&ast); return NULL; } - + /* Cleanup */ sieve_ast_unref(&ast); + if ( error_r != NULL ) + error_r = SIEVE_ERROR_NONE; + return sbin; } struct sieve_binary *sieve_compile (struct sieve_instance *svinst, const char *script_path, - const char *script_name, struct sieve_error_handler *ehandler) + const char *script_name, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { struct sieve_script *script; struct sieve_binary *sbin; if ( (script = sieve_script_create - (svinst, script_path, script_name, ehandler, NULL)) == NULL ) + (svinst, script_path, script_name, ehandler, error_r)) == NULL ) return NULL; - sbin = sieve_compile_script(script, ehandler); + sbin = sieve_compile_script(script, ehandler, error_r); sieve_script_unref(&script); @@ -266,9 +295,16 @@ static int sieve_run * Reading/writing sieve binaries */ +struct sieve_binary *sieve_load +(struct sieve_instance *svinst, const char *bin_path, enum sieve_error *error_r) +{ + return sieve_binary_open(svinst, bin_path, NULL, error_r); +} + struct sieve_binary *sieve_open (struct sieve_instance *svinst, const char *script_path, - const char *script_name, struct sieve_error_handler *ehandler, bool *exists_r) + const char *script_name, struct sieve_error_handler *ehandler, + enum sieve_error *error_r) { struct sieve_script *script; struct sieve_binary *sbin; @@ -276,7 +312,7 @@ struct sieve_binary *sieve_open /* First open the scriptfile itself */ script = sieve_script_create - (svinst, script_path, script_name, ehandler, exists_r); + (svinst, script_path, script_name, ehandler, error_r); if ( script == NULL ) { /* Failed */ @@ -286,7 +322,7 @@ struct sieve_binary *sieve_open T_BEGIN { /* Then try to open the matching binary */ bin_path = sieve_script_binpath(script); - sbin = sieve_binary_open(svinst, bin_path, script); + sbin = sieve_binary_open(svinst, bin_path, script, error_r); if (sbin != NULL) { /* Ok, it exists; now let's see if it is up to date */ @@ -297,15 +333,10 @@ struct sieve_binary *sieve_open sieve_binary_unref(&sbin); sbin = NULL; - - } else if ( !sieve_binary_load(sbin) ) { - /* Failed to load */ - sieve_binary_unref(&sbin); - sbin = NULL; - } + } } - /* If the binary does not exist, is not up-to-date or fails to load, we need + /* If the binary does not exist or is not up-to-date, we need * to (re-)compile. */ if ( sbin != NULL ) { @@ -313,19 +344,12 @@ struct sieve_binary *sieve_open sieve_sys_debug("script binary %s successfully loaded", bin_path); } else { - sbin = sieve_compile_script(script, ehandler); + sbin = sieve_compile_script(script, ehandler, error_r); /* Save the binary if compile was successful */ if ( sbin != NULL ) { if ( svinst->debug ) sieve_sys_debug("script %s successfully compiled", script_path); - - if ( sieve_binary_save(sbin, bin_path) ) { - if ( svinst->debug ) { - sieve_sys_debug - ("compiled script saved as binary file %s", bin_path); - } - } } } } T_END; @@ -336,25 +360,23 @@ struct sieve_binary *sieve_open sieve_script_unref(&script); return sbin; -} +} -bool sieve_save -(struct sieve_binary *sbin, const char *bin_path) +const char *sieve_get_source(struct sieve_binary *sbin) { - return sieve_binary_save(sbin, bin_path); + return sieve_binary_source(sbin); } -struct sieve_binary *sieve_load -(struct sieve_instance *svinst, const char *bin_path) +bool sieve_is_loaded(struct sieve_binary *sbin) { - struct sieve_binary *sbin = sieve_binary_open(svinst, bin_path, NULL); - - if ( sbin != NULL && !sieve_binary_load(sbin) ) { - sieve_binary_unref(&sbin); - sbin = NULL; - } + return sieve_binary_loaded(sbin); +} - return sbin; +int sieve_save +(struct sieve_binary *sbin, const char *bin_path, bool update, + enum sieve_error *error_r) +{ + return sieve_binary_save(sbin, bin_path, update, error_r); } void sieve_close(struct sieve_binary **sbin) @@ -623,24 +645,34 @@ struct sieve_directory { const char *path; }; -struct sieve_directory *sieve_directory_open(const char *path) +struct sieve_directory *sieve_directory_open +(const char *path, enum sieve_error *error_r) { struct sieve_directory *sdir = NULL; DIR *dirp; struct stat st; + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NONE; + /* Specified path can either be a regular file or a directory */ if ( stat(path, &st) != 0 ) { switch ( errno ) { case ENOENT: + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_FOUND; break; case EACCES: sieve_sys_error("failed to open sieve dir: %s", eacces_error_get("stat", path)); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NO_PERM; break; default: sieve_sys_error("failed to open sieve dir: " "stat(%s) failed: %m", path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; break; } return NULL; @@ -650,8 +682,24 @@ struct sieve_directory *sieve_directory_open(const char *path) /* Open the directory */ if ( (dirp = opendir(path)) == NULL ) { - sieve_sys_error("failed to open sieve dir: " - "opendir(%s) failed: %m", path); + switch ( errno ) { + case ENOENT: + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NOT_FOUND; + break; + case EACCES: + sieve_sys_error("failed to open sieve dir: %s", + eacces_error_get("opendir", path)); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_NO_PERM; + break; + default: + sieve_sys_error("failed to open sieve dir: " + "opendir(%s) failed: %m", path); + if ( error_r != NULL ) + *error_r = SIEVE_ERROR_TEMP_FAIL; + break; + } return NULL; } @@ -680,12 +728,12 @@ const char *sieve_directory_get_scriptfile(struct sieve_directory *sdir) errno = 0; if ( (dp = readdir(sdir->dirp)) == NULL ) { - if ( errno != 0 ) { + if ( errno != 0 ) { sieve_sys_error("failed to read sieve dir: " "readdir(%s) failed: %m", sdir->path); - continue; - } else - return NULL; + } + + return NULL; } if ( !sieve_script_file_has_extension(dp->d_name) ) diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index aa47978ea..8f3b4dc2f 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -48,7 +48,8 @@ void sieve_set_extensions /* sieve_compile_script: */ struct sieve_binary *sieve_compile_script - (struct sieve_script *script, struct sieve_error_handler *ehandler); + (struct sieve_script *script, struct sieve_error_handler *ehandler, + enum sieve_error *error_r); /* sieve_compile: * @@ -56,40 +57,42 @@ struct sieve_binary *sieve_compile_script */ struct sieve_binary *sieve_compile (struct sieve_instance *svinst, const char *script_path, - const char *script_name, struct sieve_error_handler *ehandler); + const char *script_name, struct sieve_error_handler *ehandler, + enum sieve_error *error_r); /* * Reading/writing Sieve binaries */ -/* sieve_open: +/* sieve_load: * - * First tries to open the binary version of the specified script and - * if it does not exist or if it contains errors, the script is - * (re-)compiled. The binary is updated if the script is recompiled. - * Note that errors in the bytecode are not caught here. + * Loads the sieve binary indicated by the provided path. + */ +struct sieve_binary *sieve_load + (struct sieve_instance *svinst, const char *bin_path, + enum sieve_error *error_r); + +/* sieve_open: * + * First tries to open the binary version of the specified script and if it + * does not exist or if it contains errors, the script is (re-)compiled. Note + * that errors in the bytecode are caught only at runtime. */ struct sieve_binary *sieve_open (struct sieve_instance *svinst, const char *script_path, const char *script_name, struct sieve_error_handler *ehandler, - bool *exists_r); + enum sieve_error *error_r); /* sieve_save: * * Saves the binary as the file indicated by the path parameter. If * path is NULL, it chooses the default path relative to the original - * script. - */ -bool sieve_save - (struct sieve_binary *sbin, const char *bin_path); - -/* sieve_load: - * - * Loads the sieve binary indicated by the provided path. + * script. This function will not write the binary to disk when it was + * loaded from the indicated bin_path, unless update is TRUE. */ -struct sieve_binary *sieve_load - (struct sieve_instance *svinst, const char *bin_path); +int sieve_save + (struct sieve_binary *sbin, const char *bin_path, bool update, + enum sieve_error *error_r); /* sieve_close: * @@ -97,6 +100,19 @@ struct sieve_binary *sieve_load */ void sieve_close(struct sieve_binary **sbin); +/* sieve_get_source: + * + * Obtains the path the binary was compiled or loaded from + */ +const char *sieve_get_source(struct sieve_binary *sbin); + +/* + * sieve_is_loeded: + * + * Indicates whether the binary was loaded from a pre-compiled file. + */ +bool sieve_is_loaded(struct sieve_binary *sbin); + /* * Debugging */ @@ -166,7 +182,8 @@ size_t sieve_max_script_size(struct sieve_instance *svinst); struct sieve_directory; -struct sieve_directory *sieve_directory_open(const char *path); +struct sieve_directory *sieve_directory_open + (const char *path, enum sieve_error *error_r); const char *sieve_directory_get_scriptfile(struct sieve_directory *sdir); void sieve_directory_close(struct sieve_directory **sdir); diff --git a/src/lib-sievestorage/Makefile.am b/src/lib-sievestorage/Makefile.am index 7636f5744..98f40e556 100644 --- a/src/lib-sievestorage/Makefile.am +++ b/src/lib-sievestorage/Makefile.am @@ -13,7 +13,6 @@ libsievestorage_a_SOURCES = \ sieve-storage.c noinst_HEADERS = \ - sieve-storage-error.h \ sieve-storage-save.h \ sieve-storage-script.h \ sieve-storage-list.h \ diff --git a/src/lib-sievestorage/sieve-storage-error.h b/src/lib-sievestorage/sieve-storage-error.h deleted file mode 100644 index a088e9824..000000000 --- a/src/lib-sievestorage/sieve-storage-error.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (c) 2002-2010 Dovecot Sieve authors, see the included COPYING file - */ - -#ifndef __SIEVE_STORAGE_ERROR_H -#define __SIEVE_STORAGE_ERROR_H - -enum sieve_storage_error { - SIEVE_STORAGE_ERROR_NONE = 0, - - /* Temporary internal error */ - SIEVE_STORAGE_ERROR_TEMP, - - /* It's not possible to do the wanted operation */ - SIEVE_STORAGE_ERROR_IMPOSSIBLE, - - /* Quota exceeded */ - SIEVE_STORAGE_ERROR_QUOTA, - - /* Out of disk space */ - SIEVE_STORAGE_ERROR_NOSPACE, - - /* Script does not exist */ - SIEVE_STORAGE_ERROR_NOTFOUND, - - /* Operation not allowed on active script */ - SIEVE_STORAGE_ERROR_ACTIVE, - - /* Operation not allowed on existing script */ - SIEVE_STORAGE_ERROR_EXISTS -}; - -#endif /* __SIEVE_STORAGE_ERROR_H */ diff --git a/src/lib-sievestorage/sieve-storage-list.c b/src/lib-sievestorage/sieve-storage-list.c index ef7cf1aa9..6efc630b1 100644 --- a/src/lib-sievestorage/sieve-storage-list.c +++ b/src/lib-sievestorage/sieve-storage-list.c @@ -25,25 +25,22 @@ struct sieve_list_context { }; struct sieve_list_context *sieve_storage_list_init - (struct sieve_storage *storage) +(struct sieve_storage *storage) { struct sieve_list_context *ctx; - const char *active; + const char *active = NULL; pool_t pool; DIR *dirp; /* Open the directory */ if ( (dirp = opendir(storage->dir)) == NULL ) { - sieve_storage_set_critical(storage, "opendir(%s) failed: %m", - storage->dir); + sieve_storage_set_critical(storage, "opendir(%s) failed: %m", storage->dir); return NULL; } T_BEGIN { - /* Get the name of the active script */ - if ( (active = sieve_storage_get_active_scriptfile(storage)) - == NULL ) { + if ( sieve_storage_get_active_scriptfile(storage, &active) < 0) { ctx = NULL; } else { pool = pool_alloconly_create("sieve_list_context", 4096); @@ -51,7 +48,7 @@ struct sieve_list_context *sieve_storage_list_init ctx->pool = pool; ctx->storage = storage; ctx->dirp = dirp; - ctx->active = p_strdup(pool, active); + ctx->active = ( active != NULL ? p_strdup(pool, active) : NULL ); ctx->seen_active = FALSE; } } T_END; @@ -60,7 +57,7 @@ struct sieve_list_context *sieve_storage_list_init } const char *sieve_storage_list_next - (struct sieve_list_context *ctx, bool *active) +(struct sieve_list_context *ctx, bool *active) { const struct sieve_storage *storage = ctx->storage; struct dirent *dp; @@ -87,8 +84,7 @@ const char *sieve_storage_list_next } } - if ( ctx->active != NULL && - strcmp(dp->d_name, ctx->active) == 0 ) { + if ( ctx->active != NULL && strcmp(dp->d_name, ctx->active) == 0 ) { *active = TRUE; ctx->active = NULL; } @@ -100,7 +96,7 @@ int sieve_storage_list_deinit(struct sieve_list_context **ctx) { if (closedir((*ctx)->dirp) < 0) { sieve_storage_set_critical((*ctx)->storage, "closedir(%s) failed: %m", - (*ctx)->storage->dir); + (*ctx)->storage->dir); } pool_unref(&(*ctx)->pool); diff --git a/src/lib-sievestorage/sieve-storage-private.h b/src/lib-sievestorage/sieve-storage-private.h index b359b2903..fe12d55ae 100644 --- a/src/lib-sievestorage/sieve-storage-private.h +++ b/src/lib-sievestorage/sieve-storage-private.h @@ -49,16 +49,14 @@ struct sieve_storage { uint64_t max_scripts; uint64_t max_storage; - enum sieve_storage_error error_code; - + enum sieve_error error_code; struct sieve_error_handler *ehandler; enum sieve_storage_flags flags; }; struct sieve_script *sieve_storage_script_init_from_path - (struct sieve_storage *storage, const char *path, - const char *scriptname, bool *exists_r); + (struct sieve_storage *storage, const char *path, const char *scriptname); #endif diff --git a/src/lib-sievestorage/sieve-storage-quota.c b/src/lib-sievestorage/sieve-storage-quota.c index 92a931934..ccd9aa1be 100644 --- a/src/lib-sievestorage/sieve-storage-quota.c +++ b/src/lib-sievestorage/sieve-storage-quota.c @@ -22,10 +22,10 @@ bool sieve_storage_quota_validsize uint64_t max_size; max_size = sieve_max_script_size(storage->svinst); - if ( max_size > 0 && size > max_size ) { + if ( max_size > 0 && size > max_size ) { *limit_r = max_size; - return FALSE; - } + return FALSE; + } return TRUE; } diff --git a/src/lib-sievestorage/sieve-storage-save.c b/src/lib-sievestorage/sieve-storage-save.c index 8ae489b77..1476f6609 100644 --- a/src/lib-sievestorage/sieve-storage-save.c +++ b/src/lib-sievestorage/sieve-storage-save.c @@ -8,6 +8,7 @@ #include "buffer.h" #include "ostream.h" #include "str.h" +#include "eacces-error.h" #include "sieve-script.h" @@ -112,7 +113,7 @@ static int sieve_storage_create_tmp *fpath_r = str_c(path); if (fd == -1) { if (ENOSPACE(errno)) { - sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOSPACE, + sieve_storage_set_error(storage, SIEVE_ERROR_NO_SPACE, "Not enough disk space"); } else { sieve_storage_set_critical(storage, @@ -140,12 +141,15 @@ static int sieve_storage_script_move(struct sieve_save_context *ctx, failed = FALSE; else { failed = TRUE; - if (ENOSPACE(errno)) { + if ( ENOSPACE(errno) ) { sieve_storage_set_error - (ctx->storage, SIEVE_STORAGE_ERROR_NOSPACE, "Not enough disk space"); + (ctx->storage, SIEVE_ERROR_NO_SPACE, "Not enough disk space"); + } else if ( errno == EACCES ) { + sieve_storage_set_critical + (ctx->storage, "%s", eacces_error_get("rename", dst)); } else { sieve_storage_set_critical - (ctx->storage, "link(%s, %s) failed: %m", ctx->tmp_path, dst); + (ctx->storage, "rename(%s, %s) failed: %m", ctx->tmp_path, dst); } } @@ -169,7 +173,7 @@ sieve_storage_save_init(struct sieve_storage *storage, /* Validate script name */ if ( !sieve_script_name_is_valid(scriptname) ) { sieve_storage_set_error(storage, - SIEVE_STORAGE_ERROR_IMPOSSIBLE, + SIEVE_ERROR_BAD_PARAMS, "Invalid script name '%s'.", scriptname); return NULL; } @@ -188,7 +192,7 @@ sieve_storage_save_init(struct sieve_storage *storage, strncmp(scriptname, storage->active_fname, namelen) == 0 ) { sieve_storage_set_error( - storage, SIEVE_STORAGE_ERROR_IMPOSSIBLE, + storage, SIEVE_ERROR_BAD_PARAMS, "Script name '%s' is reserved for internal use.", scriptname); return NULL; } @@ -263,7 +267,7 @@ int sieve_storage_save_finish(struct sieve_save_context *ctx) errno = output_errno; if ( ENOSPACE(errno) ) { - sieve_storage_set_error(ctx->storage, SIEVE_STORAGE_ERROR_NOSPACE, + sieve_storage_set_error(ctx->storage, SIEVE_ERROR_NO_SPACE, "Not enough disk space"); } else if ( errno != 0 ) { sieve_storage_set_critical(ctx->storage, @@ -289,7 +293,6 @@ struct sieve_script *sieve_storage_save_get_tempscript { const char *scriptname = ( ctx->scriptname == NULL ? "" : ctx->scriptname ); - bool exists = FALSE; if (ctx->failed) return NULL; @@ -298,14 +301,15 @@ struct sieve_script *sieve_storage_save_get_tempscript return ctx->scriptobject; ctx->scriptobject = sieve_storage_script_init_from_path - (ctx->storage, ctx->tmp_path, scriptname, &exists); - - if ( !exists ) { - sieve_storage_set_critical(ctx->storage, - "save: Temporary script file with name '%s' got lost, " - "which should not happen (possibly deleted externally).", - ctx->tmp_path); - sieve_script_unref(&ctx->scriptobject); + (ctx->storage, ctx->tmp_path, scriptname); + + if ( ctx->scriptobject == NULL ) { + if ( ctx->storage->error_code == SIEVE_ERROR_NOT_FOUND ) { + sieve_storage_set_critical(ctx->storage, + "save: Temporary script file with name '%s' got lost, " + "which should not happen (possibly deleted externally).", + ctx->tmp_path); + } return NULL; } diff --git a/src/lib-sievestorage/sieve-storage-script.c b/src/lib-sievestorage/sieve-storage-script.c index 0b6a6eba6..7ce41d902 100644 --- a/src/lib-sievestorage/sieve-storage-script.c +++ b/src/lib-sievestorage/sieve-storage-script.c @@ -7,6 +7,7 @@ #include "ioloop.h" #include "istream.h" #include "file-copy.h" +#include "eacces-error.h" #include "sieve-script-private.h" @@ -30,10 +31,11 @@ struct sieve_storage_script { struct sieve_script *sieve_storage_script_init_from_path (struct sieve_storage *storage, const char *path, - const char *scriptname, bool *exists_r) + const char *scriptname) { pool_t pool; struct sieve_storage_script *st_script = NULL; + enum sieve_error error; /* Prevent initializing the active script link as a script when it * resides in the sieve storage directory. @@ -48,8 +50,8 @@ struct sieve_script *sieve_storage_script_init_from_path fname++; if ( strcmp(fname, storage->active_fname) == 0 ) { - if ( exists_r != NULL ) - *exists_r = FALSE; + sieve_storage_set_error + (storage, SIEVE_ERROR_NOT_FOUND, "Script does not exist."); return NULL; } } @@ -60,26 +62,27 @@ struct sieve_script *sieve_storage_script_init_from_path st_script->storage = storage; if ( sieve_script_init(&st_script->script, storage->svinst, path, scriptname, - sieve_storage_get_error_handler(storage), exists_r) != NULL ) { - + sieve_storage_get_error_handler(storage), &error) != NULL ) { return &st_script->script; } pool_unref(&pool); + if ( error == SIEVE_ERROR_NOT_FOUND ) + sieve_storage_set_error(storage, error, "Script does not exist."); + return NULL; } struct sieve_script *sieve_storage_script_init -(struct sieve_storage *storage, const char *scriptname, bool *exists_r) +(struct sieve_storage *storage, const char *scriptname) { struct sieve_script *script; const char *path; /* Validate script name */ if ( !sieve_script_name_is_valid(scriptname) ) { - sieve_storage_set_error(storage, - SIEVE_STORAGE_ERROR_IMPOSSIBLE, + sieve_storage_set_error(storage, SIEVE_ERROR_BAD_PARAMS, "Invalid script name '%s'.", scriptname); return NULL; } @@ -87,15 +90,14 @@ struct sieve_script *sieve_storage_script_init T_BEGIN { path = t_strconcat( storage->dir, "/", scriptname, ".sieve", NULL ); - script = sieve_storage_script_init_from_path - (storage, path, NULL, exists_r); + script = sieve_storage_script_init_from_path(storage, path, NULL); } T_END; return script; } static struct sieve_script *sieve_storage_script_init_from_file -(struct sieve_storage *storage, const char *scriptfile, bool *exists_r) +(struct sieve_storage *storage, const char *scriptfile) { struct sieve_script *script; const char *path; @@ -103,8 +105,7 @@ static struct sieve_script *sieve_storage_script_init_from_file T_BEGIN { path = t_strconcat( storage->dir, "/", scriptfile, NULL ); - script = sieve_storage_script_init_from_path - (storage, path, NULL, exists_r); + script = sieve_storage_script_init_from_path(storage, path, NULL); } T_END; return script; @@ -123,14 +124,13 @@ const char *sieve_storage_file_get_scriptname return t_strdup_until(filename, ext); } -static const char *sieve_storage_read_active_link -(struct sieve_storage *storage, bool *not_link) +static int sieve_storage_read_active_link +(struct sieve_storage *storage, const char **link_r) { char linkbuf[PATH_MAX]; int ret; - if ( not_link != NULL ) - *not_link = FALSE; + *link_r = NULL; ret = readlink(storage->active_path, linkbuf, sizeof(linkbuf)); @@ -143,25 +143,24 @@ static const char *sieve_storage_read_active_link i_warning ("sieve-storage: Active sieve script symlink %s is no symlink.", storage->active_path); - if ( not_link != NULL ) - *not_link = TRUE; - return ""; + return 0; } - if (errno != ENOENT ) { - /* We do need to panic otherwise */ - sieve_storage_set_critical - (storage, - "Performing readlink() on active sieve symlink '%s' failed: %m", - storage->active_path); - return NULL; + if (errno == ENOENT ) { + /* Symlink not found */ + return 0; } - return ""; + /* We do need to panic otherwise */ + sieve_storage_set_critical(storage, + "Performing readlink() on active sieve symlink '%s' failed: %m", + storage->active_path); + return -1; } /* ret is now assured to be valid, i.e. > 0 */ - return t_strndup(linkbuf, ret); + *link_r = t_strndup(linkbuf, ret); + return 1; } static const char *sieve_storage_parse_link @@ -204,16 +203,17 @@ static const char *sieve_storage_parse_link return fname; } -const char *sieve_storage_get_active_scriptfile -(struct sieve_storage *storage) +int sieve_storage_get_active_scriptfile +(struct sieve_storage *storage, const char **file_r) { const char *link, *scriptfile; + int ret; - /* Read the active link */ - link = sieve_storage_read_active_link(storage, NULL); + *file_r = NULL; - if ( link == NULL || *link == '\0' ) - return link; + /* Read the active link */ + if ( (ret=sieve_storage_read_active_link(storage, &link)) <= 0 ) + return ret; /* Parse the link */ scriptfile = sieve_storage_parse_link(storage, link); @@ -223,37 +223,30 @@ const char *sieve_storage_get_active_scriptfile * ignore this situation and report 'no active script'. * Activation should fix this situation. */ - return ""; + return 0; } - return scriptfile; + *file_r = scriptfile; + return 1; } struct sieve_script *sieve_storage_get_active_script -(struct sieve_storage *storage, bool *no_active) +(struct sieve_storage *storage) { - bool exists, no_link; struct sieve_script *script; const char *scriptfile, *link; + int ret; - *no_active = FALSE; + sieve_storage_clear_error(storage); /* Read the active link */ - link = sieve_storage_read_active_link(storage, &no_link); - - if ( link == NULL ) - /* Error */ - return NULL; - - if ( *link == '\0' ) - { - if (no_link) { + if ( (ret=sieve_storage_read_active_link(storage, &link)) <= 0 ) { + if ( ret == 0 ) { /* Try to open the active_path as a regular file */ return sieve_storage_script_init_from_path - (storage, storage->active_path, NULL, NULL); + (storage, storage->active_path, NULL); } - *no_active = TRUE; return NULL; } @@ -261,43 +254,37 @@ struct sieve_script *sieve_storage_get_active_script scriptfile = sieve_storage_parse_link(storage, link); if (scriptfile == NULL) { - /* Obviously someone has been playing with our symlink, - * ignore this situation and report 'no active script'. + /* Obviously someone has been playing with our symlink, + * ignore this situation and report. */ - *no_active = TRUE; return NULL; } - exists = TRUE; - script = sieve_storage_script_init_from_file(storage, scriptfile, &exists); + script = sieve_storage_script_init_from_file(storage, scriptfile); - if ( !exists ) { + if ( script == NULL && storage->error_code == SIEVE_ERROR_NOT_FOUND ) { i_warning ("sieve-storage: Active sieve script symlink %s " "points to non-existent script (points to %s).", storage->active_path, link); } - - *no_active = !exists; + return script; } int sieve_storage_script_is_active(struct sieve_script *script) { - struct sieve_storage_script *st_script = (struct sieve_storage_script *) script; + struct sieve_storage_script *st_script = + (struct sieve_storage_script *) script; const char *afile; int ret = 0; T_BEGIN { - afile = sieve_storage_get_active_scriptfile(st_script->storage); + ret = sieve_storage_get_active_scriptfile(st_script->storage, &afile); - if (afile == NULL) { - /* Critical error */ - ret = -1; - } else { + if ( ret > 0 ) { /* Is the requested script active? */ - if ( strcmp(script->filename, afile) == 0 ) - ret = 1; + ret = ( strcmp(script->filename, afile) == 0 ? 1 : 0 ); } } T_END; @@ -306,13 +293,14 @@ int sieve_storage_script_is_active(struct sieve_script *script) int sieve_storage_script_delete(struct sieve_script **script) { - struct sieve_storage_script *st_script = (struct sieve_storage_script *) *script; + struct sieve_storage_script *st_script = + (struct sieve_storage_script *) *script; struct sieve_storage *storage = st_script->storage; int ret = 0; /* Is the requested script active? */ if ( sieve_storage_script_is_active(*script) ) { - sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_ACTIVE, + sieve_storage_set_error(storage, SIEVE_ERROR_ACTIVE, "Cannot delete the active sieve script."); ret = -1; } else { @@ -320,7 +308,7 @@ int sieve_storage_script_delete(struct sieve_script **script) if ( ret < 0 ) { if ( errno == ENOENT ) - sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOTFOUND, + sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND, "Sieve script does not exist."); else sieve_storage_set_critical( @@ -331,7 +319,6 @@ int sieve_storage_script_delete(struct sieve_script **script) /* Always deinitialize the script object */ sieve_script_unref(script); - return ret; } @@ -350,11 +337,11 @@ static bool sieve_storage_rescue_regular_file(struct sieve_storage *storage) return TRUE; } - if ( S_ISLNK( st.st_mode ) ) { + if ( S_ISLNK( st.st_mode ) ) { if ( storage->debug ) - i_info( "sieve-storage: nothing to rescue %s.", storage->active_path); - return TRUE; /* Nothing to rescue */ - } + i_info( "sieve-storage: nothing to rescue %s.", storage->active_path); + return TRUE; /* Nothing to rescue */ + } /* Only regular files can be rescued */ if ( S_ISREG( st.st_mode ) ) { @@ -480,10 +467,10 @@ static int _sieve_storage_script_activate(struct sieve_script *script) * resolves automatically. This step is only necessary to provide a * proper return value indicating whether the script was already active. */ - afile = sieve_storage_get_active_scriptfile(storage); + ret = sieve_storage_get_active_scriptfile(storage, &afile); /* Is the requested script already active? */ - if ( afile == NULL || strcmp(script->filename, afile) != 0 ) + if ( ret <= 0 || strcmp(script->filename, afile) != 0 ) activated = 1; /* Check the scriptfile we are trying to activate */ @@ -550,7 +537,7 @@ int sieve_storage_script_rename /* Check script name */ if ( !sieve_script_name_is_valid(newname) ) { sieve_storage_set_error(storage, - SIEVE_STORAGE_ERROR_IMPOSSIBLE, + SIEVE_ERROR_BAD_PARAMS, "Invalid new script name '%s'.", newname); return -1; } @@ -601,11 +588,11 @@ int sieve_storage_script_rename /* Our efforts failed right away */ switch ( errno ) { case ENOENT: - sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOTFOUND, + sieve_storage_set_error(storage, SIEVE_ERROR_NOT_FOUND, "Sieve script does not exist."); break; case EEXIST: - sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_EXISTS, + sieve_storage_set_error(storage, SIEVE_ERROR_EXISTS, "A sieve script with that name already exists."); break; default: diff --git a/src/lib-sievestorage/sieve-storage-script.h b/src/lib-sievestorage/sieve-storage-script.h index 44e7380cb..ea7c44451 100644 --- a/src/lib-sievestorage/sieve-storage-script.h +++ b/src/lib-sievestorage/sieve-storage-script.h @@ -9,16 +9,16 @@ #include "sieve-storage.h" struct sieve_script *sieve_storage_script_init - (struct sieve_storage *storage, const char *scriptname, bool *exists_r); + (struct sieve_storage *storage, const char *scriptname); const char *sieve_storage_file_get_scriptname (const struct sieve_storage *storage, const char *filename); -const char * - sieve_storage_get_active_scriptfile(struct sieve_storage *storage); +int sieve_storage_get_active_scriptfile + (struct sieve_storage *storage, const char **file_r); struct sieve_script *sieve_storage_get_active_script - (struct sieve_storage *storage, bool *no_active); + (struct sieve_storage *storage); int sieve_storage_script_is_active(struct sieve_script *script); @@ -29,7 +29,7 @@ int sieve_storage_deactivate(struct sieve_storage *storage); int sieve_storage_script_activate(struct sieve_script *script); int sieve_storage_script_rename - (struct sieve_script *script, const char *newname); +(struct sieve_script *script, const char *newname); #endif diff --git a/src/lib-sievestorage/sieve-storage.c b/src/lib-sievestorage/sieve-storage.c index 25956e561..a8e73ea34 100644 --- a/src/lib-sievestorage/sieve-storage.c +++ b/src/lib-sievestorage/sieve-storage.c @@ -140,7 +140,10 @@ static int mkdir_verify if ( stat(dir, &st) == 0 ) return 0; - if ( errno != ENOENT ) { + if ( errno == EACCES ) { + i_error("sieve-storage: %s", eacces_error_get("stat", dir)); + return -1; + } else if ( errno != ENOENT ) { i_error("sieve-storage: stat(%s) failed: %m", dir); return -1; } @@ -151,14 +154,18 @@ static int mkdir_verify return 0; } - if ( errno == EEXIST ) { + switch ( errno ) { + case EEXIST: return 0; - } else if (errno == ENOENT) { + case ENOENT: i_error("sieve-storage: storage was deleted while it was being created"); - } else if (errno == EACCES) { + break; + case EACCES: i_error("sieve-storage: %s", eacces_error_get_creating("mkdir", dir)); - } else { + break; + default: i_error("sieve-storage: mkdir(%s) failed: %m", dir); + break; } return -1; @@ -341,7 +348,7 @@ static struct sieve_storage *_sieve_storage_create if ( sieve_setting_get_size_value (svinst, "sieve_quota_max_storage", &size_setting) ) { storage->max_storage = size_setting; - } + } if ( sieve_setting_get_uint_value (svinst, "sieve_quota_max_scripts", &uint_setting) ) { @@ -416,16 +423,18 @@ static void sieve_storage_verror if (fmt != NULL) { storage->error = i_strdup_vprintf(fmt, args); } + storage->error_code = SIEVE_ERROR_TEMP_FAIL; } void sieve_storage_clear_error(struct sieve_storage *storage) { i_free(storage->error); + storage->error_code = SIEVE_ERROR_NONE; storage->error = NULL; } void sieve_storage_set_error -(struct sieve_storage *storage, enum sieve_storage_error error, +(struct sieve_storage *storage, enum sieve_error error, const char *fmt, ...) { va_list va; @@ -449,14 +458,14 @@ void sieve_storage_set_internal_error(struct sieve_storage *storage) tm = localtime(&ioloop_time); i_free(storage->error); - storage->error_code = SIEVE_STORAGE_ERROR_TEMP; + storage->error_code = SIEVE_ERROR_TEMP_FAIL; storage->error = strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ? i_strdup(str) : i_strdup(CRITICAL_MSG); } -void sieve_storage_set_critical(struct sieve_storage *storage, - const char *fmt, ...) +void sieve_storage_set_critical +(struct sieve_storage *storage, const char *fmt, ...) { va_list va; @@ -474,7 +483,7 @@ void sieve_storage_set_critical(struct sieve_storage *storage, } const char *sieve_storage_get_last_error - (struct sieve_storage *storage, enum sieve_storage_error *error_r) +(struct sieve_storage *storage, enum sieve_error *error_r) { /* We get here only in error situations, so we have to return some error. If storage->error is NULL, it means we forgot to set it at diff --git a/src/lib-sievestorage/sieve-storage.h b/src/lib-sievestorage/sieve-storage.h index 603a897ae..0e245d666 100644 --- a/src/lib-sievestorage/sieve-storage.h +++ b/src/lib-sievestorage/sieve-storage.h @@ -8,7 +8,6 @@ #include "mail-user.h" #include "sieve.h" -#include "sieve-storage-error.h" struct sieve_storage *sieve_storage_create (struct sieve_instance *svinst, const char *user, const char *home, bool debug); @@ -22,7 +21,7 @@ struct sieve_error_handler *sieve_storage_get_error_handler void sieve_storage_clear_error(struct sieve_storage *storage); void sieve_storage_set_error - (struct sieve_storage *storage, enum sieve_storage_error error, + (struct sieve_storage *storage, enum sieve_error error, const char *fmt, ...) ATTR_FORMAT(3, 4); void sieve_storage_set_critical(struct sieve_storage *storage, @@ -31,6 +30,6 @@ void sieve_storage_set_critical(struct sieve_storage *storage, void sieve_storage_set_internal_error(struct sieve_storage *storage); const char *sieve_storage_get_last_error - (struct sieve_storage *storage, enum sieve_storage_error *error_r); + (struct sieve_storage *storage, enum sieve_error *error_r); #endif diff --git a/src/managesieve/cmd-deletescript.c b/src/managesieve/cmd-deletescript.c index 422ca533e..54c3d8a9a 100644 --- a/src/managesieve/cmd-deletescript.c +++ b/src/managesieve/cmd-deletescript.c @@ -15,21 +15,15 @@ bool cmd_deletescript(struct client_command_context *cmd) struct sieve_storage *storage = client->storage; const char *scriptname; struct sieve_script *script; - bool exists; /* <scrip name>*/ if (!client_read_string_args(cmd, 1, &scriptname)) return FALSE; - exists = TRUE; - script = sieve_storage_script_init(storage, scriptname, &exists); + script = sieve_storage_script_init(storage, scriptname); if (script == NULL) { - if (!exists) - client_send_noresp(client, "NONEXISTENT", "Script does not exist."); - else - client_send_storage_error(client, storage); - + client_send_storage_error(client, storage); return TRUE; } diff --git a/src/managesieve/cmd-getscript.c b/src/managesieve/cmd-getscript.c index dd0c3afd2..746089ad8 100644 --- a/src/managesieve/cmd-getscript.c +++ b/src/managesieve/cmd-getscript.c @@ -18,28 +18,23 @@ struct cmd_getscript_context { struct sieve_script *script; struct istream *script_stream; - bool failed; - bool exists; + + unsigned int failed:1; }; static bool cmd_getscript_finish(struct cmd_getscript_context *ctx) { struct client *client = ctx->client; - if (ctx->script != NULL) + if ( ctx->script != NULL ) sieve_script_unref(&ctx->script); - if (ctx->failed) { - if (client->output->closed) { + if ( ctx->failed ) { + if ( client->output->closed ) { client_disconnect(client, "Disconnected"); return TRUE; } - if (!ctx->exists) { - client_send_noresp(client, "NONEXISTENT", "Script does not exist."); - return TRUE; - } - client_send_storage_error(client, client->storage); return TRUE; } @@ -59,7 +54,8 @@ static bool cmd_getscript_continue(struct client_command_context *cmd) if ( ret < 0 ) { sieve_storage_set_critical(ctx->storage, - "o_stream_send_istream(%s) failed: %m", sieve_script_filename(ctx->script)); + "o_stream_send_istream(%s) failed: %m", + sieve_script_filename(ctx->script)); ctx->failed = TRUE; return cmd_getscript_finish(ctx); } @@ -68,19 +64,19 @@ static bool cmd_getscript_continue(struct client_command_context *cmd) if ( ctx->script_offset != ctx->script_size && !ctx->failed ) { /* unfinished */ - if (!i_stream_have_bytes_left(ctx->script_stream)) { - /* Input stream gave less data than expected */ - i_error("GETSCRIPT for SCRIPT %s got too little data: " - "%"PRIuUOFF_T" vs %"PRIuUOFF_T, - sieve_script_name(ctx->script), - ctx->script_offset, ctx->script_size); - - client_disconnect(ctx->client, "GETSCRIPT failed"); + if ( !i_stream_have_bytes_left(ctx->script_stream) ) { + /* Input stream gave less data than expected */ + sieve_storage_set_critical(ctx->storage, + "GETSCRIPT for SCRIPT %s got too little data: " + "%"PRIuUOFF_T" vs %"PRIuUOFF_T, sieve_script_name(ctx->script), + ctx->script_offset, ctx->script_size); + + client_disconnect(ctx->client, "GETSCRIPT failed"); ctx->failed = TRUE; - return cmd_getscript_finish(ctx); - } + return cmd_getscript_finish(ctx); + } - return FALSE; + return FALSE; } return cmd_getscript_finish(ctx); @@ -91,7 +87,7 @@ bool cmd_getscript(struct client_command_context *cmd) struct client *client = cmd->client; struct cmd_getscript_context *ctx; const char *scriptname; - bool deleted_r; + enum sieve_error error; /* <scriptname> */ if (!client_read_string_args(cmd, 1, &scriptname)) @@ -102,26 +98,27 @@ bool cmd_getscript(struct client_command_context *cmd) ctx->client = client; ctx->storage = client->storage; ctx->failed = FALSE; - ctx->exists = TRUE; - ctx->script = sieve_storage_script_init(client->storage, scriptname, &ctx->exists); + ctx->script = sieve_storage_script_init(client->storage, scriptname); if (ctx->script == NULL) { ctx->failed = TRUE; return cmd_getscript_finish(ctx); } - ctx->script_stream = sieve_script_open(ctx->script, &deleted_r); + ctx->script_stream = sieve_script_open(ctx->script, &error); if ( ctx->script_stream == NULL ) { ctx->failed = TRUE; - ctx->exists = !deleted_r; + if ( error == SIEVE_ERROR_NOT_FOUND ) + sieve_storage_set_error(client->storage, error, "Script does not exist."); return cmd_getscript_finish(ctx); } ctx->script_size = sieve_script_get_size(ctx->script); ctx->script_offset = 0; - client_send_line(client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->script_size)); + client_send_line + (client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->script_size)); client->command_pending = TRUE; cmd->func = cmd_getscript_continue; diff --git a/src/managesieve/cmd-putscript.c b/src/managesieve/cmd-putscript.c index 58ca1cf97..844860676 100644 --- a/src/managesieve/cmd-putscript.c +++ b/src/managesieve/cmd-putscript.c @@ -203,7 +203,7 @@ static bool cmd_putscript_finish_parsing(struct client_command_context *cmd) (errors, TRUE, client->set->managesieve_max_compile_errors); /* Compile */ - if ( (sbin=sieve_compile_script(script, ehandler)) == NULL ) { + if ( (sbin=sieve_compile_script(script, ehandler, NULL)) == NULL ) { client_send_no(client, str_c(errors)); success = FALSE; } else { diff --git a/src/managesieve/cmd-renamescript.c b/src/managesieve/cmd-renamescript.c index 4637b2a3b..32a053796 100644 --- a/src/managesieve/cmd-renamescript.c +++ b/src/managesieve/cmd-renamescript.c @@ -16,21 +16,15 @@ bool cmd_renamescript(struct client_command_context *cmd) struct sieve_storage *storage = client->storage; const char *scriptname, *newname; struct sieve_script *script; - bool exists; /* <oldname> <newname> */ if (!client_read_string_args(cmd, 2, &scriptname, &newname)) return FALSE; - exists = TRUE; - script = sieve_storage_script_init(storage, scriptname, &exists); + script = sieve_storage_script_init(storage, scriptname); if (script == NULL) { - if (!exists) - client_send_noresp(client, "NONEXISTENT", "Script does not exist."); - else - client_send_storage_error(client, storage); - + client_send_storage_error(client, storage); return TRUE; } diff --git a/src/managesieve/cmd-setactive.c b/src/managesieve/cmd-setactive.c index 2170273ba..319b62890 100644 --- a/src/managesieve/cmd-setactive.c +++ b/src/managesieve/cmd-setactive.c @@ -14,8 +14,7 @@ bool cmd_setactive(struct client_command_context *cmd) struct client *client = cmd->client; struct sieve_storage *storage = client->storage; const char *scriptname; - struct sieve_script *script; - bool exists; + struct sieve_script *script;; int ret; /* <scriptname> */ @@ -23,15 +22,10 @@ bool cmd_setactive(struct client_command_context *cmd) return FALSE; if ( *scriptname != '\0' ) { - exists = TRUE; - script = sieve_storage_script_init(storage, scriptname, &exists); + script = sieve_storage_script_init(storage, scriptname); if ( script == NULL ) { - if (!exists) - client_send_noresp(client, "NONEXISTENT", "Script does not exist."); - else - client_send_storage_error(client, storage); - + client_send_storage_error(client, storage); return TRUE; } diff --git a/src/managesieve/managesieve-client.c b/src/managesieve/managesieve-client.c index c19b4da88..c6479e2ff 100644 --- a/src/managesieve/managesieve-client.c +++ b/src/managesieve/managesieve-client.c @@ -374,37 +374,37 @@ void client_send_command_error cmd->param_error = TRUE; } -void client_send_storage_error(struct client *client, - struct sieve_storage *storage) +void client_send_storage_error +(struct client *client, struct sieve_storage *storage) { - enum sieve_storage_error error_code; + enum sieve_error error_code; const char *error; error = sieve_storage_get_last_error(storage, &error_code); switch ( error_code ) { - case SIEVE_STORAGE_ERROR_TEMP: + case SIEVE_ERROR_TEMP_FAIL: client_send_noresp(client, "TRYLATER", error); break; - case SIEVE_STORAGE_ERROR_QUOTA: - case SIEVE_STORAGE_ERROR_NOSPACE: /* Not sure if this is appropriate */ + case SIEVE_ERROR_NO_QUOTA: + case SIEVE_ERROR_NO_SPACE: /* Not sure if this is appropriate */ client_send_noresp(client, "QUOTA", error); break; - case SIEVE_STORAGE_ERROR_NOTFOUND: + case SIEVE_ERROR_NOT_FOUND: client_send_noresp(client, "NONEXISTENT", error); break; - case SIEVE_STORAGE_ERROR_ACTIVE: + case SIEVE_ERROR_ACTIVE: client_send_noresp(client, "ACTIVE", error); break; - case SIEVE_STORAGE_ERROR_EXISTS: + case SIEVE_ERROR_EXISTS: client_send_noresp(client, "ALREADYEXISTS", error); break; - case SIEVE_STORAGE_ERROR_IMPOSSIBLE: + case SIEVE_ERROR_NOT_POSSIBLE: default: client_send_no(client, error); break; diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index 669b17b69..c36a6662a 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -121,7 +121,7 @@ struct lda_sieve_run_context { struct sieve_instance *svinst; struct mail_deliver_context *mdctx; - + const char *const *script_files; unsigned int script_count; @@ -143,7 +143,7 @@ static const char *lda_sieve_get_personal_path(struct mail_user *user) if ( mail_user_get_home(user, &home) <= 0 ) home = NULL; - script_path = mail_user_plugin_getenv(user, "sieve"); + script_path = mail_user_plugin_getenv(user, "sieve"); /* userdb may specify Sieve path */ if (script_path != NULL) { @@ -195,48 +195,68 @@ static const char *lda_sieve_get_default_path(struct mail_user *user) return script_path; } -static void lda_sieve_multiscript_get_scriptfiles +static int lda_sieve_multiscript_get_scriptfiles (const char *script_path, ARRAY_TYPE(const_string) *scriptfiles) { - struct sieve_directory *sdir = sieve_directory_open(script_path); + struct sieve_directory *sdir; + enum sieve_error error; + const char *file; - if ( sdir != NULL ) { - const char *file; + if ( (sdir=sieve_directory_open(script_path, &error)) == NULL ) + return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); - while ( (file=sieve_directory_get_scriptfile(sdir)) != NULL ) { - const char *const *scripts; - unsigned int count, i; + while ( (file=sieve_directory_get_scriptfile(sdir)) != NULL ) { + const char *const *scripts; + unsigned int count, i; - /* Insert into sorted array */ + /* Insert into sorted array */ - scripts = array_get(scriptfiles, &count); - for ( i = 0; i < count; i++ ) { - if ( strcmp(file, scripts[i]) < 0 ) - break; - } - - if ( i == count ) - array_append(scriptfiles, &file, 1); - else - array_insert(scriptfiles, i, &file, 1); + scripts = array_get(scriptfiles, &count); + for ( i = 0; i < count; i++ ) { + if ( strcmp(file, scripts[i]) < 0 ) + break; } - sieve_directory_close(&sdir); - } + if ( i == count ) + array_append(scriptfiles, &file, 1); + else + array_insert(scriptfiles, i, &file, 1); + } + + sieve_directory_close(&sdir); + return 1; } -static int lda_sieve_open +static void lda_sieve_binary_save +(struct lda_sieve_run_context *srctx, struct sieve_binary *sbin, + unsigned int script_index) +{ + const char *script_path = srctx->script_files[script_index]; + enum sieve_error error; + + /* Save binary when compiled */ + if ( sieve_save(sbin, NULL, FALSE, &error) < 0 && + error == SIEVE_ERROR_NO_PERM && script_path != srctx->user_script ) { + /* Cannot save binary for global script */ + sieve_sys_error( + "the lda sieve plugin does not have permission " + "to save global sieve script binaries; " + "global sieve scripts like %s need to be " + "pre-compiled using the sievec tool", script_path); + } +} + +static struct sieve_binary *lda_sieve_open (struct lda_sieve_run_context *srctx, unsigned int script_index, - struct sieve_binary **sbin) + enum sieve_error *error_r) { struct sieve_instance *svinst = srctx->svinst; const char *script_path = srctx->script_files[script_index]; const char *script_name = ( script_path == srctx->main_script ? "main_script" : NULL ); struct sieve_error_handler *ehandler; - bool exists = TRUE; + struct sieve_binary *sbin; bool debug = srctx->mdctx->dest_user->mail_debug; - int ret = 0; if ( script_path == srctx->user_script ) ehandler = srctx->user_ehandler; @@ -244,16 +264,14 @@ static int lda_sieve_open ehandler = srctx->master_ehandler; if ( debug ) - sieve_sys_debug("opening script %s", script_path); + sieve_sys_debug("opening script %s", script_path); sieve_error_handler_reset(ehandler); - if ( (*sbin=sieve_open(svinst, script_path, script_name, ehandler, &exists)) + /* Open the sieve script */ + if ( (sbin=sieve_open(svinst, script_path, script_name, ehandler, error_r)) == NULL ) { - - ret = sieve_get_errors(ehandler) > 0 ? -1 : 0; - - if ( !exists && ret == 0 ) { + if ( *error_r == SIEVE_ERROR_NOT_FOUND ) { if ( debug ) sieve_sys_debug("script file %s is missing", script_path); } else { @@ -269,25 +287,27 @@ static int lda_sieve_open } } - return ret; + return NULL; } - return 1; + lda_sieve_binary_save(srctx, sbin, script_index); + return sbin; } static struct sieve_binary *lda_sieve_recompile -(struct lda_sieve_run_context *srctx, unsigned int script_index) +(struct lda_sieve_run_context *srctx, unsigned int script_index, + enum sieve_error *error_r) { struct sieve_instance *svinst = srctx->svinst; const char *script_path = srctx->script_files[script_index]; const char *script_name = ( script_path == srctx->main_script ? "main_script" : NULL ); - struct sieve_error_handler *ehandler; + struct sieve_error_handler *ehandler; struct sieve_binary *sbin; /* Warn */ - sieve_sys_warning("encountered corrupt binary: recompiling script %s", + sieve_sys_warning("encountered corrupt binary: re-compiling script %s", script_path); /* Recompile */ @@ -298,7 +318,7 @@ static struct sieve_binary *lda_sieve_recompile ehandler = srctx->master_ehandler; if ( (sbin=sieve_compile - (svinst, script_path, script_name, ehandler)) == NULL ) { + (svinst, script_path, script_name, ehandler, error_r)) == NULL ) { if ( script_path == srctx->user_script && srctx->userlog != NULL ) { sieve_sys_error @@ -318,7 +338,7 @@ static struct sieve_binary *lda_sieve_recompile static int lda_sieve_handle_exec_status(const char *script_path, int status) { - int ret; + int ret; switch ( status ) { case SIEVE_EXEC_FAILURE: @@ -327,7 +347,7 @@ static int lda_sieve_handle_exec_status(const char *script_path, int status) script_path); ret = 1; break; - case SIEVE_EXEC_BIN_CORRUPT: + case SIEVE_EXEC_BIN_CORRUPT: sieve_sys_error ("!!BUG!!: binary compiled from %s is still corrupt; " "bailing out and reverting to default delivery", @@ -351,21 +371,22 @@ static int lda_sieve_singlescript_execute (struct lda_sieve_run_context *srctx) { const char *script_file = srctx->script_files[0]; - bool user_script = ( script_file == srctx->user_script ); + bool user_script = ( script_file == srctx->user_script ); struct sieve_error_handler *ehandler; struct sieve_binary *sbin; bool debug = srctx->mdctx->dest_user->mail_debug; + enum sieve_error error; int ret; /* Open the script */ - if ( (ret=lda_sieve_open(srctx, 0, &sbin)) <= 0 ) - return ret; + if ( (sbin=lda_sieve_open(srctx, 0, &error)) == NULL ) + return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); /* Execute */ if ( debug ) - sieve_sys_debug("executing compiled script %s", script_file); + sieve_sys_debug("executing script from %s", sieve_get_source(sbin)); if ( user_script ) { ehandler = srctx->user_ehandler; @@ -380,19 +401,21 @@ static int lda_sieve_singlescript_execute /* Recompile if corrupt binary */ - if ( ret == SIEVE_EXEC_BIN_CORRUPT ) { + if ( ret == SIEVE_EXEC_BIN_CORRUPT && sieve_is_loaded(sbin) ) { /* Close corrupt script */ sieve_close(&sbin); /* Recompile */ - if ( (sbin=lda_sieve_recompile(srctx, 0)) == NULL ) { - return -1; - } + if ( (sbin=lda_sieve_recompile(srctx, 0, &error)) == NULL ) + return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); /* Execute again */ + if ( debug ) + sieve_sys_debug("executing script from %s", sieve_get_source(sbin)); + if ( user_script ) sieve_error_handler_copy_masterlog(ehandler, TRUE); @@ -403,7 +426,7 @@ static int lda_sieve_singlescript_execute /* Save new version */ if ( ret != SIEVE_EXEC_BIN_CORRUPT ) - sieve_save(sbin, NULL); + lda_sieve_binary_save(srctx, sbin, 0); } sieve_close(&sbin); @@ -420,11 +443,13 @@ static int lda_sieve_multiscript_execute unsigned int count = srctx->script_count; struct sieve_multiscript *mscript; struct sieve_error_handler *ehandler = srctx->master_ehandler; + bool debug = srctx->mdctx->dest_user->mail_debug; const char *last_script = NULL; bool user_script = FALSE; unsigned int i; int ret = 1; bool more = TRUE; + enum sieve_error error; /* Start execution */ @@ -439,7 +464,7 @@ static int lda_sieve_multiscript_execute bool final = ( i == count - 1 ); user_script = ( script_file == srctx->user_script ); - last_script = script_file; + last_script = script_file; if ( user_script ) ehandler = srctx->user_ehandler; @@ -447,30 +472,35 @@ static int lda_sieve_multiscript_execute ehandler = srctx->master_ehandler; /* Open */ - - if ( (ret=lda_sieve_open(srctx, i, &sbin)) <= 0 ) + + if ( (sbin=lda_sieve_open(srctx, i, &error)) == NULL ) { + ret = ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); break; + } /* Execute */ - if ( user_script ) + if ( user_script ) sieve_error_handler_copy_masterlog(ehandler, TRUE); + if ( debug ) + sieve_sys_debug("executing script from %s", sieve_get_source(sbin)); + more = sieve_multiscript_run(mscript, sbin, ehandler, final); sieve_error_handler_copy_masterlog(ehandler, FALSE); if ( !more ) { - if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT ) { + if ( sieve_multiscript_status(mscript) == SIEVE_EXEC_BIN_CORRUPT && + sieve_is_loaded(sbin) ) { /* Close corrupt script */ sieve_close(&sbin); /* Recompile */ - if ( (sbin=lda_sieve_recompile(srctx, i)) - == NULL ) { - ret = -1; + if ( (sbin=lda_sieve_recompile(srctx, i, &error)) == NULL ) { + ret = ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); break; } @@ -487,7 +517,7 @@ static int lda_sieve_multiscript_execute if ( more && sieve_multiscript_status(mscript) != SIEVE_EXEC_BIN_CORRUPT ) - sieve_save(sbin, NULL); + lda_sieve_binary_save(srctx, sbin, i); } } @@ -496,7 +526,7 @@ static int lda_sieve_multiscript_execute /* Finish execution */ - if ( user_script ) + if ( user_script ) sieve_error_handler_copy_masterlog(ehandler, TRUE); ret = sieve_multiscript_finish(&mscript, ehandler, NULL); @@ -526,7 +556,7 @@ static int lda_sieve_run /* Initialize Sieve engine */ svinst = sieve_init(&lda_sieve_env, mdctx->dest_user, debug); - + /* Initialize */ memset(&srctx, 0, sizeof(srctx)); @@ -611,7 +641,7 @@ static int lda_sieve_run if ( srctx.script_count == 1 ) ret = lda_sieve_singlescript_execute(&srctx); else - ret = lda_sieve_multiscript_execute(&srctx); + ret = lda_sieve_multiscript_execute(&srctx); /* Record status */ @@ -647,7 +677,7 @@ static int lda_sieve_deliver_mail struct stat st; /* Find the personal script to execute */ - + user_script = lda_sieve_get_personal_path(mdctx->dest_user); default_script = lda_sieve_get_default_path(mdctx->dest_user); @@ -677,7 +707,7 @@ static int lda_sieve_deliver_mail if ( debug ) { const char *script = user_script == NULL ? default_script : user_script; - if ( script == NULL ) + if ( script == NULL ) sieve_sys_debug("user has no valid personal script"); else sieve_sys_debug("using sieve path for user's script: %s", script); @@ -692,11 +722,17 @@ static int lda_sieve_deliver_mail sieve_after = mail_user_plugin_getenv(mdctx->dest_user, "sieve_after"); if ( sieve_before != NULL && *sieve_before != '\0' ) { - lda_sieve_multiscript_get_scriptfiles(sieve_before, &scripts_before); + if ( lda_sieve_multiscript_get_scriptfiles + (sieve_before, &scripts_before) == 0 && debug ) { + sieve_sys_debug("sieve_before path not found: %s", sieve_before); + } } if ( sieve_after != NULL && *sieve_after != '\0' ) { - lda_sieve_multiscript_get_scriptfiles(sieve_after, &scripts_after); + if ( lda_sieve_multiscript_get_scriptfiles + (sieve_after, &scripts_after) == 0 && debug ) { + sieve_sys_debug("sieve_after path not found: %s", sieve_after); + } } if ( debug ) { @@ -705,17 +741,17 @@ static int lda_sieve_deliver_mail scriptfiles = array_get(&scripts_before, &count); for ( i = 0; i < count; i ++ ) { - sieve_sys_debug("executed before user's script(%d): %s", - i+1, scriptfiles[i]); + sieve_sys_debug("executed before user's script(%d): %s", + i+1, scriptfiles[i]); } scriptfiles = array_get(&scripts_after, &count); for ( i = 0; i < count; i ++ ) { - sieve_sys_debug("executed after user's script(%d): %s", - i+1, scriptfiles[i]); + sieve_sys_debug("executed after user's script(%d): %s", + i+1, scriptfiles[i]); } } - + /* Check whether there are any scripts to execute */ if ( array_count(&scripts_before) == 0 && array_count(&scripts_after) == 0 && @@ -731,7 +767,7 @@ static int lda_sieve_deliver_mail ret = 0; } else { /* Run the script(s) */ - + ret = lda_sieve_run (mdctx, user_script, default_script, &scripts_before, &scripts_after, storage_r); diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 198e5e09c..3c596c10f 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -215,7 +215,7 @@ int main(int argc, char **argv) if ( force_compile ) { main_sbin = sieve_tool_script_compile(svinst, scriptfile, NULL); if ( main_sbin != NULL ) - (void) sieve_save(main_sbin, NULL); + (void) sieve_save(main_sbin, NULL, TRUE, NULL); } else { main_sbin = sieve_tool_script_open(svinst, scriptfile); } @@ -314,7 +314,7 @@ int main(int argc, char **argv) if ( force_compile ) { sbin = sieve_tool_script_compile(svinst, sfiles[i], sfiles[i]); if ( sbin != NULL ) - (void) sieve_save(sbin, NULL); + (void) sieve_save(sbin, NULL, FALSE, NULL); } else { sbin = sieve_tool_script_open(svinst, sfiles[i]); } diff --git a/src/sieve-tools/sievec.c b/src/sieve-tools/sievec.c index 7fce62c8b..4ad5811a6 100644 --- a/src/sieve-tools/sievec.c +++ b/src/sieve-tools/sievec.c @@ -125,7 +125,7 @@ int main(int argc, char **argv) sbin = sieve_tool_script_compile(svinst, file, dp->d_name); if ( sbin != NULL ) { - sieve_save(sbin, NULL); + sieve_save(sbin, NULL, TRUE, NULL); sieve_close(&sbin); } } @@ -145,7 +145,7 @@ int main(int argc, char **argv) if ( dump ) sieve_tool_dump_binary_to(sbin, outfile); else { - sieve_save(sbin, outfile); + sieve_save(sbin, outfile, TRUE, NULL); } sieve_close(&sbin); diff --git a/src/sieve-tools/sieved.c b/src/sieve-tools/sieved.c index 61747cbc1..b48a8f611 100644 --- a/src/sieve-tools/sieved.c +++ b/src/sieve-tools/sieved.c @@ -74,7 +74,7 @@ int main(int argc, char **argv) (void) sieve_extension_register(svinst, &debug_extension, TRUE); /* Dump binary */ - sbin = sieve_load(svinst, binfile); + sbin = sieve_load(svinst, binfile, NULL); if ( sbin != NULL ) { sieve_tool_dump_binary_to(sbin, outfile == NULL ? "-" : outfile); diff --git a/src/testsuite/testsuite-binary.c b/src/testsuite/testsuite-binary.c index 11485a8cf..c573704b3 100644 --- a/src/testsuite/testsuite-binary.c +++ b/src/testsuite/testsuite-binary.c @@ -61,8 +61,8 @@ void testsuite_binary_reset(void) bool testsuite_binary_save(struct sieve_binary *sbin, const char *name) { - return sieve_save - (sbin, t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name)); + return sieve_save(sbin, + t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name), TRUE, NULL); } struct sieve_binary *testsuite_binary_load(const char *name) @@ -70,7 +70,7 @@ struct sieve_binary *testsuite_binary_load(const char *name) struct sieve_instance *svinst = testsuite_sieve_instance; return sieve_load(svinst, - t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name)); + t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name), NULL); } diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c index fe264f096..c7a7d1577 100644 --- a/src/testsuite/testsuite-script.c +++ b/src/testsuite/testsuite-script.c @@ -65,8 +65,8 @@ static struct sieve_binary *_testsuite_script_compile testsuite_setting_set ("sieve_global_dir", t_strconcat(sieve_dir, "included-global", NULL)); - if ( (sbin = sieve_compile(svinst, script_path, NULL, testsuite_log_ehandler)) - == NULL ) + if ( (sbin = sieve_compile(svinst, script_path, NULL, testsuite_log_ehandler, + NULL)) == NULL ) return NULL; return sbin; diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index dfbaffcf4..089a18cef 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -165,7 +165,7 @@ int main(int argc, char **argv) /* Compile sieve script */ if ( (sbin = sieve_compile - (svinst, scriptfile, NULL, testsuite_log_main_ehandler)) != NULL ) { + (svinst, scriptfile, NULL, testsuite_log_main_ehandler, NULL)) != NULL ) { struct ostream *tracestream = NULL; struct sieve_script_env scriptenv; -- GitLab