1// $OpenLDAP$ 2/* 3 * Copyright 2010-2021 The OpenLDAP Foundation, All Rights Reserved. 4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file 5 */ 6 7#include <fstream> 8#include <sstream> 9#include <sys/types.h> 10#include <sys/stat.h> 11#include <errno.h> 12#include <unistd.h> 13#include <cstring> 14#include "TlsOptions.h" 15#include "LDAPException.h" 16 17enum opttype { 18 INT=0, 19 STRING, 20 OTHER 21}; 22 23typedef struct tls_optmap { 24 int optval; 25 opttype type; 26} tls_optmap_t; 27 28static tls_optmap_t optmap[] = { 29 { LDAP_OPT_X_TLS_CACERTFILE, STRING }, 30 { LDAP_OPT_X_TLS_CACERTDIR, STRING }, 31 { LDAP_OPT_X_TLS_CERTFILE, STRING }, 32 { LDAP_OPT_X_TLS_KEYFILE, STRING }, 33 { LDAP_OPT_X_TLS_REQUIRE_CERT, INT }, 34 { LDAP_OPT_X_TLS_PROTOCOL_MIN, INT }, 35 { LDAP_OPT_X_TLS_CIPHER_SUITE, STRING }, 36 { LDAP_OPT_X_TLS_RANDOM_FILE, STRING }, 37 { LDAP_OPT_X_TLS_CRLCHECK, INT }, 38 { LDAP_OPT_X_TLS_DHFILE, STRING }, 39 { LDAP_OPT_X_TLS_NEWCTX, INT } 40}; 41#if 0 /* not implemented currently */ 42 static const int TLS_CRLFILE /* GNUtls only */ 43 static const int TLS_SSL_CTX /* OpenSSL SSL* */ 44 static const int TLS_CONNECT_CB 45 static const int TLS_CONNECT_ARG 46#endif 47 48static void checkOpt( TlsOptions::tls_option opt, opttype type ) { 49 if ( opt < TlsOptions::CACERTFILE || opt >= TlsOptions::LASTOPT ){ 50 throw( LDAPException( LDAP_PARAM_ERROR, "unknown Option" ) ); 51 } 52 53 if ( optmap[opt].type != type ){ 54 throw( LDAPException( LDAP_PARAM_ERROR, "not a string option" ) ); 55 } 56} 57 58TlsOptions::TlsOptions() : m_ld(NULL) {} 59 60TlsOptions::TlsOptions( LDAP* ld ): m_ld(ld) { } 61 62void TlsOptions::setOption( tls_option opt, const std::string& value ) const { 63 checkOpt(opt, STRING); 64 switch(opt) { 65 case TlsOptions::CACERTFILE : 66 case TlsOptions::CERTFILE : 67 case TlsOptions::KEYFILE : 68 { 69 // check if the supplied file is actually readable 70 std::ifstream ifile(value.c_str()); 71 if ( !ifile ) { 72 throw( LDAPException( LDAP_LOCAL_ERROR, "Unable to open the supplied file for reading" ) ); 73 } 74 } 75 break; 76 case TlsOptions::CACERTDIR : 77 { 78 struct stat st; 79 std::ostringstream msg; 80 bool fail=false; 81 int err = stat(value.c_str(),&st); 82 if ( err ) { 83 msg << strerror(errno); 84 fail = true; 85 } else { 86 if ( !S_ISDIR(st.st_mode) ){ 87 msg << "The supplied path is not a directory."; 88 fail = true; 89 } 90 } 91 if ( fail ) { 92 std::ostringstream errstr; 93 errstr << "Error while setting Certificate Directory (" << value << "): " << msg.str(); 94 throw( LDAPException( LDAP_LOCAL_ERROR, errstr.str() ) ); 95 } 96 } 97 break; 98 } 99 this->setOption( opt, value.empty() ? NULL : (void*) value.c_str() ); 100} 101 102void TlsOptions::setOption( tls_option opt, int value ) const { 103 checkOpt(opt, INT); 104 this->setOption( opt, (void*) &value); 105} 106 107void TlsOptions::setOption( tls_option opt, void *value ) const { 108 int ret = ldap_set_option( m_ld, optmap[opt].optval, value); 109 if ( ret != LDAP_OPT_SUCCESS ) 110 { 111 if ( ret != LDAP_OPT_ERROR ){ 112 throw( LDAPException( ret )); 113 } else { 114 throw( LDAPException( LDAP_PARAM_ERROR, "error while setting TLS option" ) ); 115 } 116 } 117 this->newCtx(); 118} 119 120void TlsOptions::getOption( tls_option opt, void* value ) const { 121 int ret = ldap_get_option( m_ld, optmap[opt].optval, value); 122 if ( ret != LDAP_OPT_SUCCESS ) 123 { 124 if ( ret != LDAP_OPT_ERROR ){ 125 throw( LDAPException( ret )); 126 } else { 127 throw( LDAPException( LDAP_PARAM_ERROR, "error while reading TLS option" ) ); 128 } 129 } 130} 131 132int TlsOptions::getIntOption( tls_option opt ) const { 133 int value; 134 checkOpt(opt, INT); 135 ldap_get_option( m_ld, optmap[opt].optval, (void*) &value); 136 return value; 137} 138 139std::string TlsOptions::getStringOption( tls_option opt ) const { 140 char *value; 141 checkOpt(opt, STRING); 142 ldap_get_option( m_ld, optmap[opt].optval, (void*) &value); 143 std::string strval; 144 if (value) 145 { 146 strval=std::string(value); 147 ldap_memfree(value); 148 } 149 return strval; 150} 151 152void TlsOptions::newCtx() const { 153 int val = 0; 154 int ret = ldap_set_option( m_ld, LDAP_OPT_X_TLS_NEWCTX, &val); 155 if ( ret != LDAP_OPT_SUCCESS ) 156 { 157 if ( ret != LDAP_OPT_ERROR ){ 158 throw( LDAPException( ret )); 159 } else { 160 throw( LDAPException( LDAP_LOCAL_ERROR, "error while renewing TLS context" ) ); 161 } 162 } 163} 164