mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-02-17 14:00:30 +08:00
HEADS UP: connections are forced to "anonymous" status upon receiving
of a bind request and, upon failure, are left "anonymous." Rework ACL code to hide access testing within macros to facilate additions and eventual redesign. Addition of #ifdef SLAPD_ACLAUTH to conditional include EXPERIMENTAL "auth" access controls. Adds ACL_AUTH "auth" access level (above none, below "compare"). bind requires anonymous access at this level or above access to "entry"/"userPassword"/"krbName". This allows administrators to restrict which entries can be bound to. (This will likely become default behavior after testing has completed).
This commit is contained in:
parent
daf40a51c1
commit
106eef41d8
@ -266,19 +266,19 @@ acl_access_allowed(
|
||||
if ( strcmp( edn, op->o_ndn ) == 0 ) {
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_access_allowed: matched by clause #%d access %s\n",
|
||||
i, (b->a_access & ~ACL_SELF) >=
|
||||
access ? "granted" : "denied", 0 );
|
||||
i, ACL_GRANT(b->a_access, access)
|
||||
? "granted" : "denied", 0 );
|
||||
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
} else {
|
||||
if ( regex_matches( b->a_dnpat, odn, edn, matches ) ) {
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_access_allowed: matched by clause #%d access %s\n",
|
||||
i, (b->a_access & ~ACL_SELF) >= access ?
|
||||
"granted" : "denied", 0 );
|
||||
i, ACL_GRANT(b->a_access, access)
|
||||
? "granted" : "denied", 0 );
|
||||
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -288,10 +288,10 @@ acl_access_allowed(
|
||||
{
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_access_allowed: matched by clause #%d access %s\n",
|
||||
i, (b->a_access & ~ACL_SELF) >= access ?
|
||||
"granted" : "denied", 0 );
|
||||
i, ACL_GRANT(b->a_access, access)
|
||||
? "granted" : "denied", 0 );
|
||||
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
}
|
||||
if ( b->a_domainpat != NULL ) {
|
||||
@ -302,10 +302,10 @@ acl_access_allowed(
|
||||
{
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_access_allowed: matched by clause #%d access %s\n",
|
||||
i, (b->a_access & ~ACL_SELF) >= access ?
|
||||
"granted" : "denied", 0 );
|
||||
i, ACL_GRANT(b->a_access, access)
|
||||
? "granted" : "denied", 0 );
|
||||
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
}
|
||||
if ( b->a_dnattr != NULL && op->o_ndn != NULL ) {
|
||||
@ -315,7 +315,7 @@ acl_access_allowed(
|
||||
if ( (at = attr_find( e->e_attrs, b->a_dnattr )) != NULL &&
|
||||
value_find( at->a_vals, &bv, at->a_syntax, 3 ) == 0 )
|
||||
{
|
||||
if ( (b->a_access & ACL_SELF) &&
|
||||
if ( ACL_IS_SELF(b->a_access) &&
|
||||
(val == NULL || value_cmp( &bv, val, at->a_syntax, 2 )) )
|
||||
{
|
||||
continue;
|
||||
@ -323,14 +323,14 @@ acl_access_allowed(
|
||||
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_acces_allowed: matched by clause #%d access %s\n",
|
||||
i, (b->a_access & ~ACL_SELF) >= access ?
|
||||
"granted" : "denied", 0 );
|
||||
i, ACL_GRANT(b->a_access, access)
|
||||
? "granted" : "denied", 0 );
|
||||
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
|
||||
/* asker not listed in dnattr - check for self access */
|
||||
if ( ! (b->a_access & ACL_SELF) || val == NULL ||
|
||||
if ( ! ACL_IS_SELF(b->a_access) || val == NULL ||
|
||||
value_cmp( &bv, val, at->a_syntax, 2 ) != 0 )
|
||||
{
|
||||
continue;
|
||||
@ -338,10 +338,10 @@ acl_access_allowed(
|
||||
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_access_allowed: matched by clause #%d (self) access %s\n",
|
||||
i, (b->a_access & ~ACL_SELF) >= access ? "granted"
|
||||
: "denied", 0 );
|
||||
i, ACL_GRANT(b->a_access, access)
|
||||
? "granted" : "denied", 0 );
|
||||
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
#ifdef SLAPD_ACLGROUPS
|
||||
if ( b->a_group != NULL && op->o_ndn != NULL ) {
|
||||
@ -356,12 +356,12 @@ acl_access_allowed(
|
||||
(void) dn_normalize_case(buf);
|
||||
|
||||
if (backend_group(be, e, buf, odn,
|
||||
b->a_objectclassvalue, b->a_groupattrname) == 0)
|
||||
b->a_group_oc, b->a_group_at) == 0)
|
||||
{
|
||||
Debug( LDAP_DEBUG_ACL,
|
||||
"<= acl_access_allowed: matched by clause #%d (group) access granted\n",
|
||||
i, 0, 0 );
|
||||
return( (b->a_access & ~ACL_SELF) >= access );
|
||||
return ACL_GRANT(b->a_access, access );
|
||||
}
|
||||
}
|
||||
#endif /* SLAPD_ACLGROUPS */
|
||||
|
@ -206,7 +206,6 @@ parse_acl(
|
||||
} else if ( strncasecmp( left, "group", sizeof("group")-1 ) == 0 ) {
|
||||
char *name = NULL;
|
||||
char *value = NULL;
|
||||
regtest(fname, lineno, right);
|
||||
|
||||
/* format of string is "group/objectClassValue/groupAttrName"
|
||||
*/
|
||||
@ -216,21 +215,22 @@ parse_acl(
|
||||
*name++ = '\0';
|
||||
}
|
||||
|
||||
regtest(fname, lineno, right);
|
||||
b->a_group = dn_upcase(ch_strdup( right ));
|
||||
|
||||
if (value && *value) {
|
||||
b->a_objectclassvalue = ch_strdup(value);
|
||||
b->a_group_oc = ch_strdup(value);
|
||||
*--value = '/';
|
||||
}
|
||||
else
|
||||
b->a_objectclassvalue = ch_strdup("groupOfNames");
|
||||
b->a_group_oc = ch_strdup("groupOfNames");
|
||||
|
||||
if (name && *name) {
|
||||
b->a_groupattrname = ch_strdup(name);
|
||||
b->a_group_at = ch_strdup(name);
|
||||
*--name = '/';
|
||||
}
|
||||
else
|
||||
b->a_groupattrname = ch_strdup("member");
|
||||
b->a_group_at = ch_strdup("member");
|
||||
|
||||
|
||||
|
||||
@ -263,7 +263,7 @@ parse_acl(
|
||||
|
||||
/* get <access> */
|
||||
split( argv[i], '=', &left, &right );
|
||||
if ( (b->a_access = str2access( left )) == -1 ) {
|
||||
if ( ACL_IS_INVALID(ACL_SET(str2access( left ),b->a_access)) ) {
|
||||
fprintf( stderr,
|
||||
"%s: line %d: expecting <access> got \"%s\"\n",
|
||||
fname, lineno, left );
|
||||
@ -311,21 +311,25 @@ access2str( int access )
|
||||
{
|
||||
static char buf[12];
|
||||
|
||||
if ( access & ACL_SELF ) {
|
||||
if ( ACL_IS_SELF( access ) ) {
|
||||
strcpy( buf, "self" );
|
||||
} else {
|
||||
buf[0] = '\0';
|
||||
}
|
||||
|
||||
if ( access & ACL_NONE ) {
|
||||
if ( ACL_IS_NONE(access) ) {
|
||||
strcat( buf, "none" );
|
||||
} else if ( access & ACL_COMPARE ) {
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
} else if ( ACL_IS_AUTH(access) ) {
|
||||
strcat( buf, "auth" );
|
||||
#endif
|
||||
} else if ( ACL_IS_COMPARE(access) ) {
|
||||
strcat( buf, "compare" );
|
||||
} else if ( access & ACL_SEARCH ) {
|
||||
} else if ( ACL_IS_SEARCH(access) ) {
|
||||
strcat( buf, "search" );
|
||||
} else if ( access & ACL_READ ) {
|
||||
} else if ( ACL_IS_READ(access) ) {
|
||||
strcat( buf, "read" );
|
||||
} else if ( access & ACL_WRITE ) {
|
||||
} else if ( ACL_IS_WRITE(access) ) {
|
||||
strcat( buf, "write" );
|
||||
} else {
|
||||
strcat( buf, "unknown" );
|
||||
@ -339,24 +343,29 @@ str2access( char *str )
|
||||
{
|
||||
int access;
|
||||
|
||||
access = 0;
|
||||
ACL_CLR(access);
|
||||
|
||||
if ( strncasecmp( str, "self", 4 ) == 0 ) {
|
||||
access |= ACL_SELF;
|
||||
ACL_SET_SELF(access);
|
||||
str += 4;
|
||||
}
|
||||
|
||||
if ( strcasecmp( str, "none" ) == 0 ) {
|
||||
access |= ACL_NONE;
|
||||
ACL_SET_NONE(access);
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
} else if ( strcasecmp( str, "auth" ) == 0 ) {
|
||||
ACL_SET_AUTH(access);
|
||||
#endif
|
||||
} else if ( strcasecmp( str, "compare" ) == 0 ) {
|
||||
access |= ACL_COMPARE;
|
||||
ACL_SET_COMPARE(access);
|
||||
} else if ( strcasecmp( str, "search" ) == 0 ) {
|
||||
access |= ACL_SEARCH;
|
||||
ACL_SET_SEARCH(access);
|
||||
} else if ( strcasecmp( str, "read" ) == 0 ) {
|
||||
access |= ACL_READ;
|
||||
ACL_SET_READ(access);
|
||||
} else if ( strcasecmp( str, "write" ) == 0 ) {
|
||||
access |= ACL_WRITE;
|
||||
ACL_SET_WRITE(access);
|
||||
} else {
|
||||
access = -1;
|
||||
ACL_SET_INVALID(access);
|
||||
}
|
||||
|
||||
return( access );
|
||||
@ -365,12 +374,22 @@ str2access( char *str )
|
||||
static void
|
||||
acl_usage( void )
|
||||
{
|
||||
fprintf( stderr, "\n<access clause> ::= access to <what> [ by <who> <access> ]+ \n" );
|
||||
fprintf( stderr, "<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n" );
|
||||
fprintf( stderr, "<attrlist> ::= <attr> | <attr> , <attrlist>\n" );
|
||||
fprintf( stderr, "<attr> ::= <attrname> | entry | children\n" );
|
||||
fprintf( stderr, "<who> ::= * | self | dn=<regex> | addr=<regex> |\n\tdomain=<regex> | dnattr=<dnattrname>\n" );
|
||||
fprintf( stderr, "<access> ::= [self]{none | compare | search | read | write }\n" );
|
||||
fprintf( stderr, "\n"
|
||||
"<access clause> ::= access to <what> [ by <who> <access> ]+ \n"
|
||||
"<what> ::= * | [dn=<regex>] [filter=<ldapfilter>] [attrs=<attrlist>]\n"
|
||||
"<attrlist> ::= <attr> | <attr> , <attrlist>\n"
|
||||
"<attr> ::= <attrname> | entry | children\n"
|
||||
"<who> ::= * | self | dn=<regex> | addr=<regex>\n"
|
||||
"\t| domain=<regex> | dnattr=<dnattrname>\n"
|
||||
#ifdef SLAPD_ACLGROUPS
|
||||
"\t| group[/<objectclass>[/<attrname>]]=<regex>\n"
|
||||
#endif
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
"<access> ::= [self]{none|auth|compare|search|read|write}\n"
|
||||
#else
|
||||
"<access> ::= [self]{none|auth|compare|search|read|write}\n"
|
||||
#endif
|
||||
);
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
@ -425,10 +444,10 @@ print_access( struct access *b )
|
||||
#ifdef SLAPD_ACLGROUPS
|
||||
else if ( b->a_group != NULL ) {
|
||||
fprintf( stderr, " group: %s", b->a_group );
|
||||
if ( b->a_objectclassvalue )
|
||||
fprintf( stderr, " objectClassValue: %s", b->a_objectclassvalue );
|
||||
if ( b->a_groupattrname )
|
||||
fprintf( stderr, " groupAttrName: %s", b->a_groupattrname );
|
||||
if ( b->a_group_oc )
|
||||
fprintf( stderr, " objectClass: %s", b->a_group_oc );
|
||||
if ( b->a_group_at )
|
||||
fprintf( stderr, " attributeType: %s", b->a_group_at );
|
||||
}
|
||||
#endif
|
||||
fprintf( stderr, "\n" );
|
||||
|
@ -112,6 +112,16 @@ ldbm_back_bind(
|
||||
|
||||
/* check for deleted */
|
||||
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
if ( ! access_allowed( be, conn, op, e,
|
||||
"entry", NULL, ACL_AUTH ) )
|
||||
{
|
||||
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
|
||||
rc = 1;
|
||||
goto return_results;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch ( method ) {
|
||||
case LDAP_AUTH_SIMPLE:
|
||||
if ( cred->bv_len == 0 ) {
|
||||
@ -131,6 +141,16 @@ ldbm_back_bind(
|
||||
goto return_results;
|
||||
}
|
||||
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
if ( ! access_allowed( be, conn, op, e,
|
||||
"userpassword", NULL, ACL_AUTH ) )
|
||||
{
|
||||
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
|
||||
rc = 1;
|
||||
goto return_results;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( (a = attr_find( e->e_attrs, "userpassword" )) == NULL ) {
|
||||
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
|
||||
NULL, NULL );
|
||||
@ -154,6 +174,15 @@ ldbm_back_bind(
|
||||
|
||||
#ifdef HAVE_KERBEROS
|
||||
case LDAP_AUTH_KRBV41:
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
if ( ! access_allowed( be, conn, op, e,
|
||||
"krbname", NULL, ACL_AUTH ) )
|
||||
{
|
||||
send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, "", "" );
|
||||
rc = 1;
|
||||
goto return_results;
|
||||
}
|
||||
#endif
|
||||
if ( krbv4_ldap_auth( be, cred, &ad ) != LDAP_SUCCESS ) {
|
||||
send_ldap_result( conn, op, LDAP_INVALID_CREDENTIALS,
|
||||
NULL, NULL );
|
||||
@ -167,7 +196,7 @@ ldbm_back_bind(
|
||||
* no krbName values present: check against DN
|
||||
*/
|
||||
if ( strcasecmp( dn, krbname ) == 0 ) {
|
||||
rc = 0; /* XXX wild ass guess */
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
send_ldap_result( conn, op, LDAP_INAPPROPRIATE_AUTH,
|
||||
|
@ -69,6 +69,16 @@ do_bind(
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
|
||||
|
||||
if ( op->o_ndn != NULL ) {
|
||||
free( op->o_ndn );
|
||||
op->o_ndn = NULL;
|
||||
}
|
||||
|
||||
if ( op->o_dn != NULL ) {
|
||||
free( op->o_dn );
|
||||
op->o_dn = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the bind request. It looks like this:
|
||||
*
|
||||
|
@ -425,18 +425,19 @@ read_config( char *fname )
|
||||
return( 1 );
|
||||
}
|
||||
if ( be == NULL ) {
|
||||
if ( (global_default_access =
|
||||
str2access( cargv[1] )) == -1 ) {
|
||||
if ( ACL_IS_INVALID(ACL_SET(str2access(cargv[1]),
|
||||
global_default_access)) ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
|
||||
fname, lineno, cargv[1] );
|
||||
return( 1 );
|
||||
}
|
||||
} else {
|
||||
if ( (be->be_dfltaccess =
|
||||
str2access( cargv[1] )) == -1 ) {
|
||||
if ( ACL_IS_INVALID(ACL_SET(str2access(cargv[1]),
|
||||
be->be_dfltaccess)) ) {
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"%s: line %d: bad access \"%s\" expecting [self]{none|compare|read|write}\n",
|
||||
"%s: line %d: bad access \"%s\", "
|
||||
"expecting [self]{none|compare|search|read|write}\n",
|
||||
fname, lineno, cargv[1] );
|
||||
return( 1 );
|
||||
}
|
||||
|
@ -176,12 +176,47 @@ typedef struct entry {
|
||||
|
||||
/* the "by" part */
|
||||
struct access {
|
||||
#define ACL_NONE 0x01
|
||||
#define ACL_COMPARE 0x02
|
||||
#define ACL_SEARCH 0x04
|
||||
#define ACL_READ 0x08
|
||||
#define ACL_WRITE 0x10
|
||||
#define ACL_SELF 0x40
|
||||
#define ACL_NONE 0x0001
|
||||
/* #define SLAPD_ACLAUTH 1 */
|
||||
#ifdef SLAPD_ACLAUTH
|
||||
#define ACL_AUTH 0x0002
|
||||
#endif
|
||||
#define ACL_COMPARE 0x0004
|
||||
#define ACL_SEARCH 0x0008
|
||||
#define ACL_READ 0x0010
|
||||
#define ACL_WRITE 0x0020
|
||||
#define ACL_SELF 0x4000
|
||||
#define ACL_INVALID -1
|
||||
|
||||
#define ACL_IS(lvl,a) (((a) & (lvl)) == (lvl))
|
||||
|
||||
#define ACL_IS_NONE(a) ACL_IS(ACL_SELF,(a))
|
||||
#define ACL_IS_AUTH(a) ACL_IS(ACL_AUTH,(a))
|
||||
#define ACL_IS_COMPARE(a) ACL_IS(ACL_COMPARE,(a))
|
||||
#define ACL_IS_SEARCH(a) ACL_IS(ACL_SEARCH,(a))
|
||||
#define ACL_IS_READ(a) ACL_IS(ACL_READ,(a))
|
||||
#define ACL_IS_WRITE(a) ACL_IS(ACL_WRITE,(a))
|
||||
#define ACL_IS_SELF(a) ACL_IS(ACL_SELF,(a))
|
||||
#define ACL_IS_INVALID(a) ACL_IS(ACL_INVALID,(a))
|
||||
|
||||
|
||||
#define ACL_CLR(a) ((a) = 0)
|
||||
#define ACL_SET(lvl,a) ((a) |= (lvl))
|
||||
#define ACL_SET_NONE(a) ACL_SET(ACL_SELF,(a))
|
||||
#define ACL_SET_AUTH(a) ACL_SET(ACL_AUTH,(a))
|
||||
#define ACL_SET_COMPARE(a) ACL_SET(ACL_COMPARE,(a))
|
||||
#define ACL_SET_SEARCH(a) ACL_SET(ACL_SEARCH,(a))
|
||||
#define ACL_SET_READ(a) ACL_SET(ACL_READ,(a))
|
||||
#define ACL_SET_WRITE(a) ACL_SET(ACL_WRITE,(a))
|
||||
#define ACL_SET_SELF(a) ACL_SET(ACL_SELF,(a))
|
||||
#define ACL_SET_INVALID(a) ACL_SET(ACL_INVALID,(a))
|
||||
|
||||
#define ACL_PRIV_MASK 0x00ff
|
||||
#define ACL_PRIV(a) ((a) & ACL_PRIV_MASK)
|
||||
#define ACL_GRANT(lvl,a) (ACL_PRIV(a) >= (lvl))
|
||||
#define ACL_TEST
|
||||
|
||||
|
||||
int a_access;
|
||||
|
||||
char *a_dnpat;
|
||||
@ -191,8 +226,8 @@ struct access {
|
||||
|
||||
#ifdef SLAPD_ACLGROUPS
|
||||
char *a_group;
|
||||
char *a_objectclassvalue;
|
||||
char *a_groupattrname;
|
||||
char *a_group_oc;
|
||||
char *a_group_at;
|
||||
#endif
|
||||
struct access *a_next;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user