1 /*
2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * The contents of this file are subject to the Netscape Public
7 * License Version 1.1 (the "License"); you may not use this file
8 * except in compliance with the License. You may obtain a copy of
9 * the License at http://www.mozilla.org/NPL/
10 *
11 * Software distributed under the License is distributed on an "AS
12 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13 * implied. See the License for the specific language governing
14 * rights and limitations under the License.
15 *
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
18 *
19 * The Initial Developer of the Original Code is Netscape
20 * Communications Corporation. Portions created by Netscape are
21 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
22 * Rights Reserved.
23 *
24 * Contributor(s):
25 */
26
27 /*
28 * clientinit.c
29 */
30
31 #if defined(NET_SSL)
32
33
34 #if defined( _WINDOWS )
35 #include <windows.h>
36 #include "proto-ntutil.h"
37 #endif
38
39 #include <nspr.h>
40 #include <plstr.h>
41 #include <synch.h>
42 #include <cert.h>
43 #include <key.h>
44 #include <ssl.h>
45 #include <sslproto.h>
46 #include <ldap.h>
47 #include <ldappr.h>
48 #include <solaris-int.h>
49
50
51 #include <nss.h>
52
53 /* XXX:mhein The following is a workaround for the redefinition of */
54 /* const problem on OSF. Fix to be provided by NSS */
55 /* This is a pretty benign workaround for us which */
56 /* should not cause problems in the future even if */
57 /* we forget to take it out :-) */
58
59 #ifdef OSF1V4D
60 #ifndef __STDC__
61 # define __STDC__
62 #endif /* __STDC__ */
63 #endif /* OSF1V4D */
64
65 #ifndef FILE_PATHSEP
66 #define FILE_PATHSEP '/'
67 #endif
68
69 /*
70 * StartTls()
71 */
72
73 #define START_TLS_OID "1.3.6.1.4.1.1466.20037"
74
75 static PRStatus local_SSLPLCY_Install(void);
76
77 /*
78 * This little tricky guy keeps us from initializing twice
79 */
80 static int inited = 0;
81 #ifdef _SOLARIS_SDK
82 mutex_t inited_mutex = DEFAULTMUTEX;
83 #else
84 static mutex_t inited_mutex = DEFAULTMUTEX;
85 #endif /* _SOLARIS_SDK */
86 #if 0 /* UNNEEDED BY LIBLDAP */
87 static char tokDes[34] = "Internal (Software) Database ";
88 static char ptokDes[34] = "Internal (Software) Token ";
89 #endif /* UNNEEDED BY LIBLDAP */
90
91
92 /* IN: */
93 /* string: /u/mhein/.netscape/mykey3.db */
94 /* OUT: */
95 /* dir: /u/mhein/.netscape/ */
96 /* prefix: my */
97 /* key: key3.db */
98
99 static int
splitpath(char * string,char * dir,char * prefix,char * key)100 splitpath(char *string, char *dir, char *prefix, char *key) {
101 char *k;
102 char *s;
103 char *d = string;
104 char *l;
105 int len = 0;
106
107
108 if (string == NULL)
109 return (-1);
110
111 /* goto the end of the string, and walk backwards until */
112 /* you get to the first pathseparator */
113 len = PL_strlen(string);
114 l = string + len - 1;
115 while (l != string && *l != '/' && *l != '\\')
116 l--;
117 /* search for the .db */
118 if ((k = PL_strstr(l, ".db")) != NULL) {
119 /* now we are sitting on . of .db */
120
121 /* move backward to the first 'c' or 'k' */
122 /* indicating cert or key */
123 while (k != l && *k != 'c' && *k != 'k')
124 k--;
125
126 /* move backwards to the first path separator */
127 if (k != d && k > d)
128 s = k - 1;
129 while (s != d && *s != '/' && *s != '\\')
130 s--;
131
132 /* if we are sitting on top of a path */
133 /* separator there is no prefix */
134 if (s + 1 == k) {
135 /* we know there is no prefix */
136 prefix = '\0';
137 PL_strcpy(key, k);
138 *k = '\0';
139 PL_strcpy(dir, d);
140 } else {
141 /* grab the prefix */
142 PL_strcpy(key, k);
143 *k = '\0';
144 PL_strcpy(prefix, ++s);
145 *s = '\0';
146 PL_strcpy(dir, d);
147 }
148 } else {
149 /* neither *key[0-9].db nor *cert[0=9].db found */
150 return (-1);
151 }
152
153 return (0);
154 }
155
156
local_SSLPLCY_Install(void)157 static PRStatus local_SSLPLCY_Install(void)
158 {
159 SECStatus s;
160
161 #ifdef NS_DOMESTIC
162 s = NSS_SetDomesticPolicy();
163 #elif NS_EXPORT
164 s = NSS_SetExportPolicy();
165 #else
166 s = PR_FAILURE;
167 #endif
168 return s?PR_FAILURE:PR_SUCCESS;
169 }
170
171
172
173 static void
ldapssl_basic_init(void)174 ldapssl_basic_init( void )
175 {
176 #ifndef _SOLARIS_SDK
177 /*
178 * NSPR is initialized in .init on SOLARIS
179 */
180 /* PR_Init() must to be called before everything else... */
181 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
182 #endif
183
184 PR_SetConcurrency( 4 ); /* work around for NSPR 3.x I/O hangs */
185 }
186
187
188
189 /*
190 * Cover functions for malloc(), calloc(), strdup() and free() that are
191 * compatible with the NSS libraries (they seem to use the C runtime
192 * library malloc/free so these functions are quite simple right now).
193 */
194 static void *
ldapssl_malloc(size_t size)195 ldapssl_malloc( size_t size )
196 {
197 void *p;
198
199 p = malloc( size );
200 return p;
201 }
202
203
204 static void *
ldapssl_calloc(int nelem,size_t elsize)205 ldapssl_calloc( int nelem, size_t elsize )
206 {
207 void *p;
208
209 p = calloc( nelem, elsize );
210 return p;
211 }
212
213
214 static char *
ldapssl_strdup(const char * s)215 ldapssl_strdup( const char *s )
216 {
217 char *scopy;
218
219 if ( NULL == s ) {
220 scopy = NULL;
221 } else {
222 scopy = strdup( s );
223 }
224 return scopy;
225 }
226
227
228 static void
ldapssl_free(void ** pp)229 ldapssl_free( void **pp )
230 {
231 if ( NULL != pp && NULL != *pp ) {
232 free( (void *)*pp );
233 *pp = NULL;
234 }
235 }
236
237
238 #ifdef _SOLARIS_SDK
239 /*
240 * Disable strict fork detection of NSS library to allow safe fork of
241 * consumers. Otherwise NSS will not work after fork because it was not
242 * deinitialized before fork and there is no safe way how to do it after fork.
243 *
244 * Return values:
245 * 1 - DISABLED was already set, no modification to environment
246 * 0 - successfully modified environment, old value saved to enval if there
247 * was some
248 * -1 - setenv or strdup failed, the environment was left unchanged
249 *
250 */
251 static int
update_nss_strict_fork_env(char ** enval)252 update_nss_strict_fork_env(char **enval)
253 {
254 char *temps = getenv("NSS_STRICT_NOFORK");
255 if (temps == NULL) {
256 *enval = NULL;
257 } else if (strncmp(temps, "DISABLED", 9) == 0) {
258 /* Do not need to set as DISABLED, it is already set. */
259 *enval = NULL;
260 return (1);
261 } else {
262 if ((*enval = ldapssl_strdup(temps)) == NULL)
263 return (-1);
264 }
265 return (setenv("NSS_STRICT_NOFORK", "DISABLED", 1));
266 }
267
268 /*
269 * Reset environment variable NSS_STRICT_NOFORK to value before
270 * update_nss_strict_fork_env() call or remove it from environment if it did
271 * not exist.
272 * NSS_STRICT_NOFORK=DISABLED is needed only during NSS initialization to
273 * disable activation of atfork handler in NSS which is invalidating
274 * initialization in child process after fork.
275 */
276 static int
reset_nss_strict_fork_env(char * enval)277 reset_nss_strict_fork_env(char *enval)
278 {
279 if (enval != NULL) {
280 return (setenv("NSS_STRICT_NOFORK", enval, 1));
281 } else {
282 return (unsetenv("NSS_STRICT_NOFORK"));
283 }
284 }
285 #endif
286
287
288 static char *
buildDBName(const char * basename,const char * dbname)289 buildDBName(const char *basename, const char *dbname)
290 {
291 char *result;
292 PRUint32 len, pathlen, addslash;
293
294 if (basename)
295 {
296 if (( len = PL_strlen( basename )) > 3
297 && PL_strcasecmp( ".db", basename + len - 3 ) == 0 ) {
298 return (ldapssl_strdup(basename));
299 }
300
301 pathlen = len;
302 len = pathlen + PL_strlen(dbname) + 1;
303 addslash = ( pathlen > 0 &&
304 (( *(basename + pathlen - 1) != FILE_PATHSEP ) ||
305 ( *(basename + pathlen - 1) != '\\' )));
306
307 if ( addslash ) {
308 ++len;
309 }
310 if (( result = ldapssl_malloc( len )) != NULL ) {
311 PL_strcpy( result, basename );
312 if ( addslash ) {
313 *(result+pathlen) = FILE_PATHSEP; /* replaces '\0' */
314 ++pathlen;
315 }
316 PL_strcpy(result+pathlen, dbname);
317 }
318
319 }
320
321
322 return result;
323 }
324
325 char *
GetCertDBName(void * alias,int dbVersion)326 GetCertDBName(void *alias, int dbVersion)
327 {
328 char *source;
329 char dbname[128];
330
331 source = (char *)alias;
332
333 if (!source)
334 {
335 source = "";
336 }
337
338 sprintf(dbname, "cert%d.db",dbVersion);
339 return(buildDBName(source, dbname));
340
341
342 }
343
344 /*
345 * return database name by appending "dbname" to "path".
346 * this code doesn't need to be terribly efficient (not called often).
347 */
348 /* XXXceb this is the old function. To be removed eventually */
349 static char *
GetDBName(const char * dbname,const char * path)350 GetDBName(const char *dbname, const char *path)
351 {
352 char *result;
353 PRUint32 len, pathlen;
354 int addslash;
355
356 if ( dbname == NULL ) {
357 dbname = "";
358 }
359
360 if ((path == NULL) || (*path == 0)) {
361 result = ldapssl_strdup(dbname);
362 } else {
363 pathlen = PL_strlen(path);
364 len = pathlen + PL_strlen(dbname) + 1;
365 addslash = ( path[pathlen - 1] != '/' );
366 if ( addslash ) {
367 ++len;
368 }
369 if (( result = ldapssl_malloc( len )) != NULL ) {
370 PL_strcpy( result, path );
371 if ( addslash ) {
372 *(result+pathlen) = '/'; /* replaces '\0' */
373 ++pathlen;
374 }
375 PL_strcpy(result+pathlen, dbname);
376 }
377 }
378
379 return result;
380 }
381
382 /*
383 * Initialize ns/security so it can be used for SSL client authentication.
384 * It is safe to call this more than once.
385 *
386 * If needkeydb == 0, no key database is opened and SSL server authentication
387 * is supported but not client authentication.
388 *
389 * If "certdbpath" is NULL or "", the default cert. db is used (typically
390 * ~/.netscape/cert7.db).
391 *
392 * If "certdbpath" ends with ".db" (case-insensitive compare), then
393 * it is assumed to be a full path to the cert. db file; otherwise,
394 * it is assumed to be a directory that contains a file called
395 * "cert7.db" or "cert.db".
396 *
397 * If certdbhandle is non-NULL, it is assumed to be a pointer to a
398 * SECCertDBHandle structure. It is fine to pass NULL since this
399 * routine will allocate one for you (CERT_GetDefaultDB() can be
400 * used to retrieve the cert db handle).
401 *
402 * If "keydbpath" is NULL or "", the default key db is used (typically
403 * ~/.netscape/key3.db).
404 *
405 * If "keydbpath" ends with ".db" (case-insensitive compare), then
406 * it is assumed to be a full path to the key db file; otherwise,
407 * it is assumed to be a directory that contains a file called
408 * "key3.db"
409 *
410 * If certdbhandle is non-NULL< it is assumed to be a pointed to a
411 * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
412 * routine will allocate one for you (SECKEY_GetDefaultDB() can be
413 * used to retrieve the cert db handle).
414 */
415 int
416 LDAP_CALL
ldapssl_clientauth_init(const char * certdbpath,void * certdbhandle,const int needkeydb,const char * keydbpath,void * keydbhandle)417 ldapssl_clientauth_init( const char *certdbpath, void *certdbhandle,
418 const int needkeydb, const char *keydbpath, void *keydbhandle )
419
420 {
421 int rc;
422 #ifdef _SOLARIS_SDK
423 char *enval;
424 int rcenv = 0;
425 #endif
426
427 /*
428 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_clientauth_init\n",0 ,0 ,0);
429 */
430
431 mutex_lock(&inited_mutex);
432 if ( inited ) {
433 mutex_unlock(&inited_mutex);
434 return( 0 );
435 }
436
437 ldapssl_basic_init();
438
439 #ifdef _SOLARIS_SDK
440 if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
441 mutex_unlock(&inited_mutex);
442 return (-1);
443 }
444 #endif
445
446 /* Open the certificate database */
447 rc = NSS_Init(certdbpath);
448 #ifdef _SOLARIS_SDK
449 /* Error from NSS_Init() more important! */
450 if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
451 ldapssl_free(&enval);
452 mutex_unlock(&inited_mutex);
453 return (-1);
454 }
455 ldapssl_free(&enval);
456 #endif
457 if (rc != 0) {
458 if ((rc = PR_GetError()) >= 0)
459 rc = -1;
460 mutex_unlock(&inited_mutex);
461 return (rc);
462 }
463
464 if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
465 || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
466 if (( rc = PR_GetError()) >= 0 ) {
467 rc = -1;
468 }
469 mutex_unlock(&inited_mutex);
470 return( rc );
471 }
472
473
474
475 #if defined(NS_DOMESTIC)
476 if (local_SSLPLCY_Install() == PR_FAILURE) {
477 mutex_unlock(&inited_mutex);
478 return( -1 );
479 }
480 #elif(NS_EXPORT)
481 if (local_SSLPLCY_Install() == PR_FAILURE) {
482 mutex_unlock(&inited_mutex);
483 return( -1 );
484 }
485 #else
486 mutex_unlock(&inited_mutex);
487 return( -1 );
488 #endif
489
490 inited = 1;
491 mutex_unlock(&inited_mutex);
492
493 return( 0 );
494
495 }
496
497 /*
498 * Initialize ns/security so it can be used for SSL client authentication.
499 * It is safe to call this more than once.
500 *
501 * If needkeydb == 0, no key database is opened and SSL server authentication
502 * is supported but not client authentication.
503 *
504 * If "certdbpath" is NULL or "", the default cert. db is used (typically
505 * ~/.netscape/cert7.db).
506 *
507 * If "certdbpath" ends with ".db" (case-insensitive compare), then
508 * it is assumed to be a full path to the cert. db file; otherwise,
509 * it is assumed to be a directory that contains a file called
510 * "cert7.db" or "cert.db".
511 *
512 * If certdbhandle is non-NULL, it is assumed to be a pointer to a
513 * SECCertDBHandle structure. It is fine to pass NULL since this
514 * routine will allocate one for you (CERT_GetDefaultDB() can be
515 * used to retrieve the cert db handle).
516 *
517 * If "keydbpath" is NULL or "", the default key db is used (typically
518 * ~/.netscape/key3.db).
519 *
520 * If "keydbpath" ends with ".db" (case-insensitive compare), then
521 * it is assumed to be a full path to the key db file; otherwise,
522 * it is assumed to be a directory that contains a file called
523 * "key3.db"
524 *
525 * If certdbhandle is non-NULL< it is assumed to be a pointed to a
526 * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
527 * routine will allocate one for you (SECKEY_GetDefaultDB() can be
528 * used to retrieve the cert db handle). */
529 int
530 LDAP_CALL
ldapssl_advclientauth_init(const char * certdbpath,void * certdbhandle,const int needkeydb,const char * keydbpath,void * keydbhandle,const int needsecmoddb,const char * secmoddbpath,const int sslstrength)531 ldapssl_advclientauth_init(
532 const char *certdbpath, void *certdbhandle,
533 const int needkeydb, const char *keydbpath, void *keydbhandle,
534 const int needsecmoddb, const char *secmoddbpath,
535 const int sslstrength )
536 {
537 int rc;
538 #ifdef _SOLARIS_SDK
539 char *enval;
540 int rcenv = 0;
541 #endif
542
543 mutex_lock(&inited_mutex);
544 if ( inited ) {
545 mutex_unlock(&inited_mutex);
546 return( 0 );
547 }
548
549 /*
550 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_advclientauth_init\n",0 ,0 ,0);
551 */
552
553 ldapssl_basic_init();
554
555 #ifdef _SOLARIS_SDK
556 if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
557 mutex_unlock(&inited_mutex);
558 return (-1);
559 }
560 #endif
561
562 rc = NSS_Init(certdbpath);
563 #ifdef _SOLARIS_SDK
564 /* Error from NSS_Init() more important! */
565 if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
566 ldapssl_free(&enval);
567 mutex_unlock(&inited_mutex);
568 return (-1);
569 }
570 ldapssl_free(&enval);
571 #endif
572 if (rc != 0) {
573 if ((rc = PR_GetError()) >= 0)
574 rc = -1;
575 mutex_unlock(&inited_mutex);
576 return (rc);
577 }
578
579 #if defined(NS_DOMESTIC)
580 if (local_SSLPLCY_Install() == PR_FAILURE) {
581 mutex_unlock(&inited_mutex);
582 return( -1 );
583 }
584 #elif(NS_EXPORT)
585 if (local_SSLPLCY_Install() == PR_FAILURE) {
586 mutex_unlock(&inited_mutex);
587 return( -1 );
588 }
589 #else
590 mutex_unlock(&inited_mutex);
591 return( -1 );
592 #endif
593
594 inited = 1;
595 mutex_unlock(&inited_mutex);
596
597 return( ldapssl_set_strength( NULL, sslstrength));
598
599 }
600
601
602 /*
603 * Initialize ns/security so it can be used for SSL client authentication.
604 * It is safe to call this more than once.
605 */
606
607 /*
608 * XXXceb This is a hack until the new IO functions are done.
609 * this function lives in ldapsinit.c
610 */
611 void set_using_pkcs_functions( int val );
612
613 int
614 LDAP_CALL
ldapssl_pkcs_init(const struct ldapssl_pkcs_fns * pfns)615 ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns )
616 {
617
618 char *certdbName, *s, *keydbpath;
619 char *certdbPrefix, *keydbPrefix;
620 char *confDir, *keydbName;
621 static char *secmodname = "secmod.db";
622 int rc;
623 #ifdef _SOLARIS_SDK
624 char *enval;
625 int rcenv = 0;
626 #endif
627
628 mutex_lock(&inited_mutex);
629 if ( inited ) {
630 mutex_unlock(&inited_mutex);
631 return( 0 );
632 }
633 /*
634 * XXXceb This is a hack until the new IO functions are done.
635 * this function MUST be called before ldap_enable_clienauth.
636 *
637 */
638 set_using_pkcs_functions( 1 );
639
640 /*
641 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_pkcs_init\n",0 ,0 ,0);
642 */
643
644
645 ldapssl_basic_init();
646
647 pfns->pkcs_getcertpath( NULL, &s);
648 confDir = ldapssl_strdup( s );
649 certdbPrefix = ldapssl_strdup( s );
650 certdbName = ldapssl_strdup( s );
651 *certdbPrefix = 0;
652 splitpath(s, confDir, certdbPrefix, certdbName);
653
654 pfns->pkcs_getkeypath( NULL, &s);
655 keydbpath = ldapssl_strdup( s );
656 keydbPrefix = ldapssl_strdup( s );
657 keydbName = ldapssl_strdup( s );
658 *keydbPrefix = 0;
659 splitpath(s, keydbpath, keydbPrefix, keydbName);
660
661
662 /* verify confDir == keydbpath and adjust as necessary */
663 ldapssl_free((void **)&certdbName);
664 ldapssl_free((void **)&keydbName);
665 ldapssl_free((void **)&keydbpath);
666
667 #ifdef _SOLARIS_SDK
668 if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
669 mutex_unlock(&inited_mutex);
670 return (-1);
671 }
672 #endif
673
674 rc = NSS_Initialize(confDir,certdbPrefix,keydbPrefix,secmodname,
675 NSS_INIT_READONLY);
676
677 ldapssl_free((void **)&certdbPrefix);
678 ldapssl_free((void **)&keydbPrefix);
679 ldapssl_free((void **)&confDir);
680
681 #ifdef _SOLARIS_SDK
682 /* Error from NSS_Initialize() more important! */
683 if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
684 ldapssl_free(&enval);
685 mutex_unlock(&inited_mutex);
686 return (-1);
687 }
688 ldapssl_free(&enval);
689 #endif
690
691 if (rc != 0) {
692 if ((rc = PR_GetError()) >= 0)
693 rc = -1;
694 mutex_unlock(&inited_mutex);
695 return (rc);
696 }
697
698
699 #if 0 /* UNNEEDED BY LIBLDAP */
700 /* this is odd */
701 PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
702 #endif /* UNNEEDED BY LIBLDAP */
703
704 if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
705 || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
706 if (( rc = PR_GetError()) >= 0 ) {
707 rc = -1;
708 }
709
710 mutex_unlock(&inited_mutex);
711 return( rc );
712 }
713
714 #if defined(NS_DOMESTIC)
715 if (local_SSLPLCY_Install() == PR_FAILURE) {
716 mutex_unlock(&inited_mutex);
717 return( -1 );
718 }
719 #elif(NS_EXPORT)
720 if (local_SSLPLCY_Install() == PR_FAILURE) {
721 mutex_unlock(&inited_mutex);
722 return( -1 );
723 }
724 #else
725 mutex_unlock(&inited_mutex);
726 return( -1 );
727 #endif
728
729 inited = 1;
730
731 if ( certdbName != NULL ) {
732 ldapssl_free((void **) &certdbName );
733 }
734
735 return( ldapssl_set_strength( NULL, LDAPSSL_AUTH_CNCHECK));
736 }
737
738
739 /*
740 * ldapssl_client_init() is a server-authentication only version of
741 * ldapssl_clientauth_init().
742 */
743 int
744 LDAP_CALL
ldapssl_client_init(const char * certdbpath,void * certdbhandle)745 ldapssl_client_init(const char* certdbpath, void *certdbhandle )
746 {
747 return( ldapssl_clientauth_init( certdbpath, certdbhandle,
748 0, NULL, NULL ));
749 }
750 /*
751 * ldapssl_serverauth_init() is a server-authentication only version of
752 * ldapssl_clientauth_init(). This function allows the sslstrength
753 * to be passed in. The sslstrength can take one of the following
754 * values:
755 * LDAPSSL_AUTH_WEAK: indicate that you accept the server's
756 * certificate without checking the CA who
757 * issued the certificate
758 * LDAPSSL_AUTH_CERT: indicates that you accept the server's
759 * certificate only if you trust the CA who
760 * issued the certificate
761 * LDAPSSL_AUTH_CNCHECK:
762 indicates that you accept the server's
763 * certificate only if you trust the CA who
764 * issued the certificate and if the value
765 * of the cn attribute in the DNS hostname
766 * of the server
767 */
768 int
769 LDAP_CALL
ldapssl_serverauth_init(const char * certdbpath,void * certdbhandle,const int sslstrength)770 ldapssl_serverauth_init(const char* certdbpath,
771 void *certdbhandle,
772 const int sslstrength )
773 {
774 if ( ldapssl_set_strength( NULL, sslstrength ) != 0) {
775 return ( -1 );
776 }
777
778 return( ldapssl_clientauth_init( certdbpath, certdbhandle,
779 0, NULL, NULL ));
780 }
781
782 /*
783 * Function that makes an asynchronous Start TLS extended operation request.
784 */
ldapssl_tls_start(LDAP * ld,int * msgidp)785 static int ldapssl_tls_start(LDAP *ld, int *msgidp)
786 {
787 int version, rc;
788 BerValue extreq_data;
789
790 /* Start TLS extended operation requires an absent "requestValue" field. */
791
792 extreq_data.bv_val = NULL;
793 extreq_data.bv_len = 0;
794
795 /* Make sure version is set to LDAPv3 for extended operations to be
796 supported. */
797
798 version = LDAP_VERSION3;
799 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
800
801 /* Send the Start TLS request (OID: 1.3.6.1.4.1.1466.20037) */
802 rc = ldap_extended_operation( ld, START_TLS_OID, &extreq_data,
803 NULL, NULL, msgidp );
804
805 return rc;
806 }
807
808
809 /*
810 * Function that enables SSL on an already open non-secured LDAP connection.
811 * (i.e. the connection is henceforth secured)
812 */
ldapssl_enableSSL_on_open_connection(LDAP * ld,int defsecure,char * certdbpath,char * keydbpath)813 static int ldapssl_enableSSL_on_open_connection(LDAP *ld, int defsecure,
814 char *certdbpath, char *keydbpath)
815 {
816 PRLDAPSocketInfo soi;
817
818
819 if ( ldapssl_clientauth_init( certdbpath, NULL, 1, keydbpath, NULL ) < 0 ) {
820 goto ssl_setup_failure;
821 }
822
823 /*
824 * Retrieve socket info. so we have the PRFileDesc.
825 */
826 memset( &soi, 0, sizeof(soi));
827 soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
828 if ( prldap_get_default_socket_info( ld, &soi ) < 0 ) {
829 goto ssl_setup_failure;
830 }
831
832 if ( ldapssl_install_routines( ld ) < 0 ) {
833 goto ssl_setup_failure;
834 }
835
836
837 if (soi.soinfo_prfd == NULL) {
838 int sd;
839 ldap_get_option( ld, LDAP_OPT_DESC, &sd );
840 soi.soinfo_prfd = (PRFileDesc *) PR_ImportTCPSocket( sd );
841 }
842 /* set the socket information back into the connection handle,
843 * because ldapssl_install_routines() resets the socket_arg info in the
844 * socket buffer. */
845 if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
846 goto ssl_setup_failure;
847 }
848
849 if ( ldap_set_option( ld, LDAP_OPT_SSL,
850 defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) < 0 ) {
851 goto ssl_setup_failure;
852 }
853
854 if ( ldapssl_import_fd( ld, defsecure ) < 0 ) {
855 goto ssl_setup_failure;
856 }
857
858 return 0;
859
860 ssl_setup_failure:
861 ldapssl_reset_to_nonsecure( ld );
862
863 /* we should here warn the server that we switch back to a non-secure
864 connection */
865
866 return( -1 );
867 }
868
869
870 /*
871 * ldapssl_tls_start_s() performs a synchronous Start TLS extended operation
872 * request.
873 *
874 * The function returns the result code of the extended operation response
875 * sent by the server.
876 *
877 * In case of a successfull response (LDAP_SUCCESS returned), by the time
878 * this function returns the LDAP session designed by ld will have been
879 * secured, i.e. the connection will have been imported into SSL.
880 *
881 * Should the Start TLS request be rejected by the server, the result code
882 * returned will be one of the following:
883 * LDAP_OPERATIONS_ERROR,
884 * LDAP_PROTOCOL_ERROR,
885 * LDAP_REFERRAL,
886 * LDAP_UNAVAILABLE.
887 *
888 * Any other error code returned will be due to a failure in the course
889 * of operations done on the client side.
890 *
891 * "certdbpath" and "keydbpath" should contain the path to the client's
892 * certificate and key databases respectively. Either the path to the
893 * directory containing "default name" databases (i.e. cert7.db and key3.db)
894 * can be specified or the actual filenames can be included.
895 * If any of these parameters is NULL, the function will assume the database
896 * is the same used by Netscape Communicator, which is usually under
897 * ~/.netsca /)
898 *
899 * "referralsp" is a pointer to a list of referrals the server might
900 * eventually send back with an LDAP_REFERRAL result code.
901 *
902 */
903
904 int
905 LDAP_CALL
ldapssl_tls_start_s(LDAP * ld,int defsecure,char * certdbpath,char * keydbpath,char *** referralsp)906 ldapssl_tls_start_s(LDAP *ld,int defsecure, char *certdbpath, char *keydbpath,
907 char ***referralsp)
908 {
909 int rc, resultCode, msgid;
910 char *extresp_oid;
911 BerValue *extresp_data;
912 LDAPMessage *res;
913
914 rc = ldapssl_tls_start( ld, &msgid );
915 if ( rc != LDAP_SUCCESS ) {
916 return rc;
917 }
918
919 rc = ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res );
920 if ( rc != LDAP_RES_EXTENDED ) {
921
922 /* the first response received must be an extended response to an
923 Start TLS request */
924
925 ldap_msgfree( res );
926 return( -1 );
927
928 }
929
930 rc = ldap_parse_extended_result( ld, res, &extresp_oid, &extresp_data, 0 );
931
932 if ( rc != LDAP_SUCCESS ) {
933 ldap_msgfree( res );
934 return rc;
935 }
936
937 if ( strcasecmp( extresp_oid, START_TLS_OID ) != 0 ) {
938
939 /* the extended response received doesn't correspond to the
940 Start TLS request */
941
942 ldap_msgfree( res );
943 return -1;
944 }
945
946 resultCode = ldap_get_lderrno( ld, NULL, NULL );
947
948 /* Analyze the server's response */
949 switch (resultCode) {
950 case LDAP_REFERRAL:
951 {
952 rc = ldap_parse_result( ld, res, NULL, NULL, NULL, referralsp, NULL, 0 );
953 if ( rc != LDAP_SUCCESS ) {
954 ldap_msgfree( res );
955 return rc;
956 }
957 }
958 case LDAP_OPERATIONS_ERROR:
959
960 case LDAP_PROTOCOL_ERROR:
961
962 case LDAP_UNAVAILABLE:
963 goto free_msg_and_return;
964 case LDAP_SUCCESS:
965 {
966 /*
967 * If extended response successfull, get connection ready for
968 * communicating with the server over SSL/TLS.
969 */
970
971 if ( ldapssl_enableSSL_on_open_connection( ld, defsecure,
972 certdbpath, keydbpath ) < 0 ) {
973 resultCode = -1;
974 }
975
976 } /* case LDAP_SUCCESS */
977 default:
978 goto free_msg_and_return;
979 } /* switch */
980
981 free_msg_and_return:
982 ldap_msgfree( res );
983 return resultCode;
984 }
985
986 #endif /* NET_SSL */
987