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 */