| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include <stdlib.h> /* getenv */
- #include <string.h> /* memcpy */
- #include <ldaputil/ldaputil.h> /* LDAPU_SUCCESS, ldapu_VTable_set */
- #include <ldaputil/init.h> /* ldaputil_init */
- #include <ldaputil/certmap.h> /* ldapu_cert_to_ldap_entry */
- #ifndef _WIN32
- #include <sys/param.h> /* MAXPATHLEN */
- #endif
- #include "slap.h" /* slapi_ch_malloc */
- #include "fe.h"
- char* client_auth_config_file = NULL;
- /* forward declarations */
- static void generate_id();
- static Slapi_ComponentId * auth_get_component_id();
- #define internal_ld NULL
- static int LDAP_CALL LDAP_CALLBACK
- slapu_msgfree( LDAP* ld, LDAPMessage* msg )
- {
- Slapi_PBlock* pb = (Slapi_PBlock*)msg;
- if (ld != internal_ld) {
- return ldap_msgfree (msg);
- }
- if (pb) {
- slapi_free_search_results_internal (pb);
- slapi_pblock_destroy (pb);
- }
- return LDAP_SUCCESS;
- }
- static int LDAP_CALL LDAP_CALLBACK
- slapu_search_s( LDAP* ld, const char* rawbaseDN, int scope, const char* filter,
- char** attrs, int attrsonly, LDAPMessage** result )
- {
- int err = LDAP_NO_SUCH_OBJECT;
- Slapi_PBlock* pb = NULL;
- LDAPControl **ctrls;
- char *baseDN = slapi_ch_strdup(rawbaseDN);
- char *normDN = NULL;
- size_t dnlen = 0;
- err = slapi_dn_normalize_ext(baseDN, 0, &normDN, &dnlen);
- if (err < 0) {
- err = LDAP_INVALID_DN_SYNTAX;
- LDAPDebug (LDAP_DEBUG_TRACE, "<= slapu_search_s %i\n", err, 0, 0);
- return err;
- } else if (err == 0) { /* baseDN is passed in; not terminated */
- *(normDN + dnlen) = '\0';
- } else {
- slapi_ch_free_string(&baseDN);
- baseDN = normDN;
- }
- if (ld != internal_ld) {
- err = ldap_search_ext_s(ld, baseDN, scope, filter, attrs, attrsonly,
- NULL, NULL, NULL, -1, result);
- slapi_ch_free_string(&baseDN);
- return err;
- }
- LDAPDebug (LDAP_DEBUG_TRACE, "=> slapu_search_s (\"%s\", %i, %s)\n",
- baseDN, scope, filter);
- if (filter == NULL) filter = "objectclass=*";
- /* use new internal search API */
- pb=slapi_pblock_new();
- /* we need to provide managedsait control to avoid returning continuation references */
- ctrls = (LDAPControl **)slapi_ch_calloc (2, sizeof (LDAPControl *));
- ctrls[0] = (LDAPControl*)slapi_ch_malloc (sizeof (LDAPControl));
- ctrls[0]->ldctl_oid = slapi_ch_strdup (LDAP_CONTROL_MANAGEDSAIT);
- ctrls[0]->ldctl_value.bv_val = NULL;
- ctrls[0]->ldctl_value.bv_len = 0;
- ctrls[0]->ldctl_iscritical = '\0';
- slapi_search_internal_set_pb(pb, baseDN, scope, (char *)filter, attrs, attrsonly,
- ctrls, NULL, auth_get_component_id(), 0 /* actions */);
- slapi_search_internal_pb(pb);
- if (pb != NULL) {
- if (slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &err)) {
- err = LDAP_LOCAL_ERROR;
- }
- if (err != LDAP_SUCCESS) {
- slapu_msgfree (ld, (LDAPMessage*)pb);
- pb = NULL;
- if (scope == LDAP_SCOPE_SUBTREE) {
- char ebuf[ BUFSIZ ], fbuf[ BUFSIZ ];
- LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", subtree, %s) err %i\n",
- escape_string( (char*)baseDN, ebuf ), escape_string( (char*)filter, fbuf ), err);
- }
- }
- } else {
- char ebuf[ BUFSIZ ], fbuf[ BUFSIZ ];
- LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", %i, %s) NULL\n",
- escape_string( (char*)baseDN, ebuf ), scope, escape_string( (char*)filter, fbuf ));
- }
- slapi_ch_free_string(&baseDN);
- *result = (LDAPMessage*)pb;
- LDAPDebug (LDAP_DEBUG_TRACE, "<= slapu_search_s %i\n", err, 0, 0);
- return err;
- }
- static int LDAP_CALL LDAP_CALLBACK
- slapu_count_entries( LDAP* ld, LDAPMessage* msg )
- {
- Slapi_Entry** entry = NULL;
- int count = 0;
- if (ld != internal_ld) {
- return ldap_count_entries (ld, msg);
- }
- if (!slapi_pblock_get ((Slapi_PBlock*)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry)
- && entry) {
- for (; *entry; ++entry) ++count;
- }
- return count;
- }
- /* slapu_search_s() returns a Slapi_PBlock*, but slapu_first_entry() and
- * slapu_next_entry() return a Slapi_Entry** pointing into the same array
- * as the PBlock. If one of the iteration (Slapi_Entry**) pointers was
- * passed to slapu_msgfree(), havoc would ensue. ldaputil never does this.
- * But ldap_msgfree() would support it (no?); so a plugin function might.
- * Yet another way this doesn't support plugin functions.
- */
- static LDAPMessage* LDAP_CALL LDAP_CALLBACK
- slapu_first_entry( LDAP* ld, LDAPMessage* msg )
- {
- Slapi_Entry** entry = NULL;
- if (ld != internal_ld) {
- return ldap_first_entry (ld, msg);
- }
- if (!slapi_pblock_get ((Slapi_PBlock*)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry)
- && entry && *entry) {
- return (LDAPMessage*)entry;
- }
- return NULL;
- }
- static LDAPMessage* LDAP_CALL LDAP_CALLBACK
- slapu_next_entry( LDAP* ld, LDAPMessage* msg )
- {
- Slapi_Entry** entry = (Slapi_Entry**)msg;
- if (ld != internal_ld) {
- if (msg) {
- return ldap_next_entry (ld, msg);
- } else {
- return NULL;
- }
- }
- if (entry && *entry && *++entry) {
- return (LDAPMessage*)entry;
- }
- return NULL;
- }
- static char* LDAP_CALL LDAP_CALLBACK
- slapu_get_dn( LDAP* ld, LDAPMessage* entry )
- {
- if (ld != internal_ld) {
- return ldap_get_dn (ld, entry);
- }
- return slapi_ch_strdup (slapi_entry_get_dn (*(Slapi_Entry**)entry));
- }
- static void LDAP_CALL LDAP_CALLBACK
- slapu_memfree( LDAP* ld, void* dn )
- {
- if (ld != internal_ld) {
- ldap_memfree (dn);
- } else {
- free (dn);
- }
- }
- static char*
- slapu_attr_get_desc( Slapi_Attr *attr )
- {
- char* desc = NULL;
- if (slapi_attr_get_type (attr, &desc) == LDAP_SUCCESS && desc) {
- return slapi_ch_strdup (desc);
- }
- return NULL;
- }
- /* slapu_first_attribute and slapu_next_attribute use a Slapi_Attr*
- * as an iterator. It is malloc'd by first() and free'd by ber_free().
- */
- static char* LDAP_CALL LDAP_CALLBACK
- slapu_first_attribute( LDAP* ld, LDAPMessage* entry, BerElement** iter )
- {
- if (ld != internal_ld) {
- return ldap_first_attribute (ld, entry, iter);
- } else {
- Slapi_Attr** attr = (Slapi_Attr**) slapi_ch_malloc (sizeof(Slapi_Attr*));
- *iter = (BerElement*) attr;
- if (attr && slapi_entry_first_attr (*(Slapi_Entry**)entry, attr) == LDAP_SUCCESS) {
- return slapu_attr_get_desc (*attr);
- }
- }
- return NULL;
- }
- static char* LDAP_CALL LDAP_CALLBACK
- slapu_next_attribute( LDAP* ld, LDAPMessage* entry, BerElement* iter)
- {
- Slapi_Attr** attr = (Slapi_Attr**)iter;
- if (ld != internal_ld) {
- return ldap_next_attribute (ld, entry, iter);
- }
- if (attr && slapi_entry_next_attr (*(Slapi_Entry**)entry, *attr, attr) == LDAP_SUCCESS) {
- return slapu_attr_get_desc (*attr);
- }
- return NULL;
- }
- static void LDAP_CALL LDAP_CALLBACK
- slapu_ber_free( LDAP* ld, BerElement* iter, int freebuf )
- {
- if (ld != internal_ld) {
- ber_free (iter, freebuf);
- } else {
- free ((Slapi_Attr**)iter);
- }
- }
- static struct berval** LDAP_CALL LDAP_CALLBACK
- slapu_get_values_len( LDAP *ld, LDAPMessage *entry, const char *desc )
- {
- Slapi_Attr* attr = NULL;
- if (ld != internal_ld) {
- return ldap_get_values_len (ld, entry, desc);
- }
- if (slapi_entry_attr_find (*(Slapi_Entry**)entry, desc, &attr) == LDAP_SUCCESS
- && attr) {
- struct berval** values = NULL;
- if ( slapi_attr_get_bervals_copy (attr, &values) == 0 ) {
- return (values);
- }
- }
- return NULL;
- }
- static void LDAP_CALL LDAP_CALLBACK
- slapu_value_free_len( LDAP* ld, struct berval **values )
- {
- if (ld != internal_ld) {
- ldap_value_free_len (values);
- } else {
- ber_bvecfree (values);
- }
- }
- void
- client_auth_init ()
- {
- int err;
- if (client_auth_config_file == NULL) {
- char *confdir = config_get_configdir();
- if (NULL == confdir) {
- LDAPDebug (LDAP_DEBUG_ANY,
- "client_auth_init: failed to get configdir\n",
- 0, 0, 0);
- return;
- }
- client_auth_config_file = PR_smprintf("%s/certmap.conf", confdir);
- if (NULL == client_auth_config_file) {
- LDAPDebug (LDAP_DEBUG_ANY,
- "client_auth_init: failed to duplicate \"%s/certmap\"\n",
- confdir, 0, 0);
- slapi_ch_free_string(&confdir);
- return;
- }
- slapi_ch_free_string(&confdir);
- }
- err = ldaputil_init (client_auth_config_file, "", NULL, "slapd", NULL);
- if (err != LDAPU_SUCCESS) {
- LDAPDebug (LDAP_DEBUG_TRACE, "ldaputil_init(%s,...) %i\n",
- client_auth_config_file, err, 0);
- } else {
- LDAPUVTable_t vtable = {
- NULL /* ssl_init */,
- NULL /* set_option */,
- NULL /* simple_bind_s */,
- NULL /* unbind */,
- slapu_search_s,
- slapu_count_entries,
- slapu_first_entry,
- slapu_next_entry,
- slapu_msgfree,
- slapu_get_dn,
- slapu_memfree,
- slapu_first_attribute,
- slapu_next_attribute,
- slapu_ber_free,
- NULL /* get_values */,
- NULL /* value_free */,
- slapu_get_values_len,
- slapu_value_free_len};
- ldapu_VTable_set (&vtable);
- }
- /* Generate a component id for cert-based authentication */
- generate_id();
- }
- #include <ssl.h>
- #include "slapi-plugin.h" /* SLAPI_BERVAL_EQ */
- #include "slapi-private.h" /* COMPONENT_CERT_AUTH */
- static Slapi_ComponentId * auth_component_id=NULL;
- static void generate_id()
- {
- if (auth_component_id == NULL ) {
- auth_component_id=generate_componentid (NULL /* Not a plugin */ , COMPONENT_CERT_AUTH);
- }
- }
- static Slapi_ComponentId * auth_get_component_id() {
- return auth_component_id;
- }
- static char*
- subject_of (CERTCertificate* cert)
- {
- char* dn = NULL;
- if (cert != NULL) {
- int err = ldapu_get_cert_subject_dn (cert, &dn);
- if (err != LDAPU_SUCCESS) {
- LDAPDebug (LDAP_DEBUG_ANY, "ldapu_get_cert_subject_dn(%p) %i (%s)\n",
- (void*)cert, err, ldapu_err2string (err));
- }
- }
- return dn;
- }
- static char*
- issuer_of (CERTCertificate* cert)
- {
- char* dn = NULL;
- if (cert != NULL) {
- int err = ldapu_get_cert_issuer_dn (cert, &dn);
- if (err != LDAPU_SUCCESS) {
- LDAPDebug (LDAP_DEBUG_ANY, "ldapu_get_cert_issuer_dn(%p) %i (%s)\n",
- (void*)cert, err, ldapu_err2string (err));
- }
- }
- return dn;
- }
- /*
- * Log a certificate that was rejected because the client didn't
- * authenticate it.
- *
- * Note: handle_bad_certificate() is called via slapd_ssl_badCertHook().
- * A Connection * is passed in client data. That connection must have its
- * c_mutex locked.
- */
- int
- handle_bad_certificate (void* clientData, PRFileDesc *prfd)
- {
- char sbuf[ BUFSIZ ], ibuf[ BUFSIZ ];
- Connection* conn = (Connection*) clientData;
- CERTCertificate* clientCert = slapd_ssl_peerCertificate (prfd);
- PRErrorCode errorCode = PR_GetError();
- char* subject = subject_of (clientCert);
- char* issuer = issuer_of (clientCert);
- slapi_log_access( LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " " SLAPI_COMPONENT_NAME_NSPR " error %i (%s); unauthenticated client %s; issuer %s\n",
- conn->c_connid, errorCode, slapd_pr_strerror(errorCode),
- subject ? escape_string( subject, sbuf ) : "NULL",
- issuer ? escape_string( issuer, ibuf ) : "NULL" );
- if (issuer) free (issuer);
- if (subject) free (subject);
- if (clientCert) CERT_DestroyCertificate (clientCert);
- return -1; /* non-zero means reject this certificate */
- }
- /*
- * Get an identity from the client's certificate (if any was sent).
- *
- * Note: handle_handshake_done() is called via slapd_ssl_handshakeCallback().
- * A Connection * is passed in client data. That connection must have its
- * c_mutex locked.
- */
- void
- handle_handshake_done (PRFileDesc *prfd, void* clientData)
- {
- Connection* conn = (Connection*) clientData;
- CERTCertificate* clientCert = slapd_ssl_peerCertificate(prfd);
- char* clientDN = NULL;
- int keySize = 0;
- char* cipher = NULL;
- char* extraErrorMsg = "";
- SSLChannelInfo channelInfo;
- SSLCipherSuiteInfo cipherInfo;
- char* subject = NULL;
- if ( (slapd_ssl_getChannelInfo (prfd, &channelInfo, sizeof(channelInfo))) != SECSuccess ) {
- PRErrorCode errorCode = PR_GetError();
- slapi_log_access (LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " SSL failed to obtain channel info; "
- SLAPI_COMPONENT_NAME_NSPR " error %i (%s)\n",
- conn->c_connid, errorCode, slapd_pr_strerror(errorCode));
- goto done;
- }
- if ( (slapd_ssl_getCipherSuiteInfo (channelInfo.cipherSuite, &cipherInfo, sizeof(cipherInfo)) )
- != SECSuccess) {
- PRErrorCode errorCode = PR_GetError();
- slapi_log_access (LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " SSL failed to obtain cipher info; "
- SLAPI_COMPONENT_NAME_NSPR " error %i (%s)\n",
- conn->c_connid, errorCode, slapd_pr_strerror(errorCode));
- goto done;
- }
- keySize = cipherInfo.effectiveKeyBits;
- cipher = slapi_ch_strdup(cipherInfo.symCipherName);
- /* If inside an Start TLS operation, perform the privacy level discovery
- * and if the security degree achieved after the handshake is not reckoned
- * to be enough, close the SSL connection. */
- if ( conn->c_flags & CONN_FLAG_START_TLS ) {
- if ( cipherInfo.symKeyBits == 0 ) {
- start_tls_graceful_closure( conn, NULL, 1 );
- goto done;
- }
- }
- if (config_get_SSLclientAuth() == SLAPD_SSLCLIENTAUTH_OFF ) {
- slapi_log_access (LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " SSL %i-bit %s\n",
- conn->c_connid, keySize, cipher ? cipher : "NULL" );
- goto done;
- }
- if (clientCert == NULL) {
- slapi_log_access (LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " SSL %i-bit %s\n",
- conn->c_connid, keySize, cipher ? cipher : "NULL" );
- } else {
- subject = subject_of (clientCert);
- if (!subject) {
- slapi_log_access( LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " SSL %i-bit %s; missing subject\n",
- conn->c_connid, keySize, cipher ? cipher : "NULL");
- goto done;
- }
- {
- char* issuer = issuer_of (clientCert);
- char sbuf[ BUFSIZ ], ibuf[ BUFSIZ ];
- slapi_log_access( LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " SSL %i-bit %s; client %s; issuer %s\n",
- conn->c_connid, keySize, cipher ? cipher : "NULL",
- subject ? escape_string( subject, sbuf ) : "NULL",
- issuer ? escape_string( issuer, ibuf ) : "NULL");
- if (issuer) free (issuer);
- }
- slapi_dn_normalize (subject);
- {
- LDAPMessage* chain = NULL;
- char *basedn = config_get_basedn();
- int err;
- err = ldapu_cert_to_ldap_entry
- (clientCert, internal_ld, basedn?basedn:""/*baseDN*/, &chain);
- if (err == LDAPU_SUCCESS && chain) {
- LDAPMessage* entry = slapu_first_entry (internal_ld, chain);
- if (entry) {
- /* clientDN is duplicated in slapu_get_dn */
- clientDN = slapu_get_dn (internal_ld, entry);
- } else {
-
- extraErrorMsg = "no entry";
- LDAPDebug (LDAP_DEBUG_TRACE, "<= ldapu_cert_to_ldap_entry() %s\n",
- extraErrorMsg, 0, 0);
- }
- } else {
- extraErrorMsg = ldapu_err2string(err);
- LDAPDebug (LDAP_DEBUG_TRACE, "<= ldapu_cert_to_ldap_entry() %i (%s)%s\n",
- err, extraErrorMsg, chain ? "" : " NULL");
- }
- slapi_ch_free_string(&basedn);
- slapu_msgfree (internal_ld, chain);
- }
- }
- if (clientDN != NULL) {
- char ebuf[ BUFSIZ ];
- int rc = 0;
- char *normedDN = NULL;
- size_t dnlen = 0;
- rc = slapi_dn_normalize_ext(clientDN, 0, &normedDN, &dnlen);
- if (rc < 0) {
- /* ignoring the normalization error, use the pre normalized DN */
- } else if (rc == 0) { /* clientDN is passed in; not terminated */
- *(normedDN + dnlen) = '\0';
- } else {
- slapi_ch_free_string(&clientDN);
- clientDN = normedDN;
- }
- slapi_log_access (LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " SSL client bound as %s\n",
- conn->c_connid, escape_string( clientDN, ebuf ));
- } else if (clientCert != NULL) {
- slapi_log_access (LDAP_DEBUG_STATS,
- "conn=%" NSPRIu64 " SSL failed to map client "
- "certificate to LDAP DN (%s)\n",
- conn->c_connid, extraErrorMsg );
- }
- /*
- * Associate the new credentials with the connection. Note that
- * clientDN and clientCert may be NULL.
- */
- bind_credentials_set( conn, SLAPD_AUTH_SSL, clientDN,
- SLAPD_AUTH_SSL, clientDN, clientCert , NULL);
- done:
- slapi_ch_free_string(&subject);
- slapi_ch_free_string(&cipher);
- /* clientDN and clientCert will be freed later */
- }
|