static int aci_list_has_attr( struct berval *list, const struct berval *attr, struct berval *val ) { struct berval bv, left, right; int i; for ( i = 0; acl_get_part( list, i, ',', &bv ) >= 0; i++ ) { if ( acl_get_part(&bv, 0, '=', &left ) < 0 || acl_get_part( &bv, 1, '=', &right ) < 0 ) { if ( ber_bvstrcasecmp( attr, &bv ) == 0 ) { return(1); } } else if ( val == NULL ) { if ( ber_bvstrcasecmp( attr, &left ) == 0 ) { return(1); } } else { if ( ber_bvstrcasecmp( attr, &left ) == 0 ) { /* FIXME: this is also totally undocumented! */ /* this is experimental code that implements a * simple (prefix) match of the attribute value. * the ACI draft does not provide for aci's that * apply to specific values, but it would be * nice to have. If the <attr> part of an aci's * rights list is of the form <attr>=<value>, * that means the aci applies only to attrs with * the given value. Furthermore, if the attr is * of the form <attr>=<value>*, then <value> is * treated as a prefix, and the aci applies to * any value with that prefix. * * Ideally, this would allow r.e. matches. */ if ( acl_get_part( &right, 0, '*', &left ) < 0 || right.bv_len <= left.bv_len ) { if ( ber_bvstrcasecmp( val, &right ) == 0 ) { return 1; } } else if ( val->bv_len >= left.bv_len ) { if ( strncasecmp( val->bv_val, left.bv_val, left.bv_len ) == 0 ) { return(1); } } } } } return 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; }
static SearchScope_t ldap_distproc_bv2ss( struct berval *bv ) { ReferenceType_t ss; for ( ss = 0; !BER_BVISNULL( &bv2ss[ ss ] ); ss++ ) { if ( ber_bvstrcasecmp( bv, &bv2ss[ ss ] ) == 0 ) { return ss; } } return LDAP_DP_SS_UNKNOWN; }
static ReferenceType_t ldap_distproc_bv2rt( struct berval *bv ) { ReferenceType_t rt; for ( rt = 0; !BER_BVISNULL( &bv2rt[ rt ] ); rt++ ) { if ( ber_bvstrcasecmp( bv, &bv2rt[ rt ] ) == 0 ) { return rt; } } return LDAP_DP_RT_UNKNOWN; }
/* * Matches given berval to array of bervals * Returns: * >=0 if one if the array elements equals to this berval * -1 if string was not found in array */ static int bv_getcaseidx( struct berval *bv, const struct berval *arr[] ) { int i; if ( BER_BVISEMPTY( bv ) ) { return -1; } for ( i = 0; arr[ i ] != NULL ; i++ ) { if ( ber_bvstrcasecmp( bv, arr[ i ] ) == 0 ) { return i; } } return -1; }
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; }
static int OpenLDAPaciNormalizeRight( struct berval *action, struct berval *naction, void *ctx ) { struct berval grantdeny, perms = BER_BVNULL, bv = BER_BVNULL; int idx, i; /* grant|deny */ if ( acl_get_part( action, 0, ';', &grantdeny ) < 0 ) { Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: missing ';' in '%s'\n", action->bv_val ); return LDAP_INVALID_SYNTAX; } idx = bv_getcaseidx( &grantdeny, ACIgrantdeny ); if ( idx == -1 ) { Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: '%s' must be grant or deny\n", grantdeny.bv_val ); return LDAP_INVALID_SYNTAX; } ber_dupbv_x( naction, (struct berval *)ACIgrantdeny[ idx ], ctx ); for ( i = 1; acl_get_part( action, i, ';', &bv ) >= 0; i++ ) { struct berval nattrs = BER_BVNULL; int freenattrs = 1; if ( i & 1 ) { /* perms */ if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS ) { return LDAP_INVALID_SYNTAX; } perms = bv; } else { /* attr */ char *ptr; /* could be "[all]" or an attribute description */ if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) { nattrs = aci_bv[ ACI_BV_BR_ALL ]; freenattrs = 0; } else { AttributeDescription *ad = NULL; AttributeDescription adstatic= { 0 }; const char *text = NULL; struct berval attr, left, right; int j; int len; for ( j = 0; acl_get_part( &bv, j, ',', &attr ) >= 0; j++ ) { ad = NULL; text = NULL; /* openldap 2.1 aci compabitibility [entry] -> entry */ if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_ENTRY ] ) == 0 ) { ad = &adstatic; adstatic.ad_cname = aci_bv[ ACI_BV_ENTRY ]; /* openldap 2.1 aci compabitibility [children] -> children */ } else if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_CHILDREN ] ) == 0 ) { ad = &adstatic; adstatic.ad_cname = aci_bv[ ACI_BV_CHILDREN ]; /* openldap 2.1 aci compabitibility [all] -> only [all] */ } else if ( ber_bvstrcasecmp( &attr, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) { ber_memfree_x( nattrs.bv_val, ctx ); nattrs = aci_bv[ ACI_BV_BR_ALL ]; freenattrs = 0; break; } else if ( acl_get_part( &attr, 0, '=', &left ) < 0 || acl_get_part( &attr, 1, '=', &right ) < 0 ) { if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS ) { ber_memfree_x( nattrs.bv_val, ctx ); Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: unknown attribute: '%s'\n", attr.bv_val ); return LDAP_INVALID_SYNTAX; } } else { if ( slap_bv2ad( &left, &ad, &text ) != LDAP_SUCCESS ) { ber_memfree_x( nattrs.bv_val, ctx ); Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: unknown attribute: '%s'\n", left.bv_val ); return LDAP_INVALID_SYNTAX; } } len = nattrs.bv_len + ( !BER_BVISEMPTY( &nattrs ) ? STRLENOF( "," ) : 0 ) + ad->ad_cname.bv_len; nattrs.bv_val = ber_memrealloc_x( nattrs.bv_val, len + 1, ctx ); ptr = &nattrs.bv_val[ nattrs.bv_len ]; if ( !BER_BVISEMPTY( &nattrs ) ) { *ptr++ = ','; } ptr = lutil_strncopy( ptr, ad->ad_cname.bv_val, ad->ad_cname.bv_len ); ptr[ 0 ] = '\0'; nattrs.bv_len = len; } } naction->bv_val = ber_memrealloc_x( naction->bv_val, naction->bv_len + STRLENOF( ";" ) + perms.bv_len + STRLENOF( ";" ) + nattrs.bv_len + 1, ctx ); ptr = &naction->bv_val[ naction->bv_len ]; ptr[ 0 ] = ';'; ptr++; ptr = lutil_strncopy( ptr, perms.bv_val, perms.bv_len ); ptr[ 0 ] = ';'; ptr++; ptr = lutil_strncopy( ptr, nattrs.bv_val, nattrs.bv_len ); ptr[ 0 ] = '\0'; naction->bv_len += STRLENOF( ";" ) + perms.bv_len + STRLENOF( ";" ) + nattrs.bv_len; if ( freenattrs ) { ber_memfree_x( nattrs.bv_val, ctx ); } } } /* perms;attr go in pairs */ if ( i > 1 && ( i & 1 ) ) { return LDAP_SUCCESS; } else { Debug( LDAP_DEBUG_ACL, "aciNormalizeRight: perms:attr need to be pairs in '%s'\n", action->bv_val ); return LDAP_INVALID_SYNTAX; } }
static int OpenLDAPaciValidateRight( struct berval *action ) { struct berval bv = BER_BVNULL; int i; /* grant|deny */ if ( acl_get_part( action, 0, ';', &bv ) < 0 || bv_getcaseidx( &bv, ACIgrantdeny ) == -1 ) { Debug( LDAP_DEBUG_ACL, "aciValidateRight: '%s' must be either 'grant' or 'deny'\n", bv.bv_val ); return LDAP_INVALID_SYNTAX; } for ( i = 0; acl_get_part( action, i + 1, ';', &bv ) >= 0; i++ ) { if ( i & 1 ) { /* perms */ if ( OpenLDAPaciValidatePerms( &bv ) != LDAP_SUCCESS ) { return LDAP_INVALID_SYNTAX; } } else { /* attr */ AttributeDescription *ad; const char *text; struct berval attr, left, right; int j; /* could be "[all]" or an attribute description */ if ( ber_bvstrcasecmp( &bv, &aci_bv[ ACI_BV_BR_ALL ] ) == 0 ) { continue; } for ( j = 0; acl_get_part( &bv, j, ',', &attr ) >= 0; j++ ) { ad = NULL; text = NULL; if ( acl_get_part( &attr, 0, '=', &left ) < 0 || acl_get_part( &attr, 1, '=', &right ) < 0 ) { if ( slap_bv2ad( &attr, &ad, &text ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ACL, "aciValidateRight: unknown attribute: '%s'\n", attr.bv_val ); return LDAP_INVALID_SYNTAX; } } else { if ( slap_bv2ad( &left, &ad, &text ) != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ACL, "aciValidateRight: unknown attribute: '%s'\n", left.bv_val ); return LDAP_INVALID_SYNTAX; } } } } } /* "perms;attr" go in pairs */ if ( i > 0 && ( i & 1 ) == 0 ) { return LDAP_SUCCESS; } else { Debug( LDAP_DEBUG_ACL, "aciValidateRight: perms:attr need to be pairs in '%s'\n", action->bv_val ); return LDAP_INVALID_SYNTAX; } return LDAP_SUCCESS; }
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; }
static int ndb_name_cmp( const void *v1, const void *v2 ) { NdbOcInfo *oc1 = (NdbOcInfo *)v1, *oc2 = (NdbOcInfo *)v2; return ber_bvstrcasecmp( &oc1->no_name, &oc2->no_name ); }
static int ndb_oc_list( struct ndb_info *ni, const NdbDictionary::Dictionary *myDict, struct berval *oname, int implied, NdbOcs *out ) { const NdbDictionary::Table *myTable; NdbOcInfo *oci, octmp; ObjectClass *oc; int i, rc; /* shortcut top */ if ( ber_bvstrcasecmp( oname, &slap_schema.si_oc_top->soc_cname )) { octmp.no_name = *oname; oci = (NdbOcInfo *)avl_find( ni->ni_oc_tree, &octmp, ndb_name_cmp ); if ( oci ) { oc = oci->no_oc; } else { oc = oc_bvfind( oname ); if ( !oc ) { /* undefined - shouldn't happen */ return LDAP_INVALID_SYNTAX; } } if ( oc->soc_sups ) { int i; for ( i=0; oc->soc_sups[i]; i++ ) { rc = ndb_oc_list( ni, myDict, &oc->soc_sups[i]->soc_cname, 1, out ); if ( rc ) return rc; } } } else { oc = slap_schema.si_oc_top; } /* Only insert once */ for ( i=0; i<out->no_ntext; i++ ) if ( out->no_text[i].bv_val == oc->soc_cname.bv_val ) break; if ( i == out->no_ntext ) { for ( i=0; i<out->no_nitext; i++ ) if ( out->no_itext[i].bv_val == oc->soc_cname.bv_val ) break; if ( i == out->no_nitext ) { if ( implied ) out->no_itext[out->no_nitext++] = oc->soc_cname; else out->no_text[out->no_ntext++] = oc->soc_cname; } } /* ignore top, etc... */ if ( oc->soc_kind == LDAP_SCHEMA_ABSTRACT ) return 0; if ( !oci ) { ldap_pvt_thread_rdwr_runlock( &ni->ni_oc_rwlock ); oci = (NdbOcInfo *)ch_malloc( sizeof( NdbOcInfo )+oc->soc_cname.bv_len+1 ); oci->no_table.bv_val = (char *)(oci+1); strcpy( oci->no_table.bv_val, oc->soc_cname.bv_val ); oci->no_table.bv_len = oc->soc_cname.bv_len; oci->no_name = oci->no_table; oci->no_oc = oc; oci->no_flag = 0; oci->no_nsets = 0; oci->no_nattrs = 0; ldap_pvt_thread_rdwr_wlock( &ni->ni_oc_rwlock ); if ( avl_insert( &ni->ni_oc_tree, oci, ndb_name_cmp, ndb_oc_dup_err )) { octmp.no_oc = oci->no_oc; ch_free( oci ); oci = (NdbOcInfo *)octmp.no_oc; } /* see if the oc table already exists in the DB */ myTable = myDict->getTable( oci->no_table.bv_val ); rc = ndb_oc_create( ni, oci, myTable == NULL ); ldap_pvt_thread_rdwr_wunlock( &ni->ni_oc_rwlock ); ldap_pvt_thread_rdwr_rlock( &ni->ni_oc_rwlock ); if ( rc ) return rc; } /* Only insert once */ for ( i=0; i<out->no_ninfo; i++ ) if ( out->no_info[i] == oci ) break; if ( i == out->no_ninfo ) out->no_info[out->no_ninfo++] = oci; return 0; }
static int nss_cf_gen(ConfigArgs *c) { slap_overinst *on = (slap_overinst *)c->bi; nssov_info *ni = on->on_bi.bi_private; nssov_mapinfo *mi; int i, j, rc = 0; slap_mask_t m; if ( c->op == SLAP_CONFIG_EMIT ) { switch(c->type) { case NSS_SSD: rc = 1; for (i=NM_alias;i<NM_NONE;i++) { struct berval scope; struct berval ssd; struct berval base; mi = &ni->ni_maps[i]; /* ignore all-default services */ if ( mi->mi_scope == LDAP_SCOPE_DEFAULT && bvmatch( &mi->mi_filter, &mi->mi_filter0 ) && BER_BVISNULL( &mi->mi_base )) continue; if ( BER_BVISNULL( &mi->mi_base )) base = ni->ni_db->be_nsuffix[0]; else base = mi->mi_base; ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ? LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope); ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len + base.bv_len + scope.bv_len + mi->mi_filter.bv_len; ssd.bv_val = ch_malloc( ssd.bv_len + 1 ); sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val, base.bv_val, scope.bv_val, mi->mi_filter.bv_val ); ber_bvarray_add( &c->rvalue_vals, &ssd ); rc = 0; } break; case NSS_MAP: rc = 1; for (i=NM_alias;i<NM_NONE;i++) { mi = &ni->ni_maps[i]; for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) { if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j], &mi->mi_attrs[j].an_name)) { struct berval map; map.bv_len = nss_svcs[i].word.bv_len + mi->mi_attrkeys[j].bv_len + mi->mi_attrs[j].an_desc->ad_cname.bv_len + 2; map.bv_val = ch_malloc(map.bv_len + 1); sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val, mi->mi_attrkeys[j].bv_val, mi->mi_attrs[j].an_desc->ad_cname.bv_val ); ber_bvarray_add( &c->rvalue_vals, &map ); rc = 0; } } } break; case NSS_PAM: rc = mask_to_verbs( pam_opts, ni->ni_pam_opts, &c->rvalue_vals ); break; case NSS_PAMGROUP: if (!BER_BVISEMPTY( &ni->ni_pam_group_dn )) { value_add_one( &c->rvalue_vals, &ni->ni_pam_group_dn ); value_add_one( &c->rvalue_nvals, &ni->ni_pam_group_dn ); } else { rc = 1; } break; case NSS_PAMSESS: if (ni->ni_pam_sessions) { ber_bvarray_dup_x( &c->rvalue_vals, ni->ni_pam_sessions, NULL ); } else { rc = 1; } break; } return rc; } else if ( c->op == LDAP_MOD_DELETE ) { /* FIXME */ return 1; } switch( c->type ) { case NSS_SSD: { LDAPURLDesc *lud; i = verb_to_mask(c->argv[1], nss_svcs); if ( i == NM_NONE ) return 1; mi = &ni->ni_maps[i]; rc = ldap_url_parse(c->argv[2], &lud); if ( rc ) return 1; do { struct berval base; /* Must be LDAP scheme */ if (strcasecmp(lud->lud_scheme,"ldap")) { rc = 1; break; } /* Host part, attrs, and extensions must be empty */ if (( lud->lud_host && *lud->lud_host ) || lud->lud_attrs || lud->lud_exts ) { rc = 1; break; } ber_str2bv( lud->lud_dn,0,0,&base); rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL); if ( rc ) break; if ( lud->lud_filter ) { /* steal this */ ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter); lud->lud_filter = NULL; } mi->mi_scope = lud->lud_scope; } while(0); ldap_free_urldesc( lud ); } break; case NSS_MAP: i = verb_to_mask(c->argv[1], nss_svcs); if ( i == NM_NONE ) return 1; rc = 1; mi = &ni->ni_maps[i]; for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) { if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) { AttributeDescription *ad = NULL; const char *text; rc = slap_str2ad( c->argv[3], &ad, &text); if ( rc == 0 ) { mi->mi_attrs[j].an_desc = ad; mi->mi_attrs[j].an_name = ad->ad_cname; } break; } } break; case NSS_PAM: m = ni->ni_pam_opts; i = verbs_to_mask(c->argc, c->argv, pam_opts, &m); if (i == 0) { ni->ni_pam_opts = m; if ((m & NI_PAM_USERHOST) && !nssov_pam_host_ad) { const char *text; i = slap_str2ad("host", &nssov_pam_host_ad, &text); if (i != LDAP_SUCCESS) { snprintf(c->cr_msg, sizeof(c->cr_msg), "nssov: host attr unknown: %s", text); Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0); rc = 1; break; } } if ((m & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && !nssov_pam_svc_ad) { const char *text; i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text); if (i != LDAP_SUCCESS) { snprintf(c->cr_msg, sizeof(c->cr_msg), "nssov: authorizedService attr unknown: %s", text); Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0); rc = 1; break; } } } else { rc = 1; } break; case NSS_PAMGROUP: ni->ni_pam_group_dn = c->value_ndn; ch_free( c->value_dn.bv_val ); break; case NSS_PAMSESS: ber_bvarray_add( &ni->ni_pam_sessions, &c->value_bv ); break; } return rc; }
static adremap_dnv *adremap_filter( Operation *op, adremap_info *ai ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; Filter *f = op->ors_filter, *fn = NULL; adremap_dnv *ad = NULL; struct berval bv; int fextra = 0; /* Do we need to munge the filter? First see if it's of * the form (objectClass=<mapgrp>) * or form (&(objectClass=<mapgrp>)...) * or form (&(&(objectClass=<mapgrp>)...)...) */ if (f->f_choice == LDAP_FILTER_AND && f->f_and) { fextra = 1; f = f->f_and; fn = f->f_next; } if (f->f_choice == LDAP_FILTER_AND && f->f_and) { fextra = 2; f = f->f_and; } if (f->f_choice == LDAP_FILTER_EQUALITY && f->f_av_desc == slap_schema.si_ad_objectClass) { struct berval bv = f->f_av_value; for (ad = ai->ai_dnv; ad; ad = ad->ad_next) { if (!ber_bvstrcasecmp( &bv, &ad->ad_mapgrp->soc_cname )) { /* Now check to see if next element is (<newattr>=foo) */ Filter *fnew; if (fn && fn->f_choice == LDAP_FILTER_EQUALITY && fn->f_av_desc == ad->ad_newattr) { Filter fr[3]; AttributeAssertion aa[2] = {0}; Operation op2; slap_callback cb = {0}; SlapReply rs = {REP_RESULT}; struct berval dn = BER_BVNULL; /* It's a match, setup a search with filter * (&(objectclass=<refgrp>)(<deref>=foo)) */ fr[0].f_choice = LDAP_FILTER_AND; fr[0].f_and = &fr[1]; fr[0].f_next = NULL; fr[1].f_choice = LDAP_FILTER_EQUALITY; fr[1].f_ava = &aa[0]; fr[1].f_av_desc = slap_schema.si_ad_objectClass; fr[1].f_av_value = ad->ad_refgrp->soc_cname; fr[1].f_next = &fr[2]; fr[2].f_choice = LDAP_FILTER_EQUALITY; fr[2].f_ava = &aa[1]; fr[2].f_av_desc = ad->ad_deref; fr[2].f_av_value = fn->f_av_value; fr[2].f_next = NULL; /* Search with this filter to retrieve target DN */ op2 = *op; op2.o_callback = &cb; cb.sc_response = adremap_refsearch; cb.sc_private = &dn; op2.o_req_dn = ad->ad_refbase; op2.o_req_ndn = ad->ad_refbase; op2.ors_filter = fr; filter2bv_x(op, fr, &op2.ors_filterstr); op2.ors_deref = LDAP_DEREF_NEVER; op2.ors_slimit = 1; op2.ors_tlimit = SLAP_NO_LIMIT; op2.ors_attrs = slap_anlist_no_attrs; op2.ors_attrsonly = 1; op2.o_no_schema_check = 1; op2.o_bd->bd_info = (BackendInfo *)on->on_info; op2.o_bd->be_search(&op2, &rs); op2.o_bd->bd_info = (BackendInfo *)on; op->o_tmpfree(op2.ors_filterstr.bv_val, op->o_tmpmemctx); if (!dn.bv_len) { /* no match was found */ ad = NULL; break; } if (rs.sr_err) { /* sizelimit exceeded, etc.: invalid name */ op->o_tmpfree(dn.bv_val, op->o_tmpmemctx); ad = NULL; break; } /* Build a new filter of form * (&(objectclass=<group>)(<dnattr>=foo-DN)...) */ f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); f->f_choice = LDAP_FILTER_AND; fnew = f; f->f_next = NULL; f->f_and = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); f = f->f_and; f->f_choice = LDAP_FILTER_EQUALITY; f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx); f->f_av_desc = slap_schema.si_ad_objectClass; ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx); f->f_next = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); f = f->f_next; f->f_choice = LDAP_FILTER_EQUALITY; f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx); f->f_av_desc = ad->ad_dnattr; f->f_av_value = dn; f->f_next = fn->f_next; fn->f_next = NULL; } else { /* Build a new filter of form * (objectclass=<group>) */ f->f_next = NULL; /* disconnect old chain */ f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); f->f_choice = LDAP_FILTER_EQUALITY; f->f_ava = op->o_tmpcalloc(1, sizeof(AttributeAssertion), op->o_tmpmemctx); f->f_av_desc = slap_schema.si_ad_objectClass; ber_dupbv_x(&f->f_av_value, &ad->ad_group->soc_cname, op->o_tmpmemctx); /* If there was a wrapping (&), attach it. */ if (fextra) { fnew = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); fnew->f_choice = LDAP_FILTER_AND; fnew->f_and = f; fnew->f_next = NULL; f->f_next = fn; } else { fnew = f; f->f_next = NULL; } } if (fextra > 1) { f = op->o_tmpalloc(sizeof(Filter), op->o_tmpmemctx); f->f_choice = LDAP_FILTER_AND; f->f_and = fnew->f_and; f->f_next = f->f_and->f_next; f->f_and->f_next = op->ors_filter->f_and->f_and->f_next; op->ors_filter->f_and->f_and->f_next = NULL; fnew->f_and = f; } filter_free_x(op, op->ors_filter, 1); op->o_tmpfree(op->ors_filterstr.bv_val, op->o_tmpmemctx); op->ors_filter = fnew; filter2bv_x(op, op->ors_filter, &op->ors_filterstr); break; } } } return ad; }
extern "C" int ndb_back_add(Operation *op, SlapReply *rs ) { struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private; Entry p = {0}; Attribute poc; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; AttributeDescription *children = slap_schema.si_ad_children; AttributeDescription *entry = slap_schema.si_ad_entry; NdbArgs NA; NdbRdns rdns; struct berval matched; struct berval pdn, pndn; int num_retries = 0; int success; LDAPControl **postread_ctrl = NULL; LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; int num_ctrls = 0; Debug(LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(ndb_back_add) ": %s\n", op->oq_add.rs_e->e_name.bv_val, 0, 0); ctrls[num_ctrls] = 0; /* check entry's schema */ rs->sr_err = entry_schema_check( op, op->oq_add.rs_e, NULL, get_relax(op), 1, NULL, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": entry failed schema check: " "%s (%d)\n", rs->sr_text, rs->sr_err, 0 ); goto return_results; } /* add opattrs to shadow as well, only missing attrs will actually * be added; helps compatibility with older OL versions */ rs->sr_err = slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); if ( rs->sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": entry failed op attrs add: " "%s (%d)\n", rs->sr_text, rs->sr_err, 0 ); goto return_results; } /* Get our NDB handle */ rs->sr_err = ndb_thread_handle( op, &NA.ndb ); /* * Get the parent dn and see if the corresponding entry exists. */ if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) { pdn = slap_empty_bv; pndn = slap_empty_bv; } else { dnParent( &op->ora_e->e_name, &pdn ); dnParent( &op->ora_e->e_nname, &pndn ); } p.e_name = op->ora_e->e_name; p.e_nname = op->ora_e->e_nname; op->ora_e->e_id = NOID; rdns.nr_num = 0; NA.rdns = &rdns; if( 0 ) { retry: /* transaction retry */ NA.txn->close(); NA.txn = NULL; if ( op->o_abandon ) { rs->sr_err = SLAPD_ABANDON; goto return_results; } ndb_trans_backoff( ++num_retries ); } NA.txn = NA.ndb->startTransaction(); rs->sr_text = NULL; if( !NA.txn ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": startTransaction failed: %s (%d)\n", NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } /* get entry or parent */ NA.e = &p; NA.ocs = NULL; rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched ); switch( rs->sr_err ) { case 0: rs->sr_err = LDAP_ALREADY_EXISTS; goto return_results; case LDAP_NO_SUCH_OBJECT: break; #if 0 case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; #endif case LDAP_BUSY: rs->sr_text = "ldap server busy"; goto return_results; default: rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } if ( NA.ocs ) { int i; for ( i=0; !BER_BVISNULL( &NA.ocs[i] ); i++ ); poc.a_numvals = i; poc.a_desc = slap_schema.si_ad_objectClass; poc.a_vals = NA.ocs; poc.a_nvals = poc.a_vals; poc.a_next = NULL; p.e_attrs = &poc; } if ( ber_bvstrcasecmp( &pndn, &matched ) ) { rs->sr_matched = matched.bv_val; Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": parent " "does not exist\n", 0, 0, 0 ); rs->sr_text = "parent does not exist"; rs->sr_err = LDAP_NO_SUCH_OBJECT; if ( p.e_attrs && is_entry_referral( &p )) { is_ref: p.e_attrs = NULL; ndb_entry_get_data( op, &NA, 0 ); rs->sr_ref = get_entry_referrals( op, &p ); rs->sr_err = LDAP_REFERRAL; rs->sr_flags = REP_REF_MUSTBEFREED; attrs_free( p.e_attrs ); p.e_attrs = NULL; } goto return_results; } p.e_name = pdn; p.e_nname = pndn; rs->sr_err = access_allowed( op, &p, children, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": no write access to parent\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to parent"; goto return_results; } if ( NA.ocs ) { if ( is_entry_subentry( &p )) { /* parent is a subentry, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": parent is subentry\n", 0, 0, 0 ); rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; rs->sr_text = "parent is a subentry"; goto return_results; } if ( is_entry_alias( &p ) ) { /* parent is an alias, don't allow add */ Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": parent is alias\n", 0, 0, 0 ); rs->sr_err = LDAP_ALIAS_PROBLEM; rs->sr_text = "parent is an alias"; goto return_results; } if ( is_entry_referral( &p ) ) { /* parent is a referral, don't allow add */ rs->sr_matched = p.e_name.bv_val; goto is_ref; } } rs->sr_err = access_allowed( op, op->ora_e, entry, NULL, ACL_WADD, NULL ); if ( ! rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": no write access to entry\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to entry"; goto return_results;; } /* * Check ACL for attribute write access */ if (!acl_check_modlist(op, op->ora_e, op->ora_modlist)) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_add) ": no write access to attribute\n", 0, 0, 0 ); rs->sr_err = LDAP_INSUFFICIENT_ACCESS; rs->sr_text = "no write access to attribute"; goto return_results;; } /* acquire entry ID */ if ( op->ora_e->e_id == NOID ) { rs->sr_err = ndb_next_id( op->o_bd, NA.ndb, &op->ora_e->e_id ); if( rs->sr_err != 0 ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": next_id failed (%d)\n", rs->sr_err, 0, 0 ); rs->sr_err = LDAP_OTHER; rs->sr_text = "internal error"; goto return_results; } } if ( matched.bv_val ) rdns.nr_num++; NA.e = op->ora_e; /* dn2id index */ rs->sr_err = ndb_entry_put_info( op->o_bd, &NA, 0 ); if ( rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_info failed (%d)\n", rs->sr_err, 0, 0 ); rs->sr_text = "internal error"; goto return_results; } /* id2entry index */ rs->sr_err = ndb_entry_put_data( op->o_bd, &NA ); if ( rs->sr_err ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": ndb_entry_put_data failed (%d) %s(%d)\n", rs->sr_err, NA.txn->getNdbError().message, NA.txn->getNdbError().code ); rs->sr_text = "internal error"; goto return_results; } /* post-read */ if( op->o_postread ) { if( postread_ctrl == NULL ) { postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } if ( slap_read_controls( op, rs, op->oq_add.rs_e, &slap_post_read_bv, postread_ctrl ) ) { Debug( LDAP_DEBUG_TRACE, "<=- " LDAP_XSTRING(ndb_back_add) ": post-read " "failed!\n", 0, 0, 0 ); if ( op->o_postread & SLAP_CONTROL_CRITICAL ) { /* FIXME: is it correct to abort * operation if control fails? */ goto return_results; } } } if ( op->o_noop ) { if (( rs->sr_err=NA.txn->execute( NdbTransaction::Rollback, NdbOperation::AbortOnError, 1 )) != 0 ) { rs->sr_text = "txn (no-op) failed"; } else { rs->sr_err = LDAP_X_NO_OPERATION; } } else { if(( rs->sr_err=NA.txn->execute( NdbTransaction::Commit, NdbOperation::AbortOnError, 1 )) != 0 ) { rs->sr_text = "txn_commit failed"; } else { rs->sr_err = LDAP_SUCCESS; } } if ( rs->sr_err != LDAP_SUCCESS && rs->sr_err != LDAP_X_NO_OPERATION ) { Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": %s : %s (%d)\n", rs->sr_text, NA.txn->getNdbError().message, NA.txn->getNdbError().code ); rs->sr_err = LDAP_OTHER; goto return_results; } NA.txn->close(); NA.txn = NULL; Debug(LDAP_DEBUG_TRACE, LDAP_XSTRING(ndb_back_add) ": added%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", op->oq_add.rs_e->e_id, op->oq_add.rs_e->e_dn ); rs->sr_text = NULL; if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: success = rs->sr_err; send_ldap_result( op, rs ); slap_graduate_commit_csn( op ); if( NA.txn != NULL ) { NA.txn->execute( Rollback ); NA.txn->close(); } if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) { slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx ); slap_sl_free( *postread_ctrl, op->o_tmpmemctx ); } return rs->sr_err; }