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 return NSS_SetDomesticPolicy() ? PR_FAILURE : PR_SUCCESS;
160 }
161
162
163
164 static void
ldapssl_basic_init(void)165 ldapssl_basic_init( void )
166 {
167 #ifndef _SOLARIS_SDK
168 /*
169 * NSPR is initialized in .init on SOLARIS
170 */
171 /* PR_Init() must to be called before everything else... */
172 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
173 #endif
174
175 PR_SetConcurrency( 4 ); /* work around for NSPR 3.x I/O hangs */
176 }
177
178
179
180 /*
181 * Cover functions for malloc(), calloc(), strdup() and free() that are
182 * compatible with the NSS libraries (they seem to use the C runtime
183 * library malloc/free so these functions are quite simple right now).
184 */
185 static void *
ldapssl_malloc(size_t size)186 ldapssl_malloc( size_t size )
187 {
188 void *p;
189
190 p = malloc( size );
191 return p;
192 }
193
194
195 static void *
ldapssl_calloc(int nelem,size_t elsize)196 ldapssl_calloc( int nelem, size_t elsize )
197 {
198 void *p;
199
200 p = calloc( nelem, elsize );
201 return p;
202 }
203
204
205 static char *
ldapssl_strdup(const char * s)206 ldapssl_strdup( const char *s )
207 {
208 char *scopy;
209
210 if ( NULL == s ) {
211 scopy = NULL;
212 } else {
213 scopy = strdup( s );
214 }
215 return scopy;
216 }
217
218
219 static void
ldapssl_free(void ** pp)220 ldapssl_free( void **pp )
221 {
222 if ( NULL != pp && NULL != *pp ) {
223 free( (void *)*pp );
224 *pp = NULL;
225 }
226 }
227
228
229 #ifdef _SOLARIS_SDK
230 /*
231 * Disable strict fork detection of NSS library to allow safe fork of
232 * consumers. Otherwise NSS will not work after fork because it was not
233 * deinitialized before fork and there is no safe way how to do it after fork.
234 *
235 * Return values:
236 * 1 - DISABLED was already set, no modification to environment
237 * 0 - successfully modified environment, old value saved to enval if there
238 * was some
239 * -1 - setenv or strdup failed, the environment was left unchanged
240 *
241 */
242 static int
update_nss_strict_fork_env(char ** enval)243 update_nss_strict_fork_env(char **enval)
244 {
245 char *temps = getenv("NSS_STRICT_NOFORK");
246 if (temps == NULL) {
247 *enval = NULL;
248 } else if (strncmp(temps, "DISABLED", 9) == 0) {
249 /* Do not need to set as DISABLED, it is already set. */
250 *enval = NULL;
251 return (1);
252 } else {
253 if ((*enval = ldapssl_strdup(temps)) == NULL)
254 return (-1);
255 }
256 return (setenv("NSS_STRICT_NOFORK", "DISABLED", 1));
257 }
258
259 /*
260 * Reset environment variable NSS_STRICT_NOFORK to value before
261 * update_nss_strict_fork_env() call or remove it from environment if it did
262 * not exist.
263 * NSS_STRICT_NOFORK=DISABLED is needed only during NSS initialization to
264 * disable activation of atfork handler in NSS which is invalidating
265 * initialization in child process after fork.
266 */
267 static int
reset_nss_strict_fork_env(char * enval)268 reset_nss_strict_fork_env(char *enval)
269 {
270 if (enval != NULL) {
271 return (setenv("NSS_STRICT_NOFORK", enval, 1));
272 } else {
273 return (unsetenv("NSS_STRICT_NOFORK"));
274 }
275 }
276 #endif
277
278
279 static char *
buildDBName(const char * basename,const char * dbname)280 buildDBName(const char *basename, const char *dbname)
281 {
282 char *result;
283 PRUint32 len, pathlen, addslash;
284
285 if (basename)
286 {
287 if (( len = PL_strlen( basename )) > 3
288 && PL_strcasecmp( ".db", basename + len - 3 ) == 0 ) {
289 return (ldapssl_strdup(basename));
290 }
291
292 pathlen = len;
293 len = pathlen + PL_strlen(dbname) + 1;
294 addslash = ( pathlen > 0 &&
295 (( *(basename + pathlen - 1) != FILE_PATHSEP ) ||
296 ( *(basename + pathlen - 1) != '\\' )));
297
298 if ( addslash ) {
299 ++len;
300 }
301 if (( result = ldapssl_malloc( len )) != NULL ) {
302 PL_strcpy( result, basename );
303 if ( addslash ) {
304 *(result+pathlen) = FILE_PATHSEP; /* replaces '\0' */
305 ++pathlen;
306 }
307 PL_strcpy(result+pathlen, dbname);
308 }
309
310 }
311
312
313 return result;
314 }
315
316 char *
GetCertDBName(void * alias,int dbVersion)317 GetCertDBName(void *alias, int dbVersion)
318 {
319 char *source;
320 char dbname[128];
321
322 source = (char *)alias;
323
324 if (!source)
325 {
326 source = "";
327 }
328
329 sprintf(dbname, "cert%d.db",dbVersion);
330 return(buildDBName(source, dbname));
331
332
333 }
334
335 /*
336 * return database name by appending "dbname" to "path".
337 * this code doesn't need to be terribly efficient (not called often).
338 */
339 /* XXXceb this is the old function. To be removed eventually */
340 static char *
GetDBName(const char * dbname,const char * path)341 GetDBName(const char *dbname, const char *path)
342 {
343 char *result;
344 PRUint32 len, pathlen;
345 int addslash;
346
347 if ( dbname == NULL ) {
348 dbname = "";
349 }
350
351 if ((path == NULL) || (*path == 0)) {
352 result = ldapssl_strdup(dbname);
353 } else {
354 pathlen = PL_strlen(path);
355 len = pathlen + PL_strlen(dbname) + 1;
356 addslash = ( path[pathlen - 1] != '/' );
357 if ( addslash ) {
358 ++len;
359 }
360 if (( result = ldapssl_malloc( len )) != NULL ) {
361 PL_strcpy( result, path );
362 if ( addslash ) {
363 *(result+pathlen) = '/'; /* replaces '\0' */
364 ++pathlen;
365 }
366 PL_strcpy(result+pathlen, dbname);
367 }
368 }
369
370 return result;
371 }
372
373 /*
374 * Initialize ns/security so it can be used for SSL client authentication.
375 * It is safe to call this more than once.
376 *
377 * If needkeydb == 0, no key database is opened and SSL server authentication
378 * is supported but not client authentication.
379 *
380 * If "certdbpath" is NULL or "", the default cert. db is used (typically
381 * ~/.netscape/cert7.db).
382 *
383 * If "certdbpath" ends with ".db" (case-insensitive compare), then
384 * it is assumed to be a full path to the cert. db file; otherwise,
385 * it is assumed to be a directory that contains a file called
386 * "cert7.db" or "cert.db".
387 *
388 * If certdbhandle is non-NULL, it is assumed to be a pointer to a
389 * SECCertDBHandle structure. It is fine to pass NULL since this
390 * routine will allocate one for you (CERT_GetDefaultDB() can be
391 * used to retrieve the cert db handle).
392 *
393 * If "keydbpath" is NULL or "", the default key db is used (typically
394 * ~/.netscape/key3.db).
395 *
396 * If "keydbpath" ends with ".db" (case-insensitive compare), then
397 * it is assumed to be a full path to the key db file; otherwise,
398 * it is assumed to be a directory that contains a file called
399 * "key3.db"
400 *
401 * If certdbhandle is non-NULL< it is assumed to be a pointed to a
402 * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
403 * routine will allocate one for you (SECKEY_GetDefaultDB() can be
404 * used to retrieve the cert db handle).
405 */
406 int
407 LDAP_CALL
ldapssl_clientauth_init(const char * certdbpath,void * certdbhandle,const int needkeydb,const char * keydbpath,void * keydbhandle)408 ldapssl_clientauth_init( const char *certdbpath, void *certdbhandle,
409 const int needkeydb, const char *keydbpath, void *keydbhandle )
410
411 {
412 int rc;
413 #ifdef _SOLARIS_SDK
414 char *enval;
415 int rcenv = 0;
416 #endif
417
418 /*
419 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_clientauth_init\n",0 ,0 ,0);
420 */
421
422 mutex_lock(&inited_mutex);
423 if ( inited ) {
424 mutex_unlock(&inited_mutex);
425 return( 0 );
426 }
427
428 ldapssl_basic_init();
429
430 #ifdef _SOLARIS_SDK
431 if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
432 mutex_unlock(&inited_mutex);
433 return (-1);
434 }
435 #endif
436
437 /* Open the certificate database */
438 rc = NSS_Init(certdbpath);
439 #ifdef _SOLARIS_SDK
440 /* Error from NSS_Init() more important! */
441 if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
442 ldapssl_free(&enval);
443 mutex_unlock(&inited_mutex);
444 return (-1);
445 }
446 ldapssl_free(&enval);
447 #endif
448 if (rc != 0) {
449 if ((rc = PR_GetError()) >= 0)
450 rc = -1;
451 mutex_unlock(&inited_mutex);
452 return (rc);
453 }
454
455 if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
456 || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
457 if (( rc = PR_GetError()) >= 0 ) {
458 rc = -1;
459 }
460 mutex_unlock(&inited_mutex);
461 return( rc );
462 }
463
464
465
466 if (local_SSLPLCY_Install() == PR_FAILURE) {
467 mutex_unlock(&inited_mutex);
468 return( -1 );
469 }
470
471 inited = 1;
472 mutex_unlock(&inited_mutex);
473
474 return( 0 );
475
476 }
477
478 /*
479 * Initialize ns/security so it can be used for SSL client authentication.
480 * It is safe to call this more than once.
481 *
482 * If needkeydb == 0, no key database is opened and SSL server authentication
483 * is supported but not client authentication.
484 *
485 * If "certdbpath" is NULL or "", the default cert. db is used (typically
486 * ~/.netscape/cert7.db).
487 *
488 * If "certdbpath" ends with ".db" (case-insensitive compare), then
489 * it is assumed to be a full path to the cert. db file; otherwise,
490 * it is assumed to be a directory that contains a file called
491 * "cert7.db" or "cert.db".
492 *
493 * If certdbhandle is non-NULL, it is assumed to be a pointer to a
494 * SECCertDBHandle structure. It is fine to pass NULL since this
495 * routine will allocate one for you (CERT_GetDefaultDB() can be
496 * used to retrieve the cert db handle).
497 *
498 * If "keydbpath" is NULL or "", the default key db is used (typically
499 * ~/.netscape/key3.db).
500 *
501 * If "keydbpath" ends with ".db" (case-insensitive compare), then
502 * it is assumed to be a full path to the key db file; otherwise,
503 * it is assumed to be a directory that contains a file called
504 * "key3.db"
505 *
506 * If certdbhandle is non-NULL< it is assumed to be a pointed to a
507 * SECKEYKeyDBHandle structure. It is fine to pass NULL since this
508 * routine will allocate one for you (SECKEY_GetDefaultDB() can be
509 * used to retrieve the cert db handle). */
510 int
511 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)512 ldapssl_advclientauth_init(
513 const char *certdbpath, void *certdbhandle,
514 const int needkeydb, const char *keydbpath, void *keydbhandle,
515 const int needsecmoddb, const char *secmoddbpath,
516 const int sslstrength )
517 {
518 int rc;
519 #ifdef _SOLARIS_SDK
520 char *enval;
521 int rcenv = 0;
522 #endif
523
524 mutex_lock(&inited_mutex);
525 if ( inited ) {
526 mutex_unlock(&inited_mutex);
527 return( 0 );
528 }
529
530 /*
531 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_advclientauth_init\n",0 ,0 ,0);
532 */
533
534 ldapssl_basic_init();
535
536 #ifdef _SOLARIS_SDK
537 if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
538 mutex_unlock(&inited_mutex);
539 return (-1);
540 }
541 #endif
542
543 rc = NSS_Init(certdbpath);
544 #ifdef _SOLARIS_SDK
545 /* Error from NSS_Init() more important! */
546 if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
547 ldapssl_free(&enval);
548 mutex_unlock(&inited_mutex);
549 return (-1);
550 }
551 ldapssl_free(&enval);
552 #endif
553 if (rc != 0) {
554 if ((rc = PR_GetError()) >= 0)
555 rc = -1;
556 mutex_unlock(&inited_mutex);
557 return (rc);
558 }
559
560 if (local_SSLPLCY_Install() == PR_FAILURE) {
561 mutex_unlock(&inited_mutex);
562 return( -1 );
563 }
564
565 inited = 1;
566 mutex_unlock(&inited_mutex);
567
568 return( ldapssl_set_strength( NULL, sslstrength));
569
570 }
571
572
573 /*
574 * Initialize ns/security so it can be used for SSL client authentication.
575 * It is safe to call this more than once.
576 */
577
578 /*
579 * XXXceb This is a hack until the new IO functions are done.
580 * this function lives in ldapsinit.c
581 */
582 void set_using_pkcs_functions( int val );
583
584 int
585 LDAP_CALL
ldapssl_pkcs_init(const struct ldapssl_pkcs_fns * pfns)586 ldapssl_pkcs_init( const struct ldapssl_pkcs_fns *pfns )
587 {
588
589 char *certdbName, *s, *keydbpath;
590 char *certdbPrefix, *keydbPrefix;
591 char *confDir, *keydbName;
592 static char *secmodname = "secmod.db";
593 int rc;
594 #ifdef _SOLARIS_SDK
595 char *enval;
596 int rcenv = 0;
597 #endif
598
599 mutex_lock(&inited_mutex);
600 if ( inited ) {
601 mutex_unlock(&inited_mutex);
602 return( 0 );
603 }
604 /*
605 * XXXceb This is a hack until the new IO functions are done.
606 * this function MUST be called before ldap_enable_clienauth.
607 *
608 */
609 set_using_pkcs_functions( 1 );
610
611 /*
612 * LDAPDebug(LDAP_DEBUG_TRACE, "ldapssl_pkcs_init\n",0 ,0 ,0);
613 */
614
615
616 ldapssl_basic_init();
617
618 pfns->pkcs_getcertpath( NULL, &s);
619 confDir = ldapssl_strdup( s );
620 certdbPrefix = ldapssl_strdup( s );
621 certdbName = ldapssl_strdup( s );
622 *certdbPrefix = 0;
623 splitpath(s, confDir, certdbPrefix, certdbName);
624
625 pfns->pkcs_getkeypath( NULL, &s);
626 keydbpath = ldapssl_strdup( s );
627 keydbPrefix = ldapssl_strdup( s );
628 keydbName = ldapssl_strdup( s );
629 *keydbPrefix = 0;
630 splitpath(s, keydbpath, keydbPrefix, keydbName);
631
632
633 /* verify confDir == keydbpath and adjust as necessary */
634 ldapssl_free((void **)&certdbName);
635 ldapssl_free((void **)&keydbName);
636 ldapssl_free((void **)&keydbpath);
637
638 #ifdef _SOLARIS_SDK
639 if ((rcenv = update_nss_strict_fork_env(&enval)) == -1) {
640 mutex_unlock(&inited_mutex);
641 return (-1);
642 }
643 #endif
644
645 rc = NSS_Initialize(confDir,certdbPrefix,keydbPrefix,secmodname,
646 NSS_INIT_READONLY);
647
648 ldapssl_free((void **)&certdbPrefix);
649 ldapssl_free((void **)&keydbPrefix);
650 ldapssl_free((void **)&confDir);
651
652 #ifdef _SOLARIS_SDK
653 /* Error from NSS_Initialize() more important! */
654 if ((rcenv != 1) && (reset_nss_strict_fork_env(enval) != 0) && (rc == 0)) {
655 ldapssl_free(&enval);
656 mutex_unlock(&inited_mutex);
657 return (-1);
658 }
659 ldapssl_free(&enval);
660 #endif
661
662 if (rc != 0) {
663 if ((rc = PR_GetError()) >= 0)
664 rc = -1;
665 mutex_unlock(&inited_mutex);
666 return (rc);
667 }
668
669
670 #if 0 /* UNNEEDED BY LIBLDAP */
671 /* this is odd */
672 PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
673 #endif /* UNNEEDED BY LIBLDAP */
674
675 if (SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE)
676 || SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_TRUE)) {
677 if (( rc = PR_GetError()) >= 0 ) {
678 rc = -1;
679 }
680
681 mutex_unlock(&inited_mutex);
682 return( rc );
683 }
684
685 if (local_SSLPLCY_Install() == PR_FAILURE) {
686 mutex_unlock(&inited_mutex);
687 return( -1 );
688 }
689
690 inited = 1;
691
692 if ( certdbName != NULL ) {
693 ldapssl_free((void **) &certdbName );
694 }
695
696 return( ldapssl_set_strength( NULL, LDAPSSL_AUTH_CNCHECK));
697 }
698
699
700 /*
701 * ldapssl_client_init() is a server-authentication only version of
702 * ldapssl_clientauth_init().
703 */
704 int
705 LDAP_CALL
ldapssl_client_init(const char * certdbpath,void * certdbhandle)706 ldapssl_client_init(const char* certdbpath, void *certdbhandle )
707 {
708 return( ldapssl_clientauth_init( certdbpath, certdbhandle,
709 0, NULL, NULL ));
710 }
711 /*
712 * ldapssl_serverauth_init() is a server-authentication only version of
713 * ldapssl_clientauth_init(). This function allows the sslstrength
714 * to be passed in. The sslstrength can take one of the following
715 * values:
716 * LDAPSSL_AUTH_WEAK: indicate that you accept the server's
717 * certificate without checking the CA who
718 * issued the certificate
719 * LDAPSSL_AUTH_CERT: indicates that you accept the server's
720 * certificate only if you trust the CA who
721 * issued the certificate
722 * LDAPSSL_AUTH_CNCHECK:
723 indicates that you accept the server's
724 * certificate only if you trust the CA who
725 * issued the certificate and if the value
726 * of the cn attribute in the DNS hostname
727 * of the server
728 */
729 int
730 LDAP_CALL
ldapssl_serverauth_init(const char * certdbpath,void * certdbhandle,const int sslstrength)731 ldapssl_serverauth_init(const char* certdbpath,
732 void *certdbhandle,
733 const int sslstrength )
734 {
735 if ( ldapssl_set_strength( NULL, sslstrength ) != 0) {
736 return ( -1 );
737 }
738
739 return( ldapssl_clientauth_init( certdbpath, certdbhandle,
740 0, NULL, NULL ));
741 }
742
743 /*
744 * Function that makes an asynchronous Start TLS extended operation request.
745 */
ldapssl_tls_start(LDAP * ld,int * msgidp)746 static int ldapssl_tls_start(LDAP *ld, int *msgidp)
747 {
748 int version, rc;
749 BerValue extreq_data;
750
751 /* Start TLS extended operation requires an absent "requestValue" field. */
752
753 extreq_data.bv_val = NULL;
754 extreq_data.bv_len = 0;
755
756 /* Make sure version is set to LDAPv3 for extended operations to be
757 supported. */
758
759 version = LDAP_VERSION3;
760 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
761
762 /* Send the Start TLS request (OID: 1.3.6.1.4.1.1466.20037) */
763 rc = ldap_extended_operation( ld, START_TLS_OID, &extreq_data,
764 NULL, NULL, msgidp );
765
766 return rc;
767 }
768
769
770 /*
771 * Function that enables SSL on an already open non-secured LDAP connection.
772 * (i.e. the connection is henceforth secured)
773 */
ldapssl_enableSSL_on_open_connection(LDAP * ld,int defsecure,char * certdbpath,char * keydbpath)774 static int ldapssl_enableSSL_on_open_connection(LDAP *ld, int defsecure,
775 char *certdbpath, char *keydbpath)
776 {
777 PRLDAPSocketInfo soi;
778
779
780 if ( ldapssl_clientauth_init( certdbpath, NULL, 1, keydbpath, NULL ) < 0 ) {
781 goto ssl_setup_failure;
782 }
783
784 /*
785 * Retrieve socket info. so we have the PRFileDesc.
786 */
787 memset( &soi, 0, sizeof(soi));
788 soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE;
789 if ( prldap_get_default_socket_info( ld, &soi ) < 0 ) {
790 goto ssl_setup_failure;
791 }
792
793 if ( ldapssl_install_routines( ld ) < 0 ) {
794 goto ssl_setup_failure;
795 }
796
797
798 if (soi.soinfo_prfd == NULL) {
799 int sd;
800 ldap_get_option( ld, LDAP_OPT_DESC, &sd );
801 soi.soinfo_prfd = (PRFileDesc *) PR_ImportTCPSocket( sd );
802 }
803 /* set the socket information back into the connection handle,
804 * because ldapssl_install_routines() resets the socket_arg info in the
805 * socket buffer. */
806 if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) {
807 goto ssl_setup_failure;
808 }
809
810 if ( ldap_set_option( ld, LDAP_OPT_SSL,
811 defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) < 0 ) {
812 goto ssl_setup_failure;
813 }
814
815 if ( ldapssl_import_fd( ld, defsecure ) < 0 ) {
816 goto ssl_setup_failure;
817 }
818
819 return 0;
820
821 ssl_setup_failure:
822 ldapssl_reset_to_nonsecure( ld );
823
824 /* we should here warn the server that we switch back to a non-secure
825 connection */
826
827 return( -1 );
828 }
829
830
831 /*
832 * ldapssl_tls_start_s() performs a synchronous Start TLS extended operation
833 * request.
834 *
835 * The function returns the result code of the extended operation response
836 * sent by the server.
837 *
838 * In case of a successfull response (LDAP_SUCCESS returned), by the time
839 * this function returns the LDAP session designed by ld will have been
840 * secured, i.e. the connection will have been imported into SSL.
841 *
842 * Should the Start TLS request be rejected by the server, the result code
843 * returned will be one of the following:
844 * LDAP_OPERATIONS_ERROR,
845 * LDAP_PROTOCOL_ERROR,
846 * LDAP_REFERRAL,
847 * LDAP_UNAVAILABLE.
848 *
849 * Any other error code returned will be due to a failure in the course
850 * of operations done on the client side.
851 *
852 * "certdbpath" and "keydbpath" should contain the path to the client's
853 * certificate and key databases respectively. Either the path to the
854 * directory containing "default name" databases (i.e. cert7.db and key3.db)
855 * can be specified or the actual filenames can be included.
856 * If any of these parameters is NULL, the function will assume the database
857 * is the same used by Netscape Communicator, which is usually under
858 * ~/.netsca /)
859 *
860 * "referralsp" is a pointer to a list of referrals the server might
861 * eventually send back with an LDAP_REFERRAL result code.
862 *
863 */
864
865 int
866 LDAP_CALL
ldapssl_tls_start_s(LDAP * ld,int defsecure,char * certdbpath,char * keydbpath,char *** referralsp)867 ldapssl_tls_start_s(LDAP *ld,int defsecure, char *certdbpath, char *keydbpath,
868 char ***referralsp)
869 {
870 int rc, resultCode, msgid;
871 char *extresp_oid;
872 BerValue *extresp_data;
873 LDAPMessage *res;
874
875 rc = ldapssl_tls_start( ld, &msgid );
876 if ( rc != LDAP_SUCCESS ) {
877 return rc;
878 }
879
880 rc = ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res );
881 if ( rc != LDAP_RES_EXTENDED ) {
882
883 /* the first response received must be an extended response to an
884 Start TLS request */
885
886 ldap_msgfree( res );
887 return( -1 );
888
889 }
890
891 rc = ldap_parse_extended_result( ld, res, &extresp_oid, &extresp_data, 0 );
892
893 if ( rc != LDAP_SUCCESS ) {
894 ldap_msgfree( res );
895 return rc;
896 }
897
898 if ( strcasecmp( extresp_oid, START_TLS_OID ) != 0 ) {
899
900 /* the extended response received doesn't correspond to the
901 Start TLS request */
902
903 ldap_msgfree( res );
904 return -1;
905 }
906
907 resultCode = ldap_get_lderrno( ld, NULL, NULL );
908
909 /* Analyze the server's response */
910 switch (resultCode) {
911 case LDAP_REFERRAL:
912 {
913 rc = ldap_parse_result( ld, res, NULL, NULL, NULL, referralsp, NULL, 0 );
914 if ( rc != LDAP_SUCCESS ) {
915 ldap_msgfree( res );
916 return rc;
917 }
918 }
919 case LDAP_OPERATIONS_ERROR:
920
921 case LDAP_PROTOCOL_ERROR:
922
923 case LDAP_UNAVAILABLE:
924 goto free_msg_and_return;
925 case LDAP_SUCCESS:
926 {
927 /*
928 * If extended response successfull, get connection ready for
929 * communicating with the server over SSL/TLS.
930 */
931
932 if ( ldapssl_enableSSL_on_open_connection( ld, defsecure,
933 certdbpath, keydbpath ) < 0 ) {
934 resultCode = -1;
935 }
936
937 } /* case LDAP_SUCCESS */
938 default:
939 goto free_msg_and_return;
940 } /* switch */
941
942 free_msg_and_return:
943 ldap_msgfree( res );
944 return resultCode;
945 }
946
947 #endif /* NET_SSL */
948