1 /* rbacuser.c - RBAC users */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  *
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 /* ACKNOWLEDGEMENTS:
17  */
18 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 
23 #include <ac/string.h>
24 
25 #include "slap.h"
26 #include "slap-config.h"
27 #include "lutil.h"
28 
29 #include "rbac.h"
30 
31 static int ppolicy_cid = -1;
32 
33 static rbac_user_t *
rbac_alloc_user()34 rbac_alloc_user()
35 {
36 	rbac_user_t *userp = ch_calloc( 1, sizeof(rbac_user_t) );
37 
38 	BER_BVZERO( &userp->tenantid );
39 	BER_BVZERO( &userp->uid );
40 	BER_BVZERO( &userp->dn );
41 	BER_BVZERO( &userp->password );
42 	BER_BVZERO( &userp->constraints );
43 	BER_BVZERO( &userp->msg );
44 	userp->roles = NULL;
45 	userp->role_constraints = NULL;
46 
47 	return userp;
48 }
49 
50 static int
rbac_read_user_cb(Operation * op,SlapReply * rs)51 rbac_read_user_cb( Operation *op, SlapReply *rs )
52 {
53 	rbac_callback_info_t *cbp = op->o_callback->sc_private;
54 	rbac_ad_t *user_ads;
55 	rbac_user_t *userp = NULL;
56 	int rc = 0, i;
57 
58 	Debug( LDAP_DEBUG_ANY, "rbac_read_user_cb\n" );
59 
60 	if ( rs->sr_type != REP_SEARCH ) {
61 		Debug( LDAP_DEBUG_ANY, "rbac_read_user_cb: "
62 				"sr_type != REP_SEARCH\n" );
63 		return 0;
64 	}
65 
66 	assert( cbp );
67 
68 	user_ads = cbp->tenantp->schema->user_ads;
69 
70 	userp = rbac_alloc_user();
71 	if ( !userp ) {
72 		Debug( LDAP_DEBUG_ANY, "rbac_read_user_cb: "
73 				"rbac_alloc_user failed\n" );
74 
75 		goto done;
76 	}
77 
78 	ber_dupbv( &userp->dn, &rs->sr_entry->e_name );
79 
80 	Debug( LDAP_DEBUG_ANY, "DEBUG rbac_read_user_cb (%s): "
81 			"rc (%d)\n",
82 			userp->dn.bv_val, rc );
83 
84 	for ( i = 0; !BER_BVISNULL( &user_ads[i].attr ); i++ ) {
85 		Attribute *attr = NULL;
86 
87 		attr = attr_find( rs->sr_entry->e_attrs, *user_ads[i].ad );
88 		if ( attr != NULL ) {
89 			switch ( user_ads[i].type ) {
90 				case RBAC_ROLE_ASSIGNMENT:
91 					ber_bvarray_dup_x( &userp->roles, attr->a_nvals, NULL );
92 					break;
93 				case RBAC_ROLE_CONSTRAINTS:
94 					ber_bvarray_dup_x(
95 							&userp->role_constraints, attr->a_nvals, NULL );
96 					break;
97 				case RBAC_USER_CONSTRAINTS:
98 					ber_dupbv_x( &userp->constraints, &attr->a_nvals[0], NULL );
99 					break;
100 				case RBAC_UID:
101 					ber_dupbv_x( &userp->uid, &attr->a_nvals[0], NULL );
102 					break;
103 				default:
104 					break;
105 			}
106 		}
107 	}
108 
109 done:;
110 	cbp->private = userp;
111 
112 	return 0;
113 }
114 
115 static int
rbac_bind_cb(Operation * op,SlapReply * rs)116 rbac_bind_cb( Operation *op, SlapReply *rs )
117 {
118 	rbac_user_t *ui = op->o_callback->sc_private;
119 
120 	LDAPControl *ctrl = ldap_control_find(
121 			LDAP_CONTROL_PASSWORDPOLICYRESPONSE, rs->sr_ctrls, NULL );
122 	if ( ctrl ) {
123 		LDAP *ld;
124 		ber_int_t expire, grace;
125 		LDAPPasswordPolicyError error;
126 
127 		ldap_create( &ld );
128 		if ( ld ) {
129 			int rc = ldap_parse_passwordpolicy_control(
130 					ld, ctrl, &expire, &grace, &error );
131 			if ( rc == LDAP_SUCCESS ) {
132 				ui->authz = RBAC_PASSWORD_GOOD;
133 				if ( grace > 0 ) {
134 					//ui->msg.bv_len = sprintf(ui->msg.bv_val,
135 					//		"Password expired; %d grace logins remaining",
136 					//		grace);
137 					ui->authz = RBAC_BIND_NEW_AUTHTOK_REQD;
138 				} else if ( error != PP_noError ) {
139 					ber_str2bv( ldap_passwordpolicy_err2txt( error ), 0, 0,
140 							&ui->msg );
141 
142 					switch ( error ) {
143 						case PP_passwordExpired:
144 							ui->authz = RBAC_PASSWORD_EXPIRATION_WARNING;
145 
146 							if ( expire >= 0 ) {
147 								char *unit = "seconds";
148 								if ( expire > 60 ) {
149 									expire /= 60;
150 									unit = "minutes";
151 								}
152 								if ( expire > 60 ) {
153 									expire /= 60;
154 									unit = "hours";
155 								}
156 								if ( expire > 24 ) {
157 									expire /= 24;
158 									unit = "days";
159 								}
160 #if 0 /* Who warns about expiration so far in advance? */
161 								if (expire > 7) {
162 									expire /= 7;
163 									unit = "weeks";
164 								}
165 								if (expire > 4) {
166 									expire /= 4;
167 									unit = "months";
168 								}
169 								if (expire > 12) {
170 									expire /= 12;
171 									unit = "years";
172 								}
173 #endif
174 							}
175 
176 							//rs->sr_err = ;
177 							break;
178 						case PP_accountLocked:
179 							ui->authz = RBAC_ACCOUNT_LOCKED;
180 							//rs->sr_err = ;
181 							break;
182 						case PP_changeAfterReset:
183 							ui->authz = RBAC_CHANGE_AFTER_RESET;
184 							rs->sr_err = LDAP_SUCCESS;
185 							break;
186 						case PP_passwordModNotAllowed:
187 							ui->authz = RBAC_NO_MODIFICATIONS;
188 							//rs->sr_err = ;
189 							break;
190 						case PP_mustSupplyOldPassword:
191 							ui->authz = RBAC_MUST_SUPPLY_OLD;
192 							//rs->sr_err = ;
193 							break;
194 						case PP_insufficientPasswordQuality:
195 							ui->authz = RBAC_INSUFFICIENT_QUALITY;
196 							//rs->sr_err = ;
197 							break;
198 						case PP_passwordTooShort:
199 							ui->authz = RBAC_PASSWORD_TOO_SHORT;
200 							//rs->sr_err = ;
201 							break;
202 						case PP_passwordTooYoung:
203 							ui->authz = RBAC_PASSWORD_TOO_YOUNG;
204 							//rs->sr_err = ;
205 							break;
206 						case PP_passwordInHistory:
207 							ui->authz = RBAC_HISTORY_VIOLATION;
208 							//rs->sr_err = ;
209 							break;
210 						case PP_noError:
211 						default:
212 							// do nothing
213 							//ui->authz = RBAC_PASSWORD_GOOD;
214 							rs->sr_err = LDAP_SUCCESS;
215 							break;
216 					}
217 
218 //					switch (error) {
219 //					case PP_passwordExpired:
220 						/* report this during authz */
221 //						rs->sr_err = LDAP_SUCCESS;
222 						/* fallthru */
223 //					case PP_changeAfterReset:
224 //						ui->authz = RBAC_BIND_NEW_AUTHTOK_REQD;
225 //					}
226 				}
227 			}
228 			ldap_unbind_ext( ld, NULL, NULL );
229 		}
230 	}
231 
232 	return 0;
233 }
234 
235 /* exported user functions */
236 int
rbac_authenticate_user(Operation * op,rbac_user_t * userp)237 rbac_authenticate_user( Operation *op, rbac_user_t *userp )
238 {
239 	int rc = LDAP_SUCCESS;
240 	slap_callback cb = { 0 };
241 	SlapReply rs2 = { REP_RESULT };
242 	Operation op2 = *op;
243 	LDAPControl *sctrls[4];
244 	LDAPControl sctrl[3];
245 	int nsctrls = 0;
246 	LDAPControl c;
247 	struct berval ber_bvnull = BER_BVNULL;
248 	struct berval dn, ndn;
249 
250 	rc = dnPrettyNormal( 0, &userp->dn, &dn, &ndn, NULL );
251 	if ( rc != LDAP_SUCCESS ) {
252 		goto done;
253 	}
254 
255 	cb.sc_response = rbac_bind_cb;
256 	cb.sc_private = userp;
257 	op2.o_callback = &cb;
258 	op2.o_dn = ber_bvnull;
259 	op2.o_ndn = ber_bvnull;
260 	op2.o_tag = LDAP_REQ_BIND;
261 	op2.o_protocol = LDAP_VERSION3;
262 	op2.orb_method = LDAP_AUTH_SIMPLE;
263 	op2.orb_cred = userp->password;
264 	op2.o_req_dn = dn;
265 	op2.o_req_ndn = ndn;
266 
267 	// loading the ldap pw policy controls loaded into here, added by smm:
268 	c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
269 	c.ldctl_value.bv_val = NULL;
270 	c.ldctl_value.bv_len = 0;
271 	c.ldctl_iscritical = 0;
272 	sctrl[nsctrls] = c;
273 	sctrls[nsctrls] = &sctrl[nsctrls];
274 	sctrls[++nsctrls] = NULL;
275 	op2.o_ctrls = sctrls;
276 
277 	if ( ppolicy_cid < 0 ) {
278 		rc = slap_find_control_id( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
279 				&ppolicy_cid );
280 		if ( rc != LDAP_SUCCESS ) {
281 			goto done;
282 		}
283 	}
284 	// smm - need to set the control flag too:
285 	op2.o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_CRITICAL;
286 
287 	slap_op_time( &op2.o_time, &op2.o_tincr );
288 	op2.o_bd = frontendDB;
289 	rc = op2.o_bd->be_bind( &op2, &rs2 );
290 	if ( userp->authz > 0 ) {
291 		Debug( LDAP_DEBUG_ANY, "rbac_authenticate_user (%s): "
292 				"password policy violation (%d)\n",
293 				userp->dn.bv_val ? userp->dn.bv_val : "NULL", userp->authz );
294 	}
295 
296 done:;
297 	ch_free( dn.bv_val );
298 	ch_free( ndn.bv_val );
299 
300 	Debug( LDAP_DEBUG_ANY, "rbac_authenticate_user (%s): "
301 			"rc (%d)\n",
302 			userp->dn.bv_val ? userp->dn.bv_val : "NULL", rc );
303 	return rc;
304 }
305 
306 /*
307 	isvalidusername(): from OpenLDAP ~/contrib/slapd-modules/nssov/passwd.c
308 	Checks to see if the specified name is a valid user name.
309 
310     This test is based on the definition from POSIX (IEEE Std 1003.1, 2004, 3.426 User Name
311 	 and 3.276 Portable Filename Character Set):
312 	 http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_426
313 	 http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
314 
315 	 The standard defines user names valid if they contain characters from
316 	 the set [A-Za-z0-9._-] where the hyphen should not be used as first
317 	 character. As an extension this test allows the dolar '$' sign as the last
318 	 character to support Samba special accounts.
319 */
320 static int
isvalidusername(struct berval * bv)321 isvalidusername( struct berval *bv )
322 {
323 	int i;
324 	char *name = bv->bv_val;
325 	if ( (name == NULL) || ( name[0] == '\0' ) ) return 0;
326 	/* check first character */
327 	if ( !( ( name[0] >= 'A' && name[0] <= 'Z' ) ||
328 				 ( name[0] >= 'a' && name[0] <= 'z' ) ||
329 				 ( name[0] >= '0' && name[0] <= '9' ) || name[0] == '.' ||
330 				 name[0] == '_' ) )
331 		return 0;
332 	/* check other characters */
333 	for ( i = 1; i < bv->bv_len; i++ ) {
334 		if ( name[i] == '$' ) {
335 			/* if the char is $ we require it to be the last char */
336 			if ( name[i + 1] != '\0' ) return 0;
337 		} else if ( !( ( name[i] >= 'A' && name[i] <= 'Z' ) ||
338 							( name[i] >= 'a' && name[i] <= 'z' ) ||
339 							( name[i] >= '0' && name[i] <= '9' ) ||
340 							name[i] == '.' || name[i] == '_' ||
341 							name[i] == '-' ) )
342 			return 0;
343 	}
344 	/* no test failed so it must be good */
345 	return -1;
346 }
347 
348 rbac_user_t *
rbac_read_user(Operation * op,rbac_req_t * reqp)349 rbac_read_user( Operation *op, rbac_req_t *reqp )
350 {
351 	int rc = LDAP_SUCCESS;
352 	tenant_info_t *tenantp = rbac_tid2tenant( &reqp->tenantid );
353 	rbac_user_t *userp = NULL;
354 	char fbuf[RBAC_BUFLEN];
355 	struct berval filter = { sizeof(fbuf), fbuf };
356 	SlapReply rs2 = { REP_RESULT };
357 	Operation op2 = *op;
358 	slap_callback cb = { 0 };
359 	rbac_callback_info_t rbac_cb;
360 
361 	if ( !tenantp ) {
362 		Debug( LDAP_DEBUG_ANY, "rbac_read_user: "
363 				"missing tenant information\n" );
364 		rc = LDAP_UNWILLING_TO_PERFORM;
365 		goto done;
366 	}
367 
368 	/* uid is a pre-requisite for reading the user information */
369 	if ( BER_BVISNULL( &reqp->uid ) ) {
370 		Debug( LDAP_DEBUG_ANY, "rbac_read_user: "
371 				"missing uid, unable to read user entry\n" );
372 		rc = LDAP_UNWILLING_TO_PERFORM;
373 		goto done;
374 	}
375 
376 	if ( !isvalidusername( &reqp->uid ) ) {
377 		Debug( LDAP_DEBUG_ANY, "rbac_read_user: "
378 				"invalid user id\n" );
379 		rc = LDAP_NO_SUCH_OBJECT;
380 		goto done;
381 	}
382 
383 	rbac_cb.tenantp = tenantp;
384 	rbac_cb.private = NULL;
385 
386 	memset( fbuf, 0, sizeof(fbuf) );
387 	strcpy( fbuf, "uid=" );
388 	strncat( fbuf, reqp->uid.bv_val, reqp->uid.bv_len );
389 	filter.bv_val = fbuf;
390 	filter.bv_len = strlen( fbuf );
391 
392 	if ( rc != LDAP_SUCCESS ) {
393 		Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
394 				"invalid DN syntax\n" );
395 		goto done;
396 	}
397 
398 	cb.sc_private = &rbac_cb;
399 	cb.sc_response = rbac_read_user_cb;
400 	op2.o_callback = &cb;
401 	op2.o_tag = LDAP_REQ_SEARCH;
402 	op2.o_dn = tenantp->admin;
403 	op2.o_ndn = tenantp->admin;
404 	op2.o_req_dn = tenantp->users_basedn;
405 	op2.o_req_ndn = tenantp->users_basedn;
406 	op2.ors_filterstr = filter;
407 	op2.ors_filter = str2filter_x( &op2, filter.bv_val );
408 	op2.ors_scope = LDAP_SCOPE_SUBTREE;
409 	op2.ors_attrs = tenantp->schema->user_attrs;
410 	op2.ors_tlimit = SLAP_NO_LIMIT;
411 	op2.ors_slimit = SLAP_NO_LIMIT;
412 	op2.ors_attrsonly = 0;
413 	op2.o_bd = frontendDB;
414 	op2.ors_limit = NULL;
415 	rc = op2.o_bd->be_search( &op2, &rs2 );
416 	filter_free_x( &op2, op2.ors_filter, 1 );
417 
418 done:;
419 	if ( rc == LDAP_SUCCESS && rbac_cb.private ) {
420 		userp = (rbac_user_t *)rbac_cb.private;
421 		if ( !BER_BVISNULL( &reqp->authtok ) )
422 			ber_dupbv( &userp->password, &reqp->authtok );
423 		rbac_cb.private = NULL;
424 		return userp;
425 	} else {
426 		userp = (rbac_user_t *)rbac_cb.private;
427 		rbac_free_user( userp );
428 		return NULL;
429 	}
430 }
431 
432 /* evaluate temporal constraints for the user */
433 int
rbac_user_temporal_constraint(rbac_user_t * userp)434 rbac_user_temporal_constraint( rbac_user_t *userp )
435 {
436 	int rc = LDAP_SUCCESS;
437 	rbac_constraint_t *cp = NULL;
438 
439 	if ( BER_BVISNULL( &userp->constraints ) ) {
440 		/* no temporal constraint */
441 		goto done;
442 	}
443 
444 	cp = rbac_bv2constraint( &userp->constraints );
445 	if ( !cp ) {
446 		Debug( LDAP_DEBUG_ANY, "rbac_user_temporal_constraint: "
447 				"invalid user constraint \n" );
448 		rc = LDAP_OTHER;
449 		goto done;
450 	}
451 
452 	rc = rbac_check_time_constraint( cp );
453 
454 done:;
455 	rbac_free_constraint( cp );
456 
457 	return rc;
458 }
459 
460 /*
461 rbac_constraint_t *
462 rbac_user_role_constraintsx(rbac_user_t *userp)
463 {
464 	rbac_constraint_t *tmp, *cp = NULL;
465 	int i = 0;
466 
467 	if (!userp || !userp->role_constraints)
468 		goto done;
469 
470 	while (!BER_BVISNULL(&userp->role_constraints[i])) {
471 		tmp = rbac_bv2constraint(&userp->role_constraints[i++]);
472 		if (tmp) {
473 			if (!cp) {
474 				cp = tmp;
475 			} else {
476 				tmp->next = cp;
477 				cp = tmp;
478 			}
479 		}
480 	}
481 
482 done:;
483 	return cp;
484 }
485 */
486 
487 rbac_constraint_t *
rbac_user_role_constraints(BerVarray values)488 rbac_user_role_constraints( BerVarray values )
489 {
490 	rbac_constraint_t *curr, *head = NULL;
491 	int i = 0;
492 
493 	if ( values ) {
494 		while ( !BER_BVISNULL( &values[i] ) ) {
495 			curr = rbac_bv2constraint( &values[i++] );
496 			if ( curr ) {
497 				curr->next = head;
498 				head = curr;
499 			}
500 		}
501 	}
502 
503 	return head;
504 }
505 
506 /*
507 
508 void main() {
509    item * curr, * head;
510    int i;
511 
512    head = NULL;
513 
514    for(i=1;i<=10;i++) {
515       curr = (item *)malloc(sizeof(item));
516       curr->val = i;
517       curr->next  = head;
518       head = curr;
519    }
520 
521    curr = head;
522 
523    while(curr) {
524       printf("%d\n", curr->val);
525       curr = curr->next ;
526    }
527 }
528 
529  */
530 
531 /*
532  *
533 rbac_user_role_constraints2(BerVarray values)
534 {
535 	rbac_constraint_t *tmp, *cp = NULL;
536 	int i = 0;
537 
538 	if (!values)
539 		goto done;
540 
541 	while (!BER_BVISNULL(&values[i])) {
542 		tmp = rbac_bv2constraint(&values[i++]);
543 		if (tmp) {
544 			if (!cp) {
545 				cp = tmp;
546 			} else {
547 				tmp->next = cp;
548 				cp = tmp;
549 				//cp->next = tmp;
550 				//cp = tmp->next;
551 
552 			}
553 		}
554 	}
555 
556 done:;
557 	return cp;
558 }
559 
560 
561 rbac_user_role_constraints3(rbac_constraint_t *values)
562 {
563 	rbac_constraint_t *tmp, *cp = NULL;
564 	int i = 0;
565 
566 	if (!values)
567 		goto done;
568 
569 	while (!BER_BVISNULL(values[i])) {
570 		tmp = rbac_bv2constraint(&values[i++]);
571 		if (tmp) {
572 			if (!cp) {
573 				cp = tmp;
574 			} else {
575 				tmp->next = cp;
576 				cp = tmp;
577 			}
578 		}
579 	}
580 
581 done:;
582 	return cp;
583 }
584 */
585 
586 void
rbac_free_user(rbac_user_t * userp)587 rbac_free_user( rbac_user_t *userp )
588 {
589 	if ( !userp ) return;
590 
591 	if ( !BER_BVISNULL( &userp->tenantid ) ) {
592 		ber_memfree( userp->tenantid.bv_val );
593 	}
594 
595 	if ( !BER_BVISNULL( &userp->uid ) ) {
596 		ber_memfree( userp->uid.bv_val );
597 	}
598 
599 	if ( !BER_BVISNULL( &userp->dn ) ) {
600 		ber_memfree( userp->dn.bv_val );
601 	}
602 
603 	if ( !BER_BVISNULL( &userp->constraints ) ) {
604 		ber_memfree( userp->constraints.bv_val );
605 	}
606 
607 	if ( !BER_BVISNULL( &userp->password ) ) {
608 		ber_memfree( userp->password.bv_val );
609 	}
610 
611 	if ( !BER_BVISNULL( &userp->msg ) ) {
612 		ber_memfree( userp->msg.bv_val );
613 	}
614 
615 	if ( userp->roles ) ber_bvarray_free( userp->roles );
616 
617 	if ( userp->role_constraints ) ber_bvarray_free( userp->role_constraints );
618 
619 	ch_free( userp );
620 }
621