Commit 82e1d66f6bee1a8837d8d6c89c7ed6b11f2c0a48

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.
NEWS
(4 / 0)
  
7474* Fetchmail will now apply timeouts to the authentication stage. This stage
7575 encompasses STARTTLS/STLS negotiation in IMAP/POP3.
7676 Reported missing by Thomas Jarosch.
77* Fetchmail will not try GSSAPI authentication automatically unless it has GSS
78 credentials. This avoids getting servers such as Exchange 2007 wedged if
79 GSSAPI authentication fails. Reported by Patrick Rynhart, Debian Bug #568455,
80 and Alan Murrell, to the fetchmail-users list.
7781
7882# CHANGES
7983* When encountering incorrect headers, fetchmail will refer to the bad-header
  
650650/* authentication functions */
651651int do_cram_md5(int sock, const char *command, struct query *ctl, const char *strip);
652652int do_rfc1731(int sock, const char *command, const char *truename);
653int check_gss_creds(const char *service, const char *hostname);
653654int do_gssauth(int sock, const char *command, const char *service, const char *hostname, const char *username);
654655int do_otp(int sock, const char *command, struct query *ctl);
655656
gssapi.c
(64 / 19)
  
6969#define GSSAUTH_P_INTEGRITY 2
7070#define GSSAUTH_P_PRIVACY 4
7171
72int do_gssauth(int sock, const char *command, const char *service,
73 const char *hostname, const char *username)
72static int import_name(const char *service, const char *hostname,
73 gss_name_t *target_name, flag verbose)
7474{
75 gss_buffer_desc request_buf, send_token;
76 gss_buffer_t sec_token;
77 gss_name_t target_name;
78 gss_ctx_id_t context;
79 gss_OID mech_name;
80 gss_qop_t quality;
81 int cflags;
75 char *buf1;
76 size_t buf1siz;
8277 OM_uint32 maj_stat, min_stat;
83 char buf1[8192], buf2[8192], server_conf_flags;
84 unsigned long buf_size;
85 int result;
78 gss_buffer_desc request_buf;
8679
8780 /* first things first: get an imap ticket for host */
88 snprintf(buf1, sizeof(buf1), "%s@%s", service, hostname);
81 buf1siz = strlen(service) + 1 + strlen(hostname) + 1;
82 buf1 = (char *)xmalloc(buf1siz);
83 snprintf(buf1, buf1siz, "%s@%s", service, hostname);
8984 request_buf.value = buf1;
9085 request_buf.length = strlen(buf1) + 1;
91 maj_stat = gss_import_name(&min_stat, &request_buf, GSS_C_NT_HOSTBASED_SERVICE,
92 &target_name);
86 maj_stat = gss_import_name(&min_stat, &request_buf,
87 GSS_C_NT_HOSTBASED_SERVICE, target_name);
9388 if (maj_stat != GSS_S_COMPLETE) {
9489 decode_status("gss_import_name", maj_stat, min_stat);
9590 report(stderr, GT_("Couldn't get service name for [%s]\n"), buf1);
9691 return PS_AUTHFAIL;
9792 }
98 else if (outlevel >= O_DEBUG) {
99 gss_display_name(&min_stat, target_name, &request_buf, &mech_name);
93 else if (outlevel >= O_DEBUG && verbose) {
94 (void)gss_display_name(&min_stat, *target_name, &request_buf, NULL);
10095 report(stderr, GT_("Using service name [%s]\n"),
10196 (char *)request_buf.value);
102 gss_release_buffer(&min_stat, &request_buf);
10397 }
98 (void)gss_release_buffer(&min_stat, &request_buf);
10499
100 return PS_SUCCESS;
101}
102
103/* If we don't have suitable credentials, don't bother trying GSSAPI, but
104 * fail right away. This is to avoid that a server - such as Microsoft
105 * Exchange 2007 - gets wedged and refuses different authentication
106 * mechanisms afterwards. */
107int check_gss_creds(const char *service, const char *hostname)
108{
109 OM_uint32 maj_stat, min_stat;
110 gss_cred_usage_t cu;
111 gss_name_t target_name;
112 int result;
113
114 result = import_name(service, hostname, &target_name, FALSE);
115 (void)gss_release_name(&min_stat, &target_name);
116
117 maj_stat = gss_inquire_cred(&min_stat, GSS_C_NO_CREDENTIAL,
118 NULL, NULL, &cu, NULL);
119 if (maj_stat != GSS_S_COMPLETE
120 || (cu != GSS_C_INITIATE && cu != GSS_C_BOTH)) {
121 if (outlevel >= O_DEBUG) {
122 decode_status("gss_inquire_cred", maj_stat, min_stat);
123 report(stderr, GT_("No suitable GSSAPI credentials found. Skipping GSSAPI authentication.\n"));
124 report(stderr, GT_("If you want to use GSSAPI, you need credentials first, possibly from kinit.\n"));
125 }
126 return PS_AUTHFAIL;
127 }
128
129 return PS_SUCCESS;
130}
131
132int do_gssauth(int sock, const char *command, const char *service,
133 const char *hostname, const char *username)
134{
135 gss_buffer_desc request_buf, send_token;
136 gss_buffer_t sec_token;
137 gss_name_t target_name;
138 gss_ctx_id_t context;
139 gss_qop_t quality;
140 int cflags;
141 OM_uint32 maj_stat, min_stat;
142 char buf1[8192], buf2[8192], server_conf_flags;
143 unsigned long buf_size;
144 int result;
145
146 result = import_name(service, hostname, &target_name, TRUE);
147 if (result)
148 return result;
149
105150 gen_send(sock, "%s GSSAPI", command);
106151
107152 /* upon receipt of the GSSAPI authentication request, server returns
178178 NULL);
179179 if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
180180 decode_status("gss_init_sec_context", maj_stat, min_stat);
181 gss_release_name(&min_stat, &target_name);
181 (void)gss_release_name(&min_stat, &target_name);
182182 report(stderr, GT_("Error exchanging credentials\n"));
183183
184184 /* wake up server and await NO response */
imap.c
(1 / 1)
  
565565 }
566566
567567#ifdef GSSAPI
568 if ((ctl->server.authenticate == A_ANY
568 if (((ctl->server.authenticate == A_ANY && check_gss_creds("imap", ctl->server.truename) == PS_SUCCESS)
569569 || ctl->server.authenticate == A_GSSAPI)
570570 && strstr(capabilities, "AUTH=GSSAPI"))
571571 {
pop3.c
(2 / 1)
  
565565#if defined(GSSAPI)
566566 if (has_gssapi &&
567567 (ctl->server.authenticate == A_GSSAPI ||
568 ctl->server.authenticate == A_ANY))
568 (ctl->server.authenticate == A_ANY
569 && check_gss_creds("pop", ctl->server.truename) == PS_SUCCESS)))
569570 {
570571 ok = do_gssauth(sock,"AUTH","pop",ctl->server.truename,ctl->remotename);
571572 if (ok == PS_SUCCESS || ctl->server.authenticate != A_ANY)