commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-89-ga0b6525


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-89-ga0b6525
Date: Sat, 18 Sep 2010 17:03:41 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=a0b652546f1cccc6c00c471b701f0449819cb258

The branch, master has been updated
       via  a0b652546f1cccc6c00c471b701f0449819cb258 (commit)
      from  790527fab6a62624f6c7797bd54dca57c03ef020 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a0b652546f1cccc6c00c471b701f0449819cb258
Author: Sergey Poznyakoff <address@hidden>
Date:   Sat Sep 18 19:54:24 2010 +0300

    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.

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                    |    1 +
 include/mailutils/smtp.h                        |   23 ++-
 include/mailutils/sys/smtp.h                    |   12 +-
 libmailutils/xscript-stream.c                   |   10 +-
 libmu_auth/gsasl.c                              |    2 +-
 libproto/mailer/Makefile.am                     |   12 +-
 libproto/mailer/{smtp_capa.c => smtp_auth.c}    |   26 +-
 libproto/mailer/smtp_create.c                   |    7 +
 libproto/mailer/smtp_ehlo.c                     |   10 +-
 libproto/mailer/smtp_gsasl.c                    |  319 +++++++++++++++++++++++
 libproto/mailer/smtp_mech.c                     |  177 +++++++++++++
 libproto/mailer/{smtp_domain.c => smtp_param.c} |   25 +-
 libproto/mailer/smtp_starttls.c                 |    2 +-
 testsuite/.gitignore                            |    1 +
 testsuite/smtpsend.c                            |   72 +++++-
 15 files changed, 650 insertions(+), 49 deletions(-)
 copy libproto/mailer/{smtp_capa.c => smtp_auth.c} (73%)
 create mode 100644 libproto/mailer/smtp_gsasl.c
 create mode 100644 libproto/mailer/smtp_mech.c
 rename libproto/mailer/{smtp_domain.c => smtp_param.c} (73%)

diff --git a/configure.ac b/configure.ac
index c22ab2a..bd8ea66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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")
 
diff --git a/include/mailutils/smtp.h b/include/mailutils/smtp.h
index c34af0e..48b2f85 100644
--- a/include/mailutils/smtp.h
+++ b/include/mailutils/smtp.h
@@ -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
diff --git a/include/mailutils/sys/smtp.h b/include/mailutils/sys/smtp.h
index c741076..e04ae4d 100644
--- a/include/mailutils/sys/smtp.h
+++ b/include/mailutils/sys/smtp.h
@@ -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
diff --git a/libmailutils/xscript-stream.c b/libmailutils/xscript-stream.c
index 02fafa1..b065e81 100644
--- a/libmailutils/xscript-stream.c
+++ b/libmailutils/xscript-stream.c
@@ -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])
diff --git a/libmu_auth/gsasl.c b/libmu_auth/gsasl.c
index d03f3e2..53c6952 100644
--- a/libmu_auth/gsasl.c
+++ b/libmu_auth/gsasl.c
@@ -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);
diff --git a/libproto/mailer/Makefile.am b/libproto/mailer/Makefile.am
index 7d42111..9654f90 100644
--- a/libproto/mailer/Makefile.am
+++ b/libproto/mailer/Makefile.am
@@ -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\
diff --git a/libproto/mailer/smtp_capa.c b/libproto/mailer/smtp_auth.c
similarity index 73%
copy from libproto/mailer/smtp_capa.c
copy to libproto/mailer/smtp_auth.c
index 772aa9a..b0fccec 100644
--- a/libproto/mailer/smtp_capa.c
+++ b/libproto/mailer/smtp_auth.c
@@ -19,26 +19,26 @@
 #endif
 
 #include <errno.h>
-#include <stdlib.h>
 #include <mailutils/errno.h>
-#include <mailutils/list.h>
 #include <mailutils/smtp.h>
 #include <mailutils/sys/smtp.h>
 
 int
-mu_smtp_capa_test (mu_smtp_t smtp, const char *name, const char **pret)
+mu_smtp_auth (mu_smtp_t smtp)
 {
-  if (!smtp || !name)
+  if (!smtp)
     return EINVAL;
   if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
     return MU_ERR_FAILURE;
-  if (!smtp->capa)
-    {
-      int rc = mu_smtp_ehlo (smtp);
-      if (rc)
-       return rc;
-    }
-  if (!MU_SMTP_FISSET (smtp, _MU_SMTP_ESMTP))
-    return MU_ERR_FAILURE;
-  return mu_list_locate (smtp->capa, (void*) name, (void**)pret);
+  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
 }
diff --git a/libproto/mailer/smtp_create.c b/libproto/mailer/smtp_create.c
index 0fc3a0b..3a6b20a 100644
--- a/libproto/mailer/smtp_create.c
+++ b/libproto/mailer/smtp_create.c
@@ -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;
 }
diff --git a/libproto/mailer/smtp_ehlo.c b/libproto/mailer/smtp_ehlo.c
index ad255c7..3a693c7 100644
--- a/libproto/mailer/smtp_ehlo.c
+++ b/libproto/mailer/smtp_ehlo.c
@@ -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);
diff --git a/libproto/mailer/smtp_gsasl.c b/libproto/mailer/smtp_gsasl.c
new file mode 100644
index 0000000..4566f91
--- /dev/null
+++ b/libproto/mailer/smtp_gsasl.c
@@ -0,0 +1,319 @@
+/* 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;
+}
diff --git a/libproto/mailer/smtp_mech.c b/libproto/mailer/smtp_mech.c
new file mode 100644
index 0000000..c8707b8
--- /dev/null
+++ b/libproto/mailer/smtp_mech.c
@@ -0,0 +1,177 @@
+/* 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;
+}
diff --git a/libproto/mailer/smtp_domain.c b/libproto/mailer/smtp_param.c
similarity index 73%
rename from libproto/mailer/smtp_domain.c
rename to libproto/mailer/smtp_param.c
index a3abbb4..aee2209 100644
--- a/libproto/mailer/smtp_domain.c
+++ b/libproto/mailer/smtp_param.c
@@ -1,4 +1,3 @@
-
 /* 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;
 }
 
diff --git a/libproto/mailer/smtp_starttls.c b/libproto/mailer/smtp_starttls.c
index 8eca028..10f71ca 100644
--- a/libproto/mailer/smtp_starttls.c
+++ b/libproto/mailer/smtp_starttls.c
@@ -92,7 +92,7 @@ mu_smtp_starttls (mu_smtp_t smtp)
   mu_list_destroy (&smtp->capa);
   return 0;
 #else
-  return ENOTSUP;
+  return ENOSYS;
 #endif
 }
 
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 152a8be..b312f4d 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -6,3 +6,4 @@ testsuite.dir
 testsuite.log
 mbdel
 mimetest
+smtpsend
diff --git a/testsuite/smtpsend.c b/testsuite/smtpsend.c
index cfa4958..74039dc 100644
--- a/testsuite/smtpsend.c
+++ b/testsuite/smtpsend.c
@@ -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 */


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]