On Fri, Jun 13, 2014 at 09:47:49AM +0200, Jan Synacek wrote: > I've implemented GSSAPI support for isync. I was a bit unsure about the > ifdefs and how to structure them, since I use EVP_DecodeBlock() to > decode base64, which means dependency on OpenSSL. Consider this patch > version 1. > just a partial review for now.
note that there is also a sasl branch in git. you can take a lot from the commit and also the review in the commit message. ideally, revive it as well. > From 6677e6f4b7ab436362b2a0b2ff623d516d15c3ab Mon Sep 17 00:00:00 2001 > From: Jan Synacek <[email protected]> > Date: Fri, 13 Jun 2014 09:22:05 +0200 > Subject: [PATCH] implement gssapi support > > --- > configure.ac | 14 ++++ > src/common.h | 4 ++ > src/drv_imap.c | 201 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > src/socket.h | 3 + > src/util.c | 20 ++++++ > 5 files changed, 242 insertions(+) > > diff --git a/configure.ac b/configure.ac > index 3a9927d..bf68daf 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -100,6 +100,20 @@ if test "x$ob_cv_with_ssl" != xno; then > fi > AC_SUBST(SSL_LIBS) > > +AC_ARG_ENABLE([gssapi], > + [AC_HELP_STRING([--enable-gssapi], > + [enable gssapi support [no]] > + )], > + [gssapi=${enableval}], > + [gssapi=no]) > +if test "${gssapi}" = yes; then > + AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context, [gssapi_krb5=yes]) > + if test "${gssapi_krb5}" = yes; then > + AC_DEFINE(HAVE_LIBGSSAPI, 1, [if you have the gssapi_krb5 library]) > + LDFLAGS="$LDFLAGS -lgssapi_krb5" > you need to assign (and later use) GSSAPI_LIBS instead. > + fi > +fi > + > AC_CACHE_CHECK([for Berkley DB >= 4.2], ac_cv_berkdb4, > [ac_cv_berkdb4=no > AC_TRY_LINK([#include <db.h>], > diff --git a/src/common.h b/src/common.h > index fb868b3..6afcc9f 100644 > --- a/src/common.h > +++ b/src/common.h > @@ -133,4 +133,8 @@ void fake_fd( int fd, int events ); > void del_fd( int fd ); > void main_loop( void ); > > +#if HAVE_LIBSSL && HAVE_LIBGSSAPI > +int from_base64( char *, const char *, const int ); > +#endif > + > #endif > diff --git a/src/drv_imap.c b/src/drv_imap.c > index adacc43..9c08934 100644 > --- a/src/drv_imap.c > +++ b/src/drv_imap.c > @@ -35,6 +35,11 @@ > #include <ctype.h> > #include <time.h> > #include <sys/wait.h> > +#if HAVE_LIBSSL && HAVE_LIBGSSAPI > +# include <gssapi.h> > +# include <openssl/evp.h> > +#endif > + > > typedef struct imap_server_conf { > struct imap_server_conf *next; > @@ -180,6 +185,9 @@ enum CAPABILITY { > static const char *cap_list[] = { > "LOGINDISABLED", > #ifdef HAVE_LIBSSL > +# ifdef HAVE_LIBGSSAPI > + "AUTH=GSSAPI", > +# endif > "AUTH=CRAM-MD5", > "STARTTLS", > #endif > @@ -1442,6 +1450,182 @@ do_cram_auth( imap_store_t *ctx, struct imap_cmd > *cmdp, const char *prompt ) > } > #endif > > +#ifdef HAVE_LIBGSSAPI > +static gss_ctx_id_t Gss_ctx; > +static gss_name_t Gss_name; > + > +#define GSS_BUFSIZE 16384 > + > +static int do_gssapi_auth_p2 ( imap_store_t *, struct imap_cmd *, const char > * ); > +static int do_gssapi_auth_p3 ( imap_store_t *, struct imap_cmd *, const char > * ); > + > +static int > +send_gss_buffer( imap_store_t *ctx, gss_buffer_t buffer ) > +{ > + char *buf; > + int len; > + > + buf = nfcalloc( GSS_BUFSIZE ); > + len = EVP_EncodeBlock( (unsigned char *)buf, (unsigned char > *)buffer->value, buffer->length ); > + > + if (socket_write( &ctx->conn, buf, len, GiveOwn ) < 0) > + return -1; > + return socket_write( &ctx->conn, "\r\n", 2, KeepOwn ); > +} > + > +static int > +do_gssapi_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt > ATTR_UNUSED ) > +{ > + imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server; > + > + gss_buffer_desc input; > + gss_buffer_desc output; > + OM_uint32 maj, min; > + char buf[GSS_BUFSIZE]; > + > + cmdp->param.cont = do_gssapi_auth_p2; > + > + snprintf( buf, sizeof( buf ), "imap@%s", srvc->sconf.host ); > nfsnprintf(), no? > + input.value = buf; > + input.length = strlen( buf ) + 1; > + *printf*() returns the length. > + maj = gss_import_name( &min, &input, GSS_C_NT_HOSTBASED_SERVICE, > &Gss_name ); > + if (maj != GSS_S_COMPLETE) { > + error( "Couldn't get service name for [%s]\n", buf ); > + return -1; > + } > + > + if (DFlags & VERBOSE) { > + gss_OID mech_name; > + maj = gss_display_name( &min, Gss_name, &input, &mech_name ); > + printf( "Using service name [%s]\n", (char *)input.value ); > + fflush( stdout ); > info() > + } > + > + input.value = NULL; input.length = 0; > + > + maj = gss_init_sec_context( > + &min, > + GSS_C_NO_CREDENTIAL, > + &Gss_ctx, > + Gss_name, > + GSS_C_NO_OID, > + GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, > + 0, > + GSS_C_NO_CHANNEL_BINDINGS, > + &input, > + NULL, > + &output, > + NULL, > + NULL ); > + i prefer long lines over micro wrapping. if the line becomes really long (more than 120 chars or so), wrap at some logical boundary if possible. > + if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) { > + error( "Error acquiring credentials. Do you have a kerberos > ticket?\n" ); > + gss_release_name( &min, &Gss_name ); > + return -1; > + } > + > + return send_gss_buffer( ctx, &output ); > +} > + > +static int > +do_gssapi_auth_p2( imap_store_t *ctx, struct imap_cmd *cmdp, const char > *prompt ) > +{ > + gss_buffer_desc input; > + gss_buffer_desc output; > + OM_uint32 maj, min; > + char *buf; > + > + cmdp->param.cont = do_gssapi_auth_p3; > + > + buf = nfcalloc( GSS_BUFSIZE ); > + input.length = from_base64( buf, prompt, strlen( prompt ) ); > + input.value = buf; > + > + maj = gss_init_sec_context( > + &min, > + GSS_C_NO_CREDENTIAL, > + &Gss_ctx, > + Gss_name, > + GSS_C_NO_OID, > + GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, > + 0, > + GSS_C_NO_CHANNEL_BINDINGS, > + &input, > + NULL, > + &output, > + NULL, > + NULL ); > + > + if (maj == GSS_S_CONTINUE_NEEDED) > + cmdp->param.cont = do_gssapi_auth_p2; > + else > + gss_release_name( &min, &Gss_name ); > + > + free( buf ); > + > + if (output.length > 0) > + return send_gss_buffer( ctx, &output ); > + > + return 0; > +} > + > +static int > +do_gssapi_auth_p3( imap_store_t *ctx, struct imap_cmd *cmdp, const char > *prompt ) > +{ > + imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server; > + gss_buffer_desc input; > + gss_buffer_desc output; > + OM_uint32 maj, min; > + char *buf; > + int plen; > + > + cmdp->param.cont = 0; > + > + plen = strlen( prompt ); > + buf = nfcalloc( plen + 1 ); > + input.length = from_base64( buf, prompt, plen ); > + input.value = buf; > + > + maj = gss_unwrap( &min, > + Gss_ctx, > + &input, > + &output, > + NULL, > + NULL ); > + > + if (maj != GSS_S_COMPLETE) { > + error( "Unexpected error while calling gss_unwrap()\n" ); > + return -1; > + } > + > + /* First octet means supported security level, second through forth > + octets mean maximum token size. We don't care about setting any, so > + send them back as they came in. And append the username after them. > */ > any what? them? > + memcpy( buf, output.value, 4 ); > + strcpy( buf + 4, srvc->user ); > + input.value = buf; > + input.length = 4 + strlen( srvc->user ); > + > + maj = gss_wrap( &min, > + Gss_ctx, > + 0, > + GSS_C_QOP_DEFAULT, > + &input, > + NULL, > + &output ); > + > + gss_release_buffer( &min, &input ); > + > + if (maj != GSS_S_COMPLETE) { > + error( "Unexpected error while calling gss_wrap()\n" ); > + return -1; > + } > + > + return send_gss_buffer( ctx, &output ); > +} > +#endif > + > static void imap_open_store_connected( int, void * ); > #ifdef HAVE_LIBSSL > static void imap_open_store_tlsstarted1( int, void * ); > @@ -1641,6 +1825,16 @@ imap_open_store_authenticate2( imap_store_t *ctx ) > error( "Skipping account %s, no user\n", srvc->name ); > goto bail; > } > +#ifdef HAVE_LIBGSSAPI > + if (srvc->sconf.use_gssapi) { > + struct imap_cmd *cmd = new_imap_cmd( sizeof(*cmd) ); > + > + info( "Authenticating with GSSAPI\n" ); > + cmd->param.cont = do_gssapi_auth; > + imap_exec( ctx, cmd, imap_open_store_authenticate2_p2, > "AUTHENTICATE GSSAPI" ); > + return; > + } > +#endif > if (srvc->pass_cmd) { > FILE *fp; > int ret; > @@ -2245,6 +2439,9 @@ imap_parse_store( conffile_t *cfg, store_conf_t > **storep ) > */ > server->require_ssl = 1; > server->sconf.use_tlsv1 = 1; > +# ifdef HAVE_LIBGSSAPI > + server->sconf.use_gssapi = 0; > it would seem to me that this should be on by default and be used (according to some preference rules) when the server announces support. > +# endif > #endif > server->max_in_progress = INT_MAX; > > @@ -2306,6 +2503,10 @@ imap_parse_store( conffile_t *cfg, store_conf_t > **storep ) > else if (!strcasecmp( "RequireCRAM", cfg->cmd )) > server->require_cram = parse_bool( cfg ); > #endif > +#ifdef HAVE_LIBGSSAPI > + else if (!strcasecmp( "UseGSSAPI", cfg->cmd )) > + server->sconf.use_gssapi = parse_bool( cfg ); > +#endif > else if (!strcasecmp( "Tunnel", cfg->cmd )) > server->sconf.tunnel = nfstrdup( cfg->val ); > else if (store) { > diff --git a/src/socket.h b/src/socket.h > index 1545b39..1598a0e 100644 > --- a/src/socket.h > +++ b/src/socket.h > @@ -41,6 +41,9 @@ typedef struct server_conf { > char ssl_ctx_valid; > unsigned num_trusted; > SSL_CTX *SSLContext; > +# ifdef HAVE_LIBGSSAPI > + char use_gssapi; > +# endif > #endif > } server_conf_t; > > diff --git a/src/util.c b/src/util.c > index c76916b..12a1073 100644 > --- a/src/util.c > +++ b/src/util.c > @@ -713,6 +713,26 @@ event_wait( void ) > #endif > } > > +#if HAVE_LIBSSL && HAVE_LIBGSSAPI > +#include <openssl/evp.h> > + see the bottom of socket.c. it may be worth factoring all that stuff out to imap_auth.c. > +int from_base64( char *out, const char *in, const int inlen ) > +{ > + int len; > + > + len = EVP_DecodeBlock( (unsigned char *)out, (unsigned char *)in, inlen > ); > + if (inlen > 2) { > + if (in[inlen - 1] == '=') { > + len--; > + if (in[inlen - 2] == '=') > + len--; > + } > + } > + > + return len; > +} > +#endif > + > void > main_loop( void ) > { > -- > 1.9.3 > ------------------------------------------------------------------------------ HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems _______________________________________________ isync-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/isync-devel
