]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/saslauthz.c
Add error handling to BDB_INDEX code
[openldap] / servers / slapd / saslauthz.c
index 9599f8a97319599a569c28fd0331c0f21d59d97f..fcc6c05ce9940bfdeecede469c7453bdc4925e59 100644 (file)
 #include <ac/stdlib.h>
 #include <stdio.h>
 
-#include "slap.h"
-#include "proto-slap.h"
-
 #include <ac/string.h>
 
+#include "slap.h"
+
 #ifdef HAVE_CYRUS_SASL
 #include <limits.h>
 #include <sasl.h>
 #include <ldap_pvt.h>
 #endif
 
-
-
-
-
-/* URI format:  ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]]   */
+/* URI format: ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]]   */
 
 int slap_parseURI( char *uri, char **searchbase, int *scope, Filter **filter )
 {
@@ -42,9 +37,23 @@ int slap_parseURI( char *uri, char **searchbase, int *scope, Filter **filter )
        *scope = -1;
        *filter = NULL;
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_parseURI: parsing %s\n", uri ));
+#else
        Debug( LDAP_DEBUG_TRACE, "slap_parseURI: parsing %s\n", uri, 0, 0 );
+#endif
+
 
        /* If it does not look like a URI, assume it is a DN */
+       if( !strncasecmp( uri, "dn:", 3 ) ) {
+               uri += 3;
+               uri += strspn( uri, " " );
+               *searchbase = ch_strdup( uri );
+               dn_normalize( *searchbase );
+               *scope = LDAP_SCOPE_BASE;
+               return( LDAP_SUCCESS );
+       }
        if( strncasecmp( uri, "ldap://", 7 ) ) {
                *searchbase = ch_strdup( uri );
                dn_normalize( *searchbase );
@@ -126,25 +135,39 @@ int slap_sasl_regexp_config( const char *match, const char *replace )
        /* Precompile matching pattern */
        rc = regcomp( &reg->workspace, reg->match, REG_EXTENDED|REG_ICASE );
        if ( rc ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
+                          "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
+                          reg->match ));
+#else
                Debug( LDAP_DEBUG_ANY,
                "SASL match pattern %s could not be compiled by regexp engine\n",
                reg->match, 0, 0 );
+#endif
+
                return( LDAP_OPERATIONS_ERROR );
        }
 
        /* Precompile replace pattern. Find the $<n> placeholders */
        reg->offset[0] = -2;
        n = 1;
-       for ( c = reg->replace;  *c;  c++ ) {
+       for ( c = reg->replace;  *c;  c++ ) {
                if ( *c == '\\' ) {
                        c++;
                        continue;
                }
                if ( *c == '$' ) {
                        if ( n == SASLREGEX_REPLACE ) {
+#ifdef NEW_LOGGING
+                               LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
+                                          "slap_sasl_regexp_config: \"%s\" has too many $n placeholders (max %d)\n",
+                                          reg->replace, SASLREGEX_REPLACE ));
+#else
                                Debug( LDAP_DEBUG_ANY,
                                   "SASL replace pattern %s has too many $n placeholders (max %d)\n",
                                   reg->replace, SASLREGEX_REPLACE, 0 );
+#endif
+
                                return( LDAP_OPERATIONS_ERROR );
                        }
                        reg->offset[n] = c - reg->replace;
@@ -181,8 +204,14 @@ char *slap_sasl_regexp( char *saslname )
        SaslRegexp_t *reg;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_regexp: converting SASL name %s\n", saslname ));
+#else
        Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
           saslname, 0, 0 );
+#endif
+
        if (( saslname == NULL ) || ( nSaslRegexp == 0 ))
                return( NULL );
 
@@ -214,7 +243,7 @@ char *slap_sasl_regexp( char *saslname )
                        break;
 
                /* Len of string from saslname that matched next $i  (b,d above) */
-               i = reg->replace[ reg->offset[n] + 1 ]  - '0';
+               i = reg->replace[ reg->offset[n] + 1 ]  - '0';
                len += reg->strings[i].rm_eo - reg->strings[i].rm_so;
                n++;
        }
@@ -232,7 +261,7 @@ char *slap_sasl_regexp( char *saslname )
                        break;
 
                /* Paste in string from saslname that matched next $i  (b,d above) */
-               i = reg->replace[ reg->offset[n] + 1 ]  - '0';
+               i = reg->replace[ reg->offset[n] + 1 ]  - '0';
                len = reg->strings[i].rm_eo - reg->strings[i].rm_so;
                strncpy( uri+insert, saslname + reg->strings[i].rm_so, len );
                insert += len;
@@ -241,8 +270,14 @@ char *slap_sasl_regexp( char *saslname )
        }
 
        uri[insert] = '\0';
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_regexp: converted SASL name to %s\n", uri ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "slap_sasl_regexp: converted SASL name to %s\n", uri, 0, 0 );
+#endif
+
        return( uri );
 }
 
@@ -251,7 +286,7 @@ char *slap_sasl_regexp( char *saslname )
 
 
 /*
- * Given a SASL name (e.g. "UID=name+cn=REALM,cn=MECH,cn=AUTHZ")
+ * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
  * return the LDAP DN to which it matches. The SASL regexp rules in the config
  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
  * search with scope=base), just return the URI (or its searchbase). Otherwise
@@ -259,7 +294,6 @@ char *slap_sasl_regexp( char *saslname )
  * entry, return the DN of that one entry.
  */
 
-static
 char *slap_sasl2dn( char *saslname )
 {
        char *uri=NULL, *searchbase=NULL, *DN=NULL;
@@ -271,8 +305,14 @@ char *slap_sasl2dn( char *saslname )
        LDAPMessage *res=NULL, *msg;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl2dn: converting SASL name %s to DN.\n", saslname ));
+#else
        Debug( LDAP_DEBUG_TRACE,
          "==>slap_sasl2dn: Converting SASL name %s to a DN\n", saslname, 0,0 );
+#endif
+
 
        /* Convert the SASL name into an LDAP URI */
        uri = slap_sasl_regexp( saslname );
@@ -291,11 +331,18 @@ char *slap_sasl2dn( char *saslname )
 
        /* Must do an internal search */
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
+                  "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
+                  searchbase, scope ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
           searchbase, scope, 0 );
+#endif
 
-       be = select_backend( searchbase );
+
+       be = select_backend( searchbase, 0 );
        if(( be == NULL ) || ( be->be_search == NULL))
                goto FINISHED;
        searchbase = suffix_alias( be, searchbase );
@@ -316,8 +363,14 @@ char *slap_sasl2dn( char *saslname )
 
        /* Make sure exactly one entry was returned */
        rc = ldap_count_entries( client, res );
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
+                  "slap_sasl2dn: search DN returned %d entries\n", rc ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "slap_sasl2dn: search DN returned %d entries\n", rc,0,0 );
+#endif
+
        if( rc != 1 )
                goto FINISHED;
 
@@ -332,8 +385,14 @@ FINISHED:
        if( res ) ldap_msgfree( res );
        if( client  ) ldap_unbind( client );
        if( DN ) dn_normalize( DN );
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl2dn: Converted SASL name to %s\n", DN ? DN : "<nothing>" ));
+#else
        Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
           DN ? DN : "<nothing>", 0, 0 );
+#endif
+
        return( DN );
 }
 
@@ -346,6 +405,8 @@ FINISHED:
  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
  * the rule must be used as an internal search for entries. If that search
  * returns the *assertDN entry, the match is successful.
+ *
+ * The assertDN should not have the dn: prefix
  */
 
 static
@@ -358,10 +419,17 @@ int slap_sasl_match( char *rule, char *assertDN, char *authc )
        Connection *conn=NULL;
        LDAP *client=NULL;
        LDAPMessage *res=NULL, *msg;
+       regex_t reg;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_match: comparing DN %s to rule %s\n", assertDN, rule ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN, rule, 0 );
+#endif
+
 
        rc = slap_parseURI( rule, &searchbase, &scope, &filter );
        if( rc != LDAP_SUCCESS )
@@ -370,7 +438,12 @@ int slap_sasl_match( char *rule, char *assertDN, char *authc )
        /* Massive shortcut: search scope == base */
        if( scope == LDAP_SCOPE_BASE ) {
                dn_normalize( searchbase );
-               if( strcmp( searchbase, assertDN ) == 0 )
+               rc = regcomp(&reg, searchbase, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+               if ( rc == 0 ) {
+                       rc = regexec(&reg, assertDN, 0, NULL, 0);
+                       regfree( &reg );
+               }
+               if ( rc == 0 )
                        rc = LDAP_SUCCESS;
                else
                        rc = LDAP_INAPPROPRIATE_AUTH;
@@ -379,11 +452,18 @@ int slap_sasl_match( char *rule, char *assertDN, char *authc )
 
        /* Must run an internal search. */
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
+                  "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
+                  searchbase, scope ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
           searchbase, scope, 0 );
+#endif
+
 
-       be = select_backend( searchbase );
+       be = select_backend( searchbase, 0 );
        if(( be == NULL ) || ( be->be_search == NULL)) {
                rc = LDAP_INAPPROPRIATE_AUTH;
                goto CONCLUDED;
@@ -426,8 +506,14 @@ CONCLUDED:
        if( conn ) connection_internal_close( conn );
        if( res ) ldap_msgfree( res );
        if( client  ) ldap_unbind( client );
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_match: comparison returned %d\n", rc ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
+#endif
+
        return( rc );
 }
 
@@ -440,6 +526,8 @@ CONCLUDED:
  * based on authorization rules. The rules are stored in the *searchDN, in the
  * attribute named by *attr. If any of those rules map to the *assertDN, the
  * authorization is approved.
+ *
+ * DN's passed in should have a dn: prefix
  */
 
 static int
@@ -451,20 +539,27 @@ slap_sasl_check_authz(char *searchDN, char *assertDN, char *attr, char *authc)
        AttributeDescription *ad=NULL;
 
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_check_authz: does %s match %s rule in %s?\n",
+                  assertDN, attr, searchDN ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
           assertDN, attr, searchDN);
+#endif
+
        rc = slap_str2ad( attr, &ad, &errmsg );
        if( rc != LDAP_SUCCESS )
                goto COMPLETE;
 
-       rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN, ad, &vals );
+       rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN+3, ad, &vals );
        if( rc != LDAP_SUCCESS )
                goto COMPLETE;
 
        /* Check if the *assertDN matches any **vals */
        for( i=0; vals[i] != NULL; i++ ) {
-               rc = slap_sasl_match( vals[i]->bv_val, assertDN, authc );
+               rc = slap_sasl_match( vals[i]->bv_val, assertDN+3, authc );
                if ( rc == LDAP_SUCCESS )
                        goto COMPLETE;
        }
@@ -474,63 +569,53 @@ COMPLETE:
        if( vals ) ber_bvecfree( vals );
        if( ad ) ad_free( ad, 1 );
 
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_check_authz: %s check returning %s\n", attr, rc ));
+#else
        Debug( LDAP_DEBUG_TRACE,
           "<==slap_sasl_check_authz: %s check returning %d\n", attr, rc, 0);
+#endif
+
        return( rc );
 }
 
 
 
-#endif  /* HAVE_CYRUS_SASL */
+#endif /* HAVE_CYRUS_SASL */
 
 
 
 
 
-/* Check if a bind can SASL authorize to another identity. */
+/* Check if a bind can SASL authorize to another identity.
+   Accepts authorization DN's with "dn:" prefix */
 
-int slap_sasl_authorized( Connection *conn,
-       const char *authcid, const char *authzid )
+int slap_sasl_authorized( char *authcDN, char *authzDN )
 {
        int rc;
-       char *saslname=NULL,*authcDN=NULL,*realm=NULL, *authzDN=NULL;
 
 #ifdef HAVE_CYRUS_SASL
-       Debug( LDAP_DEBUG_TRACE,
-          "==>slap_sasl_authorized: can %s become %s?\n", authcid, authzid, 0 );
-
-       /* Create a complete SASL name for the SASL regexp patterns */
-
-       sasl_getprop( conn->c_sasl_context, SASL_REALM, (void **)&realm );
-
-       /* Allocate space */
-       rc = strlen("uid=,cn=,cn=,cn=AUTHZ ");
-       if ( realm ) rc += strlen( realm );
-       if ( authcid ) rc += strlen( authcid );
-       rc += strlen( conn->c_sasl_bind_mech );
-       saslname = ch_malloc( rc );
-
-       /* Build the SASL name with whatever we have, and normalize it */
-       saslname[0] = '\0';
-       rc = 0;
-       if ( authcid )
-               rc += sprintf( saslname+rc, "%sUID=%s", rc?",":"", authcid);
-       if ( realm )
-               rc += sprintf( saslname+rc, "%sCN=%s", rc?",":"", realm);
-       if ( conn->c_sasl_bind_mech )
-               rc += sprintf( saslname+rc, "%sCN=%s", rc?",":"",
-                  conn->c_sasl_bind_mech);
-       sprintf( saslname+rc, "%sCN=AUTHZ", rc?",":"");
-       dn_normalize( saslname );
-
-       authcDN = slap_sasl2dn( saslname );
-       if( authcDN == NULL )
+       /* User binding as anonymous */
+       if ( authzDN == NULL ) {
+               rc = LDAP_SUCCESS;
                goto DONE;
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_authorized: can %s become %s?\n", authcDN, authzDN ));
+#else
+       Debug( LDAP_DEBUG_TRACE,
+          "==>slap_sasl_authorized: can %s become %s?\n", authcDN, authzDN, 0 );
+#endif
 
-       /* Normalize the name given by the clientside of the connection */
-       authzDN = ch_strdup( authzid );
-       dn_normalize( authzDN );
 
+       /* If person is authorizing to self, succeed */
+       if ( !strcmp( authcDN, authzDN ) ) {
+               rc = LDAP_SUCCESS;
+               goto DONE;
+       }
 
        /* Check source rules */
        rc = slap_sasl_check_authz( authcDN, authzDN, SASL_AUTHZ_SOURCE_ATTR,
@@ -548,9 +633,12 @@ int slap_sasl_authorized( Connection *conn,
        rc = LDAP_INAPPROPRIATE_AUTH;
 
 DONE:
-       if( saslname ) ch_free( saslname );
-       if( authcDN ) ch_free( authcDN );
-       if( authzDN ) ch_free( authzDN );
+#ifdef NEW_LOGGING
+       LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
+                  "slap_sasl_authorized: return %d\n", rc ));
+#else
        Debug( LDAP_DEBUG_TRACE, "<== slap_sasl_authorized: return %d\n",rc,0,0 );
+#endif
+
        return( rc );
 }