diff --git a/CHANGES b/CHANGES index 27343d928a4a1f4dae2c27a7584a6210a9e08427..ec407644d16baa7d4f97e99b433fe0a0490919a7 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,7 @@ OpenLDAP 2.4 Change Log OpenLDAP 2.4.13 Engineering Fixed liblutil hex conversion (ITS#5699) + Added slapd dn.this ACL limits (ITS#5734) Fixed slapd nameUIDPretty bitstring parsing (ITS#5750) Fixed slapd overlay/database open with real structure (ITS#5724) Fixed slapd parsing of read entry control (ITS#5741) diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index 47a4af8f103889033cecbd3be89c4d527cddcaac..4c22b3eef233544da9e3c6efac6bd71a555864d4 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -1250,23 +1250,33 @@ createTimestamp attributes for entries. It also controls the entryCSN and entryUUID attributes, which are needed by the syncrepl provider. By default, olcLastMod is TRUE. .TP -.B olcLimits: <who> <limit> [<limit> [...]] -Specify time and size limits based on who initiated an operation. +.B olcLimits: <selector> <limit> [<limit> [...]] +Specify time and size limits based on the operation's initiator or +base DN. The argument -.B who +.B <selector> can be any of .RS .RS .TP -anonymous | users | [dn[.<style>]=]<pattern> | group[/oc[/at]]=<pattern> +anonymous | users | [<dnspec>=]<pattern> | group[/oc[/at]]=<pattern> .RE with .RS .TP +<dnspec> ::= dn[.<type>][.<style>] +.TP +<type> ::= self | this +.TP <style> ::= exact | base | onelevel | subtree | children | regex | anonymous .RE +DN type +.B self +is the default and means the bound user, while +.B this +means the base DN of the operation. The term .B anonymous matches all unauthenticated clients. @@ -1300,7 +1310,7 @@ field is ignored. The same behavior is obtained by using the .B anonymous form of the -.B who +.B <selector> clause. The term .BR group , @@ -1414,7 +1424,7 @@ limit is set to to preserve the original behavior. In case of no match, the global limits are used. -The default values are the same as +The default values are the same as for .B olcSizeLimit and .BR olcTimeLimit ; diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index 5cb75edf3f9ec7acc59c1af9fb33bf28bdb86654..d4b47c435453ebd4ee8f68f06484701583d41c70 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1172,23 +1172,33 @@ createTimestamp attributes for entries. It also controls the entryCSN and entryUUID attributes, which are needed by the syncrepl provider. By default, lastmod is on. .TP -.B limits <who> <limit> [<limit> [...]] -Specify time and size limits based on who initiated an operation. +.B limits <selector> <limit> [<limit> [...]] +Specify time and size limits based on the operation's initiator or +base DN. The argument -.B who +.B <selector> can be any of .RS .RS .TP -anonymous | users | [dn[.<style>]=]<pattern> | group[/oc[/at]]=<pattern> +anonymous | users | [<dnspec>=]<pattern> | group[/oc[/at]]=<pattern> .RE with .RS .TP +<dnspec> ::= dn[.<type>][.<style>] +.TP +<type> ::= self | this +.TP <style> ::= exact | base | onelevel | subtree | children | regex | anonymous .RE +DN type +.B self +is the default and means the bound user, while +.B this +means the base DN of the operation. The term .B anonymous matches all unauthenticated clients. @@ -1222,7 +1232,7 @@ field is ignored. The same behavior is obtained by using the .B anonymous form of the -.B who +.B <selector> clause. The term .BR group , @@ -1336,7 +1346,7 @@ limit is set to to preserve the original behavior. In case of no match, the global limits are used. -The default values are the same of +The default values are the same as for .B sizelimit and .BR timelimit ; diff --git a/servers/slapd/limits.c b/servers/slapd/limits.c index 17e131e1c8c73eb4ffb2205ecf426071d4dc0f7f..a70c0881fb6a377fe1ece81fe621eee37b48feed 100644 --- a/servers/slapd/limits.c +++ b/servers/slapd/limits.c @@ -27,6 +27,10 @@ /* define to get an error if requesting limit higher than hard */ #undef ABOVE_HARD_LIMIT_IS_ERROR +#ifdef LDAP_DEBUG +static const char *const dn_source[2] = { "DN", "DN.THIS" }; +#endif + static char * limits2str( unsigned i ) { @@ -63,21 +67,25 @@ limits2str( unsigned i ) } } -int +static int limits_get( Operation *op, - struct berval *ndn, struct slap_limits_set **limit ) { struct slap_limits **lm; + struct berval *ndns[2]; assert( op != NULL ); assert( limit != NULL ); - Debug( LDAP_DEBUG_TRACE, "==> limits_get: %s dn=\"%s\"\n", + ndns[0] = &op->o_ndn; + ndns[1] = &op->o_req_ndn; + + Debug( LDAP_DEBUG_TRACE, "==> limits_get: %s self=\"%s\" this=\"%s\"\n", op->o_log_prefix, - BER_BVISNULL( ndn ) ? "[anonymous]" : ndn->bv_val, 0 ); + BER_BVISNULL( ndns[0] ) ? "[anonymous]" : ndns[0]->bv_val, + BER_BVISNULL( ndns[1] ) ? "" : ndns[1]->bv_val ); /* * default values */ @@ -90,6 +98,8 @@ limits_get( for ( lm = op->o_bd->be_limits; lm[0] != NULL; lm++ ) { unsigned style = lm[0]->lm_flags & SLAP_LIMITS_MASK; unsigned type = lm[0]->lm_flags & SLAP_LIMITS_TYPE_MASK; + unsigned isthis = type == SLAP_LIMITS_TYPE_THIS; + struct berval *ndn = ndns[isthis]; switch ( style ) { case SLAP_LIMITS_EXACT: @@ -118,8 +128,8 @@ limits_get( if ( dn_match( &lm[0]->lm_pat, ndn ) ) { *limit = &lm[0]->lm_limits; - Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=EXACT dn=\"%s\"\n", - lm[0]->lm_pat.bv_val, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=EXACT dn=\"%s\"\n", + dn_source[isthis], lm[0]->lm_pat.bv_val, 0 ); return( 0 ); } } @@ -171,8 +181,8 @@ limits_get( } *limit = &lm[0]->lm_limits; - Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s dn=\"%s\"\n", - limits2str( style ), lm[0]->lm_pat.bv_val, 0 ); + Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=%s dn=\"%s\"\n", + dn_source[isthis], limits2str( style ), lm[0]->lm_pat.bv_val ); return( 0 ); } @@ -187,16 +197,16 @@ limits_get( 0, NULL, 0 ) == 0 ) { *limit = &lm[0]->lm_limits; - Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s dn=\"%s\"\n", - limits2str( style ), lm[0]->lm_pat.bv_val, 0 ); + Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=%s dn=\"%s\"\n", + dn_source[isthis], limits2str( style ), lm[0]->lm_pat.bv_val ); return( 0 ); } break; case SLAP_LIMITS_ANONYMOUS: if ( BER_BVISEMPTY( ndn ) ) { - Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s\n", - limits2str( style ), 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=%s\n", + dn_source[isthis], limits2str( style ), 0 ); *limit = &lm[0]->lm_limits; return( 0 ); } @@ -205,8 +215,8 @@ limits_get( case SLAP_LIMITS_USERS: if ( !BER_BVISEMPTY( ndn ) ) { *limit = &lm[0]->lm_limits; - Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=DN match=%s\n", - limits2str( style ), 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "<== limits_get: type=%s match=%s\n", + dn_source[isthis], limits2str( style ), 0 ); return( 0 ); } break; @@ -248,6 +258,7 @@ limits_add( case SLAP_LIMITS_ANONYMOUS: case SLAP_LIMITS_USERS: case SLAP_LIMITS_ANY: + /* For these styles, type == 0 (SLAP_LIMITS_TYPE_SELF). */ for ( i = 0; be->be_limits && be->be_limits[ i ]; i++ ) { if ( be->be_limits[ i ]->lm_flags == style ) { return( -1 ); @@ -363,10 +374,12 @@ limits_parse( * * "anonymous" * "users" - * [ "dn" [ "." { "exact" | "base" | "onelevel" | "subtree" | children" - * | "regex" | "anonymous" } ] "=" ] <dn pattern> + * [ "dn" [ "." { "this" | "self" } ] [ "." { "exact" | "base" | + * "onelevel" | "subtree" | "children" | "regex" | "anonymous" } ] + * "=" ] <dn pattern> * * Note: + * "this" is the baseobject, "self" (the default) is the bound DN * "exact" and "base" are the same (exact match); * "onelevel" means exactly one rdn below, NOT including pattern * "subtree" means any rdn below, including pattern @@ -396,18 +409,31 @@ limits_parse( } else if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) { pattern += STRLENOF( "dn" ); + flags = SLAP_LIMITS_TYPE_SELF; + if ( pattern[0] == '.' ) { + pattern++; + if ( strncasecmp( pattern, "this", STRLENOF( "this" )) == 0 ) { + flags = SLAP_LIMITS_TYPE_THIS; + pattern += STRLENOF( "this" ); + } else if ( strncasecmp( pattern, "self", STRLENOF( "self" )) == 0 ) { + pattern += STRLENOF( "self" ); + } else { + goto got_dn_dot; + } + } if ( pattern[0] == '.' ) { pattern++; + got_dn_dot: if ( strncasecmp( pattern, "exact", STRLENOF( "exact" )) == 0 ) { - flags = SLAP_LIMITS_EXACT; + flags |= SLAP_LIMITS_EXACT; pattern += STRLENOF( "exact" ); } else if ( strncasecmp( pattern, "base", STRLENOF( "base" ) ) == 0 ) { - flags = SLAP_LIMITS_BASE; + flags |= SLAP_LIMITS_BASE; pattern += STRLENOF( "base" ); } else if ( strncasecmp( pattern, "one", STRLENOF( "one" ) ) == 0 ) { - flags = SLAP_LIMITS_ONE; + flags |= SLAP_LIMITS_ONE; pattern += STRLENOF( "one" ); if ( strncasecmp( pattern, "level", STRLENOF( "level" ) ) == 0 ) { pattern += STRLENOF( "level" ); @@ -420,7 +446,7 @@ limits_parse( } } else if ( strncasecmp( pattern, "sub", STRLENOF( "sub" ) ) == 0 ) { - flags = SLAP_LIMITS_SUBTREE; + flags |= SLAP_LIMITS_SUBTREE; pattern += STRLENOF( "sub" ); if ( strncasecmp( pattern, "tree", STRLENOF( "tree" ) ) == 0 ) { pattern += STRLENOF( "tree" ); @@ -433,18 +459,20 @@ limits_parse( } } else if ( strncasecmp( pattern, "children", STRLENOF( "children" ) ) == 0 ) { - flags = SLAP_LIMITS_CHILDREN; + flags |= SLAP_LIMITS_CHILDREN; pattern += STRLENOF( "children" ); } else if ( strncasecmp( pattern, "regex", STRLENOF( "regex" ) ) == 0 ) { - flags = SLAP_LIMITS_REGEX; + flags |= SLAP_LIMITS_REGEX; pattern += STRLENOF( "regex" ); /* * this could be deprecated in favour * of the pattern = "anonymous" form */ - } else if ( strncasecmp( pattern, "anonymous", STRLENOF( "anonymous" ) ) == 0 ) { + } else if ( strncasecmp( pattern, "anonymous", STRLENOF( "anonymous" ) ) == 0 + && flags == SLAP_LIMITS_TYPE_SELF ) + { flags = SLAP_LIMITS_ANONYMOUS; pattern = NULL; } @@ -463,8 +491,8 @@ limits_parse( if ( pattern[0] != '=' ) { Debug( LDAP_DEBUG_ANY, "%s : line %d: missing '=' in " - "\"dn[.{exact|base|onelevel|subtree" - "|children|regex|anonymous}]" + "\"dn[.{this|self}][.{exact|base" + "|onelevel|subtree|children|regex}]" "=<pattern>\" in " "\"limits <pattern> <limits>\" " "line.\n%s", @@ -879,13 +907,14 @@ limits_unparse( struct slap_limits *lim, struct berval *bv, ber_len_t buflen ) { struct berval btmp; char *ptr; - int lm; + int type, lm, dntypelen; if ( !bv || !bv->bv_val ) return -1; ptr = bv->bv_val; + type = lim->lm_flags & SLAP_LIMITS_TYPE_MASK; - if (( lim->lm_flags & SLAP_LIMITS_TYPE_MASK ) == SLAP_LIMITS_TYPE_GROUP ) { + if ( type == SLAP_LIMITS_TYPE_GROUP ) { if ( WHATSLEFT <= STRLENOF( "group/" "/" "=\"" "\"" ) + lim->lm_group_oc->soc_cname.bv_len + lim->lm_group_ad->ad_cname.bv_len @@ -913,9 +942,11 @@ limits_unparse( struct slap_limits *lim, struct berval *bv, ber_len_t buflen ) case SLAP_LIMITS_SUBTREE: case SLAP_LIMITS_CHILDREN: case SLAP_LIMITS_REGEX: - if ( WHATSLEFT <= STRLENOF( "dn." "=" "\"" "\"" ) + dntypelen = type == SLAP_LIMITS_TYPE_SELF + ? STRLENOF( "dn." ) : STRLENOF( "dn.this." ); + if ( WHATSLEFT <= dntypelen + STRLENOF( "=" "\"" "\"" ) + strlen( lmpats[lm] ) + lim->lm_pat.bv_len ) return -1; - ptr = lutil_strcopy( ptr, "dn." ); + ptr = lutil_strncopy( ptr, "dn.this.", dntypelen ); ptr = lutil_strcopy( ptr, lmpats[lm] ); *ptr++ = '='; *ptr++ = '"'; @@ -1132,7 +1163,7 @@ limits_check( Operation *op, SlapReply *rs ) /* if not root, get appropriate limits */ } else { - ( void ) limits_get( op, &op->o_ndn, &op->ors_limit ); + ( void ) limits_get( op, &op->ors_limit ); assert( op->ors_limit != NULL ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 4c2db2960d8ae604a03b1f67213a1dded232a8f8..42aa39fe5ad7d627e206a23150759b0c887140bd 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1115,9 +1115,6 @@ LDAP_SLAPD_F (int) slap_build_syncUUID_set LDAP_P(( /* * limits.c */ -LDAP_SLAPD_F (int) limits_get LDAP_P(( - Operation *op, struct berval *ndn, - struct slap_limits_set **limit )); LDAP_SLAPD_F (int) limits_parse LDAP_P(( Backend *be, const char *fname, int lineno, int argc, char **argv )); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 79f076a7a74ad96d317bfc6a59e7f9a0ac28d6a3..50039b23699fdfcc6f6d01a3194275259ac78744 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1639,6 +1639,7 @@ struct slap_limits_set { struct slap_limits { unsigned lm_flags; /* type of pattern */ + /* Values must match lmpats[] in limits.c */ #define SLAP_LIMITS_UNDEFINED 0x0000U #define SLAP_LIMITS_EXACT 0x0001U #define SLAP_LIMITS_BASE SLAP_LIMITS_EXACT @@ -1651,8 +1652,10 @@ struct slap_limits { #define SLAP_LIMITS_ANY 0x0008U #define SLAP_LIMITS_MASK 0x000FU -#define SLAP_LIMITS_TYPE_DN 0x0000U +#define SLAP_LIMITS_TYPE_SELF 0x0000U +#define SLAP_LIMITS_TYPE_DN SLAP_LIMITS_TYPE_SELF #define SLAP_LIMITS_TYPE_GROUP 0x0010U +#define SLAP_LIMITS_TYPE_THIS 0x0020U #define SLAP_LIMITS_TYPE_MASK 0x00F0U regex_t lm_regex; /* regex data for REGEX */