/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003-2021 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
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
. */
#if HAVE_CONFIG_H
# include
#endif
#include
#include
#ifdef WITH_GSASL
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct mu_gsasl_module_data mu_gsasl_module_data = {
.enable = 1,
.cram_md5_pwd = SITE_CRAM_MD5_PWD
};
static struct mu_cfg_param mu_gsasl_param[] = {
{ "enable", mu_c_bool, &mu_gsasl_module_data.enable, 0, NULL,
N_("Enable GSASL (default)") },
{ "cram-passwd", mu_c_string, &mu_gsasl_module_data.cram_md5_pwd, 0, NULL,
N_("Name of GSASL password file."),
N_("file") },
{ "service", mu_c_string, &mu_gsasl_module_data.service, 0, NULL,
N_("SASL service name."),
N_("name") },
{ "realm", mu_c_string, &mu_gsasl_module_data.realm, 0, NULL,
N_("SASL realm name."),
N_("name") },
{ "hostname", mu_c_string, &mu_gsasl_module_data.hostname, 0, NULL,
N_("SASL host name."),
N_("name") },
{ "anonymous-user", mu_c_string, &mu_gsasl_module_data.anon_user, 0, NULL,
N_("Anonymous user name."),
N_("name") },
{ NULL }
};
int
mu_gsasl_enabled (void)
{
return mu_gsasl_module_data.enable;
}
static enum mu_filter_result
_gsasl_encoder (void *xdata,
enum mu_filter_command cmd,
struct mu_filter_io *iobuf)
{
struct _mu_gsasl_filter *flt = xdata;
switch (cmd)
{
case mu_filter_init:
flt->bufptr = NULL;
flt->bufsize = 0;
flt->gsasl_err = 0;
return mu_filter_ok;
case mu_filter_done:
if (flt->bufptr)
free (flt->bufptr);
return mu_filter_ok;
default:
break;
}
if (flt->bufptr == NULL)
{
int status = gsasl_encode (flt->sess_ctx, iobuf->input, iobuf->isize,
&flt->bufptr, &flt->bufsize);
/* FIXME: Can it require more input? */
if (status)
{
flt->gsasl_err = status;
return mu_filter_failure;
}
}
iobuf->osize = flt->bufsize;
if (flt->bufsize > iobuf->osize)
return mu_filter_moreoutput;
memcpy (iobuf->output, flt->bufptr, flt->bufsize);
free (flt->bufptr);
flt->bufptr = NULL;
flt->bufsize = 0;
return mu_filter_ok;
}
static enum mu_filter_result
_gsasl_decoder (void *xdata,
enum mu_filter_command cmd,
struct mu_filter_io *iobuf)
{
struct _mu_gsasl_filter *flt = xdata;
int status;
switch (cmd)
{
case mu_filter_init:
flt->bufptr = NULL;
flt->bufsize = 0;
flt->gsasl_err = 0;
return mu_filter_ok;
case mu_filter_done:
if (flt->bufptr)
free (flt->bufptr);
return mu_filter_ok;
default:
break;
}
if (flt->bufptr == NULL)
{
status = gsasl_decode (flt->sess_ctx, iobuf->input, iobuf->isize,
&flt->bufptr, &flt->bufsize);
switch (status)
{
case GSASL_OK:
break;
case GSASL_NEEDS_MORE:
iobuf->isize++;
return mu_filter_moreinput;
default:
flt->gsasl_err = status;
return mu_filter_failure;
}
}
iobuf->osize = flt->bufsize;
if (flt->bufsize > iobuf->osize)
return mu_filter_moreoutput;
memcpy (iobuf->output, flt->bufptr, flt->bufsize);
free (flt->bufptr);
flt->bufptr = NULL;
flt->bufsize = 0;
return mu_filter_ok;
}
int
gsasl_encoder_stream (mu_stream_t *pstr, mu_stream_t transport,
Gsasl_session *ctx, int flags)
{
int rc;
struct _mu_gsasl_filter *flt = calloc (1, sizeof (*flt));
flt->sess_ctx = ctx;
rc = mu_filter_stream_create (pstr, transport,
MU_FILTER_ENCODE,
_gsasl_encoder,
flt, flags);
if (rc == 0)
mu_stream_set_buffer (*pstr, mu_buffer_line, 0);
return rc;
}
int
gsasl_decoder_stream (mu_stream_t *pstr, mu_stream_t transport,
Gsasl_session *ctx, int flags)
{
int rc;
struct _mu_gsasl_filter *flt = calloc (1, sizeof (*flt));
flt->sess_ctx = ctx;
rc = mu_filter_stream_create (pstr, transport,
MU_FILTER_DECODE,
_gsasl_decoder,
flt, flags);
if (rc == 0)
mu_stream_set_buffer (*pstr, mu_buffer_line, 0);
return rc;
}
int
mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
Gsasl_session *ctx, int flags)
{
int rc;
mu_stream_t in, out;
if (stream == NULL)
return MU_ERR_OUT_PTR_NULL;
rc = gsasl_encoder_stream (&in, transport, ctx, MU_STREAM_READ);
if (rc)
return rc;
rc = gsasl_decoder_stream (&out, transport, ctx, MU_STREAM_WRITE);
if (rc)
{
mu_stream_destroy (&in);
return rc;
}
rc = mu_iostream_create (stream, in, out);
mu_stream_unref (in);
mu_stream_unref (out);
return rc;
}
#else
int
mu_gsasl_enabled (void)
{
return 0;
}
#define mu_gsasl_param NULL
#endif
struct mu_auth_module mu_auth_gsasl_module = {
.name = "gsasl",
.cfg = mu_gsasl_param
};