Back to index

openldap  2.4.31
bind.c
Go to the documentation of this file.
00001 /* bind.c - decode an ldap bind operation and pass it to a backend db */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00017  * All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * provided that this notice is preserved and that due credit is given
00021  * to the University of Michigan at Ann Arbor. The name of the University
00022  * may not be used to endorse or promote products derived from this
00023  * software without specific prior written permission. This software
00024  * is provided ``as is'' without express or implied warranty.
00025  */
00026 
00027 #include "portable.h"
00028 
00029 #include <stdio.h>
00030 
00031 #include <ac/string.h>
00032 #include <ac/socket.h>
00033 
00034 #include "slap.h"
00035 
00036 int
00037 do_bind(
00038     Operation *op,
00039     SlapReply *rs )
00040 {
00041        BerElement *ber = op->o_ber;
00042        ber_int_t version;
00043        ber_tag_t method;
00044        struct berval mech = BER_BVNULL;
00045        struct berval dn = BER_BVNULL;
00046        ber_tag_t tag;
00047        Backend *be = NULL;
00048 
00049        Debug( LDAP_DEBUG_TRACE, "%s do_bind\n",
00050               op->o_log_prefix, 0, 0 );
00051 
00052        /*
00053         * Force the connection to "anonymous" until bind succeeds.
00054         */
00055        ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00056        if ( op->o_conn->c_sasl_bind_in_progress ) {
00057               be = op->o_conn->c_authz_backend;
00058        }
00059        if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
00060               /* log authorization identity demotion */
00061               Statslog( LDAP_DEBUG_STATS,
00062                      "%s BIND anonymous mech=implicit ssf=0\n",
00063                      op->o_log_prefix, 0, 0, 0, 0 );
00064        }
00065        connection2anonymous( op->o_conn );
00066        if ( op->o_conn->c_sasl_bind_in_progress ) {
00067               op->o_conn->c_authz_backend = be;
00068        }
00069        ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00070        if ( !BER_BVISNULL( &op->o_dn ) ) {
00071               /* NOTE: temporarily wasting few bytes
00072                * (until bind is completed), but saving
00073                * a couple of ch_free() and ch_strdup("") */ 
00074               op->o_dn.bv_val[0] = '\0';
00075               op->o_dn.bv_len = 0;
00076        }
00077        if ( !BER_BVISNULL( &op->o_ndn ) ) {
00078               op->o_ndn.bv_val[0] = '\0';
00079               op->o_ndn.bv_len = 0;
00080        }
00081 
00082        /*
00083         * Parse the bind request.  It looks like this:
00084         *
00085         *     BindRequest ::= SEQUENCE {
00086         *            version              INTEGER,              -- version
00087         *            name          DistinguishedName,    -- dn
00088         *            authentication       CHOICE {
00089         *                   simple        [0] OCTET STRING -- passwd
00090         *                   krbv42ldap    [1] OCTET STRING -- OBSOLETE
00091         *                   krbv42dsa     [2] OCTET STRING -- OBSOLETE
00092         *                   SASL          [3] SaslCredentials
00093         *            }
00094         *     }
00095         *
00096         *     SaslCredentials ::= SEQUENCE {
00097         *            mechanism         LDAPString,
00098         *            credentials       OCTET STRING OPTIONAL
00099         *     }
00100         */
00101 
00102        tag = ber_scanf( ber, "{imt" /*}*/, &version, &dn, &method );
00103 
00104        if ( tag == LBER_ERROR ) {
00105               Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n",
00106                      op->o_log_prefix, 0, 0 );
00107               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00108               rs->sr_err = SLAPD_DISCONNECT;
00109               goto cleanup;
00110        }
00111 
00112        op->o_protocol = version;
00113        op->orb_method = method;
00114 
00115        if( op->orb_method != LDAP_AUTH_SASL ) {
00116               tag = ber_scanf( ber, /*{*/ "m}", &op->orb_cred );
00117 
00118        } else {
00119               tag = ber_scanf( ber, "{m" /*}*/, &mech );
00120 
00121               if ( tag != LBER_ERROR ) {
00122                      ber_len_t len;
00123                      tag = ber_peek_tag( ber, &len );
00124 
00125                      if ( tag == LDAP_TAG_LDAPCRED ) { 
00126                             tag = ber_scanf( ber, "m", &op->orb_cred );
00127                      } else {
00128                             tag = LDAP_TAG_LDAPCRED;
00129                             BER_BVZERO( &op->orb_cred );
00130                      }
00131 
00132                      if ( tag != LBER_ERROR ) {
00133                             tag = ber_scanf( ber, /*{{*/ "}}" );
00134                      }
00135               }
00136        }
00137 
00138        if ( tag == LBER_ERROR ) {
00139               Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n",
00140                      op->o_log_prefix, 0, 0 );
00141               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00142               rs->sr_err = SLAPD_DISCONNECT;
00143               goto cleanup;
00144        }
00145 
00146        if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
00147               Debug( LDAP_DEBUG_ANY, "%s do_bind: get_ctrls failed\n",
00148                      op->o_log_prefix, 0, 0 );
00149               goto cleanup;
00150        } 
00151 
00152        /* We use the tmpmemctx here because it speeds up normalization.
00153         * However, we must dup with regular malloc when storing any
00154         * resulting DNs in the op or conn structures.
00155         */
00156        rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
00157               op->o_tmpmemctx );
00158        if ( rs->sr_err != LDAP_SUCCESS ) {
00159               Debug( LDAP_DEBUG_ANY, "%s do_bind: invalid dn (%s)\n",
00160                      op->o_log_prefix, dn.bv_val, 0 );
00161               send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
00162               goto cleanup;
00163        }
00164 
00165        Statslog( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" method=%ld\n",
00166            op->o_log_prefix, op->o_req_dn.bv_val,
00167               (unsigned long) op->orb_method, 0, 0 );
00168 
00169        if( op->orb_method == LDAP_AUTH_SASL ) {
00170               Debug( LDAP_DEBUG_TRACE, "do_bind: dn (%s) SASL mech %s\n",
00171                      op->o_req_dn.bv_val, mech.bv_val, NULL );
00172 
00173        } else {
00174               Debug( LDAP_DEBUG_TRACE,
00175                      "do_bind: version=%ld dn=\"%s\" method=%ld\n",
00176                      (unsigned long) version, op->o_req_dn.bv_val,
00177                      (unsigned long) op->orb_method );
00178        }
00179 
00180        if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
00181               Debug( LDAP_DEBUG_ANY, "%s do_bind: unknown version=%ld\n",
00182                      op->o_log_prefix, (unsigned long) version, 0 );
00183               send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
00184                      "requested protocol version not supported" );
00185               goto cleanup;
00186 
00187        } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) &&
00188               version < LDAP_VERSION3 )
00189        {
00190               send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
00191                      "historical protocol version requested, use LDAPv3 instead" );
00192               goto cleanup;
00193        }
00194 
00195        /*
00196         * we set connection version regardless of whether bind succeeds or not.
00197         */
00198        ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00199        op->o_conn->c_protocol = version;
00200        ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00201 
00202        op->orb_mech = mech;
00203 
00204        op->o_bd = frontendDB;
00205        rs->sr_err = frontendDB->be_bind( op, rs );
00206 
00207 cleanup:
00208        if ( rs->sr_err == LDAP_SUCCESS ) {
00209               if ( op->orb_method != LDAP_AUTH_SASL ) {
00210                      ber_dupbv( &op->o_conn->c_authmech, &mech );
00211               }
00212               op->o_conn->c_authtype = op->orb_method;
00213        }
00214 
00215        if( !BER_BVISNULL( &op->o_req_dn ) ) {
00216               slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx );
00217               BER_BVZERO( &op->o_req_dn );
00218        }
00219        if( !BER_BVISNULL( &op->o_req_ndn ) ) {
00220               slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
00221               BER_BVZERO( &op->o_req_ndn );
00222        }
00223 
00224        return rs->sr_err;
00225 }
00226 
00227 int
00228 fe_op_bind( Operation *op, SlapReply *rs )
00229 {
00230        BackendDB     *bd = op->o_bd;
00231 
00232        /* check for inappropriate controls */
00233        if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) {
00234               send_ldap_error( op, rs,
00235                      LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
00236                      "manageDSAit control inappropriate" );
00237               goto cleanup;
00238        }
00239 
00240        if ( op->orb_method == LDAP_AUTH_SASL ) {
00241               if ( op->o_protocol < LDAP_VERSION3 ) {
00242                      Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n",
00243                             (unsigned long)op->o_protocol, 0, 0 );
00244                      send_ldap_discon( op, rs,
00245                             LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" );
00246                      rs->sr_err = SLAPD_DISCONNECT;
00247                      goto cleanup;
00248               }
00249 
00250               if( BER_BVISNULL( &op->orb_mech ) || BER_BVISEMPTY( &op->orb_mech ) ) {
00251                      Debug( LDAP_DEBUG_ANY,
00252                             "do_bind: no sasl mechanism provided\n",
00253                             0, 0, 0 );
00254                      send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED,
00255                             "no SASL mechanism provided" );
00256                      goto cleanup;
00257               }
00258 
00259               /* check restrictions */
00260               if( backend_check_restrictions( op, rs, &op->orb_mech ) != LDAP_SUCCESS ) {
00261                      send_ldap_result( op, rs );
00262                      goto cleanup;
00263               }
00264 
00265               ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00266               if ( op->o_conn->c_sasl_bind_in_progress ) {
00267                      if( !bvmatch( &op->o_conn->c_sasl_bind_mech, &op->orb_mech ) ) {
00268                             /* mechanism changed between bind steps */
00269                             slap_sasl_reset(op->o_conn);
00270                      }
00271               } else {
00272                      ber_dupbv(&op->o_conn->c_sasl_bind_mech, &op->orb_mech);
00273               }
00274 
00275               /* Set the bindop for the benefit of in-directory SASL lookups */
00276               op->o_conn->c_sasl_bindop = op;
00277 
00278               ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00279 
00280               rs->sr_err = slap_sasl_bind( op, rs );
00281 
00282               goto cleanup;
00283 
00284        } else {
00285               /* Not SASL, cancel any in-progress bind */
00286               ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00287 
00288               if ( !BER_BVISNULL( &op->o_conn->c_sasl_bind_mech ) ) {
00289                      free( op->o_conn->c_sasl_bind_mech.bv_val );
00290                      BER_BVZERO( &op->o_conn->c_sasl_bind_mech );
00291               }
00292               op->o_conn->c_sasl_bind_in_progress = 0;
00293 
00294               slap_sasl_reset( op->o_conn );
00295               ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00296        }
00297 
00298        if ( op->orb_method == LDAP_AUTH_SIMPLE ) {
00299               BER_BVSTR( &op->orb_mech, "SIMPLE" );
00300               /* accept "anonymous" binds */
00301               if ( BER_BVISEMPTY( &op->orb_cred ) || BER_BVISEMPTY( &op->o_req_ndn ) ) {
00302                      rs->sr_err = LDAP_SUCCESS;
00303 
00304                      if( !BER_BVISEMPTY( &op->orb_cred ) &&
00305                             !( global_allows & SLAP_ALLOW_BIND_ANON_CRED ))
00306                      {
00307                             /* cred is not empty, disallow */
00308                             rs->sr_err = LDAP_INVALID_CREDENTIALS;
00309 
00310                      } else if ( !BER_BVISEMPTY( &op->o_req_ndn ) &&
00311                             !( global_allows & SLAP_ALLOW_BIND_ANON_DN ))
00312                      {
00313                             /* DN is not empty, disallow */
00314                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00315                             rs->sr_text =
00316                                    "unauthenticated bind (DN with no password) disallowed";
00317 
00318                      } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) {
00319                             /* disallow */
00320                             rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
00321                             rs->sr_text = "anonymous bind disallowed";
00322 
00323                      } else {
00324                             backend_check_restrictions( op, rs, &op->orb_mech );
00325                      }
00326 
00327                      /*
00328                       * we already forced connection to "anonymous",
00329                       * just need to send success
00330                       */
00331                      send_ldap_result( op, rs );
00332                      Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n",
00333                             op->o_protocol, 0, 0 );
00334                      goto cleanup;
00335 
00336               } else if ( global_disallows & SLAP_DISALLOW_BIND_SIMPLE ) {
00337                      /* disallow simple authentication */
00338                      rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00339                      rs->sr_text = "unwilling to perform simple authentication";
00340 
00341                      send_ldap_result( op, rs );
00342                      Debug( LDAP_DEBUG_TRACE,
00343                             "do_bind: v%d simple bind(%s) disallowed\n",
00344                             op->o_protocol, op->o_req_ndn.bv_val, 0 );
00345                      goto cleanup;
00346               }
00347 
00348        } else {
00349               rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
00350               rs->sr_text = "unknown authentication method";
00351 
00352               send_ldap_result( op, rs );
00353               Debug( LDAP_DEBUG_TRACE,
00354                      "do_bind: v%d unknown authentication method (%d)\n",
00355                      op->o_protocol, op->orb_method, 0 );
00356               goto cleanup;
00357        }
00358 
00359        /*
00360         * We could be serving multiple database backends.  Select the
00361         * appropriate one, or send a referral to our "referral server"
00362         * if we don't hold it.
00363         */
00364 
00365        if ( (op->o_bd = select_backend( &op->o_req_ndn, 0 )) == NULL ) {
00366               /* don't return referral for bind requests */
00367               /* noSuchObject is not allowed to be returned by bind */
00368               rs->sr_err = LDAP_INVALID_CREDENTIALS;
00369               op->o_bd = bd;
00370               send_ldap_result( op, rs );
00371               goto cleanup;
00372        }
00373 
00374        /* check restrictions */
00375        if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
00376               send_ldap_result( op, rs );
00377               goto cleanup;
00378        }
00379 
00380        if( op->o_bd->be_bind ) {
00381               op->o_conn->c_authz_cookie = NULL;
00382 
00383               rs->sr_err = (op->o_bd->be_bind)( op, rs );
00384 
00385               if ( rs->sr_err == 0 ) {
00386                      (void)fe_op_bind_success( op, rs );
00387 
00388               } else if ( !BER_BVISNULL( &op->orb_edn ) ) {
00389                      free( op->orb_edn.bv_val );
00390                      BER_BVZERO( &op->orb_edn );
00391               }
00392 
00393        } else {
00394               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00395                      "operation not supported within naming context" );
00396        }
00397 
00398 cleanup:;
00399        op->o_bd = bd;
00400        return rs->sr_err;
00401 }
00402 
00403 int
00404 fe_op_bind_success( Operation *op, SlapReply *rs )
00405 {
00406        ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00407 
00408        if( op->o_conn->c_authz_backend == NULL ) {
00409               op->o_conn->c_authz_backend = op->o_bd;
00410        }
00411 
00412        /* be_bind returns regular/global edn */
00413        if( !BER_BVISEMPTY( &op->orb_edn ) ) {
00414               op->o_conn->c_dn = op->orb_edn;
00415        } else {
00416               ber_dupbv(&op->o_conn->c_dn, &op->o_req_dn);
00417        }
00418 
00419        ber_dupbv( &op->o_conn->c_ndn, &op->o_req_ndn );
00420 
00421        /* op->o_conn->c_sb may be 0 for internal operations */
00422        if( !BER_BVISEMPTY( &op->o_conn->c_dn ) && op->o_conn->c_sb != 0 ) {
00423               ber_len_t max = sockbuf_max_incoming_auth;
00424               ber_sockbuf_ctrl( op->o_conn->c_sb,
00425                      LBER_SB_OPT_SET_MAX_INCOMING, &max );
00426        }
00427 
00428        /* log authorization identity */
00429        Statslog( LDAP_DEBUG_STATS,
00430               "%s BIND dn=\"%s\" mech=%s ssf=0\n",
00431               op->o_log_prefix,
00432               op->o_conn->c_dn.bv_val, op->orb_mech.bv_val, 0, 0 );
00433 
00434        Debug( LDAP_DEBUG_TRACE,
00435               "do_bind: v%d bind: \"%s\" to \"%s\"\n",
00436               op->o_protocol, op->o_req_dn.bv_val, op->o_conn->c_dn.bv_val );
00437 
00438        ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00439 
00440        /* send this here to avoid a race condition */
00441        send_ldap_result( op, rs );
00442 
00443        return LDAP_SUCCESS;
00444 }