~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file
 
2
 */
 
3
 
 
4
#include "lib.h"
 
5
#include "array.h"
 
6
#include "buffer.h"
 
7
#include "str.h"
 
8
#include "str-sanitize.h"
 
9
#include "istream.h"
 
10
#include "ostream.h"
 
11
#include "safe-mkstemp.h"
 
12
#include "mail-user.h"
 
13
 
 
14
#include "sieve-common.h"
 
15
#include "sieve-stringlist.h"
 
16
#include "sieve-binary.h"
 
17
#include "sieve-code.h"
 
18
#include "sieve-message.h"
 
19
#include "sieve-extensions.h"
 
20
#include "sieve-commands.h"
 
21
#include "sieve-actions.h"
 
22
#include "sieve-validator.h"
 
23
#include "sieve-generator.h"
 
24
#include "sieve-interpreter.h"
 
25
#include "sieve-dump.h"
 
26
#include "sieve-result.h"
 
27
 
 
28
#include "sieve-ext-variables.h"
 
29
 
 
30
#include "sieve-extprograms-common.h"
 
31
 
 
32
/* Filter command
 
33
 *
 
34
 * Syntax:
 
35
 *   "filter" <program-name: string> [<arguments: string-list>]
 
36
 *
 
37
 */
 
38
 
 
39
static bool cmd_filter_generate
 
40
        (const struct sieve_codegen_env *cgenv, 
 
41
                struct sieve_command *ctx);
 
42
 
 
43
const struct sieve_command_def cmd_filter = {
 
44
        "filter",
 
45
        SCT_HYBRID,
 
46
        -1, /* We check positional arguments ourselves */
 
47
        0, FALSE, FALSE,
 
48
        NULL, NULL,
 
49
        sieve_extprogram_command_validate,
 
50
        NULL,
 
51
        cmd_filter_generate,
 
52
        NULL,
 
53
};
 
54
 
 
55
/* 
 
56
 * Filter operation 
 
57
 */
 
58
 
 
59
static bool cmd_filter_operation_dump
 
60
        (const struct sieve_dumptime_env *denv, sieve_size_t *address);
 
61
static int cmd_filter_operation_execute
 
62
        (const struct sieve_runtime_env *renv, sieve_size_t *address);
 
63
 
 
64
const struct sieve_operation_def cmd_filter_operation = { 
 
65
        "FILTER", &filter_extension, 
 
66
        0,
 
67
        cmd_filter_operation_dump, 
 
68
        cmd_filter_operation_execute
 
69
};
 
70
 
 
71
/*
 
72
 * Code generation
 
73
 */
 
74
 
 
75
static bool cmd_filter_generate
 
76
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 
77
{
 
78
        sieve_operation_emit(cgenv->sblock, cmd->ext, &cmd_filter_operation);
 
79
 
 
80
        /* Emit is_test flag */
 
81
        sieve_binary_emit_byte(cgenv->sblock, ( cmd->ast_node->type == SAT_TEST ));
 
82
 
 
83
        /* Generate arguments */
 
84
        if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
 
85
                return FALSE;
 
86
 
 
87
        /* Emit a placeholder when the <arguments> argument is missing */
 
88
        if ( sieve_ast_argument_next(cmd->first_positional) == NULL )
 
89
                sieve_opr_omitted_emit(cgenv->sblock);
 
90
 
 
91
        return TRUE;
 
92
}
 
93
 
 
94
/* 
 
95
 * Code dump
 
96
 */
 
97
 
 
98
static bool cmd_filter_operation_dump
 
99
(const struct sieve_dumptime_env *denv, sieve_size_t *address)
 
100
{       
 
101
        unsigned int is_test = 0;
 
102
 
 
103
        /* Read is_test flag */
 
104
        if ( !sieve_binary_read_byte(denv->sblock, address, &is_test) )
 
105
                return FALSE;
 
106
 
 
107
        sieve_code_dumpf(denv, "FILTER (%s)", (is_test ? "test" : "command"));
 
108
        sieve_code_descend(denv);               
 
109
 
 
110
        /* Dump optional operands */
 
111
        if ( sieve_action_opr_optional_dump(denv, address, NULL) != 0 )
 
112
                return FALSE;
 
113
 
 
114
        if ( !sieve_opr_string_dump(denv, address, "program-name") )
 
115
                return FALSE;
 
116
 
 
117
        return sieve_opr_stringlist_dump_ex(denv, address, "arguments", "");
 
118
}
 
119
 
 
120
/* 
 
121
 * Code execution
 
122
 */
 
123
 
 
124
static int cmd_filter_get_tempfile
 
125
(const struct sieve_runtime_env *renv)
 
126
{
 
127
        struct sieve_instance *svinst = renv->svinst;
 
128
        struct mail_user *mail_user = renv->scriptenv->user;
 
129
        string_t *path;
 
130
        int fd;
 
131
 
 
132
        path = t_str_new(128);
 
133
        mail_user_set_get_temp_prefix(path, mail_user->set);
 
134
        fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
 
135
        if (fd == -1) {
 
136
                sieve_sys_error(svinst, "filter action: "
 
137
                        "safe_mkstemp(%s) failed: %m", str_c(path));
 
138
                return -1;
 
139
        }
 
140
 
 
141
        /* We just want the fd, unlink it */
 
142
        if (unlink(str_c(path)) < 0) {
 
143
                /* Shouldn't happen.. */
 
144
                sieve_sys_error(svinst, "filter action: "
 
145
                        "unlink(%s) failed: %m", str_c(path));
 
146
                if ( close(fd) < 0 ) {
 
147
                        sieve_sys_error(svinst, "filter action: "
 
148
                                "close(%s) failed after error: %m", str_c(path));
 
149
                }
 
150
                return -1;
 
151
        }
 
152
 
 
153
        return fd;
 
154
}
 
155
 
 
156
static int cmd_filter_operation_execute
 
157
(const struct sieve_runtime_env *renv, sieve_size_t *address)
 
158
{       
 
159
        const struct sieve_extension *this_ext = renv->oprtn->ext;
 
160
        unsigned int is_test = 0;
 
161
        struct sieve_stringlist *args_list = NULL;
 
162
        enum sieve_error error = SIEVE_ERROR_NONE;
 
163
        string_t *pname = NULL;
 
164
        const char *program_name = NULL;
 
165
        const char *const *args = NULL;
 
166
        int tmp_fd = -1;
 
167
        int ret;
 
168
 
 
169
        /*
 
170
         * Read operands
 
171
         */
 
172
 
 
173
        /* The is_test flag */
 
174
 
 
175
        if ( !sieve_binary_read_byte(renv->sblock, address, &is_test) ) {
 
176
                sieve_runtime_trace_error(renv, "invalid is_test flag");
 
177
                return SIEVE_EXEC_BIN_CORRUPT;
 
178
        }
 
179
 
 
180
        /* Optional operands */ 
 
181
 
 
182
        if ( sieve_action_opr_optional_read(renv, address, NULL, &ret, NULL) != 0 ) 
 
183
                return ret;
 
184
 
 
185
        /* Fixed operands */
 
186
 
 
187
        if ( (ret=sieve_extprogram_command_read_operands
 
188
                (renv, address, &pname, &args_list)) <= 0 )
 
189
                return ret;
 
190
 
 
191
        program_name = str_c(pname);
 
192
        if ( args_list != NULL &&
 
193
                sieve_stringlist_read_all(args_list, pool_datastack_create(), &args) < 0 ) {
 
194
                sieve_runtime_trace_error(renv, "failed to read args operand");
 
195
                return args_list->exec_status;
 
196
        }
 
197
 
 
198
        /*
 
199
         * Perform operation
 
200
         */
 
201
 
 
202
        /* Trace */
 
203
 
 
204
        sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action");
 
205
        sieve_runtime_trace_descend(renv);
 
206
        sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS,
 
207
                "execute program `%s'", str_sanitize(program_name, 128));
 
208
 
 
209
        ret = 1;
 
210
        if ( (tmp_fd=cmd_filter_get_tempfile(renv)) < 0 ) {
 
211
                ret = -1;
 
212
        }
 
213
 
 
214
        if ( ret > 0 ) {
 
215
                struct sieve_extprogram *sprog = sieve_extprogram_create
 
216
                        (this_ext, renv->scriptenv, renv->msgdata, "filter", program_name, args,
 
217
                                &error);
 
218
 
 
219
                if ( sprog != NULL && sieve_extprogram_set_input_mail
 
220
                        (sprog, sieve_message_get_mail(renv->msgctx)) >= 0 ) {
 
221
                        struct ostream *outdata =
 
222
                                o_stream_create_fd(tmp_fd, 0, FALSE);
 
223
                        sieve_extprogram_set_output(sprog, outdata);
 
224
                        o_stream_unref(&outdata);
 
225
                
 
226
                        ret = sieve_extprogram_run(sprog);
 
227
                } else {
 
228
                        ret = -1;
 
229
                }
 
230
        
 
231
                if ( sprog != NULL )
 
232
                        sieve_extprogram_destroy(&sprog);
 
233
        }
 
234
 
 
235
        if ( ret > 0 ) {
 
236
                struct istream *newmsg;
 
237
 
 
238
                sieve_runtime_trace(renv,       SIEVE_TRLVL_ACTIONS,
 
239
                        "executed program successfully");
 
240
 
 
241
                newmsg = i_stream_create_fd(tmp_fd, (size_t)-1, TRUE);
 
242
 
 
243
                if ( (ret=sieve_message_substitute(renv->msgctx, newmsg)) >= 0 ) {
 
244
                        sieve_runtime_trace(renv,       SIEVE_TRLVL_ACTIONS,
 
245
                                "changed message");
 
246
                } else {
 
247
                        sieve_runtime_critical(renv, NULL, "filter action",
 
248
                                "filter action: failed to substitute message"); 
 
249
                }
 
250
 
 
251
                i_stream_unref(&newmsg);
 
252
 
 
253
        } else {
 
254
                if ( tmp_fd >= 0 ) {
 
255
                        if ( close(tmp_fd) < 0 ) {
 
256
                                sieve_sys_error
 
257
                                        (renv->svinst, "filter action: close(temp_file) failed: %m");
 
258
                        }
 
259
                }
 
260
 
 
261
                if ( ret < 0 ) {
 
262
                        if ( error == SIEVE_ERROR_NOT_FOUND ) {
 
263
                                sieve_runtime_error(renv, NULL,
 
264
                                        "filter action: program `%s' not found",
 
265
                                        str_sanitize(program_name, 80));
 
266
                        } else {
 
267
                                sieve_extprogram_exec_error(renv->ehandler,
 
268
                                        sieve_runtime_get_full_command_location(renv),
 
269
                                        "filter action: failed to execute to program `%s'",
 
270
                                        str_sanitize(program_name, 80));
 
271
                        }
 
272
                } else {
 
273
                        sieve_runtime_trace(renv,       SIEVE_TRLVL_ACTIONS,
 
274
                                "filter action: program indicated false result");
 
275
                }
 
276
        }
 
277
 
 
278
        if ( is_test )
 
279
                sieve_interpreter_set_test_result(renv->interp, ( ret > 0 ));
 
280
 
 
281
        return SIEVE_EXEC_OK;
 
282
}
 
283