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, [ ...@@ -287,6 +287,7 @@ MU_CHECK_GSASL(0.2.3, [
287 MU_AUTHLIBS="$MU_AUTHLIBS $GSASL_LIBS" 287 MU_AUTHLIBS="$MU_AUTHLIBS $GSASL_LIBS"
288 IMAP_AUTHOBJS="$IMAP_AUTHOBJS auth_gsasl.o" 288 IMAP_AUTHOBJS="$IMAP_AUTHOBJS auth_gsasl.o"
289 status_gsasl=yes]) 289 status_gsasl=yes])
290 AM_CONDITIONAL([MU_COND_GSASL],[test "$status_gsasl" = "yes"])
290 291
291 AC_SUBST(SITE_CRAM_MD5_PWD,"\$(sysconfdir)/cram-md5.pwd") 292 AC_SUBST(SITE_CRAM_MD5_PWD,"\$(sysconfdir)/cram-md5.pwd")
292 293
......
...@@ -23,6 +23,18 @@ ...@@ -23,6 +23,18 @@
23 23
24 typedef struct _mu_smtp *mu_smtp_t; 24 typedef struct _mu_smtp *mu_smtp_t;
25 25
26 enum
27 {
28 MU_SMTP_PARAM_DOMAIN,
29 MU_SMTP_PARAM_USERNAME,
30 MU_SMTP_PARAM_PASSWORD,
31 MU_SMTP_PARAM_SERVICE,
32 MU_SMTP_PARAM_REALM,
33 MU_SMTP_PARAM_HOST
34 };
35
36 #define MU_SMTP_MAX_PARAM (MU_SMTP_PARAM_HOST+1)
37
26 int mu_smtp_create (mu_smtp_t *); 38 int mu_smtp_create (mu_smtp_t *);
27 void mu_smtp_destroy (mu_smtp_t *); 39 void mu_smtp_destroy (mu_smtp_t *);
28 int mu_smtp_set_carrier (mu_smtp_t smtp, mu_stream_t str); 40 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); ...@@ -40,8 +52,8 @@ int mu_smtp_trace_mask (mu_smtp_t smtp, int op, int lev);
40 52
41 int mu_smtp_disconnect (mu_smtp_t smtp); 53 int mu_smtp_disconnect (mu_smtp_t smtp);
42 int mu_smtp_ehlo (mu_smtp_t smtp); 54 int mu_smtp_ehlo (mu_smtp_t smtp);
43 int mu_smtp_set_domain (mu_smtp_t smtp, const char *newdom); 55 int mu_smtp_set_param (mu_smtp_t smtp, int code, const char *val);
44 int mu_smtp_get_domain (mu_smtp_t smtp, const char **pdom); 56 int mu_smtp_get_param (mu_smtp_t smtp, int code, const char **param);
45 int mu_smtp_capa_test (mu_smtp_t smtp, const char *capa, const char **pret); 57 int mu_smtp_capa_test (mu_smtp_t smtp, const char *capa, const char **pret);
46 int mu_smtp_starttls (mu_smtp_t smtp); 58 int mu_smtp_starttls (mu_smtp_t smtp);
47 59
...@@ -51,4 +63,11 @@ int mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t str); ...@@ -51,4 +63,11 @@ int mu_smtp_send_stream (mu_smtp_t smtp, mu_stream_t str);
51 int mu_smtp_rset (mu_smtp_t smtp); 63 int mu_smtp_rset (mu_smtp_t smtp);
52 int mu_smtp_quit (mu_smtp_t smtp); 64 int mu_smtp_quit (mu_smtp_t smtp);
53 65
66 int mu_smtp_auth (mu_smtp_t smtp);
67
68 int mu_smtp_add_auth_mech (mu_smtp_t smtp, const char *mech);
69 int mu_smtp_clear_auth_mech (mu_smtp_t smtp);
70 int mu_smtp_add_auth_mech_list (mu_smtp_t smtp, mu_list_t list);
71 int mu_smtp_mech_select (mu_smtp_t smtp, const char **pmech);
72
54 #endif 73 #endif
......
...@@ -46,11 +46,17 @@ enum mu_smtp_state ...@@ -46,11 +46,17 @@ enum mu_smtp_state
46 struct _mu_smtp 46 struct _mu_smtp
47 { 47 {
48 int flags; 48 int flags;
49 char *domain; 49
50 mu_stream_t carrier; 50 mu_stream_t carrier;
51 enum mu_smtp_state state; 51 enum mu_smtp_state state;
52 mu_list_t capa; 52 mu_list_t capa;
53 53 mu_list_t authimpl; /* List of implemented authentication mechs */
54
55 /* User-supplied data */
56 char *param[MU_SMTP_MAX_PARAM];
57 mu_list_t authmech; /* List of allowed authentication mechs */
58
59 /* I/O buffers */
54 char replcode[4]; 60 char replcode[4];
55 char *replptr; 61 char *replptr;
56 62
...@@ -81,5 +87,7 @@ struct _mu_smtp ...@@ -81,5 +87,7 @@ struct _mu_smtp
81 int _mu_smtp_trace_enable (mu_smtp_t smtp); 87 int _mu_smtp_trace_enable (mu_smtp_t smtp);
82 int _mu_smtp_trace_disable (mu_smtp_t smtp); 88 int _mu_smtp_trace_disable (mu_smtp_t smtp);
83 int _mu_smtp_xscript_level (mu_smtp_t smtp, int xlev); 89 int _mu_smtp_xscript_level (mu_smtp_t smtp, int xlev);
90 int _mu_smtp_gsasl_auth (mu_smtp_t smtp);
91 int _mu_smtp_mech_impl (mu_smtp_t smtp, mu_list_t list);
84 92
85 #endif 93 #endif
......
...@@ -292,11 +292,17 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) ...@@ -292,11 +292,17 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
292 mu_stream_t tmp; 292 mu_stream_t tmp;
293 293
294 if (pstr[0] != pstr[1]) 294 if (pstr[0] != pstr[1])
295 return EINVAL; /* FIXME */ 295 {
296 tmp = pstr[0]; 296 status = mu_iostream_create (&tmp, pstr[0], pstr[1]);
297 if (status)
298 return status;
299 }
300 else
301 tmp = pstr[0];
297 pstr[0] = sp->transport; 302 pstr[0] = sp->transport;
298 pstr[1] = sp->transport; 303 pstr[1] = sp->transport;
299 sp->transport = tmp; 304 sp->transport = tmp;
305 /* FIXME */
300 if (!(str->flags & MU_STREAM_AUTOCLOSE)) 306 if (!(str->flags & MU_STREAM_AUTOCLOSE))
301 { 307 {
302 if (pstr[0]) 308 if (pstr[0])
......
...@@ -206,7 +206,7 @@ mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport, ...@@ -206,7 +206,7 @@ mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
206 rc = gsasl_encoder_stream (&in, transport, ctx, MU_STREAM_READ); 206 rc = gsasl_encoder_stream (&in, transport, ctx, MU_STREAM_READ);
207 if (rc) 207 if (rc)
208 return rc; 208 return rc;
209 rc = gsasl_encoder_stream (&out, transport, ctx, MU_STREAM_WRITE); 209 rc = gsasl_decoder_stream (&out, transport, ctx, MU_STREAM_WRITE);
210 if (rc) 210 if (rc)
211 { 211 {
212 mu_stream_destroy (&in); 212 mu_stream_destroy (&in);
......
...@@ -23,22 +23,30 @@ lib_LTLIBRARIES = libmu_mailer.la ...@@ -23,22 +23,30 @@ lib_LTLIBRARIES = libmu_mailer.la
23 libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ 23 libmu_mailer_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
24 libmu_mailer_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ 24 libmu_mailer_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
25 25
26 if MU_COND_GSASL
27 SMTP_GSASL=smtp_gsasl.c
28 endif
29 EXTRA_DIST=smtp_gsasl.c
30
26 libmu_mailer_la_SOURCES = \ 31 libmu_mailer_la_SOURCES = \
27 mbox.c\ 32 mbox.c\
28 prog.c\ 33 prog.c\
29 sendmail.c\ 34 sendmail.c\
30 smtp.c\ 35 smtp.c\
36 smtp_auth.c\
31 smtp_capa.c\ 37 smtp_capa.c\
32 smtp_carrier.c\ 38 smtp_carrier.c\
33 smtp_create.c\ 39 smtp_create.c\
34 smtp_data.c\ 40 smtp_data.c\
35 smtp_disconnect.c\ 41 smtp_disconnect.c\
36 smtp_domain.c\
37 smtp_ehlo.c\ 42 smtp_ehlo.c\
43 $(SMTP_GSASL)\
38 smtp_io.c\ 44 smtp_io.c\
39 smtp_mail.c\ 45 smtp_mail.c\
40 smtp_rcpt.c\ 46 smtp_mech.c\
41 smtp_open.c\ 47 smtp_open.c\
48 smtp_param.c\
49 smtp_rcpt.c\
42 smtp_rset.c\ 50 smtp_rset.c\
43 smtp_starttls.c\ 51 smtp_starttls.c\
44 smtp_trace.c\ 52 smtp_trace.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include <errno.h>
22 #include <mailutils/errno.h>
23 #include <mailutils/smtp.h>
24 #include <mailutils/sys/smtp.h>
25
26 int
27 mu_smtp_auth (mu_smtp_t smtp)
28 {
29 if (!smtp)
30 return EINVAL;
31 if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
32 return MU_ERR_FAILURE;
33 if (MU_SMTP_FISSET (smtp, _MU_SMTP_AUTH))
34 return MU_ERR_SEQ;
35 if (smtp->state != MU_SMTP_MAIL)
36 return MU_ERR_SEQ;
37
38 #if defined(WITH_GSASL)
39 return _mu_smtp_gsasl_auth (smtp);
40 #else
41 /* FIXME: Provide support for some basic authentication methods */
42 return ENOSYS;
43 #endif
44 }
...@@ -45,6 +45,7 @@ mu_smtp_create (mu_smtp_t *psmtp) ...@@ -45,6 +45,7 @@ mu_smtp_create (mu_smtp_t *psmtp)
45 void 45 void
46 mu_smtp_destroy (mu_smtp_t *psmtp) 46 mu_smtp_destroy (mu_smtp_t *psmtp)
47 { 47 {
48 int i;
48 struct _mu_smtp *smtp; 49 struct _mu_smtp *smtp;
49 50
50 if (!psmtp || !*psmtp) 51 if (!psmtp || !*psmtp)
...@@ -52,9 +53,15 @@ mu_smtp_destroy (mu_smtp_t *psmtp) ...@@ -52,9 +53,15 @@ mu_smtp_destroy (mu_smtp_t *psmtp)
52 smtp = *psmtp; 53 smtp = *psmtp;
53 mu_stream_destroy (&smtp->carrier); 54 mu_stream_destroy (&smtp->carrier);
54 mu_list_destroy (&smtp->capa); 55 mu_list_destroy (&smtp->capa);
56 mu_list_destroy (&smtp->authimpl);
55 free (smtp->rdbuf); 57 free (smtp->rdbuf);
56 free (smtp->flbuf); 58 free (smtp->flbuf);
57 mu_list_destroy (&smtp->mlrepl); 59 mu_list_destroy (&smtp->mlrepl);
60
61 mu_list_destroy (&smtp->authmech);
62 for (i = 0; i < MU_SMTP_MAX_PARAM; i++)
63 free (smtp->param[i]);
64
58 free (smtp); 65 free (smtp);
59 *psmtp = NULL; 66 *psmtp = NULL;
60 } 67 }
......
...@@ -53,7 +53,7 @@ mu_smtp_ehlo (mu_smtp_t smtp) ...@@ -53,7 +53,7 @@ mu_smtp_ehlo (mu_smtp_t smtp)
53 if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR)) 53 if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
54 return MU_ERR_FAILURE; 54 return MU_ERR_FAILURE;
55 55
56 if (!smtp->domain) 56 if (!smtp->param[MU_SMTP_PARAM_DOMAIN])
57 { 57 {
58 char *host; 58 char *host;
59 char *p; 59 char *p;
...@@ -65,11 +65,12 @@ mu_smtp_ehlo (mu_smtp_t smtp) ...@@ -65,11 +65,12 @@ mu_smtp_ehlo (mu_smtp_t smtp)
65 p++; 65 p++;
66 else 66 else
67 p = host; 67 p = host;
68 status = mu_smtp_set_domain (smtp, p); 68 status = mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN, p);
69 MU_SMTP_CHECK_ERROR (smtp, status); 69 MU_SMTP_CHECK_ERROR (smtp, status);
70 } 70 }
71 71
72 status = mu_smtp_write (smtp, "EHLO %s\r\n", smtp->domain); 72 status = mu_smtp_write (smtp, "EHLO %s\r\n",
73 smtp->param[MU_SMTP_PARAM_DOMAIN]);
73 MU_SMTP_CHECK_ERROR (smtp, status); 74 MU_SMTP_CHECK_ERROR (smtp, status);
74 status = mu_smtp_response (smtp); 75 status = mu_smtp_response (smtp);
75 MU_SMTP_CHECK_ERROR (smtp, status); 76 MU_SMTP_CHECK_ERROR (smtp, status);
...@@ -84,7 +85,8 @@ mu_smtp_ehlo (mu_smtp_t smtp) ...@@ -84,7 +85,8 @@ mu_smtp_ehlo (mu_smtp_t smtp)
84 return MU_ERR_REPLY; 85 return MU_ERR_REPLY;
85 else 86 else
86 { 87 {
87 status = mu_smtp_write (smtp, "HELO %s\r\n", smtp->domain); 88 status = mu_smtp_write (smtp, "HELO %s\r\n",
89 smtp->param[MU_SMTP_PARAM_DOMAIN]);
88 MU_SMTP_CHECK_ERROR (smtp, status); 90 MU_SMTP_CHECK_ERROR (smtp, status);
89 status = mu_smtp_response (smtp); 91 status = mu_smtp_response (smtp);
90 MU_SMTP_CHECK_ERROR (smtp, status); 92 MU_SMTP_CHECK_ERROR (smtp, status);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <mailutils/argcv.h>
25 #include <mailutils/diag.h>
26 #include <mailutils/errno.h>
27 #include <mailutils/cctype.h>
28 #include <mailutils/list.h>
29 #include <mailutils/mutil.h>
30 #include <mailutils/smtp.h>
31 #include <mailutils/stream.h>
32 #include <mailutils/sys/smtp.h>
33 #include <mailutils/gsasl.h>
34 #include <gsasl.h>
35
36 static int
37 get_implemented_mechs (Gsasl *ctx, mu_list_t *plist)
38 {
39 char *listmech;
40 mu_list_t supp = NULL;
41 int rc;
42 int mechc;
43 char **mechv;
44
45 rc = gsasl_server_mechlist (ctx, &listmech);
46 if (rc != GSASL_OK)
47 {
48 mu_diag_output (MU_DIAG_ERROR,
49 "cannot get list of available SASL mechanisms: %s",
50 gsasl_strerror (rc));
51 return 1;
52 }
53
54 rc = mu_argcv_get (listmech, "", NULL, &mechc, &mechv);
55 if (rc == 0)
56 {
57 int i;
58
59 rc = mu_list_create (&supp);
60 if (rc == 0)
61 {
62 mu_list_set_destroy_item (supp, mu_list_free_item);
63 for (i = 0; i < mechc; i++)
64 mu_list_append (supp, mechv[i]);
65 }
66 free (mechv);
67 }
68 free (listmech);
69 *plist = supp;
70 return rc;
71 }
72
73 static int
74 _smtp_callback (Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
75 {
76 int rc = GSASL_OK;
77 mu_smtp_t smtp = gsasl_callback_hook_get (ctx);
78 char *p;
79
80 switch (prop)
81 {
82 case GSASL_PASSWORD:
83 gsasl_property_set (sctx, prop, smtp->param[MU_SMTP_PARAM_PASSWORD]);
84 break;
85
86 case GSASL_AUTHID:
87 case GSASL_ANONYMOUS_TOKEN:
88 gsasl_property_set (sctx, prop, smtp->param[MU_SMTP_PARAM_USERNAME]);
89 break;
90
91 case GSASL_AUTHZID:
92 gsasl_property_set (sctx, prop, NULL);
93 break;
94
95 case GSASL_SERVICE:
96 gsasl_property_set (sctx, prop,
97 smtp->param[MU_SMTP_PARAM_SERVICE] ?
98 smtp->param[MU_SMTP_PARAM_SERVICE] : "smtp");
99 break;
100
101 case GSASL_REALM:
102 p = smtp->param[MU_SMTP_PARAM_REALM] ?
103 smtp->param[MU_SMTP_PARAM_REALM] :
104 smtp->param[MU_SMTP_PARAM_DOMAIN];
105
106 if (!p)
107 rc = GSASL_NO_HOSTNAME;
108 else
109 gsasl_property_set (sctx, prop, p);
110 break;
111
112 case GSASL_HOSTNAME:
113 if (smtp->param[MU_SMTP_PARAM_HOST])
114 p = smtp->param[MU_SMTP_PARAM_HOST];
115 else if (mu_get_host_name (&p))
116 {
117 rc = GSASL_NO_HOSTNAME;
118 break;
119 }
120 else
121 gsasl_property_set (sctx, prop, p);
122 break;
123
124 default:
125 rc = GSASL_NO_CALLBACK;
126 mu_diag_output (MU_DIAG_NOTICE,
127 "unsupported callback property %d", prop);
128 break;
129 }
130
131 return rc;
132 }
133
134 static int
135 restore_and_return (mu_smtp_t smtp, mu_stream_t *str, int code)
136 {
137 int rc = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SWAP_STREAM, str);
138 if (rc)
139 {
140 mu_error ("%s failed when it should not: %s",
141 "MU_IOCTL_SWAP_STREAM",
142 mu_stream_strerror (smtp->carrier, rc));
143 abort ();
144 }
145 return code;
146 }
147
148 int
149 insert_gsasl_stream (mu_smtp_t smtp, Gsasl_session *sess_ctx)
150 {
151 mu_stream_t stream[2], newstream[2];
152 int rc;
153
154 stream[0] = stream[1] = NULL;
155 rc = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SWAP_STREAM, stream);
156 if (rc)
157 {
158 mu_error ("%s failed: %s", "MU_IOCTL_SWAP_STREAM",
159 mu_stream_strerror (smtp->carrier, rc));
160 return MU_ERR_FAILURE;
161 }
162
163 rc = gsasl_encoder_stream (&newstream[0], stream[0], sess_ctx,
164 MU_STREAM_READ);
165 if (rc)
166 {
167 mu_error ("%s failed: %s", "gsasl_encoder_stream",
168 mu_strerror (rc));
169 return restore_and_return (smtp, stream, MU_ERR_FAILURE);
170 }
171
172 rc = gsasl_decoder_stream (&newstream[1], stream[1], sess_ctx,
173 MU_STREAM_WRITE);
174 if (rc)
175 {
176 mu_error ("%s failed: %s", "gsasl_decoder_stream",
177 mu_strerror (rc));
178 mu_stream_destroy (&newstream[0]);
179 return restore_and_return (smtp, stream, MU_ERR_FAILURE);
180 }
181
182 mu_stream_flush (stream[1]);
183
184 rc = mu_stream_ioctl (smtp->carrier, MU_IOCTL_SWAP_STREAM, newstream);
185 if (rc)
186 {
187 mu_error ("%s failed when it should not: %s",
188 "MU_IOCTL_SWAP_STREAM",
189 mu_stream_strerror (smtp->carrier, rc));
190 abort ();
191 }
192
193 return 0;
194 }
195
196 static int
197 do_gsasl_auth (mu_smtp_t smtp, Gsasl *ctx, const char *mech)
198 {
199 Gsasl_session *sess;
200 int rc, status;
201 char *output = NULL;
202
203 rc = gsasl_client_start (ctx, mech, &sess);
204 if (rc != GSASL_OK)
205 {
206 mu_diag_output (MU_DIAG_ERROR, "SASL gsasl_client_start: %s",
207 gsasl_strerror (rc));
208 return MU_ERR_FAILURE;
209 }
210
211 status = mu_smtp_write (smtp, "AUTH %s\r\n", mech);
212 MU_SMTP_CHECK_ERROR (smtp, rc);
213
214 status = mu_smtp_response (smtp);
215 MU_SMTP_CHECK_ERROR (smtp, status);
216 if (smtp->replcode[0] != '3')
217 {
218 mu_diag_output (MU_DIAG_ERROR,
219 "GSASL handshake aborted: "
220 "unexpected reply: %s %s",
221 smtp->replcode, smtp->replptr);
222 return MU_ERR_REPLY;
223 }
224
225 do
226 {
227 rc = gsasl_step64 (sess, smtp->replptr, &output);
228 if (rc != GSASL_NEEDS_MORE && rc != GSASL_OK)
229 break;
230
231 status = mu_smtp_write (smtp, "%s\r\n", output);
232 MU_SMTP_CHECK_ERROR (smtp, status);
233
234 free (output);
235 output = NULL;
236
237 status = mu_smtp_response (smtp);
238 MU_SMTP_CHECK_ERROR (smtp, status);
239 if (smtp->replcode[0] == '2')
240 {
241 rc = GSASL_OK;
242 break;
243 }
244 else if (smtp->replcode[0] != '3')
245 break;
246 } while (rc == GSASL_NEEDS_MORE);
247
248 if (output)
249 free (output);
250
251 if (rc != GSASL_OK)
252 {
253 mu_diag_output (MU_DIAG_ERROR, "GSASL error: %s", gsasl_strerror (rc));
254 return 1;
255 }
256
257 if (smtp->replcode[0] != '2')
258 {
259 mu_diag_output (MU_DIAG_ERROR,
260 "GSASL handshake failed: %s %s",
261 smtp->replcode, smtp->replptr);
262 return MU_ERR_REPLY;
263 }
264
265 /* Authentication successful */
266 MU_SMTP_FSET (smtp, _MU_SMTP_AUTH);
267
268 return insert_gsasl_stream (smtp, sess);
269 }
270
271 int
272 _mu_smtp_gsasl_auth (mu_smtp_t smtp)
273 {
274 int rc;
275 Gsasl *ctx;
276 mu_list_t mech_list;
277 const char *mech;
278
279 rc = gsasl_init (&ctx);
280 if (rc != GSASL_OK)
281 {
282 mu_diag_output (MU_DIAG_ERROR,
283 "cannot initialize GSASL: %s",
284 gsasl_strerror (rc));
285 return MU_ERR_FAILURE;
286 }
287 rc = get_implemented_mechs (ctx, &mech_list);
288 if (rc)
289 return rc;
290 rc = _mu_smtp_mech_impl (smtp, mech_list);
291 if (rc)
292 {
293 mu_list_destroy (&mech_list);
294 return rc;
295 }
296
297 rc = mu_smtp_mech_select (smtp, &mech);
298 if (rc)
299 {
300 mu_diag_output (MU_DIAG_DEBUG,
301 "no suitable authentication mechanism found");
302 return rc;
303 }
304
305 mu_diag_output (MU_DIAG_DEBUG, "selected authentication mechanism %s",
306 mech);
307
308 gsasl_callback_hook_set (ctx, smtp);
309 gsasl_callback_set (ctx, _smtp_callback);
310
311 rc = do_gsasl_auth (smtp, ctx, mech);
312 if (rc == 0)
313 {
314 /* Invalidate the capability list */
315 mu_list_destroy (&smtp->capa);
316 }
317
318 return rc;
319 }
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <mailutils/errno.h>
25 #include <mailutils/cctype.h>
26 #include <mailutils/cstr.h>
27 #include <mailutils/list.h>
28 #include <mailutils/iterator.h>
29 #include <mailutils/mutil.h>
30 #include <mailutils/smtp.h>
31 #include <mailutils/sys/smtp.h>
32
33 static int
34 _mech_comp (const void *item, const void *data)
35 {
36 return mu_c_strcasecmp ((const char*)item, (const char*)data);
37 }
38
39 int
40 mu_smtp_add_auth_mech (mu_smtp_t smtp, const char *mech)
41 {
42 char *p;
43
44 if (!smtp)
45 return EINVAL;
46 if (!smtp->authmech)
47 {
48 int rc = mu_list_create (&smtp->authmech);
49 if (rc)
50 return rc;
51 mu_list_set_destroy_item (smtp->authmech, mu_list_free_item);
52 mu_list_set_comparator (smtp->authmech, _mech_comp);
53 }
54 p = strdup (mech);
55 if (!p)
56 return ENOMEM;
57 mu_strupper (p);
58 return mu_list_append (smtp->authmech, p);
59 }
60
61 int
62 mu_smtp_clear_auth_mech (mu_smtp_t smtp)
63 {
64 if (!smtp)
65 return EINVAL;
66 mu_list_clear (smtp->authmech);
67 return 0;
68 }
69
70 static int
71 _mech_append (void *item, void *data)
72 {
73 mu_smtp_t smtp = data;
74 const char *mech = item;
75 return mu_smtp_add_auth_mech (smtp, mech);
76 }
77
78 int
79 mu_smtp_add_auth_mech_list (mu_smtp_t smtp, mu_list_t list)
80 {
81 if (!smtp)
82 return EINVAL;
83 return mu_list_do (list, _mech_append, smtp);
84 }
85
86 /* Set a list of implemented authentication mechanisms */
87 int
88 _mu_smtp_mech_impl (mu_smtp_t smtp, mu_list_t list)
89 {
90 mu_list_destroy (&smtp->authimpl);
91 smtp->authimpl = list;
92 mu_list_set_comparator (smtp->authimpl, _mech_comp);
93 return 0;
94 }
95
96
97 static int
98 _mech_copy (void *item, void *data)
99 {
100 const char *mech = item;
101 mu_list_t list = data;
102 return mu_list_append (list, (void *)mech);
103 }
104
105 /* Select authentication mechanism to use */
106 int
107 mu_smtp_mech_select (mu_smtp_t smtp, const char **pmech)
108 {
109 int rc;
110 const char *authstr;
111 mu_list_t alist;
112 mu_iterator_t itr;
113
114 if (!smtp)
115 return EINVAL;
116
117 /* Obtain the list of mechanisms supported by the server */
118 rc = mu_smtp_capa_test (smtp, "AUTH", &authstr);
119 if (rc)
120 return rc;
121
122 /* Create an intersection of implemented and allowed mechanisms */
123 if (!smtp->authimpl)
124 return MU_ERR_NOENT; /* obvious case */
125
126 if (!smtp->authmech)
127 {
128 rc = mu_list_create (&alist);
129 if (rc == 0)
130 rc = mu_list_do (smtp->authimpl, _mech_copy, alist);
131 }
132 else
133 {
134 rc = mu_list_intersect_dup (&alist, smtp->authmech, smtp->authimpl,
135 NULL, NULL);
136 }
137 if (rc)
138 return rc;
139
140 /* Select first element from the intersection that occurs also in the
141 list of methods supported by the server */
142 rc = mu_list_get_iterator (alist, &itr);
143 if (rc == 0)
144 {
145 const char *p;
146 int res = 1;
147
148 rc = MU_ERR_NOENT;
149 authstr += 5; /* "AUTH */
150 for (mu_iterator_first (itr); rc && !mu_iterator_is_done (itr);
151 mu_iterator_next (itr))
152 {
153 const char *mech;
154 mu_iterator_current (itr, (void**) &mech);
155 for (p = authstr; *p; )
156 {
157 char *end;
158
159 p = mu_str_stripws ((char *)p);
160 end = mu_str_skip_class_comp (p, MU_CTYPE_SPACE);
161
162 res = mu_c_strncasecmp (mech, p, end - p);
163 if (res == 0)
164 {
165 *pmech = mech;
166 rc = 0;
167 break;
168 }
169 p = end;
170 }
171 }
172 }
173
174 /* cleanup and return */
175 mu_list_destroy (&alist);
176 return rc;
177 }
1
2 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
3 Copyright (C) 2010 Free Software Foundation, Inc. 2 Copyright (C) 2010 Free Software Foundation, Inc.
4 3
...@@ -28,28 +27,32 @@ ...@@ -28,28 +27,32 @@
28 #include <mailutils/smtp.h> 27 #include <mailutils/smtp.h>
29 #include <mailutils/sys/smtp.h> 28 #include <mailutils/sys/smtp.h>
30 29
31 int 30 int
32 mu_smtp_set_domain (mu_smtp_t smtp, const char *newdom) 31 mu_smtp_set_param (mu_smtp_t smtp, int pcode, const char *newparam)
33 { 32 {
34 char *dom; 33 char *param;
35 34
36 if (!smtp) 35 if (!smtp)
37 return EINVAL; 36 return EINVAL;
38 37 if (pcode < 0 || pcode >= MU_SMTP_MAX_PARAM)
39 dom = strdup (newdom); 38 return EINVAL;
40 if (!dom) 39
40 param = strdup (newparam);
41 if (!param)
41 return ENOMEM; 42 return ENOMEM;
42 free (smtp->domain); 43 free (smtp->param[pcode]);
43 smtp->domain = dom; 44 smtp->param[pcode] = param;
44 return 0; 45 return 0;
45 } 46 }
46 47
47 int 48 int
48 mu_smtp_get_domain (mu_smtp_t smtp, const char **pdom) 49 mu_smtp_get_param (mu_smtp_t smtp, int pcode, const char **pparam)
49 { 50 {
50 if (!smtp) 51 if (!smtp)
51 return EINVAL; 52 return EINVAL;
52 *pdom = smtp->domain; 53 if (pcode < 0 || pcode >= MU_SMTP_MAX_PARAM)
54 return EINVAL;
55 *pparam = smtp->param[pcode];
53 return 0; 56 return 0;
54 } 57 }
55 58
......
...@@ -92,7 +92,7 @@ mu_smtp_starttls (mu_smtp_t smtp) ...@@ -92,7 +92,7 @@ mu_smtp_starttls (mu_smtp_t smtp)
92 mu_list_destroy (&smtp->capa); 92 mu_list_destroy (&smtp->capa);
93 return 0; 93 return 0;
94 #else 94 #else
95 return ENOTSUP; 95 return ENOSYS;
96 #endif 96 #endif
97 } 97 }
98 98
......
...@@ -6,3 +6,4 @@ testsuite.dir ...@@ -6,3 +6,4 @@ testsuite.dir
6 testsuite.log 6 testsuite.log
7 mbdel 7 mbdel
8 mimetest 8 mimetest
9 smtpsend
......
...@@ -25,7 +25,9 @@ ...@@ -25,7 +25,9 @@
25 25
26 static char usage_text[] = 26 static char usage_text[] =
27 "usage: %s hostname [port=N] [trace=N] [tls=N] [from=STRING] [rcpt=STRING]\n" 27 "usage: %s hostname [port=N] [trace=N] [tls=N] [from=STRING] [rcpt=STRING]\n"
28 " [domain=STRING] input=FILE raw=N\n"; 28 " [domain=STRING] [user=STRING] [pass=STRING]\n"
29 " [service=STRING] [realm=STRING] [host=STRING]\n"
30 " [auth=method[,...]] [input=FILE] [raw=N]\n";
29 31
30 static void 32 static void
31 usage () 33 usage ()
...@@ -49,10 +51,8 @@ main (int argc, char **argv) ...@@ -49,10 +51,8 @@ main (int argc, char **argv)
49 { 51 {
50 int i; 52 int i;
51 char *host; 53 char *host;
52 char *domain = NULL;
53 char *infile = NULL; 54 char *infile = NULL;
54 int port = 25; 55 int port = 25;
55 int trace = 0;
56 int tls = 0; 56 int tls = 0;
57 int raw = 1; 57 int raw = 1;
58 int flags = 0; 58 int flags = 0;
...@@ -61,6 +61,7 @@ main (int argc, char **argv) ...@@ -61,6 +61,7 @@ main (int argc, char **argv)
61 mu_stream_t instr; 61 mu_stream_t instr;
62 char *from = NULL; 62 char *from = NULL;
63 mu_list_t rcpt_list = NULL; 63 mu_list_t rcpt_list = NULL;
64 mu_list_t meth_list = NULL;
64 65
65 mu_set_program_name (argv[0]); 66 mu_set_program_name (argv[0]);
66 #ifdef WITH_TLS 67 #ifdef WITH_TLS
...@@ -70,6 +71,8 @@ main (int argc, char **argv) ...@@ -70,6 +71,8 @@ main (int argc, char **argv)
70 if (argc < 2) 71 if (argc < 2)
71 usage (); 72 usage ();
72 73
74 MU_ASSERT (mu_smtp_create (&smtp));
75
73 for (i = 1; i < argc; i++) 76 for (i = 1; i < argc; i++)
74 { 77 {
75 if (strncmp (argv[i], "port=", 5) == 0) 78 if (strncmp (argv[i], "port=", 5) == 0)
...@@ -82,11 +85,28 @@ main (int argc, char **argv) ...@@ -82,11 +85,28 @@ main (int argc, char **argv)
82 } 85 }
83 } 86 }
84 else if (strncmp (argv[i], "trace=", 6) == 0) 87 else if (strncmp (argv[i], "trace=", 6) == 0)
85 trace = atoi (argv[i] + 6); 88 mu_smtp_trace (smtp, atoi (argv[i] + 6) ?
89 MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR);
86 else if (strncmp (argv[i], "tls=", 4) == 0) 90 else if (strncmp (argv[i], "tls=", 4) == 0)
87 tls = atoi (argv[i] + 4); 91 tls = atoi (argv[i] + 4);
88 else if (strncmp (argv[i], "domain=", 7) == 0) 92 else if (strncmp (argv[i], "domain=", 7) == 0)
89 domain = argv[i] + 7; 93 MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN,
94 argv[i] + 7));
95 else if (strncmp (argv[i], "user=", 5) == 0)
96 MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_USERNAME,
97 argv[i] + 5));
98 else if (strncmp (argv[i], "pass=", 5) == 0)
99 MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_PASSWORD,
100 argv[i] + 5));
101 else if (strncmp (argv[i], "service=", 8) == 0)
102 MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_SERVICE,
103 argv[i] + 8));
104 else if (strncmp (argv[i], "realm=", 6) == 0)
105 MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_REALM,
106 argv[i] + 6));
107 else if (strncmp (argv[i], "host=", 5) == 0)
108 MU_ASSERT (mu_smtp_set_param (smtp, MU_SMTP_PARAM_HOST,
109 argv[i] + 5));
90 else if (strncmp (argv[i], "infile=", 7) == 0) 110 else if (strncmp (argv[i], "infile=", 7) == 0)
91 infile = argv[i] + 7; 111 infile = argv[i] + 7;
92 else if (strncmp (argv[i], "raw=", 4) == 0) 112 else if (strncmp (argv[i], "raw=", 4) == 0)
...@@ -99,6 +119,22 @@ main (int argc, char **argv) ...@@ -99,6 +119,22 @@ main (int argc, char **argv)
99 } 119 }
100 else if (strncmp (argv[i], "from=", 5) == 0) 120 else if (strncmp (argv[i], "from=", 5) == 0)
101 from = argv[i] + 5; 121 from = argv[i] + 5;
122 else if (strncmp (argv[i], "auth=", 5) == 0)
123 {
124 int mc, j;
125 char **mv;
126
127 if (!meth_list)
128 MU_ASSERT (mu_list_create (&meth_list));
129
130 MU_ASSERT (mu_argcv_get_np (argv[i] + 5, strlen (argv[i] + 5),
131 ",", NULL,
132 0,
133 &mc, &mv, NULL));
134 for (j = 0; j < mc; j++)
135 MU_ASSERT (mu_list_append (meth_list, mv[j]));
136 free (mv);
137 }
102 else 138 else
103 host = argv[i]; 139 host = argv[i];
104 } 140 }
...@@ -116,18 +152,12 @@ main (int argc, char **argv) ...@@ -116,18 +152,12 @@ main (int argc, char **argv)
116 else 152 else
117 MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags)); 153 MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags));
118 154
119 MU_ASSERT (mu_smtp_create (&smtp));
120
121 host = argv[1]; 155 host = argv[1];
122 MU_ASSERT (mu_tcp_stream_create (&stream, host, port, MU_STREAM_RDWR)); 156 MU_ASSERT (mu_tcp_stream_create (&stream, host, port, MU_STREAM_RDWR));
123 MU_ASSERT (mu_stream_open (stream)); 157 MU_ASSERT (mu_stream_open (stream));
124 mu_smtp_set_carrier (smtp, stream); 158 mu_smtp_set_carrier (smtp, stream);
125 //mu_stream_unref (stream); 159 //mu_stream_unref (stream);
126 160
127 if (trace)
128 mu_smtp_trace (smtp, MU_SMTP_TRACE_SET);
129 if (domain)
130 mu_smtp_set_domain (smtp, domain);
131 if (!from) 161 if (!from)
132 { 162 {
133 from = getenv ("USER"); 163 from = getenv ("USER");
...@@ -153,6 +183,26 @@ main (int argc, char **argv) ...@@ -153,6 +183,26 @@ main (int argc, char **argv)
153 MU_ASSERT (mu_smtp_ehlo (smtp)); 183 MU_ASSERT (mu_smtp_ehlo (smtp));
154 } 184 }
155 185
186 if (meth_list)
187 {
188 int status;
189
190 MU_ASSERT (mu_smtp_add_auth_mech_list (smtp, meth_list));
191 status = mu_smtp_auth (smtp);
192 switch (status)
193 {
194 case 0:
195 case ENOSYS:
196 case MU_ERR_NOENT:
197 /* Ok, skip it */
198 break;
199
200 default:
201 mu_error ("authentication failed: %s", mu_strerror (status));
202 exit (1);
203 }
204 }
205
156 if (raw) 206 if (raw)
157 { 207 {
158 /* Raw sending mode: send from the stream directly */ 208 /* Raw sending mode: send from the stream directly */
......