Run all tests, then fail make if required
[apr-util.git] / ldap / apr_ldap_option.c
blob2dd8398964ffac8c27649767b0210dd990b99999
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. 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
20 * connection.
24 #include "apr.h"
25 #include "apu.h"
26 #include "apr_ldap.h"
27 #include "apr_errno.h"
28 #include "apr_pools.h"
29 #include "apr_strings.h"
30 #include "apr_tables.h"
32 #if APR_HAS_LDAP
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);
39 /**
40 * APR LDAP get option function
42 * This function gets option values from a given LDAP session if
43 * one was specified.
45 APU_DECLARE(int) apr_ldap_get_option(apr_pool_t *pool,
46 LDAP *ldap,
47 int option,
48 void *outvalue,
49 apr_ldap_err_t **result_err)
51 apr_ldap_err_t *result;
53 result = apr_pcalloc(pool, sizeof(apr_ldap_err_t));
54 *result_err = result;
55 if (!result) {
56 return APR_ENOMEM;
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");
66 return APR_EGENERAL;
69 return APR_SUCCESS;
73 /**
74 * APR LDAP set option function
76 * This function sets option values to a given LDAP session if
77 * one was specified.
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,
84 LDAP *ldap,
85 int option,
86 const void *invalue,
87 apr_ldap_err_t **result_err)
89 apr_ldap_err_t *result;
91 result = apr_pcalloc(pool, sizeof(apr_ldap_err_t));
92 *result_err = result;
93 if (!result) {
94 return APR_ENOMEM;
97 switch (option) {
98 case APR_LDAP_OPT_TLS_CERT:
99 option_set_cert(pool, ldap, invalue, result);
100 break;
102 case APR_LDAP_OPT_TLS:
103 option_set_tls(pool, ldap, invalue, result);
104 break;
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";
110 result->rc = -1;
111 return APR_EGENERAL;
112 #endif
113 #if APR_HAS_NOVELL_LDAPSDK
114 if (*((int*)invalue)) {
115 result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_SERVER);
117 else {
118 result->rc = ldapssl_set_verify_mode(LDAPSSL_VERIFY_NONE);
120 #endif
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);
129 else {
130 int i = LDAP_OPT_X_TLS_NEVER;
131 result->rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
133 #else
134 result->reason = "LDAP: SSL/TLS not yet supported by APR on this "
135 "version of the OpenLDAP toolkit";
136 result->rc = -1;
137 return APR_EGENERAL;
138 #endif
139 #endif
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";
146 break;
148 default:
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";
157 break;
160 /* handle the error case */
161 if (result->rc != LDAP_SUCCESS) {
162 return APR_EGENERAL;
165 return APR_SUCCESS;
170 * Handle APR_LDAP_OPT_TLS
172 * This function sets the type of TLS to be applied to this connection.
173 * The options are:
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 #if APR_HAS_LDAP_SSL /* compiled with ssl support */
184 int tls = * (const int *)invalue;
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);
191 #ifdef LDAP_OPT_SSL
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);
196 #endif
197 if (result->rc != LDAP_SUCCESS) {
198 result->msg = ldap_err2string(result->rc);
199 result->reason = "LDAP: Could not switch SSL on for this "
200 "connection.";
203 else if (tls == APR_LDAP_STARTTLS) {
204 result->reason = "LDAP: STARTTLS is not supported by the "
205 "Netscape/Mozilla/Solaris SDK";
206 result->rc = -1;
208 else if (tls == APR_LDAP_STOPTLS) {
209 result->reason = "LDAP: STOPTLS is not supported by the "
210 "Netscape/Mozilla/Solaris SDK";
211 result->rc = -1;
213 #else
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";
217 result->rc = -1;
219 #endif
220 #endif
222 /* Novell 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
227 * function.
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 "
236 "connection.";
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";
253 #endif
255 /* OpenLDAP SDK */
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 "
277 "OpenLDAP SDK";
278 result->rc = -1;
280 #else
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";
284 result->rc = -1;
286 #endif
287 #endif
289 /* Microsoft SDK */
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 "
295 "failed.";
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 "
303 "failed.";
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);
322 #endif
323 #endif
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";
329 result->rc = -1;
331 #endif
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
345 * Novell: PEM or DER
346 * OpenLDAP: PEM (others supported?)
347 * Microsoft: unknown
348 * Solaris: unknown
350 static void option_set_cert(apr_pool_t *pool, LDAP *ldap,
351 const void *invalue, apr_ldap_err_t *result)
353 #if APR_HAS_LDAP_SSL
354 apr_array_header_t *certs = (apr_array_header_t *)invalue;
355 struct apr_ldap_opt_tls_cert_t *ents = (struct apr_ldap_opt_tls_cert_t *)certs->elts;
356 int i = 0;
358 /* Netscape/Mozilla/Solaris SDK */
359 #if APR_HAS_NETSCAPE_LDAPSDK || APR_HAS_SOLARIS_LDAPSDK || APR_HAS_MOZILLA_LDAPSDK
360 #if APR_HAS_LDAPSSL_CLIENT_INIT
361 const char *nickname = NULL;
362 const char *secmod = NULL;
363 const char *key3db = NULL;
364 const char *cert7db = NULL;
365 const char *password = NULL;
367 /* set up cert7.db, key3.db and secmod parameters */
368 for (i = 0; i < certs->nelts; i++) {
369 switch (ents[i].type) {
370 case APR_LDAP_CA_TYPE_CERT7_DB:
371 cert7db = ents[i].path;
372 break;
373 case APR_LDAP_CA_TYPE_SECMOD:
374 secmod = ents[i].path;
375 break;
376 case APR_LDAP_CERT_TYPE_KEY3_DB:
377 key3db = ents[i].path;
378 break;
379 case APR_LDAP_CERT_TYPE_NICKNAME:
380 nickname = ents[i].path;
381 password = ents[i].password;
382 break;
383 default:
384 result->rc = -1;
385 result->reason = "LDAP: The Netscape/Mozilla LDAP SDK only "
386 "understands the CERT7, KEY3 and SECMOD "
387 "file types.";
388 break;
390 if (result->rc != LDAP_SUCCESS) {
391 break;
395 /* actually set the certificate parameters */
396 if (result->rc == LDAP_SUCCESS) {
397 if (nickname) {
398 result->rc = ldapssl_enable_clientauth(ldap, "",
399 (char *)password,
400 (char *)nickname);
401 if (result->rc != LDAP_SUCCESS) {
402 result->reason = "LDAP: could not set client certificate: "
403 "ldapssl_enable_clientauth() failed.";
404 result->msg = ldap_err2string(result->rc);
407 else if (secmod) {
408 result->rc = ldapssl_advclientauth_init(cert7db, NULL,
409 key3db ? 1 : 0, key3db, NULL,
410 1, secmod, LDAPSSL_AUTH_CNCHECK);
411 if (result->rc != LDAP_SUCCESS) {
412 result->reason = "LDAP: ldapssl_advclientauth_init() failed.";
413 result->msg = ldap_err2string(result->rc);
416 else if (key3db) {
417 result->rc = ldapssl_clientauth_init(cert7db, NULL,
418 1, key3db, NULL);
419 if (result->rc != LDAP_SUCCESS) {
420 result->reason = "LDAP: ldapssl_clientauth_init() failed.";
421 result->msg = ldap_err2string(result->rc);
424 else {
425 result->rc = ldapssl_client_init(cert7db, NULL);
426 if (result->rc != LDAP_SUCCESS) {
427 result->reason = "LDAP: ldapssl_client_init() failed.";
428 result->msg = ldap_err2string(result->rc);
432 #else
433 result->reason = "LDAP: SSL/TLS ldapssl_client_init() function not "
434 "supported by this Netscape/Mozilla/Solaris SDK. "
435 "Certificate authority file not set";
436 result->rc = -1;
437 #endif
438 #endif
440 /* Novell SDK */
441 #if APR_HAS_NOVELL_LDAPSDK
442 #if APR_HAS_LDAPSSL_CLIENT_INIT && APR_HAS_LDAPSSL_ADD_TRUSTED_CERT && APR_HAS_LDAPSSL_CLIENT_DEINIT
443 /* The Novell library cannot support per connection certificates. Error
444 * out if the ldap handle is provided.
446 if (ldap) {
447 result->rc = -1;
448 result->reason = "LDAP: The Novell LDAP SDK cannot support the setting "
449 "of certificates or keys on a per connection basis.";
451 /* Novell's library needs to be initialised first */
452 else {
453 result->rc = ldapssl_client_init(NULL, NULL);
454 if (result->rc != LDAP_SUCCESS) {
455 result->msg = ldap_err2string(result-> rc);
456 result->reason = apr_pstrdup(pool, "LDAP: Could not "
457 "initialize SSL");
460 /* set one or more certificates */
461 for (i = 0; LDAP_SUCCESS == result->rc && i < certs->nelts; i++) {
462 /* Novell SDK supports DER or BASE64 files. */
463 switch (ents[i].type) {
464 case APR_LDAP_CA_TYPE_DER:
465 result->rc = ldapssl_add_trusted_cert((void *)ents[i].path,
466 LDAPSSL_CERT_FILETYPE_DER);
467 result->msg = ldap_err2string(result->rc);
468 break;
469 case APR_LDAP_CA_TYPE_BASE64:
470 result->rc = ldapssl_add_trusted_cert((void *)ents[i].path,
471 LDAPSSL_CERT_FILETYPE_B64);
472 result->msg = ldap_err2string(result->rc);
473 break;
474 case APR_LDAP_CERT_TYPE_DER:
475 result->rc = ldapssl_set_client_cert((void *)ents[i].path,
476 LDAPSSL_CERT_FILETYPE_DER,
477 (void*)ents[i].password);
478 result->msg = ldap_err2string(result->rc);
479 break;
480 case APR_LDAP_CERT_TYPE_BASE64:
481 result->rc = ldapssl_set_client_cert((void *)ents[i].path,
482 LDAPSSL_CERT_FILETYPE_B64,
483 (void*)ents[i].password);
484 result->msg = ldap_err2string(result->rc);
485 break;
486 case APR_LDAP_CERT_TYPE_PFX:
487 result->rc = ldapssl_set_client_cert((void *)ents[i].path,
488 LDAPSSL_FILETYPE_P12,
489 (void*)ents[i].password);
490 result->msg = ldap_err2string(result->rc);
491 break;
492 case APR_LDAP_KEY_TYPE_DER:
493 result->rc = ldapssl_set_client_private_key((void *)ents[i].path,
494 LDAPSSL_CERT_FILETYPE_DER,
495 (void*)ents[i].password);
496 result->msg = ldap_err2string(result->rc);
497 break;
498 case APR_LDAP_KEY_TYPE_BASE64:
499 result->rc = ldapssl_set_client_private_key((void *)ents[i].path,
500 LDAPSSL_CERT_FILETYPE_B64,
501 (void*)ents[i].password);
502 result->msg = ldap_err2string(result->rc);
503 break;
504 case APR_LDAP_KEY_TYPE_PFX:
505 result->rc = ldapssl_set_client_private_key((void *)ents[i].path,
506 LDAPSSL_FILETYPE_P12,
507 (void*)ents[i].password);
508 result->msg = ldap_err2string(result->rc);
509 break;
510 default:
511 result->rc = -1;
512 result->reason = "LDAP: The Novell LDAP SDK only understands the "
513 "DER and PEM (BASE64) file types.";
514 break;
516 if (result->rc != LDAP_SUCCESS) {
517 break;
520 #else
521 result->reason = "LDAP: ldapssl_client_init(), "
522 "ldapssl_add_trusted_cert() or "
523 "ldapssl_client_deinit() functions not supported "
524 "by this Novell SDK. Certificate authority file "
525 "not set";
526 result->rc = -1;
527 #endif
528 #endif
530 /* OpenLDAP SDK */
531 #if APR_HAS_OPENLDAP_LDAPSDK
532 #ifdef LDAP_OPT_X_TLS_CACERTFILE
533 /* set one or more certificates */
534 /* FIXME: make it support setting directories as well as files */
535 for (i = 0; i < certs->nelts; i++) {
536 /* OpenLDAP SDK supports BASE64 files. */
537 switch (ents[i].type) {
538 case APR_LDAP_CA_TYPE_BASE64:
539 result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_CACERTFILE,
540 (void *)ents[i].path);
541 result->msg = ldap_err2string(result->rc);
542 break;
543 case APR_LDAP_CERT_TYPE_BASE64:
544 result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_CERTFILE,
545 (void *)ents[i].path);
546 result->msg = ldap_err2string(result->rc);
547 break;
548 case APR_LDAP_KEY_TYPE_BASE64:
549 result->rc = ldap_set_option(ldap, LDAP_OPT_X_TLS_KEYFILE,
550 (void *)ents[i].path);
551 result->msg = ldap_err2string(result->rc);
552 break;
553 default:
554 result->rc = -1;
555 result->reason = "LDAP: The OpenLDAP SDK only understands the "
556 "PEM (BASE64) file type.";
557 break;
559 if (result->rc != LDAP_SUCCESS) {
560 break;
563 #else
564 result->reason = "LDAP: LDAP_OPT_X_TLS_CACERTFILE not "
565 "defined by this OpenLDAP SDK. Certificate "
566 "authority file not set";
567 result->rc = -1;
568 #endif
569 #endif
571 /* Microsoft SDK */
572 #if APR_HAS_MICROSOFT_LDAPSDK
573 /* Microsoft SDK use the registry certificate store - error out
574 * here with a message explaining this. */
575 result->reason = "LDAP: CA certificates cannot be set using this method, "
576 "as they are stored in the registry instead.";
577 result->rc = -1;
578 #endif
580 /* SDK not recognised */
581 #if APR_HAS_OTHER_LDAPSDK
582 result->reason = "LDAP: LDAP_OPT_X_TLS_CACERTFILE not "
583 "defined by this LDAP SDK. Certificate "
584 "authority file not set";
585 result->rc = -1;
586 #endif
588 #else /* not compiled with SSL Support */
589 result->reason = "LDAP: Attempt to set certificate(s) failed. "
590 "Not built with SSL support";
591 result->rc = -1;
592 #endif /* APR_HAS_LDAP_SSL */
596 #endif /* APR_HAS_LDAP */