ITS#5369 SASL/GSSAPi refactoring from Stefan Metzmacher <metze@samba.org>

and Rafal Szczeniak <mimir@samba.org>, with minor cleanups
This commit is contained in:
Howard Chu 2008-10-09 10:51:28 +00:00
parent b2432fdbf2
commit f7484f78e6
18 changed files with 607 additions and 295 deletions

View File

@ -186,9 +186,10 @@ KRB4_LIBS = @KRB4_LIBS@
KRB5_LIBS = @KRB5_LIBS@
KRB_LIBS = @KRB4_LIBS@ @KRB5_LIBS@
SASL_LIBS = @SASL_LIBS@
GSSAPI_LIBS = @GSSAPI_LIBS@
TLS_LIBS = @TLS_LIBS@
AUTH_LIBS = @AUTH_LIBS@
SECURITY_LIBS = $(SASL_LIBS) $(KRB_LIBS) $(TLS_LIBS) $(AUTH_LIBS)
SECURITY_LIBS = $(SASL_LIBS) $(KRB_LIBS) $(GSSAPI_LIBS) $(TLS_LIBS) $(AUTH_LIBS)
ICU_LIBS = @ICU_LIBS@
MODULES_CPPFLAGS = @SLAPD_MODULES_CPPFLAGS@

View File

@ -242,6 +242,8 @@ OL_ARG_WITH(cyrus_sasl,[ --with-cyrus-sasl with Cyrus SASL support],
auto, [auto yes no] )
OL_ARG_WITH(fetch,[ --with-fetch with fetch(3) URL support],
auto, [auto yes no] )
OL_ARG_WITH(gssapi,[ --with-gssapi with GSSAPI support],
auto, [auto yes no] )
OL_ARG_WITH(threads,[ --with-threads with threads],
auto, [auto nt posix mach pth lwp yes no manual] )
OL_ARG_WITH(tls,[ --with-tls with TLS/SSL support auto|openssl|gnutls],
@ -576,6 +578,7 @@ SLAPD_SQL_INCLUDES=
KRB4_LIBS=
KRB5_LIBS=
SASL_LIBS=
GSSAPI_LIBS=
TLS_LIBS=
MODULES_LIBS=
SLAPI_LIBS=
@ -1120,6 +1123,58 @@ if test $ol_enable_local != no ; then
fi
fi
dnl ----------------------------------------------------------------
dnl GSSAPI
ol_link_gssapi=no
case $ol_with_gssapi in yes | auto)
ol_header_gssapi=no
AC_CHECK_HEADERS(gssapi/gssapi.h)
if test $ac_cv_header_gssapi_gssapi_h = yes ; then
ol_header_gssapi=yes
else
AC_CHECK_HEADERS(gssapi.h)
if test $ac_cv_header_gssapi_h = yes ; then
ol_header_gssapi=yes
fi
dnl## not every gssapi has gss_oid_to_str()
dnl## as it's not defined in the GSSAPI V2 API
dnl## anymore
saveLIBS="$LIBS"
LIBS="$LIBS $GSSAPI_LIBS"
AC_CHECK_FUNCS(gss_oid_to_str)
LIBS="$saveLIBS"
fi
if test $ol_header_gssapi = yes ; then
dnl## we check for gss_wrap
dnl## as it's new to the GSSAPI V2 API
AC_CHECK_LIB(gssapi, gss_wrap,
[ol_link_gssapi=yes;GSSAPI_LIBS="-lgssapi"],
[ol_link_gssapi=no])
if test $ol_link_gssapi != yes ; then
AC_CHECK_LIB(gssapi_krb5, gss_wrap,
[ol_link_gssapi=yes;GSSAPI_LIBS="-lgssapi_krb5"],
[ol_link_gssapi=no])
fi
fi
;;
esac
WITH_GSSAPI=no
if test $ol_link_gssapi = yes; then
AC_DEFINE(HAVE_GSSAPI, 1, [define if you have GSSAPI])
WITH_GSSAPI=yes
elif test $ol_with_gssapi = auto ; then
AC_MSG_WARN([Could not locate GSSAPI package])
AC_MSG_WARN([GSSAPI authentication not supported!])
elif test $ol_with_gssapi = yes ; then
AC_MSG_ERROR([GSSAPI detection failed])
fi
dnl ----------------------------------------------------------------
dnl TLS/SSL
@ -3048,6 +3103,7 @@ AC_SUBST(MOD_PERL_LDFLAGS)
AC_SUBST(KRB4_LIBS)
AC_SUBST(KRB5_LIBS)
AC_SUBST(SASL_LIBS)
AC_SUBST(GSSAPI_LIBS)
AC_SUBST(TLS_LIBS)
AC_SUBST(MODULES_LIBS)
AC_SUBST(SLAPI_LIBS)

View File

@ -272,6 +272,22 @@ description). The default is
specifies the maximum security layer receive buffer
size allowed. 0 disables security layers. The default is 65536.
.RE
.SH GSSAPI OPTIONS
If OpenLDAP is built with Generic Security Services Application Programming Interface support,
there are more options you can specify.
.TP
.B GSSAPI_SIGN <on/true/yes/off/false/no>
Specifies if GSSAPI signing (GSS_C_INTEG_FLAG) should be used.
The default is off.
.TP
.B GSSAPI_ENCRYPT <on/true/yes/off/false/no>
Specifies if GSSAPI encryption (GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG)
should be used. The default is off.
.TP
.B GSSAPI_ALLOW_REMOTE_PRINCIPAL <on/true/yes/off/false/no>
Specifies if GSSAPI based authentification should try to form the
target principal name out of the ldapServiceName or dnsHostName
attribute of the targets RootDSE entry. The default is off.
.SH TLS OPTIONS
If OpenLDAP is built with Transport Layer Security support, there
are more options you can specify. These options are used when an

View File

@ -108,6 +108,17 @@ LDAP_BEGIN_DECL
#define LDAP_OPT_ERROR_STRING LDAP_OPT_DIAGNOSTIC_MESSAGE
#define LDAP_OPT_MATCHED_DN 0x0033
/* 0x0034 - 0x3fff not defined */
/* 0x0091 used by Microsoft for LDAP_OPT_AUTO_RECONNECT */
#define LDAP_OPT_SSPI_FLAGS 0x0092
/* 0x0093 used by Microsoft for LDAP_OPT_SSL_INFO */
/* 0x0094 used by Microsoft for LDAP_OPT_REF_DEREF_CONN_PER_MSG */
#define LDAP_OPT_SIGN 0x0095
#define LDAP_OPT_ENCRYPT 0x0096
#define LDAP_OPT_SASL_METHOD 0x0097
/* 0x0098 used by Microsoft for LDAP_OPT_AREC_EXCLUSIVE */
#define LDAP_OPT_SECURITY_CONTEXT 0x0099
/* 0x009A used by Microsoft for LDAP_OPT_ROOTDSE_CACHE */
/* 0x009B - 0x3fff not defined */
/* API Extensions */
#define LDAP_OPT_API_EXTENSION_BASE 0x4000 /* API extensions */
@ -167,6 +178,11 @@ LDAP_BEGIN_DECL
#define LDAP_OPT_X_SASL_MAXBUFSIZE 0x6109
#define LDAP_OPT_X_SASL_MECHLIST 0x610a /* read-only */
/* OpenLDAP GSSAPI options */
#define LDAP_OPT_X_GSSAPI_DO_NOT_FREE_CONTEXT 0x6200
#define LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL 0x6201
/* Private API Extensions -- reserved for application use */
#define LDAP_OPT_PRIVATE_EXTENSION_BASE 0x7000 /* Private API inclusive */
@ -482,6 +498,8 @@ typedef struct ldapcontrol {
#define LDAP_AUTH_KRBV41 ((ber_tag_t) 0x81U) /* context specific + primitive */
#define LDAP_AUTH_KRBV42 ((ber_tag_t) 0x82U) /* context specific + primitive */
/* used by the Windows API but not used on the wire */
#define LDAP_AUTH_NEGOTIATE ((ber_tag_t) 0x04FFU)
/* filter types */
#define LDAP_FILTER_AND ((ber_tag_t) 0xa0U) /* context specific + constructed */

View File

@ -21,6 +21,7 @@
#define _LDAP_PVT_H 1
#include <lber.h> /* get ber_slen_t */
#include <lber_pvt.h> /* get Sockbuf_Buf */
LDAP_BEGIN_DECL
@ -217,12 +218,52 @@ LDAP_F (void *) ldap_pvt_sasl_mutex_new LDAP_P((void));
LDAP_F (int) ldap_pvt_sasl_mutex_lock LDAP_P((void *mutex));
LDAP_F (int) ldap_pvt_sasl_mutex_unlock LDAP_P((void *mutex));
LDAP_F (void) ldap_pvt_sasl_mutex_dispose LDAP_P((void *mutex));
#endif /* HAVE_CYRUS_SASL */
struct sockbuf; /* avoid pulling in <lber.h> */
LDAP_F (int) ldap_pvt_sasl_install LDAP_P(( struct sockbuf *, void * ));
LDAP_F (void) ldap_pvt_sasl_remove LDAP_P(( struct sockbuf * ));
#endif /* HAVE_CYRUS_SASL */
/*
* SASL encryption support for LBER Sockbufs
*/
struct sb_sasl_generic_data;
struct sb_sasl_generic_ops {
void (*init)(struct sb_sasl_generic_data *p,
ber_len_t *min_send,
ber_len_t *max_send,
ber_len_t *max_recv);
ber_int_t (*encode)(struct sb_sasl_generic_data *p,
unsigned char *buf,
ber_len_t len,
Sockbuf_Buf *dst);
ber_int_t (*decode)(struct sb_sasl_generic_data *p,
const Sockbuf_Buf *src,
Sockbuf_Buf *dst);
void (*reset_buf)(struct sb_sasl_generic_data *p,
Sockbuf_Buf *buf);
void (*fini)(struct sb_sasl_generic_data *p);
};
struct sb_sasl_generic_install {
const struct sb_sasl_generic_ops *ops;
void *ops_private;
};
struct sb_sasl_generic_data {
const struct sb_sasl_generic_ops *ops;
void *ops_private;
Sockbuf_IO_Desc *sbiod;
ber_len_t min_send;
ber_len_t max_send;
ber_len_t max_recv;
Sockbuf_Buf sec_buf_in;
Sockbuf_Buf buf_in;
Sockbuf_Buf buf_out;
};
#ifndef LDAP_PVT_SASL_LOCAL_SSF
#define LDAP_PVT_SASL_LOCAL_SSF 71 /* SSF for Unix Domain Sockets */
#endif /* ! LDAP_PVT_SASL_LOCAL_SSF */

View File

@ -250,6 +250,18 @@
/* Define to 1 if you have the <grp.h> header file. */
#undef HAVE_GRP_H
/* define if you have GSSAPI */
#undef HAVE_GSSAPI
/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
#undef HAVE_GSSAPI_GSSAPI_H
/* Define to 1 if you have the <gssapi.h> header file. */
#undef HAVE_GSSAPI_H
/* Define to 1 if you have the `gss_oid_to_str' function. */
#undef HAVE_GSS_OID_TO_STR
/* Define to 1 if you have the `hstrerror' function. */
#undef HAVE_HSTRERROR

View File

@ -20,7 +20,7 @@ PROGRAMS = apitest dntest ftest ltest urltest
SRCS = bind.c open.c result.c error.c compare.c search.c \
controls.c messages.c references.c extended.c cyrus.c \
modify.c add.c modrdn.c delete.c abandon.c \
sasl.c sbind.c unbind.c cancel.c \
sasl.c gssapi.c sbind.c unbind.c cancel.c \
filter.c free.c sort.c passwd.c whoami.c \
getdn.c getentry.c getattr.c getvalues.c addentry.c \
request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
@ -32,7 +32,7 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \
OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \
controls.lo messages.lo references.lo extended.lo cyrus.lo \
modify.lo add.lo modrdn.lo delete.lo abandon.lo \
sasl.lo sbind.lo unbind.lo cancel.lo \
sasl.lo gssapi.lo sbind.lo unbind.lo cancel.lo \
filter.lo free.lo sort.lo passwd.lo whoami.lo \
getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \

View File

@ -71,6 +71,11 @@ ldap_bind( LDAP *ld, LDAP_CONST char *dn, LDAP_CONST char *passwd, int authmetho
case LDAP_AUTH_SIMPLE:
return( ldap_simple_bind( ld, dn, passwd ) );
#ifdef HAVE_GSSAPI
case LDAP_AUTH_NEGOTIATE:
return( ldap_gssapi_bind_s( ld, dn, passwd) );
#endif
case LDAP_AUTH_SASL:
/* user must use ldap_sasl_bind */
/* FALL-THRU */
@ -107,6 +112,11 @@ ldap_bind_s(
case LDAP_AUTH_SIMPLE:
return( ldap_simple_bind_s( ld, dn, passwd ) );
#ifdef HAVE_GSSAPI
case LDAP_AUTH_NEGOTIATE:
return( ldap_gssapi_bind_s( ld, dn, passwd) );
#endif
case LDAP_AUTH_SASL:
/* user must use ldap_sasl_bind */
/* FALL-THRU */

View File

@ -133,53 +133,97 @@ int ldap_int_sasl_init( void )
return -1;
}
/*
* SASL encryption support for LBER Sockbufs
*/
struct sb_sasl_data {
sasl_conn_t *sasl_context;
unsigned *sasl_maxbuf;
Sockbuf_Buf sec_buf_in;
Sockbuf_Buf buf_in;
Sockbuf_Buf buf_out;
};
static int
sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
static void
sb_sasl_cyrus_init(
struct sb_sasl_generic_data *p,
ber_len_t *min_send,
ber_len_t *max_send,
ber_len_t *max_recv)
{
struct sb_sasl_data *p;
sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
ber_len_t maxbuf;
assert( sbiod != NULL );
sasl_getprop( sasl_context, SASL_MAXOUTBUF,
(SASL_CONST void **)(char *) &maxbuf );
p = LBER_MALLOC( sizeof( *p ) );
if ( p == NULL )
return -1;
p->sasl_context = (sasl_conn_t *)arg;
ber_pvt_sb_buf_init( &p->sec_buf_in );
ber_pvt_sb_buf_init( &p->buf_in );
ber_pvt_sb_buf_init( &p->buf_out );
if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, SASL_MIN_BUFF_SIZE ) < 0 ) {
LBER_FREE( p );
sock_errset(ENOMEM);
*min_send = SASL_MIN_BUFF_SIZE;
*max_send = maxbuf;
*max_recv = SASL_MAX_BUFF_SIZE;
}
static ber_int_t
sb_sasl_cyrus_encode(
struct sb_sasl_generic_data *p,
unsigned char *buf,
ber_len_t len,
Sockbuf_Buf *dst)
{
sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
ber_int_t ret;
unsigned tmpsize = dst->buf_size;
ret = sasl_encode( sasl_context, buf, len,
(SASL_CONST char **)&dst->buf_base,
&tmpsize );
dst->buf_size = tmpsize;
dst->buf_end = dst->buf_size;
if ( ret != SASL_OK ) {
ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
"sb_sasl_cyrus_encode: failed to encode packet: %s\n",
sasl_errstring( ret, NULL, NULL ) );
return -1;
}
sasl_getprop( p->sasl_context, SASL_MAXOUTBUF,
(SASL_CONST void **)(char *) &p->sasl_maxbuf );
sbiod->sbiod_pvt = p;
return 0;
}
static int
sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
static ber_int_t
sb_sasl_cyrus_decode(
struct sb_sasl_generic_data *p,
const Sockbuf_Buf *src,
Sockbuf_Buf *dst)
{
struct sb_sasl_data *p;
sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
ber_int_t ret;
unsigned tmpsize = dst->buf_size;
assert( sbiod != NULL );
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
ret = sasl_decode( sasl_context,
src->buf_base, src->buf_end,
(SASL_CONST char **)&dst->buf_base,
(unsigned *)&tmpsize );
dst->buf_size = tmpsize;
dst->buf_end = dst->buf_size;
if ( ret != SASL_OK ) {
ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
"sb_sasl_cyrus_decode: failed to decode packet: %s\n",
sasl_errstring( ret, NULL, NULL ) );
return -1;
}
return 0;
}
static void
sb_sasl_cyrus_reset_buf(
struct sb_sasl_generic_data *p,
Sockbuf_Buf *buf)
{
#if SASL_VERSION_MAJOR >= 2
ber_pvt_sb_buf_init( buf );
#else
ber_pvt_sb_buf_destroy( buf );
#endif
}
static void
sb_sasl_cyrus_fini(
struct sb_sasl_generic_data *p)
{
#if SASL_VERSION_MAJOR >= 2
/*
* SASLv2 encode/decode buffers are managed by
@ -188,266 +232,29 @@ sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
p->buf_in.buf_base = NULL;
p->buf_out.buf_base = NULL;
#endif
ber_pvt_sb_buf_destroy( &p->sec_buf_in );
ber_pvt_sb_buf_destroy( &p->buf_in );
ber_pvt_sb_buf_destroy( &p->buf_out );
LBER_FREE( p );
sbiod->sbiod_pvt = NULL;
return 0;
}
static ber_len_t
sb_sasl_pkt_length( const unsigned char *buf, int debuglevel )
{
ber_len_t size;
assert( buf != NULL );
size = buf[0] << 24
| buf[1] << 16
| buf[2] << 8
| buf[3];
if ( size > SASL_MAX_BUFF_SIZE ) {
/* somebody is trying to mess me up. */
ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
"sb_sasl_pkt_length: received illegal packet length "
"of %lu bytes\n", (unsigned long)size );
size = 16; /* this should lead to an error. */
}
return size + 4; /* include the size !!! */
}
/* Drop a processed packet from the input buffer */
static void
sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel )
{
ber_slen_t len;
len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
if ( len > 0 )
AC_MEMCPY( sec_buf_in->buf_base, sec_buf_in->buf_base +
sec_buf_in->buf_end, len );
if ( len >= 4 ) {
sec_buf_in->buf_end = sb_sasl_pkt_length(
(unsigned char *) sec_buf_in->buf_base, debuglevel);
}
else {
sec_buf_in->buf_end = 0;
}
sec_buf_in->buf_ptr = len;
}
static ber_slen_t
sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
struct sb_sasl_data *p;
ber_slen_t ret, bufptr;
assert( sbiod != NULL );
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
/* Are there anything left in the buffer? */
ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
bufptr = ret;
len -= ret;
if ( len == 0 )
return bufptr;
#if SASL_VERSION_MAJOR >= 2
ber_pvt_sb_buf_init( &p->buf_in );
#else
ber_pvt_sb_buf_destroy( &p->buf_in );
#endif
/* Read the length of the packet */
while ( p->sec_buf_in.buf_ptr < 4 ) {
ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
p->sec_buf_in.buf_ptr,
4 - p->sec_buf_in.buf_ptr );
#ifdef EINTR
if ( ( ret < 0 ) && ( errno == EINTR ) )
continue;
#endif
if ( ret <= 0 )
return bufptr ? bufptr : ret;
p->sec_buf_in.buf_ptr += ret;
}
/* The new packet always starts at p->sec_buf_in.buf_base */
ret = sb_sasl_pkt_length( (unsigned char *) p->sec_buf_in.buf_base,
sbiod->sbiod_sb->sb_debug );
/* Grow the packet buffer if neccessary */
if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) &&
ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
{
sock_errset(ENOMEM);
return -1;
}
p->sec_buf_in.buf_end = ret;
/* Did we read the whole encrypted packet? */
while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
/* No, we have got only a part of it */
ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
p->sec_buf_in.buf_ptr, ret );
#ifdef EINTR
if ( ( ret < 0 ) && ( errno == EINTR ) )
continue;
#endif
if ( ret <= 0 )
return bufptr ? bufptr : ret;
p->sec_buf_in.buf_ptr += ret;
}
/* Decode the packet */
{
unsigned tmpsize = p->buf_in.buf_end;
ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
p->sec_buf_in.buf_end,
(SASL_CONST char **)&p->buf_in.buf_base,
(unsigned *)&tmpsize );
p->buf_in.buf_end = tmpsize;
}
/* Drop the packet from the input buffer */
sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
if ( ret != SASL_OK ) {
ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
"sb_sasl_read: failed to decode packet: %s\n",
sasl_errstring( ret, NULL, NULL ) );
sock_errset(EIO);
return -1;
}
p->buf_in.buf_size = p->buf_in.buf_end;
bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
return bufptr;
}
static ber_slen_t
sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
struct sb_sasl_data *p;
int ret;
assert( sbiod != NULL );
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
/* Are there anything left in the buffer? */
if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
if ( ret < 0 ) return ret;
/* Still have something left?? */
if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
sock_errset(EAGAIN);
return -1;
}
}
/* now encode the next packet. */
#if SASL_VERSION_MAJOR >= 2
ber_pvt_sb_buf_init( &p->buf_out );
#else
ber_pvt_sb_buf_destroy( &p->buf_out );
#endif
if ( len > *p->sasl_maxbuf - 100 ) {
len = *p->sasl_maxbuf - 100; /* For safety margin */
}
{
unsigned tmpsize = p->buf_out.buf_size;
ret = sasl_encode( p->sasl_context, buf, len,
(SASL_CONST char **)&p->buf_out.buf_base,
&tmpsize );
p->buf_out.buf_size = tmpsize;
}
if ( ret != SASL_OK ) {
ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
"sb_sasl_write: failed to encode packet: %s\n",
sasl_errstring( ret, NULL, NULL ) );
sock_errset(EIO);
return -1;
}
p->buf_out.buf_end = p->buf_out.buf_size;
ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
/* return number of bytes encoded, not written, to ensure
* no byte is encoded twice (even if only sent once).
*/
return len;
}
static int
sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
{
struct sb_sasl_data *p;
p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
if ( opt == LBER_SB_OPT_DATA_READY ) {
if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1;
}
return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
}
Sockbuf_IO ldap_pvt_sockbuf_io_sasl = {
sb_sasl_setup, /* sbi_setup */
sb_sasl_remove, /* sbi_remove */
sb_sasl_ctrl, /* sbi_ctrl */
sb_sasl_read, /* sbi_read */
sb_sasl_write, /* sbi_write */
NULL /* sbi_close */
};
static const struct sb_sasl_generic_ops sb_sasl_cyrus_ops = {
sb_sasl_cyrus_init,
sb_sasl_cyrus_encode,
sb_sasl_cyrus_decode,
sb_sasl_cyrus_reset_buf,
sb_sasl_cyrus_fini
};
int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
{
Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
0, 0, 0 );
struct sb_sasl_generic_install install_arg;
/* don't install the stuff unless security has been negotiated */
install_arg.ops = &sb_sasl_cyrus_ops;
install_arg.ops_private = ctx_arg;
if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
&ldap_pvt_sockbuf_io_sasl ) )
{
#ifdef LDAP_DEBUG
ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" );
#endif
ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
}
return LDAP_SUCCESS;
return ldap_pvt_sasl_generic_install( sb, &install_arg );
}
void ldap_pvt_sasl_remove( Sockbuf *sb )
{
ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl,
LBER_SBIOD_LEVEL_APPLICATION );
#ifdef LDAP_DEBUG
ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
LBER_SBIOD_LEVEL_APPLICATION );
#endif
ldap_pvt_sasl_generic_remove( sb );
}
static int
@ -1126,7 +933,7 @@ ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
if ( option == LDAP_OPT_X_SASL_MECHLIST ) {
if ( ldap_int_sasl_init() )
return -1;
*(char ***)arg = sasl_global_listmech();
*(char ***)arg = (char **)sasl_global_listmech();
return 0;
}

View File

@ -47,6 +47,8 @@ struct ldapoptions ldap_int_global_options =
#define ATTR_OPT_TV 8
#define ATTR_OPT_INT 9
#define ATTR_GSSAPI 10
struct ol_keyvalue {
const char * key;
int value;
@ -102,6 +104,12 @@ static const struct ol_attribute {
{0, ATTR_SASL, "SASL_SECPROPS", NULL, LDAP_OPT_X_SASL_SECPROPS},
#endif
#ifdef HAVE_GSSAPI
{0, ATTR_GSSAPI,"GSSAPI_SIGN", NULL, LDAP_OPT_SIGN},
{0, ATTR_GSSAPI,"GSSAPI_ENCRYPT", NULL, LDAP_OPT_ENCRYPT},
{0, ATTR_GSSAPI,"GSSAPI_ALLOW_REMOTE_PRINCIPAL",NULL, LDAP_OPT_X_GSSAPI_ALLOW_REMOTE_PRINCIPAL},
#endif
#ifdef HAVE_TLS
{1, ATTR_TLS, "TLS_CERT", NULL, LDAP_OPT_X_TLS_CERTFILE},
{1, ATTR_TLS, "TLS_KEY", NULL, LDAP_OPT_X_TLS_KEYFILE},
@ -123,7 +131,7 @@ static const struct ol_attribute {
{0, ATTR_NONE, NULL, NULL, 0}
};
#define MAX_LDAP_ATTR_LEN sizeof("TLS_CIPHER_SUITE")
#define MAX_LDAP_ATTR_LEN sizeof("GSSAPI_ALLOW_REMOTE_PRINCIPAL")
#define MAX_LDAP_ENV_PREFIX_LEN 8
static void openldap_ldap_init_w_conf(
@ -252,6 +260,11 @@ static void openldap_ldap_init_w_conf(
case ATTR_SASL:
#ifdef HAVE_CYRUS_SASL
ldap_int_sasl_config( gopts, attrs[i].offset, opt );
#endif
break;
case ATTR_GSSAPI:
#ifdef HAVE_GSSAPI
ldap_int_gssapi_config( gopts, attrs[i].offset, opt );
#endif
break;
case ATTR_TLS:

View File

@ -228,6 +228,15 @@ struct ldapoptions {
struct sasl_security_properties ldo_sasl_secprops;
#endif
#ifdef HAVE_GSSAPI
unsigned gssapi_flags;
unsigned ldo_gssapi_flags;
#define LDAP_GSSAPI_OPT_DO_NOT_FREE_GSS_CONTEXT 0x0001
#define LDAP_GSSAPI_OPT_ALLOW_REMOTE_PRINCIPAL 0x0002
unsigned ldo_gssapi_options;
#endif
int ldo_refhoplimit; /* limit on referral nesting */
/* LDAPv3 server and client controls */
@ -257,6 +266,9 @@ typedef struct ldap_conn {
#ifdef HAVE_CYRUS_SASL
void *lconn_sasl_authctx; /* context for bind */
void *lconn_sasl_sockctx; /* for security layer */
#endif
#ifdef HAVE_GSSAPI
void *lconn_gss_ctx; /* gss_ctx_id_t */
#endif
int lconn_refcnt;
time_t lconn_created; /* time */
@ -402,6 +414,9 @@ LDAP_V ( ldap_pvt_thread_mutex_t ) ldap_int_resolv_mutex;
#ifdef HAVE_CYRUS_SASL
LDAP_V( ldap_pvt_thread_mutex_t ) ldap_int_sasl_mutex;
#endif
#ifdef HAVE_GSSAPI
LDAP_V( ldap_pvt_thread_mutex_t ) ldap_int_gssapi_mutex;
#endif
#endif
#ifdef LDAP_R_COMPILE

View File

@ -353,6 +353,11 @@ ldap_get_option(
if ( ldap_int_sasl_get_option( ld, option, outvalue ) == 0 ) {
return LDAP_OPT_SUCCESS;
}
#endif
#ifdef HAVE_GSSAPI
if ( ldap_int_gssapi_get_option( ld, option, outvalue ) == 0 ) {
return LDAP_OPT_SUCCESS;
}
#endif
/* bad param */
break;
@ -690,6 +695,10 @@ ldap_set_option(
#ifdef HAVE_CYRUS_SASL
if ( ldap_int_sasl_set_option( ld, option, (void *)invalue ) == 0 )
return LDAP_OPT_SUCCESS;
#endif
#ifdef HAVE_GSSAPI
if ( ldap_int_gssapi_set_option( ld, option, (void *)invalue ) == 0 )
return LDAP_OPT_SUCCESS;
#endif
/* bad param */
return LDAP_OPT_ERROR;

View File

@ -207,7 +207,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s)
== AC_SOCKET_ERROR )
{
/* XXX: needs to be replace with ber_stream_read() */
read(s, &ch, 1);
int rc = read(s, &ch, 1);
TRACE;
return -1;
}

View File

@ -149,7 +149,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s)
== AC_SOCKET_ERROR )
{
/* XXX: needs to be replace with ber_stream_read() */
read(s, &ch, 1);
int rc = read(s, &ch, 1);
TRACE;
return -1;
}

View File

@ -736,6 +736,9 @@ ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
}
ldap_int_sasl_close( ld, lc );
#ifdef HAVE_GSSAPI
ldap_int_gssapi_close( ld, lc );
#endif
ldap_free_urllist( lc->lconn_server );

View File

@ -473,3 +473,311 @@ done:
return rc;
}
#ifdef HAVE_CYRUS_SASL
#ifdef HAVE_SASL_SASL_H
#include <sasl/sasl.h>
#else
#include <sasl.h>
#endif
#if SASL_VERSION_MAJOR >= 2
#define SASL_CONST const
#else
#define SASL_CONST
#endif
#endif /* HAVE_CYRUS_SASL */
static int
sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod );
static int
sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg )
{
struct sb_sasl_generic_data *p;
struct sb_sasl_generic_install *i;
assert( sbiod != NULL );
i = (struct sb_sasl_generic_install *)arg;
p = LBER_MALLOC( sizeof( *p ) );
if ( p == NULL )
return -1;
p->ops = i->ops;
p->ops_private = i->ops_private;
p->sbiod = sbiod;
ber_pvt_sb_buf_init( &p->sec_buf_in );
ber_pvt_sb_buf_init( &p->buf_in );
ber_pvt_sb_buf_init( &p->buf_out );
sbiod->sbiod_pvt = p;
p->ops->init( p, &p->min_send, &p->max_send, &p->max_recv );
if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, p->min_send ) < 0 ) {
sb_sasl_generic_remove( sbiod );
sock_errset(ENOMEM);
return -1;
}
return 0;
}
static int
sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod )
{
struct sb_sasl_generic_data *p;
assert( sbiod != NULL );
p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
p->ops->fini(p);
ber_pvt_sb_buf_destroy( &p->sec_buf_in );
ber_pvt_sb_buf_destroy( &p->buf_in );
ber_pvt_sb_buf_destroy( &p->buf_out );
LBER_FREE( p );
sbiod->sbiod_pvt = NULL;
return 0;
}
static ber_len_t
sb_sasl_generic_pkt_length(
struct sb_sasl_generic_data *p,
const unsigned char *buf,
int debuglevel )
{
ber_len_t size;
assert( buf != NULL );
size = buf[0] << 24
| buf[1] << 16
| buf[2] << 8
| buf[3];
if ( size > p->max_recv ) {
/* somebody is trying to mess me up. */
ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
"sb_sasl_generic_pkt_length: "
"received illegal packet length of %lu bytes\n",
(unsigned long)size );
size = 16; /* this should lead to an error. */
}
return size + 4; /* include the size !!! */
}
/* Drop a processed packet from the input buffer */
static void
sb_sasl_generic_drop_packet (
struct sb_sasl_generic_data *p,
int debuglevel )
{
ber_slen_t len;
len = p->sec_buf_in.buf_ptr - p->sec_buf_in.buf_end;
if ( len > 0 )
AC_MEMCPY( p->sec_buf_in.buf_base, p->sec_buf_in.buf_base +
p->sec_buf_in.buf_end, len );
if ( len >= 4 ) {
p->sec_buf_in.buf_end = sb_sasl_generic_pkt_length(p,
(unsigned char *) p->sec_buf_in.buf_base, debuglevel);
}
else {
p->sec_buf_in.buf_end = 0;
}
p->sec_buf_in.buf_ptr = len;
}
static ber_slen_t
sb_sasl_generic_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
struct sb_sasl_generic_data *p;
ber_slen_t ret, bufptr;
assert( sbiod != NULL );
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
/* Are there anything left in the buffer? */
ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
bufptr = ret;
len -= ret;
if ( len == 0 )
return bufptr;
p->ops->reset_buf( p, &p->buf_in );
/* Read the length of the packet */
while ( p->sec_buf_in.buf_ptr < 4 ) {
ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
p->sec_buf_in.buf_ptr,
4 - p->sec_buf_in.buf_ptr );
#ifdef EINTR
if ( ( ret < 0 ) && ( errno == EINTR ) )
continue;
#endif
if ( ret <= 0 )
return bufptr ? bufptr : ret;
p->sec_buf_in.buf_ptr += ret;
}
/* The new packet always starts at p->sec_buf_in.buf_base */
ret = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base,
sbiod->sbiod_sb->sb_debug );
/* Grow the packet buffer if neccessary */
if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) &&
ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
{
sock_errset(ENOMEM);
return -1;
}
p->sec_buf_in.buf_end = ret;
/* Did we read the whole encrypted packet? */
while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
/* No, we have got only a part of it */
ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
p->sec_buf_in.buf_ptr, ret );
#ifdef EINTR
if ( ( ret < 0 ) && ( errno == EINTR ) )
continue;
#endif
if ( ret <= 0 )
return bufptr ? bufptr : ret;
p->sec_buf_in.buf_ptr += ret;
}
/* Decode the packet */
ret = p->ops->decode( p, &p->sec_buf_in, &p->buf_in );
/* Drop the packet from the input buffer */
sb_sasl_generic_drop_packet( p, sbiod->sbiod_sb->sb_debug );
if ( ret != 0 ) {
ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
"sb_sasl_generic_read: failed to decode packet\n" );
sock_errset(EIO);
return -1;
}
bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
return bufptr;
}
static ber_slen_t
sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
struct sb_sasl_generic_data *p;
int ret;
assert( sbiod != NULL );
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
/* Are there anything left in the buffer? */
if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
if ( ret < 0 ) return ret;
/* Still have something left?? */
if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
sock_errset(EAGAIN);
return -1;
}
}
/* now encode the next packet. */
p->ops->reset_buf( p, &p->buf_out );
if ( len > p->max_send - 100 ) {
len = p->max_send - 100; /* For safety margin */
}
ret = p->ops->encode( p, buf, len, &p->buf_out );
if ( ret != 0 ) {
ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
"sb_sasl_generic_write: failed to encode packet\n" );
sock_errset(EIO);
return -1;
}
ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
/* return number of bytes encoded, not written, to ensure
* no byte is encoded twice (even if only sent once).
*/
return len;
}
static int
sb_sasl_generic_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
{
struct sb_sasl_generic_data *p;
p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
if ( opt == LBER_SB_OPT_DATA_READY ) {
if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1;
}
return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
}
Sockbuf_IO ldap_pvt_sockbuf_io_sasl_generic = {
sb_sasl_generic_setup, /* sbi_setup */
sb_sasl_generic_remove, /* sbi_remove */
sb_sasl_generic_ctrl, /* sbi_ctrl */
sb_sasl_generic_read, /* sbi_read */
sb_sasl_generic_write, /* sbi_write */
NULL /* sbi_close */
};
int ldap_pvt_sasl_generic_install(
Sockbuf *sb,
struct sb_sasl_generic_install *install_arg )
{
Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_generic_install\n",
0, 0, 0 );
/* don't install the stuff unless security has been negotiated */
if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
&ldap_pvt_sockbuf_io_sasl_generic ) )
{
#ifdef LDAP_DEBUG
ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_generic_" );
#endif
ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
LBER_SBIOD_LEVEL_APPLICATION, install_arg );
}
return LDAP_SUCCESS;
}
void ldap_pvt_sasl_generic_remove( Sockbuf *sb )
{
ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
LBER_SBIOD_LEVEL_APPLICATION );
#ifdef LDAP_DEBUG
ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
LBER_SBIOD_LEVEL_APPLICATION );
#endif
}

View File

@ -411,6 +411,9 @@ void ldap_int_utils_init( void )
#ifdef HAVE_CYRUS_SASL
ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex );
#endif
#ifdef HAVE_GSSAPI
ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
#endif
#endif
/* call other module init functions here... */

View File

@ -22,7 +22,7 @@ XXSRCS = apitest.c test.c \
bind.c open.c result.c error.c compare.c search.c \
controls.c messages.c references.c extended.c cyrus.c \
modify.c add.c modrdn.c delete.c abandon.c \
sasl.c sbind.c unbind.c cancel.c \
sasl.c gssapi.c sbind.c unbind.c cancel.c \
filter.c free.c sort.c passwd.c whoami.c \
getdn.c getentry.c getattr.c getvalues.c addentry.c \
request.c os-ip.c url.c pagectrl.c sortctrl.c vlvctrl.c \
@ -39,7 +39,7 @@ OBJS = threads.lo rdwr.lo rmutex.lo tpool.lo rq.lo \
bind.lo open.lo result.lo error.lo compare.lo search.lo \
controls.lo messages.lo references.lo extended.lo cyrus.lo \
modify.lo add.lo modrdn.lo delete.lo abandon.lo \
sasl.lo sbind.lo unbind.lo cancel.lo \
sasl.lo gssapi.lo sbind.lo unbind.lo cancel.lo \
filter.lo free.lo sort.lo passwd.lo whoami.lo \
getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \
request.lo os-ip.lo url.lo pagectrl.lo sortctrl.lo vlvctrl.lo \