xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/bind.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /* bind.c - decode an ldap bind operation and pass it to a backend db */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/bind.c,v 1.201.2.4 2008/02/11 23:26:43 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 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 
36 int
37 do_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 
207 cleanup:
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 
227 int
228 fe_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 
398 cleanup:;
399 	op->o_bd = bd;
400 	return rs->sr_err;
401 }
402 
403 int
404 fe_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 	if( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
422 		ber_len_t max = sockbuf_max_incoming_auth;
423 		ber_sockbuf_ctrl( op->o_conn->c_sb,
424 			LBER_SB_OPT_SET_MAX_INCOMING, &max );
425 	}
426 
427 	/* log authorization identity */
428 	Statslog( LDAP_DEBUG_STATS,
429 		"%s BIND dn=\"%s\" mech=%s ssf=0\n",
430 		op->o_log_prefix,
431 		op->o_conn->c_dn.bv_val, op->orb_mech.bv_val, 0, 0 );
432 
433 	Debug( LDAP_DEBUG_TRACE,
434 		"do_bind: v%d bind: \"%s\" to \"%s\"\n",
435 		op->o_protocol, op->o_req_dn.bv_val, op->o_conn->c_dn.bv_val );
436 
437 	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
438 
439 	/* send this here to avoid a race condition */
440 	send_ldap_result( op, rs );
441 
442 	return LDAP_SUCCESS;
443 }
444