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 /gssapi.c | |
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.
Diffstat (limited to 'gssapi.c')
-rw-r--r-- | gssapi.c | 83 |
1 files changed, 64 insertions, 19 deletions
@@ -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 */ |