1 /* $NetBSD: bind.c,v 1.3 2021/08/14 16:14:58 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-2021 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.3 2021/08/14 16:14:58 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 "lutil.h"
40 #include "slap.h"
41
42 int
do_bind(Operation * op,SlapReply * rs)43 do_bind(
44 Operation *op,
45 SlapReply *rs )
46 {
47 BerElement *ber = op->o_ber;
48 ber_int_t version;
49 ber_tag_t method;
50 struct berval mech = BER_BVNULL;
51 struct berval dn = BER_BVNULL;
52 ber_tag_t tag;
53 Backend *be = NULL;
54
55 Debug( LDAP_DEBUG_TRACE, "%s do_bind\n",
56 op->o_log_prefix );
57
58 /*
59 * Force the connection to "anonymous" until bind succeeds.
60 */
61 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
62 if ( op->o_conn->c_sasl_bind_in_progress ) {
63 be = op->o_conn->c_authz_backend;
64 }
65 if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
66 /* log authorization identity demotion */
67 Debug( LDAP_DEBUG_STATS,
68 "%s BIND anonymous mech=implicit bind_ssf=0 ssf=%d\n",
69 op->o_log_prefix, op->o_conn->c_ssf );
70 }
71 connection2anonymous( op->o_conn );
72 if ( op->o_conn->c_sasl_bind_in_progress ) {
73 op->o_conn->c_authz_backend = be;
74 }
75 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
76 if ( !BER_BVISNULL( &op->o_dn ) ) {
77 /* NOTE: temporarily wasting few bytes
78 * (until bind is completed), but saving
79 * a couple of ch_free() and ch_strdup("") */
80 op->o_dn.bv_val[0] = '\0';
81 op->o_dn.bv_len = 0;
82 }
83 if ( !BER_BVISNULL( &op->o_ndn ) ) {
84 op->o_ndn.bv_val[0] = '\0';
85 op->o_ndn.bv_len = 0;
86 }
87
88 /*
89 * Parse the bind request. It looks like this:
90 *
91 * BindRequest ::= SEQUENCE {
92 * version INTEGER, -- version
93 * name DistinguishedName, -- dn
94 * authentication CHOICE {
95 * simple [0] OCTET STRING -- passwd
96 * krbv42ldap [1] OCTET STRING -- OBSOLETE
97 * krbv42dsa [2] OCTET STRING -- OBSOLETE
98 * SASL [3] SaslCredentials
99 * }
100 * }
101 *
102 * SaslCredentials ::= SEQUENCE {
103 * mechanism LDAPString,
104 * credentials OCTET STRING OPTIONAL
105 * }
106 */
107
108 tag = ber_scanf( ber, "{imt" /*}*/, &version, &dn, &method );
109
110 if ( tag == LBER_ERROR ) {
111 Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n",
112 op->o_log_prefix );
113 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
114 rs->sr_err = SLAPD_DISCONNECT;
115 goto cleanup;
116 }
117
118 op->o_protocol = version;
119 op->orb_method = method;
120
121 if( op->orb_method != LDAP_AUTH_SASL ) {
122 tag = ber_scanf( ber, /*{*/ "m}", &op->orb_cred );
123
124 } else {
125 tag = ber_scanf( ber, "{m" /*}*/, &mech );
126
127 if ( tag != LBER_ERROR ) {
128 ber_len_t len;
129 tag = ber_peek_tag( ber, &len );
130
131 if ( tag == LDAP_TAG_LDAPCRED ) {
132 tag = ber_scanf( ber, "m", &op->orb_cred );
133 } else {
134 tag = LDAP_TAG_LDAPCRED;
135 BER_BVZERO( &op->orb_cred );
136 }
137
138 if ( tag != LBER_ERROR ) {
139 tag = ber_scanf( ber, /*{{*/ "}}" );
140 }
141 }
142 }
143
144 if ( tag == LBER_ERROR ) {
145 Debug( LDAP_DEBUG_ANY, "%s do_bind: ber_scanf failed\n",
146 op->o_log_prefix );
147 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
148 rs->sr_err = SLAPD_DISCONNECT;
149 goto cleanup;
150 }
151
152 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
153 Debug( LDAP_DEBUG_ANY, "%s do_bind: get_ctrls failed\n",
154 op->o_log_prefix );
155 goto cleanup;
156 }
157
158 /* We use the tmpmemctx here because it speeds up normalization.
159 * However, we must dup with regular malloc when storing any
160 * resulting DNs in the op or conn structures.
161 */
162 rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
163 op->o_tmpmemctx );
164 if ( rs->sr_err != LDAP_SUCCESS ) {
165 Debug( LDAP_DEBUG_ANY, "%s do_bind: invalid dn (%s)\n",
166 op->o_log_prefix, dn.bv_val );
167 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
168 goto cleanup;
169 }
170
171 Debug( LDAP_DEBUG_STATS, "%s BIND dn=\"%s\" method=%ld\n",
172 op->o_log_prefix, op->o_req_dn.bv_val,
173 (unsigned long) op->orb_method );
174
175 if( op->orb_method == LDAP_AUTH_SASL ) {
176 Debug( LDAP_DEBUG_TRACE, "do_bind: dn (%s) SASL mech %s\n",
177 op->o_req_dn.bv_val, mech.bv_val );
178
179 } else {
180 Debug( LDAP_DEBUG_TRACE,
181 "do_bind: version=%ld dn=\"%s\" method=%ld\n",
182 (unsigned long) version, op->o_req_dn.bv_val,
183 (unsigned long) op->orb_method );
184 }
185
186 if ( version < LDAP_VERSION_MIN || version > LDAP_VERSION_MAX ) {
187 Debug( LDAP_DEBUG_ANY, "%s do_bind: unknown version=%ld\n",
188 op->o_log_prefix, (unsigned long) version );
189 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
190 "requested protocol version not supported" );
191 goto cleanup;
192
193 } else if (!( global_allows & SLAP_ALLOW_BIND_V2 ) &&
194 version < LDAP_VERSION3 )
195 {
196 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
197 "historical protocol version requested, use LDAPv3 instead" );
198 goto cleanup;
199 }
200
201 /*
202 * we set connection version regardless of whether bind succeeds or not.
203 */
204 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
205 op->o_conn->c_protocol = version;
206 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
207
208 op->orb_mech = mech;
209
210 op->o_bd = frontendDB;
211 rs->sr_err = frontendDB->be_bind( op, rs );
212
213 cleanup:
214 if ( rs->sr_err == LDAP_SUCCESS ) {
215 if ( op->orb_method != LDAP_AUTH_SASL ) {
216 ber_dupbv( &op->o_conn->c_authmech, &mech );
217 }
218 op->o_conn->c_authtype = op->orb_method;
219 }
220
221 if( !BER_BVISNULL( &op->o_req_dn ) ) {
222 slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx );
223 BER_BVZERO( &op->o_req_dn );
224 }
225 if( !BER_BVISNULL( &op->o_req_ndn ) ) {
226 slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
227 BER_BVZERO( &op->o_req_ndn );
228 }
229
230 return rs->sr_err;
231 }
232
233 int
fe_op_bind(Operation * op,SlapReply * rs)234 fe_op_bind( Operation *op, SlapReply *rs )
235 {
236 BackendDB *bd = op->o_bd;
237
238 /* check for inappropriate controls */
239 if( get_manageDSAit( op ) == SLAP_CONTROL_CRITICAL ) {
240 send_ldap_error( op, rs,
241 LDAP_UNAVAILABLE_CRITICAL_EXTENSION,
242 "manageDSAit control inappropriate" );
243 goto cleanup;
244 }
245
246 if ( op->orb_method == LDAP_AUTH_SASL ) {
247 if ( op->o_protocol < LDAP_VERSION3 ) {
248 Debug( LDAP_DEBUG_ANY, "do_bind: sasl with LDAPv%ld\n",
249 (unsigned long)op->o_protocol );
250 send_ldap_discon( op, rs,
251 LDAP_PROTOCOL_ERROR, "SASL bind requires LDAPv3" );
252 rs->sr_err = SLAPD_DISCONNECT;
253 goto cleanup;
254 }
255
256 if( BER_BVISNULL( &op->orb_mech ) || BER_BVISEMPTY( &op->orb_mech ) ) {
257 Debug( LDAP_DEBUG_ANY,
258 "do_bind: no sasl mechanism provided\n" );
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 );
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 );
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 );
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
fe_op_lastbind(Operation * op)409 fe_op_lastbind( Operation *op )
410 {
411 Operation op2 = *op;
412 SlapReply r2 = { REP_RESULT };
413 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
414 LDAPControl c, *ca[2];
415 Modifications *m;
416 Entry *e;
417 Attribute *a;
418 char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
419 struct berval timestamp;
420 time_t bindtime = (time_t)-1;
421 int rc;
422
423 rc = be_entry_get_rw( op, &op->o_conn->c_ndn, NULL, NULL, 0, &e );
424 if ( rc != LDAP_SUCCESS ) {
425 return -1;
426 }
427
428 /* get authTimestamp attribute, if it exists */
429 if ( (a = attr_find( e->e_attrs, slap_schema.si_ad_pwdLastSuccess )) != NULL ) {
430 struct lutil_tm tm;
431 struct lutil_timet tt;
432
433 if ( lutil_parsetime( a->a_nvals[0].bv_val, &tm ) == 0 ) {
434 lutil_tm2time( &tm, &tt );
435 bindtime = tt.tt_sec;
436 }
437 Debug( LDAP_DEBUG_ANY, "fe_op_lastbind: "
438 "old pwdLastSuccess value=%s %lds ago\n",
439 a->a_nvals[0].bv_val, bindtime == (time_t)-1 ? -1 : op->o_time - bindtime );
440
441 /*
442 * TODO: If the recorded bind time is within configurable precision,
443 * it doesn't need to be updated (save a write for nothing)
444 */
445 if ( bindtime != (time_t)-1 && op->o_time <= bindtime ) {
446 be_entry_release_r( op, e );
447 return LDAP_SUCCESS;
448 }
449 }
450
451 /* update the authTimestamp in the user's entry with the current time */
452 timestamp.bv_val = nowstr;
453 timestamp.bv_len = sizeof(nowstr);
454 slap_timestamp( &op->o_time, ×tamp );
455
456 m = ch_calloc( sizeof(Modifications), 1 );
457 m->sml_op = LDAP_MOD_REPLACE;
458 m->sml_flags = 0;
459 m->sml_type = slap_schema.si_ad_pwdLastSuccess->ad_cname;
460 m->sml_desc = slap_schema.si_ad_pwdLastSuccess;
461 m->sml_numvals = 1;
462 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
463 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
464
465 ber_dupbv( &m->sml_values[0], ×tamp );
466 ber_dupbv( &m->sml_nvalues[0], ×tamp );
467
468 be_entry_release_r( op, e );
469
470 op2.o_tag = LDAP_REQ_MODIFY;
471 op2.o_req_dn = op->o_conn->c_dn;
472 op2.o_req_ndn = op->o_conn->c_ndn;
473 op2.o_callback = &cb;
474 op2.orm_modlist = m;
475 op2.orm_no_opattrs = 0;
476 op2.o_dn = op->o_bd->be_rootdn;
477 op2.o_ndn = op->o_bd->be_rootndn;
478
479 /*
480 * TODO: this is core+frontend, not everything works the same way?
481 */
482 /*
483 * Code for forwarding of updates adapted from ppolicy.c of slapo-ppolicy
484 *
485 * If this server is a shadow and forward_updates is true,
486 * use the frontend to perform this modify. That will trigger
487 * the update referral, which can then be forwarded by the
488 * chain overlay. Obviously the updateref and chain overlay
489 * must be configured appropriately for this to be useful.
490 */
491 if ( SLAP_SHADOW( op->o_bd ) ) {
492 /* Must use Relax control since these are no-user-mod */
493 op2.o_relax = SLAP_CONTROL_CRITICAL;
494 op2.o_ctrls = ca;
495 ca[0] = &c;
496 ca[1] = NULL;
497 BER_BVZERO( &c.ldctl_value );
498 c.ldctl_iscritical = 1;
499 c.ldctl_oid = LDAP_CONTROL_RELAX;
500 } else {
501 /* If not forwarding, don't update opattrs and don't replicate */
502 if ( SLAP_SINGLE_SHADOW( op->o_bd )) {
503 op2.orm_no_opattrs = 1;
504 op2.o_dont_replicate = 1;
505 }
506 }
507
508 rc = op->o_bd->be_modify( &op2, &r2 );
509 slap_mods_free( m, 1 );
510
511 done:
512 return rc;
513 }
514
515 int
fe_op_bind_success(Operation * op,SlapReply * rs)516 fe_op_bind_success( Operation *op, SlapReply *rs )
517 {
518 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
519
520 if( op->o_conn->c_authz_backend == NULL ) {
521 op->o_conn->c_authz_backend = op->o_bd;
522 }
523
524 /* be_bind returns regular/global edn */
525 if( !BER_BVISEMPTY( &op->orb_edn ) ) {
526 op->o_conn->c_dn = op->orb_edn;
527 } else {
528 ber_dupbv(&op->o_conn->c_dn, &op->o_req_dn);
529 }
530
531 ber_dupbv( &op->o_conn->c_ndn, &op->o_req_ndn );
532
533 /* op->o_conn->c_sb may be 0 for internal operations */
534 if( !BER_BVISEMPTY( &op->o_conn->c_dn ) && op->o_conn->c_sb != 0 ) {
535 ber_len_t max = sockbuf_max_incoming_auth;
536 ber_sockbuf_ctrl( op->o_conn->c_sb,
537 LBER_SB_OPT_SET_MAX_INCOMING, &max );
538 }
539
540 /* log authorization identity */
541 Debug( LDAP_DEBUG_STATS,
542 "%s BIND dn=\"%s\" mech=%s bind_ssf=0 ssf=%d\n",
543 op->o_log_prefix,
544 op->o_conn->c_dn.bv_val, op->orb_mech.bv_val, op->o_conn->c_ssf );
545
546 Debug( LDAP_DEBUG_TRACE,
547 "do_bind: v%d bind: \"%s\" to \"%s\"\n",
548 op->o_protocol, op->o_req_dn.bv_val, op->o_conn->c_dn.bv_val );
549
550 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
551
552 if ( SLAP_LASTBIND( op->o_bd ) ) {
553 fe_op_lastbind( op );
554 }
555
556 /* send this here to avoid a race condition */
557 send_ldap_result( op, rs );
558
559 return LDAP_SUCCESS;
560 }
561