auth.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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. #include <stdlib.h> /* getenv */
  13. #include <string.h> /* memcpy */
  14. #include <ldaputil/ldaputil.h> /* LDAPU_SUCCESS, ldapu_VTable_set */
  15. #include <ldaputil/init.h> /* ldaputil_init */
  16. #include <ldaputil/certmap.h> /* ldapu_cert_to_ldap_entry */
  17. #include <sys/param.h> /* MAXPATHLEN */
  18. #include "slap.h" /* slapi_ch_malloc */
  19. #include "fe.h"
  20. char* client_auth_config_file = NULL;
  21. /* forward declarations */
  22. static void generate_id();
  23. static Slapi_ComponentId * auth_get_component_id();
  24. #define internal_ld NULL
  25. static int LDAP_CALL LDAP_CALLBACK
  26. slapu_msgfree( LDAP* ld, LDAPMessage* msg )
  27. {
  28. Slapi_PBlock* pb = (Slapi_PBlock*)msg;
  29. if (ld != internal_ld) {
  30. return ldap_msgfree (msg);
  31. }
  32. if (pb) {
  33. slapi_free_search_results_internal (pb);
  34. slapi_pblock_destroy (pb);
  35. }
  36. return LDAP_SUCCESS;
  37. }
  38. static int LDAP_CALL LDAP_CALLBACK
  39. slapu_search_s( LDAP* ld, const char* rawbaseDN, int scope, const char* filter,
  40. char** attrs, int attrsonly, LDAPMessage** result )
  41. {
  42. int err = LDAP_NO_SUCH_OBJECT;
  43. Slapi_PBlock* pb = NULL;
  44. LDAPControl **ctrls;
  45. Slapi_DN *sdn = slapi_sdn_new_dn_byval(rawbaseDN);
  46. const char *baseDN = slapi_sdn_get_dn(sdn);
  47. if (ld != internal_ld) {
  48. err = ldap_search_ext_s(ld, baseDN, scope, filter, attrs, attrsonly,
  49. NULL, NULL, NULL, -1, result);
  50. slapi_sdn_free(&sdn);
  51. return err;
  52. }
  53. LDAPDebug (LDAP_DEBUG_TRACE, "=> slapu_search_s (\"%s\", %i, %s)\n",
  54. baseDN, scope, filter);
  55. if (filter == NULL) filter = "objectclass=*";
  56. /* use new internal search API */
  57. pb=slapi_pblock_new();
  58. /* we need to provide managedsait control to avoid returning continuation references */
  59. ctrls = (LDAPControl **)slapi_ch_calloc (2, sizeof (LDAPControl *));
  60. ctrls[0] = (LDAPControl*)slapi_ch_malloc (sizeof (LDAPControl));
  61. ctrls[0]->ldctl_oid = slapi_ch_strdup (LDAP_CONTROL_MANAGEDSAIT);
  62. ctrls[0]->ldctl_value.bv_val = NULL;
  63. ctrls[0]->ldctl_value.bv_len = 0;
  64. ctrls[0]->ldctl_iscritical = '\0';
  65. slapi_search_internal_set_pb(pb, baseDN, scope, (char *)filter, attrs,
  66. attrsonly, ctrls, NULL,
  67. auth_get_component_id(), 0 /* actions */);
  68. slapi_search_internal_pb(pb);
  69. if (pb != NULL) {
  70. if (slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &err)) {
  71. err = LDAP_LOCAL_ERROR;
  72. }
  73. if (err != LDAP_SUCCESS) {
  74. slapu_msgfree (ld, (LDAPMessage*)pb);
  75. pb = NULL;
  76. if (scope == LDAP_SCOPE_SUBTREE) {
  77. char fbuf[ BUFSIZ ];
  78. LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", subtree, %s) err %i\n",
  79. baseDN, escape_string( (char*)filter, fbuf ), err);
  80. }
  81. }
  82. } else {
  83. char fbuf[ BUFSIZ ];
  84. LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", %i, %s) NULL\n",
  85. baseDN, scope, escape_string( (char*)filter, fbuf ));
  86. }
  87. slapi_sdn_free(&sdn);
  88. *result = (LDAPMessage*)pb;
  89. LDAPDebug (LDAP_DEBUG_TRACE, "<= slapu_search_s %i\n", err, 0, 0);
  90. return err;
  91. }
  92. static int LDAP_CALL LDAP_CALLBACK
  93. slapu_count_entries( LDAP* ld, LDAPMessage* msg )
  94. {
  95. Slapi_Entry** entry = NULL;
  96. int count = 0;
  97. if (ld != internal_ld) {
  98. return ldap_count_entries (ld, msg);
  99. }
  100. if (!slapi_pblock_get ((Slapi_PBlock*)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry)
  101. && entry) {
  102. for (; *entry; ++entry) ++count;
  103. }
  104. return count;
  105. }
  106. /* slapu_search_s() returns a Slapi_PBlock*, but slapu_first_entry() and
  107. * slapu_next_entry() return a Slapi_Entry** pointing into the same array
  108. * as the PBlock. If one of the iteration (Slapi_Entry**) pointers was
  109. * passed to slapu_msgfree(), havoc would ensue. ldaputil never does this.
  110. * But ldap_msgfree() would support it (no?); so a plugin function might.
  111. * Yet another way this doesn't support plugin functions.
  112. */
  113. static LDAPMessage* LDAP_CALL LDAP_CALLBACK
  114. slapu_first_entry( LDAP* ld, LDAPMessage* msg )
  115. {
  116. Slapi_Entry** entry = NULL;
  117. if (ld != internal_ld) {
  118. return ldap_first_entry (ld, msg);
  119. }
  120. if (!slapi_pblock_get ((Slapi_PBlock*)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry)
  121. && entry && *entry) {
  122. return (LDAPMessage*)entry;
  123. }
  124. return NULL;
  125. }
  126. static LDAPMessage* LDAP_CALL LDAP_CALLBACK
  127. slapu_next_entry( LDAP* ld, LDAPMessage* msg )
  128. {
  129. Slapi_Entry** entry = (Slapi_Entry**)msg;
  130. if (ld != internal_ld) {
  131. if (msg) {
  132. return ldap_next_entry (ld, msg);
  133. } else {
  134. return NULL;
  135. }
  136. }
  137. if (entry && *entry && *++entry) {
  138. return (LDAPMessage*)entry;
  139. }
  140. return NULL;
  141. }
  142. static char* LDAP_CALL LDAP_CALLBACK
  143. slapu_get_dn( LDAP* ld, LDAPMessage* entry )
  144. {
  145. if (ld != internal_ld) {
  146. return ldap_get_dn (ld, entry);
  147. }
  148. return slapi_ch_strdup (slapi_entry_get_dn (*(Slapi_Entry**)entry));
  149. }
  150. static void LDAP_CALL LDAP_CALLBACK
  151. slapu_memfree( LDAP* ld, void* dn )
  152. {
  153. if (ld != internal_ld) {
  154. ldap_memfree (dn);
  155. } else {
  156. free (dn);
  157. }
  158. }
  159. static char*
  160. slapu_attr_get_desc( Slapi_Attr *attr )
  161. {
  162. char* desc = NULL;
  163. if (slapi_attr_get_type (attr, &desc) == LDAP_SUCCESS && desc) {
  164. return slapi_ch_strdup (desc);
  165. }
  166. return NULL;
  167. }
  168. /* slapu_first_attribute and slapu_next_attribute use a Slapi_Attr*
  169. * as an iterator. It is malloc'd by first() and free'd by ber_free().
  170. */
  171. static char* LDAP_CALL LDAP_CALLBACK
  172. slapu_first_attribute( LDAP* ld, LDAPMessage* entry, BerElement** iter )
  173. {
  174. if (ld != internal_ld) {
  175. return ldap_first_attribute (ld, entry, iter);
  176. } else {
  177. Slapi_Attr** attr = (Slapi_Attr**) slapi_ch_malloc (sizeof(Slapi_Attr*));
  178. *iter = (BerElement*) attr;
  179. if (attr && slapi_entry_first_attr (*(Slapi_Entry**)entry, attr) == LDAP_SUCCESS) {
  180. return slapu_attr_get_desc (*attr);
  181. }
  182. }
  183. return NULL;
  184. }
  185. static char* LDAP_CALL LDAP_CALLBACK
  186. slapu_next_attribute( LDAP* ld, LDAPMessage* entry, BerElement* iter)
  187. {
  188. Slapi_Attr** attr = (Slapi_Attr**)iter;
  189. if (ld != internal_ld) {
  190. return ldap_next_attribute (ld, entry, iter);
  191. }
  192. if (attr && slapi_entry_next_attr (*(Slapi_Entry**)entry, *attr, attr) == LDAP_SUCCESS) {
  193. return slapu_attr_get_desc (*attr);
  194. }
  195. return NULL;
  196. }
  197. static void LDAP_CALL LDAP_CALLBACK
  198. slapu_ber_free( LDAP* ld, BerElement* iter, int freebuf )
  199. {
  200. if (ld != internal_ld) {
  201. ber_free (iter, freebuf);
  202. } else {
  203. free ((Slapi_Attr**)iter);
  204. }
  205. }
  206. static struct berval** LDAP_CALL LDAP_CALLBACK
  207. slapu_get_values_len( LDAP *ld, LDAPMessage *entry, const char *desc )
  208. {
  209. Slapi_Attr* attr = NULL;
  210. if (ld != internal_ld) {
  211. return ldap_get_values_len (ld, entry, desc);
  212. }
  213. if (slapi_entry_attr_find (*(Slapi_Entry**)entry, desc, &attr) == LDAP_SUCCESS
  214. && attr) {
  215. struct berval** values = NULL;
  216. if ( slapi_attr_get_bervals_copy (attr, &values) == 0 ) {
  217. return (values);
  218. }
  219. }
  220. return NULL;
  221. }
  222. static void LDAP_CALL LDAP_CALLBACK
  223. slapu_value_free_len( LDAP* ld, struct berval **values )
  224. {
  225. if (ld != internal_ld) {
  226. ldap_value_free_len (values);
  227. } else {
  228. ber_bvecfree (values);
  229. }
  230. }
  231. void
  232. client_auth_init ()
  233. {
  234. int err;
  235. if (client_auth_config_file == NULL) {
  236. char *confdir = config_get_configdir();
  237. if (NULL == confdir) {
  238. LDAPDebug (LDAP_DEBUG_ANY,
  239. "client_auth_init: failed to get configdir\n",
  240. 0, 0, 0);
  241. return;
  242. }
  243. client_auth_config_file = PR_smprintf("%s/certmap.conf", confdir);
  244. if (NULL == client_auth_config_file) {
  245. LDAPDebug (LDAP_DEBUG_ANY,
  246. "client_auth_init: failed to duplicate \"%s/certmap\"\n",
  247. confdir, 0, 0);
  248. slapi_ch_free_string(&confdir);
  249. return;
  250. }
  251. slapi_ch_free_string(&confdir);
  252. }
  253. err = ldaputil_init (client_auth_config_file, "", NULL, "slapd", NULL);
  254. if (err != LDAPU_SUCCESS) {
  255. LDAPDebug (LDAP_DEBUG_TRACE, "ldaputil_init(%s,...) %i\n",
  256. client_auth_config_file, err, 0);
  257. } else {
  258. LDAPUVTable_t vtable = {
  259. NULL /* ssl_init */,
  260. NULL /* set_option */,
  261. NULL /* simple_bind_s */,
  262. NULL /* unbind */,
  263. slapu_search_s,
  264. slapu_count_entries,
  265. slapu_first_entry,
  266. slapu_next_entry,
  267. slapu_msgfree,
  268. slapu_get_dn,
  269. slapu_memfree,
  270. slapu_first_attribute,
  271. slapu_next_attribute,
  272. slapu_ber_free,
  273. NULL /* get_values */,
  274. NULL /* value_free */,
  275. slapu_get_values_len,
  276. slapu_value_free_len};
  277. ldapu_VTable_set (&vtable);
  278. }
  279. /* Generate a component id for cert-based authentication */
  280. generate_id();
  281. }
  282. #include <ssl.h>
  283. #include "slapi-plugin.h" /* SLAPI_BERVAL_EQ */
  284. #include "slapi-private.h" /* COMPONENT_CERT_AUTH */
  285. static Slapi_ComponentId * auth_component_id=NULL;
  286. static void generate_id()
  287. {
  288. if (auth_component_id == NULL ) {
  289. auth_component_id=generate_componentid (NULL /* Not a plugin */ , COMPONENT_CERT_AUTH);
  290. }
  291. }
  292. static Slapi_ComponentId * auth_get_component_id() {
  293. return auth_component_id;
  294. }
  295. static char*
  296. subject_of (CERTCertificate* cert)
  297. {
  298. char* dn = NULL;
  299. if (cert != NULL) {
  300. int err = ldapu_get_cert_subject_dn (cert, &dn);
  301. if (err != LDAPU_SUCCESS) {
  302. LDAPDebug (LDAP_DEBUG_ANY, "ldapu_get_cert_subject_dn(%p) %i (%s)\n",
  303. (void*)cert, err, ldapu_err2string (err));
  304. }
  305. }
  306. return dn;
  307. }
  308. static char*
  309. issuer_of (CERTCertificate* cert)
  310. {
  311. char* dn = NULL;
  312. if (cert != NULL) {
  313. int err = ldapu_get_cert_issuer_dn (cert, &dn);
  314. if (err != LDAPU_SUCCESS) {
  315. LDAPDebug (LDAP_DEBUG_ANY, "ldapu_get_cert_issuer_dn(%p) %i (%s)\n",
  316. (void*)cert, err, ldapu_err2string (err));
  317. }
  318. }
  319. return dn;
  320. }
  321. /*
  322. * Log a certificate that was rejected because the client didn't
  323. * authenticate it.
  324. *
  325. * Note: handle_bad_certificate() is called via slapd_ssl_badCertHook().
  326. * A Connection * is passed in client data. That connection must have its
  327. * c_mutex locked.
  328. */
  329. int
  330. handle_bad_certificate (void* clientData, PRFileDesc *prfd)
  331. {
  332. char sbuf[ BUFSIZ ], ibuf[ BUFSIZ ];
  333. Connection* conn = (Connection*) clientData;
  334. CERTCertificate* clientCert = slapd_ssl_peerCertificate (prfd);
  335. PRErrorCode errorCode = PR_GetError();
  336. char* subject = subject_of (clientCert);
  337. char* issuer = issuer_of (clientCert);
  338. slapi_log_access( LDAP_DEBUG_STATS,
  339. "conn=%" NSPRIu64 " " SLAPI_COMPONENT_NAME_NSPR " error %i (%s); unauthenticated client %s; issuer %s\n",
  340. conn->c_connid, errorCode, slapd_pr_strerror(errorCode),
  341. subject ? escape_string( subject, sbuf ) : "NULL",
  342. issuer ? escape_string( issuer, ibuf ) : "NULL" );
  343. if (issuer) free (issuer);
  344. if (subject) free (subject);
  345. if (clientCert) CERT_DestroyCertificate (clientCert);
  346. return -1; /* non-zero means reject this certificate */
  347. }
  348. /*
  349. * Get an identity from the client's certificate (if any was sent).
  350. *
  351. * Note: handle_handshake_done() is called via slapd_ssl_handshakeCallback().
  352. * A Connection * is passed in client data. That connection must have its
  353. * c_mutex locked.
  354. */
  355. void
  356. handle_handshake_done (PRFileDesc *prfd, void* clientData)
  357. {
  358. Connection* conn = (Connection*) clientData;
  359. CERTCertificate* clientCert = slapd_ssl_peerCertificate(prfd);
  360. char* clientDN = NULL;
  361. int keySize = 0;
  362. char* cipher = NULL;
  363. char* extraErrorMsg = "";
  364. SSLChannelInfo channelInfo;
  365. SSLCipherSuiteInfo cipherInfo;
  366. char* subject = NULL;
  367. char sslversion[64];
  368. if ( (slapd_ssl_getChannelInfo (prfd, &channelInfo, sizeof(channelInfo))) != SECSuccess ) {
  369. PRErrorCode errorCode = PR_GetError();
  370. slapi_log_access (LDAP_DEBUG_STATS,
  371. "conn=%" NSPRIu64 " SSL failed to obtain channel info; "
  372. SLAPI_COMPONENT_NAME_NSPR " error %i (%s)\n",
  373. conn->c_connid, errorCode, slapd_pr_strerror(errorCode));
  374. goto done;
  375. }
  376. if ( (slapd_ssl_getCipherSuiteInfo (channelInfo.cipherSuite, &cipherInfo, sizeof(cipherInfo)) )
  377. != SECSuccess) {
  378. PRErrorCode errorCode = PR_GetError();
  379. slapi_log_access (LDAP_DEBUG_STATS,
  380. "conn=%" NSPRIu64 " SSL failed to obtain cipher info; "
  381. SLAPI_COMPONENT_NAME_NSPR " error %i (%s)\n",
  382. conn->c_connid, errorCode, slapd_pr_strerror(errorCode));
  383. goto done;
  384. }
  385. keySize = cipherInfo.effectiveKeyBits;
  386. cipher = slapi_ch_strdup(cipherInfo.symCipherName);
  387. /* If inside an Start TLS operation, perform the privacy level discovery
  388. * and if the security degree achieved after the handshake is not reckoned
  389. * to be enough, close the SSL connection. */
  390. if ( conn->c_flags & CONN_FLAG_START_TLS ) {
  391. if ( cipherInfo.symKeyBits == 0 ) {
  392. start_tls_graceful_closure( conn, NULL, 1 );
  393. goto done;
  394. }
  395. }
  396. if (config_get_SSLclientAuth() == SLAPD_SSLCLIENTAUTH_OFF ) {
  397. (void) slapi_getSSLVersion_str(channelInfo.protocolVersion, sslversion, sizeof(sslversion));
  398. slapi_log_access (LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " %s %i-bit %s\n",
  399. conn->c_connid,
  400. sslversion, keySize, cipher ? cipher : "NULL" );
  401. goto done;
  402. }
  403. if (clientCert == NULL) {
  404. (void) slapi_getSSLVersion_str(channelInfo.protocolVersion, sslversion, sizeof(sslversion));
  405. slapi_log_access (LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " %s %i-bit %s\n",
  406. conn->c_connid,
  407. sslversion, keySize, cipher ? cipher : "NULL" );
  408. } else {
  409. subject = subject_of (clientCert);
  410. if (!subject) {
  411. (void) slapi_getSSLVersion_str(channelInfo.protocolVersion,
  412. sslversion, sizeof(sslversion));
  413. slapi_log_access( LDAP_DEBUG_STATS,
  414. "conn=%" NSPRIu64 " %s %i-bit %s; missing subject\n",
  415. conn->c_connid,
  416. sslversion, keySize, cipher ? cipher : "NULL");
  417. goto done;
  418. }
  419. {
  420. char* issuer = issuer_of (clientCert);
  421. char sbuf[ BUFSIZ ], ibuf[ BUFSIZ ];
  422. (void) slapi_getSSLVersion_str(channelInfo.protocolVersion,
  423. sslversion, sizeof(sslversion));
  424. slapi_log_access( LDAP_DEBUG_STATS,
  425. "conn=%" NSPRIu64 " %s %i-bit %s; client %s; issuer %s\n",
  426. conn->c_connid,
  427. sslversion, keySize, cipher ? cipher : "NULL",
  428. subject ? escape_string( subject, sbuf ) : "NULL",
  429. issuer ? escape_string( issuer, ibuf ) : "NULL");
  430. if (issuer) free (issuer);
  431. }
  432. slapi_dn_normalize (subject);
  433. {
  434. LDAPMessage* chain = NULL;
  435. char *basedn = config_get_basedn();
  436. int err;
  437. err = ldapu_cert_to_ldap_entry
  438. (clientCert, internal_ld, basedn?basedn:""/*baseDN*/, &chain);
  439. if (err == LDAPU_SUCCESS && chain) {
  440. LDAPMessage* entry = slapu_first_entry (internal_ld, chain);
  441. if (entry) {
  442. /* clientDN is duplicated in slapu_get_dn */
  443. clientDN = slapu_get_dn (internal_ld, entry);
  444. } else {
  445. extraErrorMsg = "no entry";
  446. LDAPDebug (LDAP_DEBUG_TRACE, "<= ldapu_cert_to_ldap_entry() %s\n",
  447. extraErrorMsg, 0, 0);
  448. }
  449. } else {
  450. extraErrorMsg = ldapu_err2string(err);
  451. LDAPDebug (LDAP_DEBUG_TRACE, "<= ldapu_cert_to_ldap_entry() %i (%s)%s\n",
  452. err, extraErrorMsg, chain ? "" : " NULL");
  453. }
  454. slapi_ch_free_string(&basedn);
  455. slapu_msgfree (internal_ld, chain);
  456. }
  457. }
  458. if (clientDN != NULL) {
  459. Slapi_DN *sdn = NULL;
  460. sdn = slapi_sdn_new_dn_passin(clientDN);
  461. clientDN = slapi_ch_strdup(slapi_sdn_get_dn(sdn));
  462. slapi_sdn_free(&sdn);
  463. (void) slapi_getSSLVersion_str(channelInfo.protocolVersion,
  464. sslversion, sizeof(sslversion));
  465. slapi_log_access (LDAP_DEBUG_STATS,
  466. "conn=%" NSPRIu64 " %s client bound as %s\n",
  467. conn->c_connid,
  468. sslversion, clientDN);
  469. } else if (clientCert != NULL) {
  470. (void) slapi_getSSLVersion_str(channelInfo.protocolVersion,
  471. sslversion, sizeof(sslversion));
  472. slapi_log_access (LDAP_DEBUG_STATS,
  473. "conn=%" NSPRIu64 " %s failed to map client "
  474. "certificate to LDAP DN (%s)\n",
  475. conn->c_connid,
  476. sslversion, extraErrorMsg);
  477. }
  478. /*
  479. * Associate the new credentials with the connection. Note that
  480. * clientDN and clientCert may be NULL.
  481. */
  482. bind_credentials_set_nolock( conn, SLAPD_AUTH_SSL, clientDN,
  483. SLAPD_AUTH_SSL, clientDN, clientCert , NULL);
  484. done:
  485. slapi_ch_free_string(&subject);
  486. slapi_ch_free_string(&cipher);
  487. /* clientDN and clientCert will be freed later */
  488. }