start_tls_extop.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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. /*
  42. * Start TLS - LDAP Extended Operation.
  43. *
  44. *
  45. * This plugin implements the "Start TLS (Transport Layer Security)"
  46. * extended operation for LDAP. The plugin function is called by
  47. * the server if an LDAP client request contains the OID:
  48. * "1.3.6.1.4.1.1466.20037".
  49. *
  50. */
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <private/pprio.h>
  54. #include <prio.h>
  55. #include <ssl.h>
  56. #include "slap.h"
  57. #include "slapi-plugin.h"
  58. #include "fe.h"
  59. /* OID of the extended operation handled by this plug-in */
  60. /* #define START_TLS_OID "1.3.6.1.4.1.1466.20037" */
  61. Slapi_PluginDesc exopdesc = { "start_tls_plugin", "Fedora", "0.1",
  62. "Start TLS extended operation plugin" };
  63. /* Start TLS Extended operation plugin function */
  64. int
  65. start_tls( Slapi_PBlock *pb )
  66. {
  67. char *oid;
  68. Connection *conn;
  69. PRFileDesc *oldsocket, *newsocket;
  70. int secure;
  71. int ns;
  72. #ifdef _WIN32
  73. int oldnativesocket;
  74. #endif
  75. int rv;
  76. /* Get the pb ready for sending Start TLS Extended Responses back to the client.
  77. * The only requirement is to set the LDAP OID of the extended response to the START_TLS_OID. */
  78. if ( slapi_pblock_set( pb, SLAPI_EXT_OP_RET_OID, START_TLS_OID ) != 0 ) {
  79. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  80. "Could not set extended response oid.\n" );
  81. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  82. "Could not set extended response oid.", 0, NULL );
  83. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  84. }
  85. /* Before going any further, we'll make sure that the right extended operation plugin
  86. * has been called: i.e., the OID shipped whithin the extended operation request must
  87. * match this very plugin's OID: START_TLS_OID. */
  88. if ( slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0 ) {
  89. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  90. "Could not get OID value from request.\n" );
  91. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  92. "Could not get OID value from request.", 0, NULL );
  93. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  94. } else {
  95. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  96. "Received extended operation request with OID %s\n", oid );
  97. }
  98. if ( strcasecmp( oid, START_TLS_OID ) != 0) {
  99. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  100. "Request OID does not match Start TLS OID.\n" );
  101. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  102. "Request OID does not match Start TLS OID.", 0, NULL );
  103. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  104. } else {
  105. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  106. "Start TLS extended operation request confirmed.\n" );
  107. }
  108. /* At least we know that the request was indeed an Start TLS one. */
  109. conn = pb->pb_conn;
  110. PR_Lock( conn->c_mutex );
  111. #ifndef _WIN32
  112. oldsocket = conn->c_prfd;
  113. if ( oldsocket == (PRFileDesc *) NULL ) {
  114. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  115. "Connection socket not available.\n" );
  116. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  117. "Connection socket not available.", 0, NULL );
  118. goto unlock_and_return;
  119. }
  120. #else
  121. oldnativesocket = conn->c_sd;
  122. oldsocket = PR_ImportTCPSocket(oldnativesocket);
  123. if ( oldsocket == (PRFileDesc *) NULL ) {
  124. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  125. "Failed to import NT native socket into NSPR.\n" );
  126. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  127. "Failed to import NT native socket into NSPR.", 0, NULL );
  128. goto unlock_and_return;
  129. }
  130. #endif
  131. /* Check whether the Start TLS request can be accepted. */
  132. if ( connection_operations_pending( conn, pb->pb_op,
  133. 1 /* check for ops where result not yet sent */ )) {
  134. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  135. "Other operations are still pending on the connection.\n" );
  136. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  137. "Other operations are still pending on the connection.", 0, NULL );
  138. goto unlock_and_return;
  139. }
  140. if ( !config_get_security() ) {
  141. /* if any, here is where the referral to another SSL supporting server should be done: */
  142. /* slapi_send_ldap_result( pb, LDAP_REFERRAL, NULL, msg, 0, url ); */
  143. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  144. "SSL not supported by this server.\n" );
  145. slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
  146. "SSL not supported by this server.", 0, NULL );
  147. goto unlock_and_return;
  148. }
  149. if ( conn->c_flags & CONN_FLAG_SSL ) {
  150. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  151. "SSL connection already established.\n" );
  152. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  153. "SSL connection already established.", 0, NULL );
  154. goto unlock_and_return;
  155. }
  156. if ( conn->c_flags & CONN_FLAG_SASL_CONTINUE ) {
  157. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  158. "SASL multi-stage bind in progress.\n" );
  159. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
  160. "SASL multi-stage bind in progress.", 0, NULL );
  161. goto unlock_and_return;
  162. }
  163. if ( conn->c_flags & CONN_FLAG_CLOSING ) {
  164. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  165. "Connection being closed at this moment.\n" );
  166. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  167. "Connection being closed at this moment.", 0, NULL );
  168. goto unlock_and_return;
  169. }
  170. /* At first sight, there doesn't seem to be any major impediment to start TLS.
  171. * So, we may as well try initialising SSL. */
  172. if ( slapd_security_library_is_initialized() == 0 ) {
  173. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  174. "NSS libraries not initialised.\n" );
  175. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  176. "NSS libraries not initialised.", 0, NULL );
  177. goto unlock_and_return;
  178. }
  179. /* Since no specific argument for denying the Start TLS request has been found,
  180. * we send a success response back to the client. */
  181. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  182. "Start TLS request accepted.Server willing to negotiate SSL.\n" );
  183. slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL,
  184. "Start TLS request accepted.Server willing to negotiate SSL.", 0, NULL );
  185. /* So far we have set up the environment for deploying SSL. It's now time to import the socket
  186. * into SSL and to configure it consequently. */
  187. if ( slapd_ssl_listener_is_initialized() != 0 ) {
  188. PRFileDesc * ssl_listensocket;
  189. ssl_listensocket = get_ssl_listener_fd();
  190. if ( ssl_listensocket == (PRFileDesc *) NULL ) {
  191. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  192. "SSL listener socket not found.\n" );
  193. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  194. "SSL listener socket not found.", 0, NULL );
  195. goto unlock_and_return;
  196. }
  197. newsocket = slapd_ssl_importFD( ssl_listensocket, oldsocket );
  198. if ( newsocket == (PRFileDesc *) NULL ) {
  199. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  200. "SSL socket import failed.\n" );
  201. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  202. "SSL socket import failed.", 0, NULL );
  203. goto unlock_and_return;
  204. }
  205. } else {
  206. if ( slapd_ssl_init2( &oldsocket, 1 ) != 0 ) {
  207. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  208. "SSL socket import or configuration failed.\n" );
  209. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  210. "SSL socket import or configuration failed.", 0, NULL );
  211. goto unlock_and_return;
  212. }
  213. newsocket = oldsocket;
  214. }
  215. rv = slapd_ssl_resetHandshake( newsocket, 1 );
  216. if ( rv != SECSuccess ) {
  217. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  218. "Unable to set socket ready for SSL handshake.\n" );
  219. slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
  220. "Unable to set socket ready for SSL handshake.", 0, NULL );
  221. goto unlock_and_return;
  222. }
  223. /* From here on, messages will be sent through the SSL layer, so we need to get our
  224. * connection ready. */
  225. secure = 1;
  226. ns = configure_pr_socket( &newsocket, secure, 0 /*never local*/ );
  227. /*
  228. ber_sockbuf_set_option( conn->c_sb, LBER_SOCKBUF_OPT_DESC, &newsocket );
  229. ber_sockbuf_set_option( conn->c_sb, LBER_SOCKBUF_OPT_READ_FN, (void *)secure_read_function );
  230. ber_sockbuf_set_option( conn->c_sb, LBER_SOCKBUF_OPT_WRITE_FN, (void *)secure_write_function );
  231. */
  232. /*changed to */
  233. {
  234. struct lber_x_ext_io_fns *func_pointers = malloc(LBER_X_EXTIO_FNS_SIZE);
  235. func_pointers->lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
  236. func_pointers->lbextiofn_read = secure_read_function;
  237. func_pointers->lbextiofn_write = secure_write_function;
  238. func_pointers->lbextiofn_writev = NULL;
  239. func_pointers->lbextiofn_socket_arg = (struct lextiof_socket_private *) newsocket;
  240. ber_sockbuf_set_option( conn->c_sb,
  241. LBER_SOCKBUF_OPT_EXT_IO_FNS, func_pointers);
  242. free(func_pointers);
  243. }
  244. conn->c_flags |= CONN_FLAG_SSL;
  245. conn->c_flags |= CONN_FLAG_START_TLS;
  246. conn->c_sd = ns;
  247. conn->c_prfd = newsocket;
  248. rv = slapd_ssl_handshakeCallback (conn->c_prfd, (void *)handle_handshake_done, conn);
  249. if ( rv < 0 ) {
  250. PRErrorCode prerr = PR_GetError();
  251. slapi_log_error( SLAPI_LOG_FATAL, "start_tls",
  252. "SSL_HandshakeCallback() %d " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  253. rv, prerr, slapd_pr_strerror( prerr ) );
  254. }
  255. if ( config_get_SSLclientAuth() != SLAPD_SSLCLIENTAUTH_OFF ) {
  256. rv = slapd_ssl_badCertHook (conn->c_prfd, (void *)handle_bad_certificate, conn);
  257. if ( rv < 0 ) {
  258. PRErrorCode prerr = PR_GetError();
  259. slapi_log_error( SLAPI_LOG_FATAL, "start_tls",
  260. "SSL_BadCertHook(%i) %i " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  261. conn->c_sd, rv, prerr, slapd_pr_strerror( prerr ) );
  262. }
  263. }
  264. /* Once agreed in starting TLS, the handshake must be carried out. */
  265. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  266. "Starting SSL Handshake.\n" );
  267. unlock_and_return:
  268. PR_Unlock( conn->c_mutex );
  269. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  270. }/* start_tls */
  271. /* TLS Graceful Closure function.
  272. * The function below kind of "resets" the connection to its state previous
  273. * to receiving the Start TLS operation request. But it also sets the
  274. * authorization and authentication credentials to "anonymous". Finally,
  275. * it sends a closure alert message to the client.
  276. *
  277. * Note: start_tls_graceful_closure() must be called with c->c_mutex locked.
  278. */
  279. int
  280. start_tls_graceful_closure( Connection *c, Slapi_PBlock * pb, int is_initiator )
  281. {
  282. int ns;
  283. Slapi_PBlock *pblock = pb;
  284. struct slapdplugin *plugin;
  285. int secure = 0;
  286. PRFileDesc *ssl_fd;
  287. if ( pblock == NULL ) {
  288. pblock = slapi_pblock_new();
  289. plugin = (struct slapdplugin *) slapi_ch_calloc( 1, sizeof( struct slapdplugin ) );
  290. pblock->pb_plugin = plugin;
  291. pblock->pb_conn = c;
  292. pblock->pb_op = c->c_ops;
  293. set_db_default_result_handlers( pblock );
  294. if ( slapi_pblock_set( pblock, SLAPI_EXT_OP_RET_OID, START_TLS_OID ) != 0 ) {
  295. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  296. "Could not set extended response oid.\n" );
  297. slapi_send_ldap_result( pblock, LDAP_OPERATIONS_ERROR, NULL,
  298. "Could not set extended response oid.", 0, NULL );
  299. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  300. }
  301. slapi_ch_free( (void **) &plugin );
  302. }
  303. /* First thing to do is to finish with whatever operation may be hanging on the
  304. * encrypted session.
  305. */
  306. while ( connection_operations_pending( c, pblock->pb_op,
  307. 0 /* wait for all other ops to full complete */ )) {
  308. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  309. "Still %d operations to be completed before closing the SSL connection.\n",
  310. c->c_refcnt - 1 );
  311. }
  312. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_graceful_closure", "SSL_CLOSE_NOTIFY_ALERT\n" );
  313. /* An SSL close_notify alert should be sent to the client. However, the NSS API
  314. * doesn't provide us with anything alike.
  315. */
  316. slapi_send_ldap_result( pblock, LDAP_OPERATIONS_ERROR, NULL,
  317. "SSL_CLOSE_NOTIFY_ALERT", 0, NULL );
  318. if ( is_initiator ) {
  319. /* if this call belongs to the initiator of the SSL connection closure, it must first
  320. * wait for the peer to send another close_notify alert back.
  321. */
  322. }
  323. PR_Lock( c->c_mutex );
  324. /* "Unimport" the socket from SSL, i.e. get rid of the upper layer of the
  325. * file descriptor stack, which represents SSL.
  326. * The ssl socket assigned to c->c_prfd should also be closed and destroyed.
  327. * Should find a way of getting that ssl socket.
  328. */
  329. /*
  330. rc = strcasecmp( "SSL", PR_GetNameForIdentity( c->c_prfd->identity ) );
  331. if ( rc == 0 ) {
  332. sslSocket * ssl_socket;
  333. ssl_socket = (sslSocket *) c->c_prfd->secret;
  334. ssl_socket->fd = NULL;
  335. }
  336. */
  337. ssl_fd = PR_PopIOLayer( c->c_prfd, PR_TOP_IO_LAYER );
  338. ssl_fd->dtor( ssl_fd );
  339. #ifndef _WIN32
  340. secure = 0;
  341. ns = configure_pr_socket( &(c->c_prfd), secure, 0 /*never local*/ );
  342. ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_DESC, &(c->c_prfd) );
  343. #else
  344. ns = PR_FileDesc2NativeHandle( c->c_prfd );
  345. c->c_prfd = NULL;
  346. configure_ns_socket( &ns );
  347. ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_DESC, &ns );
  348. #endif
  349. c->c_sd = ns;
  350. c->c_flags &= ~CONN_FLAG_SSL;
  351. c->c_flags &= ~CONN_FLAG_START_TLS;
  352. ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_READ_FN, (void *)read_function );
  353. ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_WRITE_FN, (void *)write_function );
  354. /* authentication & authorization credentials must be set to "anonymous". */
  355. bind_credentials_clear( c, PR_FALSE, PR_TRUE );
  356. PR_Unlock( c->c_mutex );
  357. return ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  358. }
  359. static char *start_tls_oid_list[] = {
  360. START_TLS_OID,
  361. NULL
  362. };
  363. static char *start_tls_name_list[] = {
  364. "startTLS",
  365. NULL
  366. };
  367. int start_tls_register_plugin()
  368. {
  369. slapi_register_plugin( "extendedop", 1 /* Enabled */, "start_tls_init",
  370. start_tls_init, "Start TLS extended operation",
  371. start_tls_oid_list, NULL );
  372. return 0;
  373. }
  374. /* Initialization function */
  375. int start_tls_init( Slapi_PBlock *pb )
  376. {
  377. char **argv;
  378. char *oid;
  379. /* Get the arguments appended to the plugin extendedop directive. The first argument
  380. * (after the standard arguments for the directive) should contain the OID of the
  381. * extended operation.
  382. */
  383. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
  384. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init", "Could not get argv\n" );
  385. return( -1 );
  386. }
  387. /* Compare the OID specified in the configuration file against the Start TLS OID. */
  388. if ( argv == NULL || strcmp( argv[0], START_TLS_OID ) != 0 ) {
  389. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
  390. "OID is missing or is not %s\n", START_TLS_OID );
  391. return( -1 );
  392. } else {
  393. oid = slapi_ch_strdup( argv[0] );
  394. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
  395. "Registering plug-in for Start TLS extended op %s.\n", oid );
  396. }
  397. /* Register the plug-in function as an extended operation
  398. * plug-in function that handles the operation identified by
  399. * OID 1.3.6.1.4.1.1466.20037. Also specify the version of the server
  400. * plug-in */
  401. if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  402. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&exopdesc ) != 0 ||
  403. slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *) start_tls ) != 0 ||
  404. slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, start_tls_oid_list ) != 0 ||
  405. slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, start_tls_name_list ) != 0 ) {
  406. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
  407. "Failed to set plug-in version, function, and OID.\n" );
  408. return( -1 );
  409. }
  410. return( 0 );
  411. }