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 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 157 static PRStatus local_SSLPLCY_Install(void) 158 { 159 return NSS_SetDomesticPolicy() ? PR_FAILURE : PR_SUCCESS; 160 } 161 162 163 164 static 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 * 186 ldapssl_malloc( size_t size ) 187 { 188 void *p; 189 190 p = malloc( size ); 191 return p; 192 } 193 194 195 static void * 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 * 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 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 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 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 * 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 * 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 * 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 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 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 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 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 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 */ 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 */ 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 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