extendop.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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. /* extendedop.c - handle an LDAPv3 extended operation */
  42. #include <stdio.h>
  43. #include "slap.h"
  44. static const char *extended_op_oid2string( const char *oid );
  45. /********** this stuff should probably be moved when it's done **********/
  46. static void extop_handle_import_start(Slapi_PBlock *pb, char *extoid,
  47. struct berval *extval)
  48. {
  49. char *suffix;
  50. Slapi_DN *sdn = NULL;
  51. Slapi_Backend *be = NULL;
  52. struct berval bv;
  53. int ret;
  54. if (extval == NULL || extval->bv_val == NULL) {
  55. LDAPDebug(LDAP_DEBUG_ANY,
  56. "extop_handle_import_start: no data supplied\n", 0, 0, 0);
  57. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
  58. "no data supplied", 0, NULL);
  59. return;
  60. }
  61. suffix = slapi_ch_malloc(extval->bv_len+1);
  62. strncpy(suffix, extval->bv_val, extval->bv_len);
  63. suffix[extval->bv_len] = 0;
  64. sdn = slapi_sdn_new_dn_byval(suffix);
  65. if (!sdn) {
  66. LDAPDebug(LDAP_DEBUG_ANY,
  67. "extop_handle_import_start: out of memory\n", 0, 0, 0);
  68. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
  69. return;
  70. }
  71. /* be = slapi_be_select(sdn); */
  72. be = slapi_mapping_tree_find_backend_for_sdn(sdn);
  73. slapi_sdn_free(&sdn);
  74. if (be == NULL || be == defbackend_get_backend()) {
  75. /* might be instance name instead of suffix */
  76. be = slapi_be_select_by_instance_name(suffix);
  77. }
  78. if (be == NULL || be == defbackend_get_backend()) {
  79. LDAPDebug(LDAP_DEBUG_ANY,
  80. "bulk import: invalid suffix or instance name '%s'\n",
  81. suffix, 0, 0);
  82. send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL,
  83. "invalid suffix or instance name", 0, NULL);
  84. goto out;
  85. }
  86. slapi_pblock_set(pb, SLAPI_BACKEND, be);
  87. slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
  88. {
  89. /* Access Control Check to see if the client is
  90. * allowed to use task import
  91. */
  92. char *dummyAttr = "dummy#attr";
  93. char *dummyAttrs[2] = { NULL, NULL };
  94. int rc = 0;
  95. char dn[128];
  96. Slapi_Entry *feature;
  97. /* slapi_str2entry modify its dn parameter so we must copy
  98. * this string each time we call it !
  99. */
  100. PR_snprintf(dn, sizeof(dn), "dn: oid=%s,cn=features,cn=config",
  101. EXTOP_BULK_IMPORT_START_OID);
  102. dummyAttrs[0] = dummyAttr;
  103. feature = slapi_str2entry(dn, 0);
  104. rc = plugin_call_acl_plugin (pb, feature, dummyAttrs, NULL,
  105. SLAPI_ACL_WRITE, ACLPLUGIN_ACCESS_DEFAULT, NULL);
  106. slapi_entry_free(feature);
  107. if (rc != LDAP_SUCCESS)
  108. {
  109. /* Client isn't allowed to do this. */
  110. send_ldap_result(pb, rc, NULL, NULL, 0, NULL);
  111. goto out;
  112. }
  113. }
  114. if (be->be_wire_import == NULL) {
  115. /* not supported by this backend */
  116. LDAPDebug(LDAP_DEBUG_ANY,
  117. "bulk import attempted on '%s' (not supported)\n",
  118. suffix, 0, 0);
  119. send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
  120. goto out;
  121. }
  122. ret = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
  123. slapi_pblock_set(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &ret);
  124. ret = SLAPI_BI_STATE_START;
  125. slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
  126. ret = (*be->be_wire_import)(pb);
  127. if (ret != 0) {
  128. LDAPDebug(LDAP_DEBUG_ANY,
  129. "extop_handle_import_start: error starting import (%d)\n",
  130. ret, 0, 0);
  131. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
  132. goto out;
  133. }
  134. /* okay, the import is starting now -- save the backend in the
  135. * connection block & mark this connection as belonging to a bulk import
  136. */
  137. PR_Lock(pb->pb_conn->c_mutex);
  138. pb->pb_conn->c_flags |= CONN_FLAG_IMPORT;
  139. pb->pb_conn->c_bi_backend = be;
  140. PR_Unlock(pb->pb_conn->c_mutex);
  141. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXTOP_BULK_IMPORT_START_OID);
  142. bv.bv_val = NULL;
  143. bv.bv_len = 0;
  144. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &bv);
  145. send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  146. LDAPDebug(LDAP_DEBUG_ANY,
  147. "Bulk import: begin import on '%s'.\n", suffix, 0, 0);
  148. out:
  149. slapi_ch_free((void **)&suffix);
  150. return;
  151. }
  152. static void extop_handle_import_done(Slapi_PBlock *pb, char *extoid,
  153. struct berval *extval)
  154. {
  155. Slapi_Backend *be;
  156. struct berval bv;
  157. int ret;
  158. PR_Lock(pb->pb_conn->c_mutex);
  159. pb->pb_conn->c_flags &= ~CONN_FLAG_IMPORT;
  160. be = pb->pb_conn->c_bi_backend;
  161. pb->pb_conn->c_bi_backend = NULL;
  162. PR_Unlock(pb->pb_conn->c_mutex);
  163. if ((be == NULL) || (be->be_wire_import == NULL)) {
  164. /* can this even happen? */
  165. LDAPDebug(LDAP_DEBUG_ANY,
  166. "extop_handle_import_done: backend not supported\n",
  167. 0, 0, 0);
  168. send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
  169. return;
  170. }
  171. /* signal "done" to the backend */
  172. slapi_pblock_set(pb, SLAPI_BACKEND, be);
  173. slapi_pblock_set(pb, SLAPI_BULK_IMPORT_ENTRY, NULL);
  174. ret = SLAPI_BI_STATE_DONE;
  175. slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
  176. ret = (*be->be_wire_import)(pb);
  177. if (ret != 0) {
  178. LDAPDebug(LDAP_DEBUG_ANY,
  179. "bulk import: error ending import (%d)\n",
  180. ret, 0, 0);
  181. send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
  182. return;
  183. }
  184. /* more goofiness */
  185. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXTOP_BULK_IMPORT_DONE_OID);
  186. bv.bv_val = NULL;
  187. bv.bv_len = 0;
  188. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &bv);
  189. send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  190. LDAPDebug(LDAP_DEBUG_ANY,
  191. "Bulk import completed successfully.\n", 0, 0, 0);
  192. return;
  193. }
  194. void
  195. do_extended( Slapi_PBlock *pb )
  196. {
  197. char *extoid = NULL, *errmsg;
  198. struct berval extval = {0};
  199. int lderr, rc;
  200. ber_len_t len;
  201. ber_tag_t tag;
  202. const char *name;
  203. LDAPDebug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
  204. /*
  205. * Parse the extended request. It looks like this:
  206. *
  207. * ExtendedRequest := [APPLICATION 23] SEQUENCE {
  208. * requestName [0] LDAPOID,
  209. * requestValue [1] OCTET STRING OPTIONAL
  210. * }
  211. */
  212. if ( ber_scanf( pb->pb_op->o_ber, "{a", &extoid )
  213. == LBER_ERROR ) {
  214. LDAPDebug( LDAP_DEBUG_ANY,
  215. "ber_scanf failed (op=extended; params=OID)\n",
  216. 0, 0, 0 );
  217. op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension OID");
  218. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
  219. NULL );
  220. goto free_and_return;
  221. }
  222. tag = ber_peek_tag(pb->pb_op->o_ber, &len);
  223. if (tag == LDAP_TAG_EXOP_REQ_VALUE) {
  224. if ( ber_scanf( pb->pb_op->o_ber, "o}", &extval ) == LBER_ERROR ) {
  225. op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension value");
  226. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
  227. NULL );
  228. goto free_and_return;
  229. }
  230. } else {
  231. if ( ber_scanf( pb->pb_op->o_ber, "}") == LBER_ERROR ) {
  232. op_shared_log_error_access (pb, "EXT", "???", "decoding error");
  233. send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
  234. NULL );
  235. goto free_and_return;
  236. }
  237. }
  238. if ( NULL == ( name = extended_op_oid2string( extoid ))) {
  239. LDAPDebug( LDAP_DEBUG_ARGS, "do_extended: oid (%s)\n", extoid, 0, 0 );
  240. slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d EXT oid=\"%s\"\n",
  241. pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid );
  242. } else {
  243. LDAPDebug( LDAP_DEBUG_ARGS, "do_extended: oid (%s-%s)\n",
  244. extoid, name, 0 );
  245. slapi_log_access( LDAP_DEBUG_STATS,
  246. "conn=%" NSPRIu64 " op=%d EXT oid=\"%s\" name=\"%s\"\n",
  247. pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid, name );
  248. }
  249. /* during a bulk import, only BULK_IMPORT_DONE is allowed!
  250. * (and this is the only time it's allowed)
  251. */
  252. if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) {
  253. if (strcmp(extoid, EXTOP_BULK_IMPORT_DONE_OID) != 0) {
  254. send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
  255. goto free_and_return;
  256. }
  257. extop_handle_import_done(pb, extoid, &extval);
  258. goto free_and_return;
  259. }
  260. if (strcmp(extoid, EXTOP_BULK_IMPORT_START_OID) == 0) {
  261. extop_handle_import_start(pb, extoid, &extval);
  262. goto free_and_return;
  263. }
  264. /* If a password change is required, only allow the password
  265. * modify extended operation */
  266. if (!pb->pb_conn->c_isreplication_session &&
  267. pb->pb_conn->c_needpw && (strcmp(extoid, EXTOP_PASSWD_OID) != 0))
  268. {
  269. char *dn = NULL;
  270. slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);
  271. (void)slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  272. op_shared_log_error_access (pb, "EXT", dn ? dn : "", "need new password");
  273. send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );
  274. slapi_ch_free_string(&dn);
  275. goto free_and_return;
  276. }
  277. /* decode the optional controls - put them in the pblock */
  278. if ( (lderr = get_ldapmessage_controls( pb, pb->pb_op->o_ber, NULL )) != 0 )
  279. {
  280. char *dn = NULL;
  281. slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);
  282. op_shared_log_error_access (pb, "EXT", dn ? dn : "", "failed to decode LDAP controls");
  283. send_ldap_result( pb, lderr, NULL, NULL, 0, NULL );
  284. slapi_ch_free_string(&dn);
  285. goto free_and_return;
  286. }
  287. slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_OID, extoid );
  288. slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_VALUE, &extval );
  289. rc = plugin_call_exop_plugins( pb, extoid );
  290. if ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT != rc ) {
  291. if ( SLAPI_PLUGIN_EXTENDED_NOT_HANDLED == rc ) {
  292. lderr = LDAP_PROTOCOL_ERROR; /* no plugin handled the op */
  293. errmsg = "unsupported extended operation";
  294. } else {
  295. errmsg = NULL;
  296. lderr = rc;
  297. }
  298. send_ldap_result( pb, lderr, NULL, errmsg, 0, NULL );
  299. }
  300. free_and_return:
  301. if (extoid)
  302. slapi_ch_free((void **)&extoid);
  303. if (extval.bv_val)
  304. slapi_ch_free((void **)&extval.bv_val);
  305. return;
  306. }
  307. static const char *
  308. extended_op_oid2string( const char *oid )
  309. {
  310. const char *rval = NULL;
  311. if ( 0 == strcmp(oid, EXTOP_BULK_IMPORT_START_OID)) {
  312. rval = "Bulk Import Start";
  313. } else if ( 0 == strcmp(oid, EXTOP_BULK_IMPORT_DONE_OID)) {
  314. rval = "Bulk Import End";
  315. } else {
  316. rval = plugin_extended_op_oid2string( oid );
  317. }
  318. return( rval );
  319. }