~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/plugins/quota/quota.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2005-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "array.h"
5
5
#include "hash.h"
6
6
#include "str.h"
7
 
#include "network.h"
 
7
#include "net.h"
8
8
#include "write-full.h"
9
9
#include "eacces-error.h"
10
10
#include "mailbox-list-private.h"
15
15
#include <stdlib.h>
16
16
#include <sys/wait.h>
17
17
 
 
18
#define QUOTA_DEFAULT_GRACE "10%"
18
19
#define DEFAULT_QUOTA_EXCEEDED_MSG \
19
20
        "Quota exceeded (mailbox for user is full)"
20
21
#define RULE_NAME_DEFAULT_FORCE "*"
45
46
 
46
47
static int quota_default_test_alloc(struct quota_transaction_context *ctx,
47
48
                                    uoff_t size, bool *too_large_r);
 
49
static int
 
50
quota_root_parse_grace(struct mail_user *user, const char *root_name,
 
51
                       struct quota_root_settings *root_set,
 
52
                       const char **error_r);
48
53
 
49
54
static const struct quota_backend *quota_backend_find(const char *name)
50
55
{
175
180
                return -1;
176
181
        if (quota_root_add_warning_rules(user, root_name, root_set, error_r) < 0)
177
182
                return -1;
 
183
        if (quota_root_parse_grace(user, root_name, root_set, error_r) < 0)
 
184
                return -1;
178
185
        return 0;
179
186
}
180
187
 
183
190
                             const char **error_r)
184
191
{
185
192
        struct quota_settings *quota_set;
186
 
        char root_name[6 + MAX_INT_STRLEN];
 
193
        char root_name[5 + MAX_INT_STRLEN + 1];
187
194
        const char *env, *error;
188
195
        unsigned int i;
189
196
        pool_t pool;
195
202
        quota_set->debug = user->mail_debug;
196
203
        quota_set->quota_exceeded_msg =
197
204
                mail_user_plugin_getenv(user, "quota_exceeded_message");
198
 
        quota_set->ignore_save_errors =
199
 
                mail_user_plugin_getenv(user, "quota_ignore_save_errors") != NULL;
200
205
        if (quota_set->quota_exceeded_msg == NULL)
201
206
                quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
202
207
 
203
208
        p_array_init(&quota_set->root_sets, pool, 4);
204
 
        i_strocpy(root_name, "quota", sizeof(root_name));
 
209
        if (i_strocpy(root_name, "quota", sizeof(root_name)) < 0)
 
210
                i_unreached();
205
211
        for (i = 2;; i++) {
206
212
                env = mail_user_plugin_getenv(user, root_name);
207
213
                if (env == NULL || *env == '\0')
214
220
                        pool_unref(&pool);
215
221
                        return -1;
216
222
                }
217
 
                i_snprintf(root_name, sizeof(root_name), "quota%d", i);
 
223
                if (i_snprintf(root_name, sizeof(root_name), "quota%d", i) < 0)
 
224
                        i_unreached();
218
225
        }
219
226
        if (array_count(&quota_set->root_sets) == 0) {
220
227
                pool_unref(&pool);
221
228
                return 0;
222
229
        }
 
230
 
 
231
        quota_set->initialized = TRUE;
223
232
        *set_r = quota_set;
224
233
        return 1;
225
234
}
361
370
{
362
371
        int64_t percentage = *limit;
363
372
 
364
 
        if (percentage <= -100 || percentage >= -1U) {
365
 
                *error_r = p_strdup_printf(root_set->set->pool,
366
 
                        "Invalid rule percentage: %lld", (long long)percentage);
 
373
        if (percentage <= -100 || percentage >= UINT_MAX) {
 
374
                *error_r = "Invalid percentage";
367
375
                return -1;
368
376
        }
369
377
 
381
389
        return 0;
382
390
}
383
391
 
 
392
static int quota_limit_parse(struct quota_root_settings *root_set,
 
393
                             struct quota_rule *rule, const char *unit,
 
394
                             uint64_t multiply, int64_t *limit,
 
395
                             const char **error_r)
 
396
{
 
397
        switch (i_toupper(*unit)) {
 
398
        case '\0':
 
399
                /* default */
 
400
                break;
 
401
        case 'B':
 
402
                multiply = 1;
 
403
                break;
 
404
        case 'K':
 
405
                multiply = 1024;
 
406
                break;
 
407
        case 'M':
 
408
                multiply = 1024*1024;
 
409
                break;
 
410
        case 'G':
 
411
                multiply = 1024*1024*1024;
 
412
                break;
 
413
        case 'T':
 
414
                multiply = 1024ULL*1024*1024*1024;
 
415
                break;
 
416
        case '%':
 
417
                multiply = 0;
 
418
                if (quota_rule_parse_percentage(root_set, rule, limit,
 
419
                                                error_r) < 0)
 
420
                        return -1;
 
421
                break;
 
422
        default:
 
423
                *error_r = t_strdup_printf("Unknown unit: %s", unit);
 
424
                return -1;
 
425
        }
 
426
        *limit *= multiply;
 
427
        return 0;
 
428
}
 
429
 
384
430
static void
385
431
quota_rule_recalculate_relative_rules(struct quota_rule *rule,
386
432
                                      int64_t bytes_limit, int64_t count_limit)
407
453
                quota_rule_recalculate_relative_rules(&warning_rule->rule,
408
454
                                                      bytes_limit, count_limit);
409
455
        }
 
456
        quota_rule_recalculate_relative_rules(&root_set->grace_rule,
 
457
                                              bytes_limit, 0);
 
458
        root_set->last_mail_max_extra_bytes = root_set->grace_rule.bytes_limit;
 
459
 
 
460
        if (root_set->set->debug && root_set->set->initialized) {
 
461
                i_debug("Quota root %s: Recalculated relative rules with "
 
462
                        "bytes=%lld count=%lld. Now grace=%llu", root_set->name,
 
463
                        (long long)bytes_limit, (long long)count_limit,
 
464
                        (unsigned long long)root_set->last_mail_max_extra_bytes);
 
465
        }
410
466
}
411
467
 
412
468
static int
415
471
                        const char *full_rule_def,
416
472
                        bool relative_rule, const char **error_r)
417
473
{
418
 
        const char **args, *key, *value;
 
474
        const char **args, *key, *value, *error;
419
475
        char *p;
420
476
        uint64_t multiply;
421
477
        int64_t *limit;
462
518
                        return -1;
463
519
                }
464
520
 
465
 
                switch (i_toupper(*p)) {
466
 
                case '\0':
467
 
                        /* default */
468
 
                        break;
469
 
                case 'B':
470
 
                        multiply = 1;
471
 
                        break;
472
 
                case 'K':
473
 
                        multiply = 1024;
474
 
                        break;
475
 
                case 'M':
476
 
                        multiply = 1024*1024;
477
 
                        break;
478
 
                case 'G':
479
 
                        multiply = 1024*1024*1024;
480
 
                        break;
481
 
                case 'T':
482
 
                        multiply = 1024ULL*1024*1024*1024;
483
 
                        break;
484
 
                case '%':
485
 
                        multiply = 0;
486
 
                        if (quota_rule_parse_percentage(root_set, rule, limit,
487
 
                                                        error_r) < 0)
488
 
                                return -1;
489
 
                        break;
490
 
                default:
 
521
                if (quota_limit_parse(root_set, rule, p, multiply,
 
522
                                      limit, &error) < 0) {
491
523
                        *error_r = p_strdup_printf(root_set->set->pool,
492
 
                                        "Invalid rule limit value: %s", *args);
 
524
                                "Invalid rule limit value '%s': %s",
 
525
                                *args, error);
493
526
                        return -1;
494
527
                }
495
 
                *limit *= multiply;
496
528
        }
497
529
        if (!relative_rule) {
498
530
                if (rule->bytes_limit < 0) {
532
564
                        root_set->force_default_rule = TRUE;
533
565
                } else {
534
566
                        rule = array_append_space(&root_set->rules);
535
 
                        rule->mailbox_name =
 
567
                        rule->mailbox_name = strcasecmp(mailbox_name, "INBOX") == 0 ? "INBOX" :
536
568
                                p_strdup(root_set->set->pool, mailbox_name);
537
569
                }
538
570
        }
583
615
        return ret;
584
616
}
585
617
 
 
618
static int
 
619
quota_root_parse_grace(struct mail_user *user, const char *root_name,
 
620
                       struct quota_root_settings *root_set,
 
621
                       const char **error_r)
 
622
{
 
623
        const char *set_name, *value, *error;
 
624
        char *p;
 
625
 
 
626
        set_name = t_strconcat(root_name, "_grace", NULL);
 
627
        value = mail_user_plugin_getenv(user, set_name);
 
628
        if (value == NULL) {
 
629
                /* default */
 
630
                value = QUOTA_DEFAULT_GRACE;
 
631
        }
 
632
 
 
633
        root_set->grace_rule.bytes_limit = strtoll(value, &p, 10);
 
634
 
 
635
        if (quota_limit_parse(root_set, &root_set->grace_rule, p, 1,
 
636
                              &root_set->grace_rule.bytes_limit, &error) < 0) {
 
637
                *error_r = p_strdup_printf(root_set->set->pool,
 
638
                        "Invalid %s value '%s': %s", set_name, value, error);
 
639
                return -1;
 
640
        }
 
641
        quota_rule_recalculate_relative_rules(&root_set->grace_rule,
 
642
                root_set->default_rule.bytes_limit, 0);
 
643
        root_set->last_mail_max_extra_bytes = root_set->grace_rule.bytes_limit;
 
644
        if (root_set->set->debug) {
 
645
                i_debug("Quota grace: root=%s bytes=%lld%s",
 
646
                        root_set->name, (long long)root_set->grace_rule.bytes_limit,
 
647
                        root_set->grace_rule.bytes_percent == 0 ? "" :
 
648
                        t_strdup_printf(" (%u%%)", root_set->grace_rule.bytes_percent));
 
649
        }
 
650
        return 0;
 
651
}
 
652
 
586
653
static int quota_root_get_rule_limits(struct quota_root *root,
587
654
                                      const char *mailbox_name,
588
655
                                      uint64_t *bytes_limit_r,
634
701
 
635
702
        /* first check if there already exists a namespace with the exact same
636
703
           path. we don't want to count them twice. */
637
 
        path = mailbox_list_get_path(ns->list, NULL,
638
 
                                     MAILBOX_LIST_PATH_TYPE_MAILBOX);
639
 
        if (path != NULL) {
 
704
        if (mailbox_list_get_root_path(ns->list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
 
705
                                       &path)) {
640
706
                namespaces = array_get(&quota->namespaces, &count);
641
707
                for (i = 0; i < count; i++) {
642
 
                        path2 = mailbox_list_get_path(namespaces[i]->list, NULL,
643
 
                                        MAILBOX_LIST_PATH_TYPE_MAILBOX);
644
 
                        if (path2 != NULL && strcmp(path, path2) == 0) {
 
708
                        if (mailbox_list_get_root_path(namespaces[i]->list,
 
709
                                MAILBOX_LIST_PATH_TYPE_MAILBOX, &path2) &&
 
710
                            strcmp(path, path2) == 0) {
645
711
                                /* duplicate */
646
712
                                return;
647
713
                        }
928
994
 
929
995
        ctx->box = box;
930
996
        ctx->bytes_ceil = (uint64_t)-1;
 
997
        ctx->bytes_ceil2 = (uint64_t)-1;
931
998
        ctx->count_ceil = (uint64_t)-1;
932
999
 
933
 
        if (box->storage->user->admin) {
934
 
                /* ignore quota for admins */
 
1000
        if (box->storage->user->dsyncing) {
 
1001
                /* ignore quota for dsync */
935
1002
                ctx->limits_set = TRUE;
936
1003
        }
937
1004
        return ctx;
943
1010
        const char *mailbox_name;
944
1011
        unsigned int i, count;
945
1012
        uint64_t bytes_limit, count_limit, current, limit, diff;
 
1013
        bool use_grace;
946
1014
        int ret;
947
1015
 
948
1016
        ctx->limits_set = TRUE;
949
1017
        mailbox_name = mailbox_get_vname(ctx->box);
 
1018
        /* use last_mail_max_extra_bytes only for LDA/LMTP */
 
1019
        use_grace = (ctx->box->flags & MAILBOX_FLAG_POST_SESSION) != 0;
950
1020
 
951
1021
        /* find the lowest quota limits from all roots and use them */
952
1022
        roots = array_get(&ctx->quota->roots, &count);
966
1036
                                                 QUOTA_NAME_STORAGE_BYTES,
967
1037
                                                 &current, &limit);
968
1038
                        if (ret > 0) {
969
 
                                if (limit < current) {
 
1039
                                if (limit <= current) {
 
1040
                                        /* over quota */
970
1041
                                        ctx->bytes_ceil = 0;
 
1042
                                        ctx->bytes_ceil2 = 0;
971
1043
                                        diff = current - limit;
972
1044
                                        if (ctx->bytes_over < diff)
973
1045
                                                ctx->bytes_over = diff;
974
1046
                                } else {
975
1047
                                        diff = limit - current;
 
1048
                                        if (ctx->bytes_ceil2 > diff)
 
1049
                                                ctx->bytes_ceil2 = diff;
 
1050
                                        diff += !use_grace ? 0 :
 
1051
                                                roots[i]->set->last_mail_max_extra_bytes;
976
1052
                                        if (ctx->bytes_ceil > diff)
977
1053
                                                ctx->bytes_ceil = diff;
978
1054
                                }
1113
1189
                ret = -1;
1114
1190
        else if (ctx->bytes_used != 0 || ctx->count_used != 0 ||
1115
1191
                 ctx->recalculate) T_BEGIN {
1116
 
                ARRAY_DEFINE(warn_roots, struct quota_root *);
 
1192
                ARRAY(struct quota_root *) warn_roots;
1117
1193
 
1118
1194
                mailbox_name = mailbox_get_vname(ctx->box);
1119
1195
                (void)mail_namespace_find_unalias(
1134
1210
 
1135
1211
                        if (roots[i]->backend.v.update(roots[i], ctx) < 0)
1136
1212
                                ret = -1;
1137
 
                        else
 
1213
                        else if (!ctx->sync_transaction)
1138
1214
                                array_append(&warn_roots, &roots[i], 1);
1139
1215
                }
1140
1216
                /* execute quota warnings after all updates. this makes it
1141
1217
                   work correctly regardless of whether backend.get_resource()
1142
 
                   returns updated values before backend.update() or not */
 
1218
                   returns updated values before backend.update() or not.
 
1219
                   warnings aren't executed when dsync bring the user over,
 
1220
                   because the user probably already got the warning on the
 
1221
                   other replica. */
1143
1222
                array_foreach(&warn_roots, roots)
1144
1223
                        quota_warnings_execute(ctx, *roots);
1145
1224
        } T_END;
1156
1235
        i_free(ctx);
1157
1236
}
1158
1237
 
 
1238
static bool quota_is_over(struct quota_transaction_context *ctx, uoff_t size)
 
1239
{
 
1240
        if ((ctx->count_used < 0 ||
 
1241
             (uint64_t)ctx->count_used + 1 <= ctx->count_ceil) &&
 
1242
            ((ctx->bytes_used < 0 && size <= ctx->bytes_ceil) ||
 
1243
             (uint64_t)ctx->bytes_used + size <= ctx->bytes_ceil))
 
1244
                return FALSE;
 
1245
        else
 
1246
                return TRUE;
 
1247
}
 
1248
 
1159
1249
int quota_try_alloc(struct quota_transaction_context *ctx,
1160
1250
                    struct mail *mail, bool *too_large_r)
1161
1251
{
1183
1273
                if (quota_transaction_set_limits(ctx) < 0)
1184
1274
                        return -1;
1185
1275
        }
 
1276
        /* this is a virtual function mainly for trash plugin and similar,
 
1277
           which may automatically delete mails to stay under quota. */
1186
1278
        return ctx->quota->set->test_alloc(ctx, size, too_large_r);
1187
1279
}
1188
1280
 
1195
1287
 
1196
1288
        *too_large_r = FALSE;
1197
1289
 
1198
 
        if ((ctx->count_used < 0 ||
1199
 
             (uint64_t)ctx->count_used + 1 <= ctx->count_ceil) &&
1200
 
            ((ctx->bytes_used < 0 && size <= ctx->bytes_ceil) ||
1201
 
             (uint64_t)ctx->bytes_used + size <= ctx->bytes_ceil))
 
1290
        if (!quota_is_over(ctx, size))
1202
1291
                return 1;
1203
1292
 
1204
1293
        /* limit reached. only thing left to do now is to set too_large_r. */
1234
1323
        if (mail_get_physical_size(mail, &size) == 0)
1235
1324
                ctx->bytes_used += size;
1236
1325
 
 
1326
        ctx->bytes_ceil = ctx->bytes_ceil2;
1237
1327
        ctx->count_used++;
1238
1328
}
1239
1329