Commit 02abfc44 02abfc4419cc651df0005a065f0db781dc884594 by Sergey Poznyakoff

Re-implement GSASL support.

* libmu_auth/lbuf.c: Removed.
* libmu_auth/lbuf.h: Removed.
* libmu_auth/Makefile.am : Remove lbuf stuff.

* include/mailutils/sys/gsasl-stream.h: New file.
* include/mailutils/sys/Makefile.am: Add gsasl-stream.h.
* include/mailutils/gsasl.h (mu_gsasl_stream_create): Remove.
(gsasl_encoder_stream, gsasl_decoder_stream): New prototypes.

* libmu_auth/gsasl.c: Rewrite.

* imap4d/authenticate.c (auth_data): Remove.
Use struct imap4d_auth instead.
(_auth_try): Use new authentication API.
(imap4d_authenticate): Likewise.
* imap4d/imap4d.h (util_register_event, util_event_remove)
(util_run_events): Remove.
(imap4d_auth_handler_fp): Change prototype.
(imap4d_auth): New struct.
(imap4d_auth_result): New enum.
* imap4d/io.c (io_format_completion_response)
(io_stream_completion_response): New functions.
(io_completion_response): Rewrite using io_format_completion_response.
* imap4d/util.c (sc2string): Remove leftover prototype.
(util_register_event, util_event_remove)
(util_run_events): Remove.
* imap4d/auth_gsasl.c: Revamp using new streams and the new
authentication interface.
* imap4d/auth_gss.c: Likewise (though yet untested).

* mailbox/xscript-stream.c (_xscript_ctl): Remove unused variables.
1 parent b5986a2d
......@@ -29,43 +29,6 @@ static Gsasl_session *sess_ctx;
static void auth_gsasl_capa_init (int disable);
static int
create_gsasl_stream (mu_stream_t *newstr, mu_stream_t transport, int flags)
{
int rc;
rc = mu_gsasl_stream_create (newstr, transport, sess_ctx, flags);
if (rc)
{
mu_diag_output (MU_DIAG_ERROR, _("cannot create SASL stream: %s"),
mu_strerror (rc));
return RESP_NO;
}
if ((rc = mu_stream_open (*newstr)) != 0)
{
mu_diag_output (MU_DIAG_ERROR,
_("cannot open SASL input stream: %s"),
mu_stream_strerror (*newstr, rc));
return RESP_NO;
}
return RESP_OK;
}
int
gsasl_replace_streams (void *self, void *data)
{
mu_stream_t *s = data;
util_set_input (s[0]);
util_set_output (s[1]);
free (s);
util_event_remove (self);
free (self);
return 0;
}
static void
finish_session (void)
{
......@@ -73,7 +36,21 @@ finish_session (void)
}
static int
auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
restore_and_return (struct imap4d_auth *ap, mu_stream_t *str, int resp)
{
int rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, str);
if (rc)
{
mu_error (_("%s failed when it should not: %s"), "MU_IOCTL_SWAP_STREAM",
mu_stream_strerror (iostream, rc));
abort ();
}
ap->response = resp;
return imap4d_auth_resp;
}
static enum imap4d_auth_result
auth_gsasl (struct imap4d_auth *ap)
{
char *input_str = NULL;
size_t input_size = 0;
......@@ -81,15 +58,15 @@ auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
char *output;
int rc;
rc = gsasl_server_start (ctx, auth_type, &sess_ctx);
rc = gsasl_server_start (ctx, ap->auth_type, &sess_ctx);
if (rc != GSASL_OK)
{
mu_diag_output (MU_DIAG_NOTICE, _("SASL gsasl_server_start: %s"),
gsasl_strerror (rc));
return 0;
return imap4d_auth_fail;
}
gsasl_callback_hook_set (ctx, username);
gsasl_callback_hook_set (ctx, &ap->username);
output = NULL;
while ((rc = gsasl_step64 (sess_ctx, input_str, &output))
......@@ -105,7 +82,8 @@ auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
gsasl_strerror (rc));
free (input_str);
free (output);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
/* Some SASL mechanisms output additional data when GSASL_OK is
......@@ -119,44 +97,81 @@ auth_gsasl (struct imap4d_command *command, char *auth_type, char **username)
mu_diag_output (MU_DIAG_NOTICE, _("non-empty client response"));
free (input_str);
free (output);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
}
free (input_str);
free (output);
if (*username == NULL)
if (ap->username == NULL)
{
mu_diag_output (MU_DIAG_NOTICE, _("GSASL %s: cannot get username"), auth_type);
return RESP_NO;
mu_diag_output (MU_DIAG_NOTICE, _("GSASL %s: cannot get username"),
ap->auth_type);
ap->response = RESP_NO;
return imap4d_auth_resp;
}
auth_gsasl_capa_init (1);
if (sess_ctx)
{
mu_stream_t tmp, new_in, new_out;
mu_stream_t *s;
util_get_input (&tmp);
if (create_gsasl_stream (&new_in, tmp, MU_STREAM_READ))
return RESP_NO;
util_get_output (&tmp);
if (create_gsasl_stream (&new_out, tmp, MU_STREAM_WRITE))
mu_stream_t stream[2], newstream[2];
stream[0] = stream[1] = NULL;
rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream);
if (rc)
{
mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM",
mu_stream_strerror (iostream, rc));
ap->response = RESP_NO;
return imap4d_auth_resp;
}
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 (ap, stream, RESP_NO);
}
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 (ap, stream, RESP_NO);
}
if (ap->username)
{
mu_stream_destroy (&new_in);
return RESP_NO;
if (imap4d_session_setup (ap->username))
return restore_and_return (ap, stream, RESP_NO);
}
s = calloc (2, sizeof (mu_stream_t));
s[0] = new_in;
s[1] = new_out;
util_register_event (STATE_NONAUTH, STATE_AUTH,
gsasl_replace_streams, s);
/* FIXME: This is not reflected in the transcript. */
io_stream_completion_response (stream[1], ap->command, RESP_OK,
"%s authentication successful",
ap->auth_type);
mu_stream_flush (stream[1]);
rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, newstream);
if (rc)
{
mu_error (_("%s failed when it should not: %s"),
"MU_IOCTL_SWAP_STREAM",
mu_stream_strerror (iostream, rc));
abort ();
}
util_atexit (finish_session);
return imap4d_auth_ok;
}
auth_gsasl_capa_init (1);
return RESP_OK;
ap->response = RESP_OK;
return imap4d_auth_resp;
}
static void
......
......@@ -108,9 +108,8 @@ imap4d_gss_userok (gss_buffer_t client_name, char *name)
}
#endif
static int
auth_gssapi (struct imap4d_command *command,
char *auth_type_unused, char **username)
static enum imap4d_auth_result
auth_gssapi (struct imap4d_auth *ap)
{
gss_buffer_desc tokbuf, outbuf;
OM_uint32 maj_stat, min_stat, min_stat2;
......@@ -147,7 +146,8 @@ auth_gssapi (struct imap4d_command *command,
if (maj_stat != GSS_S_COMPLETE)
{
display_status ("import name", maj_stat, min_stat);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
maj_stat = gss_acquire_cred (&min_stat, server_name, 0,
......@@ -158,7 +158,8 @@ auth_gssapi (struct imap4d_command *command,
if (maj_stat != GSS_S_COMPLETE)
{
display_status ("acquire credentials", maj_stat, min_stat);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
/* Start the dialogue */
......@@ -206,7 +207,8 @@ auth_gssapi (struct imap4d_command *command,
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
free (token_str);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
if (outbuf.length)
......@@ -228,7 +230,8 @@ auth_gssapi (struct imap4d_command *command,
{
display_status ("wrap", maj_stat, min_stat);
free (token_str);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
mu_base64_encode (outbuf.value, outbuf.length, &tmp, &size);
......@@ -246,7 +249,8 @@ auth_gssapi (struct imap4d_command *command,
if (maj_stat != GSS_S_COMPLETE)
{
display_status ("unwrap", maj_stat, min_stat);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
sec_level = ntohl (*(OM_uint32 *) outbuf.value);
......@@ -261,23 +265,25 @@ auth_gssapi (struct imap4d_command *command,
gss_release_buffer (&min_stat, &outbuf);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
protection_mech = mech;
client_buffer_size = sec_level & 0x00ffffffff;
*username = malloc (outbuf.length - 4 + 1);
if (!*username)
ap->username = malloc (outbuf.length - 4 + 1);
if (!ap->username)
{
mu_diag_output (MU_DIAG_NOTICE, _("not enough memory"));
gss_release_buffer (&min_stat, &outbuf);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
return RESP_NO;
ap->response = RESP_NO;
return imap4d_auth_resp;
}
memcpy (*username, (char *) outbuf.value + 4, outbuf.length - 4);
(*username)[outbuf.length - 4] = '\0';
memcpy (ap->username, (char *) outbuf.value + 4, outbuf.length - 4);
ap->username[outbuf.length - 4] = '\0';
gss_release_buffer (&min_stat, &outbuf);
maj_stat = gss_display_name (&min_stat, client, &client_name, &mech_type);
......@@ -286,36 +292,40 @@ auth_gssapi (struct imap4d_command *command,
display_status ("get client name", maj_stat, min_stat);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
free (*username);
return RESP_NO;
free (ap->username);
ap->response = RESP_NO;
return imap4d_auth_resp;
}
#ifdef WITH_GSS
baduser = !gss_userok (client, *username);
baduser = !gss_userok (client, ap->username);
#else
baduser = imap4d_gss_userok (&client_name, *username);
baduser = imap4d_gss_userok (&client_name, ap->username);
#endif
if (baduser)
{
mu_diag_output (MU_DIAG_NOTICE, _("GSSAPI user %s is NOT authorized as %s"),
(char *) client_name.value, *username);
mu_diag_output (MU_DIAG_NOTICE,
_("GSSAPI user %s is NOT authorized as %s"),
(char *) client_name.value, ap->username);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
gss_release_buffer (&min_stat, &client_name);
free (*username);
return RESP_NO;
free (ap->username);
ap->response = RESP_NO;
return imap4d_auth_resp;
}
else
{
mu_diag_output (MU_DIAG_NOTICE, _("GSSAPI user %s is authorized as %s"),
(char *) client_name.value, *username);
(char *) client_name.value, ap->username);
}
gss_release_buffer (&min_stat, &client_name);
maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
gss_release_buffer (&min_stat, &outbuf);
return RESP_OK;
ap->response = RESP_OK;
return imap4d_auth_resp;
}
void
......
......@@ -19,7 +19,8 @@
#include "imap4d.h"
struct imap_auth {
struct imap_auth
{
char *name;
imap4d_auth_handler_fp handler;
};
......@@ -66,24 +67,17 @@ _auth_capa (void *item, void *usused)
return 0;
}
struct auth_data {
struct imap4d_command *command;
char *auth_type;
char *arg;
char *username;
int result;
};
static int
_auth_try (void *item, void *data)
{
struct imap_auth *p = item;
struct auth_data *ap = data;
struct imap4d_auth *ap = data;
if (strcmp (p->name, ap->auth_type) == 0)
{
ap->result = p->handler (ap->command, ap->auth_type, &ap->username);
return 1;
int res = p->handler (ap);
if (res)
return res;
}
return 0;
}
......@@ -104,8 +98,9 @@ int
imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok)
{
char *auth_type;
struct auth_data adata;
struct imap4d_auth adata;
enum imap4d_auth_result res;
if (imap4d_tokbuf_argc (tok) != 3)
return io_completion_response (command, RESP_BAD, "Invalid arguments");
......@@ -117,25 +112,35 @@ imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok)
adata.command = command;
adata.auth_type = auth_type;
adata.arg = NULL;
adata.username = NULL;
if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0)
return io_completion_response (command, RESP_NO,
"Authentication mechanism not supported");
if (adata.result == RESP_OK && adata.username)
res = mu_list_do (imap_auth_list, _auth_try, &adata);
switch (res)
{
if (imap4d_session_setup (adata.username))
return io_completion_response (command, RESP_NO,
"User name or passwd rejected");
else
return io_completion_response (command, RESP_OK,
"%s authentication successful",
auth_type);
case imap4d_auth_nosup:
return io_completion_response (command, RESP_NO,
"Authentication mechanism not supported");
case imap4d_auth_ok:
return 0;
case imap4d_auth_resp:
if (adata.response == RESP_OK && adata.username)
{
if (imap4d_session_setup (adata.username))
return io_completion_response (command, RESP_NO,
"User name or passwd rejected");
else
return io_completion_response (command, RESP_OK,
"%s authentication successful",
auth_type);
}
/* fall through */
case imap4d_auth_fail:
adata.response = RESP_NO;
break;
}
return io_completion_response (command, adata.result,
"%s authentication failed", auth_type);
return io_completion_response (command, adata.response,
"%s authentication failed", auth_type);
}
......
......@@ -218,6 +218,11 @@ extern int io_send_literal (const char *);
extern int io_copy_out (mu_stream_t str, size_t size);
extern int io_completion_response (struct imap4d_command *, int,
const char *, ...) MU_PRINTFLIKE(3,4);
extern int io_stream_completion_response (mu_stream_t str,
struct imap4d_command *command,
int rc,
const char *format, ...)
MU_PRINTFLIKE(4,5);
int io_getline (char **pbuf, size_t *psize, size_t *pnbytes);
void io_setio (FILE*, FILE*);
void io_flush (void);
......@@ -368,10 +373,6 @@ int util_type_to_attribute (int type, char **attr_str);
int util_attribute_matches_flag (mu_attribute_t attr, const char *item);
int util_uidvalidity (mu_mailbox_t smbox, unsigned long *uidvp);
void util_register_event (int old_state, int new_state,
mu_list_action_t *action, void *data);
void util_event_remove (void *id);
void util_run_events (int old_state, int new_state);
int util_is_master (void);
void util_bye (void);
......@@ -385,8 +386,26 @@ int util_trim_nl (char *s, size_t len);
int imap4d_init_tls_server (void);
#endif /* WITH_TLS */
typedef int (*imap4d_auth_handler_fp) (struct imap4d_command *,
char *, char **);
struct imap4d_auth
{
/* input */
struct imap4d_command *command;
char *auth_type;
/* output */
char *username;
int response;
};
enum imap4d_auth_result
{
imap4d_auth_nosup,
imap4d_auth_ok,
imap4d_auth_resp,
imap4d_auth_fail
};
typedef enum imap4d_auth_result
(*imap4d_auth_handler_fp) (struct imap4d_auth *);
extern void auth_add (char *name, imap4d_auth_handler_fp handler);
extern void auth_remove (char *name);
......
......@@ -219,20 +219,18 @@ io_untagged_response (int rc, const char *format, ...)
/* Send the completion response and reset the state. */
int
io_completion_response (struct imap4d_command *command, int rc,
const char *format, ...)
io_format_completion_response (mu_stream_t str,
struct imap4d_command *command, int rc,
const char *format, va_list ap)
{
int new_state;
int status = 0;
va_list ap;
const char *sc = sc2string (rc);
mu_stream_printf (iostream, "%s %s%s ",
mu_stream_printf (str, "%s %s%s ",
command->tag, sc, command->name);
va_start (ap, format);
mu_stream_vprintf (iostream, format, ap);
va_end (ap);
mu_stream_write (iostream, "\n", 1, NULL);
mu_stream_vprintf (str, format, ap);
mu_stream_write (str, "\n", 1, NULL);
/* Reset the state. */
if (rc == RESP_OK)
......@@ -243,11 +241,35 @@ io_completion_response (struct imap4d_command *command, int rc,
new_state = STATE_NONE;
if (new_state != STATE_NONE)
{
util_run_events (state, new_state);
state = new_state;
}
state = new_state;
return status;
}
int
io_completion_response (struct imap4d_command *command, int rc,
const char *format, ...)
{
va_list ap;
int status;
va_start (ap, format);
status = io_format_completion_response (iostream, command, rc, format, ap);
va_end (ap);
return status;
}
int
io_stream_completion_response (mu_stream_t str,
struct imap4d_command *command, int rc,
const char *format, ...)
{
va_list ap;
int status;
va_start (ap, format);
status = io_format_completion_response (str, command, rc, format, ap);
va_end (ap);
return status;
}
......
......@@ -20,7 +20,6 @@
#include "imap4d.h"
static int add2set (size_t **, int *, unsigned long);
static const char *sc2string (int);
/* NOTE: Allocates Memory. */
/* Expand: ~ --> /home/user and to ~guest --> /home/guest. */
......@@ -651,74 +650,6 @@ util_bye ()
mu_list_do (atexit_list, atexit_run, 0);
}
struct state_event
{
int old_state;
int new_state;
mu_list_action_t *action;
void *data;
};
static mu_list_t event_list;
void
util_register_event (int old_state, int new_state,
mu_list_action_t *action, void *data)
{
struct state_event *evp = malloc (sizeof (*evp));
if (!evp)
imap4d_bye (ERR_NO_MEM);
evp->old_state = old_state;
evp->new_state = new_state;
evp->action = action;
evp->data = data;
if (!event_list)
{
mu_list_create (&event_list);
mu_list_set_destroy_item (event_list, mu_list_free_item);
}
mu_list_append (event_list, (void*)evp);
}
void
util_event_remove (void *id)
{
mu_list_remove (event_list, id);
}
static int
event_exec (void *item, void *data)
{
struct state_event *ev = data, *elem = item;
if (ev->old_state == elem->old_state && ev->new_state == elem->new_state)
return elem->action (item, elem->data);
return 0;
}
void
util_run_events (int old_state, int new_state)
{
if (event_list)
{
struct state_event ev;
mu_iterator_t itr;
ev.old_state = old_state;
ev.new_state = new_state;
mu_list_get_iterator (event_list, &itr);
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
{
struct state_event *p;
mu_iterator_current (itr, (void **)&p);
if (event_exec (p, &ev))
break;
}
mu_iterator_destroy (&itr);
}
}
void
util_chdir (const char *dir)
{
......
......@@ -36,8 +36,10 @@ extern struct mu_gsasl_module_data mu_gsasl_module_data;
#ifdef WITH_GSASL
#include <gsasl.h>
int mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
Gsasl_session *ctx, int flags);
int gsasl_encoder_stream (mu_stream_t *pstr, mu_stream_t transport,
Gsasl_session *ctx, int flags);
int gsasl_decoder_stream (mu_stream_t *pstr, mu_stream_t transport,
Gsasl_session *ctx, int flags);
#endif
......
......@@ -22,6 +22,7 @@ sysinclude_HEADERS = \
dbgstream.h\
file_stream.h\
filter.h\
gsasl-stream.h\
header_stream.h\
header.h\
iostream.h\
......
/* 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/>. */
#ifndef _MAILUTILS_SYS_TLS_STREAM_H
# define _MAILUTILS_SYS_GSASL_STREAM_H
# include <mailutils/types.h>
# include <mailutils/stream.h>
# include <mailutils/sys/stream.h>
struct _mu_gsasl_filter
{
Gsasl_session *sess_ctx; /* Context */
int gsasl_err; /* Last Gsasl error code */
char *bufptr;
size_t bufsize;
};
struct _mu_gsasl_stream
{
struct _mu_stream stream;
mu_stream_t transport;
};
#endif
......@@ -26,8 +26,6 @@ lib_LTLIBRARIES = libmu_auth.la
libmu_auth_la_SOURCES = \
gsasl.c\
lbuf.c\
lbuf.h\
ldap.c\
pam.c\
radius.c\
......
......@@ -33,9 +33,10 @@
#include <mailutils/nls.h>
#include <mailutils/stream.h>
#include <mailutils/gsasl.h>
#include <mailutils/sys/gsasl-stream.h>
#include <mailutils/filter.h>
#include <gsasl.h>
#include <lbuf.h>
struct mu_gsasl_module_data mu_gsasl_module_data = {
SITE_CRAM_MD5_PWD
......@@ -49,235 +50,172 @@ mu_gsasl_module_init (enum mu_gocs_op op, void *data)
return 0;
}
struct _gsasl_stream {
Gsasl_session *sess_ctx; /* Context */
int last_err; /* Last Gsasl error code */
mu_stream_t stream; /* I/O stream */
struct _line_buffer *lb;
};
static void
_gsasl_destroy (mu_stream_t stream)
{
int flags;
struct _gsasl_stream *s = mu_stream_get_owner (stream);
mu_stream_get_flags (stream, &flags);
if (!(flags & MU_STREAM_NO_CLOSE))
mu_stream_destroy (&s->stream, mu_stream_get_owner (s->stream));
_auth_lb_destroy (&s->lb);
}
static int
_gsasl_readline (mu_stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
static enum mu_filter_result
_gsasl_encoder (void *xdata,
enum mu_filter_command cmd,
struct mu_filter_io *iobuf)
{
struct _gsasl_stream *s = mu_stream_get_owner (stream);
int rc;
size_t len, sz;
char *bufp = NULL;
struct _mu_gsasl_filter *flt = xdata;
if (_auth_lb_level (s->lb))
switch (cmd)
{
len = _auth_lb_readline (s->lb, optr, osize-1);
optr[len] = 0;
if (nbytes)
*nbytes = len;
return 0;
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);
free (flt);
return mu_filter_ok;
default:
break;
}
do
if (flt->bufptr == NULL)
{
char c;
size_t sz;
int status;
status = mu_stream_sequential_read (s->stream, &c, 1, &sz);
if (status == EINTR)
continue;
else if (status)
int status = gsasl_encode (flt->sess_ctx, iobuf->input, iobuf->isize,
&flt->bufptr, &flt->bufsize);
/* FIXME: Can it require more input? */
if (status)
{
free (bufp);
return status;
flt->gsasl_err = status;
return mu_filter_falure;
}
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),
&bufp, &len);
}
while (rc == GSASL_NEEDS_MORE);
iobuf->osize = flt->bufsize;
if (rc != GSASL_OK)
{
s->last_err = rc;
free (bufp);
return EIO;
}
sz = len > osize ? osize : len;
if (len > osize)
{
memcpy (optr, bufp, osize);
_auth_lb_drop (s->lb);
_auth_lb_grow (s->lb, bufp + osize, len - osize);
len = osize;
}
else
{
_auth_lb_drop (s->lb);
memcpy (optr, bufp, len);
}
if (flt->bufsize > iobuf->osize)
return mu_filter_moreoutput;
if (len < osize)
optr[len] = 0;
if (nbytes)
*nbytes = len;
free (bufp);
memcpy (iobuf->output, flt->bufptr, flt->bufsize);
return 0;
free (flt->bufptr);
flt->bufptr = NULL;
flt->bufsize = 0;
return mu_filter_ok;
}
int
write_chunk (void *data, char *start, char *end)
static enum mu_filter_result
_gsasl_decoder (void *xdata,
enum mu_filter_command cmd,
struct mu_filter_io *iobuf)
{
struct _gsasl_stream *s = data;
size_t chunk_size = end - start + 1;
size_t len = 0;
char *buf = NULL;
struct _mu_gsasl_filter *flt = xdata;
int status;
gsasl_encode (s->sess_ctx, start, chunk_size, &buf, &len);
status = mu_stream_sequential_write (s->stream, buf, len);
free (buf);
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);
free (flt);
return mu_filter_ok;
default:
break;
}
return status;
}
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_falure;
}
}
iobuf->osize = flt->bufsize;
static int
_gsasl_write (mu_stream_t stream, const char *iptr, size_t isize,
off_t offset, size_t *nbytes)
{
int rc;
struct _gsasl_stream *s = mu_stream_get_owner (stream);
if (flt->bufsize > iobuf->osize)
return mu_filter_moreoutput;
rc = _auth_lb_grow (s->lb, iptr, isize);
if (rc)
return rc;
return _auth_lb_writelines (s->lb, iptr, isize, offset,
write_chunk, s, nbytes);
}
static int
_gsasl_flush (mu_stream_t stream)
{
struct _gsasl_stream *s = mu_stream_get_owner (stream);
return mu_stream_flush (s->stream);
}
memcpy (iobuf->output, flt->bufptr, flt->bufsize);
static int
_gsasl_close (mu_stream_t stream)
{
int flags;
struct _gsasl_stream *s = mu_stream_get_owner (stream);
mu_stream_get_flags (stream, &flags);
if (!(flags & MU_STREAM_NO_CLOSE))
mu_stream_close (s->stream);
return 0;
}
static int
_gsasl_open (mu_stream_t stream)
{
/* Nothing to do */
return 0;
}
int
_gsasl_strerror (mu_stream_t stream, const char **pstr)
{
struct _gsasl_stream *s = mu_stream_get_owner (stream);
*pstr = gsasl_strerror (s->last_err);
return 0;
free (flt->bufptr);
flt->bufptr = NULL;
flt->bufsize = 0;
return mu_filter_ok;
}
int
_gsasl_get_transport2 (mu_stream_t stream, mu_transport_t *pt, mu_transport_t *pt2)
gsasl_encoder_stream (mu_stream_t *pstr, mu_stream_t transport,
Gsasl_session *ctx, int flags)
{
struct _gsasl_stream *s = mu_stream_get_owner (stream);
*pt2 = NULL; /* FIXME 1 */
*pt = (mu_transport_t) s->stream;
return 0;
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, 1024);
return rc;
}
int
_gsasl_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
gsasl_decoder_stream (mu_stream_t *pstr, mu_stream_t transport,
Gsasl_session *ctx, int flags)
{
int flags;
struct _gsasl_stream *s = mu_stream_get_owner (stream);
mu_stream_get_flags (stream, &flags);
if (((*pflags & MU_STREAM_READY_RD) && !(flags & MU_STREAM_READ))
|| ((*pflags & MU_STREAM_READY_WR) && !(flags & MU_STREAM_WRITE)))
return EINVAL;
return mu_stream_wait (s->stream, pflags, tvp);
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, 1024);
return rc;
}
int
mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport,
Gsasl_session *ctx, int flags)
{
struct _gsasl_stream *s;
int rc;
mu_stream_t in, out;
if (stream == NULL)
return MU_ERR_OUT_PTR_NULL;
if ((flags & ~(MU_STREAM_READ|MU_STREAM_WRITE))
|| (flags & (MU_STREAM_READ|MU_STREAM_WRITE)) ==
(MU_STREAM_READ|MU_STREAM_WRITE))
return EINVAL;
s = calloc (1, sizeof (*s));
if (s == NULL)
return ENOMEM;
s->stream = transport;
s->sess_ctx = ctx;
rc = mu_stream_create (stream, flags, s);
rc = gsasl_encoder_stream (&in, transport, ctx, MU_STREAM_READ);
if (rc)
return rc;
rc = gsasl_encoder_stream (&out, transport, ctx, MU_STREAM_WRITE);
if (rc)
{
free (s);
mu_stream_destroy (&in);
return rc;
}
mu_stream_set_open (*stream, _gsasl_open, s);
mu_stream_set_close (*stream, _gsasl_close, s);
mu_stream_set_flush (*stream, _gsasl_flush, s);
mu_stream_set_destroy (*stream, _gsasl_destroy, s);
mu_stream_set_strerror (*stream, _gsasl_strerror, s);
mu_stream_set_wait (*stream, _gsasl_wait, s);
mu_stream_set_get_transport2 (*stream, _gsasl_get_transport2, s);
if (flags & MU_STREAM_READ)
mu_stream_set_readline (*stream, _gsasl_readline, s);
else
mu_stream_set_write (*stream, _gsasl_write, s);
_auth_lb_create (&s->lb);
return 0;
rc = mu_iostream_create (stream, in, out);
mu_stream_unref (in);
mu_stream_unref (out);
return rc;
}
#endif
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003, 2007, 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 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, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <lbuf.h>
struct _line_buffer {
char *buffer; /* Line buffer */
size_t size; /* Allocated size */
size_t level; /* Current filling level */
};
int
_auth_lb_create (struct _line_buffer **s)
{
*s = malloc (sizeof (**s));
if (!*s)
return ENOMEM;
(*s)->buffer = NULL;
(*s)->size = 0;
(*s)->level = 0;
return 0;
}
void
_auth_lb_destroy (struct _line_buffer **s)
{
if (s && *s)
{
free ((*s)->buffer);
free (*s);
*s = NULL;
}
}
void
_auth_lb_drop (struct _line_buffer *s)
{
s->level = 0;
}
int
_auth_lb_grow (struct _line_buffer *s, const char *ptr, size_t size)
{
if (!s->buffer)
{
s->buffer = malloc (size);
s->size = size;
s->level = 0;
}
else if (s->size - s->level < size)
{
size_t newsize = s->size + size;
s->buffer = realloc (s->buffer, newsize);
if (s->buffer)
s->size = newsize;
}
if (!s->buffer)
return ENOMEM;
memcpy (s->buffer + s->level, ptr, size);
s->level += size;
return 0;
}
int
_auth_lb_read (struct _line_buffer *s, char *optr, size_t osize)
{
int len;
len = s->level > osize ? osize : s->level;
memcpy (optr, s->buffer, len);
if (s->level > len)
{
memmove (s->buffer, s->buffer + len, s->level - len);
s->level -= len;
}
else if (s->level == len)
s->level = 0;
return len;
}
int
_auth_lb_readline (struct _line_buffer *s, char *ptr, size_t size)
{
char *p = strchr (s->buffer, '\n');
if (p && p - s->buffer + 1 < size)
size = p - s->buffer + 1;
return _auth_lb_read (s, ptr, size);
}
int
_auth_lb_writelines (struct _line_buffer *s, const char *iptr, size_t isize,
off_t offset,
int (*wr) (void *data, char *start, char *end),
void *data,
size_t *nbytes)
{
if (s->level > 2)
{
char *start, *end;
for (start = s->buffer,
end = memchr (start, '\n', s->buffer + s->level - start);
end && end < s->buffer + s->level;
start = end + 1,
end = memchr (start, '\n', s->buffer + s->level - start))
if (end[-1] == '\r')
{
int rc = wr (data, start, end);
if (rc)
return rc;
}
if (start > s->buffer)
{
if (start < s->buffer + s->level)
{
int rest = s->buffer + s->level - start;
memmove (s->buffer, start, rest);
s->level = rest;
}
else
s->level = 0;
}
}
if (nbytes)
*nbytes = isize;
return 0;
}
int
_auth_lb_level (struct _line_buffer *s)
{
return s->level;
}
char *
_auth_lb_data (struct _line_buffer *s)
{
return s->buffer;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2003, 2005, 2007, 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 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, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
#include <mailutils/types.h>
struct _line_buffer;
int _auth_lb_create (struct _line_buffer **s);
void _auth_lb_destroy (struct _line_buffer **s);
void _auth_lb_drop (struct _line_buffer *s);
int _auth_lb_grow (struct _line_buffer *s, const char *ptr, size_t size);
int _auth_lb_read (struct _line_buffer *s, char *ptr, size_t size);
int _auth_lb_readline (struct _line_buffer *s, char *ptr, size_t size);
int _auth_lb_writelines (struct _line_buffer *s, const char *iptr,
size_t isize, off_t offset,
int (*wr) (void *data, char *start, char *end),
void *data, size_t *nbytes);
int _auth_lb_level (struct _line_buffer *s);
char *_auth_lb_data (struct _line_buffer *s);
......@@ -176,7 +176,6 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg)
{
struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str;
mu_transport_t *ptrans;
mu_stream_t strtab[2];
switch (op)
{
......