1 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 /* apr_ldap_option.c -- LDAP options
19 * The LDAP SDK allows the getting and setting of options on an LDAP
27 #include "apr_errno.h"
28 #include "apr_pools.h"
29 #include "apr_strings.h"
30 #include "apr_tables.h"
34 static void option_set_cert(apr_pool_t
*pool
, LDAP
*ldap
, const void *invalue
,
35 apr_ldap_err_t
*result
);
36 static void option_set_tls(apr_pool_t
*pool
, LDAP
*ldap
, const void *invalue
,
37 apr_ldap_err_t
*result
);
40 * APR LDAP get option function
42 * This function gets option values from a given LDAP session if
45 APU_DECLARE(int) apr_ldap_get_option(apr_pool_t
*pool
,
49 apr_ldap_err_t
**result_err
)
51 apr_ldap_err_t
*result
;
53 result
= apr_pcalloc(pool
, sizeof(apr_ldap_err_t
));
59 /* get the option specified using the native LDAP function */
60 result
->rc
= ldap_get_option(ldap
, option
, outvalue
);
62 /* handle the error case */
63 if (result
->rc
!= LDAP_SUCCESS
) {
64 result
->msg
= ldap_err2string(result
-> rc
);
65 result
->reason
= apr_pstrdup(pool
, "LDAP: Could not get an option");
74 * APR LDAP set option function
76 * This function sets option values to a given LDAP session if
79 * Where an option is not supported by an LDAP toolkit, this function
80 * will try and apply legacy functions to achieve the same effect,
81 * depending on the platform.
83 APU_DECLARE(int) apr_ldap_set_option(apr_pool_t
*pool
,
87 apr_ldap_err_t
**result_err
)
89 apr_ldap_err_t
*result
;
91 result
= apr_pcalloc(pool
, sizeof(apr_ldap_err_t
));
98 case APR_LDAP_OPT_TLS_CERT
:
99 option_set_cert(pool
, ldap
, invalue
, result
);
102 case APR_LDAP_OPT_TLS
:
103 option_set_tls(pool
, ldap
, invalue
, result
);
106 case APR_LDAP_OPT_VERIFY_CERT
:
107 #if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSK
108 result
->reason
= "LDAP: Verify certificate not yet supported by APR on the "
109 "Netscape, Solaris or Mozilla LDAP SDKs";
113 #if APR_HAS_NOVELL_LDAPSDK
114 if (*((int*)invalue
)) {
115 result
->rc
= ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER
);
118 result
->rc
= ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE
);
121 #if APR_HAS_OPENLDAP_LDAPSDK
122 #ifdef LDAP_OPT_X_TLS
123 /* This is not a per-connection setting so just pass NULL for the
124 Ldap connection handle */
125 if (*((int*)invalue
)) {
126 int i
= LDAP_OPT_X_TLS_DEMAND
;
127 result
->rc
= ldap_set_option(NULL
, LDAP_OPT_X_TLS_REQUIRE_CERT
, &i
);
130 int i
= LDAP_OPT_X_TLS_NEVER
;
131 result
->rc
= ldap_set_option(NULL
, LDAP_OPT_X_TLS_REQUIRE_CERT
, &i
);
134 result
->reason
= "LDAP: SSL/TLS not yet supported by APR on this "
135 "version of the OpenLDAP toolkit";
141 /* handle the error case */
142 if (result
->rc
!= LDAP_SUCCESS
) {
143 result
->msg
= ldap_err2string(result
->rc
);
144 result
->reason
= "LDAP: Could not set verify mode";
149 /* set the option specified using the native LDAP function */
150 result
->rc
= ldap_set_option(ldap
, option
, (void *)invalue
);
152 /* handle the error case */
153 if (result
->rc
!= LDAP_SUCCESS
) {
154 result
->msg
= ldap_err2string(result
->rc
);
155 result
->reason
= "LDAP: Could not set an option";
160 /* handle the error case */
161 if (result
->rc
!= LDAP_SUCCESS
) {
170 * Handle APR_LDAP_OPT_TLS
172 * This function sets the type of TLS to be applied to this connection.
174 * APR_LDAP_NONE: no encryption
175 * APR_LDAP_SSL: SSL encryption (ldaps://)
176 * APR_LDAP_STARTTLS: STARTTLS encryption
177 * APR_LDAP_STOPTLS: Stop existing TLS connecttion
179 static void option_set_tls(apr_pool_t
*pool
, LDAP
*ldap
, const void *invalue
,
180 apr_ldap_err_t
*result
)
182 int tls
= * (const int *)invalue
;
184 #if APR_HAS_LDAP_SSL /* compiled with ssl support */
186 /* Netscape/Mozilla/Solaris SDK */
187 #if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSK
188 #if APR_HAS_LDAPSSL_INSTALL_ROUTINES
189 if (tls
== APR_LDAP_SSL
) {
190 result
->rc
= ldapssl_install_routines(ldap
);
192 /* apparently Netscape and Mozilla need this too, Solaris doesn't */
193 if (result
->rc
== LDAP_SUCCESS
) {
194 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_SSL
, LDAP_OPT_ON
);
197 if (result
->rc
!= LDAP_SUCCESS
) {
198 result
->msg
= ldap_err2string(result
->rc
);
199 result
->reason
= "LDAP: Could not switch SSL on for this "
203 else if (tls
== APR_LDAP_STARTTLS
) {
204 result
->reason
= "LDAP: STARTTLS is not supported by the "
205 "Netscape/Mozilla/Solaris SDK";
208 else if (tls
== APR_LDAP_STOPTLS
) {
209 result
->reason
= "LDAP: STOPTLS is not supported by the "
210 "Netscape/Mozilla/Solaris SDK";
214 if (tls
!= APR_LDAP_NONE
) {
215 result
->reason
= "LDAP: SSL/TLS is not supported by this version "
216 "of the Netscape/Mozilla/Solaris SDK";
223 #if APR_HAS_NOVELL_LDAPSDK
224 /* ldapssl_install_routines(ldap)
225 * Behavior is unpredictable when other LDAP functions are called
226 * between the ldap_init function and the ldapssl_install_routines
229 * STARTTLS is supported by the ldap_start_tls_s() method
231 if (tls
== APR_LDAP_SSL
) {
232 result
->rc
= ldapssl_install_routines(ldap
);
233 if (result
->rc
!= LDAP_SUCCESS
) {
234 result
->msg
= ldap_err2string(result
->rc
);
235 result
->reason
= "LDAP: Could not switch SSL on for this "
239 if (tls
== APR_LDAP_STARTTLS
) {
240 result
->rc
= ldapssl_start_tls(ldap
);
241 if (result
->rc
!= LDAP_SUCCESS
) {
242 result
->msg
= ldap_err2string(result
->rc
);
243 result
->reason
= "LDAP: Could not start TLS on this connection";
246 else if (tls
== APR_LDAP_STOPTLS
) {
247 result
->rc
= ldapssl_stop_tls(ldap
);
248 if (result
->rc
!= LDAP_SUCCESS
) {
249 result
->msg
= ldap_err2string(result
->rc
);
250 result
->reason
= "LDAP: Could not stop TLS on this connection";
256 #if APR_HAS_OPENLDAP_LDAPSDK
257 #ifdef LDAP_OPT_X_TLS
258 if (tls
== APR_LDAP_SSL
) {
259 int SSLmode
= LDAP_OPT_X_TLS_HARD
;
260 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_X_TLS
, &SSLmode
);
261 if (result
->rc
!= LDAP_SUCCESS
) {
262 result
->reason
= "LDAP: ldap_set_option failed. "
263 "Could not set LDAP_OPT_X_TLS to "
264 "LDAP_OPT_X_TLS_HARD";
265 result
->msg
= ldap_err2string(result
->rc
);
268 else if (tls
== APR_LDAP_STARTTLS
) {
269 result
->rc
= ldap_start_tls_s(ldap
, NULL
, NULL
);
270 if (result
->rc
!= LDAP_SUCCESS
) {
271 result
->reason
= "LDAP: ldap_start_tls_s() failed";
272 result
->msg
= ldap_err2string(result
->rc
);
275 else if (tls
== APR_LDAP_STOPTLS
) {
276 result
->reason
= "LDAP: STOPTLS is not supported by the "
281 if (tls
!= APR_LDAP_NONE
) {
282 result
->reason
= "LDAP: SSL/TLS not yet supported by APR on this "
283 "version of the OpenLDAP toolkit";
290 #if APR_HAS_MICROSOFT_LDAPSDK
291 if (tls
== APR_LDAP_NONE
) {
292 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_SSL
, LDAP_OPT_OFF
);
293 if (result
->rc
!= LDAP_SUCCESS
) {
294 result
->reason
= "LDAP: an attempt to set LDAP_OPT_SSL off "
296 result
->msg
= ldap_err2string(result
->rc
);
299 else if (tls
== APR_LDAP_SSL
) {
300 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_SSL
, LDAP_OPT_ON
);
301 if (result
->rc
!= LDAP_SUCCESS
) {
302 result
->reason
= "LDAP: an attempt to set LDAP_OPT_SSL on "
304 result
->msg
= ldap_err2string(result
->rc
);
307 #if APR_HAS_LDAP_START_TLS_S
308 else if (tls
== APR_LDAP_STARTTLS
) {
309 result
->rc
= ldap_start_tls_s(ldap
, NULL
, NULL
, NULL
, NULL
);
310 if (result
->rc
!= LDAP_SUCCESS
) {
311 result
->reason
= "LDAP: ldap_start_tls_s() failed";
312 result
->msg
= ldap_err2string(result
->rc
);
315 else if (tls
== APR_LDAP_STOPTLS
) {
316 result
->rc
= ldap_stop_tls_s(ldap
);
317 if (result
->rc
!= LDAP_SUCCESS
) {
318 result
->reason
= "LDAP: ldap_stop_tls_s() failed";
319 result
->msg
= ldap_err2string(result
->rc
);
325 #if APR_HAS_OTHER_LDAPSDK
326 if (tls
!= APR_LDAP_NONE
) {
327 result
->reason
= "LDAP: SSL/TLS is currently not supported by "
328 "APR on this LDAP SDK";
333 #endif /* APR_HAS_LDAP_SSL */
338 * Handle APR_LDAP_OPT_TLS_CACERTFILE
340 * This function sets the CA certificate for further SSL/TLS connections.
342 * The file provided are in different formats depending on the toolkit used:
344 * Netscape: cert7.db file
346 * OpenLDAP: PEM (others supported?)
350 static void option_set_cert(apr_pool_t
*pool
, LDAP
*ldap
,
351 const void *invalue
, apr_ldap_err_t
*result
)
353 apr_array_header_t
*certs
= (apr_array_header_t
*)invalue
;
354 struct apr_ldap_opt_tls_cert_t
*ents
= (struct apr_ldap_opt_tls_cert_t
*)certs
->elts
;
359 /* Netscape/Mozilla/Solaris SDK */
360 #if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSDK
361 #if APR_HAS_LDAPSSL_CLIENT_INIT
362 const char *nickname
= NULL
;
363 const char *secmod
= NULL
;
364 const char *key3db
= NULL
;
365 const char *cert7db
= NULL
;
366 const char *password
= NULL
;
368 /* set up cert7.db, key3.db and secmod parameters */
369 for (i
= 0; i
< certs
->nelts
; i
++) {
370 switch (ents
[i
].type
) {
371 case APR_LDAP_CA_TYPE_CERT7_DB
:
372 cert7db
= ents
[i
].path
;
374 case APR_LDAP_CA_TYPE_SECMOD
:
375 secmod
= ents
[i
].path
;
377 case APR_LDAP_CERT_TYPE_KEY3_DB
:
378 key3db
= ents
[i
].path
;
380 case APR_LDAP_CERT_TYPE_NICKNAME
:
381 nickname
= ents
[i
].path
;
382 password
= ents
[i
].password
;
386 result
->reason
= "LDAP: The Netscape/Mozilla LDAP SDK only "
387 "understands the CERT7, KEY3 and SECMOD "
391 if (result
->rc
!= LDAP_SUCCESS
) {
396 /* actually set the certificate parameters */
397 if (result
->rc
== LDAP_SUCCESS
) {
399 result
->rc
= ldapssl_enable_clientauth(ldap
, "",
402 if (result
->rc
!= LDAP_SUCCESS
) {
403 result
->reason
= "LDAP: could not set client certificate: "
404 "ldapssl_enable_clientauth() failed.";
405 result
->msg
= ldap_err2string(result
->rc
);
409 result
->rc
= ldapssl_advclientauth_init(cert7db
, NULL
,
410 key3db
? 1 : 0, key3db
, NULL
,
411 1, secmod
, LDAPSSL_AUTH_CNCHECK
);
412 if (result
->rc
!= LDAP_SUCCESS
) {
413 result
->reason
= "LDAP: ldapssl_advclientauth_init() failed.";
414 result
->msg
= ldap_err2string(result
->rc
);
418 result
->rc
= ldapssl_clientauth_init(cert7db
, NULL
,
420 if (result
->rc
!= LDAP_SUCCESS
) {
421 result
->reason
= "LDAP: ldapssl_clientauth_init() failed.";
422 result
->msg
= ldap_err2string(result
->rc
);
426 result
->rc
= ldapssl_client_init(cert7db
, NULL
);
427 if (result
->rc
!= LDAP_SUCCESS
) {
428 result
->reason
= "LDAP: ldapssl_client_init() failed.";
429 result
->msg
= ldap_err2string(result
->rc
);
434 result
->reason
= "LDAP: SSL/TLS ldapssl_client_init() function not "
435 "supported by this Netscape/Mozilla/Solaris SDK. "
436 "Certificate authority file not set";
442 #if APR_HAS_NOVELL_LDAPSDK
443 #if APR_HAS_LDAPSSL_CLIENT_INIT && APR_HAS_LDAPSSL_ADD_TRUSTED_CERT && APR_HAS_LDAPSSL_CLIENT_DEINIT
444 /* The Novell library cannot support per connection certificates. Error
445 * out if the ldap handle is provided.
449 result
->reason
= "LDAP: The Novell LDAP SDK cannot support the setting "
450 "of certificates or keys on a per connection basis.";
452 /* Novell's library needs to be initialised first */
454 result
->rc
= ldapssl_client_init(NULL
, NULL
);
455 if (result
->rc
!= LDAP_SUCCESS
) {
456 result
->msg
= ldap_err2string(result
-> rc
);
457 result
->reason
= apr_pstrdup(pool
, "LDAP: Could not "
461 /* set one or more certificates */
462 for (i
= 0; LDAP_SUCCESS
== result
->rc
&& i
< certs
->nelts
; i
++) {
463 /* Novell SDK supports DER or BASE64 files. */
464 switch (ents
[i
].type
) {
465 case APR_LDAP_CA_TYPE_DER
:
466 result
->rc
= ldapssl_add_trusted_cert((void *)ents
[i
].path
,
467 LDAPSSL_CERT_FILETYPE_DER
);
468 result
->msg
= ldap_err2string(result
->rc
);
470 case APR_LDAP_CA_TYPE_BASE64
:
471 result
->rc
= ldapssl_add_trusted_cert((void *)ents
[i
].path
,
472 LDAPSSL_CERT_FILETYPE_B64
);
473 result
->msg
= ldap_err2string(result
->rc
);
475 case APR_LDAP_CERT_TYPE_DER
:
476 result
->rc
= ldapssl_set_client_cert((void *)ents
[i
].path
,
477 LDAPSSL_CERT_FILETYPE_DER
,
478 (void*)ents
[i
].password
);
479 result
->msg
= ldap_err2string(result
->rc
);
481 case APR_LDAP_CERT_TYPE_BASE64
:
482 result
->rc
= ldapssl_set_client_cert((void *)ents
[i
].path
,
483 LDAPSSL_CERT_FILETYPE_B64
,
484 (void*)ents
[i
].password
);
485 result
->msg
= ldap_err2string(result
->rc
);
487 case APR_LDAP_CERT_TYPE_PFX
:
488 result
->rc
= ldapssl_set_client_cert((void *)ents
[i
].path
,
489 LDAPSSL_FILETYPE_P12
,
490 (void*)ents
[i
].password
);
491 result
->msg
= ldap_err2string(result
->rc
);
493 case APR_LDAP_KEY_TYPE_DER
:
494 result
->rc
= ldapssl_set_client_private_key((void *)ents
[i
].path
,
495 LDAPSSL_CERT_FILETYPE_DER
,
496 (void*)ents
[i
].password
);
497 result
->msg
= ldap_err2string(result
->rc
);
499 case APR_LDAP_KEY_TYPE_BASE64
:
500 result
->rc
= ldapssl_set_client_private_key((void *)ents
[i
].path
,
501 LDAPSSL_CERT_FILETYPE_B64
,
502 (void*)ents
[i
].password
);
503 result
->msg
= ldap_err2string(result
->rc
);
505 case APR_LDAP_KEY_TYPE_PFX
:
506 result
->rc
= ldapssl_set_client_private_key((void *)ents
[i
].path
,
507 LDAPSSL_FILETYPE_P12
,
508 (void*)ents
[i
].password
);
509 result
->msg
= ldap_err2string(result
->rc
);
513 result
->reason
= "LDAP: The Novell LDAP SDK only understands the "
514 "DER and PEM (BASE64) file types.";
517 if (result
->rc
!= LDAP_SUCCESS
) {
522 result
->reason
= "LDAP: ldapssl_client_init(), "
523 "ldapssl_add_trusted_cert() or "
524 "ldapssl_client_deinit() functions not supported "
525 "by this Novell SDK. Certificate authority file "
532 #if APR_HAS_OPENLDAP_LDAPSDK
533 #ifdef LDAP_OPT_X_TLS_CACERTFILE
534 /* set one or more certificates */
535 /* FIXME: make it support setting directories as well as files */
536 for (i
= 0; i
< certs
->nelts
; i
++) {
537 /* OpenLDAP SDK supports BASE64 files. */
538 switch (ents
[i
].type
) {
539 case APR_LDAP_CA_TYPE_BASE64
:
540 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_X_TLS_CACERTFILE
,
541 (void *)ents
[i
].path
);
542 result
->msg
= ldap_err2string(result
->rc
);
544 case APR_LDAP_CERT_TYPE_BASE64
:
545 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_X_TLS_CERTFILE
,
546 (void *)ents
[i
].path
);
547 result
->msg
= ldap_err2string(result
->rc
);
549 case APR_LDAP_KEY_TYPE_BASE64
:
550 result
->rc
= ldap_set_option(ldap
, LDAP_OPT_X_TLS_KEYFILE
,
551 (void *)ents
[i
].path
);
552 result
->msg
= ldap_err2string(result
->rc
);
556 result
->reason
= "LDAP: The OpenLDAP SDK only understands the "
557 "PEM (BASE64) file type.";
560 if (result
->rc
!= LDAP_SUCCESS
) {
565 result
->reason
= "LDAP: LDAP_OPT_X_TLS_CACERTFILE not "
566 "defined by this OpenLDAP SDK. Certificate "
567 "authority file not set";
573 #if APR_HAS_MICROSOFT_LDAPSDK
574 /* Microsoft SDK use the registry certificate store - error out
575 * here with a message explaining this. */
576 result
->reason
= "LDAP: CA certificates cannot be set using this method, "
577 "as they are stored in the registry instead.";
581 /* SDK not recognised */
582 #if APR_HAS_OTHER_LDAPSDK
583 result
->reason
= "LDAP: LDAP_OPT_X_TLS_CACERTFILE not "
584 "defined by this LDAP SDK. Certificate "
585 "authority file not set";
589 #else /* not compiled with SSL Support */
590 result
->reason
= "LDAP: Attempt to set certificate(s) failed. "
591 "Not built with SSL support";
593 #endif /* APR_HAS_LDAP_SSL */
597 #endif /* APR_HAS_LDAP */