start_tls_extop.c 13 KB

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