diff options
author | Matthias Andree <matthias.andree@gmx.de> | 2010-08-21 15:38:16 +0200 |
---|---|---|
committer | Matthias Andree <matthias.andree@gmx.de> | 2010-08-21 15:38:16 +0200 |
commit | 82e1d66f6bee1a8837d8d6c89c7ed6b11f2c0a48 (patch) | |
tree | b47584d202f9cb77247f172094de530afd37327b | |
parent | e5510f67f15d893bb476a0db5b2de702129e122c (diff) | |
download | fetchmail-82e1d66f6bee1a8837d8d6c89c7ed6b11f2c0a48.tar.gz fetchmail-82e1d66f6bee1a8837d8d6c89c7ed6b11f2c0a48.tar.bz2 fetchmail-82e1d66f6bee1a8837d8d6c89c7ed6b11f2c0a48.zip |
Avoid wedging Exchange 2007 with GSSAPI.
Exchange 2007 wedges if we try GSSAPI authentication and fail for lack of
suitable credentails (for instance, because the user did not run kinit).
Only try GSSAPI automatically if we have credentials.
Reported by Patrick Rynhart, Debian Bug #568455,
and Alan Murrell, to the fetchmail-users list.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | fetchmail.h | 1 | ||||
-rw-r--r-- | gssapi.c | 83 | ||||
-rw-r--r-- | imap.c | 2 | ||||
-rw-r--r-- | pop3.c | 3 |
5 files changed, 72 insertions, 21 deletions
@@ -74,6 +74,10 @@ fetchmail-6.3.18 (not yet released): * Fetchmail will now apply timeouts to the authentication stage. This stage encompasses STARTTLS/STLS negotiation in IMAP/POP3. Reported missing by Thomas Jarosch. +* Fetchmail will not try GSSAPI authentication automatically unless it has GSS + credentials. This avoids getting servers such as Exchange 2007 wedged if + GSSAPI authentication fails. Reported by Patrick Rynhart, Debian Bug #568455, + and Alan Murrell, to the fetchmail-users list. # CHANGES * When encountering incorrect headers, fetchmail will refer to the bad-header diff --git a/fetchmail.h b/fetchmail.h index aa58bcdd..0315a9da 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -650,6 +650,7 @@ int doODMR (struct query *); /* authentication functions */ int do_cram_md5(int sock, const char *command, struct query *ctl, const char *strip); int do_rfc1731(int sock, const char *command, const char *truename); +int check_gss_creds(const char *service, const char *hostname); int do_gssauth(int sock, const char *command, const char *service, const char *hostname, const char *username); int do_otp(int sock, const char *command, struct query *ctl); @@ -69,38 +69,83 @@ static void decode_status(const char *m, uint32_t major, uint32_t minor) #define GSSAUTH_P_INTEGRITY 2 #define GSSAUTH_P_PRIVACY 4 -int do_gssauth(int sock, const char *command, const char *service, - const char *hostname, const char *username) +static int import_name(const char *service, const char *hostname, + gss_name_t *target_name, flag verbose) { - gss_buffer_desc request_buf, send_token; - gss_buffer_t sec_token; - gss_name_t target_name; - gss_ctx_id_t context; - gss_OID mech_name; - gss_qop_t quality; - int cflags; + char *buf1; + size_t buf1siz; OM_uint32 maj_stat, min_stat; - char buf1[8192], buf2[8192], server_conf_flags; - unsigned long buf_size; - int result; + gss_buffer_desc request_buf; /* first things first: get an imap ticket for host */ - snprintf(buf1, sizeof(buf1), "%s@%s", service, hostname); + buf1siz = strlen(service) + 1 + strlen(hostname) + 1; + buf1 = (char *)xmalloc(buf1siz); + snprintf(buf1, buf1siz, "%s@%s", service, hostname); request_buf.value = buf1; request_buf.length = strlen(buf1) + 1; - maj_stat = gss_import_name(&min_stat, &request_buf, GSS_C_NT_HOSTBASED_SERVICE, - &target_name); + maj_stat = gss_import_name(&min_stat, &request_buf, + GSS_C_NT_HOSTBASED_SERVICE, target_name); if (maj_stat != GSS_S_COMPLETE) { decode_status("gss_import_name", maj_stat, min_stat); report(stderr, GT_("Couldn't get service name for [%s]\n"), buf1); return PS_AUTHFAIL; } - else if (outlevel >= O_DEBUG) { - gss_display_name(&min_stat, target_name, &request_buf, &mech_name); + else if (outlevel >= O_DEBUG && verbose) { + (void)gss_display_name(&min_stat, *target_name, &request_buf, NULL); report(stderr, GT_("Using service name [%s]\n"), (char *)request_buf.value); - gss_release_buffer(&min_stat, &request_buf); } + (void)gss_release_buffer(&min_stat, &request_buf); + + return PS_SUCCESS; +} + +/* If we don't have suitable credentials, don't bother trying GSSAPI, but + * fail right away. This is to avoid that a server - such as Microsoft + * Exchange 2007 - gets wedged and refuses different authentication + * mechanisms afterwards. */ +int check_gss_creds(const char *service, const char *hostname) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_usage_t cu; + gss_name_t target_name; + int result; + + result = import_name(service, hostname, &target_name, FALSE); + (void)gss_release_name(&min_stat, &target_name); + + maj_stat = gss_inquire_cred(&min_stat, GSS_C_NO_CREDENTIAL, + NULL, NULL, &cu, NULL); + if (maj_stat != GSS_S_COMPLETE + || (cu != GSS_C_INITIATE && cu != GSS_C_BOTH)) { + if (outlevel >= O_DEBUG) { + decode_status("gss_inquire_cred", maj_stat, min_stat); + report(stderr, GT_("No suitable GSSAPI credentials found. Skipping GSSAPI authentication.\n")); + report(stderr, GT_("If you want to use GSSAPI, you need credentials first, possibly from kinit.\n")); + } + return PS_AUTHFAIL; + } + + return PS_SUCCESS; +} + +int do_gssauth(int sock, const char *command, const char *service, + const char *hostname, const char *username) +{ + gss_buffer_desc request_buf, send_token; + gss_buffer_t sec_token; + gss_name_t target_name; + gss_ctx_id_t context; + gss_qop_t quality; + int cflags; + OM_uint32 maj_stat, min_stat; + char buf1[8192], buf2[8192], server_conf_flags; + unsigned long buf_size; + int result; + + result = import_name(service, hostname, &target_name, TRUE); + if (result) + return result; gen_send(sock, "%s GSSAPI", command); @@ -133,7 +178,7 @@ int do_gssauth(int sock, const char *command, const char *service, NULL); if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) { decode_status("gss_init_sec_context", maj_stat, min_stat); - gss_release_name(&min_stat, &target_name); + (void)gss_release_name(&min_stat, &target_name); report(stderr, GT_("Error exchanging credentials\n")); /* wake up server and await NO response */ @@ -565,7 +565,7 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) } #ifdef GSSAPI - if ((ctl->server.authenticate == A_ANY + if (((ctl->server.authenticate == A_ANY && check_gss_creds("imap", ctl->server.truename) == PS_SUCCESS) || ctl->server.authenticate == A_GSSAPI) && strstr(capabilities, "AUTH=GSSAPI")) { @@ -565,7 +565,8 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) #if defined(GSSAPI) if (has_gssapi && (ctl->server.authenticate == A_GSSAPI || - ctl->server.authenticate == A_ANY)) + (ctl->server.authenticate == A_ANY + && check_gss_creds("pop", ctl->server.truename) == PS_SUCCESS))) { ok = do_gssauth(sock,"AUTH","pop",ctl->server.truename,ctl->remotename); if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY) |