#ifdef USE_SSPI
int ssl_try_count, ssl_try_no;
char ssl_call[2];
+ int bReconnect = 0;
#endif /* USE_SSPI */
mylog("%s: entering...\n", func);
switch (rnego)
{
case 'S':
- if (!StartupSspiService(sock, SchannelService, NULL))
+ if (!StartupSspiService(sock, SchannelService, ci, &bReconnect))
{
+ if (bReconnect != 0)
+ {
+ anotherVersionRetry = TRUE;
+ goto another_version_retry;
+ }
CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
goto error_proc;
}
if (!ci->gssauth_use_gssapi)
{
self->auth_svcs = KerberosService;
- authRet = StartupSspiService(sock, self->auth_svcs, MakePrincHint(ci, TRUE));
+ authRet = StartupSspiService(sock, self->auth_svcs, MakePrincHint(ci, TRUE), &bReconnect);
if (!authRet)
{
CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
mylog("in AUTH_REQ_SSPI\n");
#if defined(USE_SSPI)
self->auth_svcs = ci->gssauth_use_gssapi ? KerberosService : NegotiateService;
- if (!StartupSspiService(sock, self->auth_svcs, MakePrincHint(ci, TRUE)))
+ if (!StartupSspiService(sock, self->auth_svcs, MakePrincHint(ci, TRUE), &bReconnect))
{
CC_set_error(self, CONN_INVALID_AUTHENTICATION, "Service negotation failed", func);
goto error_proc;
KerberosEtcSpec kdata;
} SspiData;
-static int DoSchannelNegotiation(SocketClass *, SspiData *, const void *opt);
-static int DoKerberosNegotiation(SocketClass *, SspiData *, const void *opt);
-static int DoNegotiateNegotiation(SocketClass *, SspiData *, const void *opt);
+static int DoSchannelNegotiation(SocketClass *, SspiData *, const void *opt, int *bReconnect);
+static int DoKerberosNegotiation(SocketClass *, SspiData *, const void *opt, int *bReconnect);
+static int DoNegotiateNegotiation(SocketClass *, SspiData *, const void *opt, int *bReconnect);
static int DoKerberosEtcProcessAuthentication(SocketClass *, const void *opt);
static SspiData *SspiDataAlloc(SocketClass *self)
return sspidata;
}
-int StartupSspiService(SocketClass *self, SSPI_Service svc, const void *opt)
+int StartupSspiService(SocketClass *self, SSPI_Service svc, const void *opt, int *bReconnect)
{
CSTR func = "DoServicelNegotiation";
SspiData *sspidata;
+ if (bReconnect != NULL)
+ *bReconnect = 0;
if (NULL == (sspidata = SspiDataAlloc(self)))
return -1;
switch (svc)
{
case SchannelService:
- return DoSchannelNegotiation(self, sspidata, opt);
+ return DoSchannelNegotiation(self, sspidata, opt, bReconnect);
case KerberosService:
- return DoKerberosNegotiation(self, sspidata, opt);
+ return DoKerberosNegotiation(self, sspidata, opt, bReconnect);
case NegotiateService:
- return DoNegotiateNegotiation(self, sspidata, opt);
+ return DoNegotiateNegotiation(self, sspidata, opt, bReconnect);
}
free(sspidata);
static SECURITY_STATUS SchannelClientHandshakeLoop(SOCKET, PCredHandle, CtxtHandle *, BOOL, SecBuffer *);
static void GetNewSchannelClientCredentials(PCredHandle, CtxtHandle *);
+static BOOL bRootCALoaded = FALSE;
static BOOL bMyCert = FALSE;
static HCERTSTORE hMyCertStore = NULL;
static HCRYPTPROV hProv = (HCRYPTPROV) 0;
{
FreeCertStores();
bMyCert = FALSE;
+ bRootCALoaded = FALSE;
}
/*
mylog("CryptImportKey failed with error 0x%.8X\n", GetLastError());
goto cleanup;
}
+ CryptDestroyKey(hKey);
+ hKey = (HCRYPTKEY) 0;
free(pbKeyBlob);
pbKeyBlob = NULL;
free(pbKeyBlob);
if (fd != INVALID_HANDLE_VALUE)
CloseHandle(fd);
- if (hKey)
- CryptDestroyKey(hKey);
if (!success)
{
HCERTSTORE hSv = hMyCertStore;
return;
}
-static int DoSchannelNegotiation(SocketClass *self, SspiData *sspidata, const void *opt)
+static int InstallRootCA()
+{
+ HCERTSTORE hTempCertStore = NULL, hRootCertStore = NULL;
+ LPCTSTR pgsslroot = NULL;
+ LPCTSTR appdata = NULL;
+ TCHAR sslroot[256];
+ PCCERT_CONTEXT pContext = NULL;
+ int installed_count = 0, reject_count = 0;
+
+ shortterm_common_lock();
+ if (bRootCALoaded)
+ {
+ shortterm_common_unlock();
+ goto cleanup;
+ }
+ shortterm_common_unlock();
+
+ pgsslroot = getenv("PGSSLROOTCERT");
+ if (!pgsslroot)
+ {
+ appdata = getenv("APPDATA");
+ if (!appdata) goto cleanup;
+ snprintf(sslroot, sizeof(sslroot), "%s\\postgresql\\root.crt", appdata);
+ pgsslroot = sslroot;
+ }
+
+ hTempCertStore = CertOpenStore(
+ CERT_STORE_PROV_FILENAME_A
+ , 0
+ , (HCRYPTPROV) NULL
+ , CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG
+ , pgsslroot
+ );
+ if (hTempCertStore == NULL)
+ goto cleanup;
+ hRootCertStore = CertOpenSystemStore(0, TEXT("ROOT"));
+ mylog("hRootCertStore=%p sslroot=%s\n", hRootCertStore, pgsslroot);
+ if (hRootCertStore == NULL)
+ goto cleanup;
+
+ pContext = CertEnumCertificatesInStore(hTempCertStore, pContext);
+ while (pContext != NULL)
+ {
+ if (CertAddCertificateContextToStore(hRootCertStore, pContext, CERT_STORE_ADD_NEWER, NULL))
+ installed_count++;
+ else
+ {
+ int lasterror = GetLastError();
+ switch (lasterror)
+ {
+ case CRYPT_E_EXISTS:
+ mylog("Certificate already exists\n");
+ break;
+ case 1223: // ERROR_CANCELED
+ reject_count++;
+ mylog("Certificate canceled\n");
+ break;
+ default:
+ reject_count++;
+ mylog("Failed to install root certificate error=%08x\n", lasterror);
+ }
+ }
+ pContext = CertEnumCertificatesInStore(hRootCertStore, pContext);
+ }
+ shortterm_common_lock();
+ if (!bRootCALoaded)
+ {
+ if (installed_count > 0 ||
+ reject_count == 0)
+ bRootCALoaded = TRUE;
+ }
+ shortterm_common_unlock();
+
+cleanup:
+ if (hTempCertStore)
+ CertCloseStore(hTempCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
+ if (hRootCertStore)
+ CertCloseStore(hRootCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
+
+ return installed_count;
+}
+
+static int DoSchannelNegotiation(SocketClass *self, SspiData *sspidata, const void *opt, int *bReconnect)
{
CSTR func = "DoSchannelNegotiation";
SECURITY_STATUS r = SEC_E_OK;
SecBuffer ExtraData;
BOOL ret = 0, cCreds = FALSE, cCtxt = FALSE;
SchannelSpec *ssd = &(sspidata->sdata);
+ char *server = NULL;
- if (SEC_E_OK != (r = CreateSchannelCredentials(NULL, NULL, &ssd->hCred)))
+ if (SEC_E_OK != (r = CreateSchannelCredentials(opt, NULL, &ssd->hCred)))
{
cmd = "CreateSchannelCredentials";
mylog("%s:%s failed\n", func, cmd);
goto cleanup;
}
cCreds = TRUE;
- if (SEC_E_OK != (r = PerformSchannelClientHandshake(self->socket, &ssd->hCred, NULL, &ssd->hCtxt, &ExtraData)))
+ if (opt != NULL)
+ server = ((ConnInfo *) opt)->server;
+ if (SEC_E_OK != (r = PerformSchannelClientHandshake(self->socket, &ssd->hCred, server, &ssd->hCtxt, &ExtraData)))
{
cmd = "PerformSchannelClientHandshake";
+ switch (r)
+ {
+ case SEC_E_UNTRUSTED_ROOT:
+ mylog("Installing RootCA\n");
+ if (InstallRootCA() > 0)
+ *bReconnect = 1;
+ break;
+ default:
+ break;
+ }
mylog("%s:%s failed\n", func, cmd);
goto cleanup;
}
ALG_ID rgbSupportedAlgs[16];
DWORD dwProtocol = SP_PROT_SSL3 | SP_PROT_SSL2;
DWORD aiKeyExch = 0;
+ char *sslmode = NULL;
PCCERT_CONTEXT pCertContext = NULL;
* leave off this flag, in which case the InitializeSecurityContext
* function will validate the server certificate automatically.
*/
- SchannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
+ if (opt != NULL)
+ sslmode = ((ConnInfo *) opt)->sslmode;
+ if (sslmode == NULL || sslmode[0] != 'v')
+ SchannelCred.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
+ else
+ {
+ if (strcmp(sslmode, "verify-full"))
+ SchannelCred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+ // InstallRootCA();
+ }
/*
* Create an SSPI credential.
static SECURITY_STATUS CreateKerberosEtcCredentials(LPCTSTR, SEC_CHAR *, LPCTSTR, PCredHandle);
static SECURITY_STATUS PerformKerberosEtcClientHandshake(SocketClass *, KerberosEtcSpec *ssd, size_t);
-static int DoKerberosNegotiation(SocketClass *self, SspiData *sspidata, const void *opt)
+static int DoKerberosNegotiation(SocketClass *self, SspiData *sspidata, const void *opt, int *bReconnect)
{
CSTR func = "DoKerberosNegotiation";
SECURITY_STATUS r = SEC_E_OK;
return DoKerberosEtcProcessAuthentication(self, NULL);
}
-static int DoNegotiateNegotiation(SocketClass *self, SspiData *sspidata, const void *opt)
+static int DoNegotiateNegotiation(SocketClass *self, SspiData *sspidata, const void *opt, int *bReconnect)
{
CSTR func = "DoNegotiateNegotiation";
SECURITY_STATUS r = SEC_E_OK;