mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-18 11:05:48 +08:00
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:
parent
b2432fdbf2
commit
f7484f78e6
@ -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@
|
||||
|
56
configure.in
56
configure.in
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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... */
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user