Example #1
0
struct sieve_binary *sieve_open_script
(struct sieve_script *script, struct sieve_error_handler *ehandler,
	enum sieve_compile_flags flags, enum sieve_error *error_r)
{
	struct sieve_instance *svinst = sieve_script_svinst(script);
	struct sieve_binary *sbin;

	T_BEGIN {
		/* Then try to open the matching binary */
		sbin = sieve_script_binary_load(script, error_r);

		if (sbin != NULL) {
			/* Ok, it exists; now let's see if it is up to date */
			if ( !sieve_binary_up_to_date(sbin, flags) ) {
				/* Not up to date */
				if ( svinst->debug ) {
					sieve_sys_debug(svinst, "Script binary %s is not up-to-date",
						sieve_binary_path(sbin));
				}

				sieve_binary_unref(&sbin);
				sbin = NULL;
			}
		}

		/* If the binary does not exist or is not up-to-date, we need
		 * to (re-)compile.
		 */
		if ( sbin != NULL ) {
			if ( svinst->debug ) {
				sieve_sys_debug(svinst,
					"Script binary %s successfully loaded",
					sieve_binary_path(sbin));
			}

		} else {
			sbin = sieve_compile_script(script, ehandler, flags, error_r);

			if ( sbin != NULL ) {
				if ( svinst->debug ) {
					sieve_sys_debug(svinst,
						"Script `%s' from %s successfully compiled",
						sieve_script_name(script), sieve_script_location(script));
				}
			}
		}
	} T_END;

	return sbin;
}
Example #2
0
struct sieve_binary *sieve_compile
(struct sieve_instance *svinst, const char *script_location,
	const char *script_name, struct sieve_error_handler *ehandler,
	enum sieve_compile_flags flags, enum sieve_error *error_r)
{
	struct sieve_script *script;
	struct sieve_binary *sbin;
	enum sieve_error error;

	if ( (script = sieve_script_create_open
		(svinst, script_location, script_name, &error)) == NULL ) {
		if (error_r != NULL)
			*error_r = error;
		switch ( error ) {
		case SIEVE_ERROR_NOT_FOUND:
			sieve_error(ehandler, script_name, "script not found");
			break;
		default:
			sieve_internal_error(ehandler, script_name, "failed to open script");
		}
		return NULL;
	}

	sbin = sieve_compile_script(script, ehandler, flags, error_r);

	if ( svinst->debug && sbin != NULL ) {
		sieve_sys_debug(svinst, "Script `%s' from %s successfully compiled",
			sieve_script_name(script), sieve_script_location(script));
	}

	sieve_script_unref(&script);

	return sbin;
}
struct sieve_extprograms_config *sieve_extprograms_config_init
(const struct sieve_extension *ext)
{
	struct sieve_instance *svinst = ext->svinst;
	struct sieve_extprograms_config *ext_config;
	const char *extname = sieve_extension_name(ext);
	const char *bin_dir, *socket_dir, *input_eol;
	sieve_number_t execute_timeout;

	extname = strrchr(extname, '.');
	i_assert(extname != NULL);
	extname++;

	bin_dir = sieve_setting_get
		(svinst, t_strdup_printf("sieve_%s_bin_dir", extname));
	socket_dir = sieve_setting_get
		(svinst, t_strdup_printf("sieve_%s_socket_dir", extname));
	input_eol = sieve_setting_get
		(svinst, t_strdup_printf("sieve_%s_input_eol", extname));
	
	ext_config = i_new(struct sieve_extprograms_config, 1);
	ext_config->execute_timeout = 
		SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS;

	if ( bin_dir == NULL && socket_dir == NULL ) {
		if ( svinst->debug ) {
			sieve_sys_debug(svinst, "%s extension: "
				"no bin or socket directory specified; extension is unconfigured "
				"(both sieve_%s_bin_dir and sieve_%s_socket_dir are not set)",
				sieve_extension_name(ext), extname, extname);
		}
	} else {
		ext_config->bin_dir = i_strdup(bin_dir);
		ext_config->socket_dir = i_strdup(socket_dir);

		if (sieve_setting_get_duration_value
			(svinst, t_strdup_printf("sieve_%s_exec_timeout", extname),
				&execute_timeout)) {
			ext_config->execute_timeout = execute_timeout;
		}

		ext_config->default_input_eol = SIEVE_EXTPROGRAMS_EOL_CRLF;
		if (input_eol != NULL && strcasecmp(input_eol, "lf") == 0)
			ext_config->default_input_eol = SIEVE_EXTPROGRAMS_EOL_LF;
	}

	if ( sieve_extension_is(ext, vnd_pipe_extension) ) 
		ext_config->copy_ext = sieve_ext_copy_get_extension(ext->svinst);
	if ( sieve_extension_is(ext, vnd_execute_extension) ) 
		ext_config->var_ext = sieve_ext_variables_get_extension(ext->svinst);
	return ext_config;
}
static int _read_extensions(struct sieve_binary_block *sblock)
{
	struct sieve_binary *sbin = sblock->sbin;
	sieve_size_t offset = 0;
	unsigned int i, count;
	bool result = 1;

	if ( !sieve_binary_read_unsigned(sblock, &offset, &count) )
		return -1;

	for ( i = 0; result > 0 && i < count; i++ ) {
		T_BEGIN {
			string_t *extension;
			const struct sieve_extension *ext;
			unsigned int version;

			if ( sieve_binary_read_string(sblock, &offset, &extension) ) {
				ext = sieve_extension_get_by_name(sbin->svinst, str_c(extension));

				if ( ext == NULL ) {
					sieve_sys_error(sbin->svinst,
						"binary open: binary %s requires unknown extension `%s'",
						sbin->path, str_sanitize(str_c(extension), 128));
					result = 0;
				} else {
					struct sieve_binary_extension_reg *ereg = NULL;

					(void) sieve_binary_extension_register(sbin, ext, &ereg);
					if ( !sieve_binary_read_unsigned(sblock, &offset, &version) ||
						!sieve_binary_read_unsigned(sblock, &offset, &ereg->block_id) ) {
						result = -1;
					} else if ( !sieve_extension_version_is(ext, version) ) {
						sieve_sys_debug(sbin->svinst,
							"binary open: binary %s was compiled with different version "
							"of the `%s' extension (compiled v%d, expected v%d;"
							"automatically fixed when re-compiled)", sbin->path,
							sieve_extension_name(ext), version, sieve_extension_version(ext));
						result = 0;
					}
				}
			}	else
				result = -1;
		} T_END;
	}

	return result;
}
Example #5
0
struct sieve_instance *sieve_init
(const struct sieve_environment *env,
	const struct sieve_callbacks *callbacks, void *context, bool debug)
{
	struct sieve_instance *svinst;
	const char *domain;
	pool_t pool;

	/* Create Sieve engine instance */
	pool = pool_alloconly_create("sieve", 8192);
	svinst = p_new(pool, struct sieve_instance, 1);
	svinst->pool = pool;
	svinst->callbacks = callbacks;
	svinst->context = context;
	svinst->debug = debug;
	svinst->base_dir = p_strdup_empty(pool, env->base_dir);
	svinst->username = p_strdup_empty(pool, env->username);
	svinst->home_dir = p_strdup_empty(pool, env->home_dir);
	svinst->temp_dir = p_strdup_empty(pool, env->temp_dir);
	svinst->flags = env->flags;
	svinst->env_location = env->location;
	svinst->delivery_phase = env->delivery_phase;

	/* Determine domain */
	if ( env->domainname != NULL && *(env->domainname) != '\0' ) {
		domain = env->domainname;
	} else {
		/* Fall back to parsing username localpart@domain */
		domain = svinst->username == NULL ? NULL :
			strchr(svinst->username, '@');
		if ( domain == NULL || *(domain+1) == '\0' ) {
			/* Fall back to parsing hostname host.domain */
			domain = ( env->hostname != NULL ? strchr(env->hostname, '.') : NULL );
			if ( domain == NULL || *(domain+1) == '\0'
				|| strchr(domain+1, '.') == NULL ) {
				/* Fall back to bare hostname */
				domain = env->hostname;
			} else {
				domain++;
			}
		} else {
			domain++;
		}
	}
	svinst->hostname = p_strdup_empty(pool, env->hostname);
	svinst->domainname = p_strdup(pool, domain);

	sieve_errors_init(svinst);

	if ( debug ) {
		sieve_sys_debug(svinst, "%s version %s initializing",
			PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL);
	}

	/* Read configuration */

	sieve_settings_load(svinst);

	/* Initialize extensions */
	if ( !sieve_extensions_init(svinst) ) {
		sieve_deinit(&svinst);
		return NULL;
	}

	/* Initialize storage classes */
	sieve_storages_init(svinst);

	/* Initialize plugins */
	sieve_plugins_load(svinst, NULL, NULL);

	/* Configure extensions */
	sieve_extensions_configure(svinst);

	return svinst;
}
static bool _sieve_binary_open(struct sieve_binary *sbin)
{
	bool result = TRUE;
	off_t offset = 0;
	const struct sieve_binary_header *header;
	struct sieve_binary_block *ext_block;
	unsigned int i, blk_count;
	int ret;

	/* Verify header */

	T_BEGIN {
		header = LOAD_HEADER(sbin, &offset, const struct sieve_binary_header);
		/* Check header presence */
		if ( header == NULL ) {
			sieve_sys_error(sbin->svinst,
				"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(sbin->svinst,
					"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(sbin->svinst,
					"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(sbin->svinst,
					"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(sbin->svinst,
				"binary open: binary %s is corrupt: it contains no blocks",
				sbin->path);
			result = FALSE;

		/* Valid */
		} else {
			blk_count = header->blocks;
		}
	} T_END;

	if ( !result ) return FALSE;

	/* Load block index */

	for ( i = 0; i < blk_count && result; i++ ) {
		T_BEGIN {
			if ( !_read_block_index_record(sbin, &offset, i) ) {
				result = FALSE;
			}
		} T_END;
	}

	if ( !result ) return FALSE;

	/* Load extensions used by this binary */

	T_BEGIN {
		ext_block = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_EXTENSIONS);
		if ( ext_block == NULL ) {
			result = FALSE;
		} else if ( (ret=_read_extensions(ext_block)) <= 0 ) {
			if ( ret < 0 ) {
				sieve_sys_error(sbin->svinst,
					"binary open: binary %s is corrupt: failed to load extension block",
					sbin->path);
			}
			result = FALSE;
		}
	} T_END;

	return result;
}
int sieve_binary_save
(struct sieve_binary *sbin, const char *path, bool update, mode_t save_mode,
	enum sieve_error *error_r)
{
	int result, fd;
	string_t *temp_path;
	struct ostream *stream;

	if ( error_r != NULL )
		*error_r = SIEVE_ERROR_NONE;

	/* Check whether saving is necessary */
	if ( !update && sbin->path != NULL && strcmp(sbin->path, path) == 0 ) {
		if ( sbin->svinst->debug ) {
			sieve_sys_debug(sbin->svinst, "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(sbin->svinst,
				"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_PERMISSION;
		} else {
			sieve_sys_error(sbin->svinst,
				"binary save: failed to create temporary file: open(%s) failed: %m",
				str_c(temp_path));
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_TEMP_FAILURE;
		}
		return -1;
	}

	/* Save binary */
	result = 1;
	stream = o_stream_create_fd(fd, 0, FALSE);
	if ( !_sieve_binary_save(sbin, stream) ) {
		result = -1;
		if ( error_r != NULL )
			*error_r = SIEVE_ERROR_TEMP_FAILURE;
	}
	o_stream_destroy(&stream);

	/* Close saved binary */
	if ( close(fd) < 0 ) {
		sieve_sys_error(sbin->svinst,
			"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(sbin->svinst, "binary save: failed to save binary: %s",
				eacces_error_get_creating("rename", path));
			if ( error_r != NULL )
				*error_r = SIEVE_ERROR_NO_PERMISSION;
		} else {
			sieve_sys_error(sbin->svinst, "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_FAILURE;
		}
		result = -1;
	}

	if ( result < 0 ) {
		/* Get rid of temp output (if any) */
		if ( unlink(str_c(temp_path)) < 0 && errno != ENOENT ) {
			sieve_sys_error(sbin->svinst,
				"binary save: failed to clean up after error: unlink(%s) failed: %m",
				str_c(temp_path));
		}
	} else {
		if ( sbin->path == NULL ) {
			sbin->path = p_strdup(sbin->pool, path);
		}
	}

	return result;
}