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
17 enum opttype {
18 INT=0,
19 STRING,
20 OTHER
21 };
22
23 typedef struct tls_optmap {
24 int optval;
25 opttype type;
26 } tls_optmap_t;
27
28 static 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
checkOpt(TlsOptions::tls_option opt,opttype type)48 static 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
TlsOptions()58 TlsOptions::TlsOptions() : m_ld(NULL) {}
59
TlsOptions(LDAP * ld)60 TlsOptions::TlsOptions( LDAP* ld ): m_ld(ld) { }
61
setOption(tls_option opt,const std::string & value) const62 void 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
setOption(tls_option opt,int value) const102 void TlsOptions::setOption( tls_option opt, int value ) const {
103 checkOpt(opt, INT);
104 this->setOption( opt, (void*) &value);
105 }
106
setOption(tls_option opt,void * value) const107 void 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
getOption(tls_option opt,void * value) const120 void 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
getIntOption(tls_option opt) const132 int 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
getStringOption(tls_option opt) const139 std::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
newCtx() const152 void 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