diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2003-01-22 13:11:21 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2003-01-22 13:11:21 +0000 |
commit | 700a91d68bf40b904fcc112dc4bc76e2e28fc153 (patch) | |
tree | dde41d67a4a6c2a5cbb0f329cc3e28a8a617c29a /auth | |
parent | 468b8569871948ae74a376df8a906e323ddf2ca8 (diff) | |
download | mailutils-700a91d68bf40b904fcc112dc4bc76e2e28fc153.tar.gz mailutils-700a91d68bf40b904fcc112dc4bc76e2e28fc153.tar.bz2 |
Added gsasl.c.
Diffstat (limited to 'auth')
-rw-r--r-- | auth/Makefile.am | 4 | ||||
-rw-r--r-- | auth/gsasl.c | 268 |
2 files changed, 271 insertions, 1 deletions
diff --git a/auth/Makefile.am b/auth/Makefile.am index b615657a0..ef1c9e975 100644 --- a/auth/Makefile.am +++ b/auth/Makefile.am @@ -23,10 +23,12 @@ AM_CFLAGS = -DSITE_VIRTUAL_PWDDIR=\"@SITE_VIRTUAL_PWDDIR@\" lib_LTLIBRARIES = libmuauth.la libmuauth_la_SOURCES = \ +gsasl.c \ pam.c \ sql.c \ tls.c \ virtual.c -libmuauth_la_LIBADD = @LTLIBINTL@ +libmuauth_la_LIBADD = @AUTH_AUTHOBJS@ @LTLIBINTL@ libmuauth_la_LDFLAGS = -version-info 0:0:0 + diff --git a/auth/gsasl.c b/auth/gsasl.c new file mode 100644 index 000000000..926553581 --- /dev/null +++ b/auth/gsasl.c @@ -0,0 +1,268 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2003 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Mailutils 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef WITH_GSASL + +#include <stdlib.h> +#include <string.h> +#include <mailutils/argp.h> +#include <mailutils/error.h> +#include <mailutils/mu_auth.h> +#include <mailutils/nls.h> +#include <mailutils/stream.h> + +#include <gsasl.h> + +struct _gsasl_stream { + Gsasl_session_ctx *sess_ctx; /* Context */ + int last_err; /* Last Gsasl error code */ + + stream_t stream; /* Underlying stream */ + size_t offset; /* Current offset */ + + char *buffer; /* Line buffer */ + size_t size; /* Allocated size */ + size_t level; /* Current filling level */ +}; + +static void +_gsasl_destroy (stream_t stream) +{ + struct _gsasl_stream *s = stream_get_owner (stream); + stream_destroy (&s->stream, stream_get_owner (s->stream)); + free (s->buffer); + s->buffer = NULL; +} + +#define buffer_drop(s) s->level = 0 + +int +buffer_grow (struct _gsasl_stream *s, 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; +} + +static int +_gsasl_readline (stream_t stream, char *optr, size_t osize, + off_t offset, size_t *nbytes) +{ + struct _gsasl_stream *s = stream_get_owner (stream); + int rc; + size_t len, sz; + char *bufp; + + if (s->level) + { + 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; + } + if (nbytes) + *nbytes = len; + return 0; + } + + do + { + char buf[80]; + size_t sz; + + rc = stream_readline (s->stream, buf, sizeof (buf), s->offset, &sz); + if (rc) + return rc; + + s->offset += sz; + + rc = buffer_grow (s, buf, sz); + if (rc) + return rc; + + rc = gsasl_decode (s->sess_ctx, s->buffer, s->level, NULL, &len); + } + while (rc == GSASL_NEEDS_MORE); + + if (rc != GSASL_OK) + { + s->last_err = rc; + return EIO; + } + + bufp = malloc (len + 1); + if (!bufp) + return ENOMEM; + rc = gsasl_decode (s->sess_ctx, s->buffer, s->level, bufp, &len); + if (rc != GSASL_OK) + { + s->last_err = rc; + return EIO; + } + bufp[len++] = '\0'; + + sz = len > osize ? osize : len; + + if (len > osize) + { + memcpy (optr, bufp, osize); + buffer_drop (s); + buffer_grow (s, bufp + osize, len - osize); + len = osize; + } + else + memcpy (optr, bufp, len); + + if (nbytes) + *nbytes = len; + + free (bufp); + + return 0; +} + +static int +_gsasl_write (stream_t stream, const char *iptr, size_t isize, + off_t offset, size_t *nbytes) +{ + int rc; + struct _gsasl_stream *s = stream_get_owner (stream); + + rc = buffer_grow (s, iptr, isize); + if (rc) + return rc; + + if (s->level >= 2 + && s->buffer[s->level - 2] == '\r' + && s->buffer[s->level - 1] == '\n') + { + size_t len, wrsize; + char *buf = NULL; + + gsasl_encode (s->sess_ctx, s->buffer, s->level, NULL, &len); + buf = malloc (len); + if (!buf) + return ENOMEM; + + gsasl_encode (s->sess_ctx, s->buffer, s->level, buf, &len); + rc = stream_write (s->stream, buf, len, s->offset, &wrsize); + free (buf); + if (rc) + return rc; + s->offset += wrsize; + + if (nbytes) + *nbytes = wrsize; + + s->level = 0; + } + return 0; +} + +static int +_gsasl_flush (stream_t stream) +{ + struct _gsasl_stream *s = stream_get_owner (stream); + stream_flush (s->stream); + return 0; +} + +static int +_gsasl_close (stream_t stream) +{ + struct _gsasl_stream *s = stream_get_owner (stream); + stream_close (s->stream); + if (s->sess_ctx) + gsasl_server_finish (s->sess_ctx); + return 0; +} + +static int +_gsasl_open (stream_t stream) +{ + struct _gsasl_stream *s = stream_get_owner (stream); + return 0; +} + +int +_gsasl_strerror (stream_t stream, const char **pstr) +{ + struct _gsasl_stream *s = stream_get_owner (stream); + *pstr = gsasl_strerror (s->last_err); + return 0; +} + + +int +gsasl_stream_create (stream_t *stream, stream_t ins, + Gsasl_session_ctx *ctx, int flags) +{ + struct _gsasl_stream *s; + + if (stream == NULL) + return EINVAL; + + 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 = ins; + s->sess_ctx = ctx; + + stream_set_open (*stream, _gsasl_open, s); + stream_set_close (*stream, _gsasl_close, s); + stream_set_flush (*stream, _gsasl_flush, s); + stream_set_destroy (*stream, _gsasl_destroy, s); + stream_set_strerror (*stream, _gsasl_strerror, s); + + if (flags & MU_STREAM_READ) + stream_set_readline (*stream, _gsasl_readline, s); + else + stream_set_write (*stream, _gsasl_write, s); + + return 0; +} + +#endif |