]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap-urlauth: Fixed deinitialization of the URLAUTH fetch handler.
authorStephan Bosch <stephan@rename-it.nl>
Tue, 21 May 2013 19:55:23 +0000 (22:55 +0300)
committerStephan Bosch <stephan@rename-it.nl>
Tue, 21 May 2013 19:55:23 +0000 (22:55 +0300)
Added reference counting to make sure callbacks will not deinitialize the
handler prematurely.

src/imap/cmd-urlfetch.c
src/lib-imap-urlauth/imap-urlauth-fetch.c
src/lib-imap-urlauth/imap-urlauth-fetch.h

index 2826cb0fc1d06603127b1c99bd3ee3b1e619a4b4..c3fac615b805929b25024f5d6f03b56a89aa1c6f 100644 (file)
@@ -284,7 +284,6 @@ cmd_urlfetch_url_callback(struct imap_urlauth_fetch_reply *reply,
 
        if ((last && cmd->state == CLIENT_COMMAND_STATE_WAIT_EXTERNAL) ||
            ret < 0) {
-               ctx->ufetch = NULL;
                cmd_urlfetch_finish(cmd);
                client_command_free(&cmd);
        }
index 18cd342592f9cde769a089a77039606fb4b11f07..0ba4dfada1b01b2a08952026161d722bf6373d43 100644 (file)
@@ -22,6 +22,7 @@ struct imap_urlauth_fetch_url {
 };
 
 struct imap_urlauth_fetch {
+       unsigned int refcount;
        struct imap_urlauth_context *uctx;
 
        imap_urlauth_fetch_callback_t *callback;
@@ -100,17 +101,28 @@ imap_urlauth_fetch_init(struct imap_urlauth_context *uctx,
        struct imap_urlauth_fetch *ufetch;
 
        ufetch = i_new(struct imap_urlauth_fetch, 1);
+       ufetch->refcount = 1;
        ufetch->uctx = uctx;
        ufetch->callback = callback;
        ufetch->context = context;
        return ufetch;
 }
 
-void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch)
+static void imap_urlauth_fetch_ref(struct imap_urlauth_fetch *ufetch)
+{
+       i_assert(ufetch->refcount > 0);
+       ufetch->refcount++;
+}
+
+static void imap_urlauth_fetch_unref(struct imap_urlauth_fetch **_ufetch)
 {
        struct imap_urlauth_fetch *ufetch = *_ufetch;
 
+       i_assert(ufetch->refcount > 0);
+
        *_ufetch = NULL;
+       if (--ufetch->refcount > 0)
+               return;
 
        imap_urlauth_fetch_abort(ufetch);
 
@@ -120,6 +132,11 @@ void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch)
        i_free(ufetch);
 }
 
+void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch)
+{
+       imap_urlauth_fetch_unref(_ufetch);
+}
+
 static void
 imap_urlauth_fetch_error(struct imap_urlauth_fetch *ufetch, const char *url,
                         enum imap_urlauth_fetch_flags url_flags,
@@ -232,6 +249,8 @@ imap_urlauth_fetch_local(struct imap_urlauth_fetch *ufetch, const char *url,
        }
 
        if (!success && ret < 0) {
+               if (mpurl != NULL)
+                       imap_msgpart_url_free(&mpurl);
                ufetch->pending_requests--;
                (void)ufetch->callback(NULL, TRUE, ufetch->context);
                imap_urlauth_fetch_fail(ufetch);
@@ -292,6 +311,8 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply,
        ufetch->waiting_local = FALSE;
        ufetch->pending_requests--;
 
+       imap_urlauth_fetch_ref(ufetch);
+
        if (!ufetch->failed) {
                bool last = ufetch->pending_requests == 0 || reply == NULL;
                ret = ufetch->callback(reply, last, ufetch->context);
@@ -305,8 +326,8 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply,
        } else if (ret == 0) {
                ufetch->waiting_service = TRUE;
        }
-       if (ret != 0)
-               imap_urlauth_fetch_deinit(&ufetch);
+       
+       imap_urlauth_fetch_unref(&ufetch);
        return ret;
 }
 
@@ -319,6 +340,7 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url,
        struct mail_user *mail_user = uctx->user;
        struct imap_url *imap_url;
        const char *error, *errormsg;
+       int ret = 0;
 
        /* parse the url */
        if (imap_url_parse(url, NULL, url_parse_flags, &imap_url, &error) < 0) {
@@ -327,13 +349,17 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url,
                if (mail_user->mail_debug)
                        i_debug("%s", errormsg);
                ufetch->pending_requests++;
+               imap_urlauth_fetch_ref(ufetch);
                imap_urlauth_fetch_error(ufetch, url, url_flags, errormsg);
+               imap_urlauth_fetch_unref(&ufetch);
                return 1;
        }
 
        ufetch->failed = FALSE;
        ufetch->pending_requests++;
 
+       imap_urlauth_fetch_ref(ufetch);
+
        /* if access user and target user match, handle fetch request locally */
        if (imap_url->userid != NULL &&
                strcmp(mail_user->username, imap_url->userid) == 0) {
@@ -364,17 +390,22 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url,
 
        /* create request for url */
        if (imap_url != NULL && imap_url->userid != NULL) {
+               i_assert(uctx->conn != NULL);
                (void)imap_urlauth_request_new(uctx->conn, imap_url->userid,
                                url, url_flags,
                                imap_urlauth_fetch_request_callback, ufetch);
                i_assert(uctx->conn != NULL);
                if (imap_urlauth_connection_connect(uctx->conn) < 0)
-                       return -1;
+                       ret = -1;
        }
-       return (ufetch->pending_requests > 0 ? 0 : 1);
+       if (ret >= 0)
+               ret = (ufetch->pending_requests > 0 ? 0 : 1);
+
+       imap_urlauth_fetch_unref(&ufetch);
+       return ret;
 }
 
-bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch)
+static bool imap_urlauth_fetch_do_continue(struct imap_urlauth_fetch *ufetch)
 {
        struct imap_urlauth_fetch_url *url, *url_next;
        int ret;
@@ -390,7 +421,7 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch)
                ufetch->waiting_service = FALSE;
                imap_urlauth_connection_continue(ufetch->uctx->conn);
                return ufetch->pending_requests > 0;
-       } 
+       }
 
        /* finished local request */
        if (ufetch->local_url != NULL) {
@@ -457,3 +488,15 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch)
 
        return ufetch->pending_requests > 0;
 }
+
+bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch)
+{
+       bool pending;
+
+       imap_urlauth_fetch_ref(ufetch);
+       pending = imap_urlauth_fetch_do_continue(ufetch);
+       imap_urlauth_fetch_unref(&ufetch);
+
+       return pending;
+}
+
index 3c5275c35f28b64818f78a7073a48532ced700a1..55398af7bc8a1633d4fb9b00a27aaef747c532ea 100644 (file)
@@ -33,8 +33,7 @@ struct imap_urlauth_fetch_reply {
    for next reply, 0 if not all data was processed, and -1 for error. If a
    callback returns 0, imap_urlauth_fetch_continue() must be called once
    new replies may be processed. If this is the last request to yield a reply,
-   argument last is TRUE. The callback must not call
-   imap_urlauth_fetch_deinit(). */
+   argument last is TRUE. */
 typedef int
 imap_urlauth_fetch_callback_t(struct imap_urlauth_fetch_reply *reply,
                              bool last, void *context);
@@ -42,7 +41,7 @@ imap_urlauth_fetch_callback_t(struct imap_urlauth_fetch_reply *reply,
 struct imap_urlauth_fetch *
 imap_urlauth_fetch_init(struct imap_urlauth_context *uctx,
                        imap_urlauth_fetch_callback_t *callback, void *context);
-void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch);
+void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **ufetch);
 
 int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url,
                           enum imap_urlauth_fetch_flags url_flags);