From 9b4e3b2234b0d347c90dc09b1638e8e93497dae1 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Sun, 2 Jan 2000 01:21:25 +0000 Subject: [PATCH] Merged in preliminary support for Cyrus SASL library; support for DCE slash-delimited, left-to-right DNs; support for a domain socket transport (enable with --enable-ldapi); and extensions to URL parsing to support the latter transport. --- configure | 36 +- configure.in | 4 + include/ac/socket.h | 4 + include/ldap.h | 32 +- include/ldap_pvt.h | 7 + include/portable.h.in | 6 + libraries/libldap/Makefile.in | 4 +- libraries/libldap/getdn.c | 104 ++++- libraries/libldap/init.c | 4 + libraries/libldap/ldap-int.h | 22 +- libraries/libldap/open.c | 21 +- libraries/libldap/os-ip.c | 2 +- libraries/libldap/os-local.c | 219 +++++++++ libraries/libldap/request.c | 2 - libraries/libldap/sasl.c | 517 +++++++++++++++++++++- libraries/libldap/unbind.c | 6 + libraries/libldap/url.c | 73 ++- libraries/libldap_r/Makefile.in | 4 +- servers/slapd/back-ldbm/Makefile.in | 4 +- servers/slapd/back-ldbm/bind.c | 17 +- servers/slapd/back-ldbm/init.c | 6 + servers/slapd/back-ldbm/proto-back-ldbm.h | 24 + servers/slapd/back-ldbm/sasl.c | 59 +++ servers/slapd/bind.c | 13 +- servers/slapd/connection.c | 27 +- servers/slapd/daemon.c | 152 ++++++- servers/slapd/proto-slap.h | 9 + servers/slapd/sasl.c | 143 +++++- servers/slapd/slap.h | 18 + servers/slapd/tools/mimic.c | 15 + 30 files changed, 1458 insertions(+), 96 deletions(-) create mode 100644 libraries/libldap/os-local.c create mode 100644 servers/slapd/back-ldbm/sasl.c diff --git a/configure b/configure index 12be49680c..27d34f6d36 100755 --- a/configure +++ b/configure @@ -40,6 +40,8 @@ ac_help="$ac_help --enable-referrals enable V2 Referrals extension (yes)" ac_help="$ac_help --enable-cldap enable connectionless ldap (no)" +ac_help="$ac_help + --enable-ldapi enable domain socket (PF_LOCAL) transport (no)" ac_help="$ac_help --enable-x-compile enable cross compiling (no)" ac_help="$ac_help @@ -1305,6 +1307,26 @@ else ol_enable_cldap="no" fi # end --enable-cldap +# OpenLDAP --enable-ldapi + # Check whether --enable-ldapi or --disable-ldapi was given. +if test "${enable_ldapi+set}" = set; then + enableval="$enable_ldapi" + + ol_arg=invalid + for ol_val in auto yes no ; do + if test "$enableval" = "$ol_val" ; then + ol_arg="$ol_val" + fi + done + if test "$ol_arg" = "invalid" ; then + { echo "configure: error: bad value $enableval for --enable-ldapi" 1>&2; exit 1; } + fi + ol_enable_ldapi="$ol_arg" + +else + ol_enable_ldapi="no" +fi +# end --enable-ldapi # OpenLDAP --enable-x_compile # Check whether --enable-x_compile or --disable-x_compile was given. if test "${enable_x_compile+set}" = set; then @@ -1347,8 +1369,8 @@ else fi # end --enable-dmalloc -# OpenLDAP --with-cyrus_sasl - # Check whether --with-cyrus_sasl or --without-cyrus_sasl was given. +# OpenLDAP --with-cyrus-sasl + # Check whether --with-cyrus-sasl or --without-cyrus_sasl was given. if test "${with_cyrus_sasl+set}" = set; then withval="$with_cyrus_sasl" @@ -1359,14 +1381,14 @@ if test "${with_cyrus_sasl+set}" = set; then fi done if test "$ol_arg" = "invalid" ; then - { echo "configure: error: bad value $withval for --with-cyrus_sasl" 1>&2; exit 1; } + { echo "configure: error: bad value $withval for --with-cyrus-sasl" 1>&2; exit 1; } fi ol_with_cyrus_sasl="$ol_arg" else ol_with_cyrus_sasl="auto" fi -# end --with-cyrus_sasl +# end --with-cyrus-sasl # OpenLDAP --with-fetch # Check whether --with-fetch or --without-fetch was given. @@ -4601,6 +4623,7 @@ for ac_hdr in \ sys/resource.h \ sys/select.h \ sys/socket.h \ + sys/un.h \ sys/syslog.h \ sys/time.h \ sys/types.h \ @@ -14909,7 +14932,12 @@ if test "$ol_enable_cldap" != no ; then EOF fi +if test "$ol_enable_ldapi" != no ; then + cat >> confdefs.h <<\EOF +#define LDAP_PF_LOCAL 1 +EOF +fi if test "$ol_enable_crypt" != no ; then cat >> confdefs.h <<\EOF #define SLAPD_CRYPT 1 diff --git a/configure.in b/configure.in index 8b4439f8ed..75bbc1aeda 100644 --- a/configure.in +++ b/configure.in @@ -97,6 +97,7 @@ OL_ARG_ENABLE(cache,[ --enable-cache enable caching], yes)dnl OL_ARG_ENABLE(dns,[ --enable-dns enable V2 DX Referrals extension], no)dnl OL_ARG_ENABLE(referrals,[ --enable-referrals enable V2 Referrals extension], yes)dnl OL_ARG_ENABLE(cldap,[ --enable-cldap enable connectionless ldap], no)dnl +OL_ARG_ENABLE(ldapi,[ --enable-ldapi enable domain socket (PF_LOCAL) ldap], no)dnl OL_ARG_ENABLE(x_compile,[ --enable-x-compile enable cross compiling], no, [yes no])dnl @@ -2079,6 +2080,9 @@ fi if test "$ol_enable_cldap" != no ; then AC_DEFINE(LDAP_CONNECTIONLESS,1,[define to support CLDAP]) fi +if test "$ol_enable_ldapi" != no; then + AC_DEFINE(USE_PF_LOCAL,1,[define to support PF_LOCAL transport]) +fi if test "$ol_enable_crypt" != no ; then AC_DEFINE(SLAPD_CRYPT,1,[define to support crypt(3) passwords]) diff --git a/include/ac/socket.h b/include/ac/socket.h index 35c5ba3b35..5e20569f54 100644 --- a/include/ac/socket.h +++ b/include/ac/socket.h @@ -20,6 +20,10 @@ #ifdef HAVE_SYS_SOCKET_H #include +#ifdef HAVE_SYS_UN_H +#include +#endif + #ifdef HAVE_SYS_SELECT_H #include #endif diff --git a/include/ldap.h b/include/ldap.h index 57ee5715b4..d2f1a145e3 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -487,17 +487,27 @@ typedef struct ldap_friendly { * types for ldap URL handling */ typedef struct ldap_url_desc { - struct ldap_url_desc *lud_next; - int lud_ldaps; + struct ldap_url_desc *lud_next; + unsigned long lud_properties; + int lud_protocol; char *lud_host; int lud_port; char *lud_dn; char **lud_attrs; int lud_scope; char *lud_filter; - char **lud_exts; + char **lud_exts; } LDAPURLDesc; +/* lud_properties */ +#define LDAP_URL_USE_SSL 0x00000001 +#define LDAP_URL_USE_SSL_UNSPECIFIED 0x00000002 + +/* lud_protocol */ +#define LDAP_PROTO_TCP 0x00 +#define LDAP_PROTO_UDP 0x01 +#define LDAP_PROTO_LOCAL 0x02 + #define LDAP_URL_SUCCESS 0x00 /* Success */ #define LDAP_URL_ERR_MEM 0x01 /* can't allocate memory space */ #define LDAP_URL_ERR_PARAM 0x02 /* parameter is bad */ @@ -637,6 +647,17 @@ ldap_sasl_bind LDAP_P(( LDAPControl **clientctrls, int *msgidp )); +LIBLDAP_F( int ) +ldap_negotiated_sasl_bind_s LDAP_P(( + LDAP *ld, + LDAP_CONST char *dn, /* usually NULL */ + LDAP_CONST char *authorizationId, + LDAP_CONST char *authenticationId, /* usually NULL */ + LDAP_CONST char *saslMechanism, + struct berval *passPhrase, + LDAPControl **serverControls, + LDAPControl **clientControls )); + LIBLDAP_F( int ) ldap_sasl_bind_s LDAP_P(( LDAP *ld, @@ -1126,6 +1147,11 @@ LIBLDAP_F( int ) ldap_is_dns_dn LDAP_P(( /* deprecated */ LDAP_CONST char *dn )); +LIBLDAP_F( char * ) +ldap_dn2dcedn LDAP_P(( LDAP_CONST char *dn )); + +LIBLDAP_F( char * ) +ldap_dcedn2dn LDAP_P(( LDAP_CONST char *dce )); /* * in getattr.c diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h index 632652cd64..8e21b5df7d 100644 --- a/include/ldap_pvt.h +++ b/include/ldap_pvt.h @@ -100,6 +100,13 @@ LIBLDAP_F (int) ldap_pvt_unhex( int c ); #define LDAP_NEEDSESCAPE(c) ((c) == '\\' || (c) == '"') +#ifdef HAVE_CYRUS_SASL +/* sasl.c */ +LIBLDAP_F (int) ldap_pvt_sasl_init LDAP_P(( void )); /* clientside init */ +LIBLDAP_F (int) ldap_pvt_sasl_install LDAP_P(( Sockbuf *, void * )); +LIBLDAP_F (int) ldap_pvt_sasl_err2ldap LDAP_P(( int )); +#endif /* HAVE_CYRUS_SASL */ + /* search.c */ LIBLDAP_F( char * ) ldap_pvt_find_wildcard LDAP_P(( char *s )); diff --git a/include/portable.h.in b/include/portable.h.in index bff5d52a4b..7faa3ce316 100644 --- a/include/portable.h.in +++ b/include/portable.h.in @@ -531,6 +531,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define if you have the header file. */ +#undef HAVE_SYS_UN_H + /* Define if you have the header file. */ #undef HAVE_SYSEXITS_H @@ -834,6 +837,9 @@ /* define to support CLDAP */ #undef LDAP_CONNECTIONLESS +/* define to support domain sockets */ +#undef LDAP_PF_LOCAL + /* define to support crypt(3) passwords */ #undef SLAPD_CRYPT diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in index 764c29346e..43bd9e7161 100644 --- a/libraries/libldap/Makefile.in +++ b/libraries/libldap/Makefile.in @@ -17,7 +17,7 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \ getdn.c getentry.c getattr.c getvalues.c addentry.c \ request.c getdxbyname.c os-ip.c url.c charset.c \ init.c options.c print.c string.c util-int.c schema.c \ - charray.c digest.c tls.c dn.c + charray.c digest.c tls.c dn.c os-local.c OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ controls.lo messages.lo references.lo extended.lo \ modify.lo add.lo modrdn.lo delete.lo abandon.lo ufn.lo cache.lo \ @@ -26,7 +26,7 @@ OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ getdn.lo getentry.lo getattr.lo getvalues.lo addentry.lo \ request.lo getdxbyname.lo os-ip.lo url.lo charset.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ - charray.lo digest.lo tls.lo dn.lo + charray.lo digest.lo tls.lo dn.lo os-local.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index 0110e298e7..f03be3b455 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -23,6 +23,10 @@ #include "ldap-int.h" +#define DN_TYPE_LDAP_RDN 0 +#define DN_TYPE_LDAP_DN 1 +#define DN_TYPE_DCE_DN 2 + static char **explode_name( const char *name, int notypes, int is_dn ); char * @@ -180,14 +184,98 @@ ldap_explode_dn( LDAP_CONST char *dn, int notypes ) if ( ldap_is_dns_dn( dn ) ) { return( ldap_explode_dns( dn ) ); } - return explode_name( dn, notypes, 1 ); + return explode_name( dn, notypes, DN_TYPE_LDAP_DN ); } char ** ldap_explode_rdn( LDAP_CONST char *rdn, int notypes ) { Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 ); - return explode_name( rdn, notypes, 0 ); + return explode_name( rdn, notypes, DN_TYPE_LDAP_RDN ); +} + +char * +ldap_dn2dcedn( LDAP_CONST char *dn ) +{ + char *dce, *q, **rdns, **p; + int len = 0; + + Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 ); + + rdns = explode_name( dn, 0, DN_TYPE_LDAP_DN ); + if ( rdns == NULL ) { + return NULL; + } + + for ( p = rdns; *p != NULL; p++ ) { + len += strlen( *p ) + 1; + } + + q = dce = LDAP_MALLOC( len + 1 ); + if ( dce == NULL ) { + return NULL; + } + + p--; /* get back past NULL */ + + for ( ; p != rdns; p-- ) { + strcpy( q, "/" ); + q++; + strcpy( q, *p ); + q += strlen( *p ); + } + + strcpy( q, "/" ); + q++; + strcpy( q, *p ); + + return dce; +} + +char * +ldap_dcedn2dn( LDAP_CONST char *dce ) +{ + char *dn, *q, **rdns, **p; + int len; + + Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 ); + + rdns = explode_name( dce, 0, DN_TYPE_DCE_DN ); + if ( rdns == NULL ) { + return NULL; + } + + len = 0; + + for ( p = rdns; *p != NULL; p++ ) { + len += strlen( *p ) + 1; + } + + q = dn = LDAP_MALLOC( len ); + if ( dn == NULL ) { + return NULL; + } + + p--; + + for ( ; p != rdns; p-- ) { + strcpy( q, *p ); + q += strlen( *p ); + strcpy( q, "," ); + q++; + } + + if ( *dce == '/' ) { + /* the name was fully qualified, thus the most-significant + * RDN was empty. trash the last comma */ + q--; + *q = '\0'; + } else { + /* the name was relative. copy the most significant RDN */ + strcpy( q, *p ); + } + + return dn; } static char ** @@ -215,14 +303,18 @@ explode_name( const char *name, int notypes, int is_dn ) state = INQUOTE; break; case '+': - if (!is_dn) + if (is_dn == DN_TYPE_LDAP_RDN) + goto end_part; + break; + case '/': + if (is_dn == DN_TYPE_DCE_DN) goto end_part; break; case ';': case ',': - if (!is_dn) - break; - goto end_part; + if (is_dn == DN_TYPE_LDAP_DN) + goto end_part; + break; case '\0': end_part: if ( state == OUTQUOTE ) { diff --git a/libraries/libldap/init.c b/libraries/libldap/init.c index e7a8f0174b..5628eea1e7 100644 --- a/libraries/libldap/init.c +++ b/libraries/libldap/init.c @@ -343,6 +343,10 @@ void ldap_int_initialize( void ) ldap_pvt_tls_init(); #endif +#ifdef HAVE_CYRUS_SASL + ldap_pvt_sasl_init(); +#endif + if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 04c1b3147f..eca39c573f 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -30,12 +30,20 @@ #include "ldap_pvt.h" +#ifdef HAVE_CYRUS_SASL +#include +#endif /* HAVE_CYRUS_SASL */ + LDAP_BEGIN_DECL #define LDAP_URL_PREFIX "ldap://" #define LDAP_URL_PREFIX_LEN (sizeof(LDAP_URL_PREFIX)-1) #define LDAPS_URL_PREFIX "ldaps://" #define LDAPS_URL_PREFIX_LEN (sizeof(LDAPS_URL_PREFIX)-1) +#define LDAPI_URL_PREFIX "ldapi://" +#define LDAPI_URL_PREFIX_LEN (sizeof(LDAPI_URL_PREFIX)-1) +#define LDAPIS_URL_PREFIX "ldapis://" +#define LDAPIS_URL_PREFIX_LEN (sizeof(LDAPIS_URL_PREFIX)-1) #define LDAP_URL_URLCOLON "URL:" #define LDAP_URL_URLCOLON_LEN (sizeof(LDAP_URL_URLCOLON)-1) #define NULLLDAPURLDESC ((LDAPURLDesc *)NULL) @@ -132,6 +140,7 @@ typedef struct ldap_server { char *lsrv_host; char *lsrv_dn; /* if NULL, use default */ int lsrv_port; +/* int lsrv_protocol; */ struct ldap_server *lsrv_next; } LDAPServer; @@ -266,6 +275,9 @@ struct ldap { int (*ld_rebindproc)( struct ldap *ld, char **dnp, char **passwdp, int *authmethodp, int freeit ); /* routine to get info needed for re-bind */ +#ifdef HAVE_CYRUS_SASL + sasl_conn_t *ld_sasl_context; +#endif /* HAVE_CYRUS_SASL */ }; #define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION ) @@ -355,7 +367,6 @@ LIBLDAP_F (char *) ldap_get_kerberosv4_credentials LDAP_P(( LIBLDAP_F (int) ldap_open_defconn( LDAP *ld ); LIBLDAP_F (int) open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srvlist, char **krbinstancep, int async ); - /* * in os-ip.c */ @@ -365,7 +376,7 @@ LIBLDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb, const char *host, u LIBLDAP_F (void) ldap_close_connection( Sockbuf *sb ); -#ifdef HAVE_KERBEROS +#if defined(HAVE_KERBEROS) || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL) LIBLDAP_F (char *) ldap_host_connected_to( Sockbuf *sb ); #endif /* HAVE_KERBEROS */ @@ -379,6 +390,12 @@ LIBLDAP_F (void) ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ); LIBLDAP_F (int) ldap_is_read_ready( LDAP *ld, Sockbuf *sb ); LIBLDAP_F (int) ldap_is_write_ready( LDAP *ld, Sockbuf *sb ); +#ifdef LDAP_PF_LOCAL +/* + * in os-local.c + */ +LIBLDAP_F (int) ldap_connect_to_path( LDAP *ld, Sockbuf *sb, const char *path, int async ); +#endif /* LDAP_PF_LOCAL */ /* * in request.c @@ -395,7 +412,6 @@ LIBLDAP_F (void) ldap_free_request( LDAP *ld, LDAPRequest *lr ); LIBLDAP_F (void) ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ); LIBLDAP_F (void) ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ); LIBLDAP_F (void) ldap_dump_requests_and_responses( LDAP *ld ); - LIBLDAP_F (int) ldap_chase_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp, int *hadrefp ); LIBLDAP_F (int) ldap_append_referral( LDAP *ld, char **referralsp, char *s ); diff --git a/libraries/libldap/open.c b/libraries/libldap/open.c index 43c7b80a92..462b60b394 100644 --- a/libraries/libldap/open.c +++ b/libraries/libldap/open.c @@ -287,7 +287,19 @@ open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, if ( srv->lud_host == NULL || *srv->lud_host == 0 ) addr = htonl( INADDR_LOOPBACK ); - rc = ldap_connect_to_host( ld, sb, srv->lud_host, addr, port, async ); + switch ( srv->lud_protocol ) { + case LDAP_PROTO_TCP: + case LDAP_PROTO_UDP: + rc = ldap_connect_to_host( ld, sb, srv->lud_host, addr, port, async ); + break; + case LDAP_PROTO_LOCAL: + rc = ldap_connect_to_path( ld, sb, srv->lud_host, async ); + break; + default: + rc = -1; + break; + } + if ( rc == -1 ) { return( rc ); } @@ -295,9 +307,10 @@ open_ldap_connection( LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); #ifdef HAVE_TLS - tls = srv->lud_ldaps; - if (tls == -1) - tls = ld->ld_options.ldo_tls_mode; + tls = (srv->lud_properties & LDAP_URL_USE_SSL); + if (tls == 0) + tls = (srv->lud_properties & LDAP_URL_USE_SSL_UNSPECIFIED); + if ( tls != 0 ) { rc = ldap_pvt_tls_start( sb, ld->ld_options.ldo_tls_ctx ); if (rc != LDAP_SUCCESS) diff --git a/libraries/libldap/os-ip.c b/libraries/libldap/os-ip.c index 4a908d0575..530c9299dc 100644 --- a/libraries/libldap/os-ip.c +++ b/libraries/libldap/os-ip.c @@ -333,7 +333,7 @@ ldap_close_connection( Sockbuf *sb ) } -#if defined( HAVE_KERBEROS ) || defined( HAVE_TLS ) +#if defined( HAVE_KERBEROS ) || defined( HAVE_TLS ) || defined( HAVE_CYRUS_SASL ) char * ldap_host_connected_to( Sockbuf *sb ) { diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c new file mode 100644 index 0000000000..5d2a21f8f9 --- /dev/null +++ b/libraries/libldap/os-local.c @@ -0,0 +1,219 @@ +/* $OpenLDAP$ */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Portions + * Copyright (c) 1995 Regents of the University of Michigan. + * All rights reserved. + * Copyright (c) 1999 PADL Software Pty Ltd. + * os-ip.c -- platform-specific domain socket code + */ + + +#include "portable.h" + +#ifdef LDAP_PF_LOCAL + +#include + +#include + +#include +#include +#include +#include +#include + +/* XXX non-portable */ +#include + +#ifdef HAVE_IO_H +#include +#endif /* HAVE_IO_H */ + +#include "ldap-int.h" + +/* int ldap_int_tblsize = 0; */ + +#define oslocal_debug(ld,fmt,arg1,arg2,arg3) \ +do { \ + ldap_log_printf(ld, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \ +} while(0) + +static void +ldap_pvt_set_errno(int err) +{ + errno = err; +} + +static int +ldap_pvt_ndelay_on(LDAP *ld, int fd) +{ + oslocal_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0); + return ber_pvt_socket_set_nonblock( fd, 1 ); +} + +static int +ldap_pvt_ndelay_off(LDAP *ld, int fd) +{ + oslocal_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0); + return ber_pvt_socket_set_nonblock( fd, 0 ); +} + +static ber_socket_t +ldap_pvt_socket(LDAP *ld) +{ + ber_socket_t s = socket(AF_UNIX, SOCK_STREAM, 0); + oslocal_debug(ld, "ldap_new_socket: %d\n",s,0,0); + return ( s ); +} + +static int +ldap_pvt_close_socket(LDAP *ld, int s) +{ + oslocal_debug(ld, "ldap_close_socket: %d\n",s,0,0); + return tcp_close(s); +} + +#undef TRACE +#define TRACE do { \ + oslocal_debug(ld, \ + "ldap_is_socket_ready: errror on socket %d: errno: %d (%s)\n", \ + s, \ + errno, \ + strerror(errno) ); \ +} while( 0 ) + +/* + * check the socket for errors after select returned. + */ +static int +ldap_pvt_is_socket_ready(LDAP *ld, int s) +{ + oslocal_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0); + +#if defined( notyet ) /* && defined( SO_ERROR ) */ +{ + int so_errno; + int dummy = sizeof(so_errno); + if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == -1 ) { + return -1; + } + if ( so_errno ) { + ldap_pvt_set_errno(so_errno); + TRACE; + return -1; + } + return 0; +} +#else +{ + /* error slippery */ + struct sockaddr_un sun; + char ch; + int dummy = sizeof(sun); + if ( getpeername( s, (struct sockaddr *) &sun, &dummy ) == -1 ) { + /* XXX: needs to be replace with ber_stream_read() */ + read(s, &ch, 1); + TRACE; + return -1; + } + return 0; +} +#endif + return -1; +} +#undef TRACE + +static int +ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sun, int async) +{ + struct timeval tv, *opt_tv=NULL; + fd_set wfds, *z=NULL; + + if ( (opt_tv = ld->ld_options.ldo_tm_net) != NULL ) { + tv.tv_usec = opt_tv->tv_usec; + tv.tv_sec = opt_tv->tv_sec; + } + + oslocal_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n", + s, opt_tv ? tv.tv_sec : -1L, async); + + if ( ldap_pvt_ndelay_on(ld, s) == -1 ) + return ( -1 ); + + if ( connect(s, (struct sockaddr *) sun, sizeof(struct sockaddr_un)) == 0 ) + { + if ( ldap_pvt_ndelay_off(ld, s) == -1 ) + return ( -1 ); + return ( 0 ); + } + + if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) { + return ( -1 ); + } + +#ifdef notyet + if ( async ) return ( -2 ); +#endif + + FD_ZERO(&wfds); + FD_SET(s, &wfds ); + + if ( select(ldap_int_tblsize, z, &wfds, z, opt_tv ? &tv : NULL) == -1) + return ( -1 ); + + if ( FD_ISSET(s, &wfds) ) { + if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) + return ( -1 ); + if ( ldap_pvt_ndelay_off(ld, s) == -1 ) + return ( -1 ); + return ( 0 ); + } + oslocal_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0); + ldap_pvt_set_errno( ETIMEDOUT ); + return ( -1 ); +} + +int +ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async) +{ + struct sockaddr_un server; + ber_socket_t s = AC_SOCKET_INVALID; + int rc, i, len; + char *ha_buf=NULL, *p, *q; + + oslocal_debug(ld, "ldap_connect_to_path\n",0,0,0); + + if ( (s = ldap_pvt_socket( ld )) == -1 ) { + return -1; + } + + if ( path == NULL || path[0] == '\0' ) { + path = "/tmp/.ldap-sock"; + } else { + if ( strlen(path) > (sizeof( server.sun_path ) - 1) ) { + ldap_pvt_set_errno( ENAMETOOLONG ); + return -1; + } + } + + oslocal_debug(ld, "ldap_connect_to_path: Trying %s\n", path, 0, 0); + + memset( &server, 0, sizeof(server) ); + server.sun_family = AF_UNIX; + strcpy( server.sun_path, path ); + + rc = ldap_pvt_connect(ld, s, &server, async); + + if (rc == 0) { + ber_pvt_sb_set_desc( sb, s ); + } else { + ldap_pvt_close_socket(ld, s); + } + return rc; +} +#else +static int dummy; +#endif /* LDAP_PF_LOCAL */ diff --git a/libraries/libldap/request.c b/libraries/libldap/request.c index badd2468a6..30c8887beb 100644 --- a/libraries/libldap/request.c +++ b/libraries/libldap/request.c @@ -96,7 +96,6 @@ ldap_send_initial_request( ( ld->ld_host == NULL ) ? "(null)" : ld->ld_host, 0, 0 ); } - #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_DNS if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_DNS ) && ldap_is_dns_dn( dn ) ) @@ -254,7 +253,6 @@ ldap_send_server_request( return( msgid ); } - LDAPConn * ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb, int connect, int bind ) diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c index 28e36768b3..a5cfa17675 100644 --- a/libraries/libldap/sasl.c +++ b/libraries/libldap/sasl.c @@ -148,16 +148,6 @@ ldap_sasl_bind( return LDAP_SUCCESS; } -/* - * ldap_sasl_bind_s - bind to the ldap server (and X.500) using simple - * authentication. The dn and password of the entry to which to bind are - * supplied. LDAP_SUCCESS is returned upon success, the ldap error code - * otherwise. - * - * Example: - * ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us", - * "mechanism", "secret", NULL, NULL, &servercred ) - */ int ldap_sasl_bind_s( @@ -221,18 +211,18 @@ ldap_sasl_bind_s( /* - * Parse BindResponse: - * - * BindResponse ::= [APPLICATION 1] SEQUENCE { - * COMPONENTS OF LDAPResult, - * serverSaslCreds [7] OCTET STRING OPTIONAL } - * - * LDAPResult ::= SEQUENCE { - * resultCode ENUMERATED, - * matchedDN LDAPDN, - * errorMessage LDAPString, - * referral [3] Referral OPTIONAL } - */ +* Parse BindResponse: +* +* BindResponse ::= [APPLICATION 1] SEQUENCE { +* COMPONENTS OF LDAPResult, +* serverSaslCreds [7] OCTET STRING OPTIONAL } +* +* LDAPResult ::= SEQUENCE { +* resultCode ENUMERATED, +* matchedDN LDAPDN, +* errorMessage LDAPString, +* referral [3] Referral OPTIONAL } +*/ int ldap_parse_sasl_bind_result( @@ -350,3 +340,486 @@ ldap_parse_sasl_bind_result( return( ld->ld_errno ); } + +#ifdef HAVE_CYRUS_SASL +/* +* Various Cyrus SASL related stuff. +*/ + +static int sasl_setup( Sockbuf *sb, void *arg ); +static int sasl_remove( Sockbuf *sb ); +static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len ); +static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len ); +static int sasl_close( Sockbuf *sb ); + +static Sockbuf_IO sasl_io= +{ +sasl_setup, +sasl_remove, +sasl_read, +sasl_write, +sasl_close +}; + +#define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io) + +static char * +array2str( char **a ) +{ + char *s, **v, *p; + int len = 0; + + for ( v = a; *v != NULL; v++ ) { + len += strlen( *v ) + 1; /* for a space */ + } + + if ( len == 0 ) { + return NULL; + } + + s = LDAP_MALLOC ( len ); /* last space holds \0 */ + + if ( s == NULL ) { + return NULL; + } + + p = s; + for ( v = a; *v != NULL; v++ ) { + int len; + + if ( v != a ) { + strncpy( p, " ", 1 ); + ++p; + } + len = strlen( *v ); + strncpy( p, *v, len ); + p += len; + } + + *p = '\0'; + + return s; +} + +int ldap_pvt_sasl_init( void ) +{ + /* XXX not threadsafe */ + static int sasl_initialized = 0; + + if ( sasl_initialized ) { + return -1; + } +#ifndef CSRIMALLOC + sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree ); +#endif /* CSRIMALLOC */ + + if ( sasl_client_init( NULL ) == SASL_OK ) { + sasl_initialized = 1; + return 0; + } + + return -1; +} + +int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg ) +{ + /* don't install the stuff unless security has been negotiated */ + + if ( !HAS_SASL( sb ) ) { + ber_pvt_sb_clear_io( sb ); + ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg ); + } + + return 0; +} + +static int sasl_setup( Sockbuf *sb, void *arg ) +{ + sb->sb_iodata = arg; + return 0; +} + +static int sasl_remove( Sockbuf *sb ) +{ + return 0; +} + +static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen ) +{ + char *recv_tok; + unsigned recv_tok_len; + sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata; + + if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) { + return -1; + } + + if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) { + return -1; + } + + if ( recv_tok_len > buflen ) { + LDAP_FREE( recv_tok ); + return -1; + } + + memcpy( buf, recv_tok, recv_tok_len ); + + LDAP_FREE( recv_tok ); + + return recv_tok_len; +} + +static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len ) +{ + char *wrapped_tok; + unsigned wrapped_tok_len; + sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata; + + if ( sasl_encode( conn, (const char *)buf, len, + &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) { + return -1; + } + + if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) { + LDAP_FREE( wrapped_tok ); + return -1; + } + + LDAP_FREE( wrapped_tok ); + + return len; +} + +static int sasl_close( Sockbuf *sb ) +{ + (ber_pvt_sb_io_tcp.sbi_close)( sb ); +} + +int +ldap_pvt_sasl_err2ldap( int saslerr ) +{ + int rc; + + switch (saslerr) { + case SASL_CONTINUE: + rc = LDAP_SASL_BIND_IN_PROGRESS; + break; + case SASL_OK: + rc = LDAP_SUCCESS; + break; + case SASL_FAIL: + rc = LDAP_OPERATIONS_ERROR; + break; + case SASL_NOMEM: + rc = LDAP_NO_MEMORY; + break; + case SASL_NOMECH: + rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; + break; + case SASL_BADAUTH: + rc = LDAP_INVALID_CREDENTIALS; + break; + case SASL_NOAUTHZ: + rc = LDAP_INSUFFICIENT_ACCESS; + break; + case SASL_TOOWEAK: + case SASL_ENCRYPT: + rc = LDAP_INAPPROPRIATE_AUTH; + break; + default: + rc = LDAP_OPERATIONS_ERROR; + break; + } + + return rc; +} + +int +ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist ) +{ + /* we need to query the server for supported mechs anyway */ + LDAPMessage *res, *e; + char *attrs[] = { "supportedSASLMechanisms", NULL }; + char **values, *mechlist, **p; + int rc; + + rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE, + "(objectclass=*)", attrs, 0, &res ); + + if ( rc != LDAP_SUCCESS ) { + return ld->ld_errno; + } + + e = ldap_first_entry( ld, res ); + if ( e == NULL ) { + if ( ld->ld_errno == LDAP_SUCCESS ) { + ld->ld_errno = LDAP_UNAVAILABLE; + } + return ld->ld_errno; + } + + values = ldap_get_values( ld, e, "supportedSASLMechanisms" ); + if ( values == NULL ) { + ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE; + ldap_msgfree( res ); + return ld->ld_errno; + } + + if ( desired != NULL ) { + rc = LDAP_INAPPROPRIATE_AUTH; + + for ( p = values; *p != NULL; p++ ) { + if ( !strcmp( *p, desired ) == 0 ) { + rc = LDAP_SUCCESS; + break; + } + } + + if ( rc == LDAP_SUCCESS ) { + /* just return this */ + *pmechlist = LDAP_STRDUP( desired ); + return LDAP_SUCCESS; + } else { + /* couldn't find it */ + ld->ld_errno = LDAP_INAPPROPRIATE_AUTH; + return ld->ld_errno; + } + } + + mechlist = array2str( values ); + if ( mechlist == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + ldap_value_free( values ); + ldap_msgfree( res ); + return ld->ld_errno; + } + + ldap_value_free( values ); + ldap_msgfree( res ); + + *pmechlist = mechlist; + + return LDAP_SUCCESS; +} + +int +ldap_pvt_sasl_bind( + LDAP *ld, + LDAP_CONST char *dn, + LDAP_CONST char *mechanism, + const sasl_callback_t *callbacks, + LDAPControl **sctrls, + LDAPControl **cctrls ) +{ + int saslrc, rc, msgid, ssf = 0; + struct berval ccred, *scred; + char *mechlist = NULL; + char *host; + sasl_interact_t *client_interact = NULL; + + Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 ); + + /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */ + if (ld->ld_version < LDAP_VERSION3) { + ld->ld_errno = LDAP_NOT_SUPPORTED; + return ld->ld_errno; + } + + /* + * This connects to the host, side effect being that + * ldap_host_connected_to() works. + */ + rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist ); + if ( rc != LDAP_SUCCESS ) { + return ld->ld_errno; + } + + /* XXX this doesn't work with PF_LOCAL hosts */ + host = ldap_host_connected_to( &ld->ld_sb ); + + if ( host == NULL ) { + LDAP_FREE( mechlist ); + ld->ld_errno = LDAP_UNAVAILABLE; + return ld->ld_errno; + } + + if ( ld->ld_sasl_context != NULL ) { + LDAP_FREE( mechlist ); + sasl_dispose( &ld->ld_sasl_context ); + } + + saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context ); + + LDAP_FREE( host ); + + if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { + LDAP_FREE( mechlist ); + ld->ld_errno = ldap_pvt_sasl_err2ldap( rc ); + sasl_dispose( &ld->ld_sasl_context ); + return ld->ld_errno; + } + + ccred.bv_val = NULL; + ccred.bv_len = 0; + + saslrc = sasl_client_start( ld->ld_sasl_context, + mechlist, + NULL, + &client_interact, + &ccred.bv_val, + (unsigned int *)&ccred.bv_len, + &mechanism ); + + LDAP_FREE( mechlist ); + + if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { + ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc ); + sasl_dispose( &ld->ld_sasl_context ); + return ld->ld_errno; + } + + scred = NULL; + + do { + sasl_interact_t *client_interact = NULL; + + rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred ); + if ( rc == LDAP_SUCCESS ) { + break; + } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) { + if ( ccred.bv_val != NULL ) { + LDAP_FREE( ccred.bv_val ); + } + sasl_dispose( &ld->ld_sasl_context ); + return ld->ld_errno; + } + + if ( ccred.bv_val != NULL ) { + LDAP_FREE( ccred.bv_val ); + ccred.bv_val = NULL; + } + + saslrc = sasl_client_step( ld->ld_sasl_context, + (scred == NULL) ? NULL : scred->bv_val, + (scred == NULL) ? 0 : scred->bv_len, + &client_interact, + &ccred.bv_val, + (unsigned int *)&ccred.bv_len ); + + ber_bvfree( scred ); + + if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { + ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc ); + sasl_dispose( &ld->ld_sasl_context ); + return ld->ld_errno; + } + } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); + + assert ( rc == LDAP_SUCCESS ); + + if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf ) + == SASL_OK && ssf ) { + ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context ); + } + + return rc; +} + +/* based on sample/sample-client.c */ +static int +ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret) +{ + struct berval *passphrase = (struct berval *)context; + size_t len; + + if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) { + return SASL_BADPARAM; + } + + len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0; + + *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len ); + if ( *psecret == NULL ) { + return SASL_NOMEM; + } + + (*psecret)->len = passphrase->bv_len; + + if ( passphrase != NULL ) { + memcpy((*psecret)->data, passphrase->bv_val, len); + } + + return SASL_OK; +} + +static int +ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len) +{ + const char *value = (const char *)context; + + if ( result == NULL ) { + return SASL_BADPARAM; + } + + switch ( id ) { + case SASL_CB_USER: + case SASL_CB_AUTHNAME: + *result = value; + if ( len ) + *len = value ? strlen( value ) : 0; + break; + case SASL_CB_LANGUAGE: + *result = NULL; + if ( len ) + *len = 0; + break; + default: + return SASL_BADPARAM; + } + + return SASL_OK; +} + +/* + * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500) using SASL + * authentication. The dn and password of the entry to which to bind are + * supplied. LDAP_SUCCESS is returned upon success, the ldap error code + * otherwise. + * + * Example: + * ldap_negotiated_sasl_bind_s( ld, NULL, + * "dn:cn=manager", NULL, "GSSAPI", NULL, NULL, NULL ); + */ +int +ldap_negotiated_sasl_bind_s( + LDAP *ld, + LDAP_CONST char *dn, /* usually NULL */ + LDAP_CONST char *authorizationId, + LDAP_CONST char *authenticationId, + LDAP_CONST char *saslMechanism, + struct berval *passPhrase, + LDAPControl **serverControls, + LDAPControl **clientControls) +{ + sasl_callback_t callbacks[4]; + int rc; + + callbacks[0].id = SASL_CB_USER; + callbacks[0].proc = ldap_pvt_sasl_getsimple; + callbacks[0].context = (void *)authorizationId; + callbacks[1].id = SASL_CB_AUTHNAME; + callbacks[1].proc = ldap_pvt_sasl_getsimple; + callbacks[1].context = (void *)authenticationId; + callbacks[2].id = SASL_CB_PASS; + callbacks[2].proc = ldap_pvt_sasl_getsecret; + callbacks[2].context = (void *)passPhrase; + callbacks[3].id = SASL_CB_LIST_END; + callbacks[3].proc = NULL; + callbacks[3].context = NULL; + + rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks, serverControls, clientControls); + + return rc; +} +#endif /* HAVE_CYRUS_SASL */ diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c index 24c43b454c..c4222fe4ab 100644 --- a/libraries/libldap/unbind.c +++ b/libraries/libldap/unbind.c @@ -139,6 +139,12 @@ ldap_ld_free( ld->ld_options.ldo_tm_net = NULL; } +#ifdef HAVE_CYRUS_SASL + if ( ld->ld_sasl_context != NULL ) { + sasl_dispose( &ld->ld_sasl_context ); + } +#endif + ber_pvt_sb_destroy( &(ld->ld_sb) ); LDAP_FREE( (char *) ld ); diff --git a/libraries/libldap/url.c b/libraries/libldap/url.c index a4309bfcf6..9d29cc4120 100644 --- a/libraries/libldap/url.c +++ b/libraries/libldap/url.c @@ -40,48 +40,51 @@ static const char* skip_url_prefix LDAP_P(( const char *url, int *enclosedp, - int *ldaps )); + unsigned long *properties, + int *protocol)); int ldap_is_ldap_url( LDAP_CONST char *url ) { - int enclosed; - int ldaps; + int enclosed, protocol; + unsigned long properties; if( url == NULL ) { return 0; } - if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) { + if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) { return 0; } - return !ldaps; + return !(properties & LDAP_URL_USE_SSL); } int ldap_is_ldaps_url( LDAP_CONST char *url ) { - int enclosed; - int ldaps; + int enclosed, protocol; + unsigned long properties; if( url == NULL ) { return 0; } - if( skip_url_prefix( url, &enclosed, &ldaps) == NULL ) { + if( skip_url_prefix( url, &enclosed, &properties, &protocol) == NULL ) { return 0; } - return ldaps; + return (properties & LDAP_URL_USE_SSL); } static const char* skip_url_prefix( const char *url, int *enclosedp, - int *ldaps ) + unsigned long *properties, + int *protocol + ) { /* * return non-zero if this looks like a LDAP URL; zero if not @@ -109,11 +112,13 @@ skip_url_prefix( p += LDAP_URL_URLCOLON_LEN; } + *properties = 0; + /* check for "ldap://" prefix */ if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldap://" prefix and return success */ p += LDAP_URL_PREFIX_LEN; - *ldaps = 0; + *protocol = LDAP_PROTO_TCP; return( p ); } @@ -121,7 +126,25 @@ skip_url_prefix( if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) { /* skip over "ldaps://" prefix and return success */ p += LDAPS_URL_PREFIX_LEN; - *ldaps = 1; + *protocol = LDAP_PROTO_TCP; + *properties |= LDAP_URL_USE_SSL; + return( p ); + } + + /* check for "ldapi://" prefix */ + if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldapi://" prefix and return success */ + p += LDAPI_URL_PREFIX_LEN; + *protocol = LDAP_PROTO_LOCAL; + return( p ); + } + + /* check for "ldapis://" prefix: should this be legal? */ + if ( strncasecmp( p, LDAPIS_URL_PREFIX, LDAPIS_URL_PREFIX_LEN ) == 0 ) { + /* skip over "ldapis://" prefix and return success */ + p += LDAPIS_URL_PREFIX_LEN; + *protocol = LDAP_PROTO_LOCAL; + *properties |= LDAP_URL_USE_SSL; return( p ); } @@ -160,7 +183,8 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) LDAPURLDesc *ludp; char *p, *q; - int i, enclosed, ldaps; + int i, enclosed, protocol; + unsigned long properties; const char *url_tmp; char *url; @@ -172,7 +196,7 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) *ludpp = NULL; /* pessimistic */ - url_tmp = skip_url_prefix( url_in, &enclosed, &ldaps ); + url_tmp = skip_url_prefix( url_in, &enclosed, &properties, &protocol ); if ( url_tmp == NULL ) { return LDAP_URL_ERR_NOTLDAP; @@ -205,10 +229,11 @@ ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp ) ludp->lud_next = NULL; ludp->lud_host = NULL; ludp->lud_port = 0; - ludp->lud_dn = NULL; - ludp->lud_attrs = NULL; - ludp->lud_filter = NULL; - ludp->lud_ldaps = ldaps; + ludp->lud_dn = NULL; + ludp->lud_attrs = NULL; + ludp->lud_filter = NULL; + ludp->lud_properties = properties; + ludp->lud_protocol = protocol; ludp->lud_scope = LDAP_SCOPE_BASE; ludp->lud_filter = LDAP_STRDUP("(objectClass=*)"); @@ -468,7 +493,6 @@ ldap_url_dup ( LDAPURLDesc *ludp ) } } - dest->lud_ldaps = ludp->lud_ldaps; dest->lud_port = ludp->lud_port; dest->lud_scope = ludp->lud_scope; @@ -567,7 +591,8 @@ ldap_url_parsehosts (LDAPURLDesc **ludlist, const char *hosts ) ludp->lud_port = atoi(p); } ldap_pvt_hex_unescape(ludp->lud_host); - ludp->lud_ldaps = -1; /* unknown (use TLS default) */ + ludp->lud_protocol = LDAP_PROTO_TCP; + ludp->lud_properties = LDAP_URL_USE_SSL_UNSPECIFIED; ludp->lud_next = *ludlist; *ludlist = ludp; } @@ -635,7 +660,7 @@ ldap_url_list2urls (LDAPURLDesc *ludlist) p = s; for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) { - p += sprintf(p, "ldap%s://%s", (ludp->lud_ldaps == 1) ? "s" : "", ludp->lud_host); + p += sprintf(p, "ldap%s://%s", (ludp->lud_properties & LDAP_URL_USE_SSL) ? "s" : "", ludp->lud_host); if (ludp->lud_port != 0) p += sprintf(p, ":%d", ludp->lud_port); *p++ = '/'; @@ -767,9 +792,9 @@ void ldap_pvt_hex_unescape( char *s ) { /* - * Remove URL hex escapes from s... done in place. The basic concept for - * this routine is borrowed from the WWW library HTUnEscape() routine. - */ +* Remove URL hex escapes from s... done in place. The basic concept for +* this routine is borrowed from the WWW library HTUnEscape() routine. +*/ char *p; for ( p = s; *s != '\0'; ++s ) { diff --git a/libraries/libldap_r/Makefile.in b/libraries/libldap_r/Makefile.in index 7f66bac8d9..3454faefee 100644 --- a/libraries/libldap_r/Makefile.in +++ b/libraries/libldap_r/Makefile.in @@ -16,7 +16,7 @@ XXSRCS = apitest.c test.c tmpltest.c extended.c \ getdn.c getentry.c getattr.c getvalues.c addentry.c \ request.c getdxbyname.c os-ip.c url.c charset.c \ init.c options.c print.c string.c util-int.c schema.c \ - charray.c digest.c tls.c dn.c + charray.c digest.c tls.c dn.c os-local.c SRCS = thr_posix.c thr_cthreads.c thr_thr.c thr_lwp.c thr_nt.c \ thr_pth.c thr_sleep.c thr_stub.c rdwr.c OBJS = extended.lo \ @@ -29,7 +29,7 @@ OBJS = extended.lo \ init.lo options.lo print.lo string.lo util-int.lo schema.lo \ thr_posix.lo thr_cthreads.lo thr_thr.lo thr_lwp.lo thr_nt.lo \ thr_pth.lo thr_sleep.lo thr_stub.lo rdwr.lo \ - charray.lo digest.lo tls.lo dn.lo + charray.lo digest.lo tls.lo dn.lo os-local.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries diff --git a/servers/slapd/back-ldbm/Makefile.in b/servers/slapd/back-ldbm/Makefile.in index 15211cb0f7..ec0ecc9734 100644 --- a/servers/slapd/back-ldbm/Makefile.in +++ b/servers/slapd/back-ldbm/Makefile.in @@ -4,12 +4,12 @@ SRCS = idl.c add.c search.c cache.c dbcache.c dn2id.c entry.c id2entry.c \ index.c id2children.c nextid.c abandon.c compare.c group.c \ modify.c modrdn.c delete.c init.c config.c bind.c attr.c \ filterindex.c unbind.c close.c alias.c tools.c \ - extended.c passwd.c + extended.c passwd.c sasl.c OBJS = idl.lo add.lo search.lo cache.lo dbcache.lo dn2id.lo entry.lo id2entry.lo \ index.lo id2children.lo nextid.lo abandon.lo compare.lo group.lo \ modify.lo modrdn.lo delete.lo init.lo config.lo bind.lo attr.lo \ filterindex.lo unbind.lo close.lo alias.lo tools.lo \ - extended.lo passwd.lo + extended.lo passwd.lo sasl.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-ldbm/bind.c b/servers/slapd/back-ldbm/bind.c index 3935179bc6..acec9dd5a1 100644 --- a/servers/slapd/back-ldbm/bind.c +++ b/servers/slapd/back-ldbm/bind.c @@ -85,6 +85,10 @@ ldbm_back_bind( } } else if ( method == LDAP_AUTH_SASL ) { +#ifdef HAVE_CYRUS_SASL + rc = sasl_bind( be, conn, op, + dn, ndn, mech, cred, edn ); +#else if( mech != NULL && strcasecmp(mech,"DIGEST-MD5") == 0 ) { /* insert DIGEST calls here */ send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, @@ -94,7 +98,7 @@ ldbm_back_bind( send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL, NULL, NULL, NULL ); } - +#endif /* HAVE_CYRUS_SASL */ } else if ( refs != NULL ) { send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn, NULL, refs, NULL ); @@ -241,7 +245,7 @@ ldbm_back_bind( if ( (a = attr_find( e->e_attrs, "krbname" )) == NULL ) { /* - * no krbName values present: check against DN + * no krbname values present: check against DN */ if ( strcasecmp( dn, krbname ) == 0 ) { rc = 0; @@ -252,7 +256,7 @@ ldbm_back_bind( rc = 1; goto return_results; - } else { /* look for krbName match */ + } else { /* look for krbname match */ struct berval krbval; krbval.bv_val = krbname; @@ -279,7 +283,12 @@ ldbm_back_bind( case LDAP_AUTH_SASL: /* insert SASL code here */ - +#ifdef HAVE_CYRUS_SASL + /* this may discard edn as we always prefer the SASL authzid + * because it may be sealed. + */ + rc = sasl_bind( be, conn, op, dn, ndn, mech, cred, edn ); +#endif /* HAVE_CYRUS_SASL */ default: send_ldap_result( conn, op, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL, "auth method not supported", NULL, NULL ); diff --git a/servers/slapd/back-ldbm/init.c b/servers/slapd/back-ldbm/init.c index 7d59f5dde0..c50800681f 100644 --- a/servers/slapd/back-ldbm/init.c +++ b/servers/slapd/back-ldbm/init.c @@ -82,6 +82,12 @@ ldbm_back_initialize( bi->bi_tool_index_change = ldbm_tool_index_change; bi->bi_tool_sync = ldbm_tool_sync; +#ifdef HAVE_CYRUS_SASL + bi->bi_sasl_authorize = 0; /* ldbm_sasl_authorize; */ + bi->bi_sasl_getsecret = 0; /* ldbm_sasl_getsecret; */ + bi->bi_sasl_putsecret = 0; /* ldbm_sasl_putsecret; */ +#endif + bi->bi_connection_init = 0; bi->bi_connection_destroy = 0; diff --git a/servers/slapd/back-ldbm/proto-back-ldbm.h b/servers/slapd/back-ldbm/proto-back-ldbm.h index c9ebbae66e..85bfff8dfe 100644 --- a/servers/slapd/back-ldbm/proto-back-ldbm.h +++ b/servers/slapd/back-ldbm/proto-back-ldbm.h @@ -178,6 +178,30 @@ int ldbm_modify_internal LDAP_P((Backend *be, Connection *conn, Operation *op, char *dn, LDAPModList *mods, Entry *e )); +#ifdef HAVE_CYRUS_SASL +/* + * sasl.c + */ +int ldbm_sasl_authorize LDAP_P(( + BackendDB *be, + const char *auth_identity, + const char *requested_user, + const char **user, + const char **errstring )); +int ldbm_sasl_getsecret LDAP_P(( + Backend *be, + const char *mechanism, + const char *auth_identity, + const char *realm, + sasl_secret_t **secret )); +int ldbm_sasl_putsecret LDAP_P(( + Backend *be, + const char *mechanism, + const char *auth_identity, + const char *realm, + const sasl_secret_t *secret )); +#endif /* HAVE_CYRUS_SASL */ + /* * nextid.c */ diff --git a/servers/slapd/back-ldbm/sasl.c b/servers/slapd/back-ldbm/sasl.c new file mode 100644 index 0000000000..a1dc6f6b1b --- /dev/null +++ b/servers/slapd/back-ldbm/sasl.c @@ -0,0 +1,59 @@ +/* bind.c - ldbm backend bind and unbind routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#ifdef HAVE_CYRUS_SASL + +#include "portable.h" + +#include + +#include +#include +#include +#include + +#include "slap.h" +#include "back-ldbm.h" +#include "proto-back-ldbm.h" + +int +back_ldbm_sasl_authorize( + BackendDB *be, + const char *auth_identity, + const char *requested_user, + const char **user, + const char **errstring) +{ + return SASL_FAIL; +} + +int +back_ldbm_sasl_getsecret( + Backend *be, + const char *mechanism, + const char *auth_identity, + const char *realm, + sasl_secret_t **secret) +{ + return SASL_FAIL; +} + +int +back_ldbm_sasl_putsecret( + Backend *be, + const char *mechanism, + const char *auth_identity, + const char *realm, + const sasl_secret_t *secret) +{ + return SASL_FAIL; +} + +#else +static int dummy = 1; +#endif + diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c index 9be3d11c8a..881c2c7733 100644 --- a/servers/slapd/bind.c +++ b/servers/slapd/bind.c @@ -226,7 +226,6 @@ do_bind( assert( conn->c_authstate == NULL ); #endif } - } else { ldap_pvt_thread_mutex_lock( &conn->c_mutex ); @@ -305,6 +304,10 @@ do_bind( method, mech, &cred, &edn ); if ( ret == 0 ) { +#ifdef HAVE_CYRUS_SASL + int ssf = 0; +#endif + ldap_pvt_thread_mutex_lock( &conn->c_mutex ); conn->c_cdn = dn; @@ -326,6 +329,14 @@ do_bind( send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL, NULL, NULL ); +#ifdef HAVE_CYRUS_SASL + if ( conn->c_sasl_context != NULL && + sasl_getprop( conn->c_sasl_context, SASL_SSF, (void **)&ssf ) + == SASL_OK && ssf ) { + /* Enable encode/decode */ + ldap_pvt_sasl_install( conn->c_sb, conn->c_sasl_context ); + } +#endif } else if (edn != NULL) { free( edn ); } diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 3f116b6ecc..6f4ebf0a63 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -368,7 +368,7 @@ long connection_init( #ifdef HAVE_CYRUS_SASL c->c_sasl_context = NULL; -#endif +#endif /* HAVE_CYRUS_SASL */ c->c_sb = ber_sockbuf_alloc( ); c->c_currentber = NULL; @@ -485,6 +485,19 @@ connection_destroy( Connection *c ) c->c_peer_domain = NULL; } if(c->c_peer_name != NULL) { +#ifdef LDAP_PF_LOCAL + /* + * If peer was a domain socket, unlink. Mind you, + * they may be un-named. Should we leave this to + * the client? + */ + if (strncmp(c->c_peer_name, "PATH=", 5) == 0) { + char *path = c->c_peer_name + 5; + if (path != '\0') { + (void)unlink(path); + } + } +#endif /* LDAP_PF_LOCAL */ free(c->c_peer_name); c->c_peer_name = NULL; } @@ -506,7 +519,9 @@ connection_destroy( Connection *c ) sasl_dispose( &c->c_sasl_context ); c->c_sasl_context = NULL; } -#endif +#endif /* HAVE_CYRUS_SASL */ + + c->c_bind_in_progress = 0; if ( c->c_currentber != NULL ) { ber_free( c->c_currentber, 1 ); @@ -795,7 +810,13 @@ connection_operation( void *arg_v ) if( conn->c_conn_state == SLAP_C_BINDING) { conn->c_conn_state = SLAP_C_ACTIVE; } - conn->c_bind_in_progress = ( rc == LDAP_SASL_BIND_IN_PROGRESS ); + /* + * Is this ever the case? For now, rely on + * the backend to set this. + */ + if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) { + conn->c_bind_in_progress = 1; + } } ldap_pvt_thread_mutex_lock( &active_threads_mutex ); diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 56c0afe37e..9a55fc277b 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -27,10 +27,22 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_NOTICE; #endif /* TCP Wrappers */ +#ifdef LDAP_PF_LOCAL +#include +#endif /* LDAP_PF_LOCAL */ + /* globals */ time_t starttime; ber_socket_t dtblsize; +#ifdef LDAP_PF_LOCAL +typedef union slap_sockaddr { + struct sockaddr sa_addr; + struct sockaddr_in sa_in_addr; + struct sockaddr_un sa_un_addr; +} Sockaddr; +#endif /* LDAP_PF_LOCAL */ + typedef struct slap_listener { char* sl_url; char* sl_name; @@ -38,7 +50,12 @@ typedef struct slap_listener { int sl_is_tls; #endif ber_socket_t sl_sd; +#ifdef LDAP_PF_LOCAL + Sockaddr sl_sa; +#define sl_addr sl_sa.sa_in_addr +#else struct sockaddr_in sl_addr; +#endif /* LDAP_PF_LOCAL */ } Listener; Listener **slap_listeners = NULL; @@ -196,7 +213,7 @@ static Listener * open_listener( const char* url ) } #ifndef HAVE_TLS - if( lud->lud_ldaps ) { + if( lud->lud_properties & LDAP_URL_USE_SSL ) { Debug( LDAP_DEBUG_ANY, "daemon: TLS not supported (%s)\n", url, 0, 0 ); @@ -209,13 +226,42 @@ static Listener * open_listener( const char* url ) } #else - l.sl_is_tls = lud->lud_ldaps; + l.sl_is_tls = (lud->lud_properties & LDAP_URL_USE_SSL); if(! lud->lud_port ) { - lud->lud_port = lud->lud_ldaps ? LDAPS_PORT : LDAP_PORT; + lud->lud_port = (lud->lud_properties & LDAP_URL_USE_SSL) ? LDAPS_PORT : LDAP_PORT; } #endif +#ifdef LDAP_PF_LOCAL + if (lud->lud_protocol == LDAP_PROTO_LOCAL) { + port = 0; + (void) memset( (void *)&l.sl_sa.sa_un_addr, '\0', sizeof(l.sl_sa.sa_un_addr) ); + + l.sl_sa.sa_un_addr.sun_family = AF_UNIX; + + /* hack: overload the host to be the path */ + if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) { + strcpy( l.sl_sa.sa_un_addr.sun_path, "/tmp/.ldap-sock" ); + } else { + if ( strlen(lud->lud_host) > (sizeof(l.sl_sa.sa_un_addr.sun_path) - 1) ) { + Debug( LDAP_DEBUG_ANY, "domain socket path (%s) too long in URL: %s", + lud->lud_host, url, 0); + ldap_free_urldesc( lud ); + return NULL; + } + strcpy( l.sl_sa.sa_un_addr.sun_path, lud->lud_host ); + } + unlink( l.sl_sa.sa_un_addr.sun_path ); +#if 0 + /* I don't think we need to set this. */ + l.sl_sa.sa_un_addr.sun_len = sizeof( l.sl_sa.sa_un_addr.sun_len ) + + sizeof( l.sl_sa.sa_un_addr.sun_family ) + + strlen( l.sl_sa.sa_un_addr.sun_path ) + 1; +#endif + } else { +#endif /* LDAP_PF_LOCAL */ + port = lud->lud_port; (void) memset( (void*) &l.sl_addr, '\0', sizeof(l.sl_addr) ); @@ -243,11 +289,18 @@ static Listener * open_listener( const char* url ) sizeof( l.sl_addr.sin_addr ) ); } } +#ifdef LDAP_PF_LOCAL + } +#endif /* LDAP_PF_LOCAL */ ldap_free_urldesc( lud ); - +#ifdef LDAP_PF_LOCAL + l.sl_sd = socket( l.sl_sa.sa_addr.sa_family, SOCK_STREAM, 0 ); + if ( l.sl_sd == AC_SOCKET_INVALID ) { +#else if ( (l.sl_sd = socket( AF_INET, SOCK_STREAM, 0 )) == AC_SOCKET_INVALID ) { +#endif /* LDAP_PF_LOCAL */ int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "daemon: socket() failed errno=%d (%s)\n", err, @@ -265,6 +318,11 @@ static Listener * open_listener( const char* url ) } #endif +#ifdef LDAP_PF_LOCAL + /* for IP sockets only */ + if ( l.sl_sa.sa_addr.sa_family == AF_INET ) { +#endif /* LDAP_PF_LOCAL */ + #ifdef SO_REUSEADDR /* enable address reuse */ tmp = 1; @@ -302,7 +360,27 @@ static Listener * open_listener( const char* url ) } #endif +#ifdef LDAP_PF_LOCAL + /* close conditional */ + } + + switch ( l.sl_sa.sa_addr.sa_family ) { + case AF_UNIX: + rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa, + sizeof(l.sl_sa.sa_un_addr) ); + break; + case AF_INET: + rc = bind( l.sl_sd, (struct sockaddr *)&l.sl_sa, + sizeof(l.sl_sa.sa_in_addr) ); + break; + default: + rc = AC_SOCKET_ERROR; + errno = EINVAL; + break; + } +#else rc = bind( l.sl_sd, (struct sockaddr *) &l.sl_addr, sizeof(l.sl_addr) ); +#endif /* LDAP_PF_LOCAL */ if ( rc == AC_SOCKET_ERROR ) { int err = sock_errno(); Debug( LDAP_DEBUG_ANY, "daemon: bind(%ld) failed errno=%d (%s)\n", @@ -310,13 +388,40 @@ static Listener * open_listener( const char* url ) tcp_close( l.sl_sd ); return NULL; } - +#ifdef LDAP_PF_LOCAL + if ( l.sl_sa.sa_addr.sa_family == AF_UNIX ) { + if ( chmod( l.sl_sa.sa_un_addr.sun_path, S_IRWXU ) < 0 ) { + int err = sock_errno(); + Debug( LDAP_DEBUG_ANY, "daemon: fchmod(%ld) failed errno=%d (%s)", + (long) l.sl_sd, err, sock_errstr(err) ); + tcp_close( l.sl_sd ); + return NULL; + } + } +#endif /* LDAP_PF_LOACL */ l.sl_url = ch_strdup( url ); - +#ifdef LDAP_PF_LOCAL + switch ( l.sl_sa.sa_addr.sa_family ) { + case AF_UNIX: + l.sl_name = ch_malloc( strlen(l.sl_sa.sa_un_addr.sun_path) + sizeof("PATH=") ); + sprintf( l.sl_name, "PATH=%s", l.sl_sa.sa_un_addr.sun_path ); + break; + case AF_INET: + l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65336") ); + s = inet_ntoa( l.sl_addr.sin_addr ); + sprintf( l.sl_name, "IP=%s:%d", + s != NULL ? s : "unknown" , port ); + break; + default: + l.sl_name = ch_strdup( "UNKNOWN" ); + break; + } +#else l.sl_name = ch_malloc( sizeof("IP=255.255.255.255:65336") ); s = inet_ntoa( l.sl_addr.sin_addr ); sprintf( l.sl_name, "IP=%s:%d", s != NULL ? s : "unknown" , port ); +#endif /* LDAP_PF_LOCAL */ li = ch_malloc( sizeof( Listener ) ); *li = l; @@ -476,8 +581,14 @@ slapd_daemon_task( fd_set readfds; fd_set writefds; - +#ifdef LDAP_PF_LOCAL + Sockaddr from; +/* minimize impact, undefine later. */ +#define sin_addr sa_in_addr.sin_addr +#define sin_port sa_in_addr.sin_port +#else struct sockaddr_in from; +#endif /* LDAP_PF_LOCAL */ #if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD) struct hostent *hp; #endif @@ -611,9 +722,11 @@ slapd_daemon_task( char *dnsname; char *peeraddr; - +#ifdef LDAP_PF_LOCAL + char peername[MAXPATHLEN + sizeof("PATH=")]; +#else char peername[sizeof("IP=255.255.255.255:65336")]; - +#endif /* LDAP_PF_LOCAL */ if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ) continue; @@ -668,6 +781,13 @@ slapd_daemon_task( continue; } +#ifdef LDAP_PF_LOCAL + switch ( from.sa_addr.sa_family ) { + case AF_UNIX: + sprintf( peername, "PATH=%s", from.sa_un_addr.sun_path ); + break; + case AF_INET: +#endif /* LDAP_PF_LOCAL */ peeraddr = inet_ntoa( from.sin_addr ); sprintf( peername, "IP=%s:%d", peeraddr != NULL ? peeraddr : "unknown", @@ -706,6 +826,15 @@ slapd_daemon_task( continue; } #endif /* HAVE_TCPD */ +#ifdef LDAP_PF_LOCAL + break; + default: + slapd_close(s); + continue; + } +#undef sin_addr +#undef sin_port +#endif /* LDAP_PF_LOCAL */ if( (id = connection_init(s, slap_listeners[l]->sl_url, @@ -881,6 +1010,11 @@ slapd_daemon_task( for ( l = 0; slap_listeners[l] != NULL; l++ ) { if ( slap_listeners[l]->sl_sd != AC_SOCKET_INVALID ) { +#ifdef LDAP_PF_LOCAL + if ( slap_listeners[l]->sl_sa.sa_addr.sa_family == AF_UNIX ) { + unlink( slap_listeners[l]->sl_sa.sa_un_addr.sun_path ); + } +#endif /* LDAP_PF_LOCAL */ slapd_close( slap_listeners[l]->sl_sd ); break; } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 49d4c544e0..a70cb37d31 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -264,6 +264,9 @@ typedef int (*SLAP_EXTOP_MAIN_FN) LDAP_P(( typedef int (*SLAP_EXTOP_GETOID_FN) LDAP_P(( int index, char *oid, int blen )); +LIBSLAPD_F (int) load_extension LDAP_P((const void *module, const char *file_name)); +LIBSLAPD_F (char *) get_supported_extension LDAP_P((int index)); + LIBSLAPD_F (int) load_extop LDAP_P(( const char *ext_oid, SLAP_EXTOP_MAIN_FN ext_main )); @@ -424,6 +427,12 @@ LIBSLAPD_F (char **) supportedSASLMechanisms; LIBSLAPD_F (int) sasl_init(void); LIBSLAPD_F (int) sasl_destroy(void); +#ifdef HAVE_CYRUS_SASL +LIBSLAPD_F (int) sasl_errldap LDAP_P(( int )); +LIBSLAPD_F (int) sasl_bind LDAP_P((Backend *, + Connection *, Operation *, + char *, char *, char *, struct berval *, char **)); +#endif /* * schema.c diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index 6eb8eea570..433cb9d9e4 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -18,9 +18,32 @@ char **supportedSASLMechanisms = NULL; #ifdef HAVE_CYRUS_SASL -static sasl_callback_t callbacks[] = { - { SASL_CB_LIST_END, NULL, NULL } -}; +static void *sasl_pvt_mutex_new(void) +{ + ldap_pvt_thread_mutex_t *mutex; + + mutex = (ldap_pvt_thread_mutex_t *)ch_malloc( sizeof(ldap_pvt_thread_mutex_t) ); + if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) { + return mutex; + } + return NULL; +} + +static int sasl_pvt_mutex_lock(void *mutex) +{ + return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex ); +} + +static int sasl_pvt_mutex_unlock(void *mutex) +{ + return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex ); +} + +static void sasl_pvt_mutex_dispose(void *mutex) +{ + (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex ); + free( mutex ); +} int sasl_init( void ) { @@ -28,7 +51,12 @@ int sasl_init( void ) char *mechs; sasl_conn_t *server = NULL; - rc = sasl_server_init( callbacks, "slapd" ); + sasl_set_alloc( ch_malloc, ch_calloc, ch_realloc, ch_free ); + + sasl_set_mutex( sasl_pvt_mutex_new, sasl_pvt_mutex_lock, + sasl_pvt_mutex_unlock, sasl_pvt_mutex_dispose ); + + rc = sasl_server_init( NULL, "slapd" ); if( rc != SASL_OK ) { Debug( LDAP_DEBUG_ANY, "sasl_server_init failed\n", @@ -88,6 +116,113 @@ int sasl_destroy( void ) return 0; } +#ifdef HAVE_CYRUS_SASL +int sasl_bind( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + char *ndn, + char *mech, + struct berval *cred, + char **edn) +{ + struct berval response; + const char *errstr; + int sc; + int rc = 1; + + Debug(LDAP_DEBUG_ARGS, "==> sasl_bind: dn=%s, mech=%s, cred->bv_len=%d\n", + dn, mech, cred ? cred->bv_len : 0 ); + + if ( conn->c_sasl_context == NULL ) { + sasl_callback_t callbacks[4]; + int cbnum = 0; + + if (be->be_sasl_authorize) { + callbacks[cbnum].id = SASL_CB_PROXY_POLICY; + callbacks[cbnum].proc = be->be_sasl_authorize; + callbacks[cbnum].context = be; + ++cbnum; + } + + if (be->be_sasl_getsecret) { + callbacks[cbnum].id = SASL_CB_SERVER_GETSECRET; + callbacks[cbnum].proc = be->be_sasl_getsecret; + callbacks[cbnum].context = be; + ++cbnum; + } + + if (be->be_sasl_putsecret) { + callbacks[cbnum].id = SASL_CB_SERVER_PUTSECRET; + callbacks[cbnum].proc = be->be_sasl_putsecret; + callbacks[cbnum].context = be; + ++cbnum; + } + callbacks[cbnum].id = SASL_CB_LIST_END; + callbacks[cbnum].proc = NULL; + callbacks[cbnum].context = NULL; + + if ( sasl_server_new( "ldap", NULL, be->be_realm, + callbacks, SASL_SECURITY_LAYER, &conn->c_sasl_context ) != SASL_OK ) { + send_ldap_result( conn, op, LDAP_AUTH_METHOD_NOT_SUPPORTED, + NULL, NULL, NULL, NULL ); + } else { + conn->c_authmech = ch_strdup( mech ); + sc = sasl_server_start( conn->c_sasl_context, conn->c_authmech, + cred->bv_val, cred->bv_len, (char **)&response.bv_val, + (unsigned *)&response.bv_len, &errstr ); + if ( (sc != SASL_OK) && (sc != SASL_CONTINUE) ) { + send_ldap_result( conn, op, ldap_pvt_sasl_err2ldap( sc ), + NULL, errstr, NULL, NULL ); + } + } + } else { + sc = sasl_server_step( conn->c_sasl_context, cred->bv_val, cred->bv_len, + (char **)&response.bv_val, (unsigned *)&response.bv_len, &errstr ); + if ( (sc != SASL_OK) && (sc != SASL_CONTINUE) ) { + send_ldap_result( conn, op, ldap_pvt_sasl_err2ldap( sc ), + NULL, errstr, NULL, NULL ); + } + } + if ( sc == SASL_OK ) { + char *authzid; + + if ( ( sc = sasl_getprop( conn->c_sasl_context, SASL_USERNAME, + (void **)&authzid ) ) != SASL_OK ) { + send_ldap_result( conn, op, ldap_pvt_sasl_err2ldap( sc ), + NULL, NULL, NULL, NULL ); + } else { + if ( *edn != NULL ) { + free( *edn ); + } + if ( strcasecmp( authzid, "anonymous" ) == 0 ) { + *edn = ch_strdup( "" ); + } else { + *edn = ch_malloc( strlen( authzid ) + sizeof( "authzid=" ) ); + strcpy( *edn, "authzid=" ); + strcat( *edn, authzid ); + } + /* let FE send result */ + rc = 0; + } + } else if ( sc == SASL_CONTINUE ) { + /* + * We set c_bind_in_progress because it doesn't appear + * that connection.c sets this (unless do_bind() itself + * returns LDAP_SASL_BIND_IN_PROGRESS). + */ + conn->c_bind_in_progress = 1; + send_ldap_sasl( conn, op, LDAP_SASL_BIND_IN_PROGRESS, + /* matched */ NULL, /* text */ NULL, /* refs */ NULL, /* controls */ NULL, &response ); + } + + Debug(LDAP_DEBUG_TRACE, "<== sasl_bind: rc=%d\n", rc, 0, 0); + + return rc; +} +#endif /* HAVE_CYRUS_SASL */ + #else /* no SASL support */ int sasl_init( void ) { return 0; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 6ab1017b53..a9b82c6015 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -500,6 +500,12 @@ struct slap_backend_db { #define be_index_attr bd_info->bi_tool_index_attr #define be_index_change bd_info->bi_tool_index_change #define be_sync bd_info->bi_tool_sync +#endif + +#ifdef HAVE_CYRUS_SASL +#define be_sasl_authorize bd_info->bi_sasl_authorize +#define be_sasl_getsecret bd_info->bi_sasl_getsecret +#define be_sasl_putsecret bd_info->bi_sasl_putsecret #endif /* these should be renamed from be_ to bd_ */ @@ -656,6 +662,18 @@ struct slap_backend_info { struct berval **bv, ID id, int op )); int (*bi_tool_sync) LDAP_P(( BackendDB *be )); +#ifdef HAVE_CYRUS_SASL + int (*bi_sasl_authorize) LDAP_P(( BackendDB *be, + const char *authnid, const char *authzid, + const char **canon_authzid, const char **errstr )); + int (*bi_sasl_getsecret) LDAP_P(( BackendDB *be, + const char *mechanism, const char *authzid, + const char *realm, sasl_secret_t **secret )); + int (*bi_sasl_putsecret) LDAP_P(( BackendDB *be, + const char *mechanism, const char *auth_identity, + const char *realm, const sasl_secret_t *secret )); +#endif /* HAVE_CYRUS_SASL */ + #define SLAP_INDEX_ADD_OP 0x0001 #define SLAP_INDEX_DELETE_OP 0x0002 diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c index 03d91a25a9..3bb5fc93f7 100644 --- a/servers/slapd/tools/mimic.c +++ b/servers/slapd/tools/mimic.c @@ -143,3 +143,18 @@ int sasl_init(void) { int sasl_destroy(void) { return 0; } + +#ifdef HAVE_CYRUS_SASL +int sasl_bind( + Backend *be, + Connection *conn, + Operation *op, + char *dn, + char *ndn, + char *mech, + struct berval *cred, + char **edn) +{ + return -1; +} +#endif -- 2.39.5