extendop.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. /* extendedop.c - handle an LDAPv3 extended operation */
  13. #include <stdio.h>
  14. #include "slap.h"
  15. static const char *extended_op_oid2string( const char *oid );
  16. /********** this stuff should probably be moved when it's done **********/
  17. static void extop_handle_import_start(Slapi_PBlock *pb, char *extoid,
  18. struct berval *extval)
  19. {
  20. char *orig = NULL;
  21. const char *suffix = NULL;
  22. Slapi_DN *sdn = NULL;
  23. Slapi_Backend *be = NULL;
  24. struct berval bv;
  25. int ret;
  26. if (extval == NULL || extval->bv_val == NULL) {
  27. LDAPDebug(LDAP_DEBUG_ANY,
  28. "extop_handle_import_start: no data supplied\n", 0, 0, 0);
  29. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
  30. "no data supplied", 0, NULL);
  31. return;
  32. }
  33. orig = slapi_ch_malloc(extval->bv_len+1);
  34. strncpy(orig, extval->bv_val, extval->bv_len);
  35. orig[extval->bv_len] = 0;
  36. /* Check if we should be performing strict validation. */
  37. if (config_get_dn_validate_strict()) {
  38. /* check that the dn is formatted correctly */
  39. ret = slapi_dn_syntax_check(pb, orig, 1);
  40. if (ret) { /* syntax check failed */
  41. LDAPDebug1Arg(LDAP_DEBUG_ANY,
  42. "extop_handle_import_start: strict: invalid suffix\n",
  43. orig);
  44. send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL,
  45. "invalid suffix", 0, NULL);
  46. return;
  47. }
  48. }
  49. sdn = slapi_sdn_new_dn_passin(orig);
  50. if (!sdn) {
  51. LDAPDebug(LDAP_DEBUG_ANY,
  52. "extop_handle_import_start: out of memory\n", 0, 0, 0);
  53. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
  54. return;
  55. }
  56. suffix = slapi_sdn_get_dn(sdn);
  57. /* be = slapi_be_select(sdn); */
  58. be = slapi_mapping_tree_find_backend_for_sdn(sdn);
  59. if (be == NULL || be == defbackend_get_backend()) {
  60. /* might be instance name instead of suffix */
  61. be = slapi_be_select_by_instance_name(suffix);
  62. }
  63. if (be == NULL || be == defbackend_get_backend()) {
  64. LDAPDebug(LDAP_DEBUG_ANY,
  65. "bulk import: invalid suffix or instance name '%s'\n",
  66. suffix, 0, 0);
  67. send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL,
  68. "invalid suffix or instance name", 0, NULL);
  69. goto out;
  70. }
  71. slapi_pblock_set(pb, SLAPI_BACKEND, be);
  72. slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
  73. {
  74. /* Access Control Check to see if the client is
  75. * allowed to use task import
  76. */
  77. char *dummyAttr = "dummy#attr";
  78. char *dummyAttrs[2] = { NULL, NULL };
  79. int rc = 0;
  80. char dn[128];
  81. Slapi_Entry *feature;
  82. /* slapi_str2entry modify its dn parameter so we must copy
  83. * this string each time we call it !
  84. */
  85. /* This dn is no need to be normalized. */
  86. PR_snprintf(dn, sizeof(dn), "dn: oid=%s,cn=features,cn=config",
  87. EXTOP_BULK_IMPORT_START_OID);
  88. dummyAttrs[0] = dummyAttr;
  89. feature = slapi_str2entry(dn, 0);
  90. rc = plugin_call_acl_plugin (pb, feature, dummyAttrs, NULL,
  91. SLAPI_ACL_WRITE, ACLPLUGIN_ACCESS_DEFAULT, NULL);
  92. slapi_entry_free(feature);
  93. if (rc != LDAP_SUCCESS)
  94. {
  95. /* Client isn't allowed to do this. */
  96. send_ldap_result(pb, rc, NULL, NULL, 0, NULL);
  97. goto out;
  98. }
  99. }
  100. if (be->be_wire_import == NULL) {
  101. /* not supported by this backend */
  102. LDAPDebug(LDAP_DEBUG_ANY,
  103. "bulk import attempted on '%s' (not supported)\n",
  104. suffix, 0, 0);
  105. send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
  106. goto out;
  107. }
  108. ret = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
  109. slapi_pblock_set(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &ret);
  110. ret = SLAPI_BI_STATE_START;
  111. slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
  112. ret = (*be->be_wire_import)(pb);
  113. if (ret != 0) {
  114. LDAPDebug(LDAP_DEBUG_ANY,
  115. "extop_handle_import_start: error starting import (%d)\n",
  116. ret, 0, 0);
  117. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
  118. goto out;
  119. }
  120. /* okay, the import is starting now -- save the backend in the
  121. * connection block & mark this connection as belonging to a bulk import
  122. */
  123. PR_EnterMonitor(pb->pb_conn->c_mutex);
  124. pb->pb_conn->c_flags |= CONN_FLAG_IMPORT;
  125. pb->pb_conn->c_bi_backend = be;
  126. PR_ExitMonitor(pb->pb_conn->c_mutex);
  127. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXTOP_BULK_IMPORT_START_OID);
  128. bv.bv_val = NULL;
  129. bv.bv_len = 0;
  130. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &bv);
  131. send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  132. LDAPDebug(LDAP_DEBUG_ANY,
  133. "Bulk import: begin import on '%s'.\n", suffix, 0, 0);
  134. out:
  135. slapi_sdn_free(&sdn);
  136. return;
  137. }
  138. static void extop_handle_import_done(Slapi_PBlock *pb, char *extoid,
  139. struct berval *extval)
  140. {
  141. Slapi_Backend *be;
  142. struct berval bv;
  143. int ret;
  144. PR_EnterMonitor(pb->pb_conn->c_mutex);
  145. pb->pb_conn->c_flags &= ~CONN_FLAG_IMPORT;
  146. be = pb->pb_conn->c_bi_backend;
  147. pb->pb_conn->c_bi_backend = NULL;
  148. PR_ExitMonitor(pb->pb_conn->c_mutex);
  149. if ((be == NULL) || (be->be_wire_import == NULL)) {
  150. /* can this even happen? */
  151. LDAPDebug(LDAP_DEBUG_ANY,
  152. "extop_handle_import_done: backend not supported\n",
  153. 0, 0, 0);
  154. send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
  155. return;
  156. }
  157. /* signal "done" to the backend */
  158. slapi_pblock_set(pb, SLAPI_BACKEND, be);
  159. slapi_pblock_set(pb, SLAPI_BULK_IMPORT_ENTRY, NULL);
  160. ret = SLAPI_BI_STATE_DONE;
  161. slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
  162. ret = (*be->be_wire_import)(pb);
  163. if (ret != 0) {
  164. LDAPDebug(LDAP_DEBUG_ANY,
  165. "bulk import: error ending import (%d)\n",
  166. ret, 0, 0);
  167. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
  168. return;
  169. }
  170. /* more goofiness */
  171. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXTOP_BULK_IMPORT_DONE_OID);
  172. bv.bv_val = NULL;
  173. bv.bv_len = 0;
  174. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &bv);
  175. send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  176. LDAPDebug(LDAP_DEBUG_ANY,
  177. "Bulk import completed successfully.\n", 0, 0, 0);
  178. return;
  179. }
  180. void
  181. do_extended( Slapi_PBlock *pb )
  182. {
  183. char *extoid = NULL, *errmsg;
  184. struct berval extval = {0};
  185. int lderr, rc;
  186. ber_len_t len;
  187. ber_tag_t tag;
  188. const char *name;
  189. LDAPDebug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
  190. /*
  191. * Parse the extended request. It looks like this:
  192. *
  193. * ExtendedRequest := [APPLICATION 23] SEQUENCE {
  194. * requestName [0] LDAPOID,
  195. * requestValue [1] OCTET STRING OPTIONAL
  196. * }
  197. */
  198. if ( ber_scanf( pb->pb_op->o_ber, "{a", &extoid )
  199. == LBER_ERROR ) {
  200. LDAPDebug( LDAP_DEBUG_ANY,
  201. "ber_scanf failed (op=extended; params=OID)\n",
  202. 0, 0, 0 );
  203. op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension OID");
  204. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
  205. NULL );
  206. goto free_and_return;
  207. }
  208. tag = ber_peek_tag(pb->pb_op->o_ber, &len);
  209. if (tag == LDAP_TAG_EXOP_REQ_VALUE) {
  210. if ( ber_scanf( pb->pb_op->o_ber, "o}", &extval ) == LBER_ERROR ) {
  211. op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension value");
  212. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
  213. NULL );
  214. goto free_and_return;
  215. }
  216. } else {
  217. if ( ber_scanf( pb->pb_op->o_ber, "}") == LBER_ERROR ) {
  218. op_shared_log_error_access (pb, "EXT", "???", "decoding error");
  219. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
  220. NULL );
  221. goto free_and_return;
  222. }
  223. }
  224. if ( NULL == ( name = extended_op_oid2string( extoid ))) {
  225. LDAPDebug( LDAP_DEBUG_ARGS, "do_extended: oid (%s)\n", extoid, 0, 0 );
  226. slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d EXT oid=\"%s\"\n",
  227. pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid );
  228. } else {
  229. LDAPDebug( LDAP_DEBUG_ARGS, "do_extended: oid (%s-%s)\n",
  230. extoid, name, 0 );
  231. slapi_log_access( LDAP_DEBUG_STATS,
  232. "conn=%" NSPRIu64 " op=%d EXT oid=\"%s\" name=\"%s\"\n",
  233. pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid, name );
  234. }
  235. /* during a bulk import, only BULK_IMPORT_DONE is allowed!
  236. * (and this is the only time it's allowed)
  237. */
  238. if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) {
  239. if (strcmp(extoid, EXTOP_BULK_IMPORT_DONE_OID) != 0) {
  240. send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
  241. goto free_and_return;
  242. }
  243. extop_handle_import_done(pb, extoid, &extval);
  244. goto free_and_return;
  245. }
  246. if (strcmp(extoid, EXTOP_BULK_IMPORT_START_OID) == 0) {
  247. extop_handle_import_start(pb, extoid, &extval);
  248. goto free_and_return;
  249. }
  250. if (strcmp(extoid, START_TLS_OID) != 0) {
  251. int minssf = config_get_minssf();
  252. /* If anonymous access is disabled and we haven't
  253. * authenticated yet, only allow startTLS. */
  254. if ((config_get_anon_access_switch() != SLAPD_ANON_ACCESS_ON) && ((pb->pb_op->o_authtype == NULL) ||
  255. (strcasecmp(pb->pb_op->o_authtype, SLAPD_AUTH_NONE) == 0))) {
  256. send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
  257. "Anonymous access is not allowed.", 0, NULL );
  258. goto free_and_return;
  259. }
  260. /* If the minssf is not met, only allow startTLS. */
  261. if ((pb->pb_conn->c_sasl_ssf < minssf) && (pb->pb_conn->c_ssl_ssf < minssf) &&
  262. (pb->pb_conn->c_local_ssf < minssf)) {
  263. send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
  264. "Minimum SSF not met.", 0, NULL );
  265. goto free_and_return;
  266. }
  267. }
  268. /* If a password change is required, only allow the password
  269. * modify extended operation */
  270. if (!pb->pb_conn->c_isreplication_session &&
  271. pb->pb_conn->c_needpw && (strcmp(extoid, EXTOP_PASSWD_OID) != 0))
  272. {
  273. char *dn = NULL;
  274. slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);
  275. (void)slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  276. op_shared_log_error_access (pb, "EXT", dn ? dn : "", "need new password");
  277. send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );
  278. slapi_ch_free_string(&dn);
  279. goto free_and_return;
  280. }
  281. /* decode the optional controls - put them in the pblock */
  282. if ( (lderr = get_ldapmessage_controls( pb, pb->pb_op->o_ber, NULL )) != 0 )
  283. {
  284. char *dn = NULL;
  285. slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);
  286. op_shared_log_error_access (pb, "EXT", dn ? dn : "", "failed to decode LDAP controls");
  287. send_ldap_result( pb, lderr, NULL, NULL, 0, NULL );
  288. slapi_ch_free_string(&dn);
  289. goto free_and_return;
  290. }
  291. slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_OID, extoid );
  292. slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_VALUE, &extval );
  293. slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot);
  294. /* wibrown 201603 I want to rewrite this to get plugin p, and use that
  295. * rather than all these plugin_call_, that loop over the plugin lists
  296. * We do "get plugin (oid).
  297. * then we just hand *p into the call functions.
  298. * much more efficient! :)
  299. */
  300. slapi_log_error(SLAPI_LOG_TRACE, NULL, "extendop.c calling plugins ... \n");
  301. rc = plugin_call_exop_plugins( pb, extoid, SLAPI_PLUGIN_EXTENDEDOP);
  302. slapi_log_error(SLAPI_LOG_TRACE, NULL, "extendop.c called exop, got %d \n", rc);
  303. if (rc == SLAPI_PLUGIN_EXTENDED_NOT_HANDLED) {
  304. slapi_log_error(SLAPI_LOG_TRACE, NULL, "extendop.c calling betxn plugins ... \n");
  305. /* Look up the correct backend to use. */
  306. Slapi_Backend *be = plugin_extended_op_getbackend( pb, extoid );
  307. if ( be == NULL ) {
  308. slapi_log_error(SLAPI_LOG_FATAL, NULL, "extendop.c plugin_extended_op_getbackend was unable to retrieve a backend!!!\n");
  309. rc = SLAPI_PLUGIN_EXTENDED_NO_BACKEND_AVAILABLE;
  310. } else {
  311. /* We need to make a new be pb here because when you set SLAPI_BACKEND
  312. * you overwrite the plg parts of the pb. So if we re-use pb
  313. * you actually nuke the request, and everything hangs. (╯°□°)╯︵ ┻━┻
  314. */
  315. Slapi_PBlock *be_pb = NULL;
  316. be_pb = slapi_pblock_new();
  317. slapi_pblock_set(be_pb, SLAPI_BACKEND, be);
  318. int txn_rc = slapi_back_transaction_begin(be_pb);
  319. if (txn_rc) {
  320. slapi_log_error(SLAPI_LOG_FATAL, NULL, "exendop.c Failed to start be_txn for plugin_call_exop_plugins %d\n", txn_rc);
  321. } else {
  322. rc = plugin_call_exop_plugins( pb, extoid, SLAPI_PLUGIN_BETXNEXTENDEDOP);
  323. slapi_log_error(SLAPI_LOG_TRACE, NULL, "extendop.c called betxn exop, got %d \n", rc);
  324. if (rc == LDAP_SUCCESS || rc == SLAPI_PLUGIN_EXTENDED_SENT_RESULT) {
  325. /* commit */
  326. txn_rc = slapi_back_transaction_commit(be_pb);
  327. if (txn_rc == 0) {
  328. slapi_log_error(SLAPI_LOG_TRACE, NULL, "extendop.c commit with result %d \n", txn_rc);
  329. } else {
  330. slapi_log_error(SLAPI_LOG_FATAL, NULL, "extendop.c Unable to commit commit with result %d \n", txn_rc);
  331. }
  332. } else {
  333. /* abort */
  334. txn_rc = slapi_back_transaction_abort(be_pb);
  335. slapi_log_error(SLAPI_LOG_FATAL, NULL, "extendop.c abort with result %d \n", txn_rc);
  336. }
  337. } /* txn_rc */
  338. if (be_pb != NULL) {
  339. slapi_pblock_destroy(be_pb); /* Clean up after ourselves */
  340. }
  341. slapi_log_error(SLAPI_LOG_TRACE, NULL, "exendop.c plugin_call_exop_plugins rc final %d\n", rc);
  342. } /* if be */
  343. }
  344. if ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT != rc ) {
  345. if ( SLAPI_PLUGIN_EXTENDED_NOT_HANDLED == rc ) {
  346. lderr = LDAP_PROTOCOL_ERROR; /* no plugin handled the op */
  347. errmsg = "unsupported extended operation";
  348. } else {
  349. errmsg = NULL;
  350. lderr = rc;
  351. }
  352. send_ldap_result( pb, lderr, NULL, errmsg, 0, NULL );
  353. }
  354. free_and_return:
  355. if (extoid)
  356. slapi_ch_free((void **)&extoid);
  357. if (extval.bv_val)
  358. slapi_ch_free((void **)&extval.bv_val);
  359. return;
  360. }
  361. static const char *
  362. extended_op_oid2string( const char *oid )
  363. {
  364. const char *rval = NULL;
  365. if ( 0 == strcmp(oid, EXTOP_BULK_IMPORT_START_OID)) {
  366. rval = "Bulk Import Start";
  367. } else if ( 0 == strcmp(oid, EXTOP_BULK_IMPORT_DONE_OID)) {
  368. rval = "Bulk Import End";
  369. } else {
  370. rval = plugin_extended_op_oid2string( oid );
  371. }
  372. return( rval );
  373. }