Exemplo n.º 1
0
static int
constraint_update( Operation *op, SlapReply *rs )
{
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	Backend *be = op->o_bd;
	constraint *c = on->on_bi.bi_private, *cp;
	Entry *target_entry = NULL, *target_entry_copy = NULL;
	Modifications *modlist, *m;
	BerVarray b = NULL;
	int i;
	struct berval rsv = BER_BVC("modify breaks constraint");
	int rc;
	char *msg = NULL;

	if (get_relax(op)) {
		return SLAP_CB_CONTINUE;
	}

	switch ( op->o_tag ) {
	case LDAP_REQ_MODIFY:
		modlist = op->orm_modlist;
		break;

	case LDAP_REQ_MODRDN:
		modlist = op->orr_modlist;
		break;

	default:
		/* impossible! assert? */
		return LDAP_OTHER;
	}
	
	Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "constraint_update()\n", 0,0,0);
	if ((m = modlist) == NULL) {
		op->o_bd->bd_info = (BackendInfo *)(on->on_info);
		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
						"constraint_update() got null modlist");
		return(rs->sr_err);
	}

	/* Do we need to count attributes? */
	for(cp = c; cp; cp = cp->ap_next) {
		if (cp->count != 0 || cp->set || cp->restrict_lud != 0) {
			op->o_bd = on->on_info->oi_origdb;
			rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &target_entry );
			op->o_bd = be;

			if (rc != 0 || target_entry == NULL) {
				Debug(LDAP_DEBUG_TRACE, 
					"==> constraint_update rc = %d DN=\"%s\"%s\n",
					rc, op->o_req_ndn.bv_val,
					target_entry ? "" : " not found" );
				if ( rc == 0 ) 
					rc = LDAP_CONSTRAINT_VIOLATION;
				goto mod_violation;
			}
			break;
		}
	}

	rc = LDAP_CONSTRAINT_VIOLATION;
	for(;m; m = m->sml_next) {
		unsigned ce = 0;

		if (is_at_operational( m->sml_desc->ad_type )) continue;

		if ((( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_ADD) &&
			(( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_REPLACE) &&
			(( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_DELETE))
			continue;
		/* we only care about ADD and REPLACE modifications */
		/* and DELETE are used to track attribute count */
		if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL))
			continue;

		/* Get this attribute count, if needed */
		if (target_entry)
			ce = constraint_count_attr(target_entry, m->sml_desc);

		for(cp = c; cp; cp = cp->ap_next) {
			int j;
			for (j = 0; cp->ap[j]; j++) {
				if (cp->ap[j] == m->sml_desc) {
					break;
				}
			}
			if (cp->ap[j] == NULL) continue;

			if (cp->restrict_lud != NULL && constraint_check_restrict(op, cp, target_entry) == 0) {
				continue;
			}

			if (cp->count != 0) {
				unsigned ca;

				if (m->sml_op == LDAP_MOD_DELETE)
					ce = 0;

				for (ca = 0; b[ca].bv_val; ++ca);

				Debug(LDAP_DEBUG_TRACE, 
					"==> constraint_update ce = %u, "
					"ca = %u, cp->count = %lu\n",
					ce, ca, (unsigned long) cp->count);

				if (m->sml_op == LDAP_MOD_ADD) {
					if (ca + ce > cp->count) {
						rc = LDAP_CONSTRAINT_VIOLATION;
						goto mod_violation;
					}
				}
				if (m->sml_op == LDAP_MOD_REPLACE) {
					if (ca > cp->count) {
						rc = LDAP_CONSTRAINT_VIOLATION;
						goto mod_violation;
					}
					ce = ca;
				}
			} 

			/* DELETE are to be ignored beyond this point */
			if (( m->sml_op & LDAP_MOD_OP ) == LDAP_MOD_DELETE)
				continue;

			for ( i = 0; b[i].bv_val; i++ ) {
				rc = constraint_violation( cp, &b[i], op, rs );
				if ( rc ) {
					goto mod_violation;
				}
			}

			if (cp->set && target_entry) {
				if (target_entry_copy == NULL) {
					Modifications *ml;

					target_entry_copy = entry_dup(target_entry);

					/* if rename, set the new entry's name
					 * (in normalized form only) */
					if ( op->o_tag == LDAP_REQ_MODRDN ) {
						struct berval pdn, ndn = BER_BVNULL;

						if ( op->orr_nnewSup ) {
							pdn = *op->orr_nnewSup;

						} else {
							dnParent( &target_entry_copy->e_nname, &pdn );
						}

						build_new_dn( &ndn, &pdn, &op->orr_nnewrdn, NULL ); 

						ber_memfree( target_entry_copy->e_nname.bv_val );
						target_entry_copy->e_nname = ndn;
						ber_bvreplace( &target_entry_copy->e_name, &ndn );
					}

					/* apply modifications, in an attempt
					 * to estimate what the entry would
					 * look like in case all modifications
					 * pass */
					for ( ml = modlist; ml; ml = ml->sml_next ) {
						Modification *mod = &ml->sml_mod;
						const char *text;
						char textbuf[SLAP_TEXT_BUFLEN];
						size_t textlen = sizeof(textbuf);
						int err;

						switch ( mod->sm_op ) {
						case LDAP_MOD_ADD:
							err = modify_add_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case LDAP_MOD_DELETE:
							err = modify_delete_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case LDAP_MOD_REPLACE:
							err = modify_replace_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case LDAP_MOD_INCREMENT:
							err = modify_increment_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
							break;

						case SLAP_MOD_SOFTADD:
 							mod->sm_op = LDAP_MOD_ADD;
							err = modify_add_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
 							mod->sm_op = SLAP_MOD_SOFTADD;
 							if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
 								err = LDAP_SUCCESS;
 							}
							break;

						case SLAP_MOD_SOFTDEL:
 							mod->sm_op = LDAP_MOD_ADD;
							err = modify_delete_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
 							mod->sm_op = SLAP_MOD_SOFTDEL;
 							if ( err == LDAP_NO_SUCH_ATTRIBUTE ) {
 								err = LDAP_SUCCESS;
 							}
							break;

						case SLAP_MOD_ADD_IF_NOT_PRESENT:
							if ( attr_find( target_entry_copy->e_attrs, mod->sm_desc ) ) {
								err = LDAP_SUCCESS;
								break;
							}
 							mod->sm_op = LDAP_MOD_ADD;
							err = modify_add_values( target_entry_copy,
								mod, get_permissiveModify(op),
								&text, textbuf, textlen );
 							mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT;
							break;

						default:
							err = LDAP_OTHER;
							break;
						}

						if ( err != LDAP_SUCCESS ) {
							rc = err;
							goto mod_violation;
						}
					}
				}

				if ( acl_match_set(&cp->val, op, target_entry_copy, NULL) == 0) {
					rc = LDAP_CONSTRAINT_VIOLATION;
					goto mod_violation;
				}
			}
		}
	}

	if (target_entry) {
		op->o_bd = on->on_info->oi_origdb;
		be_entry_release_r(op, target_entry);
		op->o_bd = be;
	}

	if (target_entry_copy) {
		entry_free(target_entry_copy);
	}

	return SLAP_CB_CONTINUE;

mod_violation:
	/* violation */
	if (target_entry) {
		op->o_bd = on->on_info->oi_origdb;
		be_entry_release_r(op, target_entry);
		op->o_bd = be;
	}

	if (target_entry_copy) {
		entry_free(target_entry_copy);
	}

	op->o_bd->bd_info = (BackendInfo *)(on->on_info);
	if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
		msg = print_message( &rsv, m->sml_desc );
	}
	send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, msg );
	ch_free(msg);
	return (rs->sr_err);
}
Exemplo n.º 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;
}
Exemplo n.º 3
0
static int
constraint_add( Operation *op, SlapReply *rs )
{
	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
	Attribute *a;
	constraint *c = on->on_bi.bi_private, *cp;
	BerVarray b = NULL;
	int i;
	struct berval rsv = BER_BVC("add breaks constraint");
	int rc;
	char *msg = NULL;

	if (get_relax(op)) {
		return SLAP_CB_CONTINUE;
	}

	if ((a = op->ora_e->e_attrs) == NULL) {
		op->o_bd->bd_info = (BackendInfo *)(on->on_info);
		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
			"constraint_add: no attrs");
		return(rs->sr_err);
	}

	for(; a; a = a->a_next ) {
		/* we don't constrain operational attributes */
		if (is_at_operational(a->a_desc->ad_type)) continue;

		for(cp = c; cp; cp = cp->ap_next) {
			int j;
			for (j = 0; cp->ap[j]; j++) {
				if (cp->ap[j] == a->a_desc) break;
			}
			if (cp->ap[j] == NULL) continue;
			if ((b = a->a_vals) == NULL) continue;

			if (cp->restrict_lud != NULL && constraint_check_restrict(op, cp, op->ora_e) == 0) {
				continue;
			}

			Debug(LDAP_DEBUG_TRACE, 
				"==> constraint_add, "
				"a->a_numvals = %u, cp->count = %lu\n",
				a->a_numvals, (unsigned long) cp->count, 0);

			if ((cp->count != 0) && (a->a_numvals > cp->count)) {
				rc = LDAP_CONSTRAINT_VIOLATION;
				goto add_violation;
			}

			for ( i = 0; b[i].bv_val; i++ ) {
				rc = constraint_violation( cp, &b[i], op, rs );
				if ( rc ) {
					goto add_violation;
				}
			}

			if (cp->set && acl_match_set(&cp->val, op, op->ora_e, NULL) == 0) {
				rc = LDAP_CONSTRAINT_VIOLATION;
				goto add_violation; /* constraint violation */
			}

		}
	}

	/* Default is to just fall through to the normal processing */
	return SLAP_CB_CONTINUE;

add_violation:
	op->o_bd->bd_info = (BackendInfo *)(on->on_info);
	if (rc == LDAP_CONSTRAINT_VIOLATION ) {
		msg = print_message( &rsv, a->a_desc );
	}
	send_ldap_error(op, rs, rc, msg );
	ch_free(msg);
	return (rs->sr_err);
}