start_tls_extop.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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. /*changed to */
  228. {
  229. struct lber_x_ext_io_fns func_pointers;
  230. memset(&func_pointers, 0, sizeof(func_pointers));
  231. func_pointers.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
  232. func_pointers.lbextiofn_read = secure_read_function;
  233. func_pointers.lbextiofn_write = secure_write_function;
  234. func_pointers.lbextiofn_writev = NULL;
  235. func_pointers.lbextiofn_socket_arg = (struct lextiof_socket_private *) newsocket;
  236. ber_sockbuf_set_option( conn->c_sb,
  237. LBER_SOCKBUF_OPT_EXT_IO_FNS, &func_pointers);
  238. }
  239. conn->c_flags |= CONN_FLAG_SSL;
  240. conn->c_flags |= CONN_FLAG_START_TLS;
  241. conn->c_sd = ns;
  242. conn->c_prfd = newsocket;
  243. rv = slapd_ssl_handshakeCallback (conn->c_prfd, (void *)handle_handshake_done, conn);
  244. if ( rv < 0 ) {
  245. PRErrorCode prerr = PR_GetError();
  246. slapi_log_error( SLAPI_LOG_FATAL, "start_tls",
  247. "SSL_HandshakeCallback() %d " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  248. rv, prerr, slapd_pr_strerror( prerr ) );
  249. }
  250. if ( config_get_SSLclientAuth() != SLAPD_SSLCLIENTAUTH_OFF ) {
  251. rv = slapd_ssl_badCertHook (conn->c_prfd, (void *)handle_bad_certificate, conn);
  252. if ( rv < 0 ) {
  253. PRErrorCode prerr = PR_GetError();
  254. slapi_log_error( SLAPI_LOG_FATAL, "start_tls",
  255. "SSL_BadCertHook(%i) %i " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
  256. conn->c_sd, rv, prerr, slapd_pr_strerror( prerr ) );
  257. }
  258. }
  259. /* Once agreed in starting TLS, the handshake must be carried out. */
  260. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  261. "Starting SSL Handshake.\n" );
  262. unlock_and_return:
  263. PR_Unlock( conn->c_mutex );
  264. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  265. }/* start_tls */
  266. /* TLS Graceful Closure function.
  267. * The function below kind of "resets" the connection to its state previous
  268. * to receiving the Start TLS operation request. But it also sets the
  269. * authorization and authentication credentials to "anonymous". Finally,
  270. * it sends a closure alert message to the client.
  271. *
  272. * Note: start_tls_graceful_closure() must be called with c->c_mutex locked.
  273. */
  274. int
  275. start_tls_graceful_closure( Connection *c, Slapi_PBlock * pb, int is_initiator )
  276. {
  277. int ns;
  278. Slapi_PBlock *pblock = pb;
  279. struct slapdplugin *plugin;
  280. int secure = 0;
  281. PRFileDesc *ssl_fd;
  282. if ( pblock == NULL ) {
  283. pblock = slapi_pblock_new();
  284. plugin = (struct slapdplugin *) slapi_ch_calloc( 1, sizeof( struct slapdplugin ) );
  285. pblock->pb_plugin = plugin;
  286. pblock->pb_conn = c;
  287. pblock->pb_op = c->c_ops;
  288. set_db_default_result_handlers( pblock );
  289. if ( slapi_pblock_set( pblock, SLAPI_EXT_OP_RET_OID, START_TLS_OID ) != 0 ) {
  290. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  291. "Could not set extended response oid.\n" );
  292. slapi_send_ldap_result( pblock, LDAP_OPERATIONS_ERROR, NULL,
  293. "Could not set extended response oid.", 0, NULL );
  294. return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  295. }
  296. slapi_ch_free( (void **) &plugin );
  297. }
  298. /* First thing to do is to finish with whatever operation may be hanging on the
  299. * encrypted session.
  300. */
  301. while ( connection_operations_pending( c, pblock->pb_op,
  302. 0 /* wait for all other ops to full complete */ )) {
  303. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
  304. "Still %d operations to be completed before closing the SSL connection.\n",
  305. c->c_refcnt - 1 );
  306. }
  307. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_graceful_closure", "SSL_CLOSE_NOTIFY_ALERT\n" );
  308. /* An SSL close_notify alert should be sent to the client. However, the NSS API
  309. * doesn't provide us with anything alike.
  310. */
  311. slapi_send_ldap_result( pblock, LDAP_OPERATIONS_ERROR, NULL,
  312. "SSL_CLOSE_NOTIFY_ALERT", 0, NULL );
  313. if ( is_initiator ) {
  314. /* if this call belongs to the initiator of the SSL connection closure, it must first
  315. * wait for the peer to send another close_notify alert back.
  316. */
  317. }
  318. PR_Lock( c->c_mutex );
  319. /* "Unimport" the socket from SSL, i.e. get rid of the upper layer of the
  320. * file descriptor stack, which represents SSL.
  321. * The ssl socket assigned to c->c_prfd should also be closed and destroyed.
  322. * Should find a way of getting that ssl socket.
  323. */
  324. /*
  325. rc = strcasecmp( "SSL", PR_GetNameForIdentity( c->c_prfd->identity ) );
  326. if ( rc == 0 ) {
  327. sslSocket * ssl_socket;
  328. ssl_socket = (sslSocket *) c->c_prfd->secret;
  329. ssl_socket->fd = NULL;
  330. }
  331. */
  332. ssl_fd = PR_PopIOLayer( c->c_prfd, PR_TOP_IO_LAYER );
  333. ssl_fd->dtor( ssl_fd );
  334. #ifndef _WIN32
  335. secure = 0;
  336. ns = configure_pr_socket( &(c->c_prfd), secure, 0 /*never local*/ );
  337. #else
  338. ns = PR_FileDesc2NativeHandle( c->c_prfd );
  339. c->c_prfd = NULL;
  340. configure_ns_socket( &ns );
  341. #endif
  342. c->c_sd = ns;
  343. c->c_flags &= ~CONN_FLAG_SSL;
  344. c->c_flags &= ~CONN_FLAG_START_TLS;
  345. /* authentication & authorization credentials must be set to "anonymous". */
  346. bind_credentials_clear( c, PR_FALSE, PR_TRUE );
  347. PR_Unlock( c->c_mutex );
  348. return ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
  349. }
  350. static char *start_tls_oid_list[] = {
  351. START_TLS_OID,
  352. NULL
  353. };
  354. static char *start_tls_name_list[] = {
  355. "startTLS",
  356. NULL
  357. };
  358. int start_tls_register_plugin()
  359. {
  360. slapi_register_plugin( "extendedop", 1 /* Enabled */, "start_tls_init",
  361. start_tls_init, "Start TLS extended operation",
  362. start_tls_oid_list, NULL );
  363. return 0;
  364. }
  365. /* Initialization function */
  366. int start_tls_init( Slapi_PBlock *pb )
  367. {
  368. char **argv;
  369. char *oid;
  370. /* Get the arguments appended to the plugin extendedop directive. The first argument
  371. * (after the standard arguments for the directive) should contain the OID of the
  372. * extended operation.
  373. */
  374. if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
  375. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init", "Could not get argv\n" );
  376. return( -1 );
  377. }
  378. /* Compare the OID specified in the configuration file against the Start TLS OID. */
  379. if ( argv == NULL || strcmp( argv[0], START_TLS_OID ) != 0 ) {
  380. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
  381. "OID is missing or is not %s\n", START_TLS_OID );
  382. return( -1 );
  383. } else {
  384. oid = slapi_ch_strdup( argv[0] );
  385. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
  386. "Registering plug-in for Start TLS extended op %s.\n", oid );
  387. slapi_ch_free_string( &oid );
  388. }
  389. /* Register the plug-in function as an extended operation
  390. * plug-in function that handles the operation identified by
  391. * OID 1.3.6.1.4.1.1466.20037. Also specify the version of the server
  392. * plug-in */
  393. if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  394. slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&exopdesc ) != 0 ||
  395. slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *) start_tls ) != 0 ||
  396. slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, start_tls_oid_list ) != 0 ||
  397. slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, start_tls_name_list ) != 0 ) {
  398. slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
  399. "Failed to set plug-in version, function, and OID.\n" );
  400. return( -1 );
  401. }
  402. return( 0 );
  403. }