Commit a0b65254 a0b652546f1cccc6c00c471b701f0449819cb258 by Sergey Poznyakoff

Implement SMTP AUTH (via GSASL).

* configure.ac (MU_COND_GSASL): New cond.
* include/mailutils/smtp.h (MU_SMTP_PARAM_DOMAIN)
(MU_SMTP_PARAM_USERNAME, MU_SMTP_PARAM_PASSWORD)
(MU_SMTP_PARAM_SERVICE, MU_SMTP_PARAM_REALM)
(MU_SMTP_PARAM_HOST, MU_SMTP_MAX_PARAM): New constants.
(mu_smtp_set_domain, mu_smtp_get_param): Remove.
(mu_smtp_set_param, mu_smtp_get_param): New prototypes.
(mu_smtp_auth, mu_smtp_add_auth_mech)
(mu_smtp_add_auth_mech_list, mu_smtp_mech_select): New prototypes.
* include/mailutils/sys/smtp.h (_mu_smtp) <domain>: Remove.
(_mu_smtp) <authimpl, param, authmech>: New members.
(_mu_smtp_gsasl_auth, _mu_smtp_mech_impl): New prototypes.

* libproto/mailer/Makefile.am [MU_COND_GSASL]: Define SMTP_GSASL.
(libmu_mailer_la_SOURCES): Add new sources.
* libproto/mailer/smtp_domain.c: Remove.
* libproto/mailer/smtp_param.c: New file.
* libproto/mailer/smtp_mech.c: New file.
* libproto/mailer/smtp_auth.c: New file.
* libproto/mailer/smtp_gsasl.c: New file.
* libproto/mailer/smtp_create.c (mu_smtp_destroy): Free new members of
struct _mu_smtp.
* libproto/mailer/smtp_ehlo.c (mu_smtp_ehlo): Use param[MU_SMTP_PARAM_DOMAIN]
instead of domain.
* testsuite/smtpsend.c: Handle SMTP AUTH.

* libmu_auth/gsasl.c (mu_gsasl_stream_create): Bugfix.

* libmailutils/xscript-stream.c (_xscript_ctl)
<MU_IOCTL_SWAP_STREAM>: If instream!=outstream, combine them first
into an iostream.
1 parent 790527fa
......@@ -287,6 +287,7 @@ MU_CHECK_GSASL(0.2.3, [
MU_AUTHLIBS="$MU_AUTHLIBS $GSASL_LIBS"
IMAP_AUTHOBJS="$IMAP_AUTHOBJS auth_gsasl.o"
status_gsasl=yes])
AM_CONDITIONAL([MU_COND_GSASL],[test "$status_gsasl" = "yes"])
AC_SUBST(SITE_CRAM_MD5_PWD,"\$(sysconfdir)/cram-md5.pwd")
......
......@@ -23,6 +23,18 @@
typedef struct _mu_smtp *mu_smtp_t;
enum
{
MU_SMTP_PARAM_DOMAIN,
MU_SMTP_PARAM_USERNAME,
MU_SMTP_PARAM_PASSWORD,
MU_SMTP_PARAM_SERVICE,
MU_SMTP_PARAM_REALM,
MU_SMTP_PARAM_HOST
};
#define MU_SMTP_MAX_PARAM (MU_SMTP_PARAM_HOST+1)
int mu_smtp_create (mu_smtp_t *);
void mu_smtp_destroy (mu_smtp_t *);
int mu_smtp_set_carrier (mu_smtp_t smtp, mu_stream_t str);
......@@ -40,8 +52,8 @@ int mu_smtp_trace_mask (mu_smtp_t smtp, int op, int lev);
int mu_smtp_disconnect (mu_smtp_t smtp);
int mu_smtp_ehlo (mu_smtp_t smtp);
int mu_smtp_set_domain (mu_smtp_t smtp, const char *newdom);
int mu_smtp_get_domain (mu_smtp_t smtp, const char **pdom);
int mu_smtp_set_param (mu_smtp_t smtp, int code, const char *val);
int mu_smtp_get_param (mu_smtp_t smtp, int code, const char **param);
int mu_smtp_capa_test (mu_smtp_t smtp, const char *capa, const char **pret);
int mu_smtp_starttls (mu_smtp_t smtp);
......@@ -51,4 +63,11 @@ int mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t str);
int mu_smtp_rset (mu_smtp_t smtp);
int mu_smtp_quit (mu_smtp_t smtp);
int mu_smtp_auth (mu_smtp_t smtp);
int mu_smtp_add_auth_mech (mu_smtp_t smtp, const char *mech);
int mu_smtp_clear_auth_mech (mu_smtp_t smtp);
int mu_smtp_add_auth_mech_list (mu_smtp_t smtp, mu_list_t list);
int mu_smtp_mech_select (mu_smtp_t smtp, const char **pmech);
#endif
......
......@@ -46,11 +46,17 @@ enum mu_smtp_state
struct _mu_smtp
{
int flags;
char *domain;
mu_stream_t carrier;
enum mu_smtp_state state;
mu_list_t capa;
mu_list_t authimpl; /* List of implemented authentication mechs */
/* User-supplied data */
char *param[MU_SMTP_MAX_PARAM];
mu_list_t authmech; /* List of allowed authentication mechs */
/* I/O buffers */
char replcode[4];
char *replptr;
......@@ -81,5 +87,7 @@ struct _mu_smtp
int _mu_smtp_trace_enable (mu_smtp_t smtp);
int _mu_smtp_trace_disable (mu_smtp_t smtp);
int _mu_smtp_xscript_level (mu_smtp_t smtp, int xlev);
int _mu_smtp_gsasl_auth (mu_smtp_t smtp);
int _mu_smtp_mech_impl (mu_smtp_t smtp, mu_list_t list);
#endif
......
......@@ -292,11 +292,17 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
mu_stream_t tmp;
if (pstr[0] != pstr[1])
return EINVAL; /* FIXME */
tmp = pstr[0];
{
status = mu_iostream_create (&tmp, pstr[0], pstr[1]);
if (status)
return status;
}
else
tmp = pstr[0];
pstr[0] = sp->transport;
pstr[1] = sp->transport;
sp->transport = tmp;
/* FIXME */
if (!(str->flags & MU_STREAM_AUTOCLOSE))
{
if (pstr[0])
......
......@@ -206,7 +206,7 @@ mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
rc = gsasl_encoder_stream (&in, transport, ctx, MU_STREAM_READ);
if (rc)
return rc;
rc = gsasl_encoder_stream (&out, transport, ctx, MU_STREAM_WRITE);
rc = gsasl_decoder_stream (&out, transport, ctx, MU_STREAM_WRITE);
if (rc)
{
mu_stream_destroy (&in);
......
......@@ -23,22 +23,30 @@ lib_LTLIBRARIES = libmu_mailer.la
libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
libmu_mailer_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
if MU_COND_GSASL
SMTP_GSASL=smtp_gsasl.c
endif
EXTRA_DIST=smtp_gsasl.c
libmu_mailer_la_SOURCES = \
mbox.c\
prog.c\
sendmail.c\
smtp.c\
smtp_auth.c\
smtp_capa.c\
smtp_carrier.c\
smtp_create.c\
smtp_data.c\
smtp_disconnect.c\
smtp_domain.c\
smtp_ehlo.c\
$(SMTP_GSASL)\
smtp_io.c\
smtp_mail.c\
smtp_rcpt.c\
smtp_mech.c\
smtp_open.c\
smtp_param.c\
smtp_rcpt.c\
smtp_rset.c\
smtp_starttls.c\
smtp_trace.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 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, 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <mailutils/errno.h>
#include <mailutils/smtp.h>
#include <mailutils/sys/smtp.h>
int
mu_smtp_auth (mu_smtp_t smtp)
{
if (!smtp)
return EINVAL;
if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
return MU_ERR_FAILURE;
if (MU_SMTP_FISSET (smtp, _MU_SMTP_AUTH))
return MU_ERR_SEQ;
if (smtp->state != MU_SMTP_MAIL)
return MU_ERR_SEQ;
#if defined(WITH_GSASL)
return _mu_smtp_gsasl_auth (smtp);
#else
/* FIXME: Provide support for some basic authentication methods */
return ENOSYS;
#endif
}
......@@ -45,6 +45,7 @@ mu_smtp_create (mu_smtp_t *psmtp)
void
mu_smtp_destroy (mu_smtp_t *psmtp)
{
int i;
struct _mu_smtp *smtp;
if (!psmtp || !*psmtp)
......@@ -52,9 +53,15 @@ mu_smtp_destroy (mu_smtp_t *psmtp)
smtp = *psmtp;
mu_stream_destroy (&smtp->carrier);
mu_list_destroy (&smtp->capa);
mu_list_destroy (&smtp->authimpl);
free (smtp->rdbuf);
free (smtp->flbuf);
mu_list_destroy (&smtp->mlrepl);
mu_list_destroy (&smtp->authmech);
for (i = 0; i < MU_SMTP_MAX_PARAM; i++)
free (smtp->param[i]);
free (smtp);
*psmtp = NULL;
}
......
......@@ -53,7 +53,7 @@ mu_smtp_ehlo (mu_smtp_t smtp)
if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
return MU_ERR_FAILURE;
if (!smtp->domain)
if (!smtp->param[MU_SMTP_PARAM_DOMAIN])
{
char *host;
char *p;
......@@ -65,11 +65,12 @@ mu_smtp_ehlo (mu_smtp_t smtp)
p++;
else
p = host;
status = mu_smtp_set_domain (smtp, p);
status = mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN, p);
MU_SMTP_CHECK_ERROR (smtp, status);
}
status = mu_smtp_write (smtp, "EHLO %s\r\n", smtp->domain);
status = mu_smtp_write (smtp, "EHLO %s\r\n",
smtp->param[MU_SMTP_PARAM_DOMAIN]);
MU_SMTP_CHECK_ERROR (smtp, status);
status = mu_smtp_response (smtp);
MU_SMTP_CHECK_ERROR (smtp, status);
......@@ -84,7 +85,8 @@ mu_smtp_ehlo (mu_smtp_t smtp)
return MU_ERR_REPLY;
else
{
status = mu_smtp_write (smtp, "HELO %s\r\n", smtp->domain);
status = mu_smtp_write (smtp, "HELO %s\r\n",
smtp->param[MU_SMTP_PARAM_DOMAIN]);
MU_SMTP_CHECK_ERROR (smtp, status);
status = mu_smtp_response (smtp);
MU_SMTP_CHECK_ERROR (smtp, status);
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 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, 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/argcv.h>
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/cctype.h>
#include <mailutils/list.h>
#include <mailutils/mutil.h>
#include <mailutils/smtp.h>
#include <mailutils/stream.h>
#include <mailutils/sys/smtp.h>
#include <mailutils/gsasl.h>
#include <gsasl.h>
static int
get_implemented_mechs (Gsasl *ctx, mu_list_t *plist)
{
char *listmech;
mu_list_t supp = NULL;
int rc;
int mechc;
char **mechv;
rc = gsasl_server_mechlist (ctx, &listmech);
if (rc != GSASL_OK)
{
mu_diag_output (MU_DIAG_ERROR,
"cannot get list of available SASL mechanisms: %s",
gsasl_strerror (rc));
return 1;
}
rc = mu_argcv_get (listmech, "", NULL, &mechc, &mechv);
if (rc == 0)
{
int i;
rc = mu_list_create (&supp);
if (rc == 0)
{
mu_list_set_destroy_item (supp, mu_list_free_item);
for (i = 0; i < mechc; i++)
mu_list_append (supp, mechv[i]);
}
free (mechv);
}
free (listmech);
*plist = supp;
return rc;
}
static int
_smtp_callback (Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
{
int rc = GSASL_OK;
mu_smtp_t smtp = gsasl_callback_hook_get (ctx);
char *p;
switch (prop)
{
case GSASL_PASSWORD:
gsasl_property_set (sctx, prop, smtp->param[MU_SMTP_PARAM_PASSWORD]);
break;
case GSASL_AUTHID:
case GSASL_ANONYMOUS_TOKEN:
gsasl_property_set (sctx, prop, smtp->param[MU_SMTP_PARAM_USERNAME]);
break;
case GSASL_AUTHZID:
gsasl_property_set (sctx, prop, NULL);
break;
case GSASL_SERVICE:
gsasl_property_set (sctx, prop,
smtp->param[MU_SMTP_PARAM_SERVICE] ?
smtp->param[MU_SMTP_PARAM_SERVICE] : "smtp");
break;
case GSASL_REALM:
p = smtp->param[MU_SMTP_PARAM_REALM] ?
smtp->param[MU_SMTP_PARAM_REALM] :
smtp->param[MU_SMTP_PARAM_DOMAIN];
if (!p)
rc = GSASL_NO_HOSTNAME;
else
gsasl_property_set (sctx, prop, p);
break;
case GSASL_HOSTNAME:
if (smtp->param[MU_SMTP_PARAM_HOST])
p = smtp->param[MU_SMTP_PARAM_HOST];
else if (mu_get_host_name (&p))
{
rc = GSASL_NO_HOSTNAME;
break;
}
else
gsasl_property_set (sctx, prop, p);
break;
default:
rc = GSASL_NO_CALLBACK;
mu_diag_output (MU_DIAG_NOTICE,
"unsupported callback property %d", prop);
break;
}
return rc;
}
static int
restore_and_return (mu_smtp_t smtp, mu_stream_t *str, int code)
{
int rc = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SWAP_STREAM, str);
if (rc)
{
mu_error ("%s failed when it should not: %s",
"MU_IOCTL_SWAP_STREAM",
mu_stream_strerror (smtp->carrier, rc));
abort ();
}
return code;
}
int
insert_gsasl_stream (mu_smtp_t smtp, Gsasl_session *sess_ctx)
{
mu_stream_t stream[2], newstream[2];
int rc;
stream[0] = stream[1] = NULL;
rc = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SWAP_STREAM, stream);
if (rc)
{
mu_error ("%s failed: %s", "MU_IOCTL_SWAP_STREAM",
mu_stream_strerror (smtp->carrier, rc));
return MU_ERR_FAILURE;
}
rc = gsasl_encoder_stream (&newstream[0], stream[0], sess_ctx,
MU_STREAM_READ);
if (rc)
{
mu_error ("%s failed: %s", "gsasl_encoder_stream",
mu_strerror (rc));
return restore_and_return (smtp, stream, MU_ERR_FAILURE);
}
rc = gsasl_decoder_stream (&newstream[1], stream[1], sess_ctx,
MU_STREAM_WRITE);
if (rc)
{
mu_error ("%s failed: %s", "gsasl_decoder_stream",
mu_strerror (rc));
mu_stream_destroy (&newstream[0]);
return restore_and_return (smtp, stream, MU_ERR_FAILURE);
}
mu_stream_flush (stream[1]);
rc = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SWAP_STREAM, newstream);
if (rc)
{
mu_error ("%s failed when it should not: %s",
"MU_IOCTL_SWAP_STREAM",
mu_stream_strerror (smtp->carrier, rc));
abort ();
}
return 0;
}
static int
do_gsasl_auth (mu_smtp_t smtp, Gsasl *ctx, const char *mech)
{
Gsasl_session *sess;
int rc, status;
char *output = NULL;
rc = gsasl_client_start (ctx, mech, &sess);
if (rc != GSASL_OK)
{
mu_diag_output (MU_DIAG_ERROR, "SASL gsasl_client_start: %s",
gsasl_strerror (rc));
return MU_ERR_FAILURE;
}
status = mu_smtp_write (smtp, "AUTH %s\r\n", mech);
MU_SMTP_CHECK_ERROR (smtp, rc);
status = mu_smtp_response (smtp);
MU_SMTP_CHECK_ERROR (smtp, status);
if (smtp->replcode[0] != '3')
{
mu_diag_output (MU_DIAG_ERROR,
"GSASL handshake aborted: "
"unexpected reply: %s %s",
smtp->replcode, smtp->replptr);
return MU_ERR_REPLY;
}
do
{
rc = gsasl_step64 (sess, smtp->replptr, &output);
if (rc != GSASL_NEEDS_MORE && rc != GSASL_OK)
break;
status = mu_smtp_write (smtp, "%s\r\n", output);
MU_SMTP_CHECK_ERROR (smtp, status);
free (output);
output = NULL;
status = mu_smtp_response (smtp);
MU_SMTP_CHECK_ERROR (smtp, status);
if (smtp->replcode[0] == '2')
{
rc = GSASL_OK;
break;
}
else if (smtp->replcode[0] != '3')
break;
} while (rc == GSASL_NEEDS_MORE);
if (output)
free (output);
if (rc != GSASL_OK)
{
mu_diag_output (MU_DIAG_ERROR, "GSASL error: %s", gsasl_strerror (rc));
return 1;
}
if (smtp->replcode[0] != '2')
{
mu_diag_output (MU_DIAG_ERROR,
"GSASL handshake failed: %s %s",
smtp->replcode, smtp->replptr);
return MU_ERR_REPLY;
}
/* Authentication successful */
MU_SMTP_FSET (smtp, _MU_SMTP_AUTH);
return insert_gsasl_stream (smtp, sess);
}
int
_mu_smtp_gsasl_auth (mu_smtp_t smtp)
{
int rc;
Gsasl *ctx;
mu_list_t mech_list;
const char *mech;
rc = gsasl_init (&ctx);
if (rc != GSASL_OK)
{
mu_diag_output (MU_DIAG_ERROR,
"cannot initialize GSASL: %s",
gsasl_strerror (rc));
return MU_ERR_FAILURE;
}
rc = get_implemented_mechs (ctx, &mech_list);
if (rc)
return rc;
rc = _mu_smtp_mech_impl (smtp, mech_list);
if (rc)
{
mu_list_destroy (&mech_list);
return rc;
}
rc = mu_smtp_mech_select (smtp, &mech);
if (rc)
{
mu_diag_output (MU_DIAG_DEBUG,
"no suitable authentication mechanism found");
return rc;
}
mu_diag_output (MU_DIAG_DEBUG, "selected authentication mechanism %s",
mech);
gsasl_callback_hook_set (ctx, smtp);
gsasl_callback_set (ctx, _smtp_callback);
rc = do_gsasl_auth (smtp, ctx, mech);
if (rc == 0)
{
/* Invalidate the capability list */
mu_list_destroy (&smtp->capa);
}
return rc;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 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, 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
#include <mailutils/list.h>
#include <mailutils/iterator.h>
#include <mailutils/mutil.h>
#include <mailutils/smtp.h>
#include <mailutils/sys/smtp.h>
static int
_mech_comp (const void *item, const void *data)
{
return mu_c_strcasecmp ((const char*)item, (const char*)data);
}
int
mu_smtp_add_auth_mech (mu_smtp_t smtp, const char *mech)
{
char *p;
if (!smtp)
return EINVAL;
if (!smtp->authmech)
{
int rc = mu_list_create (&smtp->authmech);
if (rc)
return rc;
mu_list_set_destroy_item (smtp->authmech, mu_list_free_item);
mu_list_set_comparator (smtp->authmech, _mech_comp);
}
p = strdup (mech);
if (!p)
return ENOMEM;
mu_strupper (p);
return mu_list_append (smtp->authmech, p);
}
int
mu_smtp_clear_auth_mech (mu_smtp_t smtp)
{
if (!smtp)
return EINVAL;
mu_list_clear (smtp->authmech);
return 0;
}
static int
_mech_append (void *item, void *data)
{
mu_smtp_t smtp = data;
const char *mech = item;
return mu_smtp_add_auth_mech (smtp, mech);
}
int
mu_smtp_add_auth_mech_list (mu_smtp_t smtp, mu_list_t list)
{
if (!smtp)
return EINVAL;
return mu_list_do (list, _mech_append, smtp);
}
/* Set a list of implemented authentication mechanisms */
int
_mu_smtp_mech_impl (mu_smtp_t smtp, mu_list_t list)
{
mu_list_destroy (&smtp->authimpl);
smtp->authimpl = list;
mu_list_set_comparator (smtp->authimpl, _mech_comp);
return 0;
}
static int
_mech_copy (void *item, void *data)
{
const char *mech = item;
mu_list_t list = data;
return mu_list_append (list, (void *)mech);
}
/* Select authentication mechanism to use */
int
mu_smtp_mech_select (mu_smtp_t smtp, const char **pmech)
{
int rc;
const char *authstr;
mu_list_t alist;
mu_iterator_t itr;
if (!smtp)
return EINVAL;
/* Obtain the list of mechanisms supported by the server */
rc = mu_smtp_capa_test (smtp, "AUTH", &authstr);
if (rc)
return rc;
/* Create an intersection of implemented and allowed mechanisms */
if (!smtp->authimpl)
return MU_ERR_NOENT; /* obvious case */
if (!smtp->authmech)
{
rc = mu_list_create (&alist);
if (rc == 0)
rc = mu_list_do (smtp->authimpl, _mech_copy, alist);
}
else
{
rc = mu_list_intersect_dup (&alist, smtp->authmech, smtp->authimpl,
NULL, NULL);
}
if (rc)
return rc;
/* Select first element from the intersection that occurs also in the
list of methods supported by the server */
rc = mu_list_get_iterator (alist, &itr);
if (rc == 0)
{
const char *p;
int res = 1;
rc = MU_ERR_NOENT;
authstr += 5; /* "AUTH */
for (mu_iterator_first (itr); rc && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
const char *mech;
mu_iterator_current (itr, (void**) &mech);
for (p = authstr; *p; )
{
char *end;
p = mu_str_stripws ((char *)p);
end = mu_str_skip_class_comp (p, MU_CTYPE_SPACE);
res = mu_c_strncasecmp (mech, p, end - p);
if (res == 0)
{
*pmech = mech;
rc = 0;
break;
}
p = end;
}
}
}
/* cleanup and return */
mu_list_destroy (&alist);
return rc;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010 Free Software Foundation, Inc.
......@@ -28,28 +27,32 @@
#include <mailutils/smtp.h>
#include <mailutils/sys/smtp.h>
int
mu_smtp_set_domain (mu_smtp_t smtp, const char *newdom)
int
mu_smtp_set_param (mu_smtp_t smtp, int pcode, const char *newparam)
{
char *dom;
char *param;
if (!smtp)
return EINVAL;
dom = strdup (newdom);
if (!dom)
if (pcode < 0 || pcode >= MU_SMTP_MAX_PARAM)
return EINVAL;
param = strdup (newparam);
if (!param)
return ENOMEM;
free (smtp->domain);
smtp->domain = dom;
free (smtp->param[pcode]);
smtp->param[pcode] = param;
return 0;
}
int
mu_smtp_get_domain (mu_smtp_t smtp, const char **pdom)
mu_smtp_get_param (mu_smtp_t smtp, int pcode, const char **pparam)
{
if (!smtp)
return EINVAL;
*pdom = smtp->domain;
if (pcode < 0 || pcode >= MU_SMTP_MAX_PARAM)
return EINVAL;
*pparam = smtp->param[pcode];
return 0;
}
......
......@@ -92,7 +92,7 @@ mu_smtp_starttls (mu_smtp_t smtp)
mu_list_destroy (&smtp->capa);
return 0;
#else
return ENOTSUP;
return ENOSYS;
#endif
}
......
......@@ -6,3 +6,4 @@ testsuite.dir
testsuite.log
mbdel
mimetest
smtpsend
......
......@@ -25,7 +25,9 @@
static char usage_text[] =
"usage: %s hostname [port=N] [trace=N] [tls=N] [from=STRING] [rcpt=STRING]\n"
" [domain=STRING] input=FILE raw=N\n";
" [domain=STRING] [user=STRING] [pass=STRING]\n"
" [service=STRING] [realm=STRING] [host=STRING]\n"
" [auth=method[,...]] [input=FILE] [raw=N]\n";
static void
usage ()
......@@ -49,10 +51,8 @@ main (int argc, char **argv)
{
int i;
char *host;
char *domain = NULL;
char *infile = NULL;
int port = 25;
int trace = 0;
int tls = 0;
int raw = 1;
int flags = 0;
......@@ -61,6 +61,7 @@ main (int argc, char **argv)
mu_stream_t instr;
char *from = NULL;
mu_list_t rcpt_list = NULL;
mu_list_t meth_list = NULL;
mu_set_program_name (argv[0]);
#ifdef WITH_TLS
......@@ -70,6 +71,8 @@ main (int argc, char **argv)
if (argc < 2)
usage ();
MU_ASSERT (mu_smtp_create (&smtp));
for (i = 1; i < argc; i++)
{
if (strncmp (argv[i], "port=", 5) == 0)
......@@ -82,11 +85,28 @@ main (int argc, char **argv)
}
}
else if (strncmp (argv[i], "trace=", 6) == 0)
trace = atoi (argv[i] + 6);
mu_smtp_trace (smtp, atoi (argv[i] + 6) ?
MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR);
else if (strncmp (argv[i], "tls=", 4) == 0)
tls = atoi (argv[i] + 4);
else if (strncmp (argv[i], "domain=", 7) == 0)
domain = argv[i] + 7;
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN,
argv[i] + 7));
else if (strncmp (argv[i], "user=", 5) == 0)
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_USERNAME,
argv[i] + 5));
else if (strncmp (argv[i], "pass=", 5) == 0)
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_PASSWORD,
argv[i] + 5));
else if (strncmp (argv[i], "service=", 8) == 0)
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_SERVICE,
argv[i] + 8));
else if (strncmp (argv[i], "realm=", 6) == 0)
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_REALM,
argv[i] + 6));
else if (strncmp (argv[i], "host=", 5) == 0)
MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_HOST,
argv[i] + 5));
else if (strncmp (argv[i], "infile=", 7) == 0)
infile = argv[i] + 7;
else if (strncmp (argv[i], "raw=", 4) == 0)
......@@ -99,6 +119,22 @@ main (int argc, char **argv)
}
else if (strncmp (argv[i], "from=", 5) == 0)
from = argv[i] + 5;
else if (strncmp (argv[i], "auth=", 5) == 0)
{
int mc, j;
char **mv;
if (!meth_list)
MU_ASSERT (mu_list_create (&meth_list));
MU_ASSERT (mu_argcv_get_np (argv[i] + 5, strlen (argv[i] + 5),
",", NULL,
0,
&mc, &mv, NULL));
for (j = 0; j < mc; j++)
MU_ASSERT (mu_list_append (meth_list, mv[j]));
free (mv);
}
else
host = argv[i];
}
......@@ -116,18 +152,12 @@ main (int argc, char **argv)
else
MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags));
MU_ASSERT (mu_smtp_create (&smtp));
host = argv[1];
MU_ASSERT (mu_tcp_stream_create (&stream, host, port, MU_STREAM_RDWR));
MU_ASSERT (mu_stream_open (stream));
mu_smtp_set_carrier (smtp, stream);
//mu_stream_unref (stream);
if (trace)
mu_smtp_trace (smtp, MU_SMTP_TRACE_SET);
if (domain)
mu_smtp_set_domain (smtp, domain);
if (!from)
{
from = getenv ("USER");
......@@ -153,6 +183,26 @@ main (int argc, char **argv)
MU_ASSERT (mu_smtp_ehlo (smtp));
}
if (meth_list)
{
int status;
MU_ASSERT (mu_smtp_add_auth_mech_list (smtp, meth_list));
status = mu_smtp_auth (smtp);
switch (status)
{
case 0:
case ENOSYS:
case MU_ERR_NOENT:
/* Ok, skip it */
break;
default:
mu_error ("authentication failed: %s", mu_strerror (status));
exit (1);
}
}
if (raw)
{
/* Raw sending mode: send from the stream directly */
......