cb_search.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include "cb.h"
  42. /*
  43. * Build a candidate list for this backentry and scope.
  44. * Could be a BASE, ONELEVEL, or SUBTREE search.
  45. *
  46. * Returns:
  47. * 0 - success
  48. * <0 - fail
  49. *
  50. */
  51. int
  52. chainingdb_build_candidate_list ( Slapi_PBlock *pb )
  53. {
  54. cb_backend_instance *cb = NULL;
  55. cb_outgoing_conn *cnx;
  56. cb_searchContext *ctx = NULL;
  57. Slapi_Backend *be;
  58. Slapi_Operation *op;
  59. LDAPControl **serverctrls = NULL;
  60. LDAPControl **controls = NULL;
  61. LDAPControl **ctrls = NULL;
  62. LDAPMessage *res = NULL;
  63. LDAP *ld = NULL;
  64. Slapi_DN *target_sdn = NULL;
  65. const char *target = NULL;
  66. char *filter;
  67. char **attrs = NULL;
  68. struct timeval timeout;
  69. time_t optime;
  70. time_t endbefore = 0;
  71. time_t endtime = 0;
  72. char *matched_msg, *error_msg;
  73. char **referrals = NULL;
  74. char *cnxerrbuf = NULL;
  75. int scope, attrsonly, sizelimit, timelimit, searchreferral;
  76. int rc, parse_rc, doit;
  77. slapi_pblock_get( pb, SLAPI_BACKEND, &be );
  78. cb = cb_get_instance(be);
  79. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  80. slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &filter );
  81. slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
  82. slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
  83. slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &target_sdn );
  84. target = slapi_sdn_get_dn(target_sdn);
  85. if ( LDAP_SUCCESS != (parse_rc=cb_forward_operation(pb) )) {
  86. /* Don't return errors */
  87. if (cb_debug_on()) {
  88. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  89. "local search: base:<%s> scope:<%s> filter:<%s>\n",target,
  90. scope==LDAP_SCOPE_SUBTREE?"SUBTREE":scope==LDAP_SCOPE_ONELEVEL ? "ONE-LEVEL" : "BASE" , filter);
  91. }
  92. ctx = (cb_searchContext *)slapi_ch_calloc(1,sizeof(cb_searchContext));
  93. ctx->type = CB_SEARCHCONTEXT_ENTRY;
  94. ctx->data=NULL;
  95. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
  96. return 0;
  97. }
  98. cb_update_monitor_info(pb,cb,SLAPI_OPERATION_SEARCH);
  99. /* Check wether the chaining BE is available or not */
  100. if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
  101. return -1;
  102. }
  103. if (cb_debug_on()) {
  104. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  105. "chained search: base:<%s> scope:<%s> filter:<%s>\n",target,
  106. scope==LDAP_SCOPE_SUBTREE ? "SUBTREE": scope==LDAP_SCOPE_ONELEVEL ? "ONE-LEVEL" : "BASE",
  107. filter);
  108. }
  109. slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs );
  110. slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
  111. slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls );
  112. slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
  113. slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
  114. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  115. if ((scope != LDAP_SCOPE_BASE) && (scope != LDAP_SCOPE_ONELEVEL) && (scope != LDAP_SCOPE_SUBTREE)) {
  116. cb_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "Bad scope", 0, NULL );
  117. return 1;
  118. }
  119. searchreferral=cb->searchreferral;
  120. if (( scope != LDAP_SCOPE_BASE ) && ( searchreferral )) {
  121. int i;
  122. struct berval bv,*bvals[2];
  123. Slapi_Entry ** aciArray=(Slapi_Entry **) slapi_ch_malloc(2*sizeof(Slapi_Entry *));
  124. Slapi_Entry *anEntry = slapi_entry_alloc();
  125. slapi_entry_set_sdn(anEntry, target_sdn);
  126. bvals[1]=NULL;
  127. bvals[0]=&bv;
  128. bv.bv_val="referral";
  129. bv.bv_len=strlen(bv.bv_val);
  130. slapi_entry_add_values( anEntry, "objectclass", bvals);
  131. slapi_rwlock_rdlock(cb->rwl_config_lock);
  132. for (i=0; cb->url_array && cb->url_array[i]; i++) {
  133. char * anUrl = slapi_ch_smprintf("%s%s",cb->url_array[i],target);
  134. bv.bv_val=anUrl;
  135. bv.bv_len=strlen(bv.bv_val);
  136. slapi_entry_attr_merge( anEntry, "ref", bvals);
  137. slapi_ch_free((void **)&anUrl);
  138. }
  139. slapi_rwlock_unlock(cb->rwl_config_lock);
  140. aciArray[0]=anEntry;
  141. aciArray[1]=NULL;
  142. ctx = (cb_searchContext *)slapi_ch_calloc(1,sizeof(cb_searchContext));
  143. ctx->type = CB_SEARCHCONTEXT_ENTRY;
  144. ctx->data=aciArray;
  145. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
  146. return 0;
  147. }
  148. /*
  149. ** Time limit management.
  150. ** Make sure the operation has not expired
  151. */
  152. if ( timelimit == -1 ) {
  153. timeout.tv_sec = timeout.tv_usec = 0;
  154. } else {
  155. time_t now=current_time();
  156. endbefore=optime + timelimit;
  157. if (now >= endbefore) {
  158. cb_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL,NULL, 0, NULL);
  159. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
  160. return 1;
  161. }
  162. timeout.tv_sec=(time_t)timelimit-(now-optime);
  163. timeout.tv_usec=0;
  164. }
  165. /* Operational attribute support for internal searches: */
  166. /* The front-end relies on the fact that operational attributes */
  167. /* are returned along with standard attrs when the attr list is */
  168. /* NULL. To make it work, we need to explicitly request for all*/
  169. /* possible operational attrs. Too bad. */
  170. if ( (attrs == NULL) && operation_is_flag_set(op, OP_FLAG_INTERNAL) ) {
  171. attrs = cb->every_attribute;
  172. } else {
  173. int i;
  174. if ( attrs != NULL ) {
  175. for ( i = 0; attrs[i] != NULL; i++ ) {
  176. if ( strcasecmp( "nsrole", attrs[i] ) == 0 ){
  177. attrs = cb->every_attribute;
  178. break;
  179. }
  180. }
  181. }
  182. }
  183. /* Grab a connection handle */
  184. rc = cb_get_connection(cb->pool, &ld, &cnx, &timeout, &cnxerrbuf);
  185. if (LDAP_SUCCESS != rc) {
  186. static int warned_get_conn = 0;
  187. if (!warned_get_conn) {
  188. slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  189. "cb_get_connection failed (%d) %s\n",
  190. rc, ldap_err2string(rc));
  191. warned_get_conn = 1;
  192. }
  193. if (rc == LDAP_TIMELIMIT_EXCEEDED) {
  194. cb_send_ldap_result(pb, rc, NULL, cnxerrbuf, 0, NULL);
  195. } else {
  196. cb_send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
  197. cnxerrbuf, 0, NULL);
  198. }
  199. slapi_ch_free_string(&cnxerrbuf);
  200. /* ping the farm.
  201. * If the farm is unreachable, we increment the counter */
  202. cb_ping_farm(cb, NULL, 0);
  203. return 1;
  204. }
  205. /*
  206. * Control management
  207. */
  208. if ( LDAP_SUCCESS != (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH ))) {
  209. cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
  210. cb_release_op_connection(cb->pool,ld,0);
  211. return 1;
  212. }
  213. if ( slapi_op_abandoned( pb )) {
  214. cb_release_op_connection(cb->pool,ld,0);
  215. ldap_controls_free(ctrls);
  216. return 1;
  217. }
  218. ctx = (cb_searchContext *) slapi_ch_calloc(1,sizeof(cb_searchContext));
  219. /*
  220. ** We need to store the connection handle in the search context
  221. ** to make sure we reuse it in the next_entry iteration
  222. ** Indeed, if another thread on this connection detects a problem
  223. ** on this connection, it may reallocate a new connection and
  224. ** a call to get_connection may return a new cnx. Too bad.
  225. */
  226. ctx->ld=ld;
  227. ctx->cnx=cnx;
  228. /* for some reasons, it is an error to pass in a zero'd timeval */
  229. /* to ldap_search_ext() */
  230. if ((timeout.tv_sec==0) && (timeout.tv_usec==0))
  231. timeout.tv_sec=timeout.tv_usec=-1;
  232. /* heart-beat management */
  233. if (cb->max_idle_time>0)
  234. endtime=current_time() + cb->max_idle_time;
  235. rc = ldap_search_ext(ld ,target,scope,filter,attrs,attrsonly,
  236. ctrls, NULL, &timeout,sizelimit, &(ctx->msgid) );
  237. ldap_controls_free(ctrls);
  238. if ( LDAP_SUCCESS != rc ) {
  239. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string(rc), 0, NULL);
  240. cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
  241. slapi_ch_free((void **) &ctx);
  242. return 1;
  243. }
  244. /*
  245. ** Need to get the very first result to handle
  246. ** errors properly, especially no search base.
  247. */
  248. doit=1;
  249. while (doit) {
  250. if (cb_check_forward_abandon(cb,pb,ctx->ld,ctx->msgid)) {
  251. slapi_ch_free((void **) &ctx);
  252. return 1;
  253. }
  254. rc = ldap_result(ld,ctx->msgid,LDAP_MSG_ONE,&cb->abandon_timeout,&res);
  255. switch ( rc ) {
  256. case -1:
  257. /* An error occurred. return now */
  258. rc = slapi_ldap_get_lderrno(ld,NULL,NULL);
  259. /* tuck away some errors in a OPERATION_ERROR */
  260. if (CB_LDAP_CONN_ERROR(rc)) {
  261. cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
  262. ldap_err2string( rc ), 0, NULL);
  263. } else {
  264. cb_send_ldap_result(pb,rc, NULL, NULL,0,NULL);
  265. }
  266. cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
  267. ldap_msgfree(res);
  268. slapi_ch_free((void **)&ctx);
  269. return 1;
  270. case 0:
  271. /* Local timeout management */
  272. if (timelimit != -1) {
  273. if (current_time() > endbefore) {
  274. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  275. "Local timeout expiration\n");
  276. cb_send_ldap_result(pb,LDAP_TIMELIMIT_EXCEEDED,
  277. NULL,NULL, 0, NULL);
  278. /* Force connection close */
  279. cb_release_op_connection(cb->pool,ld,1);
  280. ldap_msgfree(res);
  281. slapi_ch_free((void **)&ctx);
  282. return 1;
  283. }
  284. }
  285. /* heart-beat management */
  286. if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
  287. cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
  288. ldap_err2string(rc), 0, NULL);
  289. cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
  290. ldap_msgfree(res);
  291. slapi_ch_free((void **)&ctx);
  292. return 1;
  293. }
  294. #ifdef CB_YIELD
  295. DS_Sleep(PR_INTERVAL_NO_WAIT);
  296. #endif
  297. break;
  298. case LDAP_RES_SEARCH_ENTRY:
  299. case LDAP_RES_SEARCH_REFERENCE:
  300. /* Some results received */
  301. /* don't parse result here */
  302. ctx->pending_result=res;
  303. ctx->pending_result_type=rc;
  304. doit = 0;
  305. break;
  306. case LDAP_RES_SEARCH_RESULT:
  307. matched_msg=NULL;
  308. error_msg=NULL;
  309. referrals=NULL;
  310. serverctrls=NULL;
  311. parse_rc=ldap_parse_result(ld,res,&rc,&matched_msg,
  312. &error_msg,&referrals, &serverctrls, 0 );
  313. if ( parse_rc != LDAP_SUCCESS ) {
  314. static int warned_parse_rc = 0;
  315. if (!warned_parse_rc && error_msg) {
  316. slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  317. "%s%s%s\n",
  318. matched_msg?matched_msg:"",
  319. (matched_msg&&(*matched_msg!='\0'))?": ":"",
  320. error_msg );
  321. warned_parse_rc = 1;
  322. }
  323. cb_send_ldap_result( pb, parse_rc, NULL, ENDUSERMSG, 0, NULL );
  324. rc=-1;
  325. } else if ( rc != LDAP_SUCCESS ) {
  326. static int warned_rc = 0;
  327. if (!warned_rc) {
  328. slapi_ldap_get_lderrno( ctx->ld, &matched_msg, &error_msg );
  329. slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  330. "%s%s%s\n",
  331. matched_msg?matched_msg:"",
  332. (matched_msg&&(*matched_msg!='\0'))?": ":"",
  333. error_msg );
  334. warned_rc = 1;
  335. }
  336. cb_send_ldap_result( pb, rc, NULL, ENDUSERMSG, 0, NULL);
  337. /* BEWARE: matched_msg and error_msg points */
  338. /* to ld fields. */
  339. matched_msg=NULL;
  340. error_msg=NULL;
  341. rc = -1;
  342. }
  343. slapi_ch_free_string(&matched_msg);
  344. slapi_ch_free_string(&error_msg);
  345. ldap_controls_free(serverctrls);
  346. charray_free(referrals);
  347. if (rc != LDAP_SUCCESS) {
  348. cb_release_op_connection(cb->pool,ld,
  349. CB_LDAP_CONN_ERROR(rc));
  350. ldap_msgfree(res);
  351. slapi_ch_free((void **)&ctx);
  352. return -1;
  353. }
  354. /* Store the msg in the ctx */
  355. /* Parsed in iterate. */
  356. ctx->pending_result = res;
  357. ctx->pending_result_type = LDAP_RES_SEARCH_RESULT;
  358. doit = 0;
  359. }
  360. }
  361. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
  362. return 0;
  363. }
  364. /*
  365. * Return the next entry in the result set. The entry is returned
  366. * in the pblock.
  367. * Returns 0 normally. If -1 is returned, it means that some
  368. * exceptional condition, e.g. timelimit exceeded has occurred,
  369. * and this routine has sent a result to the client. If zero
  370. * is returned and no entry is available in the PBlock, then
  371. * we've iterated through all the entries.
  372. */
  373. int
  374. chainingdb_next_search_entry ( Slapi_PBlock *pb )
  375. {
  376. Slapi_DN *target_sdn = NULL;
  377. int sizelimit, timelimit;
  378. int rc, parse_rc, retcode;
  379. int i, attrsonly;
  380. time_t optime;
  381. LDAPMessage *res=NULL;
  382. char *matched_msg,*error_msg;
  383. cb_searchContext *ctx=NULL;
  384. Slapi_Entry *entry;
  385. LDAPControl **serverctrls=NULL;
  386. char **referrals=NULL;
  387. cb_backend_instance * cb=NULL;
  388. Slapi_Backend * be;
  389. time_t endtime = 0;
  390. matched_msg=error_msg=NULL;
  391. slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &ctx );
  392. slapi_pblock_get( pb, SLAPI_BACKEND, &be );
  393. slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
  394. slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
  395. slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &target_sdn );
  396. slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
  397. slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
  398. cb = cb_get_instance(be);
  399. if ( NULL == ctx ) {
  400. /* End of local search */
  401. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  402. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  403. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  404. "Unexpected NULL ctx in chainingdb_next_search_entry\n");
  405. return 0;
  406. }
  407. if ( NULL != ctx->readahead) {
  408. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, ctx);
  409. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, ctx->readahead);
  410. if (ctx->tobefreed != ctx->readahead) {
  411. slapi_entry_free(ctx->tobefreed);
  412. }
  413. ctx->tobefreed = ctx->readahead;
  414. ctx->readahead = NULL;
  415. cb_set_acl_policy(pb);
  416. return 0;
  417. }
  418. if ( NULL != ctx->tobefreed ) {
  419. slapi_entry_free(ctx->tobefreed);
  420. ctx->tobefreed=NULL;
  421. }
  422. if ( ctx->type == CB_SEARCHCONTEXT_ENTRY ) {
  423. int n;
  424. Slapi_Entry ** ptr;
  425. if ( (timelimit != -1) && (timelimit != 0)) {
  426. time_t now=current_time();
  427. if (now > (optime + timelimit)) {
  428. cb_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL,NULL, 0, NULL);
  429. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
  430. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  431. for ( n = 0, ptr=(Slapi_Entry **)ctx->data; ptr != NULL && ptr[n] != NULL; n++ ) {
  432. slapi_entry_free(ptr[n]);
  433. }
  434. if (ctx->data)
  435. slapi_ch_free((void **)&ctx->data);
  436. slapi_ch_free((void **)&ctx);
  437. return -1;
  438. }
  439. }
  440. /*
  441. ** Return the Slapi_Entry of the result set one
  442. ** by one
  443. */
  444. for ( n = 0, ptr=(Slapi_Entry **)ctx->data; ptr != NULL && ptr[n] != NULL; n++ );
  445. if ( n != 0) {
  446. Slapi_Entry * anEntry=ptr[n-1];
  447. ptr[n-1]=NULL;
  448. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,anEntry);
  449. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
  450. cb_set_acl_policy(pb);
  451. ctx->tobefreed=anEntry;
  452. } else {
  453. slapi_ch_free((void **) &ctx);
  454. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
  455. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  456. }
  457. return 0;
  458. }
  459. /*
  460. * Grab a connection handle. Should be the same as the one
  461. * used in the build_candidate list. To be certain of that, grab it from
  462. * the context.
  463. */
  464. /* Poll the server for the results of the search operation.
  465. * Passing LDAP_MSG_ONE indicates that you want to receive
  466. * the entries one at a time, as they come in. If the next
  467. * entry that you retrieve is NULL, there are no more entries.
  468. */
  469. /* heart-beat management */
  470. if (cb->max_idle_time>0)
  471. endtime=current_time() + cb->max_idle_time;
  472. while (1) {
  473. if (cb_check_forward_abandon(cb,pb,ctx->ld,ctx->msgid)) {
  474. /* cnx handle released */
  475. ldap_msgfree(ctx->pending_result);
  476. slapi_ch_free((void **) &ctx);
  477. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
  478. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  479. return -1;
  480. }
  481. /* Check for time limit done by the remote farm server */
  482. /* Check for size limit done by the remote farm server */
  483. /* Use pending msg if one is available */
  484. if (ctx->pending_result) {
  485. res=ctx->pending_result;
  486. rc=ctx->pending_result_type;
  487. ctx->pending_result=NULL;
  488. } else {
  489. rc=ldap_result(ctx->ld,ctx->msgid,
  490. LDAP_MSG_ONE, &cb->abandon_timeout, &res );
  491. }
  492. /* The server can return three types of results back to the client,
  493. * and the return value of ldap_result() indicates the result type:
  494. * LDAP_RES_SEARCH_ENTRY identifies an entry found by the search,
  495. * LDAP_RES_SEARCH_REFERENCE identifies a search reference returned
  496. * by the server, and LDAP_RES_SEARCH_RESULT is the last result
  497. * sent from the server to the client after the operation completes.
  498. * We need to check for each of these types of results.
  499. */
  500. switch ( rc ) {
  501. case -1:
  502. /* An error occurred. */
  503. rc = slapi_ldap_get_lderrno( ctx->ld, NULL, NULL );
  504. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  505. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  506. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string( rc ), 0, NULL);
  507. ldap_msgfree(res);
  508. cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(rc));
  509. slapi_ch_free((void **)&ctx);
  510. return -1;
  511. case 0:
  512. /* heart-beat management */
  513. if ((rc=cb_ping_farm(cb,ctx->cnx,endtime)) != LDAP_SUCCESS) {
  514. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  515. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  516. cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
  517. ldap_err2string(rc), 0, NULL);
  518. ldap_msgfree(res);
  519. cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(rc));
  520. slapi_ch_free((void **)&ctx);
  521. return -1;
  522. }
  523. #ifdef CB_YIELD
  524. DS_Sleep(PR_INTERVAL_NO_WAIT);
  525. #endif
  526. break;
  527. case LDAP_RES_SEARCH_ENTRY:
  528. /* heart-beat management */
  529. if (cb->max_idle_time>0)
  530. endtime=current_time() + cb->max_idle_time;
  531. /* The server sent one of the entries found by the search */
  532. if ((entry = cb_LDAPMessage2Entry(ctx->ld,res,attrsonly)) == NULL) {
  533. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,"Invalid entry received.\n");
  534. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  535. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  536. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL , 0, NULL);
  537. ldap_msgfree(res);
  538. cb_release_op_connection(cb->pool,ctx->ld,0);
  539. slapi_ch_free((void **)&ctx);
  540. return -1;
  541. }
  542. ctx->tobefreed=entry;
  543. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
  544. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,entry);
  545. cb_set_acl_policy(pb);
  546. ldap_msgfree(res);
  547. return 0;
  548. case LDAP_RES_SEARCH_REFERENCE:
  549. /* The server sent a search reference encountered during the
  550. * search operation.
  551. */
  552. /* heart-beat management */
  553. if (cb->max_idle_time>0)
  554. endtime=current_time() + cb->max_idle_time;
  555. parse_rc = ldap_parse_reference( ctx->ld, res, &referrals, NULL, 1 );
  556. if ( parse_rc != LDAP_SUCCESS ) {
  557. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  558. ldap_err2string( parse_rc ), 0, NULL);
  559. cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(parse_rc));
  560. slapi_ch_free((void **)&ctx);
  561. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  562. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  563. return -1;
  564. }
  565. /*
  566. ** build a dummy entry on the fly with a ref attribute
  567. */
  568. {
  569. struct berval bv;
  570. int i;
  571. struct berval *bvals[2];
  572. Slapi_Entry *anEntry = slapi_entry_alloc();
  573. slapi_entry_set_sdn(anEntry, target_sdn);
  574. bvals[1]=NULL;
  575. bvals[0]=&bv;
  576. bv.bv_val="referral";
  577. bv.bv_len=strlen(bv.bv_val);
  578. slapi_entry_add_values( anEntry, "objectclass", bvals);
  579. for (i=0;referrals[i] != NULL; i++) {
  580. bv.bv_val=referrals[i];
  581. bv.bv_len=strlen(bv.bv_val);
  582. slapi_entry_add_values( anEntry, "ref", bvals);
  583. }
  584. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
  585. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,anEntry);
  586. cb_set_acl_policy(pb);
  587. }
  588. if (referrals != NULL) {
  589. slapi_ldap_value_free( referrals );
  590. }
  591. return 0;
  592. case LDAP_RES_SEARCH_RESULT:
  593. /* Parse the final result received from the server. Note the last
  594. * argument is a non-zero value, which indicates that the
  595. * LDAPMessage structure will be freed when done.
  596. */
  597. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
  598. slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
  599. parse_rc = ldap_parse_result( ctx->ld, res,
  600. &rc,&matched_msg,&error_msg, &referrals, &serverctrls, 1 );
  601. if ( parse_rc != LDAP_SUCCESS ) {
  602. static int warned_parse_rc = 0;
  603. if (!warned_parse_rc) {
  604. slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  605. "%s%s%s\n",
  606. matched_msg?matched_msg:"",
  607. (matched_msg&&(*matched_msg!='\0'))?": ":"",
  608. ldap_err2string( parse_rc ));
  609. warned_parse_rc = 1;
  610. }
  611. cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  612. ENDUSERMSG, 0, NULL );
  613. retcode=-1;
  614. } else
  615. if ( rc != LDAP_SUCCESS ) {
  616. static int warned_rc = 0;
  617. slapi_ldap_get_lderrno( ctx->ld, &matched_msg, &error_msg );
  618. if (!warned_rc) {
  619. slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
  620. "%s%s%s\n",
  621. matched_msg?matched_msg:"",
  622. (matched_msg&&(*matched_msg!='\0'))?": ":"",
  623. error_msg );
  624. warned_rc = 1;
  625. }
  626. cb_send_ldap_result( pb, rc, matched_msg, ENDUSERMSG, 0, NULL );
  627. /* BEWARE: Don't free matched_msg && error_msg */
  628. /* Points to the ld fields */
  629. matched_msg=NULL;
  630. error_msg=NULL;
  631. retcode=-1;
  632. } else {
  633. /* Add control response sent by the farm server */
  634. for (i=0; serverctrls && serverctrls[i];i++)
  635. slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
  636. retcode=0;
  637. }
  638. ldap_controls_free(serverctrls);
  639. slapi_ch_free_string(&matched_msg);
  640. slapi_ch_free_string(&error_msg);
  641. charray_free(referrals);
  642. cb_release_op_connection(cb->pool,ctx->ld,0);
  643. slapi_ch_free((void **)&ctx);
  644. return retcode;
  645. default:
  646. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  647. "chainingdb_next_search_entry:default case.\n");
  648. }
  649. }
  650. /* Not reached */
  651. /* return 0; */
  652. }
  653. int
  654. chaining_back_entry_release ( Slapi_PBlock *pb ) {
  655. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM, "chaining_back_entry_release\n");
  656. return 0;
  657. }
  658. void
  659. chaining_back_search_results_release ( void **sr )
  660. {
  661. cb_searchContext *ctx = (cb_searchContext *)(*sr);
  662. slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
  663. "chaining_back_search_results_release\n");
  664. if (ctx->readahead != ctx->tobefreed) {
  665. slapi_entry_free(ctx->readahead);
  666. }
  667. slapi_entry_free(ctx->tobefreed);
  668. ctx->tobefreed = NULL;
  669. slapi_ch_free((void **)&ctx->data);
  670. slapi_ch_free((void **)&ctx);
  671. return;
  672. }
  673. void
  674. chainingdb_prev_search_results ( Slapi_PBlock *pb )
  675. {
  676. cb_searchContext *ctx = NULL;
  677. Slapi_Entry *entry = NULL;
  678. slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &ctx );
  679. slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_ENTRY, &entry );
  680. if (ctx) {
  681. ctx->readahead = entry;
  682. }
  683. return;
  684. }