Beispiel #1
0
/* Find the given attribute's value in the RDN of the DN */
int nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value)
{
	struct berval rdn;
	char *next;

	BER_BVZERO(value);
	dnRdn( dn, &rdn );
	do {
		next = ber_bvchr( &rdn, '+' );
		if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' &&
			!ber_bvcmp( &rdn, &ad->ad_cname )) {
			if ( next )
				rdn.bv_len = next - rdn.bv_val;
			value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1;
			value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1;
			break;
		}
		if ( !next )
			break;
		next++;
		rdn.bv_len -= next - rdn.bv_val;
		rdn.bv_val = next;
	} while (1);
}
Beispiel #2
0
static int
aci_mask(
	Operation		*op,
	Entry			*e,
	AttributeDescription	*desc,
	struct berval		*val,
	struct berval		*aci,
	int			nmatch,
	regmatch_t		*matches,
	slap_access_t		*grant,
	slap_access_t		*deny,
	slap_aci_scope_t	asserted_scope )
{
	struct berval		bv,
				scope,
				perms,
				type,
				opts,
				sdn;
	int			rc;

	ACL_INIT( *grant );
	ACL_INIT( *deny );

	assert( !BER_BVISNULL( &desc->ad_cname ) );

	/* parse an aci of the form:
		oid # scope # action;rights;attr;rights;attr
			$ action;rights;attr;rights;attr # type # subject

	   [NOTE: the following comment is very outdated,
	   as the draft version it refers to (Ando, 2004-11-20)].

	   See draft-ietf-ldapext-aci-model-04.txt section 9.1 for
	   a full description of the format for this attribute.
	   Differences: "this" in the draft is "self" here, and
	   "self" and "public" is in the position of type.

	   <scope> = {entry|children|subtree}
	   <type> = {public|users|access-id|subtree|onelevel|children|
	             self|dnattr|group|role|set|set-ref}

	   This routine now supports scope={ENTRY,CHILDREN}
	   with the semantics:
	     - ENTRY applies to "entry" and "subtree";
	     - CHILDREN applies to "children" and "subtree"
	 */

	/* check that the aci has all 5 components */
	if ( acl_get_part( aci, 4, '#', NULL ) < 0 ) {
		return 0;
	}

	/* check that the aci family is supported */
	/* FIXME: the OID is ignored? */
	if ( acl_get_part( aci, 0, '#', &bv ) < 0 ) {
		return 0;
	}

	/* check that the scope matches */
	if ( acl_get_part( aci, 1, '#', &scope ) < 0 ) {
		return 0;
	}

	/* note: scope can be either ENTRY or CHILDREN;
	 * they respectively match "entry" and "children" in bv
	 * both match "subtree" */
	switch ( asserted_scope ) {
	case SLAP_ACI_SCOPE_ENTRY:
		if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_ENTRY ] ) != 0
				&& ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
		{
			return 0;
		}
		break;

	case SLAP_ACI_SCOPE_CHILDREN:
		if ( ber_bvcmp( &scope, &aci_bv[ ACI_BV_CHILDREN ] ) != 0
				&& ber_bvstrcasecmp( &scope, &aci_bv[ ACI_BV_SUBTREE ] ) != 0 )
		{
			return 0;
		}
		break;

	case SLAP_ACI_SCOPE_SUBTREE:
		/* TODO: add assertion? */
		return 0;
	}

	/* get the list of permissions clauses, bail if empty */
	if ( acl_get_part( aci, 2, '#', &perms ) <= 0 ) {
		LDAP_BUG();
		return 0;
	}

	/* check if any permissions allow desired access */
	if ( aci_list_get_rights( &perms, &desc->ad_cname, val, grant, deny ) == 0 ) {
		return 0;
	}

	/* see if we have a DN match */
	if ( acl_get_part( aci, 3, '#', &type ) < 0 ) {
		LDAP_BUG();
		return 0;
	}

	/* see if we have a public (i.e. anonymous) access */
	if ( ber_bvcmp( &aci_bv[ ACI_BV_PUBLIC ], &type ) == 0 ) {
		return 1;
	}

	/* otherwise require an identity */
	if ( BER_BVISNULL( &op->o_ndn ) || BER_BVISEMPTY( &op->o_ndn ) ) {
		return 0;
	}

	/* see if we have a users access */
	if ( ber_bvcmp( &aci_bv[ ACI_BV_USERS ], &type ) == 0 ) {
		return 1;
	}

	/* NOTE: this may fail if a DN contains a valid '#' (unescaped);
	 * just grab all the berval up to its end (ITS#3303).
	 * NOTE: the problem could be solved by providing the DN with
	 * the embedded '#' encoded as hexpairs: "cn=Foo#Bar" would
	 * become "cn=Foo\23Bar" and be safely used by aci_mask(). */
#if 0
	if ( acl_get_part( aci, 4, '#', &sdn ) < 0 ) {
		return 0;
	}
#endif
	sdn.bv_val = type.bv_val + type.bv_len + STRLENOF( "#" );
	sdn.bv_len = aci->bv_len - ( sdn.bv_val - aci->bv_val );

	/* get the type options, if any */
	if ( acl_get_part( &type, 1, '/', &opts ) > 0 ) {
		opts.bv_len = type.bv_len - ( opts.bv_val - type.bv_val );
		type.bv_len = opts.bv_val - type.bv_val - 1;

	} else {
		BER_BVZERO( &opts );
	}

	if ( ber_bvcmp( &aci_bv[ ACI_BV_ACCESS_ID ], &type ) == 0 ) {
		return dn_match( &op->o_ndn, &sdn );

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_SUBTREE ], &type ) == 0 ) {
		return dnIsSuffix( &op->o_ndn, &sdn );

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_ONELEVEL ], &type ) == 0 ) {
		struct berval pdn;

		dnParent( &sdn, &pdn );

		return dn_match( &op->o_ndn, &pdn );

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_CHILDREN ], &type ) == 0 ) {
		return ( !dn_match( &op->o_ndn, &sdn ) && dnIsSuffix( &op->o_ndn, &sdn ) );

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_SELF ], &type ) == 0 ) {
		return dn_match( &op->o_ndn, &e->e_nname );

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_DNATTR ], &type ) == 0 ) {
		Attribute		*at;
		AttributeDescription	*ad = NULL;
		const char		*text;

		rc = slap_bv2ad( &sdn, &ad, &text );
		assert( rc == LDAP_SUCCESS );

		rc = 0;
		for ( at = attrs_find( e->e_attrs, ad );
				at != NULL;
				at = attrs_find( at->a_next, ad ) )
		{
			if ( attr_valfind( at,
				SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
					SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
				&op->o_ndn, NULL, op->o_tmpmemctx ) == 0 )
			{
				rc = 1;
				break;
			}
		}

		return rc;

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_GROUP ], &type ) == 0 ) {
		struct berval	oc,
				at;

		if ( BER_BVISNULL( &opts ) ) {
			oc = aci_bv[ ACI_BV_GROUP_CLASS ];
			at = aci_bv[ ACI_BV_GROUP_ATTR ];

		} else {
			if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
				LDAP_BUG();
			}

			if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
				at = aci_bv[ ACI_BV_GROUP_ATTR ];
			}
		}

		if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
		{
			return 1;
		}

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_ROLE ], &type ) == 0 ) {
		struct berval	oc,
				at;

		if ( BER_BVISNULL( &opts ) ) {
			oc = aci_bv[ ACI_BV_ROLE_CLASS ];
			at = aci_bv[ ACI_BV_ROLE_ATTR ];

		} else {
			if ( acl_get_part( &opts, 0, '/', &oc ) < 0 ) {
				LDAP_BUG();
			}

			if ( acl_get_part( &opts, 1, '/', &at ) < 0 ) {
				at = aci_bv[ ACI_BV_ROLE_ATTR ];
			}
		}

		if ( aci_group_member( &sdn, &oc, &at, op, e, nmatch, matches ) )
		{
			return 1;
		}

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET ], &type ) == 0 ) {
		if ( acl_match_set( &sdn, op, e, NULL ) ) {
			return 1;
		}

	} else if ( ber_bvcmp( &aci_bv[ ACI_BV_SET_REF ], &type ) == 0 ) {
		if ( acl_match_set( &sdn, op, e, (struct berval *)&aci_bv[ ACI_BV_SET_ATTR ] ) ) {
			return 1;
		}

	} else {
		/* it passed normalization! */
		LDAP_BUG();
	}

	return 0;
}
Beispiel #3
0
static int
do_base( char *uri, char *dn, struct berval *pass, char *base, char *filter, char *pwattr,
	int maxloop, int force, int chaserefs, int noinit, int delay,
	int action_type, void *action )
{
	LDAP	*ld = NULL;
	int  	i = 0;
	int     rc = LDAP_SUCCESS;
	ber_int_t msgid;
	LDAPMessage *res, *msg;
	char **dns = NULL;
	struct berval *creds = NULL;
	char *attrs[] = { LDAP_NO_ATTRS, NULL };
	int ndns = 0;
#ifdef _WIN32
	DWORD beg, end;
#else
	struct timeval beg, end;
#endif
	int version = LDAP_VERSION3;
	char *nullstr = "";

	ldap_initialize( &ld, uri );
	if ( ld == NULL ) {
		tester_perror( "ldap_initialize", NULL );
		exit( EXIT_FAILURE );
	}

	(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
	(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
		chaserefs ? LDAP_OPT_ON: LDAP_OPT_OFF );

	rc = ldap_sasl_bind_s( ld, dn, LDAP_SASL_SIMPLE, pass, NULL, NULL, NULL );
	if ( rc != LDAP_SUCCESS ) {
		tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
		exit( EXIT_FAILURE );
	}

	fprintf( stderr, "PID=%ld - Bind(%d): base=\"%s\", filter=\"%s\" attr=\"%s\".\n",
			(long) pid, maxloop, base, filter, pwattr );

	if ( pwattr != NULL ) {
		attrs[ 0 ] = pwattr;
	}
	rc = ldap_search_ext( ld, base, LDAP_SCOPE_SUBTREE,
			filter, attrs, 0, NULL, NULL, 0, 0, &msgid );
	if ( rc != LDAP_SUCCESS ) {
		tester_ldap_error( ld, "ldap_search_ext", NULL );
		exit( EXIT_FAILURE );
	}

	while ( ( rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ONE, NULL, &res ) ) > 0 )
	{
		BerElement *ber;
		struct berval bv;
		int done = 0;

		for ( msg = ldap_first_message( ld, res ); msg;
			msg = ldap_next_message( ld, msg ) )
		{
			switch ( ldap_msgtype( msg ) ) {
			case LDAP_RES_SEARCH_ENTRY:
				rc = ldap_get_dn_ber( ld, msg, &ber, &bv );
				dns = realloc( dns, (ndns + 1)*sizeof(char *) );
				dns[ndns] = ber_strdup( bv.bv_val );
				if ( pwattr != NULL ) {
					struct berval	**values = ldap_get_values_len( ld, msg, pwattr );

					creds = realloc( creds, (ndns + 1)*sizeof(struct berval) );
					if ( values == NULL ) {
novals:;
						creds[ndns].bv_len = 0;
						creds[ndns].bv_val = nullstr;

					} else {
						static struct berval	cleartext = BER_BVC( "{CLEARTEXT} " );
						struct berval		value = *values[ 0 ];

						if ( value.bv_val[ 0 ] == '{' ) {
							char *end = ber_bvchr( &value, '}' );

							if ( end ) {
								if ( ber_bvcmp( &value, &cleartext ) == 0 ) {
									value.bv_val += cleartext.bv_len;
									value.bv_len -= cleartext.bv_len;

								} else {
									ldap_value_free_len( values );
									goto novals;
								}
							}

						}

						ber_dupbv( &creds[ndns], &value );
						ldap_value_free_len( values );
					}
				}
				ndns++;
				ber_free( ber, 0 );
				break;

			case LDAP_RES_SEARCH_RESULT:
				done = 1;
				break;
			}
			if ( done )
				break;
		}
		ldap_msgfree( res );
		if ( done ) break;
	}

#ifdef _WIN32
	beg = GetTickCount();
#else
	gettimeofday( &beg, NULL );
#endif

	if ( ndns == 0 ) {
		tester_error( "No DNs" );
		return 1;
	}

	fprintf( stderr, "  PID=%ld - Bind base=\"%s\" filter=\"%s\" got %d values.\n",
		(long) pid, base, filter, ndns );

	/* Ok, got list of DNs, now start binding to each */
	for ( i = 0; i < maxloop; i++ ) {
		int		j;
		struct berval	cred = { 0, NULL };


#if 0	/* use high-order bits for better randomness (Numerical Recipes in "C") */
		j = rand() % ndns;
#endif
		j = ((double)ndns)*rand()/(RAND_MAX + 1.0);

		if ( creds && !BER_BVISEMPTY( &creds[j] ) ) {
			cred = creds[j];
		}

		if ( do_bind( uri, dns[j], &cred, 1, force, chaserefs, noinit, &ld,
			action_type, action ) && !force )
		{
			break;
		}

		if ( delay ) {
			sleep( delay );
		}
	}

	if ( ld != NULL ) {
		ldap_unbind_ext( ld, NULL, NULL );
		ld = NULL;
	}

#ifdef _WIN32
	end = GetTickCount();
	end -= beg;

	fprintf( stderr, "  PID=%ld - Bind done %d in %d.%03d seconds.\n",
		(long) pid, i, end / 1000, end % 1000 );
#else
	gettimeofday( &end, NULL );
	end.tv_usec -= beg.tv_usec;
	if (end.tv_usec < 0 ) {
		end.tv_usec += 1000000;
		end.tv_sec -= 1;
	}
	end.tv_sec -= beg.tv_sec;

	fprintf( stderr, "  PID=%ld - Bind done %d in %ld.%06ld seconds.\n",
		(long) pid, i, (long) end.tv_sec, (long) end.tv_usec );
#endif

	if ( dns ) {
		for ( i = 0; i < ndns; i++ ) {
			ber_memfree( dns[i] );
		}
		free( dns );
	}

	if ( creds ) {
		for ( i = 0; i < ndns; i++ ) {
			if ( creds[i].bv_val != nullstr ) {
				ber_memfree( creds[i].bv_val );
			}
		}
		free( creds );
	}

	return 0;
}
Beispiel #4
0
int ldap_dn2domain(
	LDAP_CONST char *dn_in,
	char **domainp)
{
	int i, j;
	char *ndomain;
	LDAPDN dn = NULL;
	LDAPRDN rdn = NULL;
	LDAPAVA *ava = NULL;
	struct berval domain = BER_BVNULL;
	static const struct berval DC = BER_BVC("DC");
	static const struct berval DCOID = BER_BVC("0.9.2342.19200300.100.1.25");

	assert( dn_in != NULL );
	assert( domainp != NULL );

	*domainp = NULL;

	if ( ldap_str2dn( dn_in, &dn, LDAP_DN_FORMAT_LDAP ) != LDAP_SUCCESS ) {
		return -2;
	}

	if( dn ) for( i=0; dn[i] != NULL; i++ ) {
		rdn = dn[i];

		for( j=0; rdn[j] != NULL; j++ ) {
			ava = rdn[j];

			if( rdn[j+1] == NULL &&
				(ava->la_flags & LDAP_AVA_STRING) &&
				ava->la_value.bv_len &&
				( ber_bvstrcasecmp( &ava->la_attr, &DC ) == 0
				|| ber_bvcmp( &ava->la_attr, &DCOID ) == 0 ) )
			{
				if( domain.bv_len == 0 ) {
					ndomain = LDAP_REALLOC( domain.bv_val,
						ava->la_value.bv_len + 1);

					if( ndomain == NULL ) {
						goto return_error;
					}

					domain.bv_val = ndomain;

					AC_MEMCPY( domain.bv_val, ava->la_value.bv_val,
						ava->la_value.bv_len );

					domain.bv_len = ava->la_value.bv_len;
					domain.bv_val[domain.bv_len] = '\0';

				} else {
					ndomain = LDAP_REALLOC( domain.bv_val,
						ava->la_value.bv_len + sizeof(".") + domain.bv_len );

					if( ndomain == NULL ) {
						goto return_error;
					}

					domain.bv_val = ndomain;
					domain.bv_val[domain.bv_len++] = '.';
					AC_MEMCPY( &domain.bv_val[domain.bv_len],
						ava->la_value.bv_val, ava->la_value.bv_len );
					domain.bv_len += ava->la_value.bv_len;
					domain.bv_val[domain.bv_len] = '\0';
				}
			} else {
				domain.bv_len = 0;
			}
		} 
	}


	if( domain.bv_len == 0 && domain.bv_val != NULL ) {
		LDAP_FREE( domain.bv_val );
		domain.bv_val = NULL;
	}

	ldap_dnfree( dn );
	*domainp = domain.bv_val;
	return 0;

return_error:
	ldap_dnfree( dn );
	LDAP_FREE( domain.bv_val );
	return -1;
}
Beispiel #5
0
/* set all the unique attrs of this objectclass into the table
 */
extern "C" int
ndb_oc_attrs(
	NdbTransaction *txn,
	const NdbDictionary::Table *myTable,
	Entry *e,
	NdbOcInfo *no,
	NdbAttrInfo **attrs,
	int nattrs,
	Attribute *old
)
{
	char buf[65538], *ptr;
	Attribute **an, **ao, *a;
	NdbOperation *myop;
	int i, j, max = 0;
	int changed, rc;
	Uint64 eid = e->e_id;

	if ( !nattrs )
		return 0;

	an = (Attribute **)ch_malloc( 2 * nattrs * sizeof(Attribute *));
	ao = an + nattrs;

	/* Turn lists of attrs into arrays for easier access */
	for ( i=0; i<nattrs; i++ ) {
		if ( attrs[i]->na_oi != no ) {
			an[i] = NULL;
			ao[i] = NULL;
			continue;
		}
		for ( a=e->e_attrs; a; a=a->a_next ) {
			if ( a->a_desc == slap_schema.si_ad_objectClass )
				continue;
			if ( a->a_desc->ad_type == attrs[i]->na_attr ) {
				/* Don't process same attr twice */
				if ( a->a_flags & SLAP_ATTR_IXADD )
					a = NULL;
				else
					a->a_flags |= SLAP_ATTR_IXADD;
				break;
			}
		}
		an[i] = a;
		if ( a && a->a_numvals > max )
			max = a->a_numvals;
		for ( a=old; a; a=a->a_next ) {
			if ( a->a_desc == slap_schema.si_ad_objectClass )
				continue;
			if ( a->a_desc->ad_type == attrs[i]->na_attr )
				break;
		}
		ao[i] = a;
		if ( a && a->a_numvals > max )
			max = a->a_numvals;
	}

	for ( i=0; i<max; i++ ) {
		myop = NULL;
		for ( j=0; j<nattrs; j++ ) {
			if ( !an[j] && !ao[j] )
				continue;
			changed = 0;
			if ( an[j] && an[j]->a_numvals > i ) {
				/* both old and new are present, compare for changes */
				if ( ao[j] && ao[j]->a_numvals > i ) {
					if ( ber_bvcmp( &ao[j]->a_nvals[i], &an[j]->a_nvals[i] ))
						changed = V_REP;
				} else {
					changed = V_INS;
				}
			} else {
				if ( ao[j] && ao[j]->a_numvals > i )
					changed = V_DEL;
			}
			if ( changed ) {
				if ( !myop ) {
					rc = LDAP_OTHER;
					myop = txn->getNdbOperation( myTable );
					if ( !myop ) {
						goto done;
					}
					if ( old ) {
						if ( myop->writeTuple()) {
							goto done;
						}
					} else {
						if ( myop->insertTuple()) {
							goto done;
						}
					}
					if ( myop->equal( EID_COLUMN, eid )) {
						goto done;
					}
					if ( myop->equal( VID_COLUMN, i )) {
						goto done;
					}
				}
				if ( attrs[j]->na_flag & NDB_INFO_ATBLOB ) {
					NdbBlob *myBlob = myop->getBlobHandle( attrs[j]->na_column );
					rc = LDAP_OTHER;
					if ( !myBlob ) {
						Debug( LDAP_DEBUG_TRACE, "ndb_oc_attrs: getBlobHandle failed %s (%d)\n",
							myop->getNdbError().message, myop->getNdbError().code, 0 );
						goto done;
					}
					if ( slapMode & SLAP_TOOL_MODE )
						ndb_flush_blobs = 1;
					if ( changed & V_INS ) {
						if ( myBlob->setValue( an[j]->a_vals[i].bv_val, an[j]->a_vals[i].bv_len )) {
							Debug( LDAP_DEBUG_TRACE, "ndb_oc_attrs: blob->setValue failed %s (%d)\n",
								myBlob->getNdbError().message, myBlob->getNdbError().code, 0 );
							goto done;
						}
					} else {
						if ( myBlob->setValue( NULL, 0 )) {
							Debug( LDAP_DEBUG_TRACE, "ndb_oc_attrs: blob->setValue failed %s (%d)\n",
								myBlob->getNdbError().message, myBlob->getNdbError().code, 0 );
							goto done;
						}
					}
				} else {
					if ( changed & V_INS ) {
						if ( an[j]->a_vals[i].bv_len > attrs[j]->na_len ) {
							Debug( LDAP_DEBUG_ANY, "ndb_oc_attrs: attribute %s too long for column\n",
								attrs[j]->na_name.bv_val, 0, 0 );
							rc = LDAP_CONSTRAINT_VIOLATION;
							goto done;
						}
						ptr = buf;
						*ptr++ = an[j]->a_vals[i].bv_len & 0xff;
						if ( attrs[j]->na_len > 255 ) {
							/* MedVar */
							*ptr++ = an[j]->a_vals[i].bv_len >> 8;
						}
						memcpy( ptr, an[j]->a_vals[i].bv_val, an[j]->a_vals[i].bv_len );
						ptr = buf;
					} else {
						ptr = NULL;
					}
					if ( myop->setValue( attrs[j]->na_column, ptr )) {
						rc = LDAP_OTHER;
						goto done;
					}
				}
			}
		}
Beispiel #6
0
static int ndb_dnid_cmp( const void *v1, const void *v2 )
{
	struct dn_id *dn1 = (struct dn_id *)v1,
		*dn2 = (struct dn_id *)v2;
	return ber_bvcmp( &dn1->dn, &dn2->dn );
}
Beispiel #7
0
int
bdb_db_cache(
	Backend	*be,
	struct berval *name,
	DB **dbout )
{
	int i, flags;
	int rc;
	struct bdb_info *bdb = (struct bdb_info *) be->be_private;
	struct bdb_db_info *db;
	char *file;

	*dbout = NULL;

	for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
		if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) {
			*dbout = bdb->bi_databases[i]->bdi_db;
			return 0;
		}
	}

	ldap_pvt_thread_mutex_lock( &bdb->bi_database_mutex );

	/* check again! may have been added by another thread */
	for( i=BDB_NDB; i < bdb->bi_ndatabases; i++ ) {
		if( !ber_bvcmp( &bdb->bi_databases[i]->bdi_name, name) ) {
			*dbout = bdb->bi_databases[i]->bdi_db;
			ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
			return 0;
		}
	}

	if( i >= BDB_INDICES ) {
		ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
		return -1;
	}

	db = (struct bdb_db_info *) ch_calloc(1, sizeof(struct bdb_db_info));

	ber_dupbv( &db->bdi_name, name );

	rc = db_create( &db->bdi_db, bdb->bi_dbenv, 0 );
	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_cache: db_create(%s) failed: %s (%d)\n",
			bdb->bi_dbenv_home, db_strerror(rc), rc );
		ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
		ch_free( db );
		return rc;
	}

	if( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
		rc = db->bdi_db->set_flags( db->bdi_db, DB_ENCRYPT );
		if ( rc ) {
			Debug( LDAP_DEBUG_ANY,
				"bdb_db_cache: db set_flags(DB_ENCRYPT)(%s) failed: %s (%d)\n",
				bdb->bi_dbenv_home, db_strerror(rc), rc );
			ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
			db->bdi_db->close( db->bdi_db, 0 );
			ch_free( db );
			return rc;
		}
	}

	if( bdb->bi_flags & BDB_CHKSUM ) {
		rc = db->bdi_db->set_flags( db->bdi_db, DB_CHKSUM );
		if ( rc ) {
			Debug( LDAP_DEBUG_ANY,
				"bdb_db_cache: db set_flags(DB_CHKSUM)(%s) failed: %s (%d)\n",
				bdb->bi_dbenv_home, db_strerror(rc), rc );
			ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
			db->bdi_db->close( db->bdi_db, 0 );
			ch_free( db );
			return rc;
		}
	}

	/* If no explicit size set, use the FS default */
	flags = bdb_db_findsize( bdb, name );
	if ( flags )
		rc = db->bdi_db->set_pagesize( db->bdi_db, flags );

#ifdef BDB_INDEX_USE_HASH
	rc = db->bdi_db->set_h_hash( db->bdi_db, bdb_db_hash );
#endif
	rc = db->bdi_db->set_flags( db->bdi_db, DB_DUP | DB_DUPSORT );

	file = ch_malloc( db->bdi_name.bv_len + sizeof(BDB_SUFFIX) );
	strcpy( file, db->bdi_name.bv_val );
	strcpy( file+db->bdi_name.bv_len, BDB_SUFFIX );

#ifdef HAVE_EBCDIC
	__atoe( file );
#endif
	flags = DB_CREATE | DB_THREAD;
#ifdef DB_AUTO_COMMIT
	if ( !( slapMode & SLAP_TOOL_QUICK ))
		flags |= DB_AUTO_COMMIT;
#endif
	/* Cannot Truncate when Transactions are in use */
	if ( (slapMode & (SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE)) ==
		(SLAP_TOOL_QUICK|SLAP_TRUNCATE_MODE))
			flags |= DB_TRUNCATE;

	rc = DB_OPEN( db->bdi_db,
		file, NULL /* name */,
		BDB_INDEXTYPE, bdb->bi_db_opflags | flags, bdb->bi_dbenv_mode );

	ch_free( file );

	if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"bdb_db_cache: db_open(%s) failed: %s (%d)\n",
			name->bv_val, db_strerror(rc), rc );
		ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
		db->bdi_db->close( db->bdi_db, 0 );
		ch_free( db );
		return rc;
	}

	bdb->bi_databases[i] = db;
	bdb->bi_ndatabases = i+1;

	*dbout = db->bdi_db;

	ldap_pvt_thread_mutex_unlock( &bdb->bi_database_mutex );
	return 0;
}
Beispiel #8
0
int passwd_extop(
	Operation *op,
	SlapReply *rs )
{
	struct berval id = {0, NULL}, hash, *rsp = NULL;
	req_pwdexop_s *qpw = &op->oq_pwdexop;
	req_extended_s qext = op->oq_extended;
	Modifications *ml;
	slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
	int i, nhash;
	char **hashes, idNul;
	int rc;
	BackendDB *op_be;
	int freenewpw = 0;
	struct berval dn = BER_BVNULL, ndn = BER_BVNULL;

	assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 );

	if( op->o_dn.bv_len == 0 ) {
		Statslog( LDAP_DEBUG_STATS, "%s PASSMOD\n",
			op->o_log_prefix, 0, 0, 0, 0 );
		rs->sr_text = "only authenticated users may change passwords";
		return LDAP_STRONG_AUTH_REQUIRED;
	}

	qpw->rs_old.bv_len = 0;
	qpw->rs_old.bv_val = NULL;
	qpw->rs_new.bv_len = 0;
	qpw->rs_new.bv_val = NULL;
	qpw->rs_mods = NULL;
	qpw->rs_modtail = NULL;

	rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
		&qpw->rs_old, &qpw->rs_new, &rs->sr_text );

	if ( !BER_BVISNULL( &id )) {
		idNul = id.bv_val[id.bv_len];
		id.bv_val[id.bv_len] = '\0';
	}
	if ( rs->sr_err == LDAP_SUCCESS && !BER_BVISEMPTY( &id ) ) {
		Statslog( LDAP_DEBUG_STATS, "%s PASSMOD id=\"%s\"%s%s\n",
			op->o_log_prefix, id.bv_val,
			qpw->rs_old.bv_val ? " old" : "",
			qpw->rs_new.bv_val ? " new" : "", 0 );
	} else {
		Statslog( LDAP_DEBUG_STATS, "%s PASSMOD%s%s\n",
			op->o_log_prefix,
			qpw->rs_old.bv_val ? " old" : "",
			qpw->rs_new.bv_val ? " new" : "", 0, 0 );
	}

	if ( rs->sr_err != LDAP_SUCCESS ) {
		if ( !BER_BVISNULL( &id ))
			id.bv_val[id.bv_len] = idNul;
		return rs->sr_err;
	}

	if ( !BER_BVISEMPTY( &id ) ) {
		rs->sr_err = dnPrettyNormal( NULL, &id, &dn, &ndn, op->o_tmpmemctx );
		id.bv_val[id.bv_len] = idNul;
		if ( rs->sr_err != LDAP_SUCCESS ) {
			rs->sr_text = "Invalid DN";
			rc = rs->sr_err;
			goto error_return;
		}
		op->o_req_dn = dn;
		op->o_req_ndn = ndn;
		op->o_bd = select_backend( &op->o_req_ndn, 1 );

	} else {
		ber_dupbv_x( &dn, &op->o_dn, op->o_tmpmemctx );
		ber_dupbv_x( &ndn, &op->o_ndn, op->o_tmpmemctx );
		op->o_req_dn = dn;
		op->o_req_ndn = ndn;
		ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
		op->o_bd = op->o_conn->c_authz_backend;
		ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
	}

	if( op->o_bd == NULL ) {
		if ( qpw->rs_old.bv_val != NULL ) {
			rs->sr_text = "unwilling to verify old password";
			rc = LDAP_UNWILLING_TO_PERFORM;
			goto error_return;
		}

#ifdef HAVE_CYRUS_SASL
		rc = slap_sasl_setpass( op, rs );
#else
		rs->sr_text = "no authz backend";
		rc = LDAP_OTHER;
#endif
		goto error_return;
	}

	if ( op->o_req_ndn.bv_len == 0 ) {
		rs->sr_text = "no password is associated with the Root DSE";
		rc = LDAP_UNWILLING_TO_PERFORM;
		goto error_return;
	}

	/* If we've got a glued backend, check the real backend */
	op_be = op->o_bd;
	if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
		op->o_bd = select_backend( &op->o_req_ndn, 0 );
	}

	if (backend_check_restrictions( op, rs,
			(struct berval *)&slap_EXOP_MODIFY_PASSWD ) != LDAP_SUCCESS) {
		rc = rs->sr_err;
		goto error_return;
	}

	/* check for referrals */
	if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
		rc = rs->sr_err;
		goto error_return;
	}

	/* This does not apply to multi-master case */
	if(!( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ))) {
		/* we SHOULD return a referral in this case */
		BerVarray defref = op->o_bd->be_update_refs
			? op->o_bd->be_update_refs : default_referral; 

		if( defref != NULL ) {
			rs->sr_ref = referral_rewrite( op->o_bd->be_update_refs,
				NULL, NULL, LDAP_SCOPE_DEFAULT );
			if(rs->sr_ref) {
				rs->sr_flags |= REP_REF_MUSTBEFREED;
			} else {
				rs->sr_ref = defref;
			}
			rc = LDAP_REFERRAL;
			goto error_return;

		}

		rs->sr_text = "shadow context; no update referral";
		rc = LDAP_UNWILLING_TO_PERFORM;
		goto error_return;
	}

	/* generate a new password if none was provided */
	if ( qpw->rs_new.bv_len == 0 ) {
		slap_passwd_generate( &qpw->rs_new );
		if ( qpw->rs_new.bv_len ) {
			rsp = slap_passwd_return( &qpw->rs_new );
			freenewpw = 1;
		}
	}
	if ( qpw->rs_new.bv_len == 0 ) {
		rs->sr_text = "password generation failed";
		rc = LDAP_OTHER;
		goto error_return;
	}

	op->o_bd = op_be;

	/* Give the backend a chance to handle this itself */
	if ( op->o_bd->be_extended ) {
		rs->sr_err = op->o_bd->be_extended( op, rs );
		if ( rs->sr_err != LDAP_UNWILLING_TO_PERFORM &&
			rs->sr_err != SLAP_CB_CONTINUE )
		{
			rc = rs->sr_err;
			if ( rsp ) {
				rs->sr_rspdata = rsp;
				rsp = NULL;
			}
			goto error_return;
		}
	}

	/* The backend didn't handle it, so try it here */
	if( op->o_bd && !op->o_bd->be_modify ) {
		rs->sr_text = "operation not supported for current user";
		rc = LDAP_UNWILLING_TO_PERFORM;
		goto error_return;
	}

	if ( qpw->rs_old.bv_val != NULL ) {
		Entry *e = NULL;

		rc = be_entry_get_rw( op, &op->o_req_ndn, NULL,
			slap_schema.si_ad_userPassword, 0, &e );
		if ( rc == LDAP_SUCCESS && e ) {
			Attribute *a = attr_find( e->e_attrs,
				slap_schema.si_ad_userPassword );
			if ( a )
				rc = slap_passwd_check( op, e, a, &qpw->rs_old, &rs->sr_text );
			else
				rc = 1;
			be_entry_release_r( op, e );
			if ( rc == LDAP_SUCCESS )
				goto old_good;
		}
		rs->sr_text = "unwilling to verify old password";
		rc = LDAP_UNWILLING_TO_PERFORM;
		goto error_return;
	}

old_good:
	ml = ch_malloc( sizeof(Modifications) );
	if ( !qpw->rs_modtail ) qpw->rs_modtail = &ml->sml_next;

	if ( default_passwd_hash ) {
		for ( nhash = 0; default_passwd_hash[nhash]; nhash++ );
		hashes = default_passwd_hash;
	} else {
		nhash = 1;
		hashes = (char **)defhash;
	}
	ml->sml_numvals = nhash;
	ml->sml_values = ch_malloc( (nhash+1)*sizeof(struct berval) );
	for ( i=0; hashes[i]; i++ ) {
		slap_passwd_hash_type( &qpw->rs_new, &hash, hashes[i], &rs->sr_text );
		if ( hash.bv_len == 0 ) {
			if ( !rs->sr_text ) {
				rs->sr_text = "password hash failed";
			}
			break;
		}
		ml->sml_values[i] = hash;
	}
	ml->sml_values[i].bv_val = NULL;
	ml->sml_nvalues = NULL;
	ml->sml_desc = slap_schema.si_ad_userPassword;
	ml->sml_type = ml->sml_desc->ad_cname;
	ml->sml_op = LDAP_MOD_REPLACE;
	ml->sml_flags = 0;
	ml->sml_next = qpw->rs_mods;
	qpw->rs_mods = ml;

	if ( hashes[i] ) {
		rs->sr_err = LDAP_OTHER;

	} else {
		slap_callback *sc = op->o_callback;

		op->o_tag = LDAP_REQ_MODIFY;
		op->o_callback = &cb;
		op->orm_modlist = qpw->rs_mods;
		op->orm_no_opattrs = 0;
		
		cb.sc_private = qpw;	/* let Modify know this was pwdMod,
					 * if it cares... */

		rs->sr_err = op->o_bd->be_modify( op, rs );

		/* be_modify() might have shuffled modifications */
		qpw->rs_mods = op->orm_modlist;

		if ( rs->sr_err == LDAP_SUCCESS ) {
			rs->sr_rspdata = rsp;

		} else if ( rsp ) {
			ber_bvfree( rsp );
			rsp = NULL;
		}
		op->o_tag = LDAP_REQ_EXTENDED;
		op->o_callback = sc;
	}

	rc = rs->sr_err;
	op->oq_extended = qext;

error_return:;
	if ( qpw->rs_mods ) {
		slap_mods_free( qpw->rs_mods, 1 );
	}
	if ( freenewpw ) {
		free( qpw->rs_new.bv_val );
	}
	if ( !BER_BVISNULL( &dn ) ) {
		op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
		BER_BVZERO( &op->o_req_dn );
	}
	if ( !BER_BVISNULL( &ndn ) ) {
		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
		BER_BVZERO( &op->o_req_ndn );
	}

	return rc;
}
Beispiel #9
0
static int
ldap_back_exop_passwd(
	Operation	*op,
	SlapReply	*rs,
	ldapconn_t	**lcp )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = *lcp;
	req_pwdexop_s	*qpw = &op->oq_pwdexop;
	LDAPMessage	*res;
	ber_int_t	msgid;
	int		rc, isproxy, freedn = 0;
	int		do_retry = 1;
	char		*text = NULL;
	struct berval	dn = op->o_req_dn,
			ndn = op->o_req_ndn;

	assert( lc != NULL );
	assert( rs->sr_ctrls == NULL );

	if ( BER_BVISNULL( &ndn ) && op->ore_reqdata != NULL ) {
		/* NOTE: most of this code is mutated
		 * from slap_passwd_parse();
		 * But here we only need
		 * the first berval... */

		ber_tag_t tag;
		ber_len_t len = -1;
		BerElementBuffer berbuf;
		BerElement *ber = (BerElement *)&berbuf;

		struct berval	tmpid = BER_BVNULL;

		if ( op->ore_reqdata->bv_len == 0 ) {
			return LDAP_PROTOCOL_ERROR;
		}

		/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
		ber_init2( ber, op->ore_reqdata, 0 );

		tag = ber_scanf( ber, "{" /*}*/ );

		if ( tag == LBER_ERROR ) {
			return LDAP_PROTOCOL_ERROR;
		}

		tag = ber_peek_tag( ber, &len );
		if ( tag == LDAP_TAG_EXOP_MODIFY_PASSWD_ID ) {
			tag = ber_get_stringbv( ber, &tmpid, LBER_BV_NOTERM );

			if ( tag == LBER_ERROR ) {
				return LDAP_PROTOCOL_ERROR;
			}
		}

		if ( !BER_BVISEMPTY( &tmpid ) ) {
			char idNull = tmpid.bv_val[tmpid.bv_len];
			tmpid.bv_val[tmpid.bv_len] = '\0';
			rs->sr_err = dnPrettyNormal( NULL, &tmpid, &dn,
				&ndn, op->o_tmpmemctx );
			tmpid.bv_val[tmpid.bv_len] = idNull;
			if ( rs->sr_err != LDAP_SUCCESS ) {
				/* should have been successfully parsed earlier! */
				return rs->sr_err;
			}
			freedn = 1;

		} else {
			dn = op->o_dn;
			ndn = op->o_ndn;
		}
	}

	isproxy = ber_bvcmp( &ndn, &op->o_ndn );

	Debug( LDAP_DEBUG_ARGS, "==> ldap_back_exop_passwd(\"%s\")%s\n",
		dn.bv_val, isproxy ? " (proxy)" : "", 0 );

retry:
	rc = ldap_passwd( lc->lc_ld,  &dn,
		qpw->rs_old.bv_val ? &qpw->rs_old : NULL,
		qpw->rs_new.bv_val ? &qpw->rs_new : NULL,
		op->o_ctrls, NULL, &msgid );

	if ( rc == LDAP_SUCCESS ) {
		/* TODO: set timeout? */
		/* by now, make sure no timeout is used (ITS#6282) */
		struct timeval tv = { -1, 0 };
		if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) == -1 ) {
			ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
			rs->sr_err = rc;

		} else {
			/* only touch when activity actually took place... */
			if ( li->li_idle_timeout ) {
				lc->lc_time = op->o_time;
			}

			/* sigh. parse twice, because parse_passwd
			 * doesn't give us the err / match / msg info.
			 */
			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
					(char **)&rs->sr_matched,
					&text,
					NULL, &rs->sr_ctrls, 0 );

			if ( rc == LDAP_SUCCESS ) {
				if ( rs->sr_err == LDAP_SUCCESS ) {
					struct berval	newpw;

					/* this never happens because 
					 * the frontend	is generating 
					 * the new password, so when
					 * the passwd exop is proxied,
					 * it never delegates password
					 * generation to the remote server
					 */
					rc = ldap_parse_passwd( lc->lc_ld, res,
							&newpw );
					if ( rc == LDAP_SUCCESS &&
							!BER_BVISNULL( &newpw ) )
					{
						rs->sr_type = REP_EXTENDED;
						rs->sr_rspdata = slap_passwd_return( &newpw );
						free( newpw.bv_val );
					}

				} else {
					rc = rs->sr_err;
				}
			}
			ldap_msgfree( res );
		}
	}

	if ( rc != LDAP_SUCCESS ) {
		rs->sr_err = slap_map_api2result( rs );
		if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
			do_retry = 0;
			if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
				goto retry;
			}
		}

		if ( LDAP_BACK_QUARANTINE( li ) ) {
			ldap_back_quarantine( op, rs );
		}

		if ( text ) rs->sr_text = text;
		send_ldap_extended( op, rs );
		/* otherwise frontend resends result */
		rc = rs->sr_err = SLAPD_ABANDON;

	} else if ( LDAP_BACK_QUARANTINE( li ) ) {
		ldap_back_quarantine( op, rs );
	}

	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_EXTENDED ], 1 );
	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );

	if ( freedn ) {
		op->o_tmpfree( dn.bv_val, op->o_tmpmemctx );
		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
	}

	/* these have to be freed anyway... */
	if ( rs->sr_matched ) {
		free( (char *)rs->sr_matched );
		rs->sr_matched = NULL;
	}

	if ( rs->sr_ctrls ) {
		ldap_controls_free( rs->sr_ctrls );
		rs->sr_ctrls = NULL;
	}

	if ( text ) {
		free( text );
		rs->sr_text = NULL;
	}

	/* in case, cleanup handler */
	if ( lc == NULL ) {
		*lcp = NULL;
	}

	return rc;
}
Beispiel #10
0
idattr_check_isowner (
    Operation	*op,
    Entry *user,
    Entry   *target,
    AttributeDescription *searchAttr,
    idattr_t *id)
{
    int rc = LDAP_INSUFFICIENT_ACCESS;
    int entry_rc = LDAP_INSUFFICIENT_ACCESS;
    Entry		*targetEntry = NULL;
    Entry		*requestEntry = NULL;
    Attribute	*ownerIDAttr = NULL;

    if (op->o_conn->c_authz.c_sai_krb5_auth_data_provisioned) {
        entry_rc = be_entry_get_rw( op, &target->e_nname, NULL, idattr_owneruuid, 0, &targetEntry );

        // check target for owner
        if (entry_rc == LDAP_SUCCESS && targetEntry != NULL) {
            Attribute *theOwnerIDAttr = NULL;

            theOwnerIDAttr = attr_find( targetEntry->e_attrs, idattr_owneruuid);

            if (theOwnerIDAttr && ber_bvcmp(&op->o_conn->c_authz.c_sai_krb5_pac_id , &theOwnerIDAttr->a_nvals[0]) == 0) {
                rc = LDAP_SUCCESS;
                Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by request[%s] - PROXYUSER BY TARGET\n", op->o_req_ndn.bv_val, 0, 0);
            } else {
                rc =  LDAP_INSUFFICIENT_ACCESS;
            }

        }
        // check entry for owner
        if ((rc != LDAP_SUCCESS) && !BER_BVISNULL(&op->o_req_ndn)) {
            entry_rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, idattr_owneruuid, 0, &requestEntry );
            if (entry_rc == LDAP_SUCCESS && requestEntry != NULL) {
                Attribute *theOwnerIDAttr = NULL;
                theOwnerIDAttr = attr_find( requestEntry->e_attrs, idattr_owneruuid);

                if (theOwnerIDAttr == NULL) {
                    rc =  LDAP_INSUFFICIENT_ACCESS;
                    goto exitonerror;
                }

                if (ber_bvcmp(&op->o_conn->c_authz.c_sai_krb5_pac_id , &theOwnerIDAttr->a_nvals[0]) == 0) {
                    rc = LDAP_SUCCESS;
                    Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by request[%s] - PROXYUSER BY ENTRY\n", op->o_req_ndn.bv_val, 0, 0);
                }

            }
        }

    } else {
        if (user == NULL) {
            rc =  LDAP_INSUFFICIENT_ACCESS;
            goto exitonerror;
        }

        ownerIDAttr = attr_find( user->e_attrs, searchAttr);

        if (ownerIDAttr == NULL) {
            rc =  LDAP_INSUFFICIENT_ACCESS;
            goto exitonerror;
        }

        entry_rc = be_entry_get_rw( op, &target->e_nname, NULL, idattr_owneruuid, 0, &targetEntry );

        if (entry_rc == LDAP_SUCCESS && targetEntry != NULL) {
            Attribute *theAttr = NULL;

            theAttr = attr_find( targetEntry->e_attrs, idattr_owneruuid);
            if (theAttr) {
                entry_rc = value_find_ex( idattr_owneruuid,
                                          SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
                                          SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
                                          theAttr->a_nvals, ownerIDAttr->a_nvals,
                                          op->o_tmpmemctx );
                if (entry_rc == LDAP_SUCCESS) {
                    rc = LDAP_SUCCESS;
                    Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by target[%s]\n", target->e_nname.bv_val, 0, 0);
                }

                // check group membership if applicable
                if (rc != LDAP_SUCCESS) {
                    u_int32_t isMember = 0;
                    if (BER_BVISNULL(&id->idattr_owner_dn)) {
                        idattr_id_to_dn (op,searchAttr, theAttr->a_nvals, &id->idattr_owner_dn);
                    }
                    if (!BER_BVISNULL(&id->idattr_owner_dn) && strstr(id->idattr_owner_dn.bv_val, group_subtree) != NULL) {
                        Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: len[%d] idattr_owner_dn[%s] \n", id->idattr_owner_dn.bv_len, id->idattr_owner_dn.bv_val, 0 );
                        idattr_is_member ( op, &id->idattr_owner_dn, idattr_memberships, ownerIDAttr->a_nvals , &isMember);
                        if (isMember) {
                            Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: user is member of Group (from target)\n", 0, 0, 0 );
                            rc = LDAP_SUCCESS;
                        }
                    }
                }
            }
        }
        // check op->o_req_ndn
        // target: cn=record,dc=com
        // request_dn: cn=myrecord,cn=record,dc=com
        // access to the parent (target) is required prior to requesting right access to the child (request_dn)
        // lookahead at the child to check for ownership
        if ((rc != LDAP_SUCCESS) && !BER_BVISNULL(&op->o_req_ndn)) {
            entry_rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, idattr_owneruuid, 0, &requestEntry );

            if (entry_rc == LDAP_SUCCESS && requestEntry != NULL) {
                Attribute *theAttr = NULL;

                theAttr = attr_find( requestEntry->e_attrs, idattr_owneruuid);
                if (theAttr) {
                    entry_rc = value_find_ex( idattr_owneruuid,
                                              SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
                                              SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
                                              theAttr->a_nvals, ownerIDAttr->a_nvals,
                                              op->o_tmpmemctx );
                    if (entry_rc == LDAP_SUCCESS) {
                        rc = LDAP_SUCCESS;
                        Debug(LDAP_DEBUG_ACL, "idattr_check_isowner by request[%s]\n", op->o_req_ndn.bv_val, 0, 0);
                    }

                    // check group membership if applicable
                    u_int32_t isMember = 0;
                    if (BER_BVISNULL(&id->idattr_owner_dn)) {
                        idattr_id_to_dn (op,searchAttr, theAttr->a_nvals, &id->idattr_owner_dn);
                    }
                    if (!BER_BVISNULL(&id->idattr_owner_dn) && strstr(id->idattr_owner_dn.bv_val, group_subtree) != NULL) {
                        Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: len[%d] id->idattr_owner_dn[%s] \n", id->idattr_owner_dn.bv_len, id->idattr_owner_dn.bv_val, 0 );
                        idattr_is_member ( op, &id->idattr_owner_dn, idattr_memberships, ownerIDAttr->a_nvals , &isMember);
                        if (isMember) {
                            Debug( LDAP_DEBUG_ACL, "idattr_check_isowner: user is member of Group (by parent)\n", 0, 0, 0 );
                            rc = LDAP_SUCCESS;
                        }
                    }
                }
            }
        }
    }
exitonerror:
    if (targetEntry)
        be_entry_release_r(op, targetEntry);
    if (requestEntry)
        be_entry_release_r(op, requestEntry);
    return rc;
}
Beispiel #11
0
static ber_tag_t
try_read1msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	LDAPConn **lcp,
	LDAPMessage **result )
{
	BerElement	*ber;
	LDAPMessage	*newmsg, *l, *prev;
	ber_int_t	id;
	int		idx;
	ber_tag_t	tag;
	ber_len_t	len;
	int		foundit = 0;
	LDAPRequest	*lr, *tmplr, dummy_lr = { 0 };
	LDAPConn	*lc;
	BerElement	tmpber;
	int		rc, refer_cnt, hadref, simple_request;
	ber_int_t	lderr;

#ifdef LDAP_CONNECTIONLESS
	LDAPMessage	*tmp = NULL, *chain_head = NULL;
	int		moremsgs = 0, isv2 = 0;
#endif

	assert( ld != NULL );
	assert( lcp != NULL );
	assert( *lcp != NULL );
	
#ifdef LDAP_R_COMPILE
	LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
#endif

	Debug( LDAP_DEBUG_TRACE, "read1msg: ld %p msgid %d all %d\n",
		(void *)ld, msgid, all );

	lc = *lcp;

retry:
	if ( lc->lconn_ber == NULL ) {
		lc->lconn_ber = ldap_alloc_ber_with_options( ld );

		if ( lc->lconn_ber == NULL ) {
			return -1;
		}
	}

	ber = lc->lconn_ber;
	assert( LBER_VALID (ber) );

	/* get the next message */
	sock_errset(0);
#ifdef LDAP_CONNECTIONLESS
	if ( LDAP_IS_UDP(ld) ) {
		struct sockaddr from;
		ber_int_sb_read( lc->lconn_sb, &from, sizeof(struct sockaddr) );
		if ( ld->ld_options.ldo_version == LDAP_VERSION2 ) isv2 = 1;
	}
nextresp3:
#endif
	tag = ber_get_next( lc->lconn_sb, &len, ber );
	switch ( tag ) {
	case LDAP_TAG_MESSAGE:
		/*
	 	 * We read a complete message.
	 	 * The connection should no longer need this ber.
	 	 */
		lc->lconn_ber = NULL;
		break;

	case LBER_DEFAULT:
#ifdef LDAP_DEBUG		   
		Debug( LDAP_DEBUG_CONNS,
			"ber_get_next failed.\n", 0, 0, 0 );
#endif		   
#ifdef EWOULDBLOCK			
		if ( sock_errno() == EWOULDBLOCK ) return LDAP_MSG_X_KEEP_LOOKING;
#endif
#ifdef EAGAIN
		if ( sock_errno() == EAGAIN ) return LDAP_MSG_X_KEEP_LOOKING;
#endif
		ld->ld_errno = LDAP_SERVER_DOWN;
#ifdef LDAP_R_COMPILE
		ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
		ldap_free_connection( ld, lc, 1, 0 );
#ifdef LDAP_R_COMPILE
		ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
		lc = *lcp = NULL;
		return -1;

	default:
		ld->ld_errno = LDAP_LOCAL_ERROR;
		return -1;
	}

	/* message id */
	if ( ber_get_int( ber, &id ) == LBER_ERROR ) {
		ber_free( ber, 1 );
		ld->ld_errno = LDAP_DECODING_ERROR;
		return( -1 );
	}

	/* id == 0 iff unsolicited notification message (RFC 4511) */

	/* if it's been abandoned, toss it */
	if ( id > 0 ) {
		if ( ldap_abandoned( ld, id, &idx ) ) {
			/* the message type */
			tag = ber_peek_tag( ber, &len );
			switch ( tag ) {
			case LDAP_RES_SEARCH_ENTRY:
			case LDAP_RES_SEARCH_REFERENCE:
			case LDAP_RES_INTERMEDIATE:
			case LBER_ERROR:
				break;

			default:
				/* there's no need to keep the id
				 * in the abandoned list any longer */
				ldap_mark_abandoned( ld, id, idx );
				break;
			}

			Debug( LDAP_DEBUG_ANY,
				"abandoned/discarded ld %p msgid %ld message type %s\n",
				(void *)ld, (long)id, ldap_int_msgtype2str( tag ) );

retry_ber:
			ber_free( ber, 1 );
			if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
				goto retry;
			}
			return( LDAP_MSG_X_KEEP_LOOKING );	/* continue looking */
		}

		lr = ldap_find_request_by_msgid( ld, id );
		if ( lr == NULL ) {
			const char	*msg = "unknown";

			/* the message type */
			tag = ber_peek_tag( ber, &len );
			switch ( tag ) {
			case LBER_ERROR:
				break;

			default:
				msg = ldap_int_msgtype2str( tag );
				break;
			}

			Debug( LDAP_DEBUG_ANY,
				"no request for response on ld %p msgid %ld message type %s (tossing)\n",
				(void *)ld, (long)id, msg );

			goto retry_ber;
		}

#ifdef LDAP_CONNECTIONLESS
		if ( LDAP_IS_UDP(ld) && isv2 ) {
			ber_scanf(ber, "x{");
		}
nextresp2:
#endif
	}

	/* the message type */
	tag = ber_peek_tag( ber, &len );
	if ( tag == LBER_ERROR ) {
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free( ber, 1 );
		return( -1 );
	}

	Debug( LDAP_DEBUG_TRACE,
		"read1msg: ld %p msgid %ld message type %s\n",
		(void *)ld, (long)lr->lr_msgid, ldap_int_msgtype2str( tag ) );

	if ( id == 0 ) {
		/* unsolicited notification message (RFC 4511) */
		if ( tag != LDAP_RES_EXTENDED ) {
			/* toss it */
			goto retry_ber;

			/* strictly speaking, it's an error; from RFC 4511:

4.4.  Unsolicited Notification

   An unsolicited notification is an LDAPMessage sent from the server to
   the client that is not in response to any LDAPMessage received by the
   server.  It is used to signal an extraordinary condition in the
   server or in the LDAP session between the client and the server.  The
   notification is of an advisory nature, and the server will not expect
   any response to be returned from the client.

   The unsolicited notification is structured as an LDAPMessage in which
   the messageID is zero and protocolOp is set to the extendedResp
   choice using the ExtendedResponse type (See Section 4.12).  The
   responseName field of the ExtendedResponse always contains an LDAPOID
   that is unique for this notification.

			 * however, since unsolicited responses
			 * are of advisory nature, better
			 * toss it, right now
			 */

#if 0
			ld->ld_errno = LDAP_DECODING_ERROR;
			ber_free( ber, 1 );
			return( -1 );
#endif
		}

		lr = &dummy_lr;
	}

	id = lr->lr_origid;
	refer_cnt = 0;
	hadref = simple_request = 0;
	rc = LDAP_MSG_X_KEEP_LOOKING;	/* default is to keep looking (no response found) */
	lr->lr_res_msgtype = tag;

	/*
	 * Check for V3 search reference
	 */
	if ( tag == LDAP_RES_SEARCH_REFERENCE ) {
		if ( ld->ld_version > LDAP_VERSION2 ) {
			/* This is a V3 search reference */
			if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
					lr->lr_parent != NULL )
			{
				char **refs = NULL;
				tmpber = *ber;

				/* Get the referral list */
				if ( ber_scanf( &tmpber, "{v}", &refs ) == LBER_ERROR ) {
					rc = LDAP_DECODING_ERROR;

				} else {
					/* Note: refs array is freed by ldap_chase_v3referrals */
					refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
						1, &lr->lr_res_error, &hadref );
					if ( refer_cnt > 0 ) {
						/* successfully chased reference */
						/* If haven't got end search, set chasing referrals */
						if ( lr->lr_status != LDAP_REQST_COMPLETED ) {
							lr->lr_status = LDAP_REQST_CHASINGREFS;
							Debug( LDAP_DEBUG_TRACE,
								"read1msg:  search ref chased, "
								"mark request chasing refs, "
								"id = %d\n",
								lr->lr_msgid, 0, 0 );
						}
					}
				}
			}
		}

	} else if ( tag != LDAP_RES_SEARCH_ENTRY && tag != LDAP_RES_INTERMEDIATE ) {
		/* All results that just return a status, i.e. don't return data
		 * go through the following code.  This code also chases V2 referrals
		 * and checks if all referrals have been chased.
		 */
		char		*lr_res_error = NULL;

		tmpber = *ber; 	/* struct copy */
		if ( ber_scanf( &tmpber, "{eAA", &lderr,
				&lr->lr_res_matched, &lr_res_error )
				!= LBER_ERROR )
		{
			if ( lr_res_error != NULL ) {
				if ( lr->lr_res_error != NULL ) {
					(void)ldap_append_referral( ld, &lr->lr_res_error, lr_res_error );
					LDAP_FREE( (char *)lr_res_error );

				} else {
					lr->lr_res_error = lr_res_error;
				}
				lr_res_error = NULL;
			}

			/* Do we need to check for referrals? */
			if ( LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_REFERRALS) ||
					lr->lr_parent != NULL )
			{
				char		**refs = NULL;
				ber_len_t	len;

				/* Check if V3 referral */
				if ( ber_peek_tag( &tmpber, &len ) == LDAP_TAG_REFERRAL ) {
					if ( ld->ld_version > LDAP_VERSION2 ) {
						/* Get the referral list */
						if ( ber_scanf( &tmpber, "{v}", &refs) == LBER_ERROR) {
							rc = LDAP_DECODING_ERROR;
							lr->lr_status = LDAP_REQST_COMPLETED;
							Debug( LDAP_DEBUG_TRACE,
								"read1msg: referral decode error, "
								"mark request completed, ld %p msgid %d\n",
								(void *)ld, lr->lr_msgid, 0 );

						} else {
							/* Chase the referral 
							 * refs array is freed by ldap_chase_v3referrals
							 */
							refer_cnt = ldap_chase_v3referrals( ld, lr, refs,
								0, &lr->lr_res_error, &hadref );
							lr->lr_status = LDAP_REQST_COMPLETED;
							Debug( LDAP_DEBUG_TRACE,
								"read1msg: referral %s chased, "
								"mark request completed, ld %p msgid %d\n",
								refer_cnt > 0 ? "" : "not",
								(void *)ld, lr->lr_msgid);
							if ( refer_cnt < 0 ) {
								refer_cnt = 0;
							}
						}
					}
				} else {
					switch ( lderr ) {
					case LDAP_SUCCESS:
					case LDAP_COMPARE_TRUE:
					case LDAP_COMPARE_FALSE:
						break;

					default:
						if ( lr->lr_res_error == NULL ) {
							break;
						}

						/* pedantic, should never happen */
						if ( lr->lr_res_error[ 0 ] == '\0' ) {
							LDAP_FREE( lr->lr_res_error );
							lr->lr_res_error = NULL;
							break;	
						}

						/* V2 referrals are in error string */
						refer_cnt = ldap_chase_referrals( ld, lr,
							&lr->lr_res_error, -1, &hadref );
						lr->lr_status = LDAP_REQST_COMPLETED;
						Debug( LDAP_DEBUG_TRACE,
							"read1msg:  V2 referral chased, "
							"mark request completed, id = %d\n",
							lr->lr_msgid, 0, 0 );
						break;
					}
				}
			}

			/* save errno, message, and matched string */
			if ( !hadref || lr->lr_res_error == NULL ) {
				lr->lr_res_errno =
					lderr == LDAP_PARTIAL_RESULTS
					? LDAP_SUCCESS : lderr;

			} else if ( ld->ld_errno != LDAP_SUCCESS ) {
				lr->lr_res_errno = ld->ld_errno;

			} else {
				lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
			}
		}

		/* in any case, don't leave any lr_res_error 'round */
		if ( lr_res_error ) {
			LDAP_FREE( lr_res_error );
		}

		Debug( LDAP_DEBUG_TRACE,
			"read1msg: ld %p %d new referrals\n",
			(void *)ld, refer_cnt, 0 );

		if ( refer_cnt != 0 ) {	/* chasing referrals */
			ber_free( ber, 1 );
			ber = NULL;
			if ( refer_cnt < 0 ) {
				ldap_return_request( ld, lr, 0 );
				return( -1 );	/* fatal error */
			}
			lr->lr_res_errno = LDAP_SUCCESS; /* sucessfully chased referral */

		} else {
			if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
				/* request without any referrals */
				simple_request = ( hadref ? 0 : 1 );

			} else {
				/* request with referrals or child request */
				ber_free( ber, 1 );
				ber = NULL;
			}

			lr->lr_status = LDAP_REQST_COMPLETED; /* declare this request done */
			Debug( LDAP_DEBUG_TRACE,
				"read1msg:  mark request completed, ld %p msgid %d\n",
				(void *)ld, lr->lr_msgid, 0);
			while ( lr->lr_parent != NULL ) {
				merge_error_info( ld, lr->lr_parent, lr );

				lr = lr->lr_parent;
				if ( --lr->lr_outrefcnt > 0 ) {
					break;	/* not completely done yet */
				}
			}

			/* Check if all requests are finished, lr is now parent */
			tmplr = lr;
			if ( tmplr->lr_status == LDAP_REQST_COMPLETED ) {
				for ( tmplr = lr->lr_child;
					tmplr != NULL;
					tmplr = tmplr->lr_refnext )
				{
					if ( tmplr->lr_status != LDAP_REQST_COMPLETED ) break;
				}
			}

			/* This is the parent request if the request has referrals */
			if ( lr->lr_outrefcnt <= 0 &&
				lr->lr_parent == NULL &&
				tmplr == NULL )
			{
				id = lr->lr_msgid;
				tag = lr->lr_res_msgtype;
				Debug( LDAP_DEBUG_TRACE, "request done: ld %p msgid %ld\n",
					(void *)ld, (long) id, 0 );
				Debug( LDAP_DEBUG_TRACE,
					"res_errno: %d, res_error: <%s>, "
					"res_matched: <%s>\n",
					lr->lr_res_errno,
					lr->lr_res_error ? lr->lr_res_error : "",
					lr->lr_res_matched ? lr->lr_res_matched : "" );
				if ( !simple_request ) {
					ber_free( ber, 1 );
					ber = NULL;
					if ( build_result_ber( ld, &ber, lr )
					    == LBER_ERROR )
					{
						rc = -1; /* fatal error */
					}
				}

				if ( lr != &dummy_lr ) {
					ldap_return_request( ld, lr, 1 );
				}
				lr = NULL;
			}

			/*
			 * RF 4511 unsolicited (id == 0) responses
			 * shouldn't necessarily end the connection
			 */
			if ( lc != NULL && id != 0 ) {
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
				ldap_free_connection( ld, lc, 0, 1 );
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
				lc = *lcp = NULL;
			}
		}
	}

	if ( lr != NULL ) {
		if ( lr != &dummy_lr ) {
			ldap_return_request( ld, lr, 0 );
		}
		lr = NULL;
	}

	if ( ber == NULL ) {
		return( rc );
	}

	/* try to handle unsolicited responses as appropriate */
	if ( id == 0 && msgid > LDAP_RES_UNSOLICITED ) {
		int	is_nod = 0;

		tag = ber_peek_tag( &tmpber, &len );

		/* we have a res oid */
		if ( tag == LDAP_TAG_EXOP_RES_OID ) {
			static struct berval	bv_nod = BER_BVC( LDAP_NOTICE_OF_DISCONNECTION );
			struct berval		resoid = BER_BVNULL;

			if ( ber_scanf( &tmpber, "m", &resoid ) == LBER_ERROR ) {
				ld->ld_errno = LDAP_DECODING_ERROR;
				ber_free( ber, 1 );
				return -1;
			}

			assert( !BER_BVISEMPTY( &resoid ) );

			is_nod = ber_bvcmp( &resoid, &bv_nod ) == 0;

			tag = ber_peek_tag( &tmpber, &len );
		}

#if 0 /* don't need right now */
		/* we have res data */
		if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
			struct berval resdata;

			if ( ber_scanf( &tmpber, "m", &resdata ) == LBER_ERROR ) {
				ld->ld_errno = LDAP_DECODING_ERROR;
				ber_free( ber, 0 );
				return ld->ld_errno;
			}

			/* use it... */
		}
#endif

		/* handle RFC 4511 "Notice of Disconnection" locally */

		if ( is_nod ) {
			if ( tag == LDAP_TAG_EXOP_RES_VALUE ) {
				ld->ld_errno = LDAP_DECODING_ERROR;
				ber_free( ber, 1 );
				return -1;
			}

			/* get rid of the connection... */
			if ( lc != NULL ) {
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
#endif
				ldap_free_connection( ld, lc, 0, 1 );
#ifdef LDAP_R_COMPILE
				ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
#endif
				lc = *lcp = NULL;
			}

			/* need to return -1, because otherwise
			 * a valid result is expected */
			return -1;
		}
	}

	/* make a new ldap message */
	newmsg = (LDAPMessage *) LDAP_CALLOC( 1, sizeof(LDAPMessage) );
	if ( newmsg == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return( -1 );
	}
	newmsg->lm_msgid = (int)id;
	newmsg->lm_msgtype = tag;
	newmsg->lm_ber = ber;
	newmsg->lm_chain_tail = newmsg;

#ifdef LDAP_CONNECTIONLESS
	/* CLDAP replies all fit in a single datagram. In LDAPv2 RFC1798
	 * the responses are all a sequence wrapped in one message. In
	 * LDAPv3 each response is in its own message. The datagram must
	 * end with a SearchResult. We can't just parse each response in
	 * separate calls to try_read1msg because the header info is only
	 * present at the beginning of the datagram, not at the beginning
	 * of each response. So parse all the responses at once and queue
	 * them up, then pull off the first response to return to the
	 * caller when all parsing is complete.
	 */
	if ( LDAP_IS_UDP(ld) ) {
		/* If not a result, look for more */
		if ( tag != LDAP_RES_SEARCH_RESULT ) {
			int ok = 0;
			moremsgs = 1;
			if (isv2) {
				/* LDAPv2: dup the current ber, skip past the current
				 * response, and see if there are any more after it.
				 */
				ber = ber_dup( ber );
				ber_scanf( ber, "x" );
				if ( ber_peek_tag( ber, &len ) != LBER_DEFAULT ) {
					/* There's more - dup the ber buffer so they can all be
					 * individually freed by ldap_msgfree.
					 */
					struct berval bv;
					ber_get_option( ber, LBER_OPT_BER_REMAINING_BYTES, &len );
					bv.bv_val = LDAP_MALLOC( len );
					if ( bv.bv_val ) {
						ok = 1;
						ber_read( ber, bv.bv_val, len );
						bv.bv_len = len;
						ber_init2( ber, &bv, ld->ld_lberoptions );
					}
				}
			} else {
				/* LDAPv3: Just allocate a new ber. Since this is a buffered
				 * datagram, if the sockbuf is readable we still have data
				 * to parse.
				 */
				ber = ldap_alloc_ber_with_options( ld );
				if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) ok = 1;
			}
			/* set up response chain */
			if ( tmp == NULL ) {
				newmsg->lm_next = ld->ld_responses;
				ld->ld_responses = newmsg;
				chain_head = newmsg;
			} else {
				tmp->lm_chain = newmsg;
			}
			chain_head->lm_chain_tail = newmsg;
			tmp = newmsg;
			/* "ok" means there's more to parse */
			if ( ok ) {
				if ( isv2 ) {
					goto nextresp2;

				} else {
					goto nextresp3;
				}
			} else {
				/* got to end of datagram without a SearchResult. Free
				 * our dup'd ber, but leave any buffer alone. For v2 case,
				 * the previous response is still using this buffer. For v3,
				 * the new ber has no buffer to free yet.
				 */
				ber_free( ber, 0 );
				return -1;
			}
		} else if ( moremsgs ) {
		/* got search result, and we had multiple responses in 1 datagram.
		 * stick the result onto the end of the chain, and then pull the
		 * first response off the head of the chain.
		 */
			tmp->lm_chain = newmsg;
			chain_head->lm_chain_tail = newmsg;
			*result = chkResponseList( ld, msgid, all );
			ld->ld_errno = LDAP_SUCCESS;
			return( (*result)->lm_msgtype );
		}
	}
#endif /* LDAP_CONNECTIONLESS */

	/* is this the one we're looking for? */
	if ( msgid == LDAP_RES_ANY || id == msgid ) {
		if ( all == LDAP_MSG_ONE
			|| ( newmsg->lm_msgtype != LDAP_RES_SEARCH_RESULT
			    	&& newmsg->lm_msgtype != LDAP_RES_SEARCH_ENTRY
			  	&& newmsg->lm_msgtype != LDAP_RES_SEARCH_REFERENCE ) )
		{
			*result = newmsg;
			ld->ld_errno = LDAP_SUCCESS;
			return( tag );

		} else if ( newmsg->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
			foundit = 1;	/* return the chain later */
		}
	}

	/* 
	 * if not, we must add it to the list of responses.  if
	 * the msgid is already there, it must be part of an existing
	 * search response.
	 */

	prev = NULL;
	for ( l = ld->ld_responses; l != NULL; l = l->lm_next ) {
		if ( l->lm_msgid == newmsg->lm_msgid ) {
			break;
		}
		prev = l;
	}

	/* not part of an existing search response */
	if ( l == NULL ) {
		if ( foundit ) {
			*result = newmsg;
			goto exit;
		}

		newmsg->lm_next = ld->ld_responses;
		ld->ld_responses = newmsg;
		goto exit;
	}

	Debug( LDAP_DEBUG_TRACE, "adding response ld %p msgid %ld type %ld:\n",
		(void *)ld, (long) newmsg->lm_msgid, (long) newmsg->lm_msgtype );

	/* part of a search response - add to end of list of entries */
	l->lm_chain_tail->lm_chain = newmsg;
	l->lm_chain_tail = newmsg;

	/* return the whole chain if that's what we were looking for */
	if ( foundit ) {
		if ( prev == NULL ) {
			ld->ld_responses = l->lm_next;
		} else {
			prev->lm_next = l->lm_next;
		}
		*result = l;
	}

exit:
	if ( foundit ) {
		ld->ld_errno = LDAP_SUCCESS;
		return( tag );
	}
	if ( lc && ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_DATA_READY, NULL ) ) {
		goto retry;
	}
	return( LDAP_MSG_X_KEEP_LOOKING );	/* continue looking */
}


static ber_tag_t
build_result_ber( LDAP *ld, BerElement **bp, LDAPRequest *lr )
{
	ber_len_t	len;
	ber_tag_t	tag;
	ber_int_t	along;
	BerElement *ber;

	*bp = NULL;
	ber = ldap_alloc_ber_with_options( ld );

	if( ber == NULL ) {
		ld->ld_errno = LDAP_NO_MEMORY;
		return LBER_ERROR;
	}

	if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
		lr->lr_res_msgtype, lr->lr_res_errno,
		lr->lr_res_matched ? lr->lr_res_matched : "",
		lr->lr_res_error ? lr->lr_res_error : "" ) == -1 )
	{
		ld->ld_errno = LDAP_ENCODING_ERROR;
		ber_free( ber, 1 );
		return( LBER_ERROR );
	}

	ber_reset( ber, 1 );

	if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free( ber, 1 );
		return( LBER_ERROR );
	}

	if ( ber_get_enum( ber, &along ) == LBER_ERROR ) {
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free( ber, 1 );
		return( LBER_ERROR );
	}

	tag = ber_peek_tag( ber, &len );

	if ( tag == LBER_ERROR ) {
		ld->ld_errno = LDAP_DECODING_ERROR;
		ber_free( ber, 1 );
		return( LBER_ERROR );
	}

	*bp = ber;
	return tag;
}
Beispiel #12
0
static int pbkdf2_check(
	const struct berval *scheme,
	const struct berval *passwd,
	const struct berval *cred,
	const char **text)
{
	int rc;
	int iteration;

	/* salt_value require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
	unsigned char salt_value[PBKDF2_SALT_SIZE + 1];
	char salt_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_SALT_SIZE) + 1];
	/* dk_value require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
	unsigned char dk_value[PBKDF2_MAX_DK_SIZE + 1];
	char dk_b64[LUTIL_BASE64_ENCODE_LEN(PBKDF2_MAX_DK_SIZE) + 1];
	unsigned char input_dk_value[PBKDF2_MAX_DK_SIZE];
	size_t dk_len;
#ifdef HAVE_OPENSSL
	const EVP_MD *md;
#elif HAVE_GNUTLS
	struct hmac_sha1_ctx sha1_ctx;
	struct hmac_sha256_ctx sha256_ctx;
	struct hmac_sha512_ctx sha512_ctx;
	void * current_ctx = NULL;
	pbkdf2_hmac_update current_hmac_update = NULL;
	pbkdf2_hmac_digest current_hmac_digest = NULL;
#endif

#ifdef SLAPD_PBKDF2_DEBUG
	printf("Checking for %s\n", scheme->bv_val);
	printf("  Stored Value:\t%s\n", passwd->bv_val);
	printf("  Input Cred:\t%s\n", cred->bv_val);
#endif

#ifdef HAVE_OPENSSL
	if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
		dk_len = PBKDF2_SHA1_DK_SIZE;
		md = EVP_sha1();
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
		dk_len = PBKDF2_SHA1_DK_SIZE;
		md = EVP_sha1();
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
		dk_len = PBKDF2_SHA256_DK_SIZE;
		md = EVP_sha256();
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
		dk_len = PBKDF2_SHA512_DK_SIZE;
		md = EVP_sha512();
	}else{
		return LUTIL_PASSWD_ERR;
	}
#elif HAVE_GNUTLS
	if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
		dk_len = PBKDF2_SHA1_DK_SIZE;
		current_ctx = &sha1_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
		hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
		dk_len = PBKDF2_SHA1_DK_SIZE;
		current_ctx = &sha1_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
		hmac_sha1_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
		dk_len = PBKDF2_SHA256_DK_SIZE;
		current_ctx = &sha256_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest;
		hmac_sha256_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
		dk_len = PBKDF2_SHA512_DK_SIZE;
		current_ctx = &sha512_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest;
		hmac_sha512_set_key(current_ctx, cred->bv_len, (const uint8_t *) cred->bv_val);
	}else{
		return LUTIL_PASSWD_ERR;
	}
#endif

	iteration = atoi(passwd->bv_val);
	if(iteration < 1){
		return LUTIL_PASSWD_ERR;
	}

	char *ptr;
	ptr = strchr(passwd->bv_val, '$');
	if(!ptr){
		return LUTIL_PASSWD_ERR;
	}
	ptr++; /* skip '$' */
	rc = ab64_to_b64(ptr, salt_b64, sizeof(salt_b64));
	if(rc < 0){
		return LUTIL_PASSWD_ERR;
	}

	ptr = strchr(ptr, '$');
	if(!ptr){
		return LUTIL_PASSWD_ERR;
	}
	ptr++; /* skip '$' */
	rc = ab64_to_b64(ptr, dk_b64, sizeof(dk_b64));
	if(rc < 0){
		return LUTIL_PASSWD_ERR;
	}

	/* The targetsize require PBKDF2_SALT_SIZE + 1 in lutil_b64_pton. */
	rc = lutil_b64_pton(salt_b64, salt_value, PBKDF2_SALT_SIZE + 1);
	if(rc < 0){
		return LUTIL_PASSWD_ERR;
	}

	/* consistency check */
	if(rc != PBKDF2_SALT_SIZE){
		return LUTIL_PASSWD_ERR;
	}

	/* The targetsize require PBKDF2_MAX_DK_SIZE + 1 in lutil_b64_pton. */
	rc = lutil_b64_pton(dk_b64, dk_value, sizeof(dk_value));
	if(rc < 0){
		return LUTIL_PASSWD_ERR;
	}

	/* consistency check */
	if(rc != dk_len){
		return LUTIL_PASSWD_ERR;
	}

#ifdef HAVE_OPENSSL
	if(!PKCS5_PBKDF2_HMAC(cred->bv_val, cred->bv_len,
						  salt_value, PBKDF2_SALT_SIZE,
						  iteration, md, dk_len, input_dk_value)){
		return LUTIL_PASSWD_ERR;
	}
#elif HAVE_GNUTLS
	PBKDF2(current_ctx, current_hmac_update, current_hmac_digest,
						  dk_len, iteration,
						  PBKDF2_SALT_SIZE, salt_value,
						  dk_len, input_dk_value);
#endif

	rc = memcmp(dk_value, input_dk_value, dk_len);
#ifdef SLAPD_PBKDF2_DEBUG
	printf("  Iteration:\t%d\n", iteration);
	printf("  Base64 Salt:\t%s\n", salt_b64);
	printf("  Base64 DK:\t%s\n", dk_b64);
	int i;
	printf("  Stored Salt:\t");
	for(i=0; i<PBKDF2_SALT_SIZE; i++){
		printf("%02x", salt_value[i]);
	}
	printf("\n");

	printf("  Stored DK:\t");
	for(i=0; i<dk_len; i++){
		printf("%02x", dk_value[i]);
	}
	printf("\n");

	printf("  Input DK:\t");
	for(i=0; i<dk_len; i++){
		printf("%02x", input_dk_value[i]);
	}
	printf("\n");
	printf("  Result:\t%d\n", rc);
#endif
	return rc?LUTIL_PASSWD_ERR:LUTIL_PASSWD_OK;
}
Beispiel #13
0
static int pbkdf2_encrypt(
	const struct berval *scheme,
	const struct berval *passwd,
	struct berval *msg,
	const char **text)
{
	unsigned char salt_value[PBKDF2_SALT_SIZE];
	struct berval salt;
	unsigned char dk_value[PBKDF2_MAX_DK_SIZE];
	struct berval dk;
	int iteration = PBKDF2_ITERATION;
	int rc;
#ifdef HAVE_OPENSSL
	const EVP_MD *md;
#elif HAVE_GNUTLS
	struct hmac_sha1_ctx sha1_ctx;
	struct hmac_sha256_ctx sha256_ctx;
	struct hmac_sha512_ctx sha512_ctx;
	void * current_ctx = NULL;
	pbkdf2_hmac_update current_hmac_update = NULL;
	pbkdf2_hmac_digest current_hmac_digest = NULL;
#endif

	salt.bv_val = (char *)salt_value;
	salt.bv_len = sizeof(salt_value);
	dk.bv_val = (char *)dk_value;

#ifdef HAVE_OPENSSL
	if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
		dk.bv_len = PBKDF2_SHA1_DK_SIZE;
		md = EVP_sha1();
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
		dk.bv_len = PBKDF2_SHA1_DK_SIZE;
		md = EVP_sha1();
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
		dk.bv_len = PBKDF2_SHA256_DK_SIZE;
		md = EVP_sha256();
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
		dk.bv_len = PBKDF2_SHA512_DK_SIZE;
		md = EVP_sha512();
	}else{
		return LUTIL_PASSWD_ERR;
	}
#elif HAVE_GNUTLS
	if(!ber_bvcmp(scheme, &pbkdf2_scheme)){
		dk.bv_len = PBKDF2_SHA1_DK_SIZE;
		current_ctx = &sha1_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
		hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha1_scheme)){
		dk.bv_len = PBKDF2_SHA1_DK_SIZE;
		current_ctx = &sha1_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha1_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha1_digest;
		hmac_sha1_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha256_scheme)){
		dk.bv_len = PBKDF2_SHA256_DK_SIZE;
		current_ctx = &sha256_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha256_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha256_digest;
		hmac_sha256_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
	}else if(!ber_bvcmp(scheme, &pbkdf2_sha512_scheme)){
		dk.bv_len = PBKDF2_SHA512_DK_SIZE;
		current_ctx = &sha512_ctx;
		current_hmac_update = (pbkdf2_hmac_update) &hmac_sha512_update;
		current_hmac_digest = (pbkdf2_hmac_digest) &hmac_sha512_digest;
		hmac_sha512_set_key(current_ctx, passwd->bv_len, (const uint8_t *) passwd->bv_val);
	}else{
		return LUTIL_PASSWD_ERR;
	}
#endif

	if(lutil_entropy((unsigned char *)salt.bv_val, salt.bv_len) < 0){
		return LUTIL_PASSWD_ERR;
	}

#ifdef HAVE_OPENSSL
	if(!PKCS5_PBKDF2_HMAC(passwd->bv_val, passwd->bv_len,
						  (unsigned char *)salt.bv_val, salt.bv_len,
						  iteration, md, dk.bv_len, dk_value)){
		return LUTIL_PASSWD_ERR;
	}
#elif HAVE_GNUTLS
	PBKDF2(current_ctx, current_hmac_update, current_hmac_digest,
						  dk.bv_len, iteration,
						  salt.bv_len, (const uint8_t *) salt.bv_val,
						  dk.bv_len, dk_value);
#endif

#ifdef SLAPD_PBKDF2_DEBUG
	printf("Encrypt for %s\n", scheme->bv_val);
	printf("  Password:\t%s\n", passwd->bv_val);

	printf("  Salt:\t\t");
	int i;
	for(i=0; i<salt.bv_len; i++){
		printf("%02x", salt_value[i]);
	}
	printf("\n");
	printf("  Iteration:\t%d\n", iteration);

	printf("  DK:\t\t");
	for(i=0; i<dk.bv_len; i++){
		printf("%02x", dk_value[i]);
	}
	printf("\n");
#endif

	rc = pbkdf2_format(scheme, iteration, &salt, &dk, msg);

#ifdef SLAPD_PBKDF2_DEBUG
	printf("  Output:\t%s\n", msg->bv_val);
#endif

	return rc;
}