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 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 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 * 195 ldapssl_malloc( size_t size ) 196 { 197 void *p; 198 199 p = malloc( size ); 200 return p; 201 } 202 203 204 static void * 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 * 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 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 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 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 * 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 * 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 * 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 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 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 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 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 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 */ 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 */ 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 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