1/* $NetBSD: search.c,v 1.1.1.3 2010/12/12 15:22:45 adam Exp $ */ 2 3/* OpenLDAP: pkg/ldap/servers/slapd/search.c,v 1.181.2.11 2010/04/13 20:23:19 kurt Exp */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2010 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* Portions Copyright (c) 1995 Regents of the University of Michigan. 18 * All rights reserved. 19 * 20 * Redistribution and use in source and binary forms are permitted 21 * provided that this notice is preserved and that due credit is given 22 * to the University of Michigan at Ann Arbor. The name of the University 23 * may not be used to endorse or promote products derived from this 24 * software without specific prior written permission. This software 25 * is provided ``as is'' without express or implied warranty. 26 */ 27 28#include "portable.h" 29 30#include <stdio.h> 31 32#include <ac/string.h> 33#include <ac/socket.h> 34 35#include "lutil.h" 36#include "slap.h" 37 38int 39do_search( 40 Operation *op, /* info about the op to which we're responding */ 41 SlapReply *rs /* all the response data we'll send */ ) 42{ 43 struct berval base = BER_BVNULL; 44 ber_len_t siz, off, i; 45 46 Debug( LDAP_DEBUG_TRACE, "%s do_search\n", 47 op->o_log_prefix, 0, 0 ); 48 /* 49 * Parse the search request. It looks like this: 50 * 51 * SearchRequest := [APPLICATION 3] SEQUENCE { 52 * baseObject DistinguishedName, 53 * scope ENUMERATED { 54 * baseObject (0), 55 * singleLevel (1), 56 * wholeSubtree (2), 57 * subordinate (3) -- OpenLDAP extension 58 * }, 59 * derefAliases ENUMERATED { 60 * neverDerefaliases (0), 61 * derefInSearching (1), 62 * derefFindingBaseObj (2), 63 * alwaysDerefAliases (3) 64 * }, 65 * sizelimit INTEGER (0 .. 65535), 66 * timelimit INTEGER (0 .. 65535), 67 * attrsOnly BOOLEAN, 68 * filter Filter, 69 * attributes SEQUENCE OF AttributeType 70 * } 71 */ 72 73 /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */ 74 if ( ber_scanf( op->o_ber, "{miiiib" /*}*/, 75 &base, &op->ors_scope, &op->ors_deref, &op->ors_slimit, 76 &op->ors_tlimit, &op->ors_attrsonly ) == LBER_ERROR ) 77 { 78 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); 79 rs->sr_err = SLAPD_DISCONNECT; 80 goto return_results; 81 } 82 83 if ( op->ors_tlimit < 0 || op->ors_tlimit > SLAP_MAX_LIMIT ) { 84 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid time limit" ); 85 goto return_results; 86 } 87 88 if ( op->ors_slimit < 0 || op->ors_slimit > SLAP_MAX_LIMIT ) { 89 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid size limit" ); 90 goto return_results; 91 } 92 93 switch( op->ors_scope ) { 94 case LDAP_SCOPE_BASE: 95 case LDAP_SCOPE_ONELEVEL: 96 case LDAP_SCOPE_SUBTREE: 97 case LDAP_SCOPE_SUBORDINATE: 98 break; 99 default: 100 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid scope" ); 101 goto return_results; 102 } 103 104 switch( op->ors_deref ) { 105 case LDAP_DEREF_NEVER: 106 case LDAP_DEREF_FINDING: 107 case LDAP_DEREF_SEARCHING: 108 case LDAP_DEREF_ALWAYS: 109 break; 110 default: 111 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid deref" ); 112 goto return_results; 113 } 114 115 rs->sr_err = dnPrettyNormal( NULL, &base, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx ); 116 if( rs->sr_err != LDAP_SUCCESS ) { 117 Debug( LDAP_DEBUG_ANY, "%s do_search: invalid dn: \"%s\"\n", 118 op->o_log_prefix, base.bv_val, 0 ); 119 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); 120 goto return_results; 121 } 122 123 Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d", 124 base.bv_val, op->ors_scope, op->ors_deref ); 125 Debug( LDAP_DEBUG_ARGS, " %d %d %d\n", 126 op->ors_slimit, op->ors_tlimit, op->ors_attrsonly); 127 128 /* filter - returns a "normalized" version */ 129 rs->sr_err = get_filter( op, op->o_ber, &op->ors_filter, &rs->sr_text ); 130 if( rs->sr_err != LDAP_SUCCESS ) { 131 if( rs->sr_err == SLAPD_DISCONNECT ) { 132 rs->sr_err = LDAP_PROTOCOL_ERROR; 133 send_ldap_disconnect( op, rs ); 134 rs->sr_err = SLAPD_DISCONNECT; 135 } else { 136 send_ldap_result( op, rs ); 137 } 138 goto return_results; 139 } 140 filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); 141 142 Debug( LDAP_DEBUG_ARGS, " filter: %s\n", 143 !BER_BVISEMPTY( &op->ors_filterstr ) ? op->ors_filterstr.bv_val : "empty", 0, 0 ); 144 145 /* attributes */ 146 siz = sizeof(AttributeName); 147 off = offsetof(AttributeName,an_name); 148 if ( ber_scanf( op->o_ber, "{M}}", &op->ors_attrs, &siz, off ) == LBER_ERROR ) { 149 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding attrs error" ); 150 rs->sr_err = SLAPD_DISCONNECT; 151 goto return_results; 152 } 153 for ( i=0; i<siz; i++ ) { 154 const char *dummy; /* ignore msgs from bv2ad */ 155 op->ors_attrs[i].an_desc = NULL; 156 op->ors_attrs[i].an_oc = NULL; 157 op->ors_attrs[i].an_flags = 0; 158 if ( slap_bv2ad( &op->ors_attrs[i].an_name, 159 &op->ors_attrs[i].an_desc, &dummy ) != LDAP_SUCCESS ) 160 { 161 slap_bv2undef_ad( &op->ors_attrs[i].an_name, 162 &op->ors_attrs[i].an_desc, &dummy, 163 SLAP_AD_PROXIED|SLAP_AD_NOINSERT ); 164 }; 165 } 166 167 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { 168 Debug( LDAP_DEBUG_ANY, "%s do_search: get_ctrls failed\n", 169 op->o_log_prefix, 0, 0 ); 170 goto return_results; 171 } 172 173 Debug( LDAP_DEBUG_ARGS, " attrs:", 0, 0, 0 ); 174 175 if ( siz != 0 ) { 176 for ( i = 0; i<siz; i++ ) { 177 Debug( LDAP_DEBUG_ARGS, " %s", op->ors_attrs[i].an_name.bv_val, 0, 0 ); 178 } 179 } 180 181 Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 ); 182 183 if ( StatslogTest( LDAP_DEBUG_STATS ) ) { 184 char abuf[BUFSIZ/2], *ptr = abuf; 185 unsigned len = 0, alen; 186 187 sprintf(abuf, "scope=%d deref=%d", op->ors_scope, op->ors_deref); 188 Statslog( LDAP_DEBUG_STATS, 189 "%s SRCH base=\"%s\" %s filter=\"%s\"\n", 190 op->o_log_prefix, op->o_req_dn.bv_val, abuf, 191 op->ors_filterstr.bv_val, 0 ); 192 193 for ( i = 0; i<siz; i++ ) { 194 alen = op->ors_attrs[i].an_name.bv_len; 195 if (alen >= sizeof(abuf)) { 196 alen = sizeof(abuf)-1; 197 } 198 if (len && (len + 1 + alen >= sizeof(abuf))) { 199 Statslog( LDAP_DEBUG_STATS, "%s SRCH attr=%s\n", 200 op->o_log_prefix, abuf, 0, 0, 0 ); 201 len = 0; 202 ptr = abuf; 203 } 204 if (len) { 205 *ptr++ = ' '; 206 len++; 207 } 208 ptr = lutil_strncopy(ptr, op->ors_attrs[i].an_name.bv_val, alen); 209 len += alen; 210 *ptr = '\0'; 211 } 212 if (len) { 213 Statslog( LDAP_DEBUG_STATS, "%s SRCH attr=%s\n", 214 op->o_log_prefix, abuf, 0, 0, 0 ); 215 } 216 } 217 218 op->o_bd = frontendDB; 219 rs->sr_err = frontendDB->be_search( op, rs ); 220 221return_results:; 222 if ( !BER_BVISNULL( &op->o_req_dn ) ) { 223 slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx ); 224 } 225 if ( !BER_BVISNULL( &op->o_req_ndn ) ) { 226 slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx ); 227 } 228 if ( !BER_BVISNULL( &op->ors_filterstr ) ) { 229 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 230 } 231 if ( op->ors_filter != NULL) { 232 filter_free_x( op, op->ors_filter, 1 ); 233 } 234 if ( op->ors_attrs != NULL ) { 235 op->o_tmpfree( op->ors_attrs, op->o_tmpmemctx ); 236 } 237 238 return rs->sr_err; 239} 240 241int 242fe_op_search( Operation *op, SlapReply *rs ) 243{ 244 BackendDB *bd = op->o_bd; 245 246 if ( op->ors_scope == LDAP_SCOPE_BASE ) { 247 Entry *entry = NULL; 248 249 if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { 250#ifdef LDAP_CONNECTIONLESS 251 /* Ignore LDAPv2 CLDAP Root DSE queries */ 252 if (op->o_protocol == LDAP_VERSION2 && op->o_conn->c_is_udp) { 253 goto return_results; 254 } 255#endif 256 /* check restrictions */ 257 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { 258 send_ldap_result( op, rs ); 259 goto return_results; 260 } 261 262 rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text ); 263 264 } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { 265 /* check restrictions */ 266 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { 267 send_ldap_result( op, rs ); 268 goto return_results; 269 } 270 271 rs->sr_err = schema_info( &entry, &rs->sr_text ); 272 } 273 274 if( rs->sr_err != LDAP_SUCCESS ) { 275 send_ldap_result( op, rs ); 276 goto return_results; 277 278 } else if ( entry != NULL ) { 279 rs->sr_err = test_filter( op, entry, op->ors_filter ); 280 281 if( rs->sr_err == LDAP_COMPARE_TRUE ) { 282 /* note: we set no limits because either 283 * no limit is specified, or at least 1 284 * is specified, and we're going to return 285 * at most one entry */ 286 op->ors_slimit = SLAP_NO_LIMIT; 287 op->ors_tlimit = SLAP_NO_LIMIT; 288 289 rs->sr_entry = entry; 290 rs->sr_attrs = op->ors_attrs; 291 rs->sr_operational_attrs = NULL; 292 rs->sr_flags = 0; 293 send_search_entry( op, rs ); 294 rs->sr_entry = NULL; 295 rs->sr_operational_attrs = NULL; 296 } 297 entry_free( entry ); 298 299 rs->sr_err = LDAP_SUCCESS; 300 send_ldap_result( op, rs ); 301 goto return_results; 302 } 303 } 304 305 if( BER_BVISEMPTY( &op->o_req_ndn ) && !BER_BVISEMPTY( &default_search_nbase ) ) { 306 slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx ); 307 slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx ); 308 309 ber_dupbv_x( &op->o_req_dn, &default_search_base, op->o_tmpmemctx ); 310 ber_dupbv_x( &op->o_req_ndn, &default_search_nbase, op->o_tmpmemctx ); 311 } 312 313 /* 314 * We could be serving multiple database backends. Select the 315 * appropriate one, or send a referral to our "referral server" 316 * if we don't hold it. 317 */ 318 319 op->o_bd = select_backend( &op->o_req_ndn, 1 ); 320 if ( op->o_bd == NULL ) { 321 rs->sr_ref = referral_rewrite( default_referral, 322 NULL, &op->o_req_dn, op->ors_scope ); 323 324 if (!rs->sr_ref) rs->sr_ref = default_referral; 325 rs->sr_err = LDAP_REFERRAL; 326 op->o_bd = bd; 327 send_ldap_result( op, rs ); 328 329 if (rs->sr_ref != default_referral) 330 ber_bvarray_free( rs->sr_ref ); 331 rs->sr_ref = NULL; 332 goto return_results; 333 } 334 335 /* check restrictions */ 336 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { 337 send_ldap_result( op, rs ); 338 goto return_results; 339 } 340 341 /* check for referrals */ 342 if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { 343 goto return_results; 344 } 345 346 if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) { 347 /* don't use shadow copy */ 348 BerVarray defref = op->o_bd->be_update_refs 349 ? op->o_bd->be_update_refs : default_referral; 350 351 if( defref != NULL ) { 352 rs->sr_ref = referral_rewrite( defref, 353 NULL, &op->o_req_dn, op->ors_scope ); 354 if( !rs->sr_ref) rs->sr_ref = defref; 355 rs->sr_err = LDAP_REFERRAL; 356 send_ldap_result( op, rs ); 357 358 if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref ); 359 360 } else { 361 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 362 "copy not used; no referral information available" ); 363 } 364 365 } else if ( op->o_bd->be_search ) { 366 if ( limits_check( op, rs ) == 0 ) { 367 /* actually do the search and send the result(s) */ 368 (op->o_bd->be_search)( op, rs ); 369 } 370 /* else limits_check() sends error */ 371 372 } else { 373 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 374 "operation not supported within namingContext" ); 375 } 376 377return_results:; 378 op->o_bd = bd; 379 return rs->sr_err; 380} 381 382