search.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /*
  13. * Copyright (c) 1995 Regents of the University of Michigan.
  14. * All rights reserved.
  15. *
  16. * Redistribution and use in source and binary forms are permitted
  17. * provided that this notice is preserved and that due credit is given
  18. * to the University of Michigan at Ann Arbor. The name of the University
  19. * may not be used to endorse or promote products derived from this
  20. * software without specific prior written permission. This software
  21. * is provided ``as is'' without express or implied warranty.
  22. */
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include "slap.h"
  27. #include "pratom.h"
  28. #include "snmp_collator.h"
  29. static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *filter, const char *msg);
  30. void
  31. do_search( Slapi_PBlock *pb )
  32. {
  33. Slapi_Operation *operation;
  34. BerElement *ber;
  35. int i, err, attrsonly;
  36. ber_int_t scope, deref, sizelimit, timelimit;
  37. char *rawbase = NULL;
  38. int rawbase_set_in_pb = 0; /* was rawbase set in pb? */
  39. char *base = NULL, *fstr = NULL;
  40. struct slapi_filter *filter = NULL;
  41. char **attrs = NULL;
  42. char **gerattrs = NULL;
  43. int psearch = 0;
  44. struct berval *psbvp;
  45. ber_int_t changetypes;
  46. int send_entchg_controls;
  47. int changesonly = 0;
  48. int rc = -1;
  49. int strict = 0;
  50. int minssf_exclude_rootdse = 0;
  51. int filter_normalized = 0;
  52. LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
  53. slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
  54. ber = operation->o_ber;
  55. /* count the search request */
  56. slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
  57. /*
  58. * Parse the search request. It looks like this:
  59. *
  60. * SearchRequest := [APPLICATION 3] SEQUENCE {
  61. * baseObject DistinguishedName,
  62. * scope ENUMERATED {
  63. * baseObject (0),
  64. * singleLevel (1),
  65. * wholeSubtree (2)
  66. * },
  67. * derefAliases ENUMERATED {
  68. * neverDerefaliases (0),
  69. * derefInSearching (1),
  70. * derefFindingBaseObj (2),
  71. * alwaysDerefAliases (3)
  72. * },
  73. * sizelimit INTEGER (0 .. 65535),
  74. * timelimit INTEGER (0 .. 65535),
  75. * attrsOnly BOOLEAN,
  76. * filter Filter,
  77. * attributes SEQUENCE OF AttributeType
  78. * }
  79. */
  80. /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
  81. if ( ber_scanf( ber, "{aiiiib", &rawbase, &scope, &deref, &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ){
  82. slapi_ch_free((void**)&rawbase );
  83. log_search_access (pb, "???", -1, "???", "decoding error");
  84. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL );
  85. return;
  86. }
  87. /* Check if we should be performing strict validation. */
  88. strict = config_get_dn_validate_strict();
  89. if (strict) {
  90. /* check that the dn is formatted correctly */
  91. rc = slapi_dn_syntax_check(pb, rawbase, 1);
  92. if (rc) { /* syntax check failed */
  93. op_shared_log_error_access(pb, "SRCH",
  94. rawbase?rawbase:"", "strict: invalid dn");
  95. send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX,
  96. NULL, "invalid dn", 0, NULL);
  97. slapi_ch_free((void **) &rawbase);
  98. return;
  99. }
  100. }
  101. /* If anonymous access is only allowed for searching the root DSE,
  102. * we need to reject any other anonymous search attempts. */
  103. if ((slapi_sdn_get_dn(&(operation->o_sdn)) == NULL) &&
  104. ((rawbase && strlen(rawbase) > 0) || (scope != LDAP_SCOPE_BASE)) &&
  105. (config_get_anon_access_switch() == SLAPD_ANON_ACCESS_ROOTDSE)) {
  106. op_shared_log_error_access(pb, "SRCH", rawbase?rawbase:"",
  107. "anonymous search not allowed");
  108. send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
  109. "Anonymous access is not allowed.", 0, NULL );
  110. goto free_and_return;
  111. }
  112. /*
  113. * If nsslapd-minssf-exclude-rootdse is on, the minssf check has been
  114. * postponed till this moment since we need to know whether the basedn
  115. * is rootdse or not.
  116. *
  117. * If (minssf_exclude_rootdse && (basedn is rootdse),
  118. * then we allow accessing rootdse.
  119. * Otherwise, return Minimum SSF not met.
  120. */
  121. minssf_exclude_rootdse = config_get_minssf_exclude_rootdse();
  122. if (!minssf_exclude_rootdse || (rawbase && strlen(rawbase) > 0)) {
  123. int minssf = 0;
  124. /* Check if the minimum SSF requirement has been met. */
  125. minssf = config_get_minssf();
  126. if ((pb->pb_conn->c_sasl_ssf < minssf) &&
  127. (pb->pb_conn->c_ssl_ssf < minssf) &&
  128. (pb->pb_conn->c_local_ssf < minssf)) {
  129. op_shared_log_error_access(pb, "SRCH", rawbase?rawbase:"",
  130. "Minimum SSF not met");
  131. send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
  132. "Minimum SSF not met.", 0, NULL);
  133. goto free_and_return;
  134. }
  135. }
  136. /*
  137. * ignore negative time and size limits since they make no sense
  138. */
  139. if ( timelimit < 0 ) {
  140. timelimit = 0;
  141. }
  142. if ( sizelimit < 0 ) {
  143. sizelimit = 0;
  144. }
  145. if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
  146. && scope != LDAP_SCOPE_SUBTREE ) {
  147. log_search_access (pb, base, scope, "???", "Unknown search scope");
  148. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
  149. "Unknown search scope", 0, NULL );
  150. goto free_and_return;
  151. }
  152. /* check and record the scope for snmp */
  153. if ( scope == LDAP_SCOPE_ONELEVEL) {
  154. /* count the one level search request */
  155. slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps);
  156. } else if (scope == LDAP_SCOPE_SUBTREE) {
  157. /* count the subtree search request */
  158. slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps);
  159. }
  160. /* filter - returns a "normalized" version */
  161. filter = NULL;
  162. fstr = NULL;
  163. if ( (err = get_filter( pb->pb_conn, ber, scope, &filter, &fstr )) != 0 ) {
  164. char *errtxt;
  165. if ( LDAP_UNWILLING_TO_PERFORM == err ) {
  166. errtxt = "The search filter is too deeply nested";
  167. } else {
  168. errtxt = "Bad search filter";
  169. }
  170. log_search_access( pb, base, scope, "???", errtxt );
  171. send_ldap_result( pb, err, NULL, errtxt, 0, NULL );
  172. goto free_and_return;
  173. }
  174. /* attributes */
  175. attrs = NULL;
  176. if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
  177. log_search_access (pb, base, scope, fstr, "decoding error");
  178. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
  179. NULL );
  180. goto free_and_return;
  181. }
  182. /*
  183. * This search is performed against the legacy consumer, so ask explicitly
  184. * for the aci attribute as it is an operational in 5.0
  185. */
  186. if ( operation->o_flags & OP_FLAG_LEGACY_REPLICATION_DN )
  187. {
  188. /* If attrs==NULL in a 4.x request, means that we want all the attributes, as aci is
  189. * now operational, we need to ask it explicilty as well as all the attributes
  190. */
  191. if ( (attrs == NULL) || (attrs[0] == NULL) )
  192. {
  193. charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
  194. charray_add(&attrs, slapi_attr_syntax_normalize(LDAP_ALL_USER_ATTRS));
  195. }
  196. }
  197. if ( attrs != NULL ) {
  198. char *normaci = slapi_attr_syntax_normalize("aci");
  199. int replace_aci = 0;
  200. if (!normaci) {
  201. normaci = slapi_ch_strdup("aci");
  202. } else if (strcasecmp(normaci, "aci")) {
  203. /* normaci is not "aci" */
  204. replace_aci = 1;
  205. }
  206. /*
  207. * . store gerattrs if any
  208. * . add "aci" once if "*" is given
  209. */
  210. for ( i = 0; attrs[i] != NULL; i++ )
  211. {
  212. char *p = NULL;
  213. /* check if @<objectclass> is included */
  214. p = strchr(attrs[i], '@');
  215. if ( p )
  216. {
  217. char *dummyary[2]; /* need a char ** for charray_merge_nodup */
  218. if ((*(p + 1) == '\0') || (p == attrs[i]) || (strchr(p+1, '@'))) /* e.g. "foo@" or "@objectclassname" or "foo@bar@baz" */
  219. {
  220. slapi_log_error( SLAPI_LOG_ARGS, "do_search",
  221. "invalid attribute [%s] in list - must be of the form "
  222. "attributename@objectclassname where attributename is the "
  223. "name of an attribute or \"*\" or \"+\" and objectclassname "
  224. "is the name of an objectclass\n", attrs[i] );
  225. continue;
  226. }
  227. dummyary[0] = p; /* p = @objectclassname */
  228. dummyary[1] = NULL;
  229. /* copy string to gerattrs with leading @ - disallow dups */
  230. charray_merge_nodup(&gerattrs, dummyary, 1);
  231. /* null terminate the attribute name at the @ after it has been copied */
  232. *p = '\0';
  233. } else if (strcmp(attrs[i], LDAP_ALL_USER_ATTRS /* '*' */) == 0) {
  234. if (!charray_inlist(attrs, normaci)) {
  235. charray_add(&attrs, slapi_ch_strdup(normaci));
  236. }
  237. } else if (replace_aci && (strcasecmp(attrs[i], "aci") == 0)) {
  238. slapi_ch_free_string(&attrs[i]);
  239. attrs[i] = slapi_ch_strdup(normaci);
  240. }
  241. }
  242. slapi_ch_free_string(&normaci);
  243. if (config_get_return_orig_type_switch()) {
  244. /* return the original type, e.g., "sn (surname)" */
  245. operation->o_searchattrs = charray_dup( attrs );
  246. for ( i = 0; attrs[i] != NULL; i++ ) {
  247. char *type;
  248. type = slapi_attr_syntax_normalize(attrs[i]);
  249. slapi_ch_free( (void**)&(attrs[i]) );
  250. attrs[i] = type;
  251. }
  252. } else {
  253. /* return the chopped type, e.g., "sn" */
  254. operation->o_searchattrs = NULL;
  255. for ( i = 0; attrs[i] != NULL; i++ ) {
  256. char *type;
  257. type = slapi_attr_syntax_normalize_ext(attrs[i],
  258. ATTR_SYNTAX_NORM_ORIG_ATTR);
  259. /* attrs[i] is consumed */
  260. charray_add(&operation->o_searchattrs, attrs[i]);
  261. attrs[i] = type;
  262. }
  263. }
  264. }
  265. if ( slapd_ldap_debug & LDAP_DEBUG_ARGS ) {
  266. char abuf[ 1024 ], *astr;
  267. if ( NULL == attrs ) {
  268. astr = "ALL";
  269. } else {
  270. strarray2str( attrs, abuf, sizeof( abuf ), 1 /* include quotes */);
  271. astr = abuf;
  272. }
  273. slapi_log_error( SLAPI_LOG_ARGS, NULL, "SRCH base=\"%s\" "
  274. "scope=%d deref=%d "
  275. "sizelimit=%d timelimit=%d attrsonly=%d filter=\"%s\" "
  276. "attrs=%s\n", base, scope, deref, sizelimit, timelimit,
  277. attrsonly, fstr, astr );
  278. }
  279. /*
  280. * in LDAPv3 there can be optional control extensions on
  281. * the end of an LDAPMessage. we need to read them in and
  282. * pass them to the backend. get_ldapmessage_controls()
  283. * reads the controls and sets any we know about in the pb.
  284. */
  285. if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
  286. log_search_access (pb, base, scope, fstr, "failed to decode LDAP controls");
  287. send_ldap_result( pb, err, NULL, NULL, 0, NULL );
  288. goto free_and_return;
  289. }
  290. /* we support persistent search for regular operations only */
  291. if ( slapi_control_present( operation->o_params.request_controls,
  292. LDAP_CONTROL_PERSISTENTSEARCH, &psbvp, NULL )){
  293. operation_set_flag(operation, OP_FLAG_PS);
  294. psearch = 1;
  295. if ( ps_parse_control_value( psbvp, &changetypes,
  296. &changesonly, &send_entchg_controls ) != LDAP_SUCCESS )
  297. {
  298. changetypes = LDAP_CHANGETYPE_ANY;
  299. send_entchg_controls = 0;
  300. }
  301. else if ( changesonly )
  302. {
  303. operation_set_flag(operation, OP_FLAG_PS_CHANGESONLY);
  304. }
  305. }
  306. slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET_DN, rawbase );
  307. rawbase_set_in_pb = 1; /* rawbase is now owned by pb */
  308. slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, &scope );
  309. slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, &deref );
  310. slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, filter );
  311. slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_NORMALIZED,
  312. &filter_normalized );
  313. slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, fstr );
  314. slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, attrs );
  315. slapi_pblock_set( pb, SLAPI_SEARCH_GERATTRS, gerattrs );
  316. slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
  317. slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
  318. slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
  319. slapi_pblock_set( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
  320. op_shared_search (pb, psearch ? 0 : 1/* send result */);
  321. slapi_pblock_get (pb, SLAPI_PLUGIN_OPRETURN, &rc);
  322. slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
  323. if ( psearch && rc == 0 ) {
  324. ps_add( pb, changetypes, send_entchg_controls );
  325. }
  326. free_and_return:;
  327. if ( !psearch || rc != 0 ) {
  328. slapi_ch_free_string(&fstr);
  329. slapi_filter_free( filter, 1 );
  330. slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs );
  331. charray_free( attrs ); /* passing NULL is fine */
  332. charray_free( gerattrs ); /* passing NULL is fine */
  333. /*
  334. * Fix for defect 526719 / 553356 : Persistent search op failed.
  335. * Marking it as non-persistent so that operation resources get freed
  336. */
  337. if (psearch){
  338. operation->o_flags &= ~OP_FLAG_PS;
  339. }
  340. /* we strdup'd this above - need to free */
  341. if (rawbase_set_in_pb) {
  342. slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET_DN, &rawbase);
  343. }
  344. slapi_ch_free_string(&rawbase);
  345. }
  346. }
  347. static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *fstr, const char *msg)
  348. {
  349. slapi_log_access(LDAP_DEBUG_STATS,
  350. "conn=%" NSPRIu64 " op=%d SRCH base=\"%s\" scope=%d filter=\"%s\", %s\n",
  351. pb->pb_conn->c_connid, pb->pb_op->o_opid,
  352. base, scope, fstr, msg ? msg : "");
  353. }