Back to index

openldap  2.4.31
cyrus.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 
00018 #include <stdio.h>
00019 
00020 #include <ac/socket.h>
00021 #include <ac/stdlib.h>
00022 #include <ac/string.h>
00023 #include <ac/time.h>
00024 #include <ac/errno.h>
00025 #include <ac/ctype.h>
00026 #include <ac/unistd.h>
00027 
00028 #ifdef HAVE_LIMITS_H
00029 #include <limits.h>
00030 #endif
00031 
00032 #include "ldap-int.h"
00033 
00034 #ifdef HAVE_CYRUS_SASL
00035 
00036 #ifdef HAVE_LIMITS_H
00037 #include <limits.h>
00038 #endif
00039 
00040 #ifndef INT_MAX
00041 #define       INT_MAX       2147483647    /* 32 bit signed max */
00042 #endif
00043 
00044 #ifdef LDAP_R_COMPILE
00045 ldap_pvt_thread_mutex_t ldap_int_sasl_mutex;
00046 #endif
00047 
00048 #ifdef HAVE_SASL_SASL_H
00049 #include <sasl/sasl.h>
00050 #else
00051 #include <sasl.h>
00052 #endif
00053 
00054 #if SASL_VERSION_MAJOR >= 2
00055 #define SASL_CONST const
00056 #else
00057 #define SASL_CONST
00058 #endif
00059 
00060 /*
00061 * Various Cyrus SASL related stuff.
00062 */
00063 
00064 static const sasl_callback_t client_callbacks[] = {
00065 #ifdef SASL_CB_GETREALM
00066        { SASL_CB_GETREALM, NULL, NULL },
00067 #endif
00068        { SASL_CB_USER, NULL, NULL },
00069        { SASL_CB_AUTHNAME, NULL, NULL },
00070        { SASL_CB_PASS, NULL, NULL },
00071        { SASL_CB_ECHOPROMPT, NULL, NULL },
00072        { SASL_CB_NOECHOPROMPT, NULL, NULL },
00073        { SASL_CB_LIST_END, NULL, NULL }
00074 };
00075 
00076 int ldap_int_sasl_init( void )
00077 {
00078        /* XXX not threadsafe */
00079        static int sasl_initialized = 0;
00080 
00081 #ifdef HAVE_SASL_VERSION
00082        /* stringify the version number, sasl.h doesn't do it for us */
00083 #define VSTR0(maj, min, pat)       #maj "." #min "." #pat
00084 #define VSTR(maj, min, pat) VSTR0(maj, min, pat)
00085 #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
00086                             SASL_VERSION_STEP)
00087        { int rc;
00088        sasl_version( NULL, &rc );
00089        if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) ||
00090               (rc & 0xffff) < SASL_VERSION_STEP) {
00091               char version[sizeof("xxx.xxx.xxxxx")];
00092               sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff,
00093                      rc & 0xffff );
00094 
00095               Debug( LDAP_DEBUG_ANY,
00096               "ldap_int_sasl_init: SASL library version mismatch:"
00097               " expected " SASL_VERSION_STRING ","
00098               " got %s\n", version, 0, 0 );
00099               return -1;
00100        }
00101        }
00102 #endif
00103        if ( sasl_initialized ) {
00104               return 0;
00105        }
00106 
00107 /* SASL 2 takes care of its own memory completely internally */
00108 #if SASL_VERSION_MAJOR < 2 && !defined(CSRIMALLOC)
00109        sasl_set_alloc(
00110               ber_memalloc,
00111               ber_memcalloc,
00112               ber_memrealloc,
00113               ber_memfree );
00114 #endif /* CSRIMALLOC */
00115 
00116 #ifdef LDAP_R_COMPILE
00117        sasl_set_mutex(
00118               ldap_pvt_sasl_mutex_new,
00119               ldap_pvt_sasl_mutex_lock,
00120               ldap_pvt_sasl_mutex_unlock,    
00121               ldap_pvt_sasl_mutex_dispose );    
00122 #endif
00123 
00124        if ( sasl_client_init( NULL ) == SASL_OK ) {
00125               sasl_initialized = 1;
00126               return 0;
00127        }
00128 
00129 #if SASL_VERSION_MAJOR < 2
00130        /* A no-op to make sure we link with Cyrus 1.5 */
00131        sasl_client_auth( NULL, NULL, NULL, 0, NULL, NULL );
00132 #endif
00133        return -1;
00134 }
00135 
00136 static void
00137 sb_sasl_cyrus_init(
00138        struct sb_sasl_generic_data *p,
00139        ber_len_t *min_send,
00140        ber_len_t *max_send,
00141        ber_len_t *max_recv)
00142 {
00143        sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
00144        ber_len_t maxbuf;
00145 
00146        sasl_getprop( sasl_context, SASL_MAXOUTBUF,
00147                     (SASL_CONST void **)(char *) &maxbuf );
00148 
00149        *min_send = SASL_MIN_BUFF_SIZE;
00150        *max_send = maxbuf;
00151        *max_recv = SASL_MAX_BUFF_SIZE;
00152 }
00153 
00154 static ber_int_t
00155 sb_sasl_cyrus_encode(
00156        struct sb_sasl_generic_data *p,
00157        unsigned char *buf,
00158        ber_len_t len,
00159        Sockbuf_Buf *dst)
00160 {
00161        sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
00162        ber_int_t ret;
00163        unsigned tmpsize = dst->buf_size;
00164 
00165        ret = sasl_encode( sasl_context, (char *)buf, len,
00166                         (SASL_CONST char **)&dst->buf_base,
00167                         &tmpsize );
00168 
00169        dst->buf_size = tmpsize;
00170        dst->buf_end = dst->buf_size;
00171 
00172        if ( ret != SASL_OK ) {
00173               ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
00174                             "sb_sasl_cyrus_encode: failed to encode packet: %s\n",
00175                             sasl_errstring( ret, NULL, NULL ) );
00176               return -1;
00177        }
00178 
00179        return 0;
00180 }
00181 
00182 static ber_int_t
00183 sb_sasl_cyrus_decode(
00184        struct sb_sasl_generic_data *p,
00185        const Sockbuf_Buf *src,
00186        Sockbuf_Buf *dst)
00187 {
00188        sasl_conn_t *sasl_context = (sasl_conn_t *)p->ops_private;
00189        ber_int_t ret;
00190        unsigned tmpsize = dst->buf_size;
00191 
00192        ret = sasl_decode( sasl_context,
00193                         src->buf_base, src->buf_end,
00194                         (SASL_CONST char **)&dst->buf_base,
00195                         (unsigned *)&tmpsize );
00196 
00197 
00198        dst->buf_size = tmpsize;
00199        dst->buf_end = dst->buf_size;
00200 
00201        if ( ret != SASL_OK ) {
00202               ber_log_printf( LDAP_DEBUG_ANY, p->sbiod->sbiod_sb->sb_debug,
00203                             "sb_sasl_cyrus_decode: failed to decode packet: %s\n",
00204                             sasl_errstring( ret, NULL, NULL ) );
00205               return -1;
00206        }
00207 
00208        return 0;
00209 }
00210 
00211 static void
00212 sb_sasl_cyrus_reset_buf(
00213        struct sb_sasl_generic_data *p,
00214        Sockbuf_Buf *buf)
00215 {
00216 #if SASL_VERSION_MAJOR >= 2
00217        ber_pvt_sb_buf_init( buf );
00218 #else
00219        ber_pvt_sb_buf_destroy( buf );
00220 #endif
00221 }
00222 
00223 static void
00224 sb_sasl_cyrus_fini(
00225        struct sb_sasl_generic_data *p)
00226 {
00227 #if SASL_VERSION_MAJOR >= 2
00228        /*
00229         * SASLv2 encode/decode buffers are managed by
00230         * libsasl2. Ensure they are not freed by liblber.
00231         */
00232        p->buf_in.buf_base = NULL;
00233        p->buf_out.buf_base = NULL;
00234 #endif
00235 }
00236 
00237 static const struct sb_sasl_generic_ops sb_sasl_cyrus_ops = {
00238        sb_sasl_cyrus_init,
00239        sb_sasl_cyrus_encode,
00240        sb_sasl_cyrus_decode,
00241        sb_sasl_cyrus_reset_buf,
00242        sb_sasl_cyrus_fini
00243  };
00244 
00245 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
00246 {
00247        struct sb_sasl_generic_install install_arg;
00248 
00249        install_arg.ops             = &sb_sasl_cyrus_ops;
00250        install_arg.ops_private = ctx_arg;
00251 
00252        return ldap_pvt_sasl_generic_install( sb, &install_arg );
00253 }
00254 
00255 void ldap_pvt_sasl_remove( Sockbuf *sb )
00256 {
00257        ldap_pvt_sasl_generic_remove( sb );
00258 }
00259 
00260 static int
00261 sasl_err2ldap( int saslerr )
00262 {
00263        int rc;
00264 
00265        /* map SASL errors to LDAP API errors returned by:
00266         *     sasl_client_new()
00267         *            SASL_OK, SASL_NOMECH, SASL_NOMEM
00268         *     sasl_client_start()
00269         *            SASL_OK, SASL_NOMECH, SASL_NOMEM, SASL_INTERACT
00270         *     sasl_client_step()
00271         *            SASL_OK, SASL_INTERACT, SASL_BADPROT, SASL_BADSERV
00272         */
00273 
00274        switch (saslerr) {
00275               case SASL_CONTINUE:
00276                      rc = LDAP_MORE_RESULTS_TO_RETURN;
00277                      break;
00278               case SASL_INTERACT:
00279                      rc = LDAP_LOCAL_ERROR;
00280                      break;
00281               case SASL_OK:
00282                      rc = LDAP_SUCCESS;
00283                      break;
00284               case SASL_NOMEM:
00285                      rc = LDAP_NO_MEMORY;
00286                      break;
00287               case SASL_NOMECH:
00288                      rc = LDAP_AUTH_UNKNOWN;
00289                      break;
00290               case SASL_BADPROT:
00291                      rc = LDAP_DECODING_ERROR;
00292                      break;
00293               case SASL_BADSERV:
00294                      rc = LDAP_AUTH_UNKNOWN;
00295                      break;
00296 
00297               /* other codes */
00298               case SASL_BADAUTH:
00299                      rc = LDAP_AUTH_UNKNOWN;
00300                      break;
00301               case SASL_NOAUTHZ:
00302                      rc = LDAP_PARAM_ERROR;
00303                      break;
00304               case SASL_FAIL:
00305                      rc = LDAP_LOCAL_ERROR;
00306                      break;
00307               case SASL_TOOWEAK:
00308               case SASL_ENCRYPT:
00309                      rc = LDAP_AUTH_UNKNOWN;
00310                      break;
00311               default:
00312                      rc = LDAP_LOCAL_ERROR;
00313                      break;
00314        }
00315 
00316        assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
00317        return rc;
00318 }
00319 
00320 int
00321 ldap_int_sasl_open(
00322        LDAP *ld, 
00323        LDAPConn *lc,
00324        const char * host )
00325 {
00326        int rc;
00327        sasl_conn_t *ctx;
00328 
00329        assert( lc->lconn_sasl_authctx == NULL );
00330 
00331        if ( host == NULL ) {
00332               ld->ld_errno = LDAP_LOCAL_ERROR;
00333               return ld->ld_errno;
00334        }
00335 
00336        if ( ldap_int_sasl_init() ) {
00337               ld->ld_errno = LDAP_LOCAL_ERROR;
00338               return ld->ld_errno;
00339        }
00340 
00341 #if SASL_VERSION_MAJOR >= 2
00342        rc = sasl_client_new( "ldap", host, NULL, NULL,
00343               client_callbacks, 0, &ctx );
00344 #else
00345        rc = sasl_client_new( "ldap", host, client_callbacks,
00346               SASL_SECURITY_LAYER, &ctx );
00347 #endif
00348 
00349        if ( rc != SASL_OK ) {
00350               ld->ld_errno = sasl_err2ldap( rc );
00351               return ld->ld_errno;
00352        }
00353 
00354        Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n",
00355               host, 0, 0 );
00356 
00357        lc->lconn_sasl_authctx = ctx;
00358 
00359        return LDAP_SUCCESS;
00360 }
00361 
00362 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
00363 {
00364        sasl_conn_t *ctx = lc->lconn_sasl_authctx;
00365 
00366        if( ctx != NULL ) {
00367               sasl_dispose( &ctx );
00368               if ( lc->lconn_sasl_sockctx &&
00369                      lc->lconn_sasl_authctx != lc->lconn_sasl_sockctx ) {
00370                      ctx = lc->lconn_sasl_sockctx;
00371                      sasl_dispose( &ctx );
00372               }
00373               lc->lconn_sasl_sockctx = NULL;
00374               lc->lconn_sasl_authctx = NULL;
00375        }
00376 
00377        return LDAP_SUCCESS;
00378 }
00379 
00380 int
00381 ldap_int_sasl_bind(
00382        LDAP                 *ld,
00383        const char           *dn,
00384        const char           *mechs,
00385        LDAPControl          **sctrls,
00386        LDAPControl          **cctrls,
00387        unsigned             flags,
00388        LDAP_SASL_INTERACT_PROC *interact,
00389        void                 *defaults,
00390        LDAPMessage          *result,
00391        const char           **rmech,
00392        int                         *msgid )
00393 {
00394        const char           *mech;
00395        sasl_ssf_t           *ssf;
00396        sasl_conn_t          *ctx;
00397        sasl_interact_t *prompts = NULL;
00398        struct berval ccred = BER_BVNULL;
00399        int saslrc, rc;
00400        unsigned credlen;
00401 
00402        Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
00403               mechs ? mechs : "<null>", 0, 0 );
00404 
00405        /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
00406        if (ld->ld_version < LDAP_VERSION3) {
00407               ld->ld_errno = LDAP_NOT_SUPPORTED;
00408               return ld->ld_errno;
00409        }
00410 
00411        /* Starting a Bind */
00412        if ( !result ) {
00413               const char *pmech = NULL;
00414               sasl_conn_t   *oldctx;
00415               ber_socket_t         sd;
00416               void   *ssl;
00417 
00418               rc = 0;
00419               LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
00420               ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
00421 
00422               if ( sd == AC_SOCKET_INVALID || !ld->ld_defconn ) {
00423                      /* not connected yet */
00424 
00425                      rc = ldap_open_defconn( ld );
00426 
00427                      if ( rc == 0 ) {
00428                             ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb,
00429                                    LBER_SB_OPT_GET_FD, &sd );
00430 
00431                             if( sd == AC_SOCKET_INVALID ) {
00432                                    ld->ld_errno = LDAP_LOCAL_ERROR;
00433                                    rc = ld->ld_errno;
00434                             }
00435                      }
00436               }
00437               if ( rc == 0 && ld->ld_defconn &&
00438                      ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING ) {
00439                      rc = ldap_int_check_async_open( ld, sd );
00440               }
00441               LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
00442               if( rc != 0 ) return ld->ld_errno;
00443 
00444               oldctx = ld->ld_defconn->lconn_sasl_authctx;
00445 
00446               /* If we already have an authentication context, clear it out */
00447               if( oldctx ) {
00448                      if ( oldctx != ld->ld_defconn->lconn_sasl_sockctx ) {
00449                             sasl_dispose( &oldctx );
00450                      }
00451                      ld->ld_defconn->lconn_sasl_authctx = NULL;
00452               }
00453 
00454               {
00455                      char *saslhost;
00456                      int nocanon = (int)LDAP_BOOL_GET( &ld->ld_options,
00457                             LDAP_BOOL_SASL_NOCANON );
00458 
00459                      /* If we don't need to canonicalize just use the host
00460                       * from the LDAP URI.
00461                       */
00462                      if ( nocanon )
00463                             saslhost = ld->ld_defconn->lconn_server->lud_host;
00464                      else 
00465                             saslhost = ldap_host_connected_to( ld->ld_defconn->lconn_sb,
00466                             "localhost" );
00467                      rc = ldap_int_sasl_open( ld, ld->ld_defconn, saslhost );
00468                      if ( !nocanon )
00469                             LDAP_FREE( saslhost );
00470               }
00471 
00472               if ( rc != LDAP_SUCCESS ) return rc;
00473 
00474               ctx = ld->ld_defconn->lconn_sasl_authctx;
00475 
00476 #ifdef HAVE_TLS
00477               /* Check for TLS */
00478               ssl = ldap_pvt_tls_sb_ctx( ld->ld_defconn->lconn_sb );
00479               if ( ssl ) {
00480                      struct berval authid = BER_BVNULL;
00481                      ber_len_t fac;
00482 
00483                      fac = ldap_pvt_tls_get_strength( ssl );
00484                      /* failure is OK, we just can't use SASL EXTERNAL */
00485                      (void) ldap_pvt_tls_get_my_dn( ssl, &authid, NULL, 0 );
00486 
00487                      (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid.bv_val, fac );
00488                      LDAP_FREE( authid.bv_val );
00489               }
00490 #endif
00491 
00492 #if !defined(_WIN32)
00493               /* Check for local */
00494               if ( ldap_pvt_url_scheme2proto(
00495                      ld->ld_defconn->lconn_server->lud_scheme ) == LDAP_PROTO_IPC )
00496               {
00497                      char authid[sizeof("gidNumber=4294967295+uidNumber=4294967295,"
00498                             "cn=peercred,cn=external,cn=auth")];
00499                      sprintf( authid, "gidNumber=%u+uidNumber=%u,"
00500                             "cn=peercred,cn=external,cn=auth",
00501                             getegid(), geteuid() );
00502                      (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid,
00503                             LDAP_PVT_SASL_LOCAL_SSF );
00504               }
00505 #endif
00506 
00507               /* (re)set security properties */
00508               sasl_setprop( ctx, SASL_SEC_PROPS,
00509                      &ld->ld_options.ldo_sasl_secprops );
00510 
00511               mech = NULL;
00512 
00513               do {
00514                      saslrc = sasl_client_start( ctx,
00515                             mechs,
00516 #if SASL_VERSION_MAJOR < 2
00517                             NULL,
00518 #endif
00519                             &prompts,
00520                             (SASL_CONST char **)&ccred.bv_val,
00521                             &credlen,
00522                             &mech );
00523 
00524                      if( pmech == NULL && mech != NULL ) {
00525                             pmech = mech;
00526                             *rmech = mech;
00527 
00528                             if( flags != LDAP_SASL_QUIET ) {
00529                                    fprintf(stderr,
00530                                           "SASL/%s authentication started\n",
00531                                           pmech );
00532                             }
00533                      }
00534 
00535                      if( saslrc == SASL_INTERACT ) {
00536                             int res;
00537                             if( !interact ) break;
00538                             res = (interact)( ld, flags, defaults, prompts );
00539 
00540                             if( res != LDAP_SUCCESS ) break;
00541                      }
00542               } while ( saslrc == SASL_INTERACT );
00543               rc = LDAP_SASL_BIND_IN_PROGRESS;
00544 
00545        } else {
00546               /* continuing an in-progress Bind */
00547               struct berval *scred = NULL;
00548 
00549               ctx = ld->ld_defconn->lconn_sasl_authctx;
00550 
00551               rc = ldap_parse_sasl_bind_result( ld, result, &scred, 0 );
00552               if ( rc != LDAP_SUCCESS )
00553                      goto done;
00554 
00555               rc = ldap_result2error( ld, result, 0 );
00556               if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
00557                      if( scred ) {
00558                             /* and server provided us with data? */
00559                             Debug( LDAP_DEBUG_TRACE,
00560                                    "ldap_int_sasl_bind: rc=%d len=%ld\n",
00561                                    rc, scred ? (long) scred->bv_len : -1L, 0 );
00562                             ber_bvfree( scred );
00563                             scred = NULL;
00564                      }
00565                      goto done;
00566               }
00567 
00568               mech = *rmech;
00569               if ( rc == LDAP_SUCCESS && mech == NULL )
00570                      goto success;
00571 
00572               do {
00573                      if( ! scred ) {
00574                             /* no data! */
00575                             Debug( LDAP_DEBUG_TRACE,
00576                                    "ldap_int_sasl_bind: no data in step!\n",
00577                                    0, 0, 0 );
00578                      }
00579 
00580                      saslrc = sasl_client_step( ctx,
00581                             (scred == NULL) ? NULL : scred->bv_val,
00582                             (scred == NULL) ? 0 : scred->bv_len,
00583                             &prompts,
00584                             (SASL_CONST char **)&ccred.bv_val,
00585                             &credlen );
00586 
00587                      Debug( LDAP_DEBUG_TRACE, "sasl_client_step: %d\n",
00588                             saslrc, 0, 0 );
00589 
00590                      if( saslrc == SASL_INTERACT ) {
00591                             int res;
00592                             if( !interact ) break;
00593                             res = (interact)( ld, flags, defaults, prompts );
00594                             if( res != LDAP_SUCCESS ) break;
00595                      }
00596               } while ( saslrc == SASL_INTERACT );
00597 
00598               ber_bvfree( scred );
00599        }
00600 
00601        if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
00602               rc = ld->ld_errno = sasl_err2ldap( saslrc );
00603 #if SASL_VERSION_MAJOR >= 2
00604               if ( ld->ld_error ) {
00605                      LDAP_FREE( ld->ld_error );
00606               }
00607               ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
00608 #endif
00609               goto done;
00610        }
00611 
00612        if ( saslrc == SASL_OK )
00613               *rmech = NULL;
00614 
00615        ccred.bv_len = credlen;
00616 
00617        if ( rc == LDAP_SASL_BIND_IN_PROGRESS ) {
00618               rc = ldap_sasl_bind( ld, dn, mech, &ccred, sctrls, cctrls, msgid );
00619 
00620               if ( ccred.bv_val != NULL ) {
00621 #if SASL_VERSION_MAJOR < 2
00622                      LDAP_FREE( ccred.bv_val );
00623 #endif
00624                      ccred.bv_val = NULL;
00625               }
00626               if ( rc == LDAP_SUCCESS )
00627                      rc = LDAP_SASL_BIND_IN_PROGRESS;
00628               goto done;
00629        }
00630 
00631 success:
00632        /* Conversation was completed successfully by now */
00633        if( flags != LDAP_SASL_QUIET ) {
00634               char *data;
00635               saslrc = sasl_getprop( ctx, SASL_USERNAME,
00636                      (SASL_CONST void **)(char *) &data );
00637               if( saslrc == SASL_OK && data && *data ) {
00638                      fprintf( stderr, "SASL username: %s\n", data );
00639               }
00640 
00641 #if SASL_VERSION_MAJOR < 2
00642               saslrc = sasl_getprop( ctx, SASL_REALM,
00643                      (SASL_CONST void **) &data );
00644               if( saslrc == SASL_OK && data && *data ) {
00645                      fprintf( stderr, "SASL realm: %s\n", data );
00646               }
00647 #endif
00648        }
00649 
00650        ssf = NULL;
00651        saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **)(char *) &ssf );
00652        if( saslrc == SASL_OK ) {
00653               if( flags != LDAP_SASL_QUIET ) {
00654                      fprintf( stderr, "SASL SSF: %lu\n",
00655                             (unsigned long) *ssf );
00656               }
00657 
00658               if( ssf && *ssf ) {
00659                      if ( ld->ld_defconn->lconn_sasl_sockctx ) {
00660                             sasl_conn_t   *oldctx = ld->ld_defconn->lconn_sasl_sockctx;
00661                             sasl_dispose( &oldctx );
00662                             ldap_pvt_sasl_remove( ld->ld_defconn->lconn_sb );
00663                      }
00664                      ldap_pvt_sasl_install( ld->ld_defconn->lconn_sb, ctx );
00665                      ld->ld_defconn->lconn_sasl_sockctx = ctx;
00666 
00667                      if( flags != LDAP_SASL_QUIET ) {
00668                             fprintf( stderr, "SASL data security layer installed.\n" );
00669                      }
00670               }
00671        }
00672        ld->ld_defconn->lconn_sasl_authctx = ctx;
00673 
00674 done:
00675        return rc;
00676 }
00677 
00678 int
00679 ldap_int_sasl_external(
00680        LDAP *ld,
00681        LDAPConn *conn,
00682        const char * authid,
00683        ber_len_t ssf )
00684 {
00685        int sc;
00686        sasl_conn_t *ctx;
00687 #if SASL_VERSION_MAJOR < 2
00688        sasl_external_properties_t extprops;
00689 #else
00690        sasl_ssf_t sasl_ssf = ssf;
00691 #endif
00692 
00693        ctx = conn->lconn_sasl_authctx;
00694 
00695        if ( ctx == NULL ) {
00696               return LDAP_LOCAL_ERROR;
00697        }
00698    
00699 #if SASL_VERSION_MAJOR >= 2
00700        sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf );
00701        if ( sc == SASL_OK )
00702               sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid );
00703 #else
00704        memset( &extprops, '\0', sizeof(extprops) );
00705        extprops.ssf = ssf;
00706        extprops.auth_id = (char *) authid;
00707 
00708        sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
00709               (void *) &extprops );
00710 #endif
00711 
00712        if ( sc != SASL_OK ) {
00713               return LDAP_LOCAL_ERROR;
00714        }
00715 
00716        return LDAP_SUCCESS;
00717 }
00718 
00719 
00720 #define GOT_MINSSF   1
00721 #define       GOT_MAXSSF    2
00722 #define       GOT_MAXBUF    4
00723 
00724 static struct {
00725        struct berval key;
00726        int sflag;
00727        int ival;
00728        int idef;
00729 } sprops[] = {
00730        { BER_BVC("none"), 0, 0, 0 },
00731        { BER_BVC("nodict"), SASL_SEC_NODICTIONARY, 0, 0 },
00732        { BER_BVC("noplain"), SASL_SEC_NOPLAINTEXT, 0, 0 },
00733        { BER_BVC("noactive"), SASL_SEC_NOACTIVE, 0, 0 },
00734        { BER_BVC("passcred"), SASL_SEC_PASS_CREDENTIALS, 0, 0 },
00735        { BER_BVC("forwardsec"), SASL_SEC_FORWARD_SECRECY, 0, 0 },
00736        { BER_BVC("noanonymous"), SASL_SEC_NOANONYMOUS, 0, 0 },
00737        { BER_BVC("minssf="), 0, GOT_MINSSF, 0 },
00738        { BER_BVC("maxssf="), 0, GOT_MAXSSF, INT_MAX },
00739        { BER_BVC("maxbufsize="), 0, GOT_MAXBUF, 65536 },
00740        { BER_BVNULL, 0, 0, 0 }
00741 };
00742 
00743 void ldap_pvt_sasl_secprops_unparse(
00744        sasl_security_properties_t *secprops,
00745        struct berval *out )
00746 {
00747        int i, l = 0;
00748        int comma;
00749        char *ptr;
00750 
00751        if ( secprops == NULL || out == NULL ) {
00752               return;
00753        }
00754 
00755        comma = 0;
00756        for ( i=0; !BER_BVISNULL( &sprops[i].key ); i++ ) {
00757               if ( sprops[i].ival ) {
00758                      int v = 0;
00759 
00760                      switch( sprops[i].ival ) {
00761                      case GOT_MINSSF: v = secprops->min_ssf; break;
00762                      case GOT_MAXSSF: v = secprops->max_ssf; break;
00763                      case GOT_MAXBUF: v = secprops->maxbufsize; break;
00764                      }
00765                      /* It is the default, ignore it */
00766                      if ( v == sprops[i].idef ) continue;
00767 
00768                      l += sprops[i].key.bv_len + 24;
00769               } else if ( sprops[i].sflag ) {
00770                      if ( sprops[i].sflag & secprops->security_flags ) {
00771                             l += sprops[i].key.bv_len;
00772                      }
00773               } else if ( secprops->security_flags == 0 ) {
00774                      l += sprops[i].key.bv_len;
00775               }
00776               if ( comma ) l++;
00777               comma = 1;
00778        }
00779        l++;
00780 
00781        out->bv_val = LDAP_MALLOC( l );
00782        if ( out->bv_val == NULL ) {
00783               out->bv_len = 0;
00784               return;
00785        }
00786 
00787        ptr = out->bv_val;
00788        comma = 0;
00789        for ( i=0; !BER_BVISNULL( &sprops[i].key ); i++ ) {
00790               if ( sprops[i].ival ) {
00791                      int v = 0;
00792 
00793                      switch( sprops[i].ival ) {
00794                      case GOT_MINSSF: v = secprops->min_ssf; break;
00795                      case GOT_MAXSSF: v = secprops->max_ssf; break;
00796                      case GOT_MAXBUF: v = secprops->maxbufsize; break;
00797                      }
00798                      /* It is the default, ignore it */
00799                      if ( v == sprops[i].idef ) continue;
00800 
00801                      if ( comma ) *ptr++ = ',';
00802                      ptr += sprintf(ptr, "%s%d", sprops[i].key.bv_val, v );
00803                      comma = 1;
00804               } else if ( sprops[i].sflag ) {
00805                      if ( sprops[i].sflag & secprops->security_flags ) {
00806                             if ( comma ) *ptr++ = ',';
00807                             ptr += sprintf(ptr, "%s", sprops[i].key.bv_val );
00808                             comma = 1;
00809                      }
00810               } else if ( secprops->security_flags == 0 ) {
00811                      if ( comma ) *ptr++ = ',';
00812                      ptr += sprintf(ptr, "%s", sprops[i].key.bv_val );
00813                      comma = 1;
00814               }
00815        }
00816        out->bv_len = ptr - out->bv_val;
00817 }
00818 
00819 int ldap_pvt_sasl_secprops(
00820        const char *in,
00821        sasl_security_properties_t *secprops )
00822 {
00823        unsigned i, j, l;
00824        char **props;
00825        unsigned sflags = 0;
00826        int got_sflags = 0;
00827        sasl_ssf_t max_ssf = 0;
00828        int got_max_ssf = 0;
00829        sasl_ssf_t min_ssf = 0;
00830        int got_min_ssf = 0;
00831        unsigned maxbufsize = 0;
00832        int got_maxbufsize = 0;
00833 
00834        if( secprops == NULL ) {
00835               return LDAP_PARAM_ERROR;
00836        }
00837        props = ldap_str2charray( in, "," );
00838        if( props == NULL ) {
00839               return LDAP_PARAM_ERROR;
00840        }
00841 
00842        for( i=0; props[i]; i++ ) {
00843               l = strlen( props[i] );
00844               for ( j=0; !BER_BVISNULL( &sprops[j].key ); j++ ) {
00845                      if ( l < sprops[j].key.bv_len ) continue;
00846                      if ( strncasecmp( props[i], sprops[j].key.bv_val,
00847                             sprops[j].key.bv_len )) continue;
00848                      if ( sprops[j].ival ) {
00849                             unsigned v;
00850                             char *next = NULL;
00851                             if ( !isdigit( (unsigned char)props[i][sprops[j].key.bv_len] ))
00852                                    continue;
00853                             v = strtoul( &props[i][sprops[j].key.bv_len], &next, 10 );
00854                             if ( next == &props[i][sprops[j].key.bv_len] || next[0] != '\0' ) continue;
00855                             switch( sprops[j].ival ) {
00856                             case GOT_MINSSF:
00857                                    min_ssf = v; got_min_ssf++; break;
00858                             case GOT_MAXSSF:
00859                                    max_ssf = v; got_max_ssf++; break;
00860                             case GOT_MAXBUF:
00861                                    maxbufsize = v; got_maxbufsize++; break;
00862                             }
00863                      } else {
00864                             if ( props[i][sprops[j].key.bv_len] ) continue;
00865                             if ( sprops[j].sflag )
00866                                    sflags |= sprops[j].sflag;
00867                             else
00868                                    sflags = 0;
00869                             got_sflags++;
00870                      }
00871                      break;
00872               }
00873               if ( BER_BVISNULL( &sprops[j].key )) {
00874                      ldap_charray_free( props );
00875                      return LDAP_NOT_SUPPORTED;
00876               }
00877        }
00878 
00879        if(got_sflags) {
00880               secprops->security_flags = sflags;
00881        }
00882        if(got_min_ssf) {
00883               secprops->min_ssf = min_ssf;
00884        }
00885        if(got_max_ssf) {
00886               secprops->max_ssf = max_ssf;
00887        }
00888        if(got_maxbufsize) {
00889               secprops->maxbufsize = maxbufsize;
00890        }
00891 
00892        ldap_charray_free( props );
00893        return LDAP_SUCCESS;
00894 }
00895 
00896 int
00897 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
00898 {
00899        int rc;
00900 
00901        switch( option ) {
00902        case LDAP_OPT_X_SASL_SECPROPS:
00903               rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
00904               if( rc == LDAP_SUCCESS ) return 0;
00905        }
00906 
00907        return -1;
00908 }
00909 
00910 int
00911 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
00912 {
00913        if ( option == LDAP_OPT_X_SASL_MECHLIST ) {
00914               if ( ldap_int_sasl_init() )
00915                      return -1;
00916               *(char ***)arg = (char **)sasl_global_listmech();
00917               return 0;
00918        }
00919 
00920        if ( ld == NULL )
00921               return -1;
00922 
00923        switch ( option ) {
00924               case LDAP_OPT_X_SASL_MECH: {
00925                      *(char **)arg = ld->ld_options.ldo_def_sasl_mech
00926                             ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL;
00927               } break;
00928               case LDAP_OPT_X_SASL_REALM: {
00929                      *(char **)arg = ld->ld_options.ldo_def_sasl_realm
00930                             ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL;
00931               } break;
00932               case LDAP_OPT_X_SASL_AUTHCID: {
00933                      *(char **)arg = ld->ld_options.ldo_def_sasl_authcid
00934                             ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL;
00935               } break;
00936               case LDAP_OPT_X_SASL_AUTHZID: {
00937                      *(char **)arg = ld->ld_options.ldo_def_sasl_authzid
00938                             ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL;
00939               } break;
00940 
00941               case LDAP_OPT_X_SASL_SSF: {
00942                      int sc;
00943                      sasl_ssf_t    *ssf;
00944                      sasl_conn_t *ctx;
00945 
00946                      if( ld->ld_defconn == NULL ) {
00947                             return -1;
00948                      }
00949 
00950                      ctx = ld->ld_defconn->lconn_sasl_sockctx;
00951 
00952                      if ( ctx == NULL ) {
00953                             return -1;
00954                      }
00955 
00956                      sc = sasl_getprop( ctx, SASL_SSF,
00957                             (SASL_CONST void **)(char *) &ssf );
00958 
00959                      if ( sc != SASL_OK ) {
00960                             return -1;
00961                      }
00962 
00963                      *(ber_len_t *)arg = *ssf;
00964               } break;
00965 
00966               case LDAP_OPT_X_SASL_SSF_EXTERNAL:
00967                      /* this option is write only */
00968                      return -1;
00969 
00970               case LDAP_OPT_X_SASL_SSF_MIN:
00971                      *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
00972                      break;
00973               case LDAP_OPT_X_SASL_SSF_MAX:
00974                      *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
00975                      break;
00976               case LDAP_OPT_X_SASL_MAXBUFSIZE:
00977                      *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
00978                      break;
00979               case LDAP_OPT_X_SASL_NOCANON:
00980                      *(int *)arg = (int) LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON );
00981                      break;
00982 
00983               case LDAP_OPT_X_SASL_USERNAME: {
00984                      int sc;
00985                      char *username;
00986                      sasl_conn_t *ctx;
00987 
00988                      if( ld->ld_defconn == NULL ) {
00989                             return -1;
00990                      }
00991 
00992                      ctx = ld->ld_defconn->lconn_sasl_authctx;
00993 
00994                      if ( ctx == NULL ) {
00995                             return -1;
00996                      }
00997 
00998                      sc = sasl_getprop( ctx, SASL_USERNAME,
00999                             (SASL_CONST void **)(char **) &username );
01000 
01001                      if ( sc != SASL_OK ) {
01002                             return -1;
01003                      }
01004 
01005                      *(char **)arg = username ? LDAP_STRDUP( username ) : NULL;
01006               } break;
01007 
01008               case LDAP_OPT_X_SASL_SECPROPS:
01009                      /* this option is write only */
01010                      return -1;
01011 
01012 #ifdef SASL_GSS_CREDS
01013               case LDAP_OPT_X_SASL_GSS_CREDS: {
01014                      sasl_conn_t *ctx;
01015                      int sc;
01016 
01017                      if ( ld->ld_defconn == NULL )
01018                             return -1;
01019 
01020                      ctx = ld->ld_defconn->lconn_sasl_authctx;
01021                      if ( ctx == NULL )
01022                             return -1;
01023 
01024                      sc = sasl_getprop( ctx, SASL_GSS_CREDS, arg );
01025                      if ( sc != SASL_OK )
01026                             return -1;
01027                      }
01028                      break;
01029 #endif
01030 
01031               default:
01032                      return -1;
01033        }
01034        return 0;
01035 }
01036 
01037 int
01038 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
01039 {
01040        if ( ld == NULL )
01041               return -1;
01042 
01043        if ( arg == NULL && option != LDAP_OPT_X_SASL_NOCANON )
01044               return -1;
01045 
01046        switch ( option ) {
01047        case LDAP_OPT_X_SASL_SSF:
01048        case LDAP_OPT_X_SASL_USERNAME:
01049               /* This option is read-only */
01050               return -1;
01051 
01052        case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
01053               int sc;
01054 #if SASL_VERSION_MAJOR < 2
01055               sasl_external_properties_t extprops;
01056 #else
01057               sasl_ssf_t sasl_ssf;
01058 #endif
01059               sasl_conn_t *ctx;
01060 
01061               if( ld->ld_defconn == NULL ) {
01062                      return -1;
01063               }
01064 
01065               ctx = ld->ld_defconn->lconn_sasl_authctx;
01066 
01067               if ( ctx == NULL ) {
01068                      return -1;
01069               }
01070 
01071 #if SASL_VERSION_MAJOR >= 2
01072               sasl_ssf = * (ber_len_t *)arg;
01073               sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &sasl_ssf);
01074 #else
01075               memset(&extprops, 0L, sizeof(extprops));
01076 
01077               extprops.ssf = * (ber_len_t *) arg;
01078 
01079               sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
01080                      (void *) &extprops );
01081 #endif
01082 
01083               if ( sc != SASL_OK ) {
01084                      return -1;
01085               }
01086               } break;
01087 
01088        case LDAP_OPT_X_SASL_SSF_MIN:
01089               ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
01090               break;
01091        case LDAP_OPT_X_SASL_SSF_MAX:
01092               ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
01093               break;
01094        case LDAP_OPT_X_SASL_MAXBUFSIZE:
01095               ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
01096               break;
01097        case LDAP_OPT_X_SASL_NOCANON:
01098               if ( arg == LDAP_OPT_OFF ) {
01099                      LDAP_BOOL_CLR(&ld->ld_options, LDAP_BOOL_SASL_NOCANON );
01100               } else {
01101                      LDAP_BOOL_SET(&ld->ld_options, LDAP_BOOL_SASL_NOCANON );
01102               }
01103               break;
01104 
01105        case LDAP_OPT_X_SASL_SECPROPS: {
01106               int sc;
01107               sc = ldap_pvt_sasl_secprops( (char *) arg,
01108                      &ld->ld_options.ldo_sasl_secprops );
01109 
01110               return sc == LDAP_SUCCESS ? 0 : -1;
01111               }
01112 
01113 #ifdef SASL_GSS_CREDS
01114        case LDAP_OPT_X_SASL_GSS_CREDS: {
01115               sasl_conn_t *ctx;
01116               int sc;
01117 
01118               if ( ld->ld_defconn == NULL )
01119                      return -1;
01120 
01121               ctx = ld->ld_defconn->lconn_sasl_authctx;
01122               if ( ctx == NULL )
01123                      return -1;
01124 
01125               sc = sasl_setprop( ctx, SASL_GSS_CREDS, arg );
01126               if ( sc != SASL_OK )
01127                      return -1;
01128               }
01129               break;
01130 #endif
01131 
01132        default:
01133               return -1;
01134        }
01135        return 0;
01136 }
01137 
01138 #ifdef LDAP_R_COMPILE
01139 #define LDAP_DEBUG_R_SASL
01140 void *ldap_pvt_sasl_mutex_new(void)
01141 {
01142        ldap_pvt_thread_mutex_t *mutex;
01143 
01144        mutex = (ldap_pvt_thread_mutex_t *) LDAP_CALLOC( 1,
01145               sizeof(ldap_pvt_thread_mutex_t) );
01146 
01147        if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
01148               return mutex;
01149        }
01150 #ifndef LDAP_DEBUG_R_SASL
01151        assert( 0 );
01152 #endif /* !LDAP_DEBUG_R_SASL */
01153        return NULL;
01154 }
01155 
01156 int ldap_pvt_sasl_mutex_lock(void *mutex)
01157 {
01158 #ifdef LDAP_DEBUG_R_SASL
01159        if ( mutex == NULL ) {
01160               return SASL_OK;
01161        }
01162 #else /* !LDAP_DEBUG_R_SASL */
01163        assert( mutex != NULL );
01164 #endif /* !LDAP_DEBUG_R_SASL */
01165        return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
01166               ? SASL_FAIL : SASL_OK;
01167 }
01168 
01169 int ldap_pvt_sasl_mutex_unlock(void *mutex)
01170 {
01171 #ifdef LDAP_DEBUG_R_SASL
01172        if ( mutex == NULL ) {
01173               return SASL_OK;
01174        }
01175 #else /* !LDAP_DEBUG_R_SASL */
01176        assert( mutex != NULL );
01177 #endif /* !LDAP_DEBUG_R_SASL */
01178        return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
01179               ? SASL_FAIL : SASL_OK;
01180 }
01181 
01182 void ldap_pvt_sasl_mutex_dispose(void *mutex)
01183 {
01184 #ifdef LDAP_DEBUG_R_SASL
01185        if ( mutex == NULL ) {
01186               return;
01187        }
01188 #else /* !LDAP_DEBUG_R_SASL */
01189        assert( mutex != NULL );
01190 #endif /* !LDAP_DEBUG_R_SASL */
01191        (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
01192        LDAP_FREE( mutex );
01193 }
01194 #endif
01195 
01196 #else
01197 int ldap_int_sasl_init( void )
01198 { return LDAP_SUCCESS; }
01199 
01200 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
01201 { return LDAP_SUCCESS; }
01202 
01203 int
01204 ldap_int_sasl_bind(
01205        LDAP                 *ld,
01206        const char           *dn,
01207        const char           *mechs,
01208        LDAPControl          **sctrls,
01209        LDAPControl          **cctrls,
01210        unsigned             flags,
01211        LDAP_SASL_INTERACT_PROC *interact,
01212        void                 *defaults,
01213        LDAPMessage          *result,
01214        const char           **rmech,
01215        int                         *msgid )
01216 { return LDAP_NOT_SUPPORTED; }
01217 
01218 int
01219 ldap_int_sasl_external(
01220        LDAP *ld,
01221        LDAPConn *conn,
01222        const char * authid,
01223        ber_len_t ssf )
01224 { return LDAP_SUCCESS; }
01225 
01226 #endif /* HAVE_CYRUS_SASL */