]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldbm/modrdn.c
Fix reference scope.
[openldap] / servers / slapd / back-ldbm / modrdn.c
index 0e6d513a764d354d6ce8cc97b9359c1df4bd13c8..43ab2c557b283f8d9808bcaf00751d023bfae586 100644 (file)
@@ -50,6 +50,7 @@ ldbm_back_modrdn(
        char            *new_dn = NULL, *new_ndn = NULL;
        Entry           *e, *p = NULL;
        Entry           *matched;
+       int             isroot = -1;
        int             rootlock = 0;
 #define CAN_ROLLBACK   -1
 #define MUST_DESTROY   1
@@ -77,36 +78,36 @@ ldbm_back_modrdn(
 
 #ifdef NEW_LOGGING
        LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY,
-                  "ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
-                  dn ? dn : "NULL", newSuperior ? newSuperior : "NULL" ));
+               "ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
+               dn ? dn : "NULL", newSuperior ? newSuperior : "NULL" ));
 #else
        Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n",
-              (newSuperior ? newSuperior : "NULL"),
-              0, 0 );
+           (newSuperior ? newSuperior : "NULL"),
+           0, 0 );
 #endif
 
        /* get entry with writer lock */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
                char* matched_dn = NULL;
-               struct berval** refs = NULL;
+               struct berval** refs;
 
                if( matched != NULL ) {
                        matched_dn = strdup( matched->e_dn );
                        refs = is_entry_referral( matched )
-                               ? get_entry_referrals( be, conn, op, matched )
+                               ? get_entry_referrals( be, conn, op, matched,
+                                       dn, LDAP_SCOPE_DEFAULT )
                                : NULL;
                        cache_return_entry_r( &li->li_cache, matched );
                } else {
-                       refs = default_referral;
+                       refs = referral_rewrite( default_referral,
+                               NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
-               if ( matched != NULL ) {
-                       ber_bvecfree( refs );
-                       free( matched_dn );
-               }
+               ber_bvecfree( refs );
+               free( matched_dn );
 
                return( -1 );
        }
@@ -115,13 +116,13 @@ ldbm_back_modrdn(
                /* parent is a referral, don't allow add */
                /* parent is an alias, don't allow add */
                struct berval **refs = get_entry_referrals( be,
-                       conn, op, e );
+                       conn, op, e, dn, LDAP_SCOPE_DEFAULT );
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                          "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn ));
+                       "ldbm_back_modrdn: entry %s is a referral\n", e->e_dn ));
 #else
-               Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
+               Debug( LDAP_DEBUG_TRACE, "entry %s is referral\n", e->e_dn,
                    0, 0 );
 #endif
 
@@ -135,9 +136,9 @@ ldbm_back_modrdn(
        if ( has_children( be, e ) ) {
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                          "ldbm_back_modrdn: entry %s has children\n", e->e_dn ));
+                       "ldbm_back_modrdn: entry %s has children\n", e->e_dn ));
 #else
-               Debug( LDAP_DEBUG_TRACE, "entry %s referral\n", e->e_dn,
+               Debug( LDAP_DEBUG_TRACE, "entry %s has children\n", e->e_dn,
                    0, 0 );
 #endif
 
@@ -154,7 +155,7 @@ ldbm_back_modrdn(
                if( (p = dn2entry_w( be, p_ndn, NULL )) == NULL) {
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                                  "ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn ));
+                               "ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn ));
 #else
                        Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
                                0, 0, 0);
@@ -204,20 +205,51 @@ ldbm_back_modrdn(
 #endif
 
        } else {
-               /* no parent, modrdn entry directly under root */
-               if( ! be_isroot( be, op->o_ndn ) && ! be_issuffix( be, "" ) ) {
+               /* no parent, must be root to modify rdn */
+               isroot = be_isroot( be, op->o_ndn );
+               if ( ! be_isroot ) {
+                       if ( be_issuffix( be, "" )
+                                       || be_isupdate( be, op->o_ndn ) ) {
+                               p = (Entry *)&slap_entry_root;
+                               
+                               rc = access_allowed( be, conn, op, p,
+                                               children, NULL, ACL_WRITE );
+                               p = NULL;
+                                                               
+                               /* check parent for "children" acl */
+                               if ( ! rc ) {
 #ifdef NEW_LOGGING
-                       LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                                  "ldbm_back_modrdn: (%s) no parent & not a root.\n",
-                                  e->e_dn ));
+                                       LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
+                                               "ldbm_back_modrdn: no access "
+                                               "to parent \"\"\n" ));
 #else
-                       Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
-                               0, 0, 0);
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "<=- ldbm_back_modrdn: no "
+                                               "access to parent\n", 0, 0, 0 );
 #endif
 
-                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL, NULL );
-                       goto return_results;
+                                       send_ldap_result( conn, op, 
+                                               LDAP_INSUFFICIENT_ACCESS,
+                                               NULL, NULL, NULL, NULL );
+                                       goto return_results;
+                               }
+
+                       } else {
+#ifdef NEW_LOGGING
+                               LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
+                                          "ldbm_back_modrdn: (%s) has no "
+                                          "parent & not a root.\n", dn ));
+#else
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "<=- ldbm_back_modrdn: no parent & "
+                                       "not root\n", 0, 0, 0);
+#endif
+
+                               send_ldap_result( conn, op, 
+                                       LDAP_INSUFFICIENT_ACCESS,
+                                       NULL, NULL, NULL, NULL );
+                               goto return_results;
+                       }
                }
 
                ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
@@ -269,91 +301,145 @@ ldbm_back_modrdn(
                /* newSuperior == entry being moved?, if so ==> ERROR */
                /* Get Entry with dn=newSuperior. Does newSuperior exist? */
 
-               if( (np = dn2entry_w( be, np_ndn, NULL )) == NULL) {
+               if ( newSuperior[ 0 ] != '\0' ) {
+
+                       if( (np = dn2entry_w( be, np_ndn, NULL )) == NULL) {
 #ifdef NEW_LOGGING
-                       LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
-                                  "ldbm_back_modrdn: newSup(ndn=%s) not found.\n", np_ndn ));
+                               LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
+                                          "ldbm_back_modrdn: newSup(ndn=%s) not found.\n", np_ndn ));
 #else
-                       Debug( LDAP_DEBUG_TRACE,
-                              "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
-                              np_ndn, 0, 0);
+                               Debug( LDAP_DEBUG_TRACE,
+                                      "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
+                                      np_ndn, 0, 0);
 #endif
 
-                       send_ldap_result( conn, op, LDAP_OTHER,
-                               NULL, "newSuperior not found", NULL, NULL );
-                       goto return_results;
-               }
+                               send_ldap_result( conn, op, LDAP_OTHER,
+                                       NULL, "newSuperior not found", NULL, NULL );
+                               goto return_results;
+                       }
 
 #ifdef NEW_LOGGING
-               LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
-                          "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
-                          np, np->e_id ));
+                       LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
+                                  "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
+                                  np, np->e_id ));
 #else
-               Debug( LDAP_DEBUG_TRACE,
-                      "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
-                      np, np->e_id, 0 );
+                       Debug( LDAP_DEBUG_TRACE,
+                              "ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
+                              np, np->e_id, 0 );
 #endif
 
-               /* check newSuperior for "children" acl */
-               if ( !access_allowed( be, conn, op, np, children, NULL,
-                                     ACL_WRITE ) )
-               {
+                       /* check newSuperior for "children" acl */
+                       if ( !access_allowed( be, conn, op, np, children, NULL,
+                                             ACL_WRITE ) )
+                       {
 #ifdef NEW_LOGGING
-                       LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                                  "ldbm_back_modrdn: no wr to newSup children.\n" ));
+                               LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
+                                          "ldbm_back_modrdn: no wr to newSup children.\n" ));
 #else
-                       Debug( LDAP_DEBUG_TRACE,
-                              "ldbm_back_modrdn: no wr to newSup children\n",
-                              0, 0, 0 );
+                               Debug( LDAP_DEBUG_TRACE,
+                                      "ldbm_back_modrdn: no wr to newSup children\n",
+                                      0, 0, 0 );
 #endif
 
-                       send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
-                               NULL, NULL, NULL, NULL );
-                       goto return_results;
-               }
+                               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
+                                       NULL, NULL, NULL, NULL );
+                               goto return_results;
+                       }
 
-               if ( is_entry_alias( np ) ) {
-                       /* entry is an alias, don't allow bind */
+                       if ( is_entry_alias( np ) ) {
+                               /* parent is an alias, don't allow add */
 #ifdef NEW_LOGGING
-                       LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                                  "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn ));
+                               LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
+                                          "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn ));
 #else
-                       Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0,
-                           0, 0 );
+                               Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
 #endif
 
 
-                       send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
-                           NULL, "newSuperior is an alias", NULL, NULL );
+                               send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
+                                   NULL, "newSuperior is an alias", NULL, NULL );
 
-                       goto return_results;
-               }
+                               goto return_results;
+                       }
 
-               if ( is_entry_referral( np ) ) {
-                       /* parent is a referral, don't allow add */
-                       /* parent is an alias, don't allow add */
+                       if ( is_entry_referral( np ) ) {
+                               /* parent is a referral, don't allow add */
 #ifdef NEW_LOGGING
-                       LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
-                                  "ldbm_back_modrdn: entry (%s) is a referral\n",
-                                  np->e_dn ));
+                               LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
+                                       "ldbm_back_modrdn: entry (%s) is a referral\n",
+                               np->e_dn ));
 #else
-                       Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
-                               0, 0 );
+                               Debug( LDAP_DEBUG_TRACE, "entry (%s) is referral\n",
+                                       np->e_dn, 0, 0 );
 #endif
 
-                       send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
-                           NULL, "newSuperior is a referral", NULL, NULL );
+                               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
+                                   NULL, "newSuperior is a referral", NULL, NULL );
 
-                       goto return_results;
+                               goto return_results;
+                       }
+
+               } else {
+
+                       /* no parent, must be root to modify newSuperior */
+                       if ( isroot == -1 ) {
+                               isroot = be_isroot( be, op->o_ndn );
+                       }
+
+                       if ( ! be_isroot ) {
+                               if ( be_issuffix( be, "" )
+                                               || be_isupdate( be, op->o_ndn ) ) {
+                                       np = (Entry *)&slap_entry_root;
+                               
+                                       rc = access_allowed( be, conn, op, np,
+                                                       children, NULL, ACL_WRITE );
+                                       np = NULL;
+                                                               
+                                       /* check parent for "children" acl */
+                                       if ( ! rc ) {
+#ifdef NEW_LOGGING
+                                               LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
+                                                       "ldbm_back_modrdn: no access "
+                                                       "to new superior \"\"\n" ));
+#else
+                                               Debug( LDAP_DEBUG_TRACE,
+                                                       "<=- ldbm_back_modrdn: no "
+                                                       "access to new superior\n", 0, 0, 0 );
+#endif
+
+                                               send_ldap_result( conn, op, 
+                                                       LDAP_INSUFFICIENT_ACCESS,
+                                                       NULL, NULL, NULL, NULL );
+                                               goto return_results;
+                                       }
+
+                               } else {
+#ifdef NEW_LOGGING
+                                       LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
+                                                  "ldbm_back_modrdn: \"\" "
+                                                  "not allowed as new superior\n" ));
+#else
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "<=- ldbm_back_modrdn: \"\" "
+                                               "not allowed as new superior\n", 
+                                               0, 0, 0);
+#endif
+
+                                       send_ldap_result( conn, op, 
+                                               LDAP_INSUFFICIENT_ACCESS,
+                                               NULL, NULL, NULL, NULL );
+                                       goto return_results;
+                               }
+                       }
                }
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
-                          "ldbm_back_modrdn: wr to new parent's children OK.\n" ));
+                       "ldbm_back_modrdn: wr to new parent's children OK.\n" ));
 #else
                Debug( LDAP_DEBUG_TRACE,
-                      "ldbm_back_modrdn: wr to new parent's children OK\n",
-                      0, 0 , 0 );
+                   "ldbm_back_modrdn: wr to new parent's children OK\n",
+                   0, 0, 0 );
 #endif
 
                new_parent_dn = np_dn;
@@ -367,10 +453,10 @@ ldbm_back_modrdn(
 
 #ifdef NEW_LOGGING
        LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
-                  "ldbm_back_modrdn: new ndn=%s\n", new_ndn ));
+               "ldbm_back_modrdn: new ndn=%s\n", new_ndn ));
 #else
        Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
-              new_ndn, 0, 0 );
+           new_ndn, 0, 0 );
 #endif
 
        /* check for abandon */
@@ -484,14 +570,13 @@ ldbm_back_modrdn(
 
        mod = NULL;
        for ( a_cnt = 0; new_rdn_types[a_cnt]; a_cnt++ ) {
-               int rc;
-               Modifications *mod_tmp;
+               int                     rc;
+               AttributeDescription    *desc = NULL;
+               Modifications           *mod_tmp;
+               struct berval           val;
 
-               mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) );
 
-               mod_tmp->sml_desc = NULL;
-               rc = slap_str2ad( new_rdn_types[a_cnt], 
-                               &mod_tmp->sml_desc, &text );
+               rc = slap_str2ad( new_rdn_types[a_cnt], &desc, &text );
 
                if ( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
@@ -510,6 +595,30 @@ ldbm_back_modrdn(
                        goto return_results;            
                }
 
+               val.bv_val = new_rdn_vals[a_cnt];
+               val.bv_len = strlen( val.bv_val );
+               if ( ! access_allowed( be, conn, op, e, 
+                               desc, &val, ACL_WRITE ) ) {
+#ifdef NEW_LOGGING
+                       LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
+                                  "ldbm_back_modrdn: access "
+                                  "not allowed to attr \"%s\"\n",
+                                  new_rdn_types[a_cnt] ));
+#else
+                       Debug( LDAP_DEBUG_TRACE,
+                               "ldbm_back_modrdn: access not allowed "
+                               "to attr \"%s\"\n%s%s",
+                               new_rdn_types[a_cnt], "", "" );
+#endif
+                       send_ldap_result( conn, op, 
+                               LDAP_INSUFFICIENT_ACCESS,
+                               NULL, NULL, NULL, NULL );
+
+                       goto return_results;
+               }
+
+               mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) );
+               mod_tmp->sml_desc = desc;
                mod_tmp->sml_bvalues = (struct berval **)ch_malloc( 2 * sizeof(struct berval *) );
                mod_tmp->sml_bvalues[0] = ber_bvstrdup( new_rdn_vals[a_cnt] );
                mod_tmp->sml_bvalues[1] = NULL;
@@ -537,15 +646,13 @@ ldbm_back_modrdn(
                }
 
                for ( d_cnt = 0; old_rdn_types[d_cnt]; d_cnt++ ) {    
-                       int rc;
-                       Modifications *mod_tmp;
-
-                       mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) );
+                       int                     rc;
+                       AttributeDescription    *desc = NULL;
+                       Modifications           *mod_tmp;
+                       struct berval           val;
 
 
-                       mod_tmp->sml_desc = NULL;
-                       rc = slap_str2ad( old_rdn_types[d_cnt], 
-                                       &mod_tmp->sml_desc, &text );
+                       rc = slap_str2ad( old_rdn_types[d_cnt], &desc, &text );
 
                        if ( rc != LDAP_SUCCESS ) {
 #ifdef NEW_LOGGING
@@ -564,7 +671,31 @@ ldbm_back_modrdn(
                                goto return_results;
                        }
 
+                       val.bv_val = old_rdn_vals[d_cnt];
+                       val.bv_len = strlen( val.bv_val );
+                       if ( ! access_allowed( be, conn, op, e, 
+                                       desc, &val, ACL_WRITE ) ) {
+#ifdef NEW_LOGGING
+                               LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
+                                          "ldbm_back_modrdn: access "
+                                          "not allowed to attr \"%s\"\n",
+                                          old_rdn_types[d_cnt] ));
+#else
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "ldbm_back_modrdn: access not allowed "
+                                       "to attr \"%s\"\n%s%s",
+                                       old_rdn_types[d_cnt], "", "" );
+#endif
+                               send_ldap_result( conn, op, 
+                                       LDAP_INSUFFICIENT_ACCESS,
+                                       NULL, NULL, NULL, NULL );
+
+                               goto return_results;
+                       }
+
                        /* Remove old value of rdn as an attribute. */
+                       mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) );
+                       mod_tmp->sml_desc = desc;
                        mod_tmp->sml_bvalues = (struct berval **)ch_malloc( 2 * sizeof(struct berval *) );
                        mod_tmp->sml_bvalues[0] = ber_bvstrdup( old_rdn_vals[d_cnt] );
                        mod_tmp->sml_bvalues[1] = NULL;
@@ -627,8 +758,14 @@ ldbm_back_modrdn(
                        send_ldap_result( conn, op, rc,
                                NULL, text, NULL, NULL );
                }
+
+               /* here we may try to delete the newly added dn */
+               if ( dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
+                       /* we already are in trouble ... */
+                       ;
+               }
            
-           goto return_results;
+               goto return_results;
        }
        
        (void) cache_update_entry( &li->li_cache, e );