1/* bind.c - decode an ldap bind operation and pass it to a backend db */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16/* Portions Copyright (c) 1995 Regents of the University of Michigan. 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms are permitted 20 * provided that this notice is preserved and that due credit is given 21 * to the University of Michigan at Ann Arbor. The name of the University 22 * may not be used to endorse or promote products derived from this 23 * software without specific prior written permission. This software 24 * is provided ``as is'' without express or implied warranty. 25 */ 26 27#include "portable.h" 28 29#include <stdio.h> 30 31#include <ac/string.h> 32#include <ac/socket.h> 33 34#include "slap.h" 35 36int 37do_bind( 38 Operation *op, 39 SlapReply *rs ) 40{ 41 BerElement *ber = op->o_ber; 42 ber_int_t version; 43 ber_tag_t method; 44 struct berval mech = BER_BVNULL; 45 struct berval dn = BER_BVNULL; 46 ber_tag_t tag; 47 Backend *be = NULL; 48 49 Debug( LDAP_DEBUG_TRACE, "%s do_bind\n", 50 op->o_log_prefix, 0, 0 ); 51 52 /* 53 * Force the connection to "anonymous" until bind succeeds. 54 */ 55 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 56 if ( op->o_conn->c_sasl_bind_in_progress ) { 57 be = op->o_conn->c_authz_backend; 58 } 59 if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) { 60 /* log authorization identity demotion */ 61 Statslog( LDAP_DEBUG_STATS, 62 "%s BIND anonymous mech=implicit ssf=0\n", 63 op->o_log_prefix, 0, 0, 0, 0 ); 64 } 65 connection2anonymous( op->o_conn ); 66 if ( op->o_conn->c_sasl_bind_in_progress ) { 67 op->o_conn->c_authz_backend = be; 68 } 69 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 70 if ( !BER_BVISNULL( &op->o_dn ) ) { 71 /* NOTE: temporarily wasting few bytes 72 * (until bind is completed), but saving 73 * a couple of ch_free() and ch_strdup("") */ 74 op->o_dn.bv_val[0] = '\0'; 75 op->o_dn.bv_len = 0; 76 } 77 if ( !BER_BVISNULL( &op->o_ndn ) ) { 78 op->o_ndn.bv_val[0] = '\0'; 79 op->o_ndn.bv_len = 0; 80 } 81 82 /* 83 * Parse the bind request. It looks like this: 84 * 85 * BindRequest ::= SEQUENCE { 86 * version INTEGER, -- version 87 * name DistinguishedName, -- dn 88 * authentication CHOICE { 89 * simple [0] OCTET STRING -- passwd 90 * krbv42ldap [1] OCTET STRING -- OBSOLETE 91 * krbv42dsa [2] OCTET STRING -- OBSOLETE 92 * SASL [3] SaslCredentials 93 * } 94 * } 95 * 96 * SaslCredentials ::= SEQUENCE { 97 * mechanism LDAPString, 98 * credentials OCTET STRING OPTIONAL 99 * } 100 */ 101 102 tag = ber_scanf( ber, "{imt" /*}*/, &version, &dn, &method ); 103 104 if ( tag == LBER_ERROR ) { 105 Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n", 106 op->o_log_prefix, 0, 0 ); 107 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); 108 rs->sr_err = SLAPD_DISCONNECT; 109 goto cleanup; 110 } 111 112 op->o_protocol = version; 113 op->orb_method = method; 114 115 if( op->orb_method != LDAP_AUTH_SASL ) { 116 tag = ber_scanf( ber, /*{*/ "m}", &op->orb_cred ); 117 118 } else { 119 tag = ber_scanf( ber, "{m" /*}*/, &mech ); 120 121 if ( tag != LBER_ERROR ) { 122 ber_len_t len; 123 tag = ber_peek_tag( ber, &len ); 124 125 if ( tag == LDAP_TAG_LDAPCRED ) { 126 tag = ber_scanf( ber, "m", &op->orb_cred ); 127 } else { 128 tag = LDAP_TAG_LDAPCRED; 129 BER_BVZERO( &op->orb_cred ); 130 } 131 132 if ( tag != LBER_ERROR ) { 133 tag = ber_scanf( ber, /*{{*/ "}}" ); 134 } 135 } 136 } 137 138 if ( tag == LBER_ERROR ) { 139 Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n", 140 op->o_log_prefix, 0, 0 ); 141 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); 142 rs->sr_err = SLAPD_DISCONNECT; 143 goto cleanup; 144 } 145 146 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { 147 Debug( LDAP_DEBUG_ANY, "%s do_bind: get_ctrls failed\n", 148 op->o_log_prefix, 0, 0 ); 149 goto cleanup; 150 } 151 152 /* We use the tmpmemctx here because it speeds up normalization. 153 * However, we must dup with regular malloc when storing any 154 * resulting DNs in the op or conn structures. 155 */ 156 rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, 157 op->o_tmpmemctx ); 158 if ( rs->sr_err != LDAP_SUCCESS ) { 159 Debug( LDAP_DEBUG_ANY, "%s do_bind: invalid dn (%s)\n", 160 op->o_log_prefix, dn.bv_val, 0 ); 161 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); 162 goto cleanup; 163 } 164 165 Statslog( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" method=%ld\n", 166 op->o_log_prefix, op->o_req_dn.bv_val, 167 (unsigned long) op->orb_method, 0, 0 ); 168 169 if( op->orb_method == LDAP_AUTH_SASL ) { 170 Debug( LDAP_DEBUG_TRACE, "do_bind: dn (%s) SASL mech %s\n", 171 op->o_req_dn.bv_val, mech.bv_val, NULL ); 172 173 } else { 174 Debug( LDAP_DEBUG_TRACE, 175 "do_bind: version=%ld dn=\"%s\" method=%ld\n", 176 (unsigned long) version, op->o_req_dn.bv_val, 177 (unsigned long) op->orb_method ); 178 } 179 180 if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) { 181 Debug( LDAP_DEBUG_ANY, "%s do_bind: unknown version=%ld\n", 182 op->o_log_prefix, (unsigned long) version, 0 ); 183 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, 184 "requested protocol version not supported" ); 185 goto cleanup; 186 187 } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) && 188 version < LDAP_VERSION3 ) 189 { 190 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, 191 "historical protocol version requested, use LDAPv3 instead" ); 192 goto cleanup; 193 } 194 195 /* 196 * we set connection version regardless of whether bind succeeds or not. 197 */ 198 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 199 op->o_conn->c_protocol = version; 200 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 201 202 op->orb_mech = mech; 203 204 op->o_bd = frontendDB; 205 rs->sr_err = frontendDB->be_bind( op, rs ); 206 207cleanup: 208 if ( rs->sr_err == LDAP_SUCCESS ) { 209 if ( op->orb_method != LDAP_AUTH_SASL ) { 210 ber_dupbv( &op->o_conn->c_authmech, &mech ); 211 } 212 op->o_conn->c_authtype = op->orb_method; 213 } 214 215 if( !BER_BVISNULL( &op->o_req_dn ) ) { 216 slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx ); 217 BER_BVZERO( &op->o_req_dn ); 218 } 219 if( !BER_BVISNULL( &op->o_req_ndn ) ) { 220 slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx ); 221 BER_BVZERO( &op->o_req_ndn ); 222 } 223 224 return rs->sr_err; 225} 226 227int 228fe_op_bind( Operation *op, SlapReply *rs ) 229{ 230 BackendDB *bd = op->o_bd; 231 232 /* check for inappropriate controls */ 233 if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) { 234 send_ldap_error( op, rs, 235 LDAP_UNAVAILABLE_CRITICAL_EXTENSION, 236 "manageDSAit control inappropriate" ); 237 goto cleanup; 238 } 239 240 if ( op->orb_method == LDAP_AUTH_SASL ) { 241 if ( op->o_protocol < LDAP_VERSION3 ) { 242 Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n", 243 (unsigned long)op->o_protocol, 0, 0 ); 244 send_ldap_discon( op, rs, 245 LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" ); 246 rs->sr_err = SLAPD_DISCONNECT; 247 goto cleanup; 248 } 249 250 if( BER_BVISNULL( &op->orb_mech ) || BER_BVISEMPTY( &op->orb_mech ) ) { 251 Debug( LDAP_DEBUG_ANY, 252 "do_bind: no sasl mechanism provided\n", 253 0, 0, 0 ); 254 send_ldap_error( op, rs, LDAP_AUTH_METHOD_NOT_SUPPORTED, 255 "no SASL mechanism provided" ); 256 goto cleanup; 257 } 258 259 /* check restrictions */ 260 if( backend_check_restrictions( op, rs, &op->orb_mech ) != LDAP_SUCCESS ) { 261 send_ldap_result( op, rs ); 262 goto cleanup; 263 } 264 265 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 266 if ( op->o_conn->c_sasl_bind_in_progress ) { 267 if( !bvmatch( &op->o_conn->c_sasl_bind_mech, &op->orb_mech ) ) { 268 /* mechanism changed between bind steps */ 269 slap_sasl_reset(op->o_conn); 270 } 271 } else { 272 ber_dupbv(&op->o_conn->c_sasl_bind_mech, &op->orb_mech); 273 } 274 275 /* Set the bindop for the benefit of in-directory SASL lookups */ 276 op->o_conn->c_sasl_bindop = op; 277 278 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 279 280 rs->sr_err = slap_sasl_bind( op, rs ); 281 282 goto cleanup; 283 284 } else { 285 /* Not SASL, cancel any in-progress bind */ 286 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 287 288 if ( !BER_BVISNULL( &op->o_conn->c_sasl_bind_mech ) ) { 289 free( op->o_conn->c_sasl_bind_mech.bv_val ); 290 BER_BVZERO( &op->o_conn->c_sasl_bind_mech ); 291 } 292 op->o_conn->c_sasl_bind_in_progress = 0; 293 294 slap_sasl_reset( op->o_conn ); 295 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 296 } 297 298 if ( op->orb_method == LDAP_AUTH_SIMPLE ) { 299 BER_BVSTR( &op->orb_mech, "SIMPLE" ); 300 /* accept "anonymous" binds */ 301 if ( BER_BVISEMPTY( &op->orb_cred ) || BER_BVISEMPTY( &op->o_req_ndn ) ) { 302 rs->sr_err = LDAP_SUCCESS; 303 304 if( !BER_BVISEMPTY( &op->orb_cred ) && 305 !( global_allows & SLAP_ALLOW_BIND_ANON_CRED )) 306 { 307 /* cred is not empty, disallow */ 308 rs->sr_err = LDAP_INVALID_CREDENTIALS; 309 310 } else if ( !BER_BVISEMPTY( &op->o_req_ndn ) && 311 !( global_allows & SLAP_ALLOW_BIND_ANON_DN )) 312 { 313 /* DN is not empty, disallow */ 314 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 315 rs->sr_text = 316 "unauthenticated bind (DN with no password) disallowed"; 317 318 } else if ( global_disallows & SLAP_DISALLOW_BIND_ANON ) { 319 /* disallow */ 320 rs->sr_err = LDAP_INAPPROPRIATE_AUTH; 321 rs->sr_text = "anonymous bind disallowed"; 322 323 } else { 324 backend_check_restrictions( op, rs, &op->orb_mech ); 325 } 326 327 /* 328 * we already forced connection to "anonymous", 329 * just need to send success 330 */ 331 send_ldap_result( op, rs ); 332 Debug( LDAP_DEBUG_TRACE, "do_bind: v%d anonymous bind\n", 333 op->o_protocol, 0, 0 ); 334 goto cleanup; 335 336 } else if ( global_disallows & SLAP_DISALLOW_BIND_SIMPLE ) { 337 /* disallow simple authentication */ 338 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 339 rs->sr_text = "unwilling to perform simple authentication"; 340 341 send_ldap_result( op, rs ); 342 Debug( LDAP_DEBUG_TRACE, 343 "do_bind: v%d simple bind(%s) disallowed\n", 344 op->o_protocol, op->o_req_ndn.bv_val, 0 ); 345 goto cleanup; 346 } 347 348 } else { 349 rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED; 350 rs->sr_text = "unknown authentication method"; 351 352 send_ldap_result( op, rs ); 353 Debug( LDAP_DEBUG_TRACE, 354 "do_bind: v%d unknown authentication method (%d)\n", 355 op->o_protocol, op->orb_method, 0 ); 356 goto cleanup; 357 } 358 359 /* 360 * We could be serving multiple database backends. Select the 361 * appropriate one, or send a referral to our "referral server" 362 * if we don't hold it. 363 */ 364 365 if ( (op->o_bd = select_backend( &op->o_req_ndn, 0 )) == NULL ) { 366 /* don't return referral for bind requests */ 367 /* noSuchObject is not allowed to be returned by bind */ 368 rs->sr_err = LDAP_INVALID_CREDENTIALS; 369 op->o_bd = bd; 370 send_ldap_result( op, rs ); 371 goto cleanup; 372 } 373 374 /* check restrictions */ 375 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { 376 send_ldap_result( op, rs ); 377 goto cleanup; 378 } 379 380 if( op->o_bd->be_bind ) { 381 op->o_conn->c_authz_cookie = NULL; 382 383 rs->sr_err = (op->o_bd->be_bind)( op, rs ); 384 385 if ( rs->sr_err == 0 ) { 386 (void)fe_op_bind_success( op, rs ); 387 388 } else if ( !BER_BVISNULL( &op->orb_edn ) ) { 389 free( op->orb_edn.bv_val ); 390 BER_BVZERO( &op->orb_edn ); 391 } 392 393 } else { 394 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 395 "operation not supported within naming context" ); 396 } 397 398cleanup:; 399 op->o_bd = bd; 400 return rs->sr_err; 401} 402 403int 404fe_op_bind_success( Operation *op, SlapReply *rs ) 405{ 406 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 407 408 if( op->o_conn->c_authz_backend == NULL ) { 409 op->o_conn->c_authz_backend = op->o_bd; 410 } 411 412 /* be_bind returns regular/global edn */ 413 if( !BER_BVISEMPTY( &op->orb_edn ) ) { 414 op->o_conn->c_dn = op->orb_edn; 415 } else { 416 ber_dupbv(&op->o_conn->c_dn, &op->o_req_dn); 417 } 418 419 ber_dupbv( &op->o_conn->c_ndn, &op->o_req_ndn ); 420 421 /* op->o_conn->c_sb may be 0 for internal operations */ 422 if( !BER_BVISEMPTY( &op->o_conn->c_dn ) && op->o_conn->c_sb != 0 ) { 423 ber_len_t max = sockbuf_max_incoming_auth; 424 ber_sockbuf_ctrl( op->o_conn->c_sb, 425 LBER_SB_OPT_SET_MAX_INCOMING, &max ); 426 } 427 428 /* log authorization identity */ 429 Statslog( LDAP_DEBUG_STATS, 430 "%s BIND dn=\"%s\" mech=%s ssf=0\n", 431 op->o_log_prefix, 432 op->o_conn->c_dn.bv_val, op->orb_mech.bv_val, 0, 0 ); 433 434 Debug( LDAP_DEBUG_TRACE, 435 "do_bind: v%d bind: \"%s\" to \"%s\"\n", 436 op->o_protocol, op->o_req_dn.bv_val, op->o_conn->c_dn.bv_val ); 437 438 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 439 440 /* send this here to avoid a race condition */ 441 send_ldap_result( op, rs ); 442 443 return LDAP_SUCCESS; 444} 445