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