xref: /onnv-gate/usr/src/lib/libkmsagent/common/KMSClientProfile.cpp (revision 12720:3db6e0082404)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <stdio.h>
27 #include <errno.h>
28 
29 #if !defined(UNIX) && !defined(METAWARE)
30 #include "KMSAgent_direct.h"
31 #endif
32 
33 #include <string.h>
34 
35 #include "KMSClientProfile.h"
36 
37 #include "KMSAgent.h"
38 #include "KMS_CAStub.h"
39 #include "KMS_CertificateStub.h"
40 #include "KMS_DiscoveryStub.h"
41 #include "KMSClientProfileImpl.h"
42 #include "KMSAuditLogger.h"
43 #include "KMSAgentSoapUtilities.h"
44 #include "KMSAgentStringUtilities.h"
45 
46 
47 #include "KMSAgentPKICommon.h" // must be before agentstorage
48 
49 #include "stdsoap2.h"
50 #include "KMSAgentStorage.h"   // uses KMSClientProfile
51 
52 
53 #include "KMSAgentWebServiceNamespaces.h"
54 #include "k_setupssl.h"
55 #include "KMSAgentChallenge.h"
56 #include "KMSAgentCryptoUtilities.h"
57 #include "ApplianceParameters.h"
58 #include "AutoMutex.h"
59 
60 #include "KMSAgentLoadBalancer.h"
61 #include "KMSAgentDataUnitCache.h"
62 
63 #include "ClientSoapFaultCodes.h"
64 #ifdef METAWARE
65 #include "debug.h"
66 #include "sizet.h"
67 typedef unsigned char		uint8_t;
68 typedef unsigned short		uint16_t;
69 typedef unsigned int		uint32_t;
70 typedef unsigned long long	uint64_t;
71 #include "literals.h"
72 #endif
73 #include "KMSAgentAESKeyWrap.h"
74 
75 #if defined(METAWARE) && defined(DEBUG)
76 #include "debug.h"
77 #endif
78 #include "KMSAuditLogger.h"
79 #include "KMSClientProfileImpl.h"
80 
81 #ifdef METAWARE
82 extern "C" void
83 tnMsg( const char   *format,
84        ... );
85 #endif
86 
87 bool g_bUseFileLog = false;
88 char g_wsWorkingDirectory[KMS_MAX_PATH_LENGTH+1] = "./";
89 
90 
InitializeLogging(const utf8cstr i_wsWorkingDirectory,int i_bUseFileLog)91 static bool InitializeLogging(
92    const utf8cstr  i_wsWorkingDirectory,
93    int i_bUseFileLog )
94 {
95    FATAL_ASSERT( !i_bUseFileLog || i_wsWorkingDirectory );
96 
97    bool bFileLogSuccess = true;
98 
99    g_bUseFileLog = ( i_bUseFileLog != 0 );
100 
101    // InitializeFileLogging must always be called,
102    // because the file is always used by FATALs.
103 
104    bFileLogSuccess = InitializeFileLogging( i_wsWorkingDirectory ) ? true:false;
105 
106    return bFileLogSuccess;
107 }
108 
FinalizeLogging()109 static void FinalizeLogging()
110 {
111    // FinalizeFileLogging must always be called,
112    // because the file is always used by FATALs.
113    FinalizeFileLogging();
114 
115    return;
116 }
117 
118 
119 
120 
121 /*---------------------------------------------------------------------------
122  * Function: KMSClient_InitializeLibrary
123  *
124  *--------------------------------------------------------------------------*/
125 
KMSClient_InitializeLibrary(const utf8cstr i_wsWorkingDirectory,int i_bUseFileLog)126 bool KMSClient_InitializeLibrary(
127    const utf8cstr  i_wsWorkingDirectory,
128    int i_bUseFileLog)
129 {
130    bool bSuccess;
131 
132 #if defined(DEBUG) && defined(METAWARE)
133    log_printf("KMSClient_InitializeLibrary : ENTERING");
134 #endif
135 
136    // setup SSL
137    bSuccess = K_SetupSSL() == 1;
138    if(!bSuccess)
139    {
140       return false;
141    }
142 
143 #if defined(DEBUG) && defined(METAWARE)
144    log_printf("KMSClient_InitializeLibrary : set current directory");
145 #endif
146 
147    // if i_wsWorkingDirectory is null, caller means current directory
148    if ( i_wsWorkingDirectory != NULL )
149    {
150 #if defined(DEBUG) && defined(METAWARE)
151       log_printf("KMSClient_InitializeLibrary : check working directory");
152 #endif
153 
154       // string is there but is empty or junk
155       if (strlen(i_wsWorkingDirectory) <= 0)
156       {
157          strcpy(i_wsWorkingDirectory, ".");
158       }
159 
160       if ( strlen(i_wsWorkingDirectory) >= KMS_MAX_PATH_LENGTH )
161       {
162          return false;
163       }
164 
165 #if defined(DEBUG) && defined(METAWARE)
166       log_printf("KMSClient_InitializeLibrary : set global working directory");
167 #endif
168 
169       // set global working directory to input
170       strncpy(g_wsWorkingDirectory,
171               i_wsWorkingDirectory,
172               KMS_MAX_PATH_LENGTH);
173       g_wsWorkingDirectory[KMS_MAX_PATH_LENGTH] = 0;
174    }
175    else
176    {
177       strcpy(g_wsWorkingDirectory, ".");
178    }
179 
180 #if defined(DEBUG) && defined(METAWARE)
181    log_printf("KMSClient_InitializeLibrary : Initialize logging");
182 #endif
183 
184    // initialize file logging
185    bSuccess = InitializeLogging( g_wsWorkingDirectory,
186                                  i_bUseFileLog);
187 
188    return bSuccess;
189 }
190 
191 
192 /*---------------------------------------------------------------------------
193  * Function: KMSClient_FinalizeLibrary
194  *--------------------------------------------------------------------------*/
KMSClient_FinalizeLibrary()195 bool KMSClient_FinalizeLibrary()
196 {
197 #if defined(DEBUG) && defined(METAWARE)
198    log_printf("KMSClient_FinalizeLibrary : ENTERING");
199 #endif
200 
201    K_CleanupSSL();
202 
203    FinalizeLogging();
204 
205    return true; /* always */
206 }
207 
208 
209 int LogError_lastErrno;
210 
211 
212 /**
213  * Construct a message for the KMSAuditLogger and store the message
214  *  in the profile as the last error message.
215  */
LogError_function(KMSClientProfile * i_pProfile,int i_iErrno,const char * i_sOperation,const char * i_sEntityID,const char * i_sNetworkAddress,const char * i_sMessage)216 void LogError_function(KMSClientProfile *i_pProfile,
217                        int i_iErrno,
218                        const char* i_sOperation,
219                        const char* i_sEntityID,
220                        const char* i_sNetworkAddress,
221                        const char* i_sMessage )
222 {
223    FATAL_ASSERT( i_pProfile && i_sOperation );
224 
225    // save for caller's use - this shouldn't be a global, but I don't
226    // want this as an item in the profile as I don't want it persisted
227    LogError_lastErrno = i_iErrno;
228 
229    // log the message to a data file (and internal logs)
230 #ifndef METAWARE
231    if ( g_bUseFileLog )
232 #endif
233    {
234       Log_function(i_iErrno,
235                    i_sOperation,
236                    i_sEntityID,
237                    i_sNetworkAddress,
238                    i_sMessage);
239    }
240 
241 #ifdef METAWARE
242    /* print this to the T10000/9840 VOP */
243    /* NOTE the \n is important to VOP - leave it in */
244    tnMsg("`msg`KMS2.0:msg#=%i,op=%s\r\n",
245          i_iErrno,
246          i_sOperation);
247 
248    tnMsg("`msg`msg=%s,eid=%s,addr=%s\r\n",
249          i_sMessage,
250          i_sEntityID,
251          i_sNetworkAddress);
252 
253 #endif
254 
255    // copy the error message into the profile (for later reference)
256    strncpy(i_pProfile->m_wsErrorString,
257            i_sOperation,
258            KMS_MAX_ERROR_STRING);
259 
260    // make sure to NUL out the end
261    i_pProfile->m_wsErrorString[KMS_MAX_ERROR_STRING] = 0;
262 
263    if ( i_sEntityID )
264    {
265       strncat(i_pProfile->m_wsErrorString,
266               i_sEntityID,
267               KMS_MAX_ERROR_STRING);
268    }
269 
270    if ( i_sNetworkAddress )
271    {
272       strncat(i_pProfile->m_wsErrorString,
273               ",Address=",
274               KMS_MAX_ERROR_STRING);
275       strncat(i_pProfile->m_wsErrorString,
276               i_sNetworkAddress,
277               KMS_MAX_ERROR_STRING);
278    }
279 
280    if ( i_sMessage )
281    {
282       strncat(i_pProfile->m_wsErrorString,
283               ",Msg=",
284               KMS_MAX_ERROR_STRING);
285       strncat(i_pProfile->m_wsErrorString,
286               i_sMessage,
287               KMS_MAX_ERROR_STRING);
288    }
289 
290    // make sure to NUL out the end
291    i_pProfile->m_wsErrorString[KMS_MAX_ERROR_STRING] = 0;
292 
293 }
294 
295 // see KMSClientProfileImpl.h
SSL_InvalidCertificate(const char * const i_sErrorString)296 bool SSL_InvalidCertificate (const char * const i_sErrorString)
297 {
298     if (
299         // OpenSSL generates this msg
300         strstr(i_sErrorString, "sslv3 alert certificate unknown"))
301     {
302         return true;
303     }
304     return false;
305 
306 }
307 
308 // see KMSClientProfileImpl.h
ServerError(const char * i_sErrorString,int i_iErrno)309 bool ServerError (const char * i_sErrorString, int i_iErrno )
310 {
311     // The Client Soap Fault Code returned by the KMA
312     // may be at the start of i_sErrorString or immediately
313     // follwing "SoapFaultString=" depending on the caller's
314     // string
315 
316     int iErrorCode;
317 
318     const char* sFaultstringStart  = strstr(i_sErrorString, "SoapFaultString=" );
319     if ( sFaultstringStart )
320     {
321         iErrorCode = GET_FAULT_CODE( sFaultstringStart + strlen("SoapFaultString=") );
322     }
323     else
324     {
325         // This may be zero if there is no error code at the start of the string.
326         iErrorCode = GET_FAULT_CODE( i_sErrorString );
327     }
328 
329     // the following is commented out so the former check can be observed.  This check is no longer
330     // made since invalid certificate failures may be due to a KMA that is behind on
331     // replication updates hence failover would succeed.
332 //    if (
333 //            // OpenSSL generates this msg
334 //            SSL_InvalidCertificate(i_sErrorString))
335 //    {
336 //        return false;
337 //    }
338 
339     if (
340        // when the KMA is locked
341        iErrorCode == CLIENT_ERROR_AGENT_APPLIANCE_LOCKED
342 
343        // KMS 2.2 change when the KMA is locked
344        || iErrorCode == CLIENT_ERROR_MANAGER_APPLIANCE_LOCKED
345 
346        // KMS 2.2 change for core security internal error
347        || iErrorCode == CLIENT_ERROR_MANAGER_INTERNAL
348 
349        // if the KMA's pre-gen'd key pool is depleted
350        || iErrorCode == CLIENT_ERROR_AGENT_NO_READY_KEYS
351 
352        // if the KMA's HSM is broke and the KMA is in FIPS mode
353        || iErrorCode == CLIENT_ERROR_SERVER_HSM_REQUIRED_BUT_MISSING
354 
355        // when the server is too slow
356        || NULL != strstr( i_sErrorString, "Timeout" )
357        || NULL != strstr( i_sErrorString, "Operation interrupted or timed out" )
358 
359        // The Appliance is powered down, or is not reachable
360        || NULL != strstr( i_sErrorString, "Connection refused" )
361 
362        || NULL != strstr( i_sErrorString, "Unknown error" )
363 
364        // SOAP EOF
365        || NULL != strstr( i_sErrorString, "End of file or no input:" )
366 
367        // Appliance server software is not running (while Appliance machine is OK)
368        || NULL != strstr( i_sErrorString, "connect failed in tcp_connect()" )
369 
370        // If the server has an internal error but still responds
371        || NULL != strstr( i_sErrorString, "Server Error" )
372 
373        // OpenSSL protocol errors (Note: the SSL_ERROR_SSL may be due
374        // to invalid client-side values, but for now it's used as a
375        // catch-all; a side-effect is that any actual invalid client-side
376        // value will cause one audit log entry to be created on each
377        // Appliance in the cluster).
378        || NULL != strstr( i_sErrorString,
379                        "Error observed by underlying BIO: No error" )
380        || NULL != strstr( i_sErrorString,
381                           "EOF was observed that violates the protocol" )
382        || NULL != strstr( i_sErrorString,
383                           "SSL_ERROR_SSL" ) )
384     {
385         return true;
386     }
387 
388 #ifndef WIN32
389 	// check for errno values that imply connection problems to the server
390     switch (i_iErrno)
391     {
392         case ECONNABORTED : return true; // Connection aborted.
393         case ECONNREFUSED : return true; // Connection refused.
394         case ECONNRESET :   return true; // Connection reset.
395         case EHOSTUNREACH : return true; // Host is unreachable.
396         case ENETDOWN :     return true; // Network is down.
397         case ENETRESET :    return true; // Connection aborted by network.
398         case ENETUNREACH :  return true; // Network unreachable.
399         case ENOPROTOOPT :  return true; // Protocol not available.
400 #ifndef METAWARE
401         case ETIME :        return true; // Stream ioctl() timeout.
402 #endif
403         case ETIMEDOUT :    return true; // Connection timed out.
404     }
405 #endif
406     // at this point we conclude its a client side issue
407     return false;
408 }
409 
410 /*---------------------------------------------------------------------------
411  * Function: KMSClient_GetLastErrorMessage
412  *
413  *--------------------------------------------------------------------------*/
414 
415 // extern "C"
KMSClient_GetLastErrorMessage(KMSClientProfile * i_pProfile)416 utf8char * KMSClient_GetLastErrorMessage(KMSClientProfile *i_pProfile)
417 {
418    FATAL_ASSERT(i_pProfile);
419 
420    CAutoMutex oAutoMutex( 0 );
421    if ( i_pProfile->m_pLock )
422    {
423       oAutoMutex.Lock( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
424    }
425 
426    return i_pProfile->m_wsErrorString;
427 }
428 
429 
430 /*---------------------------------------------------------------------------
431  * Function: KMSClient_RetrieveEntityCertificate
432  * Get the Root CA Certificate and store it into the profile
433  *--------------------------------------------------------------------------*/
KMSClient_RetrieveEntityCertificate(KMSClientProfile * i_pProfile,utf8cstr i_wsEntityID,utf8cstr i_wsPassphrase,char * const o_sHexHashedPassphrase)434 static bool KMSClient_RetrieveEntityCertificate(
435    KMSClientProfile* i_pProfile,
436    utf8cstr  i_wsEntityID,
437    utf8cstr  i_wsPassphrase,
438    char* const o_sHexHashedPassphrase )
439 {
440    FATAL_ASSERT( i_pProfile && i_wsEntityID && i_wsPassphrase );
441 
442 #if defined(DEBUG) && defined(METAWARE)
443     log_printf("KMSClient_RetrieveEntityCertificate : entered");
444 #endif
445 
446    CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
447    char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH];
448    char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH];
449 
450    strcpy(o_sHexHashedPassphrase, "");
451 
452    bool bSuccess = true;
453    bool bTryFailOver = false;
454 
455    struct soap *pstCASoap;
456    pstCASoap = (struct soap *) malloc( sizeof(struct soap) );
457    if(pstCASoap == NULL)
458    {
459 #if defined(DEBUG) && defined(METAWARE)
460       log_printf("Malloc %x pstCASoap returned null\n", sizeof(struct soap));
461 #endif
462       LogError(i_pProfile,
463                LoadProfile_AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_SOAP_ERROR,
464                NULL,
465                NULL,
466                "malloc failure for pstCASoap" );
467       return false;
468    }
469 
470    // initialize the SOAP connection that will get the RootCA
471    soap_init2( pstCASoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING), (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
472 
473 #ifdef METAWARE
474    K_SetupCallbacks ( pstCASoap );
475 #endif
476 
477    CCertificate* pRootCACertificate = 0;
478    CCertificate* pEntityCertificate = 0;
479    CPrivateKey*  pEntityPrivateKey = 0;
480 
481    soap_set_namespaces( pstCASoap, KMS_CA_namespaces );
482 
483    pstCASoap->connect_timeout = i_pProfile->m_iTransactionTimeout;
484    pstCASoap->send_timeout    = i_pProfile->m_iTransactionTimeout;
485    pstCASoap->recv_timeout    = i_pProfile->m_iTransactionTimeout;
486 
487    struct soap *pstCertificateSoap;
488 
489    pstCertificateSoap = (struct soap *) malloc( sizeof(struct soap) );
490 
491    if(pstCertificateSoap == NULL)
492    {
493 #if defined(METAWARE)
494       log_printf("Malloc %x pstCertificateSoap returned null\n",
495                  sizeof(struct soap));
496 #endif
497       soap_free( pstCASoap );
498       free(pstCASoap);
499       return false;
500    }
501 
502    // initialize the SOAP connection that will get the Certificate
503    soap_init2( pstCertificateSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING), (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
504 
505 #ifdef METAWARE
506    K_SetupCallbacks ( pstCertificateSoap );
507 #endif
508 
509    soap_set_namespaces( pstCertificateSoap, KMS_Certificate_namespaces );
510 
511    pstCertificateSoap->connect_timeout = i_pProfile->m_iTransactionTimeout;
512    pstCertificateSoap->send_timeout = i_pProfile->m_iTransactionTimeout;
513    pstCertificateSoap->recv_timeout = i_pProfile->m_iTransactionTimeout;
514 
515    CAgentLoadBalancer oLoadBalancer(i_pProfile);
516    int iIndex = oLoadBalancer.Balance();
517 
518 #if defined(DEBUG) && defined(METAWARE)
519    log_printf("KMSClient_RetrieveEntityCertificate : call KMS_CA__RetrieveRootCACertificate");
520 #endif
521 
522    // get the server's URL that will provide SOAP services
523    do
524    {
525       bSuccess = true;
526       bTryFailOver = false;
527       bool bFailedOnRetrieveRootCA = false;
528       const char* sURL = 0;
529 
530       if ( bSuccess )
531       {
532          sURL = oLoadBalancer.GetHTTPURL(iIndex,
533                                          i_pProfile->m_iPortForCAService);
534 
535          if ( !sURL )
536          {
537             bSuccess = false;
538          }
539       }
540 
541       if ( bSuccess )
542       {
543          strncpy(i_pProfile->m_sURL, sURL, KMS_MAX_URL);
544          i_pProfile->m_sURL[KMS_MAX_URL] = 0;
545       }
546 
547 
548       // SOAP CALL -  retrieve Root CA Certificate from the Server
549       struct KMS_CA::
550          KMS_CA__RetrieveRootCACertificateResponse stRootCACertificateResponse;
551 
552       if ( bSuccess )
553       {
554 #if defined(DEBUG) && defined(METAWARE)
555          log_printf("KMSClient_RetrieveCertificate : call KMS_CA__RetrieveRootCACertificate again");
556 #endif
557          bSuccess =
558             KMS_CA::soap_call_KMS_CA__RetrieveRootCACertificate(
559                pstCASoap,
560                i_pProfile->m_sURL,
561                NULL,
562                i_wsEntityID,
563                stRootCACertificateResponse ) == SOAP_OK;
564 
565          if ( !bSuccess )
566          {
567             GetSoapFault(sSoapFaultMsg, (struct soap*)pstCASoap);
568             GetPeerNetworkAddress(sKmaAddress, pstCASoap);
569             LogError(i_pProfile,
570                      LoadProfile_AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_SOAP_ERROR,
571                      NULL,
572                      sKmaAddress,
573                      sSoapFaultMsg );
574 
575             bTryFailOver = ServerError(GET_SOAP_FAULTSTRING(pstCASoap), pstCASoap->errnum);
576             bFailedOnRetrieveRootCA = true;
577          }
578       }
579 #if defined(DEBUG) && defined(METAWARE)
580       else
581       {
582          log_printf("!bSuccess 1\n");
583       }
584 #endif
585 
586 
587       // Validate the SOAP response
588       if ( bSuccess )
589       {
590          if ( stRootCACertificateResponse.RootCACertificate.__size < 1 ||
591               stRootCACertificateResponse.RootCACertificate.__ptr == NULL ||
592               stRootCACertificateResponse.AuthenticationHashIterationCount <
593               MIN_AUTHENTICATION_ITERATION_COUNT ||
594               stRootCACertificateResponse.AuthenticationHashIterationCount >
595                   MAX_AUTHENTICATION_ITERATION_COUNT ||
596               stRootCACertificateResponse.ClientAuthenticationChallenge.__size !=
597                   AUTHENTICATION_CHALLENGE_LENGTH ||
598               stRootCACertificateResponse.ClientAuthenticationChallenge.__ptr == NULL )
599          {
600             bSuccess = false;
601 
602             GetPeerNetworkAddress(sKmaAddress, pstCASoap);
603             LogError(i_pProfile,
604                      AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_INVALID_RESPONSE_FORMAT,
605                      NULL,
606                      sKmaAddress,
607                      NULL);
608          }
609          else
610          {
611             GetPeerNetworkAddress(sKmaAddress, pstCASoap);
612             Log(AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_SUCCESS,
613                  NULL,
614                  sKmaAddress,
615                  NULL);
616          }
617 
618       }
619 #if defined(DEBUG) && defined(METAWARE)
620       else
621       {
622          log_printf("!bSuccess 2\n");
623       }
624 #endif
625 
626       // build our RootCACertificate object
627       if ( bSuccess )
628       {
629          pRootCACertificate = new CCertificate;
630 
631          // make sure the new was successful
632          bSuccess = ( pRootCACertificate != 0 );
633       }
634 #if defined(DEBUG) && defined(METAWARE)
635       else
636       {
637          log_printf("!bSuccess 3\n");
638       }
639 #endif
640 
641       if ( bSuccess )
642       {
643          // OVERLOADED Load method - 3 parameters means
644          // recall from BUFFER
645          bSuccess =
646             pRootCACertificate->Load(
647                stRootCACertificateResponse.RootCACertificate.__ptr,  // to here
648                stRootCACertificateResponse.RootCACertificate.__size, // size
649                PKI_FORMAT );                                         // ignored
650 
651          if( !bSuccess )
652          {
653             GetPeerNetworkAddress(sKmaAddress, pstCASoap);
654             LogError(i_pProfile,
655                      AUDIT_CLIENT_GET_ROOT_CA_CERTIFICATE_INVALID_CA_CERTIFICATE_FORMAT,
656                      NULL,
657                      sKmaAddress,
658                      NULL);
659          }
660 
661       }
662 #if defined(DEBUG) && defined(METAWARE)
663       else
664       {
665          log_printf("!bSuccess 4\n");
666       }
667 #endif
668 
669 
670       if ( bSuccess )
671       {
672          // save the built CACertificate object to a FILE (i_pProfile gets the
673          // persistent handle to that file)
674          bSuccess = StoreCACertificate( i_pProfile, pRootCACertificate );
675 
676          if ( !bSuccess )
677          {
678             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_SAVE_CA_CERTIFICATE_FAILED,
679                      NULL,
680                      NULL,
681                      NULL);
682          }
683       }
684 #if defined(DEBUG) && defined(METAWARE)
685       else
686       {
687          log_printf("!bSuccess 5\n");
688       }
689 #endif
690 
691       //-------------------------------
692       // Initialize SSL - use SERVER AUTH
693       //-------------------------------
694       if ( bSuccess )
695       {
696          // SERVER_AUTHENTICATION needs just the pstCertificateSoap
697          bSuccess =
698             K_soap_ssl_client_context(
699                i_pProfile,                            // in ->m_wsProfileName,->m_sHexHashedPassphrase
700                pstCertificateSoap,                    // in - soap structure
701                SOAP_SSL_REQUIRE_SERVER_AUTHENTICATION // in - flags
702                ) == SOAP_OK;
703 
704          if ( !bSuccess )
705          {
706             GetSoapFault(sSoapFaultMsg, (struct soap*)pstCertificateSoap);
707             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
708             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_SOAP_ERROR,
709                      NULL,
710                      sKmaAddress,
711                      sSoapFaultMsg );
712          }
713       }
714 #if defined(DEBUG) && defined(METAWARE)
715       else
716       {
717          log_printf("!bSuccess 6\n");
718       }
719 #endif
720 
721       // hash the passphrase passed in
722       char sHexAuthenticationSecret[2*HASH_LENGTH+1];
723 
724       if ( bSuccess )
725       {
726          bSuccess = ComputeFixedEntityHashedPassphraseAndAuthenticationSecret(
727             i_wsPassphrase,
728             o_sHexHashedPassphrase,
729             stRootCACertificateResponse.AuthenticationHashIterationCount,
730             sHexAuthenticationSecret );
731 
732          if ( !bSuccess )
733          {
734             LogError(i_pProfile,AUDIT_CLIENT_COMPUTE_FIXED_FAILED,
735                      NULL,
736                      NULL,
737                      NULL);
738          }
739       }
740 #if defined(DEBUG) && defined(METAWARE)
741       else
742       {
743          log_printf("!bSuccess 7\n");
744       }
745 #endif
746 
747       // copy received Root CA into buffer for input
748       // into challenge-response computation
749       unsigned char aRootCACertificate[MAX_CERT_SIZE];
750       int iRootCACertificateLength;
751 
752       if ( bSuccess )
753       {
754          // OVERLOADED save method - save iRootCACertificateLength to aRootCACertificate
755          // buffer
756          bSuccess = pRootCACertificate->Save(
757             aRootCACertificate,
758             MAX_CERT_SIZE,
759             &iRootCACertificateLength,
760             PKI_FORMAT );
761 
762          if ( !bSuccess )
763          {
764             LogError(i_pProfile,AUDIT_CLIENT_SAVE_ROOTCA_FAILED,
765                      NULL,
766                      NULL,
767                      NULL);
768          }
769       }
770 #if defined(DEBUG) && defined(METAWARE)
771       else
772       {
773          log_printf("!bSuccess 8\n");
774       }
775 #endif
776 
777       // respond to server's challenge
778       unsigned char aAuthenticationSecret[AUTHENTICATION_SECRET_LENGTH];
779       unsigned char
780          aClientAuthenticationChallengeResponse[AUTHENTICATION_RESPONSE_LENGTH];
781 
782       if ( bSuccess )
783       {
784          FATAL_ASSERT( AUTHENTICATION_SECRET_LENGTH ==
785                        ConvertUTF8HexStringToBinary(
786                           sHexAuthenticationSecret, NULL ) );
787 
788          ConvertUTF8HexStringToBinary(
789             sHexAuthenticationSecret, aAuthenticationSecret );
790 
791          // client authentication response
792          bSuccess = ComputeChallengeResponse(
793             aAuthenticationSecret,
794             AUTHENTICATION_SECRET_LENGTH,
795             aRootCACertificate,
796             iRootCACertificateLength,
797             stRootCACertificateResponse.ClientAuthenticationChallenge.__ptr,
798             AUTHENTICATION_CHALLENGE_LENGTH,
799             aClientAuthenticationChallengeResponse,
800             AUTHENTICATION_RESPONSE_LENGTH );
801 
802          if ( !bSuccess )
803          {
804             LogError(i_pProfile,AUDIT_CLIENT_COMPUTE_CHALLENGE_RESPONSE_FAILED,
805                      NULL,
806                      NULL,
807                      NULL);
808          }
809       }
810 #if defined(DEBUG) && defined(METAWARE)
811       else
812       {
813          log_printf("!bSuccess 9\n");
814       }
815 #endif
816 
817       struct KMS_Certificate::xsd__hexBinary stClientAuthenticationResponse;
818 
819       if ( bSuccess )
820       {
821          stClientAuthenticationResponse.__size =
822             AUTHENTICATION_RESPONSE_LENGTH;
823          stClientAuthenticationResponse.__ptr =
824             (unsigned char*)soap_malloc(
825                pstCertificateSoap, AUTHENTICATION_RESPONSE_LENGTH );
826 
827          if ( stClientAuthenticationResponse.__ptr != NULL )
828          {
829             memcpy( stClientAuthenticationResponse.__ptr,
830                     aClientAuthenticationChallengeResponse,
831                     AUTHENTICATION_RESPONSE_LENGTH );
832          }
833          else
834          {
835             bSuccess = false;
836          }
837       }
838 #if defined(DEBUG) && defined(METAWARE)
839       else
840       {
841          log_printf("!bSuccess 10\n");
842       }
843 #endif
844 
845       // generate challenge nonce
846       struct KMS_Certificate::xsd__hexBinary stServerAuthenticationChallenge;
847 
848       if ( bSuccess )
849       {
850          stServerAuthenticationChallenge.__size =
851             AUTHENTICATION_CHALLENGE_LENGTH;
852          stServerAuthenticationChallenge.__ptr =
853             (unsigned char*)soap_malloc( pstCertificateSoap,
854                                          AUTHENTICATION_CHALLENGE_LENGTH );
855 
856          bSuccess = ( stServerAuthenticationChallenge.__ptr != NULL );
857       }
858 #if defined(DEBUG) && defined(METAWARE)
859       else
860       {
861          log_printf("!bSuccess 11\n");
862       }
863 #endif
864 
865       if ( bSuccess )
866       {
867          bSuccess = GetPseudorandomBytes(
868             AUTHENTICATION_CHALLENGE_LENGTH,
869             stServerAuthenticationChallenge.__ptr );
870       }
871 #if defined(DEBUG) && defined(METAWARE)
872       else
873       {
874          log_printf("!bSuccess 12\n");
875       }
876 #endif
877 
878       if ( bSuccess )
879       {
880          sURL = oLoadBalancer.GetHTTPSURL(iIndex,
881                                           i_pProfile->
882                                           m_iPortForCertificateService);
883 
884          if ( !sURL )
885          {
886             bSuccess = false;
887          }
888       }
889 #if defined(DEBUG) && defined(METAWARE)
890       else
891       {
892          log_printf("!bSuccess 13\n");
893       }
894 #endif
895 
896       // Verify that the same URL is used for Root CA Certificate
897       // retrieval as for Entity Certificate retrieval
898 
899       if ( bSuccess )
900       {
901          char sTempCAURL[KMS_MAX_URL + 1];
902          strncpy( sTempCAURL, i_pProfile->m_sURL, KMS_MAX_URL );
903          sTempCAURL[KMS_MAX_URL] = 0;
904 
905          char * sRetrieveRootCACertificateURL = strtok( sTempCAURL, ":" );
906 
907          sRetrieveRootCACertificateURL = strtok(NULL, ":");
908 
909          char sTempAgentURL[KMS_MAX_URL + 1];
910          strncpy( sTempAgentURL, sURL, KMS_MAX_URL );
911          sTempAgentURL[KMS_MAX_URL] = 0;
912          char * sRetrieveAgentCertificateURL = strtok( sTempAgentURL, ":" );
913          sRetrieveAgentCertificateURL = strtok(NULL, ":");
914 
915          FATAL_ASSERT( strcmp( sRetrieveRootCACertificateURL,
916                                sRetrieveAgentCertificateURL ) == 0 );
917 
918          strncpy(i_pProfile->m_sURL, sURL, KMS_MAX_URL);
919          i_pProfile->m_sURL[KMS_MAX_URL] = 0;
920       }
921 #if defined(DEBUG) && defined(METAWARE)
922       else
923       {
924          log_printf("!bSuccess 14\n");
925       }
926 #endif
927 
928       KMS_Certificate::KMS_Certificate__RetrieveEntityCertificateResponse
929          stRetrieveEntityCertificateResponse;
930 
931       // SOAP - retrieve ENTITY Certificate, passing the challenge response,
932       // a challenge to the server and get back the server's response
933       if ( bSuccess )
934       {
935          bSuccess =
936             KMS_Certificate::soap_call_KMS_Certificate__RetrieveEntityCertificate(
937                pstCertificateSoap,
938                sURL,
939                NULL,
940                (utf8cstr )i_wsEntityID,
941                stClientAuthenticationResponse,
942                stServerAuthenticationChallenge,
943                stRetrieveEntityCertificateResponse ) == SOAP_OK;
944 
945          if( !bSuccess )
946          {
947             GetSoapFault(sSoapFaultMsg, (struct soap*)pstCertificateSoap);
948             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
949             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_SOAP_ERROR,
950                      NULL,
951                      sKmaAddress,
952                      sSoapFaultMsg );
953 
954             bTryFailOver = ServerError(GET_SOAP_FAULTSTRING(pstCertificateSoap),
955                                         pstCertificateSoap->errnum);
956          }
957       }
958 #if defined(DEBUG) && defined(METAWARE)
959       else
960       {
961          log_printf("!bSuccess 15\n");
962       }
963 #endif
964 
965       // Validate the response structure
966       if ( bSuccess )
967       {
968          if ( stRetrieveEntityCertificateResponse.
969               ServerAuthenticationResponse.__ptr == NULL
970 
971               || stRetrieveEntityCertificateResponse.
972               ServerAuthenticationResponse.__size !=
973               AUTHENTICATION_RESPONSE_LENGTH
974 
975               || stRetrieveEntityCertificateResponse.Certificate.__size < 1
976 
977               || stRetrieveEntityCertificateResponse.Certificate.__ptr == 0
978 
979               || stRetrieveEntityCertificateResponse.
980               WrappedPrivateKeyMaterial.__size < 1
981 
982               || stRetrieveEntityCertificateResponse.
983               WrappedPrivateKeyMaterial.__ptr == 0 )
984          {
985             bSuccess = false;
986 
987             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
988             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_RESPONSE_FORMAT,
989                      NULL,
990                      sKmaAddress,
991                      NULL );
992          }
993          else
994          {
995             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
996             Log(AUDIT_CLIENT_GET_CERTIFICATE_SUCCESS,
997                  NULL,
998                  sKmaAddress,
999                  NULL );
1000          }
1001      }
1002 #if defined(DEBUG) && defined(METAWARE)
1003       else
1004       {
1005          log_printf("!bSuccess 16\n");
1006       }
1007 #endif
1008 
1009       // if valid, calculate the correct challenge-response
1010       unsigned char
1011          aServerAuthenticationChallengeResponse[AUTHENTICATION_RESPONSE_LENGTH];
1012 
1013       if ( bSuccess )
1014       {
1015          bSuccess = ComputeChallengeResponse(
1016             aAuthenticationSecret,
1017             AUTHENTICATION_SECRET_LENGTH,
1018             aRootCACertificate,
1019             iRootCACertificateLength,
1020             stServerAuthenticationChallenge.__ptr,
1021             AUTHENTICATION_CHALLENGE_LENGTH,
1022             aServerAuthenticationChallengeResponse,
1023             AUTHENTICATION_RESPONSE_LENGTH );
1024       }
1025 #if defined(DEBUG) && defined(METAWARE)
1026       else
1027       {
1028          log_printf("!bSuccess 17\n");
1029       }
1030 #endif
1031 
1032       // if successful, check if the server provided the correct challenge-response
1033       if ( bSuccess )
1034       {
1035          if ( 0 != memcmp(
1036             aServerAuthenticationChallengeResponse,
1037             stRetrieveEntityCertificateResponse.ServerAuthenticationResponse.__ptr,
1038             AUTHENTICATION_RESPONSE_LENGTH )  )
1039          {
1040             bSuccess = false;
1041 
1042             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
1043             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_CHALLENGE_RESPONSE,
1044                      NULL,
1045                      sKmaAddress,
1046                      NULL );
1047          }
1048       }
1049 #if defined(DEBUG) && defined(METAWARE)
1050       else
1051       {
1052          log_printf("!bSuccess 18\n");
1053       }
1054 #endif
1055 
1056 
1057       if ( bSuccess )
1058       {
1059          pEntityCertificate = new CCertificate;
1060          // if certificate was obtained
1061          bSuccess = ( pEntityCertificate != 0 );
1062       }
1063 #if defined(DEBUG) && defined(METAWARE)
1064       else
1065       {
1066          log_printf("!bSuccess 19\n");
1067       }
1068 #endif
1069 
1070       if ( bSuccess )
1071       {
1072          // Load(recall) the signed certificate using OVERLOADED load method
1073          // 3 parameters means load from a buffer
1074          bSuccess = pEntityCertificate->Load(
1075             stRetrieveEntityCertificateResponse.Certificate.__ptr,  // load into
1076             stRetrieveEntityCertificateResponse.Certificate.__size,
1077             PKI_FORMAT );
1078 
1079          if ( !bSuccess )
1080          {
1081             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
1082             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_CERTIFICATE_FORMAT,
1083                      NULL,
1084                      sKmaAddress,
1085                      NULL );
1086          }
1087       }
1088 #if defined(DEBUG) && defined(METAWARE)
1089       else
1090       {
1091          log_printf("!bSuccess 20\n");
1092       }
1093 #endif
1094 
1095       if ( bSuccess )
1096       {
1097          pEntityPrivateKey = new CPrivateKey;
1098          bSuccess = ( pEntityPrivateKey != 0 );
1099       }
1100 #if defined(DEBUG) && defined(METAWARE)
1101       else
1102       {
1103          log_printf("!bSuccess 21\n");
1104       }
1105 #endif
1106 
1107 
1108       if ( bSuccess )
1109       {
1110          // Load the Private Key using OVERLOADED Load method - 3 parameters
1111          // means load from a buffer
1112 
1113          // TODO: change this when certificate service supports requesting unwrapped private keys
1114          bSuccess = pEntityPrivateKey->Load(
1115             stRetrieveEntityCertificateResponse.WrappedPrivateKeyMaterial.__ptr, // load into
1116             stRetrieveEntityCertificateResponse.WrappedPrivateKeyMaterial.__size,
1117             NULL,
1118             PKI_FORMAT );
1119 
1120          if (!bSuccess )
1121          {
1122 
1123             GetPeerNetworkAddress(sKmaAddress, pstCertificateSoap);
1124             LogError(i_pProfile,AUDIT_CLIENT_GET_CERTIFICATE_INVALID_KEY_FORMAT,
1125                      NULL,
1126                      sKmaAddress,
1127                      NULL );
1128          }
1129       }
1130 
1131       if ( bSuccess )
1132       {
1133             strncpy(i_pProfile->m_wsEntityID,
1134                 i_wsEntityID,
1135                 KMS_MAX_ENTITY_ID );
1136             i_pProfile->m_wsEntityID[KMS_MAX_ENTITY_ID] = 0;
1137 
1138             // store PKI certificates and unwrapped private key
1139             bSuccess = StorePKIcerts( i_pProfile,
1140                             pRootCACertificate,
1141                             pEntityCertificate,
1142                             pEntityPrivateKey,
1143 #ifdef KMSUSERPKCS12
1144 			    i_wsPassphrase
1145 #else
1146                             NULL
1147 #endif
1148 			    );
1149 #ifdef KMSUSERPKCS12
1150 		if (bSuccess) {
1151 			/*
1152 			 * Write out the cert and key individually so GetPKIcerts
1153 			 * can use them.
1154 			 */
1155 			bSuccess = StoreTempAgentPKI(i_pProfile,
1156 			    pEntityCertificate, pEntityPrivateKey);
1157 		}
1158 
1159 #endif
1160 	}
1161 
1162       if ( !bSuccess )
1163       {
1164          if (pRootCACertificate)
1165          {
1166              delete pRootCACertificate;
1167          }
1168          if (pEntityCertificate)
1169          {
1170              delete pEntityCertificate;
1171          }
1172          if (pEntityPrivateKey)
1173          {
1174              delete pEntityPrivateKey;
1175          }
1176 
1177          i_pProfile->m_iEnrolled = FALSE;
1178 
1179          if ( bTryFailOver )
1180          {
1181             iIndex = oLoadBalancer.FailOver(iIndex, bFailedOnRetrieveRootCA ? pstCASoap : pstCertificateSoap);
1182          }
1183       }
1184    }
1185    while ( bTryFailOver && (iIndex >= 0) && !bSuccess );
1186 
1187    // certs are now persisted so free up space
1188    if ( bSuccess )
1189    {
1190         delete pRootCACertificate;
1191         delete pEntityCertificate;
1192         delete pEntityPrivateKey;
1193    }
1194 
1195    // Clean up SOAP resources for pstCASoap
1196    soap_destroy( pstCASoap );
1197    soap_end( pstCASoap );
1198    soap_done( pstCASoap );
1199 
1200    // Clean up SOAP resources for pstCertificateSoap
1201    soap_destroy( pstCertificateSoap );
1202    soap_end( pstCertificateSoap );
1203    soap_done( pstCertificateSoap );
1204 
1205    free(pstCASoap);
1206    free(pstCertificateSoap);
1207 
1208    return bSuccess;
1209 }
1210 
1211 /*--------------------------------------------------------------------------
1212  * LoadClusterInformation
1213  *  calls GetCluster - that's it.
1214  *    If there is no cluster file, this function will return true,
1215  *    but o_bClusterInformationFound will be false.
1216  *-------------------------------------------------------------------------*/
LoadClusterInformation(KMSClientProfile * i_pProfile,int & o_bClusterInformationFound)1217 static bool LoadClusterInformation( KMSClientProfile* i_pProfile,
1218                                     int& o_bClusterInformationFound )
1219 {
1220     FATAL_ASSERT( i_pProfile );
1221 
1222     o_bClusterInformationFound = false;
1223 
1224     CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
1225 
1226     return GetCluster( i_pProfile, o_bClusterInformationFound ) ;
1227 
1228 }
1229 
1230 
1231 /*--------------------------------------------------------------------------
1232  * EnrollAgent
1233  *  calls functions to perform enrollment and save PKI info to persistent storage
1234  *  stores configuration in persistent storage
1235  *-------------------------------------------------------------------------*/
1236 
EnrollAgent(KMSClientProfile * io_pProfile,utf8cstr i_wsEntityID,utf8cstr i_wsPassphrase)1237 static bool EnrollAgent( KMSClientProfile * io_pProfile,
1238                          utf8cstr           i_wsEntityID,
1239                          utf8cstr           i_wsPassphrase )
1240 {
1241     FATAL_ASSERT( io_pProfile && i_wsEntityID && i_wsPassphrase );
1242 
1243     bool bSuccess = true;
1244 
1245     // see KMSAgentCryptoUtilities for HASH_LENGTH, aka KMS_MAX_HASH_SIZE
1246     char sHexHashedPassphrase[2*KMS_MAX_HASH_SIZE+1];
1247 
1248     if ( bSuccess )
1249     {
1250         // performs enrollment and saves PKI info to persistent storage
1251         bSuccess = KMSClient_RetrieveEntityCertificate(
1252                                     io_pProfile,
1253                                     i_wsEntityID,
1254                                     i_wsPassphrase,
1255                                     sHexHashedPassphrase );
1256 
1257         // KMSClient_RetrieveCertificate logs errors
1258     }
1259 
1260     if (bSuccess)
1261     {
1262         strncpy(io_pProfile->m_sHexHashedPassphrase,
1263             sHexHashedPassphrase,
1264             2*KMS_MAX_HASH_SIZE );
1265         io_pProfile->m_sHexHashedPassphrase[2*KMS_MAX_HASH_SIZE] = 0;
1266 
1267         // persist the profile now updated with the hashed passphrase
1268         bSuccess = StoreConfig( io_pProfile );
1269 
1270         if (!bSuccess)
1271         {
1272               Log(AUDIT_CLIENT_LOAD_PROFILE,
1273                   i_wsEntityID,
1274                   NULL,
1275                   "store config failed following enrollment" );
1276         }
1277     }
1278 
1279     return bSuccess;
1280 }
1281 
1282 /*---------------------------------------------------------------------------
1283  * Function: KMSClient_LoadProfile
1284  *
1285  *--------------------------------------------------------------------------*/
KMSClient_LoadProfile(KMSClientProfile * io_pProfile,utf8char * i_wsProfileName,utf8char * i_wsEntityID,utf8char * i_wsPassphrase,utf8char * i_wsApplianceAddress,int i_iTransactionTimeout,int i_iFailOverLimit,int i_iClusterDiscoveryFrequency,int i_eKMSmode)1286 bool KMSClient_LoadProfile(
1287                 KMSClientProfile *io_pProfile,
1288                 utf8char *i_wsProfileName,
1289                 utf8char *i_wsEntityID,
1290                 utf8char *i_wsPassphrase,
1291                 utf8char *i_wsApplianceAddress,
1292                 int      i_iTransactionTimeout,
1293                 int      i_iFailOverLimit,
1294                 int      i_iClusterDiscoveryFrequency,
1295                 int       i_eKMSmode)
1296 {
1297     FATAL_ASSERT(io_pProfile);
1298     FATAL_ASSERT(i_wsProfileName);
1299 
1300     bool bSuccess = true;
1301 
1302     char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH];
1303     char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH];
1304 
1305 #if defined(DEBUG) && defined(METAWARE)
1306     log_printf("KMSClient_LoadProfile : entered");
1307 #endif
1308 
1309     memset( io_pProfile, 0, sizeof(KMSClientProfile) );
1310 
1311     // create lock
1312 
1313     if (bSuccess)
1314     {
1315         bSuccess =
1316            ( K_CreateMutex((K_MUTEX_HANDLE *)&io_pProfile->m_pLock) ==
1317              K_SYS_OK );
1318     }
1319 
1320     // initialize profile with parameters
1321 
1322     strncpy(io_pProfile->m_wsProfileName,
1323             i_wsProfileName,
1324             KMS_MAX_ENTITY_ID);
1325     io_pProfile->m_wsProfileName[KMS_MAX_ENTITY_ID] = 0;
1326 
1327     io_pProfile->m_iPortForCAService =
1328        DEFAULT_CA_SERVICE_PORT_NUMBER;
1329     io_pProfile->m_iPortForCertificateService =
1330        DEFAULT_CERTIFICATE_SERVICE_PORT_NUMBER;
1331     io_pProfile->m_iPortForDiscoveryService =
1332        DEFAULT_DISCOVERY_SERVICE_PORT_NUMBER;
1333     io_pProfile->m_iPortForAgentService =
1334        DEFAULT_AGENT_SERVICE_PORT_NUMBER;
1335     strncpy(io_pProfile->m_wsApplianceAddress,
1336             i_wsApplianceAddress,
1337             KMS_MAX_NETWORK_ADDRESS);
1338     io_pProfile->m_wsApplianceAddress[KMS_MAX_NETWORK_ADDRESS] = 0;
1339     io_pProfile->m_iClusterDiscoveryFrequency = i_iClusterDiscoveryFrequency;
1340     io_pProfile->m_iTransactionTimeout = i_iTransactionTimeout;
1341     io_pProfile->m_iFailoverLimit = i_iFailOverLimit;
1342     io_pProfile->m_eKMSmode = i_eKMSmode;
1343 
1344     // if the file isn't found, create a new one
1345     bool bProfileExists = ProfileExists( g_wsWorkingDirectory,  /* pass in default */
1346                                          io_pProfile->m_wsProfileName );
1347 
1348 #ifdef KMSUSERPKCS12
1349 	/*
1350 	 * Fix logic for determining if this request is for enrollment.
1351 	 * Look to see if the server cert and clientkey.p12 file exist.
1352 	 * We always expect a password for Solaris which is used to
1353 	 * validate that the user has access to the clientkey data by
1354 	 * attempting to use it to open the PKCS12 file.
1355 	 */
1356 	 bool bEnrolling = !ClientKeyP12Exists(io_pProfile->m_wsProfileName);
1357 #else
1358     bool bEnrolling = i_wsEntityID && i_wsPassphrase;
1359 #endif
1360 
1361     if ( bSuccess && !bEnrolling && !bProfileExists )
1362     {
1363        // when not enrolling a profile must exist
1364        bSuccess = false;
1365        Log(AUDIT_CLIENT_LOAD_PROFILE,
1366            i_wsProfileName,
1367            NULL,
1368            "Enrollment attempted but profile could not be found" );
1369     }
1370 
1371     // if the file isn't found, create a new one
1372     if ( bSuccess && !bProfileExists )
1373     {
1374        strncpy(io_pProfile->m_wsEntityID,
1375                i_wsEntityID,
1376                KMS_MAX_ENTITY_ID );
1377        io_pProfile->m_wsEntityID[KMS_MAX_ENTITY_ID] = 0;
1378        bSuccess = CreateProfile( io_pProfile,
1379                                  g_wsWorkingDirectory,
1380                                  io_pProfile->m_wsProfileName );
1381     }
1382 
1383     // load profile.cfg file
1384     if ( bSuccess )
1385     {
1386         bSuccess = GetConfig( io_pProfile );
1387 
1388     }
1389 
1390     // if profile settings changed then update the profile storage
1391     if ( bSuccess &&
1392          ( strncmp(io_pProfile->m_wsApplianceAddress,
1393                    i_wsApplianceAddress, KMS_MAX_NETWORK_ADDRESS ) != 0 ||
1394            io_pProfile->m_iClusterDiscoveryFrequency != i_iClusterDiscoveryFrequency ||
1395            io_pProfile->m_iTransactionTimeout != i_iTransactionTimeout ||
1396            io_pProfile->m_iFailoverLimit != i_iFailOverLimit
1397          ))
1398     {
1399         strncpy(io_pProfile->m_wsApplianceAddress,
1400                 i_wsApplianceAddress,
1401                 KMS_MAX_NETWORK_ADDRESS);
1402         io_pProfile->m_wsApplianceAddress[KMS_MAX_NETWORK_ADDRESS] = 0;
1403         io_pProfile->m_iClusterDiscoveryFrequency = i_iClusterDiscoveryFrequency;
1404         io_pProfile->m_iTransactionTimeout = i_iTransactionTimeout;
1405         io_pProfile->m_iFailoverLimit = i_iFailOverLimit;
1406 
1407         bSuccess = StoreConfig( io_pProfile );
1408     }
1409 
1410     // get PKI info from prior enrollment
1411     if ( bSuccess && !bEnrolling )
1412     {
1413 #ifdef KMSUSERPKCS12
1414 	/*
1415 	 * Decrypt the PKCS12 file with the client cert and key using
1416 	 * the given password.  If it fails, then return an auth failure
1417 	 * status.  If success, write the client cert and key to the client file
1418 	 * so it can be used later by the SOAP SSL functions.
1419 	 */
1420 	CCertificate* pEntityCertificate = new CCertificate;;
1421 	CPrivateKey*  pEntityPrivateKey = new CPrivateKey;
1422 	bSuccess = GetPKCS12CertAndKey(io_pProfile,
1423 	    i_wsPassphrase,
1424 	    pEntityCertificate,
1425 	    pEntityPrivateKey);
1426 	if (!bSuccess) {
1427 		Log(AUDIT_CLIENT_LOAD_PROFILE,
1428 			i_wsProfileName,
1429 			NULL,
1430 			"Enrollment Certificate and Private Key "\
1431 			"were not loaded from PKCS12" );
1432 	} else {
1433 		/*
1434 		 * Write out the cert and key individually so GetPKIcerts
1435 		 * can use them.
1436 		 */
1437 		 bSuccess = StoreTempAgentPKI(io_pProfile,
1438 		    pEntityCertificate, pEntityPrivateKey);
1439 		 if (!bSuccess) {
1440 			Log(AUDIT_CLIENT_LOAD_PROFILE,
1441 				i_wsProfileName,
1442 				NULL,
1443 				"Enrollment Certificate and Private Key "\
1444 				"were not stored to file." );
1445 		 }
1446 	}
1447 	delete pEntityCertificate;
1448 	delete pEntityPrivateKey;
1449 
1450 #endif
1451 	if (bSuccess)
1452         	bSuccess = GetPKIcerts( io_pProfile );
1453     }
1454 
1455     // if not enrolling then previously enrolled PKI info should now be initialized
1456     if ( bSuccess && !bEnrolling &&
1457         (!io_pProfile->m_sHexHashedPassphrase ||
1458         !io_pProfile->m_iEnrolled  ))
1459     {
1460         bSuccess = false;
1461         Log(AUDIT_CLIENT_LOAD_PROFILE,
1462           i_wsProfileName,
1463           NULL,
1464           "Enrollment Certificates and Private Key were not loaded from profile" );
1465     }
1466 
1467     io_pProfile->m_bIsClusterDiscoveryCalled = false;
1468 
1469     // allocate main soap struct
1470     struct soap* pstSoap = 0;
1471 
1472     if ( bSuccess )
1473     {
1474         pstSoap = (struct soap*)malloc( sizeof(struct soap) );
1475 
1476         io_pProfile->m_pvSoap = pstSoap;
1477 
1478         bSuccess = ( pstSoap != NULL );
1479 
1480         if ( bSuccess )
1481         {
1482             soap_init2( pstSoap,
1483                     (SOAP_XML_STRICT | SOAP_C_UTFSTRING ),
1484                     (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
1485 
1486 #ifdef METAWARE
1487             K_SetupCallbacks ( pstSoap );
1488 #endif
1489 
1490             soap_set_namespaces( pstSoap, KMS_Agent_namespaces );
1491 
1492             pstSoap->connect_timeout = io_pProfile->m_iTransactionTimeout;
1493             pstSoap->send_timeout = io_pProfile->m_iTransactionTimeout;
1494             pstSoap->recv_timeout = io_pProfile->m_iTransactionTimeout;
1495         }
1496         else
1497         {
1498 #if defined(DEBUG) && defined(METAWARE)
1499            log_printf("Malloc %x pstSoap returned null\n",
1500                       sizeof(struct soap));
1501 #endif
1502 
1503         }
1504     }
1505 
1506     // delete the existing cluster config if the input IP address
1507     // does not match one already known to the cluster config
1508 
1509     // Note that KMSClientProfile may be too large to fit on the stack, so we're
1510     // going to put it on the heap.
1511 
1512     KMSClientProfile* pstTempProfile = 0;
1513     bool bFound = false;
1514     int i;
1515 
1516     if ( bSuccess )
1517     {
1518         pstTempProfile = (KMSClientProfile*)malloc( sizeof(KMSClientProfile) );
1519         bSuccess = (pstTempProfile != 0);
1520 #if defined(METAWARE)
1521         if (!bSuccess)
1522            log_printf("Malloc %x pstTempProfile returned null\n",
1523                       sizeof(KMSClientProfile));
1524 #endif
1525 
1526     }
1527 
1528     int bClusterInformationFound = false;
1529 
1530     if ( bSuccess )
1531     {
1532         memcpy( pstTempProfile, io_pProfile, sizeof(KMSClientProfile) );
1533 
1534         bSuccess = LoadClusterInformation( pstTempProfile, bClusterInformationFound );
1535     }
1536 
1537     // got cluster info from persistent storage
1538     if ( bSuccess && bClusterInformationFound )
1539     {
1540        // see if address is a member of the remembered cluster or is a
1541        // new kma, meaning this KMA joins the cluster as the
1542        // discovery KMA.
1543         for ( i = 0; i < pstTempProfile->m_iClusterNum; i++ )
1544         {
1545             bFound = (strncmp( pstTempProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
1546                               io_pProfile->m_wsApplianceAddress,
1547                               KMS_MAX_NETWORK_ADDRESS) == 0);
1548 
1549             if ( bFound )
1550             {
1551                 break;
1552             }
1553 #if defined(DEBUG) && defined(METAWARE)
1554             else
1555                log_printf ("KMSClient_LoadProfile : Appliance Address doesn't match");
1556 #endif
1557         }
1558 
1559         if ( !bFound )
1560         {
1561 #if defined(DEBUG) && defined(METAWARE)
1562            log_printf ("KMSClient_LoadProfile : delete cluster");
1563 #endif
1564            DeleteCluster( pstTempProfile );
1565            char msg[256];
1566            K_snprintf(msg, 256,
1567                "KMSClientProfile.LoadProfile(): deleting previous cluster config, %s not found\n",
1568                 io_pProfile->m_wsApplianceAddress);
1569            Log(AUDIT_CLIENT_LOAD_PROFILE,
1570               i_wsProfileName,
1571               NULL,
1572               msg );
1573            DeleteCluster( pstTempProfile );
1574         }
1575         else
1576         {
1577             // since address is a member of the persisted cluster copy the persisted cluster info to the profile
1578             io_pProfile->m_iClusterNum = pstTempProfile->m_iClusterNum;
1579             memcpy(io_pProfile->m_aCluster,
1580                    pstTempProfile->m_aCluster,
1581                     sizeof(KMSClusterEntry)*io_pProfile->m_iClusterNum);
1582         }
1583     }
1584 #if defined(DEBUG) && defined(METAWARE)
1585     else
1586        log_printf ("KMSClient_LoadProfile : no persisted cluster information");
1587 #endif
1588 
1589     if ( pstTempProfile )
1590     {
1591 #if defined(DEBUG) && defined(METAWARE)
1592        log_printf ("KMSClient_LoadProfile : free the temporary profile");
1593 #endif
1594         free( pstTempProfile );
1595         pstTempProfile = 0;
1596     }
1597 
1598     if ( bSuccess && !io_pProfile->m_iEnrolled )
1599     {
1600 #if defined(DEBUG) && defined(METAWARE)
1601        log_printf ("KMSClient_LoadProfile : call EnrollAgent");
1602 #endif
1603         // enroll the agent
1604         bSuccess = EnrollAgent( io_pProfile,
1605                                 i_wsEntityID,
1606                                 i_wsPassphrase );
1607     }
1608 #if defined(DEBUG) && defined(METAWARE)
1609     else if (io_pProfile->m_iEnrolled)
1610        log_printf ("KMSClient_LoadProfile : Already Enrolled");
1611 #endif
1612 
1613 
1614 
1615     if (bSuccess)
1616     {
1617        // Initialize SSL - use CLIENT AUTH
1618        // CLIENT_AUTHENTICATION needs the pstSoap, and expects
1619        // the profile io_pProfile to be full (have the other certificates
1620        // and keypair)
1621 
1622         if ( bSuccess )
1623         {
1624             bSuccess =
1625                 K_soap_ssl_client_context(
1626                    io_pProfile,                            // in/out
1627                    pstSoap,                                // out
1628                    SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION  // in - flags
1629                     ) == SOAP_OK;
1630 
1631             if ( !bSuccess )
1632             {
1633 #if defined(DEBUG) && defined(METAWARE)
1634                 if (!bSuccess)
1635                   log_printf ("KMSClient_LoadProfile : K_soap_ssl_client_context failed");
1636 #endif
1637                 GetSoapFault(sSoapFaultMsg, (struct soap*)pstSoap);
1638                 GetPeerNetworkAddress(sKmaAddress, pstSoap);
1639 
1640                 LogError(io_pProfile,
1641                     AUDIT_CLIENT_LOAD_PROFILE_SOAP_ERROR,
1642                     NULL,
1643                     sKmaAddress,
1644                     sSoapFaultMsg );
1645             }
1646         }
1647 
1648         // discover the cluster
1649 
1650         if ( bSuccess &&
1651             io_pProfile->m_iClusterDiscoveryFrequency > 0 )
1652          {
1653               bSuccess = ( KMSClient_GetClusterInformation(
1654                                             io_pProfile,
1655                                             io_pProfile->m_wsEntitySiteID,
1656                                             sizeof(io_pProfile->m_wsEntitySiteID),
1657                                             &(io_pProfile->m_iClusterNum),
1658                                             io_pProfile->m_aCluster,
1659                                             KMS_MAX_CLUSTER_NUM) != 0 );
1660               // KMSClient_GetClusterInformation logs errors
1661 
1662               if (bSuccess && i_eKMSmode == FIPS_MODE)
1663               {
1664                     bSuccess = !KMSClient_NoFIPSCompatibleKMAs(io_pProfile);
1665                     if (!bSuccess)
1666                     {
1667                         LogError(io_pProfile,
1668                             AUDIT_CLIENT_AGENT_LOAD_PROFILE_NO_FIPS_COMPATIBLE_KMAS_AVAILABLE,
1669                             NULL,
1670                             NULL,
1671                             NULL );
1672                     }
1673               }
1674          }
1675 #if defined(DEBUG) && defined(METAWARE)
1676         if (!bSuccess)
1677            log_printf ("KMSClient_LoadProfile : getClusterInformation failed");
1678 #endif
1679 
1680 #ifdef KMSUSERPKCS12
1681 	/*
1682 	 * Once the SSL context is established, delete the
1683 	 * private key file.
1684 	 */
1685 	 (void) CleanupPrivateKeyFile(io_pProfile);
1686 #endif
1687     }
1688 #if defined(DEBUG) && defined(METAWARE)
1689     else if (!bSuccess)
1690        log_printf ("KMSClient_LoadProfile : EnrollAgent failed");
1691 #endif
1692 
1693     CAgentLoadBalancer *pAgentLoadBalancer = new CAgentLoadBalancer(io_pProfile);
1694     if(pAgentLoadBalancer == NULL)
1695     {
1696         bSuccess = false;
1697     }
1698 
1699 #if defined(DEBUG) && defined(METAWARE)
1700     if (!bSuccess)
1701        log_printf ("KMSClient_LoadProfile : new CAgentLoadBalancer failed");
1702 #endif
1703 
1704     io_pProfile->m_pAgentLoadBalancer = pAgentLoadBalancer;
1705 
1706     // create a data unit server affinity cache for Agents
1707 
1708     if ( bSuccess )
1709     {
1710         io_pProfile->m_pDataUnitCache = new CDataUnitCache();
1711 
1712         bSuccess = ( io_pProfile->m_pDataUnitCache != NULL );
1713     }
1714 
1715     if ( bSuccess )
1716     {
1717 #if defined(DEBUG) && defined(METAWARE)
1718        log_printf ("KMSClient_LoadProfile : set version to KMS_AGENT_VERSION = %x",
1719                    KMS_AGENT_VERSION);
1720        log_printf ("KMSClient_LoadProfile : profile is: %x\n", io_pProfile);
1721 #endif
1722        // this is checked later by ProfileLoaded and is taken
1723        // to indicate that the profile was correctly loaded
1724 	   io_pProfile->m_iVersion = KMS_AGENT_VERSION;
1725     }
1726 
1727     if( !bSuccess )
1728     {
1729         K_DestroyMutex((K_MUTEX_HANDLE)io_pProfile->m_pLock);
1730         io_pProfile->m_pLock = 0;
1731 
1732         if ( io_pProfile->m_pvSoap )
1733         {
1734             soap_destroy( (struct soap*)io_pProfile->m_pvSoap );
1735             soap_end( (struct soap*)io_pProfile->m_pvSoap );
1736             soap_done( (struct soap*)io_pProfile->m_pvSoap );
1737 
1738             free( (struct soap*)io_pProfile->m_pvSoap );
1739             io_pProfile->m_pvSoap = 0;
1740 
1741             if( io_pProfile->m_pAgentLoadBalancer != NULL)
1742             {
1743                 delete(reinterpret_cast <CAgentLoadBalancer *>(io_pProfile->m_pAgentLoadBalancer));
1744             }
1745 
1746             if( io_pProfile->m_pDataUnitCache != NULL)
1747             {
1748                 delete(reinterpret_cast <CDataUnitCache *>(io_pProfile->m_pDataUnitCache));
1749             }
1750 
1751         }
1752 #if defined(DEBUG) && defined(METAWARE)
1753         log_printf ("KMSClient_LoadProfile : failed - returning");
1754 #endif
1755     }
1756 
1757     return bSuccess;
1758 }
1759 
1760 /**
1761  *  compare cluster entries having equivalent KMA names (aka Appliance alias) and
1762  *  return true if equal.  Note:  KMANetworkAddress comparison is handled separately
1763  *  due to IPv4/IPv6
1764  */
EqualClusterEntry(struct KMS_Discovery::KMS_Discovery_ClusterMember const * i_pLeft,KMSClusterEntry const * i_pRight)1765 static bool EqualClusterEntry(
1766                        struct KMS_Discovery::KMS_Discovery_ClusterMember const *i_pLeft,
1767                        KMSClusterEntry                                   const *i_pRight)
1768 {
1769     bool bEnabled = i_pRight->m_iEnabled ? true : false;
1770     if ( i_pLeft->Enabled != bEnabled )
1771     {
1772         return false;
1773     }
1774     if ( i_pLeft->KMAID != i_pRight->m_lApplianceID )
1775     {
1776         return false;
1777     }
1778     if ( strncmp(i_pLeft->KMASiteID,
1779             i_pRight->m_wsApplianceSiteID,
1780             KMS_MAX_ENTITY_SITE_ID) != 0 )
1781     {
1782         return false;
1783     }
1784     //    Note: we now minimize persistence of cluster changes by not saving
1785     //      whenever m_iResponding changes
1786 
1787     return true;
1788 }
1789 /**
1790  *  @return true if the current address matches the provided IPv6Address
1791  *  when the i_bUseIPv6 arg is true, otherwise compare the current address
1792  *  with the IPv4Address.  If i_bUseIPv6 then i_pCurrentAddress must be
1793  *  enclosed in brackets, i.e. as in RFC 2396.
1794  */
EqualKMANetworkAddress(bool i_bUseIPv6,const char * const i_pIPv6Address,const char * const i_pIPv4Address,const char * const i_pCurrentAddress)1795 static bool EqualKMANetworkAddress (
1796                                     bool i_bUseIPv6,
1797                                     const char * const i_pIPv6Address,
1798                                     const char * const i_pIPv4Address,
1799                                     const char * const i_pCurrentAddress
1800                                     )
1801 {
1802     bool bEqualAddress = true;
1803 
1804     if ( i_pCurrentAddress == NULL )
1805     {
1806         return false;
1807     }
1808 
1809     if (i_bUseIPv6)
1810     {
1811         if ( i_pIPv6Address == NULL )
1812         {
1813             return false;
1814         }
1815         char sIPv6Address[KMS_MAX_NETWORK_ADDRESS] = "[";
1816 
1817         strcat(sIPv6Address, i_pIPv6Address);
1818 
1819         char * pLoc = strchr(sIPv6Address, '/');
1820 
1821         if ( pLoc != NULL )
1822         {
1823             // remove prefix from address
1824             *pLoc = '\0';
1825         }
1826         strcat(sIPv6Address, "]");
1827         bEqualAddress = strncmp(sIPv6Address, i_pCurrentAddress, KMS_MAX_NETWORK_ADDRESS) == 0;
1828     }
1829     else
1830     {
1831         if ( i_pIPv4Address == NULL )
1832         {
1833             return false;
1834         }
1835         bEqualAddress = strncmp(i_pIPv4Address, i_pCurrentAddress, KMS_MAX_NETWORK_ADDRESS) == 0;
1836     }
1837 
1838     return bEqualAddress;
1839 }
1840 
1841 /**
1842  *  compares the profile's current cluster state with the filtered discover
1843  *  cluster response and returns true if the repsonse
1844  *  differs from i_pProfile->m_aCluster.  A cluster has changed if the state of any
1845  *  cluster node has changed or if the set of cluster nodes has changed.
1846  *  The order of nodes is immaterial.
1847  */
ClusterConfigChanged(KMSClientProfile const * i_pProfile,char * const i_sResponseEntitySiteID,struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers const * i_pFilteredCluster)1848 static bool ClusterConfigChanged (
1849                                   KMSClientProfile const *i_pProfile,
1850                                   char * const i_sResponseEntitySiteID,
1851                                   struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers const *i_pFilteredCluster)
1852 {
1853     int i, j;
1854 
1855     FATAL_ASSERT(i_pProfile);
1856     FATAL_ASSERT(i_pFilteredCluster);
1857 
1858     // cardinality check
1859     if (i_pProfile->m_iClusterNum !=
1860         i_pFilteredCluster->__size)
1861     {
1862         return true;
1863     }
1864 
1865     // check if the agent's site ID changed
1866     if (strncmp(i_pProfile->m_wsEntitySiteID,
1867         i_sResponseEntitySiteID, KMS_MAX_ENTITY_SITE_ID) != 0)
1868     {
1869         return true;
1870     }
1871 
1872     // for all KMAs in filtered response check if they exist unchanged in the profile
1873     for (i = 0; i < i_pFilteredCluster->__size; i++)
1874     {
1875         bool bFound = false;
1876         for (j = 0; j < i_pProfile->m_iClusterNum; j++)
1877         {
1878             if (strncmp(i_pFilteredCluster->__ptr[i].KMAName,
1879                     i_pProfile->m_aCluster[j].m_wsApplianceAlias,
1880                     KMS_MAX_ENTITY_ID) == 0)
1881             {
1882                 bFound = true;
1883                 if (
1884                 !EqualKMANetworkAddress(
1885                     strchr(i_pProfile->m_wsApplianceAddress, ':') ? true : false,
1886                     i_pFilteredCluster->__ptr[i].KMANetworkAddressIPv6,
1887                     i_pFilteredCluster->__ptr[i].KMANetworkAddress,
1888                     i_pProfile->m_aCluster[j].m_wsApplianceNetworkAddress) ||
1889                 !EqualClusterEntry((i_pFilteredCluster->__ptr + i),
1890                     &i_pProfile->m_aCluster[j]))
1891 
1892                 {
1893                     return true;
1894                 }
1895             }
1896         }
1897         if ( !bFound )
1898         {
1899             return true;
1900         }
1901     }
1902     return false;
1903 }
1904 
1905 /**
1906  *  returns true if the string is a valid IPv6 address syntactically
1907  */
ValidIPv6KMAaddress(const char * const i_pIPAddress)1908 static bool ValidIPv6KMAaddress( const char * const i_pIPAddress )
1909 {
1910     FATAL_ASSERT( i_pIPAddress );
1911 
1912     if ( strlen(i_pIPAddress) <= 0 )
1913     {
1914         return false;
1915     }
1916 
1917     // simple check
1918     if ( strchr( i_pIPAddress, ':'))
1919     {
1920         return true;
1921     }
1922 
1923     return false;
1924 }
1925 /**
1926  *
1927  */
FreeFilteredCluster(struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster,int iLimit)1928 static void FreeFilteredCluster (
1929                                   struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster,
1930                                   int iLimit )
1931 {
1932     int j = 0;
1933     for (; j < iLimit; j++ )
1934     {
1935         free( io_stFilteredCluster->__ptr[j].KMAName );
1936         free( io_stFilteredCluster->__ptr[j].KMASiteID );
1937         free( io_stFilteredCluster->__ptr[j].KMAHostName );
1938         free( io_stFilteredCluster->__ptr[j].KMANetworkAddress );
1939         free( io_stFilteredCluster->__ptr[j].KMAVersion );
1940         free( io_stFilteredCluster->__ptr[j].KMAHostNameIPv6 );
1941         free( io_stFilteredCluster->__ptr[j].KMANetworkAddressIPv6 );
1942     }
1943 
1944     free( io_stFilteredCluster->__ptr );
1945 }
1946 
1947 /**
1948  *  filters the discover cluster response to be less than or equal to KMS_MAX_CLUSTER_NUM KMAs.  The heuristic used to filter
1949  *  the response is the same as used by CAgentLoadBalancer::KMSClient_SortClusterArray(), FIPS compatibility, then within site,
1950  *  then responding and enabled KMAs.
1951  *  @param i_stResponse pointer to gsoap discover cluster service response
1952  *  @param io_stFilteredCluster pointer to gsoap discover cluster array to be populated with the filtered list of KMAs
1953  *  @return true on success and io_stFilteredCluster->__size less than or equal to KMS_MAX_CLUSTER_NUM,
1954  *  otherwise io_stFilteredCluster is undefined. io_stFilteredCluster->__ptr is populated with the array of elements
1955  *  malloc'd.
1956  */
FilterCluster(struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse * const i_stResponse,bool i_bFIPS,struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster)1957 static bool FilterCluster (struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse * const i_stResponse,
1958                            bool i_bFIPS,
1959                            struct KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers * const io_stFilteredCluster)
1960 {
1961     /*
1962      *  do something like KMSAgentLoadBalancer:SortClusterArray() to the stResponse array
1963      *  return 1st KMS_MAX_CLUSTER_NUM entries and free the rest.
1964     */
1965 
1966     FATAL_ASSERT(i_stResponse);
1967     FATAL_ASSERT(io_stFilteredCluster);
1968 
1969     io_stFilteredCluster->__size = i_stResponse->ArrayOfClusterMembers.__size;
1970     io_stFilteredCluster->__ptr = reinterpret_cast < struct KMS_Discovery::KMS_Discovery_ClusterMember * >
1971             ( calloc( io_stFilteredCluster->__size,
1972                       sizeof (struct KMS_Discovery::KMS_Discovery_ClusterMember ) ) );
1973 
1974     if (io_stFilteredCluster->__ptr == NULL)
1975     {
1976         Log(AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
1977                 NULL,
1978                 NULL,
1979                 "calloc failed");
1980         return false;
1981     }
1982 
1983     if (io_stFilteredCluster->__size <= 0)
1984     {
1985         Log(AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
1986                 NULL,
1987                 NULL,
1988                 "returned cluster size is not positive");
1989         return false;
1990     }
1991 
1992     // copy response cluster members
1993     for (int i = 0; i < io_stFilteredCluster->__size; i++)
1994     {
1995         bool bSuccess = true;
1996 
1997         size_t iKMANameSize = 0, iKMASiteIDSize = 0, iKMAHostNameSize = 0,
1998                 iKMANetworkAddressSize = 0, iKMAVersionSize = 0, iKMAHostNameIPv6Size = 0,
1999                 iKMANetworkAddressIPv6Size = 0;
2000 
2001         // allocate storage for the various struct member's arrays
2002         iKMANameSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAName)+1;
2003         io_stFilteredCluster->__ptr[i].KMAName = reinterpret_cast <char *> (malloc(iKMANameSize));
2004 
2005         iKMASiteIDSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMASiteID)+1;
2006         io_stFilteredCluster->__ptr[i].KMASiteID = reinterpret_cast <char *> (malloc(iKMASiteIDSize));
2007 
2008         iKMAHostNameSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostName)+1;
2009         io_stFilteredCluster->__ptr[i].KMAHostName = reinterpret_cast <char *> (malloc(iKMAHostNameSize));
2010 
2011         iKMANetworkAddressSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddress)+1;
2012         io_stFilteredCluster->__ptr[i].KMANetworkAddress = reinterpret_cast <char *> (malloc(iKMANetworkAddressSize));
2013 
2014         // KMAVersion is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
2015         if (i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAVersion)
2016         {
2017             iKMAVersionSize = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAVersion)+1;
2018             io_stFilteredCluster->__ptr[i].KMAVersion = reinterpret_cast <char *> (malloc(iKMAVersionSize));
2019             if (io_stFilteredCluster->__ptr[i].KMAVersion == NULL)
2020             {
2021                 bSuccess = false;
2022             }
2023         }
2024         else
2025         {
2026             io_stFilteredCluster->__ptr[i].KMAVersion = NULL;
2027         }
2028 
2029         // KMAHostNameIPv6 is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
2030         if (i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostNameIPv6)
2031         {
2032             iKMAHostNameIPv6Size = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostNameIPv6)+1;
2033             io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 = reinterpret_cast <char *> (malloc(iKMAHostNameIPv6Size));
2034             if ( io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 == NULL )
2035             {
2036                 bSuccess = false;
2037             }
2038         }
2039         else
2040         {
2041             io_stFilteredCluster->__ptr[i].KMAHostNameIPv6 = NULL;
2042         }
2043 
2044         // KMANetworkAddressIPv6 is an optional field derived from an xml attribute in the soap interface that will not be present in 2.0 KMAs
2045         if (i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6)
2046         {
2047             iKMANetworkAddressIPv6Size = strlen(i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6)+1;
2048             io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 = reinterpret_cast <char *> (malloc(iKMANetworkAddressIPv6Size));
2049             if ( io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 == NULL )
2050             {
2051                 bSuccess = false;
2052             }
2053             }
2054         else
2055         {
2056             io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 = NULL;
2057         }
2058 
2059         if ( io_stFilteredCluster->__ptr[i].KMAName == NULL ||
2060              io_stFilteredCluster->__ptr[i].KMASiteID == NULL ||
2061              io_stFilteredCluster->__ptr[i].KMAHostName == NULL ||
2062              io_stFilteredCluster->__ptr[i].KMANetworkAddress == NULL ||
2063              !bSuccess )
2064         {
2065             // cleanup and return
2066             FreeFilteredCluster( io_stFilteredCluster, i+1 );
2067             Log( AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
2068                     NULL,
2069                     NULL,
2070                     "malloc failed" );
2071             return false;
2072         }
2073 
2074         strncpy(io_stFilteredCluster->__ptr[i].KMAName,
2075                 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAName,
2076                 iKMANameSize);
2077         io_stFilteredCluster->__ptr[i].KMAName[iKMANameSize-1] = '\0';
2078 
2079         strncpy(io_stFilteredCluster->__ptr[i].KMASiteID,
2080                 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMASiteID,
2081                 iKMASiteIDSize);
2082         io_stFilteredCluster->__ptr[i].KMASiteID[iKMASiteIDSize-1] = '\0';
2083 
2084         strncpy(io_stFilteredCluster->__ptr[i].KMAHostName,
2085                 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostName,
2086                 iKMAHostNameSize);
2087         io_stFilteredCluster->__ptr[i].KMAHostName[iKMAHostNameSize-1] = '\0';
2088 
2089         strncpy(io_stFilteredCluster->__ptr[i].KMANetworkAddress,
2090                 i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddress,
2091                 iKMANetworkAddressSize);
2092         io_stFilteredCluster->__ptr[i].KMANetworkAddress[iKMANetworkAddressSize-1] = '\0';
2093 
2094         if ( io_stFilteredCluster->__ptr[i].KMAVersion )
2095         {
2096             strncpy( io_stFilteredCluster->__ptr[i].KMAVersion,
2097                     i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAVersion,
2098                     iKMAVersionSize );
2099             io_stFilteredCluster->__ptr[i].KMAVersion[iKMAVersionSize-1] = '\0';
2100         }
2101 
2102         if (io_stFilteredCluster->__ptr[i].KMAHostNameIPv6)
2103         {
2104             strncpy(io_stFilteredCluster->__ptr[i].KMAHostNameIPv6,
2105                     i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAHostNameIPv6,
2106                     iKMAHostNameIPv6Size);
2107             io_stFilteredCluster->__ptr[i].KMAHostNameIPv6[iKMAHostNameIPv6Size-1] = '\0';
2108         }
2109 
2110         if ( io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6 )
2111         {
2112             strncpy( io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6,
2113                     i_stResponse->ArrayOfClusterMembers.__ptr[i].KMANetworkAddressIPv6,
2114                     iKMANetworkAddressIPv6Size );
2115             io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6[iKMANetworkAddressIPv6Size-1] = '\0';
2116         }
2117 
2118         io_stFilteredCluster->__ptr[i].KMAID = i_stResponse->ArrayOfClusterMembers.__ptr[i].KMAID;
2119         io_stFilteredCluster->__ptr[i].Enabled = i_stResponse->ArrayOfClusterMembers.__ptr[i].Enabled;
2120         io_stFilteredCluster->__ptr[i].KMS_Discovery__Locked = i_stResponse->ArrayOfClusterMembers.__ptr[i].KMS_Discovery__Locked;
2121 
2122         // set load to zero, KMA with version <= Build600 don't initialize
2123         // the load field from the service network
2124         if ( ( io_stFilteredCluster->__ptr[i].KMAVersion &&
2125              strcmp( io_stFilteredCluster->__ptr[i].KMAVersion, "Build600" ) <= 0 ) ||
2126              io_stFilteredCluster->__ptr[i].KMAVersion == NULL )
2127         {
2128             io_stFilteredCluster->__ptr[i].Load = 0;
2129         }
2130         else
2131         {
2132             io_stFilteredCluster->__ptr[i].Load = i_stResponse->ArrayOfClusterMembers.__ptr[i].Load;
2133         }
2134 
2135         io_stFilteredCluster->__ptr[i].Responding = i_stResponse->ArrayOfClusterMembers.__ptr[i].Responding;
2136 
2137         if (!bSuccess)
2138         {
2139             FreeFilteredCluster( io_stFilteredCluster, i );
2140             Log(AUDIT_CLIENT_FILTER_CLUSTER_FAILED,
2141                     NULL,
2142                     NULL,
2143                     "cluster member copy failed");
2144             return false;
2145         }
2146     }
2147 
2148     // is filtering necessary?
2149     if (io_stFilteredCluster->__size <= KMS_MAX_CLUSTER_NUM)
2150     {
2151         // no filtering required
2152         return true;
2153     }
2154     else
2155     {
2156         char sMesg[100];
2157         K_snprintf(sMesg, sizeof (sMesg), "DiscoverCluster returned %d KMAs, filtering to %d ...", io_stFilteredCluster->__size, KMS_MAX_CLUSTER_NUM);
2158         Log(AUDIT_CLIENT_FILTER_CLUSTER,
2159                     NULL,
2160                     NULL,
2161                     sMesg);
2162 
2163     }
2164 
2165     // adjust loads according to availability, site and FIPS compatibility
2166     {
2167         int i = 0;
2168         for (; i < io_stFilteredCluster->__size; i++)
2169         {
2170             if (io_stFilteredCluster->__ptr[i].Enabled == false
2171                 || io_stFilteredCluster->__ptr[i].Responding == false
2172                 || io_stFilteredCluster->__ptr[i].KMS_Discovery__Locked == true)
2173             {
2174                 io_stFilteredCluster->__ptr[i].Load += 0x40;
2175             }
2176 
2177             if (strcmp(io_stFilteredCluster->__ptr[i].KMASiteID,
2178                 i_stResponse->EntitySiteID) != 0)
2179             {
2180                 io_stFilteredCluster->__ptr[i].Load += 0x20;
2181 
2182             }
2183 
2184             if ( i_bFIPS &&
2185                     !FIPScompatibleKMA(io_stFilteredCluster->__ptr[i].KMAVersion))
2186             {
2187                 io_stFilteredCluster->__ptr[i].Load += 0x80;
2188             }
2189         }
2190     }
2191 
2192     // sort ascending by load
2193 
2194     // gnome sort: the simplest sort algoritm
2195     {
2196         int i = 0;
2197         while (i < io_stFilteredCluster->__size)
2198         {
2199             if (i == 0 || io_stFilteredCluster->__ptr[i - 1].Load <= io_stFilteredCluster->__ptr[i].Load)
2200             {
2201                 i++;
2202             }
2203             else
2204             {
2205                 struct KMS_Discovery::KMS_Discovery_ClusterMember tmp = io_stFilteredCluster->__ptr[i];
2206                 io_stFilteredCluster->__ptr[i] = io_stFilteredCluster->__ptr[i - 1];
2207                 io_stFilteredCluster->__ptr[--i] = tmp;
2208             }
2209         }
2210     }
2211 
2212     // now filter the list, freeing memory allocated for copied elements that are not being retained
2213     {
2214         int i=KMS_MAX_CLUSTER_NUM;
2215         for (; i < io_stFilteredCluster->__size; i++)
2216         {
2217             free(io_stFilteredCluster->__ptr[i].KMAName);
2218             free(io_stFilteredCluster->__ptr[i].KMASiteID);
2219             free(io_stFilteredCluster->__ptr[i].KMAHostName);
2220             free(io_stFilteredCluster->__ptr[i].KMANetworkAddress);
2221             free(io_stFilteredCluster->__ptr[i].KMAVersion);
2222             free(io_stFilteredCluster->__ptr[i].KMAHostNameIPv6);
2223             free(io_stFilteredCluster->__ptr[i].KMANetworkAddressIPv6);
2224         }
2225     }
2226 
2227     io_stFilteredCluster->__size = KMS_MAX_CLUSTER_NUM;
2228 
2229     Log(AUDIT_CLIENT_FILTER_CLUSTER,
2230                 NULL,
2231                 NULL,
2232                 "success");
2233 
2234     return true;
2235 };
2236 
2237 /*---------------------------------------------------------------------------
2238  * Function: KMSClient_GetClusterInformation
2239  *
2240  *--------------------------------------------------------------------------*/
KMSClient_GetClusterInformation(KMSClientProfile * i_pProfile,utf8char * o_wsEntitySiteID,int i_iEntitySiteIDSize,int * o_pApplianceNum,KMSClusterEntry * o_pClusterEntryArray,int i_iClusterEntryArraySize)2241 bool KMSClient_GetClusterInformation(
2242         KMSClientProfile *i_pProfile,
2243         utf8char *o_wsEntitySiteID,
2244         int i_iEntitySiteIDSize,
2245         int *o_pApplianceNum,
2246         KMSClusterEntry *o_pClusterEntryArray,
2247         int i_iClusterEntryArraySize)
2248 {
2249    FATAL_ASSERT(i_pProfile);
2250    FATAL_ASSERT( o_wsEntitySiteID );
2251    FATAL_ASSERT( o_pApplianceNum );
2252    FATAL_ASSERT( o_pClusterEntryArray );
2253    FATAL_ASSERT( i_iEntitySiteIDSize <= KMS_MAX_ENTITY_ID+1 );
2254 
2255    CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
2256 
2257    bool bSuccess = true;
2258    char sSoapFaultMsg[g_iMAX_SOAP_FAULT_MESSAGE_LENGTH];
2259    char sKmaAddress[g_iMAX_PEER_NETWORK_ADDRESS_LENGTH];
2260 
2261    char sURL[KMS_MAX_URL+1];
2262 
2263    // set URL from the initial appliance address
2264    utf8cstr sApplianceAddress = i_pProfile->m_wsApplianceAddress;
2265 
2266 #if defined(DEBUG) && defined(METAWARE)
2267     log_printf("KMSClient_GetClusterInformation : entered");
2268 #endif
2269 
2270    K_snprintf(sURL,
2271            KMS_MAX_URL,
2272            "https://%s:%d",
2273            sApplianceAddress,
2274            i_pProfile->m_iPortForDiscoveryService);
2275    strncpy(i_pProfile->m_sURL, sURL, KMS_MAX_URL);
2276    i_pProfile->m_sURL[KMS_MAX_URL] = 0;
2277 
2278    // allocate and initialize a new soap env for the cluster discovery call
2279    struct soap *pstSoap = (struct soap*)i_pProfile->m_pvDiscoverySoap;
2280 
2281    if ( !i_pProfile->m_iEnrolled )
2282    {
2283         bSuccess = false;
2284    }
2285 
2286    if ( bSuccess )
2287    {
2288 	   // allocate discovery soap runtime
2289 	   if (pstSoap == NULL )
2290 	   {
2291    	   	   pstSoap = soap_new();
2292 		   i_pProfile->m_pvDiscoverySoap = pstSoap;
2293            /* soap_copy results in a segfault in sk_free() within libcrytpo.so
2294            pstSoap = soap_copy( (soap*)i_pProfile->m_pvSoap );
2295            */
2296            if (pstSoap == NULL)
2297            {
2298                bSuccess = false;
2299            }
2300            else
2301            {
2302                pstSoap->connect_timeout = i_pProfile->m_iTransactionTimeout;
2303                pstSoap->send_timeout = i_pProfile->m_iTransactionTimeout;
2304                pstSoap->recv_timeout = i_pProfile->m_iTransactionTimeout;
2305 
2306                soap_set_imode( pstSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
2307                soap_set_omode( pstSoap, (SOAP_XML_STRICT | SOAP_C_UTFSTRING) );
2308 
2309                soap_set_namespaces( pstSoap, KMS_Discovery_namespaces );
2310                bSuccess = K_soap_ssl_client_context(
2311                                i_pProfile,
2312                                pstSoap,
2313                                SOAP_SSL_REQUIRE_CLIENT_AUTHENTICATION
2314                                 ) == SOAP_OK;
2315                if ( !bSuccess )
2316                {
2317                     Log(AUDIT_CLIENT_GetClusterInformation,
2318                        NULL,
2319                        NULL,
2320                        "K_soap_ssl_client_context failed");
2321                     soap_destroy(pstSoap);
2322                     soap_end(pstSoap);
2323                     soap_done(pstSoap);
2324                }
2325            }
2326 	   }
2327    }
2328 
2329    // Discovery
2330    struct KMS_Discovery::KMS_Discovery__DiscoverClusterResponse stResponse;
2331 
2332 #if defined(DEBUG) && defined(METAWARE)
2333     log_printf("KMSClient_GetClusterInformation : call KMS_Discovery_DiscoverCluster");
2334 #endif
2335 
2336     // SOAP - discover cluster
2337    if ( bSuccess )
2338    {
2339 #ifdef DEBUG
2340       int iStartTickCount = K_GetTickCount();
2341       int iEndTickCount;
2342       char sDiscoverTimeMsg[100];
2343 #endif
2344       bSuccess =
2345          KMS_Discovery::soap_call_KMS_Discovery__DiscoverCluster(
2346             pstSoap,
2347             sURL,
2348             NULL,
2349             NULL,
2350             stResponse ) == SOAP_OK;
2351 #ifdef DEBUG
2352       iEndTickCount = K_GetTickCount();
2353       sprintf(sDiscoverTimeMsg, "DiscoverCluster soapcall elapsed time=%u ms",
2354               iEndTickCount-iStartTickCount);
2355       Log(AUDIT_CLIENT_GetClusterInformation,
2356            NULL,
2357            sApplianceAddress,
2358            sDiscoverTimeMsg);
2359 #endif
2360 
2361       if ( !bSuccess )
2362       {
2363          GetSoapFault(sSoapFaultMsg, (struct soap*)pstSoap);
2364          GetPeerNetworkAddress(sKmaAddress, pstSoap);
2365          LogError(i_pProfile,AUDIT_CLIENT_GET_CLUSTER_INFORMATION_SOAP_ERROR,
2366                   NULL,
2367                   sKmaAddress,
2368                   sSoapFaultMsg );
2369 
2370          if ( !ServerError( sSoapFaultMsg, pstSoap->errnum ) )
2371          {
2372                 // do not failover if error is client related
2373                 soap_destroy( pstSoap );
2374                 soap_end( pstSoap );
2375                 soap_free( pstSoap );
2376                 return false;
2377          }
2378       }
2379 
2380       // If we did not succeed to Discover from the initial appliance,
2381       // try to discover from other appliances that we know about that are enabled.
2382       // Disabled Appliances are not attempted because they may have a stale view
2383       // of the cluster. In particular, they themselves are not aware that they
2384       // are disabled.
2385 
2386       if ( !bSuccess && i_pProfile->m_iClusterNum > 0 )
2387       {
2388          // Copy the profile's cluster array so that we don't have to lock the
2389          // profile around a SOAP call
2390 
2391          int j = 0;
2392          int iClusterNum = 0;
2393          KMSClusterEntry* aCluster =
2394             (KMSClusterEntry*)malloc(sizeof(KMSClusterEntry) * KMS_MAX_CLUSTER_NUM);
2395 
2396          bSuccess = ( aCluster != 0 );
2397 #if defined(DEBUG) && defined(METAWARE)
2398         if (!bSuccess)
2399            log_printf("Malloc %x aCluster returned null\n",
2400                       sizeof(KMSClusterEntry) * KMS_MAX_CLUSTER_NUM);
2401 #endif
2402 
2403          if ( bSuccess )
2404          {
2405             iClusterNum = i_pProfile->m_iClusterNum;
2406             memcpy( aCluster, i_pProfile->m_aCluster,
2407                     sizeof(KMSClusterEntry) * iClusterNum );
2408 
2409             // initialize to false since all KMAs could be disabled
2410             bSuccess = false;
2411             for ( j = 0; j < iClusterNum; j++ )
2412             {
2413                if ( aCluster[j].m_iEnabled == FALSE )
2414                {
2415                   continue;
2416                }
2417 
2418                sApplianceAddress = aCluster[j].m_wsApplianceNetworkAddress;
2419                K_snprintf(sURL,
2420                        KMS_MAX_URL,
2421                        "https://%s:%d",
2422                        sApplianceAddress,
2423                        i_pProfile->m_iPortForDiscoveryService);
2424 
2425                Log(AUDIT_CLIENT_GetClusterInformation,
2426                    NULL,
2427                    sApplianceAddress,
2428                    "Failing over and trying this appliance");
2429 
2430                // SOAP - discover cluster
2431                bSuccess =
2432                   KMS_Discovery::soap_call_KMS_Discovery__DiscoverCluster(
2433                      pstSoap,
2434                      sURL,
2435                      NULL,
2436                      NULL,
2437                      stResponse ) == SOAP_OK;
2438 
2439                if ( !bSuccess )
2440                {
2441                   GetSoapFault(sSoapFaultMsg, (struct soap*)pstSoap);
2442                   GetPeerNetworkAddress(sKmaAddress, pstSoap);
2443                   LogError(i_pProfile,AUDIT_CLIENT_GET_CLUSTER_INFORMATION_SOAP_ERROR,
2444                            NULL,
2445                            sKmaAddress,
2446                            sSoapFaultMsg );
2447                }
2448                else
2449                {
2450                   // The discover succeeded
2451                   break;
2452                }
2453             }
2454          }
2455 
2456          if ( aCluster != 0 )
2457          {
2458             free(aCluster);
2459          }
2460 
2461          if ( bSuccess )
2462          {
2463             // Set the Profile's initial appliance to the Appliance
2464             // that we just succeeded to Discover from. KMSClient_SelectAppliance()
2465             // persists the updated config
2466             KMSClient_SelectAppliance( i_pProfile,
2467                                        i_pProfile->m_aCluster[j].m_wsApplianceNetworkAddress );
2468          }
2469       }
2470    }
2471 
2472    if ( bSuccess )
2473    {
2474       if (((int)strlen(stResponse.EntitySiteID) > i_iEntitySiteIDSize - 1))
2475       {
2476          bSuccess = false;
2477          LogError(i_pProfile,AUDIT_CLIENT_GET_CLUSTER_INFORMATION,
2478                   NULL,
2479                   NULL,
2480                   "returned site id size too large" );
2481       }
2482    }
2483 
2484    // copy returned cluster information into i_pProfile->m_aCluster after
2485    // filtering the cluster members to a list with size <= KMS_MAX_CLUSTER_NUM
2486    if ( bSuccess )
2487    {
2488       KMS_Discovery::KMS_Discovery__ArrayOfClusterMembers aFilteredCluster;
2489 
2490       bSuccess = FilterCluster(&stResponse, i_pProfile->m_eKMSmode == FIPS_MODE, &aFilteredCluster);
2491       if (!bSuccess )
2492       {
2493           LogError(i_pProfile, AUDIT_CLIENT_GET_CLUSTER_INFORMATION,
2494                   NULL,
2495                   NULL,
2496                   "cluster response filtering failed" );
2497       }
2498 
2499       if(bSuccess)
2500       {
2501          int i;
2502          bool bPersistClusterConfig = ClusterConfigChanged(i_pProfile,
2503                     stResponse.EntitySiteID,
2504                     &aFilteredCluster);
2505 
2506          strncpy(o_wsEntitySiteID,stResponse.EntitySiteID, i_iEntitySiteIDSize-1 );
2507          o_wsEntitySiteID[i_iEntitySiteIDSize-1] = '\0';
2508 
2509          strncpy(i_pProfile->m_wsEntitySiteID, stResponse.EntitySiteID, i_iEntitySiteIDSize-1 );
2510          i_pProfile->m_wsEntitySiteID[i_iEntitySiteIDSize-1] = '\0';
2511 
2512          // fill the aCluster array in the i_pProfile
2513          i_pProfile->m_iClusterNum = aFilteredCluster.__size;
2514          for (i = 0;  i < i_pProfile->m_iClusterNum; i++)
2515          {
2516             i_pProfile->m_aCluster[i].m_lApplianceID =
2517                (aFilteredCluster.__ptr+i)->KMAID;
2518             i_pProfile->m_aCluster[i].m_iEnabled =
2519                (aFilteredCluster.__ptr+i)->Enabled;
2520             i_pProfile->m_aCluster[i].m_iResponding =
2521                (aFilteredCluster.__ptr+i)->Responding;
2522 
2523             i_pProfile->m_aCluster[i].m_lLoad = (aFilteredCluster.__ptr+i)->Load;
2524             strncpy(i_pProfile->m_aCluster[i].m_wsApplianceAlias,
2525                    (aFilteredCluster.__ptr+i)->KMAName,
2526                    KMS_MAX_ENTITY_ID);
2527             i_pProfile->m_aCluster[i].m_wsApplianceAlias[KMS_MAX_ENTITY_ID] = '\0';
2528             // if the m_wsApplianceAddress is IPv6 then we'll store
2529             // KMA IPv6 addresses if they have one
2530             if ( strchr( i_pProfile->m_wsApplianceAddress, ':') )
2531             {
2532                 // KMAs prior to 2.1, or 2.1 KMAs at rep schema < 10
2533                 // will not have IPv6 attributes in the soap response
2534                 if ( (aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6 &&
2535                       ValidIPv6KMAaddress((aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6))
2536                 {
2537                     strcpy(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress, "[");
2538                     char * pLoc = strchr((aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6,
2539                             '/');
2540                     if ( pLoc != NULL )
2541                     {
2542                         // remove prefix from address
2543                         *pLoc = '\0';
2544                         strcat(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2545                                (aFilteredCluster.__ptr+i)->KMANetworkAddressIPv6 );
2546                     }
2547                     else
2548                     {
2549                         strcat(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2550                                 (aFilteredCluster.__ptr + i)->KMANetworkAddressIPv6);
2551                     }
2552                     strcat(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress, "]");
2553                 }
2554                 else
2555                 {
2556                     // use the IPv4 address
2557                     strncpy(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2558                            (aFilteredCluster.__ptr+i)->KMANetworkAddress,
2559                            KMS_MAX_NETWORK_ADDRESS);
2560                 }
2561             }
2562             else
2563             {
2564                 strncpy(i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2565                        (aFilteredCluster.__ptr+i)->KMANetworkAddress,
2566                        KMS_MAX_NETWORK_ADDRESS);
2567             }
2568             i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS] = '\0';
2569             strncpy(i_pProfile->m_aCluster[i].m_wsApplianceSiteID,
2570                    (aFilteredCluster.__ptr+i)->KMASiteID,
2571                    KMS_MAX_ENTITY_SITE_ID);
2572             i_pProfile->m_aCluster[i].m_wsApplianceSiteID[KMS_MAX_ENTITY_SITE_ID] = '\0';
2573 
2574             if ((aFilteredCluster.__ptr + i)->KMAVersion)
2575             {
2576                 strncpy(i_pProfile->m_aCluster[i].m_sKMAVersion,
2577                         (aFilteredCluster.__ptr + i)->KMAVersion,
2578                         KMS_MAX_VERSION_LENGTH);
2579                 i_pProfile->m_aCluster[i].m_sKMAVersion[KMS_MAX_VERSION_LENGTH] = '\0';
2580             }
2581             else
2582             {
2583                 i_pProfile->m_aCluster[i].m_sKMAVersion[0] = '\0';
2584             }
2585 
2586             if ((aFilteredCluster.__ptr + i)->KMS_Discovery__Locked)
2587             {
2588                 i_pProfile->m_aCluster[i].m_iKMALocked = TRUE;
2589             }
2590             else
2591             {
2592                 i_pProfile->m_aCluster[i].m_iKMALocked = FALSE;
2593             }
2594          }
2595 
2596          // now release malloc'd storage from filtering the cluster response
2597          FreeFilteredCluster( &aFilteredCluster, aFilteredCluster.__size );
2598 
2599          // fill the array specified by the caller
2600          *o_pApplianceNum = i_pProfile->m_iClusterNum;
2601          for (i = 0;  i < i_pProfile->m_iClusterNum; i++)
2602          {
2603             o_pClusterEntryArray[i].m_lApplianceID = i_pProfile->m_aCluster[i].m_lApplianceID;
2604             o_pClusterEntryArray[i].m_iEnabled = i_pProfile->m_aCluster[i].m_iEnabled;
2605             o_pClusterEntryArray[i].m_iResponding = i_pProfile->m_aCluster[i].m_iResponding;
2606             o_pClusterEntryArray[i].m_lLoad = i_pProfile->m_aCluster[i].m_lLoad;
2607             strncpy(o_pClusterEntryArray[i].m_wsApplianceAlias,
2608                    i_pProfile->m_aCluster[i].m_wsApplianceAlias,
2609                    KMS_MAX_ENTITY_ID);
2610             o_pClusterEntryArray[i].m_wsApplianceAlias[KMS_MAX_ENTITY_ID] = '\0';
2611             strncpy(o_pClusterEntryArray[i].m_wsApplianceNetworkAddress,
2612                    i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2613                    KMS_MAX_NETWORK_ADDRESS);
2614             o_pClusterEntryArray[i].m_wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS] = '\0';
2615             strncpy(o_pClusterEntryArray[i].m_wsApplianceSiteID,
2616                    i_pProfile->m_aCluster[i].m_wsApplianceSiteID,
2617                    KMS_MAX_ENTITY_SITE_ID);
2618             o_pClusterEntryArray[i].m_wsApplianceSiteID[KMS_MAX_ENTITY_SITE_ID] = '\0';
2619             strncpy(o_pClusterEntryArray[i].m_sKMAVersion, i_pProfile->m_aCluster[i].m_sKMAVersion,
2620                     KMS_MAX_VERSION_LENGTH);
2621             o_pClusterEntryArray[i].m_sKMAVersion[KMS_MAX_VERSION_LENGTH] = '\0';
2622          }
2623 
2624          i_pProfile->m_iLastClusterDiscoveryTime = K_GetTickCount() / 1000;
2625          i_pProfile->m_bIsClusterDiscoveryCalled = true;
2626 
2627          if ( bPersistClusterConfig )
2628          {
2629              bSuccess = StoreCluster(i_pProfile);
2630              if (!bSuccess)
2631              {
2632                  Log(AUDIT_CLIENT_GetClusterInformation,
2633                      NULL,
2634                      NULL,
2635                      "Could not store cluster");
2636              }
2637          }
2638       }
2639    }
2640 
2641    // cleanup
2642    if (pstSoap)
2643    {
2644       soap_destroy(pstSoap);
2645       soap_end(pstSoap);
2646       if (!bSuccess)
2647       {
2648           soap_free(pstSoap);
2649       }
2650       else
2651       {
2652         // we want to persist discovery soap runtime to avoid ssl handshakes so soap_free() is not called
2653       }
2654    }
2655 
2656    // if we're enrolled but cannot get cluster information from an appliance, then we'll try to load
2657    // it from the profile
2658    if ( !bSuccess && i_pProfile->m_iEnrolled )
2659    {
2660       int bClusterInformationFound = false;
2661 
2662       bSuccess = LoadClusterInformation( i_pProfile, bClusterInformationFound );
2663 
2664       if ( bSuccess && bClusterInformationFound )
2665       {
2666          Log(AUDIT_CLIENT_GetClusterInformation,
2667                  NULL,
2668                  NULL,
2669                  "Using persisted cluster information");
2670 
2671          strncpy(o_wsEntitySiteID, i_pProfile->m_wsEntitySiteID, i_iEntitySiteIDSize-1);
2672          o_wsEntitySiteID[i_iEntitySiteIDSize-1] = '\0';
2673 
2674          // fill the array specified by the caller
2675          *o_pApplianceNum = i_pProfile->m_iClusterNum;
2676          for (int i = 0;  i < i_pProfile->m_iClusterNum; i++)
2677          {
2678             o_pClusterEntryArray[i].m_lApplianceID = i_pProfile->m_aCluster[i].m_lApplianceID;
2679             o_pClusterEntryArray[i].m_iEnabled = i_pProfile->m_aCluster[i].m_iEnabled;
2680             o_pClusterEntryArray[i].m_iResponding = TRUE; // since cluster info comes from a file, set it to TRUE
2681 
2682             o_pClusterEntryArray[i].m_lLoad = i_pProfile->m_aCluster[i].m_lLoad;
2683             strncpy(o_pClusterEntryArray[i].m_wsApplianceAlias,
2684                    i_pProfile->m_aCluster[i].m_wsApplianceAlias,
2685                    KMS_MAX_ENTITY_ID);
2686             o_pClusterEntryArray[i].m_wsApplianceAlias[KMS_MAX_ENTITY_ID] = '\0';
2687             strncpy(o_pClusterEntryArray[i].m_wsApplianceNetworkAddress,
2688                    i_pProfile->m_aCluster[i].m_wsApplianceNetworkAddress,
2689                    KMS_MAX_NETWORK_ADDRESS);
2690             o_pClusterEntryArray[i].m_wsApplianceNetworkAddress[KMS_MAX_NETWORK_ADDRESS] = '\0';
2691             strncpy(o_pClusterEntryArray[i].m_wsApplianceSiteID,
2692                    i_pProfile->m_aCluster[i].m_wsApplianceSiteID,
2693                    KMS_MAX_ENTITY_SITE_ID);
2694             o_pClusterEntryArray[i].m_wsApplianceSiteID[KMS_MAX_ENTITY_SITE_ID] = '\0';
2695             strncpy(o_pClusterEntryArray[i].m_sKMAVersion,
2696                     i_pProfile->m_aCluster[i].m_sKMAVersion,
2697                     KMS_MAX_VERSION_LENGTH);
2698             o_pClusterEntryArray[i].m_sKMAVersion[KMS_MAX_VERSION_LENGTH] = '\0';
2699          }
2700 
2701          i_pProfile->m_iLastClusterDiscoveryTime = K_GetTickCount() / 1000;
2702       }
2703       else if ( bSuccess && !bClusterInformationFound )
2704       {
2705          // if we're here, then we need to return an error
2706          bSuccess = false;
2707       }
2708    }
2709 
2710    return bSuccess;
2711 }
2712 
KMSClient_NoFIPSCompatibleKMAs(const KMSClientProfile * const i_pProfile)2713 bool KMSClient_NoFIPSCompatibleKMAs(const KMSClientProfile * const i_pProfile)
2714 {
2715     bool bNoFIPScompatibleKMA = true;
2716     for (int i=0; i < i_pProfile->m_iClusterNum; i++)
2717     {
2718         if ( FIPScompatibleKMA(i_pProfile->m_aCluster[i].m_sKMAVersion))
2719         {
2720             bNoFIPScompatibleKMA = false;
2721             break;
2722         }
2723     }
2724     return bNoFIPScompatibleKMA;
2725 }
2726 
2727 /*---------------------------------------------------------------------------
2728  * Function: KMSClient_SelectAppliance
2729  *
2730  *--------------------------------------------------------------------------*/
KMSClient_SelectAppliance(KMSClientProfile * i_pProfile,utf8char * i_wsApplianceAddress)2731 bool KMSClient_SelectAppliance(KMSClientProfile *i_pProfile,
2732                                 utf8char *i_wsApplianceAddress)
2733 {
2734     FATAL_ASSERT(i_pProfile);
2735     FATAL_ASSERT(i_wsApplianceAddress);
2736 
2737     CAutoMutex oAutoMutex( (K_MUTEX_HANDLE)i_pProfile->m_pLock );
2738 
2739     bool bSuccess = true;
2740 
2741     if(strlen(i_wsApplianceAddress) >= KMS_MAX_NETWORK_ADDRESS)
2742     {
2743         LogError(i_pProfile,AUDIT_CLIENT_SELECT_APPLIANCE,
2744             NULL,
2745             NULL,
2746             "Appliance Address too large" );
2747         bSuccess = false;
2748     }
2749 
2750     if(bSuccess)
2751     {
2752         strncpy(i_pProfile->m_wsApplianceAddress,
2753             i_wsApplianceAddress,
2754             KMS_MAX_NETWORK_ADDRESS);
2755         i_pProfile->m_wsApplianceAddress[KMS_MAX_NETWORK_ADDRESS] = 0;
2756     }
2757 
2758     bSuccess = StoreConfig( i_pProfile );
2759 
2760     return bSuccess;
2761 }
2762 
KMSClient_ProfileLoaded(KMSClientProfile * i_pProfile)2763 bool KMSClient_ProfileLoaded( KMSClientProfile *i_pProfile )
2764 {
2765 
2766 #if defined(DEBUG) && defined(METAWARE)
2767    log_printf ("profile: %x", i_pProfile);
2768    log_printf ("profile: enrolled %x", i_pProfile->m_iEnrolled);
2769    log_printf ("profile: version  %x", i_pProfile->m_iVersion);
2770 #endif
2771 
2772     // more extensive tests could be performed but this should suffice
2773     if ( i_pProfile &&
2774         i_pProfile->m_iEnrolled &&
2775 		i_pProfile->m_iVersion == KMS_AGENT_VERSION )
2776     {
2777         return true;
2778     }
2779     else
2780     {
2781         return false;
2782     }
2783 }
2784 
2785 /*---------------------------------------------------------------------------
2786  * Function: KMSClient_DeleteProfile
2787  *
2788  *--------------------------------------------------------------------------*/
KMSClient_DeleteProfile(utf8char * i_wsProfileName)2789 bool KMSClient_DeleteProfile(utf8char *i_wsProfileName)
2790 {
2791     FATAL_ASSERT( i_wsProfileName && (strlen(i_wsProfileName) > 0) );
2792 
2793     bool bSuccess = true;
2794 
2795     if (ProfileExists(g_wsWorkingDirectory, /* pass in default */
2796                       i_wsProfileName))
2797     {
2798         bSuccess = DeleteStorageProfile(i_wsProfileName);
2799     }
2800 
2801     return bSuccess;
2802 }
2803 
2804 /*---------------------------------------------------------------------------
2805  * Function: KMSClient_UnloadProfile
2806  *
2807  *--------------------------------------------------------------------------*/
KMSClient_UnloadProfile(KMSClientProfile * i_pProfile)2808 bool KMSClient_UnloadProfile(KMSClientProfile *i_pProfile)
2809 {
2810     if(i_pProfile != NULL && i_pProfile->m_pLock != NULL )
2811     {
2812 #ifdef KMSUSERPKCS12
2813 	/* Delete the private client key file if it's still around */
2814 	CleanupPrivateKeyFile(i_pProfile);
2815 #endif
2816         if (i_pProfile->m_pAgentLoadBalancer != NULL)
2817         {
2818             delete reinterpret_cast
2819                 <CAgentLoadBalancer *> (i_pProfile->m_pAgentLoadBalancer);
2820         }
2821         if (i_pProfile->m_pDataUnitCache != NULL)
2822         {
2823             delete reinterpret_cast<CDataUnitCache *> (i_pProfile->m_pDataUnitCache);
2824         }
2825         K_DestroyMutex((K_MUTEX_HANDLE)i_pProfile->m_pLock);
2826         i_pProfile->m_pLock = 0;
2827 
2828         if ( i_pProfile->m_pvSoap )
2829         {
2830             soap_destroy( (struct soap*)i_pProfile->m_pvSoap );
2831             soap_end( (struct soap*)i_pProfile->m_pvSoap );
2832             soap_done( (struct soap*)i_pProfile->m_pvSoap );
2833 
2834             free( (struct soap*)i_pProfile->m_pvSoap );
2835             i_pProfile->m_pvSoap = 0;
2836         }
2837 
2838         if ( i_pProfile->m_pvDiscoverySoap)
2839         {
2840             soap_destroy( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2841             soap_end( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2842             soap_done( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2843 
2844             free( (struct soap*)i_pProfile->m_pvDiscoverySoap );
2845             i_pProfile->m_pvDiscoverySoap = 0;
2846         }
2847     }
2848 
2849     i_pProfile->m_iEnrolled = FALSE;
2850 
2851     return true; /* always return true, maybe there are cases which return false in the future */
2852 }
2853 
FIPScompatibleKMA(const char * const i_sKMAVersion)2854 bool FIPScompatibleKMA(
2855         const char * const i_sKMAVersion) {
2856     return (strcmp(i_sKMAVersion,
2857             FIPS_COMPATIBLE_KMA_VERSION) >= 0);
2858 }
2859 
2860 #ifdef KMSUSERPKCS12
2861 extern "C"
2862 KMS_AGENT_STATUS
KMSAgent_GetProfileStatus(char * i_pProfileName,KMSAGENT_PROFILE_FLAGS * flags)2863 KMSAgent_GetProfileStatus(
2864 	char* i_pProfileName,
2865 	KMSAGENT_PROFILE_FLAGS *flags)
2866 {
2867 	/*
2868 	 * Determine how "initialized" the KMS token is by checking for
2869 	 * the profile config file and also the entity key container (pkcs#12).
2870 	 */
2871 	if (ProfileExists(g_wsWorkingDirectory, i_pProfileName)) {
2872 		*flags |= KMSAGENT_PROFILE_EXISTS_FLAG;
2873 		if (ClientKeyP12Exists(i_pProfileName))
2874 			*flags |= KMSAGENT_CLIENTKEY_EXISTS_FLAG;
2875 	}
2876 	return (KMS_AGENT_STATUS_OK);
2877 }
2878 #endif
2879