Commit 6a637bb9 6a637bb9fea8581dcda7f310d60d5033a20ac73d by Sergey Poznyakoff

Fix GSASL in imap4d.

* auth/gsasl.c (_gsasl_readline): Prevent stucking in
blocking streams.
* imap4d/auth_gsasl.c: Remove deprecated functions and data types.
* imap4d/auth_gss.c (auth_gssapi): Fix signature.
* imap4d/copy.c (imap4d_copy0): Fix return value.
* imap4d/imap4d.c (imap4d_cfg_param): Fix type of login-disabled.
* include/mailutils/gsasl.h (struct mu_gsasl_module_data): New
members: service, realm, hostname, anon_user.
* libcfg/gsasl.c (mu_gsasl_param): New keywords: service,
realm, hostname, anonymous-user.
1 parent d1dbce46
1 2008-08-14 Sergey Poznyakoff <gray@gnu.org.ua>
2
3 Fix GSASL in imap4d.
4 * auth/gsasl.c (_gsasl_readline): Prevent stucking in
5 blocking streams.
6 * imap4d/auth_gsasl.c: Remove deprecated functions and data types.
7 * imap4d/auth_gss.c (auth_gssapi): Fix signature.
8 * imap4d/copy.c (imap4d_copy0): Fix return value.
9 * imap4d/imap4d.c (imap4d_cfg_param): Fix type of login-disabled.
10 * include/mailutils/gsasl.h (struct mu_gsasl_module_data): New
11 members: service, realm, hostname, anon_user.
12 * libcfg/gsasl.c (mu_gsasl_param): New keywords: service,
13 realm, hostname, anonymous-user.
14
1 2008-08-13 Sergey Poznyakoff <gray@gnu.org.ua> 15 2008-08-13 Sergey Poznyakoff <gray@gnu.org.ua>
2 16
3 * imap4d/util.c (imap4d_readline): Fix loop break condition. 17 * imap4d/util.c (imap4d_readline): Fix loop break condition.
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 2 Copyright (C) 2003, 2004, 2005, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -90,11 +90,11 @@ _gsasl_readline (mu_stream_t stream, char *optr, size_t osize, ...@@ -90,11 +90,11 @@ _gsasl_readline (mu_stream_t stream, char *optr, size_t osize,
90 90
91 do 91 do
92 { 92 {
93 char buf[80]; 93 char c;
94 size_t sz; 94 size_t sz;
95 int status; 95 int status;
96 96
97 status = mu_stream_sequential_read (s->stream, buf, sizeof (buf), &sz); 97 status = mu_stream_sequential_read (s->stream, &c, 1, &sz);
98 if (status == EINTR) 98 if (status == EINTR)
99 continue; 99 continue;
100 else if (status) 100 else if (status)
...@@ -102,10 +102,10 @@ _gsasl_readline (mu_stream_t stream, char *optr, size_t osize, ...@@ -102,10 +102,10 @@ _gsasl_readline (mu_stream_t stream, char *optr, size_t osize,
102 free (bufp); 102 free (bufp);
103 return status; 103 return status;
104 } 104 }
105 rc = _auth_lb_grow (s->lb, buf, sz); 105 rc = _auth_lb_grow (s->lb, &c, sz);
106 if (rc) 106 if (rc)
107 return rc; 107 return rc;
108 108
109 rc = gsasl_decode (s->sess_ctx, 109 rc = gsasl_decode (s->sess_ctx,
110 _auth_lb_data (s->lb), 110 _auth_lb_data (s->lb),
111 _auth_lb_level (s->lb), 111 _auth_lb_level (s->lb),
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
23 # include <mailutils/sql.h> 23 # include <mailutils/sql.h>
24 #endif 24 #endif
25 25
26 static Gsasl_ctx *ctx; 26 static Gsasl *ctx;
27 static Gsasl_session_ctx *sess_ctx; 27 static Gsasl_session *sess_ctx;
28 28
29 static void auth_gsasl_capa_init (int disable); 29 static void auth_gsasl_capa_init (int disable);
30 30
...@@ -69,20 +69,17 @@ gsasl_replace_streams (void *self, void *data) ...@@ -69,20 +69,17 @@ gsasl_replace_streams (void *self, void *data)
69 static void 69 static void
70 finish_session (void) 70 finish_session (void)
71 { 71 {
72 gsasl_server_finish (sess_ctx); 72 gsasl_finish (sess_ctx);
73 } 73 }
74 74
75 static int 75 static int
76 auth_gsasl (struct imap4d_command *command, 76 auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
77 char *auth_type, char *arg, char **username)
78 { 77 {
79 char *input = NULL; 78 char *input_str = NULL;
79 size_t input_size = 0;
80 size_t input_len;
80 char *output; 81 char *output;
81 char *s;
82 int rc; 82 int rc;
83
84 input = util_getword (arg, &s);
85 util_unquote (&input);
86 83
87 rc = gsasl_server_start (ctx, auth_type, &sess_ctx); 84 rc = gsasl_server_start (ctx, auth_type, &sess_ctx);
88 if (rc != GSASL_OK) 85 if (rc != GSASL_OK)
...@@ -92,18 +89,21 @@ auth_gsasl (struct imap4d_command *command, ...@@ -92,18 +89,21 @@ auth_gsasl (struct imap4d_command *command,
92 return 0; 89 return 0;
93 } 90 }
94 91
95 gsasl_server_application_data_set (sess_ctx, username); 92 gsasl_callback_hook_set (ctx, username);
96 93
97 output = NULL; 94 output = NULL;
98 while ((rc = gsasl_step64 (sess_ctx, input, &output)) == GSASL_NEEDS_MORE) 95 while ((rc = gsasl_step64 (sess_ctx, input_str, &output))
96 == GSASL_NEEDS_MORE)
99 { 97 {
100 util_send ("+ %s\r\n", output); 98 util_send ("+ %s\r\n", output);
101 input = imap4d_readline_ex (); 99 imap4d_getline (&input_str, &input_size, &input_len);
102 } 100 }
103 101
102 free (input_str);
104 if (rc != GSASL_OK) 103 if (rc != GSASL_OK)
105 { 104 {
106 mu_diag_output (MU_DIAG_NOTICE, _("GSASL error: %s"), gsasl_strerror (rc)); 105 mu_diag_output (MU_DIAG_NOTICE, _("GSASL error: %s"),
106 gsasl_strerror (rc));
107 free (output); 107 free (output);
108 return RESP_NO; 108 return RESP_NO;
109 } 109 }
...@@ -169,133 +169,142 @@ auth_gsasl_capa_init (int disable) ...@@ -169,133 +169,142 @@ auth_gsasl_capa_init (int disable)
169 free (listmech); 169 free (listmech);
170 } 170 }
171 171
172 /* This is for DIGEST-MD5 */ 172 #define IMAP_GSSAPI_SERVICE "imap"
173
173 static int 174 static int
174 cb_realm (Gsasl_session_ctx *ctx, char *out, size_t *outlen, size_t nth) 175 retrieve_password (Gsasl *ctx, Gsasl_session *sctx)
175 { 176 {
176 char *realm = util_localname (); 177 char **username = gsasl_callback_hook_get (ctx);
177 178 char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
178 if (nth > 0) 179
179 return GSASL_NO_MORE_REALMS; 180 if (username && *username == 0)
181 *username = strdup (authid);
180 182
181 if (out) 183 if (mu_gsasl_module_data.cram_md5_pwd
184 && access (mu_gsasl_module_data.cram_md5_pwd, R_OK) == 0)
182 { 185 {
183 if (*outlen < strlen (realm)) 186 char *key;
184 return GSASL_TOO_SMALL_BUFFER; 187 int rc = gsasl_simple_getpass (mu_gsasl_module_data.cram_md5_pwd,
185 memcpy (out, realm, strlen (realm)); 188 authid, &key);
189 if (rc == GSASL_OK)
190 {
191 gsasl_property_set (sctx, GSASL_PASSWORD, key);
192 free (key);
193 return rc;
194 }
186 } 195 }
187 196
188 *outlen = strlen (realm); 197 #ifdef USE_SQL
189 198 if (mu_sql_module_config.password_type == password_plaintext)
190 return GSASL_OK; 199 {
200 char *passwd;
201 int status = mu_sql_getpass (*username, &passwd);
202 if (status == 0)
203 {
204 gsasl_property_set (sctx, GSASL_PASSWORD, passwd);
205 free (passwd);
206 return GSASL_OK;
207 }
208 }
209 #endif
210
211 return GSASL_AUTHENTICATION_ERROR;
191 } 212 }
192 213
193 static int 214 static int
194 cb_validate (Gsasl_session_ctx *ctx, 215 cb_validate (Gsasl *ctx, Gsasl_session *sctx)
195 const char *authorization_id,
196 const char *authentication_id,
197 const char *password)
198 { 216 {
199 int rc; 217 int rc;
200 struct mu_auth_data *auth; 218 struct mu_auth_data *auth;
201 char **username = gsasl_server_application_data_get (ctx); 219 char **username = gsasl_callback_hook_get (ctx);
202 220 const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
203 *username = strdup (authentication_id ? 221 const char *pass = gsasl_property_get (sctx, GSASL_PASSWORD);
204 authentication_id : authorization_id); 222
223 if (!authid)
224 return GSASL_NO_AUTHID;
225 if (!pass)
226 return GSASL_NO_PASSWORD;
205 227
206 auth_data = mu_get_auth_by_name (*username); 228 *username = strdup (authid);
229
230 auth = mu_get_auth_by_name (*username);
207 231
208 if (auth_data == NULL) 232 if (auth == NULL)
209 return GSASL_AUTHENTICATION_ERROR; 233 return GSASL_AUTHENTICATION_ERROR;
210 234
211 rc = mu_authenticate (auth, password); 235 rc = mu_authenticate (auth, pass);
212 mu_auth_data_free (auth); 236 mu_auth_data_free (auth);
213 237
214 return rc == 0 ? GSASL_OK : GSASL_AUTHENTICATION_ERROR; 238 return rc == 0 ? GSASL_OK : GSASL_AUTHENTICATION_ERROR;
215 } 239 }
216 240
217 #define GSSAPI_SERVICE "imap"
218
219 static int
220 cb_service (Gsasl_session_ctx *ctx, char *srv, size_t *srvlen,
221 char *host, size_t *hostlen)
222 {
223 char *hostname = util_localname ();
224
225 if (srv)
226 {
227 if (*srvlen < strlen (GSSAPI_SERVICE))
228 return GSASL_TOO_SMALL_BUFFER;
229
230 memcpy (srv, GSSAPI_SERVICE, strlen (GSSAPI_SERVICE));
231 }
232
233 if (srvlen)
234 *srvlen = strlen (GSSAPI_SERVICE);
235
236 if (host)
237 {
238 if (*hostlen < strlen (hostname))
239 return GSASL_TOO_SMALL_BUFFER;
240
241 memcpy (host, hostname, strlen (hostname));
242 }
243
244 if (hostlen)
245 *hostlen = strlen (hostname);
246
247 return GSASL_OK;
248 }
249
250 /* This gets called when SASL mechanism EXTERNAL is invoked */
251 static int
252 cb_external (Gsasl_session_ctx *ctx)
253 {
254 return GSASL_AUTHENTICATION_ERROR;
255 }
256
257 /* This gets called when SASL mechanism CRAM-MD5 or DIGEST-MD5 is invoked */
258
259 static int 241 static int
260 cb_retrieve (Gsasl_session_ctx *ctx, 242 callback (Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
261 const char *authentication_id,
262 const char *authorization_id,
263 const char *realm,
264 char *key,
265 size_t *keylen)
266 { 243 {
267 char **username = gsasl_server_application_data_get (ctx); 244 int rc = GSASL_OK;
268
269 if (username && *username == 0 && authentication_id)
270 *username = strdup (authentication_id);
271 245
272 if (mu_gsasl_module_data.cram_md5_pwd 246 switch (prop) {
273 && access (mu_gsasl_module_data.cram_md5_pwd, R_OK) == 0) 247 case GSASL_PASSWORD:
274 { 248 rc = retrieve_password (ctx, sctx);
275 int rc = gsasl_md5pwd_get_password (mu_gsasl_module_data.cram_md5_pwd, 249 break;
276 authentication_id, 250
277 key, keylen); 251 case GSASL_SERVICE:
278 if (rc == GSASL_OK) 252 gsasl_property_set (sctx, prop,
279 return rc; 253 mu_gsasl_module_data.service ?
280 } 254 mu_gsasl_module_data.service :IMAP_GSSAPI_SERVICE);
281 255 break;
282 #ifdef USE_SQL 256
283 if (mu_sql_module_config.password_type == password_plaintext) 257 case GSASL_REALM:
284 { 258 gsasl_property_set (sctx, prop,
285 char *passwd; 259 mu_gsasl_module_data.realm ?
286 int status = mu_sql_getpass (username, &passwd); 260 mu_gsasl_module_data.realm : util_localname ());
287 if (status == 0) 261 break;
262
263 case GSASL_HOSTNAME:
264 gsasl_property_set (sctx, prop,
265 mu_gsasl_module_data.hostname ?
266 mu_gsasl_module_data.hostname : util_localname ());
267 break;
268
269 #if 0
270 FIXME:
271 case GSASL_VALIDATE_EXTERNAL:
272 case GSASL_VALIDATE_SECURID:
273 #endif
274
275 case GSASL_VALIDATE_SIMPLE:
276 rc = cb_validate (ctx, sctx);
277 break;
278
279 case GSASL_VALIDATE_ANONYMOUS:
280 if (mu_gsasl_module_data.anon_user)
288 { 281 {
289 *keylen = strlen (passwd); 282 char **username = gsasl_callback_hook_get (ctx);
290 if (key) 283 mu_diag_output (MU_DIAG_INFO, _("Anonymous user %s logged in"),
291 memcpy (key, passwd, *keylen); 284 gsasl_property_get (sctx, GSASL_ANONYMOUS_TOKEN));
292 free (passwd); 285 *username = strdup (mu_gsasl_module_data.anon_user);
293 return GSASL_OK;
294 } 286 }
287 else
288 {
289 mu_diag_output (MU_DIAG_ERR,
290 _("Attempt to log in as anonymous user denied"));
291 }
292 break;
293
294 case GSASL_VALIDATE_GSSAPI:
295 {
296 char **username = gsasl_callback_hook_get (ctx);
297 *username = strdup (gsasl_property_get(sctx, GSASL_AUTHZID));
298 break;
299 }
300
301 default:
302 rc = GSASL_NO_CALLBACK;
303 mu_error (_("Unsupported callback property %d"), prop);
304 break;
295 } 305 }
296 #endif 306
297 307 return rc;
298 return GSASL_AUTHENTICATION_ERROR;
299 } 308 }
300 309
301 void 310 void
...@@ -310,12 +319,7 @@ auth_gsasl_init () ...@@ -310,12 +319,7 @@ auth_gsasl_init ()
310 gsasl_strerror (rc)); 319 gsasl_strerror (rc));
311 } 320 }
312 321
313 gsasl_server_callback_realm_set (ctx, cb_realm); 322 gsasl_callback_set (ctx, callback);
314 gsasl_server_callback_external_set (ctx, cb_external);
315 gsasl_server_callback_validate_set (ctx, cb_validate);
316 gsasl_server_callback_service_set (ctx, cb_service);
317
318 gsasl_server_callback_retrieve_set (ctx, cb_retrieve);
319 323
320 auth_gsasl_capa_init (0); 324 auth_gsasl_capa_init (0);
321 } 325 }
......
...@@ -110,7 +110,7 @@ imap4d_gss_userok (gss_buffer_t client_name, char *name) ...@@ -110,7 +110,7 @@ imap4d_gss_userok (gss_buffer_t client_name, char *name)
110 110
111 static int 111 static int
112 auth_gssapi (struct imap4d_command *command, 112 auth_gssapi (struct imap4d_command *command,
113 char *auth_type_unused, char *arg_unused, char **username) 113 char *auth_type_unused, char **username)
114 { 114 {
115 gss_buffer_desc tokbuf, outbuf; 115 gss_buffer_desc tokbuf, outbuf;
116 OM_uint32 maj_stat, min_stat, min_stat2; 116 OM_uint32 maj_stat, min_stat, min_stat2;
......
...@@ -130,6 +130,6 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) ...@@ -130,6 +130,6 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
130 of the text of the tagged NO response. This gives a hint to the 130 of the text of the tagged NO response. This gives a hint to the
131 client that it can attempt a CREATE command and retry the copy if 131 client that it can attempt a CREATE command and retry the copy if
132 the CREATE is successful. */ 132 the CREATE is successful. */
133 *err_text = "NO [TRYCREATE] failed"; 133 *err_text = "[TRYCREATE] failed";
134 return RESP_NONE; 134 return RESP_NO;
135 } 135 }
......
...@@ -294,7 +294,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = { ...@@ -294,7 +294,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
294 { "shared-namespace", mu_cfg_callback, NULL, 0, cb_shared, 294 { "shared-namespace", mu_cfg_callback, NULL, 0, cb_shared,
295 N_("Set shared namespace. Argument is a colon-separated list " 295 N_("Set shared namespace. Argument is a colon-separated list "
296 "of directories comprising the namespace.") }, 296 "of directories comprising the namespace.") },
297 { "login-disabled", mu_cfg_int, &login_disabled, 0, NULL, 297 { "login-disabled", mu_cfg_bool, &login_disabled, 0, NULL,
298 N_("Disable LOGIN command.") }, 298 N_("Disable LOGIN command.") },
299 { "create-home-dir", mu_cfg_bool, &create_home_dir, 0, NULL, 299 { "create-home-dir", mu_cfg_bool, &create_home_dir, 0, NULL,
300 N_("If true, create non-existing user home directories.") }, 300 N_("If true, create non-existing user home directories.") },
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
21 21
22 struct mu_gsasl_module_data 22 struct mu_gsasl_module_data
23 { 23 {
24 char *service;
25 char *realm;
26 char *hostname;
27 char *anon_user;
24 char *cram_md5_pwd; 28 char *cram_md5_pwd;
25 }; 29 };
26 30
......
...@@ -28,6 +28,19 @@ static struct mu_cfg_param mu_gsasl_param[] = { ...@@ -28,6 +28,19 @@ static struct mu_cfg_param mu_gsasl_param[] = {
28 { "cram-passwd", mu_cfg_string, &gsasl_settings.cram_md5_pwd, 0, NULL, 28 { "cram-passwd", mu_cfg_string, &gsasl_settings.cram_md5_pwd, 0, NULL,
29 N_("Name of GSASL password file."), 29 N_("Name of GSASL password file."),
30 N_("file") }, 30 N_("file") },
31 { "service", mu_cfg_string, &gsasl_settings.service, 0, NULL,
32 N_("SASL service name."),
33 N_("name") },
34 { "realm", mu_cfg_string, &gsasl_settings.realm, 0, NULL,
35 N_("SASL realm name."),
36 N_("name") },
37 { "hostname", mu_cfg_string, &gsasl_settings.hostname, 0, NULL,
38 N_("SASL host name."),
39 N_("name") },
40 { "anonymous-user", mu_cfg_string, &gsasl_settings.anon_user, 0, NULL,
41 N_("Anonymous user name."),
42 N_("name") },
43
31 { NULL } 44 { NULL }
32 }; 45 };
33 46
......