~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101918

« back to all changes in this revision

Viewing changes to src/lib-storage/index/mbox/mbox-lock.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* 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 restrictions
    - 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 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
   + debian/patches/dovecot-postfix.conf.diff:
     + 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.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
 
4
#include "eacces-error.h"
4
5
#include "restrict-access.h"
5
6
#include "nfs-workarounds.h"
6
7
#include "mail-index-private.h"
14
15
#include <unistd.h>
15
16
#include <fcntl.h>
16
17
#include <sys/stat.h>
 
18
#include <grp.h>
17
19
 
18
20
#ifdef HAVE_FLOCK
19
21
#  include <sys/file.h>
260
262
                                      enum mbox_dotlock_op op)
261
263
{
262
264
        const char *dir, *fname;
263
 
        int ret = -1, orig_dir_fd;
 
265
        int ret = -1, orig_dir_fd, orig_errno;
264
266
 
265
267
        orig_dir_fd = open(".", O_RDONLY);
266
268
        if (orig_dir_fd == -1) {
267
 
                i_error("open(.) failed: %m");
 
269
                mail_storage_set_critical(&mbox->storage->storage,
 
270
                                          "open(.) failed: %m");
268
271
                return -1;
269
272
        }
270
273
 
283
286
        } else {
284
287
                dir = t_strdup_until(mbox->path, fname);
285
288
                if (chdir(dir) < 0) {
286
 
                        i_error("chdir(%s) failed: %m", dir);
 
289
                        mail_storage_set_critical(&mbox->storage->storage,
 
290
                                "chdir(%s) failed: %m", dir);
287
291
                        (void)close(orig_dir_fd);
288
292
                        return -1;
289
293
                }
291
295
        }
292
296
        if (op == MBOX_DOTLOCK_OP_LOCK) {
293
297
                if (access(fname, R_OK) < 0) {
294
 
                        i_error("access(%s) failed: %m", mbox->path);
 
298
                        mail_storage_set_critical(&mbox->storage->storage,
 
299
                                "access(%s) failed: %m", mbox->path);
295
300
                        return -1;
296
301
                }
297
302
        }
307
312
                ret = file_dotlock_create(set, fname, 0, &mbox->mbox_dotlock);
308
313
                if (ret > 0)
309
314
                        mbox->mbox_used_privileges = TRUE;
 
315
                else if (ret < 0 && errno == EACCES) {
 
316
                        const char *errmsg =
 
317
                                eacces_error_get_creating("file_dotlock_create",
 
318
                                                          fname);
 
319
                        mail_storage_set_critical(&mbox->storage->storage,
 
320
                                                  "%s", errmsg);
 
321
                } else {
 
322
                        mbox_set_syscall_error(mbox, "file_dotlock_create()");
 
323
                }
310
324
                break;
311
325
        case MBOX_DOTLOCK_OP_UNLOCK:
312
326
                /* we're now privileged - avoid doing as much as possible */
313
327
                ret = file_dotlock_delete(&mbox->mbox_dotlock);
 
328
                if (ret < 0)
 
329
                        mbox_set_syscall_error(mbox, "file_dotlock_delete()");
314
330
                mbox->mbox_used_privileges = FALSE;
315
331
                break;
316
332
        case MBOX_DOTLOCK_OP_TOUCH:
317
 
                if (!file_dotlock_is_locked(mbox->mbox_dotlock)) {
318
 
                        file_dotlock_delete(&mbox->mbox_dotlock);
319
 
                        mbox->mbox_used_privileges = TRUE;
320
 
                        ret = -1;
321
 
                } else {
322
 
                        ret = file_dotlock_touch(mbox->mbox_dotlock);
323
 
                }
 
333
                ret = file_dotlock_touch(mbox->mbox_dotlock);
 
334
                if (ret < 0)
 
335
                        mbox_set_syscall_error(mbox, "file_dotlock_touch()");
324
336
                break;
325
337
        }
326
338
 
 
339
        orig_errno = errno;
327
340
        restrict_access_drop_priv_gid();
328
341
 
329
 
        if (fchdir(orig_dir_fd) < 0)
330
 
                i_error("fchdir() failed: %m");
 
342
        if (fchdir(orig_dir_fd) < 0) {
 
343
                mail_storage_set_critical(&mbox->storage->storage,
 
344
                        "fchdir() failed: %m");
 
345
        }
331
346
        (void)close(orig_dir_fd);
 
347
        errno = orig_errno;
332
348
        return ret;
333
349
}
334
350
 
 
351
static void
 
352
mbox_dotlock_log_eacces_error(struct mbox_mailbox *mbox, const char *path)
 
353
{
 
354
        const char *dir, *errmsg;
 
355
        struct stat st;
 
356
        const struct group *group;
 
357
        int orig_errno = errno;
 
358
 
 
359
        errmsg = eacces_error_get_creating("file_dotlock_create", path);
 
360
        dir = strrchr(path, '/');
 
361
        dir = dir == NULL ? "." : t_strdup_until(path, dir);
 
362
        if (strcmp(mbox->ibox.box.name, "INBOX") != 0) {
 
363
                mail_storage_set_critical(&mbox->storage->storage,
 
364
                        "%s (not INBOX -> no privileged locking)", errmsg);
 
365
        } else if (!mbox->mbox_privileged_locking) {
 
366
                dir = mailbox_list_get_path(mbox->storage->storage.list, NULL,
 
367
                                            MAILBOX_LIST_PATH_TYPE_DIR);
 
368
                mail_storage_set_critical(&mbox->storage->storage,
 
369
                        "%s (under root dir %s -> no privileged locking)",
 
370
                        errmsg, dir);
 
371
        } else if (stat(dir, &st) == 0 &&
 
372
                   (st.st_mode & 02) == 0 && /* not world-writable */
 
373
                   (st.st_mode & 020) != 0) { /* group-writable */
 
374
                group = getgrgid(st.st_gid);
 
375
                mail_storage_set_critical(&mbox->storage->storage,
 
376
                        "%s (set mail_privileged_group=%s)", errmsg,
 
377
                        group == NULL ? dec2str(st.st_gid) : group->gr_name);
 
378
        } else {
 
379
                mail_storage_set_critical(&mbox->storage->storage,
 
380
                        "%s (nonstandard permissions in %s)", errmsg, dir);
 
381
        }
 
382
        errno = orig_errno;
 
383
}
 
384
 
335
385
static int
336
386
mbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
337
387
{
343
393
                if (!mbox->mbox_dotlocked)
344
394
                        return 1;
345
395
 
346
 
                if (!mbox->mbox_used_privileges)
347
 
                        ret = file_dotlock_delete(&mbox->mbox_dotlock);
348
 
                else {
 
396
                if (!mbox->mbox_used_privileges) {
 
397
                        if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
 
398
                                mbox_set_syscall_error(mbox,
 
399
                                                       "file_dotlock_delete()");
 
400
                        }
 
401
                } else {
349
402
                        ctx->using_privileges = TRUE;
350
 
                        ret = mbox_dotlock_privileged_op(mbox, NULL,
351
 
                                                        MBOX_DOTLOCK_OP_UNLOCK);
 
403
                        (void)mbox_dotlock_privileged_op(mbox, NULL,
 
404
                                                         MBOX_DOTLOCK_OP_UNLOCK);
352
405
                        ctx->using_privileges = FALSE;
353
406
                }
354
 
                if (ret <= 0) {
355
 
                        mbox_set_syscall_error(mbox, "file_dotlock_delete()");
356
 
                        ret = -1;
357
 
                }
358
407
                mbox->mbox_dotlocked = FALSE;
359
408
                return 1;
360
409
        }
375
424
        set.context = ctx;
376
425
 
377
426
        ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
378
 
        if (ret < 0 && errno == EACCES && restrict_access_have_priv_gid() &&
379
 
            mbox->mbox_privileged_locking) {
 
427
        if (ret >= 0) {
 
428
                /* success / timeout */
 
429
        } else if (errno == EACCES && restrict_access_have_priv_gid() &&
 
430
                   mbox->mbox_privileged_locking) {
380
431
                /* try again, this time with extra privileges */
381
432
                ret = mbox_dotlock_privileged_op(mbox, &set,
382
433
                                                 MBOX_DOTLOCK_OP_LOCK);
383
 
        }
 
434
        } else if (errno == EACCES)
 
435
                mbox_dotlock_log_eacces_error(mbox, mbox->path);
 
436
        else
 
437
                mbox_set_syscall_error(mbox, "file_dotlock_create()");
384
438
 
385
439
        if (ret < 0) {
386
440
                if ((ENOSPACE(errno) || errno == EACCES) && try)
387
441
                        return 1;
388
 
 
389
 
                mbox_set_syscall_error(mbox, "file_lock_dotlock()");
390
442
                return -1;
391
443
        }
392
444
        if (ret == 0) {
418
470
                           time_t max_wait_time)
419
471
{
420
472
        time_t now, last_notify;
 
473
        unsigned int next_alarm;
421
474
 
422
475
        if (mbox_file_open_latest(ctx, lock_type) < 0)
423
476
                return -1;
432
485
        else
433
486
                lock_type = LOCK_UN;
434
487
 
 
488
        if (max_wait_time == 0) {
 
489
                /* usually we're waiting here, but if we came from
 
490
                   mbox_lock_dotlock(), we just want to try locking */
 
491
                lock_type |= LOCK_NB;
 
492
        } else {
 
493
                now = time(NULL);
 
494
                if (now >= max_wait_time)
 
495
                        alarm(1);
 
496
                else
 
497
                        alarm(I_MIN(max_wait_time - now, 5));
 
498
        }
 
499
 
435
500
        last_notify = 0;
436
 
        while (flock(ctx->mbox->mbox_fd, lock_type | LOCK_NB) < 0) {
437
 
                if (errno != EWOULDBLOCK) {
 
501
        while (flock(ctx->mbox->mbox_fd, lock_type) < 0) {
 
502
                if (errno != EINTR) {
 
503
                        if (errno == EWOULDBLOCK && max_wait_time == 0) {
 
504
                                /* non-blocking lock trying failed */
 
505
                                return 0;
 
506
                        }
 
507
                        alarm(0);
438
508
                        mbox_set_syscall_error(ctx->mbox, "flock()");
439
509
                        return -1;
440
510
                }
441
511
 
442
512
                now = time(NULL);
443
 
                if (now >= max_wait_time)
 
513
                if (now >= max_wait_time) {
 
514
                        alarm(0);
444
515
                        return 0;
445
 
 
446
 
                if (now != last_notify) {
447
 
                        index_storage_lock_notify(&ctx->mbox->ibox,
448
 
                                MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
449
 
                                max_wait_time - now);
450
516
                }
451
517
 
452
 
                usleep(LOCK_RANDOM_USLEEP_TIME);
 
518
                /* notify locks once every 5 seconds.
 
519
                   try to use rounded values. */
 
520
                next_alarm = (max_wait_time - now) % 5;
 
521
                if (next_alarm == 0)
 
522
                        next_alarm = 5;
 
523
                alarm(next_alarm);
 
524
 
 
525
                index_storage_lock_notify(&ctx->mbox->ibox,
 
526
                                          MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
 
527
                                          max_wait_time - now);
453
528
        }
454
529
 
 
530
        alarm(0);
455
531
        return 1;
456
532
}
457
533
#endif
461
537
                           time_t max_wait_time)
462
538
{
463
539
        time_t now, last_notify;
 
540
        unsigned int next_alarm;
464
541
 
465
542
        if (mbox_file_open_latest(ctx, lock_type) < 0)
466
543
                return -1;
468
545
        if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
469
546
                return 1;
470
547
 
471
 
        if (lock_type != F_UNLCK)
 
548
        if (lock_type == F_UNLCK)
 
549
                lock_type = F_ULOCK;
 
550
        else if (max_wait_time == 0) {
 
551
                /* usually we're waiting here, but if we came from
 
552
                   mbox_lock_dotlock(), we just want to try locking */
472
553
                lock_type = F_TLOCK;
473
 
        else
474
 
                lock_type = F_ULOCK;
 
554
        } else {
 
555
                now = time(NULL);
 
556
                if (now >= max_wait_time)
 
557
                        alarm(1);
 
558
                else
 
559
                        alarm(I_MIN(max_wait_time - now, 5));
 
560
                lock_type = F_LOCK;
 
561
        }
475
562
 
476
563
        last_notify = 0;
477
564
        while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
478
 
                if (errno != EAGAIN) {
 
565
                if (errno != EINTR) {
 
566
                        if ((errno == EACCES || errno == EAGAIN) &&
 
567
                            max_wait_time == 0) {
 
568
                                /* non-blocking lock trying failed */
 
569
                                return 0;
 
570
                        }
 
571
                        alarm(0);
479
572
                        mbox_set_syscall_error(ctx->mbox, "lockf()");
480
573
                        return -1;
481
574
                }
482
575
 
483
576
                now = time(NULL);
484
 
                if (now >= max_wait_time)
 
577
                if (now >= max_wait_time) {
 
578
                        alarm(0);
485
579
                        return 0;
486
 
 
487
 
                if (now != last_notify) {
488
 
                        index_storage_lock_notify(&ctx->mbox->ibox,
489
 
                                MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
490
 
                                max_wait_time - now);
491
580
                }
492
581
 
493
 
                usleep(LOCK_RANDOM_USLEEP_TIME);
 
582
                /* notify locks once every 5 seconds.
 
583
                   try to use rounded values. */
 
584
                next_alarm = (max_wait_time - now) % 5;
 
585
                if (next_alarm == 0)
 
586
                        next_alarm = 5;
 
587
                alarm(next_alarm);
 
588
 
 
589
                index_storage_lock_notify(&ctx->mbox->ibox,
 
590
                                          MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
 
591
                                          max_wait_time - now);
494
592
        }
495
593
 
 
594
        alarm(0);
496
595
        return 1;
497
596
}
498
597
#endif