Commit 700a91d6 700a91d68bf40b904fcc112dc4bc76e2e28fc153 by Sergey Poznyakoff

Added gsasl.c.

1 parent 468b8569
......@@ -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
......
/* 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