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