~ubuntu-branches/ubuntu/trusty/dovecot/trusty

« back to all changes in this revision

Viewing changes to src/director/director-request.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-11 11:11:54 UTC
  • mfrom: (1.15.2) (4.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120611111154-678cwbdj6ktgsv1h
Tags: 1:2.1.7-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/{control,rules}: enable PIE hardening.
  + 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.
  + d/control: Added Pre-Depends: dpkg (>= 1.15.6) to dovecot-dbg to support
    xz compression in Ubuntu.
  + d/control: Demote dovecot-common Recommends: to Suggests: to prevent
    install of extra packages on upgrade.
  + d/patches/dovecot-drac.patch: Updated with version for dovecot >= 2.0.0.
  + d/control: Drop B-D on systemd.
* Dropped changes:
  + d/patches/fix-racey-restart.patch: part of 2.1.x, no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "ioloop.h"
5
5
#include "array.h"
 
6
#include "str.h"
6
7
#include "mail-host.h"
7
8
#include "user-directory.h"
8
9
#include "director.h"
21
22
        void *context;
22
23
};
23
24
 
 
25
static const char *
 
26
director_request_get_timeout_error(struct director_request *request)
 
27
{
 
28
        string_t *str = t_str_new(128);
 
29
        struct user *user;
 
30
        unsigned int secs;
 
31
 
 
32
        str_printfa(str, "Timeout - queued for %u secs (",
 
33
                    (unsigned int)(ioloop_time - request->create_time));
 
34
 
 
35
        if (request->dir->ring_last_sync_time == 0)
 
36
                str_append(str, "Ring has never been synced");
 
37
        else {
 
38
                secs = ioloop_time - request->dir->ring_last_sync_time;
 
39
                if (request->dir->ring_synced)
 
40
                        str_printfa(str, "Ring synced for %u secs", secs);
 
41
                else
 
42
                        str_printfa(str, "Ring not synced for %u secs", secs);
 
43
        }
 
44
 
 
45
        user = user_directory_lookup(request->dir->users,
 
46
                                     request->username_hash);
 
47
        if (user != NULL) {
 
48
                if (user->weak)
 
49
                        str_append(str, ", weak user");
 
50
                str_printfa(str, ", user refreshed %u secs ago",
 
51
                            (unsigned int)(ioloop_time - user->timestamp));
 
52
        }
 
53
        str_append_c(str, ')');
 
54
        return str_c(str);
 
55
}
 
56
 
24
57
static void director_request_timeout(struct director *dir)
25
58
{
26
59
        struct director_request **requestp, *request;
 
60
        const char *errormsg;
27
61
 
28
62
        while (array_count(&dir->pending_requests) > 0) {
29
63
                requestp = array_idx_modifiable(&dir->pending_requests, 0);
34
68
                        break;
35
69
 
36
70
                array_delete(&dir->pending_requests, 0, 1);
37
 
                request->callback(NULL, request->context);
 
71
                errormsg = director_request_get_timeout_error(request);
 
72
                T_BEGIN {
 
73
                        request->callback(NULL, errormsg, request->context);
 
74
                } T_END;
38
75
                i_free(request);
39
76
        }
40
77
 
46
83
                      director_request_callback *callback, void *context)
47
84
{
48
85
        struct director_request *request;
49
 
        unsigned int username_hash = user_directory_get_username_hash(username);
 
86
        unsigned int username_hash =
 
87
                user_directory_get_username_hash(dir->users, username);
50
88
 
51
89
        request = i_new(struct director_request, 1);
52
90
        request->dir = dir;
89
127
                                                ring_noconn_warning, dir);
90
128
}
91
129
 
 
130
static bool director_request_existing(struct director *dir, struct user *user)
 
131
{
 
132
        struct mail_host *host;
 
133
 
 
134
        if (user->kill_state != USER_KILL_STATE_NONE) {
 
135
                /* delay processing this user's connections until
 
136
                   its existing connections have been killed */
 
137
                return FALSE;
 
138
        }
 
139
        if (user->weak) {
 
140
                /* wait for user to become non-weak */
 
141
                return FALSE;
 
142
        }
 
143
        if (!user_directory_user_is_near_expiring(dir->users, user))
 
144
                return TRUE;
 
145
 
 
146
        /* user is close to being expired. another director may have
 
147
           already expired it. */
 
148
        host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash);
 
149
        if (!dir->ring_synced) {
 
150
                /* try again later once ring is synced */
 
151
                return FALSE;
 
152
        }
 
153
        if (user->host == host) {
 
154
                /* doesn't matter, other directors would
 
155
                   assign the user the same way regardless */
 
156
                return TRUE;
 
157
        }
 
158
 
 
159
        /* We have to worry about two separate timepoints in here:
 
160
 
 
161
           a) some directors think the user isn't expiring, and
 
162
           others think the user is near expiring
 
163
 
 
164
           b) some directors think the user is near expiring, and
 
165
           others think the user has already expired
 
166
 
 
167
           What we don't have to worry about is:
 
168
 
 
169
           !c) some directors think the user isn't expiring, and
 
170
           others think the user has already expired
 
171
 
 
172
           If !c) happens, the user might get redirected to different backends.
 
173
           We'll use a large enough timeout between a) and b) states, so that
 
174
           !c) should never happen.
 
175
 
 
176
           So what we'll do here is:
 
177
 
 
178
           1. Send a USER-WEAK notification to all directors with the new host.
 
179
           2. Each director receiving USER-WEAK refreshes the user's timestamp
 
180
           and host, but marks the user as being weak.
 
181
           3. Once USER-WEAK has reached all directors, a real USER update is
 
182
           sent, which removes the weak-flag.
 
183
           4. If a director ever receives a USER update for a weak user, the
 
184
           USER update overrides the host and removes the weak-flag.
 
185
           5. Director doesn't let any weak user log in, until the weak-flag
 
186
           gets removed.
 
187
        */
 
188
        if (dir->ring_min_version < DIRECTOR_VERSION_WEAK_USERS) {
 
189
                /* weak users not supported by ring currently */
 
190
                return TRUE;
 
191
        } else {
 
192
                user->weak = TRUE;
 
193
                director_update_user_weak(dir, dir->self_host, NULL, user);
 
194
                return FALSE;
 
195
        }
 
196
}
 
197
 
92
198
bool director_request_continue(struct director_request *request)
93
199
{
94
200
        struct director *dir = request->dir;
103
209
 
104
210
        user = user_directory_lookup(dir->users, request->username_hash);
105
211
        if (user != NULL) {
106
 
                if (user->kill_state != USER_KILL_STATE_NONE) {
107
 
                        /* delay processing this user's connections until
108
 
                           its existing connections have been killed */
 
212
                if (!director_request_existing(dir, user))
109
213
                        return FALSE;
110
 
                }
111
214
                user_directory_refresh(dir->users, user);
112
215
        } else {
113
216
                if (!dir->ring_synced) {
125
228
                                          host, ioloop_time);
126
229
        }
127
230
 
 
231
        i_assert(!user->weak);
128
232
        director_update_user(dir, dir->self_host, user);
129
 
        request->callback(&user->host->ip, request->context);
 
233
        T_BEGIN {
 
234
                request->callback(&user->host->ip, NULL, request->context);
 
235
        } T_END;
130
236
        i_free(request);
131
237
        return TRUE;
132
238
}