Back to index

openldap  2.4.31
compare.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00016  * All rights reserved.
00017  *
00018  * Redistribution and use in source and binary forms are permitted
00019  * provided that this notice is preserved and that due credit is given
00020  * to the University of Michigan at Ann Arbor. The name of the University
00021  * may not be used to endorse or promote products derived from this
00022  * software without specific prior written permission. This software
00023  * is provided ``as is'' without express or implied warranty.
00024  */
00025 
00026 #include "portable.h"
00027 
00028 #include <stdio.h>
00029 #include <ac/socket.h>
00030 #include <ac/string.h>
00031 
00032 #include "slap.h"
00033 
00034 int
00035 do_compare(
00036     Operation *op,
00037     SlapReply *rs )
00038 {
00039        struct berval dn = BER_BVNULL;
00040        struct berval desc = BER_BVNULL;
00041        struct berval value = BER_BVNULL;
00042        AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
00043 
00044        Debug( LDAP_DEBUG_TRACE, "%s do_compare\n",
00045               op->o_log_prefix, 0, 0 );
00046        /*
00047         * Parse the compare request.  It looks like this:
00048         *
00049         *     CompareRequest := [APPLICATION 14] SEQUENCE {
00050         *            entry  DistinguishedName,
00051         *            ava    SEQUENCE {
00052         *                   type   AttributeType,
00053         *                   value  AttributeValue
00054         *            }
00055         *     }
00056         */
00057 
00058        if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
00059               Debug( LDAP_DEBUG_ANY, "%s do_compare: ber_scanf failed\n",
00060                      op->o_log_prefix, 0, 0 );
00061               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00062               return SLAPD_DISCONNECT;
00063        }
00064 
00065        if ( ber_scanf( op->o_ber, "{mm}", &desc, &value ) == LBER_ERROR ) {
00066               Debug( LDAP_DEBUG_ANY, "%s do_compare: get ava failed\n",
00067                      op->o_log_prefix, 0, 0 );
00068               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00069               return SLAPD_DISCONNECT;
00070        }
00071 
00072        if ( ber_scanf( op->o_ber, /*{*/ "}" ) == LBER_ERROR ) {
00073               Debug( LDAP_DEBUG_ANY, "%s do_compare: ber_scanf failed\n",
00074                      op->o_log_prefix, 0, 0 );
00075               send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
00076               return SLAPD_DISCONNECT;
00077        }
00078 
00079        if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
00080               Debug( LDAP_DEBUG_ANY, "%s do_compare: get_ctrls failed\n",
00081                      op->o_log_prefix, 0, 0 );
00082               goto cleanup;
00083        } 
00084 
00085        rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
00086               op->o_tmpmemctx );
00087        if( rs->sr_err != LDAP_SUCCESS ) {
00088               Debug( LDAP_DEBUG_ANY, "%s do_compare: invalid dn (%s)\n",
00089                      op->o_log_prefix, dn.bv_val, 0 );
00090               send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
00091               goto cleanup;
00092        }
00093 
00094        Statslog( LDAP_DEBUG_STATS,
00095               "%s CMP dn=\"%s\" attr=\"%s\"\n",
00096               op->o_log_prefix, op->o_req_dn.bv_val,
00097               desc.bv_val, 0, 0 );
00098 
00099        rs->sr_err = slap_bv2ad( &desc, &ava.aa_desc, &rs->sr_text );
00100        if( rs->sr_err != LDAP_SUCCESS ) {
00101               rs->sr_err = slap_bv2undef_ad( &desc, &ava.aa_desc,
00102                             &rs->sr_text,
00103                             SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
00104               if( rs->sr_err != LDAP_SUCCESS ) {
00105                      send_ldap_result( op, rs );
00106                      goto cleanup;
00107               }
00108        }
00109 
00110        rs->sr_err = asserted_value_validate_normalize( ava.aa_desc,
00111               ava.aa_desc->ad_type->sat_equality,
00112               SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
00113               &value, &ava.aa_value, &rs->sr_text, op->o_tmpmemctx );
00114        if( rs->sr_err != LDAP_SUCCESS ) {
00115               send_ldap_result( op, rs );
00116               goto cleanup;
00117        }
00118 
00119        op->orc_ava = &ava;
00120 
00121        Debug( LDAP_DEBUG_ARGS,
00122               "do_compare: dn (%s) attr (%s) value (%s)\n",
00123               op->o_req_dn.bv_val,
00124               ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
00125 
00126        op->o_bd = frontendDB;
00127        rs->sr_err = frontendDB->be_compare( op, rs );
00128 
00129 cleanup:;
00130        op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
00131        op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
00132        if ( !BER_BVISNULL( &ava.aa_value ) ) {
00133               op->o_tmpfree( ava.aa_value.bv_val, op->o_tmpmemctx );
00134        }
00135 
00136        return rs->sr_err;
00137 }
00138 
00139 int
00140 fe_op_compare( Operation *op, SlapReply *rs )
00141 {
00142        Entry                *entry = NULL;
00143        AttributeAssertion   *ava = op->orc_ava;
00144        BackendDB            *bd = op->o_bd;
00145 
00146        if( strcasecmp( op->o_req_ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) {
00147               if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
00148                      send_ldap_result( op, rs );
00149                      goto cleanup;
00150               }
00151 
00152               rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text );
00153               if( rs->sr_err != LDAP_SUCCESS ) {
00154                      send_ldap_result( op, rs );
00155                      goto cleanup;
00156               }
00157 
00158        } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) {
00159               if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
00160                      send_ldap_result( op, rs );
00161                      rs->sr_err = 0;
00162                      goto cleanup;
00163               }
00164 
00165               rs->sr_err = schema_info( &entry, &rs->sr_text );
00166               if( rs->sr_err != LDAP_SUCCESS ) {
00167                      send_ldap_result( op, rs );
00168                      rs->sr_err = 0;
00169                      goto cleanup;
00170               }
00171        }
00172 
00173        if( entry ) {
00174               rs->sr_err = slap_compare_entry( op, entry, ava );
00175               entry_free( entry );
00176 
00177               send_ldap_result( op, rs );
00178 
00179               if( rs->sr_err == LDAP_COMPARE_TRUE ||
00180                      rs->sr_err == LDAP_COMPARE_FALSE )
00181               {
00182                      rs->sr_err = LDAP_SUCCESS;
00183               }
00184 
00185               goto cleanup;
00186        }
00187 
00188        /*
00189         * We could be serving multiple database backends.  Select the
00190         * appropriate one, or send a referral to our "referral server"
00191         * if we don't hold it.
00192         */
00193        op->o_bd = select_backend( &op->o_req_ndn, 0 );
00194        if ( op->o_bd == NULL ) {
00195               rs->sr_ref = referral_rewrite( default_referral,
00196                      NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00197 
00198               rs->sr_err = LDAP_REFERRAL;
00199               if (!rs->sr_ref) rs->sr_ref = default_referral;
00200               op->o_bd = bd;
00201               send_ldap_result( op, rs );
00202 
00203               if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
00204               rs->sr_err = 0;
00205               goto cleanup;
00206        }
00207 
00208        /* check restrictions */
00209        if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
00210               send_ldap_result( op, rs );
00211               goto cleanup;
00212        }
00213 
00214        /* check for referrals */
00215        if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
00216               goto cleanup;
00217        }
00218 
00219        if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) {
00220               /* don't use shadow copy */
00221               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00222                      "copy not used" );
00223 
00224        } else if ( ava->aa_desc == slap_schema.si_ad_entryDN ) {
00225               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00226                      "entryDN compare not supported" );
00227 
00228        } else if ( ava->aa_desc == slap_schema.si_ad_subschemaSubentry ) {
00229               send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
00230                      "subschemaSubentry compare not supported" );
00231 
00232 #ifndef SLAP_COMPARE_IN_FRONTEND
00233        } else if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates
00234               && op->o_bd->be_has_subordinates )
00235        {
00236               int    rc, hasSubordinates = LDAP_SUCCESS;
00237 
00238               rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry );
00239               if ( rc == 0 && entry ) {
00240                      if ( ! access_allowed( op, entry,
00241                             ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) )
00242                      {      
00243                             rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00244                             
00245                      } else {
00246                             rc = rs->sr_err = op->o_bd->be_has_subordinates( op,
00247                                           entry, &hasSubordinates );
00248                             be_entry_release_r( op, entry );
00249                      }
00250               }
00251 
00252               if ( rc == 0 ) {
00253                      int    asserted;
00254 
00255                      asserted = bvmatch( &ava->aa_value, &slap_true_bv )
00256                             ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
00257                      if ( hasSubordinates == asserted ) {
00258                             rs->sr_err = LDAP_COMPARE_TRUE;
00259 
00260                      } else {
00261                             rs->sr_err = LDAP_COMPARE_FALSE;
00262                      }
00263 
00264               } else {
00265                      /* return error only if "disclose"
00266                       * is granted on the object */
00267                      if ( backend_access( op, NULL, &op->o_req_ndn,
00268                                    slap_schema.si_ad_entry,
00269                                    NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS )
00270                      {
00271                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00272                      }
00273               }
00274 
00275               send_ldap_result( op, rs );
00276 
00277               if ( rc == 0 ) {
00278                      rs->sr_err = LDAP_SUCCESS;
00279               }
00280 
00281        } else if ( op->o_bd->be_compare ) {
00282               rs->sr_err = op->o_bd->be_compare( op, rs );
00283 
00284 #endif /* ! SLAP_COMPARE_IN_FRONTEND */
00285        } else {
00286               rs->sr_err = SLAP_CB_CONTINUE;
00287        }
00288 
00289        if ( rs->sr_err == SLAP_CB_CONTINUE ) {
00290               /* do our best to compare that AVA
00291                * 
00292                * NOTE: this code is used only
00293                * if SLAP_COMPARE_IN_FRONTEND 
00294                * is #define'd (it's not by default)
00295                * or if op->o_bd->be_compare is NULL.
00296                * 
00297                * FIXME: one potential issue is that
00298                * if SLAP_COMPARE_IN_FRONTEND overlays
00299                * are not executed for compare. */
00300               BerVarray     vals = NULL;
00301               int           rc = LDAP_OTHER;
00302 
00303               rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn,
00304                             ava->aa_desc, &vals, ACL_COMPARE );
00305               switch ( rs->sr_err ) {
00306               default:
00307                      /* return error only if "disclose"
00308                       * is granted on the object */
00309                      if ( backend_access( op, NULL, &op->o_req_ndn,
00310                                    slap_schema.si_ad_entry,
00311                                    NULL, ACL_DISCLOSE, NULL )
00312                                    == LDAP_INSUFFICIENT_ACCESS )
00313                      {
00314                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00315                      }
00316                      break;
00317 
00318               case LDAP_SUCCESS:
00319                      if ( value_find_ex( op->oq_compare.rs_ava->aa_desc,
00320                             SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
00321                                    SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
00322                             vals, &ava->aa_value, op->o_tmpmemctx ) == 0 )
00323                      {
00324                             rs->sr_err = LDAP_COMPARE_TRUE;
00325                             break;
00326 
00327                      } else {
00328                             rs->sr_err = LDAP_COMPARE_FALSE;
00329                      }
00330                      rc = LDAP_SUCCESS;
00331                      break;
00332               }
00333 
00334               send_ldap_result( op, rs );
00335 
00336               if ( rc == 0 ) {
00337                      rs->sr_err = LDAP_SUCCESS;
00338               }
00339               
00340               if ( vals ) {
00341                      ber_bvarray_free_x( vals, op->o_tmpmemctx );
00342               }
00343        }
00344 
00345 cleanup:;
00346        op->o_bd = bd;
00347        return rs->sr_err;
00348 }
00349 
00350 int slap_compare_entry(
00351        Operation *op,
00352        Entry *e,
00353        AttributeAssertion *ava )
00354 {
00355        int rc = LDAP_COMPARE_FALSE;
00356        Attribute *a;
00357 
00358        if ( ! access_allowed( op, e,
00359               ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) )
00360        {      
00361               rc = LDAP_INSUFFICIENT_ACCESS;
00362               goto done;
00363        }
00364 
00365        if ( get_assert( op ) &&
00366               ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
00367        {
00368               rc = LDAP_ASSERTION_FAILED;
00369               goto done;
00370        }
00371 
00372        a = attrs_find( e->e_attrs, ava->aa_desc );
00373        if( a == NULL ) {
00374               rc = LDAP_NO_SUCH_ATTRIBUTE;
00375               goto done;
00376        }
00377 
00378        for(;
00379               a != NULL;
00380               a = attrs_find( a->a_next, ava->aa_desc ))
00381        {
00382               if (( ava->aa_desc != a->a_desc ) && ! access_allowed( op,
00383                      e, a->a_desc, &ava->aa_value, ACL_COMPARE, NULL ) )
00384               {      
00385                      rc = LDAP_INSUFFICIENT_ACCESS;
00386                      break;
00387               }
00388 
00389               if ( attr_valfind( a, 
00390                      SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
00391                             SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
00392                      &ava->aa_value, NULL, op->o_tmpmemctx ) == 0 )
00393               {
00394                      rc = LDAP_COMPARE_TRUE;
00395                      break;
00396               }
00397        }
00398 
00399 done:
00400        if( rc != LDAP_COMPARE_TRUE && rc != LDAP_COMPARE_FALSE ) {
00401               if ( ! access_allowed( op, e,
00402                      slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) )
00403               {
00404                      rc = LDAP_NO_SUCH_OBJECT;
00405               }
00406        }
00407 
00408        return rc;
00409 }