Пример #1
0
static int
aci_list_get_rights(
	struct berval	*list,
	struct berval	*attr,
	struct berval	*val,
	slap_access_t	*grant,
	slap_access_t	*deny )
{
	struct berval	perm, actn, baseattr;
	slap_access_t	*mask;
	int		i, found;

	if ( attr == NULL || BER_BVISEMPTY( attr ) ) {
		attr = (struct berval *)&aci_bv[ ACI_BV_ENTRY ];

	} else if ( acl_get_part( attr, 0, ';', &baseattr ) > 0 ) {
		attr = &baseattr;
	}
	found = 0;
	ACL_INIT(*grant);
	ACL_INIT(*deny);
	/* loop through each permissions clause */
	for ( i = 0; acl_get_part( list, i, '$', &perm ) >= 0; i++ ) {
		if ( acl_get_part( &perm, 0, ';', &actn ) < 0 ) {
			continue;
		}

		if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_GRANT ], &actn ) == 0 ) {
			mask = grant;

		} else if ( ber_bvstrcasecmp( &aci_bv[ ACI_BV_DENY ], &actn ) == 0 ) {
			mask = deny;

		} else {
			continue;
		}

		*mask |= aci_list_get_attr_rights( &perm, attr, val );
		*mask |= aci_list_get_attr_rights( &perm, &aci_bv[ ACI_BV_BR_ALL ], NULL );

		if ( *mask != ACL_PRIV_NONE ) {
			found = 1;
		}
	}

	return found;
}
Пример #2
0
static int
aci_list_map_rights(
	struct berval	*list )
{
	struct berval	bv;
	slap_access_t	mask;
	int		i;

	ACL_INIT( mask );
	for ( i = 0; acl_get_part( list, i, ',', &bv ) >= 0; i++ ) {
		if ( bv.bv_len <= 0 ) {
			continue;
		}

		switch ( *bv.bv_val ) {
		case 'x':
			/* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt does not
			 * define any equivalent to the AUTH right, so I've just used
			 * 'x' for now.
			 */
			ACL_PRIV_SET(mask, ACL_PRIV_AUTH);
			break;
		case 'd':
			/* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
			 * the right 'd' to mean "delete"; we hijack it to mean
			 * "disclose" for consistency wuith the rest of slapd.
			 */
			ACL_PRIV_SET(mask, ACL_PRIV_DISCLOSE);
			break;
		case 'c':
			ACL_PRIV_SET(mask, ACL_PRIV_COMPARE);
			break;
		case 's':
			/* **** NOTE: draft-ietf-ldapext-aci-model-0.3.txt defines
			 * the right 's' to mean "set", but in the examples states
			 * that the right 's' means "search".  The latter definition
			 * is used here.
			 */
			ACL_PRIV_SET(mask, ACL_PRIV_SEARCH);
			break;
		case 'r':
			ACL_PRIV_SET(mask, ACL_PRIV_READ);
			break;
		case 'w':
			ACL_PRIV_SET(mask, ACL_PRIV_WRITE);
			break;
		default:
			break;
		}

	}

	return mask;
}
Пример #3
0
static slap_access_t
aci_list_get_attr_rights(
	struct berval		*list,
	const struct berval	*attr,
	struct berval		*val )
{
	struct berval	bv;
	slap_access_t	mask;
	int		i;

	/* loop through each rights/attr pair, skip first part (action) */
	ACL_INIT(mask);
	for ( i = 1; acl_get_part( list, i + 1, ';', &bv ) >= 0; i += 2 ) {
		if ( aci_list_has_attr( &bv, attr, val ) == 0 ) {
			Debug( LDAP_DEBUG_ACL,
				"        <= aci_list_get_attr_rights "
				"test %s for %s -> failed\n",
				bv.bv_val, attr->bv_val, 0 );
			continue;
		}

		Debug( LDAP_DEBUG_ACL,
			"        <= aci_list_get_attr_rights "
			"test %s for %s -> ok\n",
			bv.bv_val, attr->bv_val, 0 );

		if ( acl_get_part( list, i, ';', &bv ) < 0 ) {
			Debug( LDAP_DEBUG_ACL,
				"        <= aci_list_get_attr_rights "
				"test no rights\n",
				0, 0, 0 );
			continue;
		}

		mask |= aci_list_map_rights( &bv );
		Debug( LDAP_DEBUG_ACL,
			"        <= aci_list_get_attr_rights "
			"rights %s to mask 0x%x\n",
			bv.bv_val, mask, 0 );
	}

	return mask;
}
Пример #4
0
static int
dynacl_aci_mask(
	void			*priv,
	Operation		*op,
	Entry			*e,
	AttributeDescription	*desc,
	struct berval		*val,
	int			nmatch,
	regmatch_t		*matches,
	slap_access_t		*grantp,
	slap_access_t		*denyp )
{
	AttributeDescription	*ad = ( AttributeDescription * )priv;
	Attribute		*at;
	slap_access_t		tgrant, tdeny, grant, deny;
#ifdef LDAP_DEBUG
	char			accessmaskbuf[ACCESSMASK_MAXLEN];
	char			accessmaskbuf1[ACCESSMASK_MAXLEN];
#endif /* LDAP_DEBUG */

	if ( BER_BVISEMPTY( &e->e_nname ) ) {
		/* no ACIs in the root DSE */
		return -1;
	}

	/* start out with nothing granted, nothing denied */
	ACL_INIT(tgrant);
	ACL_INIT(tdeny);

	/* get the aci attribute */
	at = attr_find( e->e_attrs, ad );
	if ( at != NULL ) {
		int		i;

		/* the aci is an multi-valued attribute.  The
		 * rights are determined by OR'ing the individual
		 * rights given by the acis.
		 */
		for ( i = 0; !BER_BVISNULL( &at->a_nvals[i] ); i++ ) {
			if ( aci_mask( op, e, desc, val, &at->a_nvals[i],
					nmatch, matches, &grant, &deny,
					SLAP_ACI_SCOPE_ENTRY ) != 0 )
			{
				tgrant |= grant;
				tdeny |= deny;
			}
		}

		Debug( LDAP_DEBUG_ACL, "        <= aci_mask grant %s deny %s\n",
			  accessmask2str( tgrant, accessmaskbuf, 1 ),
			  accessmask2str( tdeny, accessmaskbuf1, 1 ) );
	}

	/* If the entry level aci didn't contain anything valid for the
	 * current operation, climb up the tree and evaluate the
	 * acis with scope set to subtree
	 */
	if ( tgrant == ACL_PRIV_NONE && tdeny == ACL_PRIV_NONE ) {
		struct berval	parent_ndn;

		dnParent( &e->e_nname, &parent_ndn );
		while ( !BER_BVISEMPTY( &parent_ndn ) ){
			int		i;
			BerVarray	bvals = NULL;
			int		ret, stop;

			/* to solve the chicken'n'egg problem of accessing
			 * the OpenLDAPaci attribute, the direct access
			 * to the entry's attribute is unchecked; however,
			 * further accesses to OpenLDAPaci values in the
			 * ancestors occur through backend_attribute(), i.e.
			 * with the identity of the operation, requiring
			 * further access checking.  For uniformity, this
			 * makes further requests occur as the rootdn, if
			 * any, i.e. searching for the OpenLDAPaci attribute
			 * is considered an internal search.  If this is not
			 * acceptable, then the same check needs be performed
			 * when accessing the entry's attribute. */
			struct berval	save_o_dn = {0}, save_o_ndn = {0};

			if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
				save_o_dn = op->o_dn;
				save_o_ndn = op->o_ndn;

				op->o_dn = op->o_bd->be_rootdn;
				op->o_ndn = op->o_bd->be_rootndn;
			}

			Debug( LDAP_DEBUG_ACL, "        checking ACI of \"%s\"\n", parent_ndn.bv_val );
			ret = backend_attribute( op, NULL, &parent_ndn, ad, &bvals, ACL_AUTH );

			if ( !BER_BVISNULL( &op->o_bd->be_rootndn ) ) {
				op->o_dn = save_o_dn;
				op->o_ndn = save_o_ndn;
			}

			switch ( ret ) {
			case LDAP_SUCCESS :
				stop = 0;
				if ( !bvals ) {
					break;
				}

				for ( i = 0; !BER_BVISNULL( &bvals[i] ); i++ ) {
					if ( aci_mask( op, e, desc, val,
							&bvals[i],
							nmatch, matches,
							&grant, &deny,
							SLAP_ACI_SCOPE_CHILDREN ) != 0 )
					{
						tgrant |= grant;
						tdeny |= deny;
						/* evaluation stops as soon as either a "deny" or a
						 * "grant" directive matches.
						 */
						if ( tgrant != ACL_PRIV_NONE || tdeny != ACL_PRIV_NONE ) {
							stop = 1;
						}
					}
					Debug( LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
						accessmask2str( tgrant, accessmaskbuf, 1 ),
						accessmask2str( tdeny, accessmaskbuf1, 1 ) );
				}
				break;

			case LDAP_NO_SUCH_ATTRIBUTE:
				/* just go on if the aci-Attribute is not present in
				 * the current entry
				 */
				Debug( LDAP_DEBUG_ACL, "no such attribute\n" );
				stop = 0;
				break;

			case LDAP_NO_SUCH_OBJECT:
				/* We have reached the base object */
				Debug( LDAP_DEBUG_ACL, "no such object\n" );
				stop = 1;
				break;

			default:
				stop = 1;
				break;
			}

			if ( stop ) {
				break;
			}
			dnParent( &parent_ndn, &parent_ndn );
		}
	}

	*grantp = tgrant;
	*denyp = tdeny;

	return 0;
}
Пример #5
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;
}