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
2008-08-14 Sergey Poznyakoff <gray@gnu.org.ua>
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.
2008-08-13 Sergey Poznyakoff <gray@gnu.org.ua>
* imap4d/util.c (imap4d_readline): Fix loop break condition.
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
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,
do
{
char buf[80];
char c;
size_t sz;
int status;
status = mu_stream_sequential_read (s->stream, buf, sizeof (buf), &sz);
status = mu_stream_sequential_read (s->stream, &c, 1, &sz);
if (status == EINTR)
continue;
else if (status)
......@@ -102,10 +102,10 @@ _gsasl_readline (mu_stream_t stream, char *optr, size_t osize,
free (bufp);
return status;
}
rc = _auth_lb_grow (s->lb, buf, sz);
rc = _auth_lb_grow (s->lb, &c, sz);
if (rc)
return rc;
rc = gsasl_decode (s->sess_ctx,
_auth_lb_data (s->lb),
_auth_lb_level (s->lb),
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -23,8 +23,8 @@
# include <mailutils/sql.h>
#endif
static Gsasl_ctx *ctx;
static Gsasl_session_ctx *sess_ctx;
static Gsasl *ctx;
static Gsasl_session *sess_ctx;
static void auth_gsasl_capa_init (int disable);
......@@ -69,20 +69,17 @@ gsasl_replace_streams (void *self, void *data)
static void
finish_session (void)
{
gsasl_server_finish (sess_ctx);
gsasl_finish (sess_ctx);
}
static int
auth_gsasl (struct imap4d_command *command,
char *auth_type, char *arg, char **username)
auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
{
char *input = NULL;
char *input_str = NULL;
size_t input_size = 0;
size_t input_len;
char *output;
char *s;
int rc;
input = util_getword (arg, &s);
util_unquote (&input);
rc = gsasl_server_start (ctx, auth_type, &sess_ctx);
if (rc != GSASL_OK)
......@@ -92,18 +89,21 @@ auth_gsasl (struct imap4d_command *command,
return 0;
}
gsasl_server_application_data_set (sess_ctx, username);
gsasl_callback_hook_set (ctx, username);
output = NULL;
while ((rc = gsasl_step64 (sess_ctx, input, &output)) == GSASL_NEEDS_MORE)
while ((rc = gsasl_step64 (sess_ctx, input_str, &output))
== GSASL_NEEDS_MORE)
{
util_send ("+ %s\r\n", output);
input = imap4d_readline_ex ();
imap4d_getline (&input_str, &input_size, &input_len);
}
free (input_str);
if (rc != GSASL_OK)
{
mu_diag_output (MU_DIAG_NOTICE, _("GSASL error: %s"), gsasl_strerror (rc));
mu_diag_output (MU_DIAG_NOTICE, _("GSASL error: %s"),
gsasl_strerror (rc));
free (output);
return RESP_NO;
}
......@@ -169,133 +169,142 @@ auth_gsasl_capa_init (int disable)
free (listmech);
}
/* This is for DIGEST-MD5 */
#define IMAP_GSSAPI_SERVICE "imap"
static int
cb_realm (Gsasl_session_ctx *ctx, char *out, size_t *outlen, size_t nth)
retrieve_password (Gsasl *ctx, Gsasl_session *sctx)
{
char *realm = util_localname ();
if (nth > 0)
return GSASL_NO_MORE_REALMS;
char **username = gsasl_callback_hook_get (ctx);
char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
if (username && *username == 0)
*username = strdup (authid);
if (out)
if (mu_gsasl_module_data.cram_md5_pwd
&& access (mu_gsasl_module_data.cram_md5_pwd, R_OK) == 0)
{
if (*outlen < strlen (realm))
return GSASL_TOO_SMALL_BUFFER;
memcpy (out, realm, strlen (realm));
char *key;
int rc = gsasl_simple_getpass (mu_gsasl_module_data.cram_md5_pwd,
authid, &key);
if (rc == GSASL_OK)
{
gsasl_property_set (sctx, GSASL_PASSWORD, key);
free (key);
return rc;
}
}
*outlen = strlen (realm);
return GSASL_OK;
#ifdef USE_SQL
if (mu_sql_module_config.password_type == password_plaintext)
{
char *passwd;
int status = mu_sql_getpass (*username, &passwd);
if (status == 0)
{
gsasl_property_set (sctx, GSASL_PASSWORD, passwd);
free (passwd);
return GSASL_OK;
}
}
#endif
return GSASL_AUTHENTICATION_ERROR;
}
static int
cb_validate (Gsasl_session_ctx *ctx,
const char *authorization_id,
const char *authentication_id,
const char *password)
cb_validate (Gsasl *ctx, Gsasl_session *sctx)
{
int rc;
struct mu_auth_data *auth;
char **username = gsasl_server_application_data_get (ctx);
*username = strdup (authentication_id ?
authentication_id : authorization_id);
char **username = gsasl_callback_hook_get (ctx);
const char *authid = gsasl_property_get (sctx, GSASL_AUTHID);
const char *pass = gsasl_property_get (sctx, GSASL_PASSWORD);
if (!authid)
return GSASL_NO_AUTHID;
if (!pass)
return GSASL_NO_PASSWORD;
auth_data = mu_get_auth_by_name (*username);
*username = strdup (authid);
auth = mu_get_auth_by_name (*username);
if (auth_data == NULL)
if (auth == NULL)
return GSASL_AUTHENTICATION_ERROR;
rc = mu_authenticate (auth, password);
rc = mu_authenticate (auth, pass);
mu_auth_data_free (auth);
return rc == 0 ? GSASL_OK : GSASL_AUTHENTICATION_ERROR;
}
#define GSSAPI_SERVICE "imap"
static int
cb_service (Gsasl_session_ctx *ctx, char *srv, size_t *srvlen,
char *host, size_t *hostlen)
{
char *hostname = util_localname ();
if (srv)
{
if (*srvlen < strlen (GSSAPI_SERVICE))
return GSASL_TOO_SMALL_BUFFER;
memcpy (srv, GSSAPI_SERVICE, strlen (GSSAPI_SERVICE));
}
if (srvlen)
*srvlen = strlen (GSSAPI_SERVICE);
if (host)
{
if (*hostlen < strlen (hostname))
return GSASL_TOO_SMALL_BUFFER;
memcpy (host, hostname, strlen (hostname));
}
if (hostlen)
*hostlen = strlen (hostname);
return GSASL_OK;
}
/* This gets called when SASL mechanism EXTERNAL is invoked */
static int
cb_external (Gsasl_session_ctx *ctx)
{
return GSASL_AUTHENTICATION_ERROR;
}
/* This gets called when SASL mechanism CRAM-MD5 or DIGEST-MD5 is invoked */
static int
cb_retrieve (Gsasl_session_ctx *ctx,
const char *authentication_id,
const char *authorization_id,
const char *realm,
char *key,
size_t *keylen)
callback (Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
{
char **username = gsasl_server_application_data_get (ctx);
if (username && *username == 0 && authentication_id)
*username = strdup (authentication_id);
int rc = GSASL_OK;
if (mu_gsasl_module_data.cram_md5_pwd
&& access (mu_gsasl_module_data.cram_md5_pwd, R_OK) == 0)
{
int rc = gsasl_md5pwd_get_password (mu_gsasl_module_data.cram_md5_pwd,
authentication_id,
key, keylen);
if (rc == GSASL_OK)
return rc;
}
#ifdef USE_SQL
if (mu_sql_module_config.password_type == password_plaintext)
{
char *passwd;
int status = mu_sql_getpass (username, &passwd);
if (status == 0)
switch (prop) {
case GSASL_PASSWORD:
rc = retrieve_password (ctx, sctx);
break;
case GSASL_SERVICE:
gsasl_property_set (sctx, prop,
mu_gsasl_module_data.service ?
mu_gsasl_module_data.service :IMAP_GSSAPI_SERVICE);
break;
case GSASL_REALM:
gsasl_property_set (sctx, prop,
mu_gsasl_module_data.realm ?
mu_gsasl_module_data.realm : util_localname ());
break;
case GSASL_HOSTNAME:
gsasl_property_set (sctx, prop,
mu_gsasl_module_data.hostname ?
mu_gsasl_module_data.hostname : util_localname ());
break;
#if 0
FIXME:
case GSASL_VALIDATE_EXTERNAL:
case GSASL_VALIDATE_SECURID:
#endif
case GSASL_VALIDATE_SIMPLE:
rc = cb_validate (ctx, sctx);
break;
case GSASL_VALIDATE_ANONYMOUS:
if (mu_gsasl_module_data.anon_user)
{
*keylen = strlen (passwd);
if (key)
memcpy (key, passwd, *keylen);
free (passwd);
return GSASL_OK;
char **username = gsasl_callback_hook_get (ctx);
mu_diag_output (MU_DIAG_INFO, _("Anonymous user %s logged in"),
gsasl_property_get (sctx, GSASL_ANONYMOUS_TOKEN));
*username = strdup (mu_gsasl_module_data.anon_user);
}
else
{
mu_diag_output (MU_DIAG_ERR,
_("Attempt to log in as anonymous user denied"));
}
break;
case GSASL_VALIDATE_GSSAPI:
{
char **username = gsasl_callback_hook_get (ctx);
*username = strdup (gsasl_property_get(sctx, GSASL_AUTHZID));
break;
}
default:
rc = GSASL_NO_CALLBACK;
mu_error (_("Unsupported callback property %d"), prop);
break;
}
#endif
return GSASL_AUTHENTICATION_ERROR;
return rc;
}
void
......@@ -310,12 +319,7 @@ auth_gsasl_init ()
gsasl_strerror (rc));
}
gsasl_server_callback_realm_set (ctx, cb_realm);
gsasl_server_callback_external_set (ctx, cb_external);
gsasl_server_callback_validate_set (ctx, cb_validate);
gsasl_server_callback_service_set (ctx, cb_service);
gsasl_server_callback_retrieve_set (ctx, cb_retrieve);
gsasl_callback_set (ctx, callback);
auth_gsasl_capa_init (0);
}
......
......@@ -110,7 +110,7 @@ imap4d_gss_userok (gss_buffer_t client_name, char *name)
static int
auth_gssapi (struct imap4d_command *command,
char *auth_type_unused, char *arg_unused, char **username)
char *auth_type_unused, char **username)
{
gss_buffer_desc tokbuf, outbuf;
OM_uint32 maj_stat, min_stat, min_stat2;
......
......@@ -130,6 +130,6 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
of the text of the tagged NO response. This gives a hint to the
client that it can attempt a CREATE command and retry the copy if
the CREATE is successful. */
*err_text = "NO [TRYCREATE] failed";
return RESP_NONE;
*err_text = "[TRYCREATE] failed";
return RESP_NO;
}
......
......@@ -294,7 +294,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
{ "shared-namespace", mu_cfg_callback, NULL, 0, cb_shared,
N_("Set shared namespace. Argument is a colon-separated list "
"of directories comprising the namespace.") },
{ "login-disabled", mu_cfg_int, &login_disabled, 0, NULL,
{ "login-disabled", mu_cfg_bool, &login_disabled, 0, NULL,
N_("Disable LOGIN command.") },
{ "create-home-dir", mu_cfg_bool, &create_home_dir, 0, NULL,
N_("If true, create non-existing user home directories.") },
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
......@@ -21,6 +21,10 @@
struct mu_gsasl_module_data
{
char *service;
char *realm;
char *hostname;
char *anon_user;
char *cram_md5_pwd;
};
......
......@@ -28,6 +28,19 @@ static struct mu_cfg_param mu_gsasl_param[] = {
{ "cram-passwd", mu_cfg_string, &gsasl_settings.cram_md5_pwd, 0, NULL,
N_("Name of GSASL password file."),
N_("file") },
{ "service", mu_cfg_string, &gsasl_settings.service, 0, NULL,
N_("SASL service name."),
N_("name") },
{ "realm", mu_cfg_string, &gsasl_settings.realm, 0, NULL,
N_("SASL realm name."),
N_("name") },
{ "hostname", mu_cfg_string, &gsasl_settings.hostname, 0, NULL,
N_("SASL host name."),
N_("name") },
{ "anonymous-user", mu_cfg_string, &gsasl_settings.anon_user, 0, NULL,
N_("Anonymous user name."),
N_("name") },
{ NULL }
};
......