~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101901

« back to all changes in this revision

Viewing changes to managesieve/src/lib-sievestorage/sieve-storage-script.c

  • Committer: Chuck Short
  • Date: 2010-01-21 20:21:25 UTC
  • mfrom: (4.1.11 squeeze)
  • Revision ID: zulcss@ubuntu.com-20100121202125-pme73o491kfwj5nc
* Merge from debian testing, remaining changes:
  + Add new binary pkg dovecot-postfix that integrates postfix and dovecot
    automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restriction
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
  + debian/dovecot-postfix.dirs: create backup directory for postfix's config
    configuration
  + restart postfix and dovecot.
  + debian/dovecot-postfix.postrm:
    - remove all dovecot related configuration from postfix.
    - restart postfix and dovecot.
  + debian/dovecot-common.init:
    - check if /etc/dovecot/dovecot-postfix.conf exists and use it
      as the configuration file if so.
  + debian/patches/warning-ubuntu-postfix.dpatch
    - add warning about dovecot-postfix.conf in dovecot default
      configuration file
  + debian/patches/dovecot-postfix.conf.diff:
    - Ubuntu server custom changes to the default dovecot configuration for
      better interfation with postfix.
    - enable sieve plugin.
    - Ubuntu server custom changes to the default dovecot configuration for
      better integration with postfix:
      - enable imap, pop3, imaps, pop3s and managesieve by default.
      - enable dovecot LDA (deliver).
      - enable SASL auth socket in postfix private directory
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules: install profile.
     - debian/control: suggest ufw.
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). (LP: #254721)
   + debian/control: Update Vcs-* headers.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
* New upstream release.
* debian/patches/gold-fix.patch: Removed. Fixed upstream.
* Moved libexec to lib corrections in dovecot-managesieve.patch and
  dovecot-managesieve-dist.patch to dovecot-example.patch
* debian/patches/dovecot-mboxlocking.patch: Regenerated to avoid FTBFS
  when quilt isn't installed.
* debian/patches/quota-mountpoint.patch: Removed. Not needed anymore.
* debian/patches/dovecot-quota.patch: Removed. Quotas aren't properly
  enabled unless mail_plugins = quota imap_quota.
* debian/patches/gold-fix.patch: Fixed configure script to build even
  with binutils-gold or --no-add-needed linker flag (Closes: #554306)
* debian/dovecot-common.init: fixed LSB headers. Thanks to Pascal Volk.
  (Closes: #558040)
* debian/changelog: added CVE references to previous changelog entry.
* debian/rules: checked up the build system. It's not fragile anymore.
  (Closes: 493803)
* debian/dovecot-common.postinst: Now invoking dpkg-reconfigure
  on dovecot-common is enough to generate new certificates
  if the previous ones were removed. (Closes: #545582)
* debian/rules: No longer install convert-tool in /usr/bin.
  It isn't an user utility and it should stay in /usr/lib/dovecot
  like all other similar tool.
* New upstream release. (Closes: #557601)
* [SECURITY] Fixes local information disclosure and denial of service.
  (see: http://www.dovecot.org/list/dovecot-news/2009-November/000143.html
  and CVE-2009-3897)
* Added myself to uploaders.
* Switched to the new source format "3.0 (quilt)":
  - removed dpatch from build-depends
  - removed debian/README.source because now we use only standard
    dpkg features
  - regenerated all patches
* Prepared to switch to multi-origin source:
  - recreated dovecot-libsieve.patch and dovecot-managesieve-dist.patch
    starting from the upstream tarball
  - removed all autotools related build-depends and build-conflict
  - renamed dovecot-libsieve and dovecot-managesieve directories
    to libsieve and managesieve.
* debian/rules: Moved the configuration of libsieve and managesieve from
  the build phase to the configuration phase
* Added dovecot-dbg package  with debugging symbols.  Thanks Stephan Bosch.
  (Closes: #554710)
* Fixed some stray libexec'isms in the default configuration.
* New upstream release.
* debian/dovecot-common.init:
  - use $CONF when starting the daemon. (Closes: #549944)
  - always output start/stop messages. (Closes: #523810)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
 
2
 */
 
3
 
 
4
#include "lib.h"
 
5
#include "mempool.h"
 
6
#include "hostpid.h"
 
7
#include "ioloop.h"
 
8
#include "istream.h"
 
9
#include "file-copy.h"
 
10
 
 
11
#include "sieve-script-private.h"
 
12
 
 
13
#include "sieve-storage.h"
 
14
#include "sieve-storage-private.h"
 
15
#include "sieve-storage-script.h"
 
16
 
 
17
#include <stdio.h>
 
18
#include <stdlib.h>
 
19
#include <unistd.h>
 
20
#include <sys/stat.h>
 
21
#include <ctype.h>
 
22
#include <time.h>
 
23
#include <fcntl.h>
 
24
 
 
25
struct sieve_storage_script {
 
26
        struct sieve_script script;     
 
27
 
 
28
    struct sieve_storage *storage;
 
29
};
 
30
 
 
31
struct sieve_script *sieve_storage_script_init_from_path
 
32
(struct sieve_storage *storage, const char *path, 
 
33
        const char *scriptname, bool *exists_r)
 
34
{
 
35
        pool_t pool;
 
36
        struct sieve_storage_script *st_script = NULL;  
 
37
 
 
38
        /* Prevent initializing the active script link as a script when it
 
39
         * resides in the sieve storage directory.
 
40
         */
 
41
        if ( *(storage->link_path) == '\0' ) {
 
42
                const char *fname;
 
43
 
 
44
                fname = strrchr(path, '/');
 
45
                if ( fname == NULL )
 
46
                        fname = path;
 
47
                else
 
48
                        fname++;
 
49
 
 
50
                if ( strcmp(fname, storage->active_fname) == 0 ) {
 
51
                        if ( exists_r != NULL )
 
52
                                *exists_r = FALSE;
 
53
                        return NULL;
 
54
                }
 
55
        }
 
56
 
 
57
        pool = pool_alloconly_create("sieve_storage_script", 4096);     
 
58
        st_script = p_new(pool, struct sieve_storage_script, 1);
 
59
        st_script->script.pool = pool;
 
60
        st_script->storage = storage;
 
61
 
 
62
        if ( sieve_script_init(&st_script->script, path, scriptname, 
 
63
                sieve_storage_get_error_handler(storage), exists_r) != NULL ) {
 
64
 
 
65
                return &st_script->script;
 
66
        }
 
67
 
 
68
        pool_unref(&pool);
 
69
 
 
70
        return NULL;
 
71
}
 
72
 
 
73
struct sieve_script *sieve_storage_script_init
 
74
(struct sieve_storage *storage, const char *scriptname, bool *exists_r)
 
75
{       
 
76
        struct sieve_script *script;
 
77
        const char *path;
 
78
 
 
79
        /* Disallow '/' characters in script name */    
 
80
        if ( strchr(scriptname, '/') != NULL ) {
 
81
                sieve_storage_set_error(storage, 
 
82
                        SIEVE_STORAGE_ERROR_IMPOSSIBLE,
 
83
                        "Invalid script name '%s'.", scriptname);
 
84
                return NULL;
 
85
        }
 
86
 
 
87
        T_BEGIN {
 
88
                path = t_strconcat( storage->dir, "/", scriptname, ".sieve", NULL );
 
89
 
 
90
                script = sieve_storage_script_init_from_path
 
91
                        (storage, path, NULL, exists_r);
 
92
        } T_END;
 
93
 
 
94
        return script;
 
95
}
 
96
 
 
97
static struct sieve_script *sieve_storage_script_init_from_file
 
98
(struct sieve_storage *storage, const char *scriptfile, bool *exists_r)
 
99
{       
 
100
        struct sieve_script *script;
 
101
        const char *path;
 
102
 
 
103
        T_BEGIN {
 
104
                path = t_strconcat( storage->dir, "/", scriptfile, NULL );
 
105
 
 
106
                script = sieve_storage_script_init_from_path
 
107
                        (storage, path, NULL, exists_r);
 
108
        } T_END;
 
109
 
 
110
        return script;
 
111
}
 
112
 
 
113
const char *sieve_storage_file_get_scriptname
 
114
(const struct sieve_storage *storage ATTR_UNUSED, const char *filename)
 
115
{
 
116
        const char *ext;
 
117
 
 
118
        ext = strrchr(filename, '.');
 
119
 
 
120
        if ( ext == NULL || ext == filename || strcmp(ext,".sieve") != 0 ) 
 
121
                return NULL;
 
122
        
 
123
        return t_strdup_until(filename, ext);
 
124
}
 
125
 
 
126
static const char *sieve_storage_read_active_link
 
127
(struct sieve_storage *storage, bool *not_link)
 
128
{
 
129
  char linkbuf[PATH_MAX];
 
130
  int ret;
 
131
 
 
132
        if ( not_link != NULL )
 
133
                *not_link = FALSE;
 
134
 
 
135
        ret = readlink(storage->active_path, linkbuf, sizeof(linkbuf));
 
136
 
 
137
        if ( ret < 0 ) {
 
138
                if (errno == EINVAL) {
 
139
                        /* Our symlink is no symlink. Report 'no active script'.
 
140
                         * Activating a script will automatically resolve this, so
 
141
                         * there is no need to panic on this one.
 
142
                         */
 
143
                        i_warning
 
144
                          ("sieve-storage: Active sieve script symlink %s is no symlink.",
 
145
                           storage->active_path);
 
146
                        if ( not_link != NULL )
 
147
                                *not_link = TRUE;
 
148
                        return "";
 
149
                }
 
150
 
 
151
                if (errno != ENOENT ) {
 
152
                        /* We do need to panic otherwise */
 
153
                        sieve_storage_set_critical
 
154
                          (storage,
 
155
                                "Performing readlink() on active sieve symlink '%s' failed: %m", 
 
156
                                        storage->active_path);
 
157
                        return NULL;
 
158
                }
 
159
 
 
160
                return "";
 
161
        }
 
162
 
 
163
        /* ret is now assured to be valid, i.e. > 0 */
 
164
        return t_strndup(linkbuf, ret);
 
165
}
 
166
 
 
167
static const char *sieve_storage_parse_link
 
168
(struct sieve_storage *storage, const char *link)
 
169
{
 
170
        const char *fname, *scriptname, *scriptpath;
 
171
 
 
172
        /* Split link into path and filename */
 
173
        fname = strrchr(link, '/');
 
174
        if ( fname != NULL ) {
 
175
                scriptpath = t_strdup_until(link, fname+1);
 
176
                fname++;
 
177
        } else {
 
178
                scriptpath = "";
 
179
                fname = link;
 
180
        }
 
181
 
 
182
        /* Check the script name */
 
183
        scriptname = sieve_storage_file_get_scriptname(storage, fname);
 
184
 
 
185
        /* Warn if link is deemed to be invalid */
 
186
        if ( scriptname == NULL ) {
 
187
                i_warning
 
188
                        ("sieve-storage: Active sieve script symlink %s is broken: "
 
189
                                "invalid scriptname (points to %s).",
 
190
                                storage->active_path, link);
 
191
                return NULL;
 
192
        }
 
193
 
 
194
        /* Check whether the path is any good */
 
195
        if ( strcmp(scriptpath, storage->link_path) != 0 &&
 
196
                strcmp(scriptpath, storage->dir) != 0 ) {
 
197
                i_warning
 
198
                        ("sieve-storage: Active sieve script symlink %s is broken: "
 
199
                                "invalid/unknown path to storage (points to %s).",
 
200
                                storage->active_path, link);
 
201
                return NULL; 
 
202
        }
 
203
 
 
204
        return fname;
 
205
}
 
206
 
 
207
const char *sieve_storage_get_active_scriptfile
 
208
(struct sieve_storage *storage)
 
209
{
 
210
        const char *link, *scriptfile;
 
211
 
 
212
        /* Read the active link */
 
213
        link = sieve_storage_read_active_link(storage, NULL);
 
214
 
 
215
        if ( link == NULL || *link == '\0' ) 
 
216
                return link;
 
217
 
 
218
        /* Parse the link */
 
219
        scriptfile = sieve_storage_parse_link(storage, link);
 
220
 
 
221
        if (scriptfile == NULL) {
 
222
                /* Obviously someone has been playing with our symlink,
 
223
                 * ignore this situation and report 'no active script'.
 
224
                 * Activation should fix this situation.
 
225
                 */
 
226
                return "";
 
227
        }
 
228
 
 
229
        return scriptfile;
 
230
}
 
231
 
 
232
struct sieve_script *sieve_storage_get_active_script
 
233
(struct sieve_storage *storage, bool *no_active)
 
234
{
 
235
        bool exists, no_link;
 
236
        struct sieve_script *script;
 
237
        const char *scriptfile, *link;
 
238
 
 
239
        *no_active = FALSE;
 
240
 
 
241
        /* Read the active link */
 
242
        link = sieve_storage_read_active_link(storage, &no_link);
 
243
        
 
244
        if ( link == NULL )
 
245
                /* Error */
 
246
                return NULL;
 
247
 
 
248
        if ( *link == '\0' )
 
249
        {
 
250
                if (no_link) {
 
251
                        /* Try to open the active_path as a regular file */
 
252
                        return sieve_storage_script_init_from_path
 
253
                                (storage, storage->active_path, NULL, NULL);
 
254
                }
 
255
 
 
256
                *no_active = TRUE;
 
257
                return NULL;
 
258
        }
 
259
 
 
260
        /* Parse the link */
 
261
        scriptfile = sieve_storage_parse_link(storage, link);
 
262
 
 
263
        if (scriptfile == NULL) {
 
264
                /* Obviously someone has been playing with our symlink,
 
265
                 * ignore this situation and report 'no active script'.
 
266
                 */
 
267
                *no_active = TRUE;
 
268
                return NULL;
 
269
        }
 
270
        
 
271
        exists = TRUE;
 
272
        script = sieve_storage_script_init_from_file(storage, scriptfile, &exists);     
 
273
 
 
274
        if ( !exists ) {
 
275
                i_warning
 
276
                  ("sieve-storage: Active sieve script symlink %s "
 
277
                   "points to non-existent script (points to %s).",
 
278
                   storage->active_path, link);
 
279
        }
 
280
        
 
281
        *no_active = !exists;
 
282
        return script;
 
283
}
 
284
 
 
285
int sieve_storage_script_is_active(struct sieve_script *script)
 
286
{
 
287
        struct sieve_storage_script *st_script = (struct sieve_storage_script *) script;
 
288
        const char *afile;
 
289
        int ret = 0;
 
290
 
 
291
        T_BEGIN {
 
292
                afile = sieve_storage_get_active_scriptfile(st_script->storage);
 
293
        
 
294
                if (afile == NULL) {
 
295
                        /* Critical error */
 
296
                        ret = -1;
 
297
                } else {
 
298
                        /* Is the requested script active? */
 
299
                        if ( strcmp(script->filename, afile) == 0 ) 
 
300
                                ret = 1;
 
301
                }
 
302
        } T_END;
 
303
 
 
304
        return ret;
 
305
}
 
306
 
 
307
int sieve_storage_script_delete(struct sieve_script **script) 
 
308
{
 
309
        struct sieve_storage_script *st_script = (struct sieve_storage_script *) *script;
 
310
        struct sieve_storage *storage = st_script->storage;
 
311
        int ret = 0;
 
312
 
 
313
        /* Is the requested script active? */
 
314
        if ( sieve_storage_script_is_active(*script) ) {
 
315
                sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_ACTIVE,
 
316
                        "Cannot delete the active sieve script.");
 
317
                ret = -1;
 
318
        } else {
 
319
                ret = unlink((*script)->path);
 
320
 
 
321
                if ( ret < 0 ) {
 
322
                        if ( errno == ENOENT ) 
 
323
                                sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOTFOUND,
 
324
                                        "Sieve script does not exist.");
 
325
                        else
 
326
                                sieve_storage_set_critical(
 
327
                                        storage, "Performing unlink() failed on sieve file '%s': %m", 
 
328
                                        (*script)->path);
 
329
                }       
 
330
        }
 
331
 
 
332
        /* Always deinitialize the script object */
 
333
        sieve_script_unref(script);
 
334
 
 
335
        return ret;     
 
336
}
 
337
 
 
338
static bool sieve_storage_rescue_regular_file(struct sieve_storage *storage)
 
339
{
 
340
        struct stat st;
 
341
        
 
342
        /* Stat the file */
 
343
        if ( lstat(storage->active_path, &st) != 0 ) {
 
344
                if ( errno != ENOENT ) {
 
345
                        sieve_storage_set_critical(storage, 
 
346
                                "Failed to stat active sieve script symlink (%s): %m.", 
 
347
                                storage->active_path); 
 
348
                        return FALSE;   
 
349
                } 
 
350
                return TRUE;
 
351
        }
 
352
 
 
353
        if ( S_ISLNK( st.st_mode ) ) {
 
354
                if ( getenv("DEBUG") != NULL )
 
355
                i_info( "sieve-storage: nothing to rescue %s.", storage->active_path);
 
356
        return TRUE; /* Nothing to rescue */
 
357
        }
 
358
 
 
359
        /* Only regular files can be rescued */
 
360
        if ( S_ISREG( st.st_mode ) ) {
 
361
                const char *dstpath;
 
362
                bool result = TRUE;
 
363
 
 
364
                T_BEGIN {
 
365
 
 
366
                        dstpath = t_strconcat
 
367
                                ( storage->dir, "/dovecot.orig.sieve", NULL );
 
368
                        if ( file_copy(storage->active_path, dstpath, 1) < 1 ) {
 
369
                                sieve_storage_set_critical(storage, 
 
370
                                        "Active sieve script file '%s' is a regular file and copying it to the "
 
371
                                        "script storage as '%s' failed. This needs to be fixed manually.",
 
372
                                                storage->active_path, dstpath);
 
373
                                result = FALSE; 
 
374
                        } else {
 
375
                                i_info("sieve-storage: Moved active sieve script file '%s' "
 
376
                                        "to script storage as '%s'.",
 
377
                                        storage->active_path, dstpath); 
 
378
                }
 
379
                } T_END;
 
380
 
 
381
                return result;
 
382
        }
 
383
 
 
384
        sieve_storage_set_critical( storage,
 
385
                "Active sieve script file '%s' is no symlink nor a regular file. "
 
386
                "This needs to be fixed manually.", storage->active_path );
 
387
        return FALSE;   
 
388
}
 
389
 
 
390
int sieve_storage_deactivate(struct sieve_storage *storage)
 
391
{
 
392
        int ret;
 
393
 
 
394
        if ( !sieve_storage_rescue_regular_file(storage) ) 
 
395
                return -1;
 
396
 
 
397
        /* Delete the symlink, so no script is active */
 
398
        ret = unlink(storage->active_path);
 
399
 
 
400
        if ( ret < 0 ) {
 
401
                if ( errno != ENOENT ) {
 
402
                        sieve_storage_set_critical(storage, "sieve_storage_deactivate(): "
 
403
                                "error on unlink(%s): %m", storage->active_path);
 
404
                        return -1;
 
405
                } else 
 
406
                        return 0;
 
407
        } 
 
408
 
 
409
        return 1;
 
410
}
 
411
 
 
412
static int sieve_storage_replace_active_link
 
413
        (struct sieve_storage *storage, const char *link_path)
 
414
{
 
415
        const char *active_path_new;
 
416
        struct timeval *tv, tv_now;
 
417
        int ret = 0;    
 
418
 
 
419
        tv = &ioloop_timeval;
 
420
 
 
421
        for (;;) {      
 
422
                /* First the new symlink is created with a different filename */
 
423
                active_path_new = t_strdup_printf
 
424
                        ("%s-new.%s.P%sM%s.%s.sieve",
 
425
                                storage->active_path,
 
426
                                dec2str(tv->tv_sec), my_pid,
 
427
                                dec2str(tv->tv_usec), my_hostname);
 
428
 
 
429
                ret = symlink(link_path, active_path_new);
 
430
                
 
431
                if ( ret < 0 ) {
 
432
                        /* If link exists we try again later */
 
433
                        if ( errno == EEXIST ) {
 
434
                                /* Wait and try again - very unlikely */
 
435
                                sleep(2);
 
436
                                tv = &tv_now;
 
437
                                if (gettimeofday(&tv_now, NULL) < 0)
 
438
                                        i_fatal("gettimeofday(): %m");
 
439
                                continue;
 
440
                        }
 
441
 
 
442
                        /* Other error, critical */
 
443
                        sieve_storage_set_critical
 
444
                                (storage, "Creating symlink() %s to %s failed: %m", 
 
445
                                active_path_new, link_path);
 
446
                        return -1;
 
447
                }
 
448
        
 
449
                /* Link created */
 
450
                break;
 
451
        }
 
452
 
 
453
        /* Replace the existing link. This activates the new script */
 
454
        ret = rename(active_path_new, storage->active_path);
 
455
 
 
456
        if ( ret < 0 ) {
 
457
                /* Failed; created symlink must be deleted */
 
458
                (void)unlink(active_path_new);
 
459
                sieve_storage_set_critical
 
460
                        (storage, "Performing rename() %s to %s failed: %m", 
 
461
                        active_path_new, storage->active_path);
 
462
                return -1;
 
463
        }       
 
464
 
 
465
        return 1;
 
466
}
 
467
 
 
468
static int _sieve_storage_script_activate(struct sieve_script *script)
 
469
{
 
470
        struct sieve_storage_script *st_script = (struct sieve_storage_script *) script;
 
471
        struct sieve_storage *storage = st_script->storage;
 
472
        struct stat st;
 
473
        const char *link_path, *afile;
 
474
        int activated = 0;
 
475
        int ret;
 
476
 
 
477
        /* Find out whether there is an active script, but recreate
 
478
         * the symlink either way. This way, any possible error in the symlink
 
479
         * resolves automatically. This step is only necessary to provide a
 
480
         * proper return value indicating whether the script was already active.
 
481
         */
 
482
        afile = sieve_storage_get_active_scriptfile(storage);
 
483
 
 
484
        /* Is the requested script already active? */
 
485
        if ( afile == NULL || strcmp(script->filename, afile) != 0 ) 
 
486
                activated = 1; 
 
487
 
 
488
        /* Check the scriptfile we are trying to activate */
 
489
        if ( lstat(script->path, &st) != 0 ) {
 
490
                sieve_storage_set_critical(storage, 
 
491
                  "Stat on sieve script %s failed, but it is to be activated: %m.", 
 
492
                        script->path);
 
493
                return -1;
 
494
        }
 
495
 
 
496
        /* Rescue a possible .dovecot.sieve regular file remaining from old 
 
497
         * installations.
 
498
         */
 
499
        if ( !sieve_storage_rescue_regular_file(storage) ) {
 
500
                /* Rescue failed, manual intervention is necessary */
 
501
                return -1;
 
502
        }
 
503
 
 
504
        /* Just try to create the symlink first */
 
505
        link_path = t_strconcat
 
506
          ( storage->link_path, script->filename, NULL );
 
507
                
 
508
        ret = symlink(link_path, storage->active_path);
 
509
 
 
510
        if ( ret < 0 ) {
 
511
                if ( errno == EEXIST ) {
 
512
                        ret = sieve_storage_replace_active_link(storage, link_path);
 
513
                        if ( ret < 0 ) {
 
514
                                return ret;
 
515
                        }
 
516
                } else {
 
517
                        /* Other error, critical */
 
518
                        sieve_storage_set_critical
 
519
                                (storage,
 
520
                                        "Creating symlink() %s to %s failed: %m",
 
521
                                        storage->active_path, link_path);
 
522
                        return -1;
 
523
                }
 
524
        }
 
525
 
 
526
        return activated;
 
527
}
 
528
 
 
529
int sieve_storage_script_activate(struct sieve_script *script)
 
530
{
 
531
        int ret;
 
532
        
 
533
        T_BEGIN { 
 
534
                ret = _sieve_storage_script_activate(script);
 
535
        } T_END;
 
536
 
 
537
        return ret;
 
538
}
 
539
 
 
540
int sieve_storage_script_rename(struct sieve_script *script, const char *newname) 
 
541
{
 
542
        struct sieve_storage_script *st_script = (struct sieve_storage_script *) script;
 
543
        struct sieve_storage *storage = st_script->storage;
 
544
        const char *newpath, *newfile, *link_path;
 
545
        int ret = 0;
 
546
 
 
547
        /* Disallow '/' characters in script name */
 
548
        if ( strchr(newname, '/') != NULL ) {
 
549
                sieve_storage_set_error(storage, 
 
550
                        SIEVE_STORAGE_ERROR_IMPOSSIBLE, 
 
551
                        "Invalid new script name '%s'.", newname);
 
552
                return -1;
 
553
        }
 
554
 
 
555
        T_BEGIN {
 
556
                newfile = t_strconcat( newname, ".sieve", NULL );
 
557
                newpath = t_strconcat( storage->dir, "/", newfile, NULL );
 
558
 
 
559
                /* The normal rename() system call overwrites the existing file without notice. 
 
560
                 * Also, active scripts must not be disrupted by renaming a script. That is why
 
561
                 * we use a link(newpath) [activate newpath] unlink(oldpath)
 
562
                 */
 
563
 
 
564
                /* Link to the new path */
 
565
                ret = link(script->path, newpath);
 
566
                if ( ret >= 0 ) {
 
567
                        /* Is the requested script active? */
 
568
                        if ( sieve_storage_script_is_active(script) ) {
 
569
                                /* Active; make active link point to the new copy */
 
570
                                link_path = t_strconcat
 
571
                                        ( storage->link_path, newfile, NULL );
 
572
 
 
573
                                ret = sieve_storage_replace_active_link(storage, link_path);
 
574
                        }
 
575
 
 
576
                        if ( ret >= 0 ) {
 
577
                                /* If all is good, remove the old link */
 
578
                                if ( unlink(script->path) < 0 ) {
 
579
                                        i_error("Failed to clean up old file link '%s' after rename: %m", 
 
580
                                                script->path);
 
581
                                }
 
582
 
 
583
                                if ( script->name != NULL && *script->name != '\0' )
 
584
                                        script->name = p_strdup(script->pool, newname);
 
585
                                script->path = p_strdup(script->pool, newpath);
 
586
                                script->filename = p_strdup(script->pool, newfile);
 
587
                                script->basename = p_strdup(script->pool, newname);
 
588
                        } else {
 
589
                                /* If something went wrong, remove the new link to restore previous state */
 
590
                                if ( unlink(newpath) < 0 ) {
 
591
                                        i_error("Failed to clean up new file link '%s'"
 
592
                                                " after failed rename: %m", newpath);
 
593
                                }
 
594
                        }
 
595
                } else {
 
596
                        /* Our efforts failed right away */
 
597
                        switch ( errno ) {
 
598
                        case ENOENT: 
 
599
                                sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_NOTFOUND, 
 
600
                                        "Sieve script does not exist.");
 
601
                                break;
 
602
                        case EEXIST:
 
603
                                sieve_storage_set_error(storage, SIEVE_STORAGE_ERROR_EXISTS,
 
604
                                        "A sieve script with that name already exists.");
 
605
                                break;
 
606
                        default:
 
607
                                sieve_storage_set_critical(
 
608
                                        storage, "Performing link(%s, %s) failed: %m", 
 
609
                                                script->path, newpath);
 
610
                        }                               
 
611
                }
 
612
        } T_END;
 
613
 
 
614
        return ret;     
 
615
}
 
616
 
 
617