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