2025-04-27 07:49:33 -04:00

877 lines
18 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: odbc.cpp
//
// Contents: Cert Server Data Base interface implementation for odbc
//
// History: 06-jan-97 larrys created
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "certdb2.h"
#include "csprop2.h"
//#include "db2.h"
//#include "dbcore.h"
#include "odbc.h"
#define __myFILE__ "odbc.cpp"
HENV henv = SQL_NULL_HENV;
HDBC hdbc = SQL_NULL_HDBC;
typedef struct _DBENUMHANDLETABLE
{
LIST_ENTRY Next;
HSTMT hEnum;
BYTE Name[MAX_PATH];
SQLLEN cbName;
HANDLE hToData;
} DBENUMHANDLETABLE, *PDBENUMHANDLETABLE;
LIST_ENTRY g_DBEnumHandleList;
PDBENUMHANDLETABLE GetDBEnumHandle(HANDLE dwHandle);
CRITICAL_SECTION g_DBEnumCriticalSection;
BOOL g_fDBEnumCSInit = FALSE;
/////
STATUS
DBStatus(
RETCODE rc)
{
STATUS s;
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
s = ERROR_SUCCESS;
break;
case SQL_NO_DATA_FOUND:
s = CERTSRV_E_PROPERTY_EMPTY;
break;
case SQL_INVALID_HANDLE:
s = ERROR_INVALID_HANDLE;
break;
case SQL_ERROR:
default:
s = GetLastError();
if (ERROR_SUCCESS == s)
{
s = (DWORD) -1;
}
break;
}
return(s);
}
/////
void
DBCheck(
RETCODE rc
DBGPARM(char const *pszFile)
DBGPARM(DWORD Line),
HSTMT hstmt)
{
if ( rc != SQL_SUCCESS )
{
UCHAR state[SQL_MAX_MESSAGE_LENGTH-1];
UCHAR msg [SQL_MAX_MESSAGE_LENGTH-1];
SDWORD native;
SQLError ( henv, hdbc, hstmt, state, &native, msg, sizeof(msg), NULL );
if (SQL_SUCCESS_WITH_INFO != rc || 2 < g_fVerbose)
{
wprintf(
DBGPARM0(L"%hs(%u): ")
L"rc=%d, SQLError %hs (%d): %hs\n"
DBGPARM(pszFile)
DBGPARM(Line),
rc,
state,
native,
msg);
}
}
}
/////
STATUS odbcInitRequestQueue(
UCHAR *dsn,
UCHAR *user,
UCHAR *pwd
)
{
RETCODE rc;
rc = SQLAllocEnv ( &henv );
if ( rc == SQL_SUCCESS )
{
rc = SQLAllocConnect ( henv, &hdbc );
if ( rc == SQL_SUCCESS )
{
rc = SQLConnect ( hdbc, dsn, SQL_NTS, user, SQL_NTS, pwd, SQL_NTS );
DBCHECKLINE ( rc, SQL_NULL_HSTMT );
if ( rc == SQL_SUCCESS_WITH_INFO )
{
rc = SQL_SUCCESS;
}
if ( rc != SQL_SUCCESS )
SQLFreeConnect ( hdbc );
}
if ( rc != SQL_SUCCESS )
SQLFreeEnv ( henv );
}
if ( rc != SQL_SUCCESS )
{
wprintf(myLoadResourceString(IDS_RED_CONNECT_FAIL), rc, rc);
wprintf(wszNewLine);
}
return DBStatus ( rc );
}
/////
void odbcFinishRequestQueue(void)
{
SQLDisconnect ( hdbc );
SQLFreeConnect ( hdbc );
SQLFreeEnv ( henv );
}
/////
RETCODE dbGetNameId(
IN REQID ReqId,
IN UCHAR *pszSQL,
OUT NAMEID *pnameid,
OUT SQLLEN *poutlen)
{
RETCODE rc;
HSTMT hstmt = SQL_NULL_HSTMT;
rc = SQLAllocStmt(hdbc, &hstmt);
if (SQL_SUCCESS != rc)
{
goto error;
}
// bind request-id parameter
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
0,
0,
&ReqId,
0,
NULL);
if (SQL_SUCCESS != rc)
{
goto error;
}
// do query
rc = SQLExecDirect(
hstmt,
pszSQL,
SQL_NTS);
if (SQL_SUCCESS != rc)
{
goto error;
}
// get result value
rc = SQLBindCol(
hstmt,
1,
SQL_C_ULONG,
pnameid,
sizeof(DWORD),
poutlen);
if (SQL_SUCCESS != rc)
{
goto error;
}
rc = SQLFetch(hstmt);
if (SQL_SUCCESS != rc)
{
goto error;
}
error:
if (hstmt != SQL_NULL_HSTMT)
{
SQLFreeStmt(
hstmt,
SQL_DROP);
}
return(rc);
}
/////
RETCODE odbcSPExtensionOrAttributeDB(
IN DWORD id,
IN DBTABLE_RED *pdtOut,
IN UCHAR *pquery,
IN DWORD cbInProp,
IN BYTE const *pbInProp
)
{
RETCODE rc;
HSTMT hstmt = SQL_NULL_HSTMT;
SQLLEN datalen;
DWORD cbParam2Prop;
BYTE const *pbParam2Prop;
DWORD cbParam3Prop;
BYTE const *pbParam3Prop;
SWORD wCType;
SWORD wSqlType;
BYTE data[] = {'\0', '\0', '\0', '\0'};
static UCHAR updateextension[] = "Update CertificateExtensions SET %ws = ? WHERE ExtensionName = \'%ws\' AND RequestID = ?;";
static UCHAR updateattrib[] = "Update RequestAttributes SET AttributeValue = ? WHERE AttributeName = \'%ws\' AND RequestID = ?;";
rc = SQLAllocStmt(hdbc, &hstmt);
if (SQL_SUCCESS != rc)
{
goto error;
}
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
0,
0,
&id,
0,
NULL);
if (SQL_SUCCESS != rc)
{
goto error;
}
if (0 == lstrcmpi(wszPROPCERTIFICATEEXTENSIONFLAGS, pdtOut->pwszPropName) ||
pdtOut->dwTable == TABLE_REQUEST_ATTRIBS)
{
cbParam2Prop = cbInProp;
pbParam2Prop = pbInProp;
cbParam3Prop = 1;
pbParam3Prop = data;
}
else
{
cbParam2Prop = 1;
pbParam2Prop = data;
cbParam3Prop = cbInProp;
pbParam3Prop = pbInProp;
}
if (pdtOut->dwTable == TABLE_EXTENSIONS)
{
wCType = SQL_C_ULONG;
wSqlType = SQL_INTEGER;
}
else
{
wCType = SQL_C_CHAR;
wSqlType = SQL_VARCHAR;
}
datalen = cbParam2Prop;
rc = SQLBindParameter(
hstmt,
2,
SQL_PARAM_INPUT,
wCType,
wSqlType,
cbParam2Prop,
0,
(void*)pbParam2Prop,
cbParam2Prop,
&datalen);
if (SQL_SUCCESS != rc)
{
goto error;
}
if (pdtOut->dwTable == TABLE_EXTENSIONS)
{
datalen = cbParam3Prop;
rc = SQLBindParameter(
hstmt,
3,
SQL_PARAM_INPUT,
SQL_C_BINARY,
SQL_LONGVARBINARY,
cbParam3Prop,
0,
(void*)pbParam3Prop,
cbParam3Prop,
&datalen);
if (SQL_SUCCESS != rc)
{
goto error;
}
}
rc = SQLExecDirect(
hstmt,
pquery,
SQL_NTS);
// See if we could insert a new row.
if (SQL_SUCCESS == rc)
{
goto done;
}
datalen = cbInProp;
// Try to do an update of the row instead
if (pdtOut->dwTable == TABLE_EXTENSIONS)
{
sprintf(
(char *) pquery,
(char *) updateextension,
pdtOut->pwszPropNameObjId,
pdtOut->pwszFieldName);
if (0 == lstrcmpi(wszPROPCERTIFICATEEXTENSIONFLAGS, pdtOut->pwszPropName))
{
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
cbInProp,
0,
(void*)pbInProp,
cbInProp,
&datalen);
}
else
{
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_BINARY,
SQL_LONGVARBINARY,
cbInProp,
0,
(void*)pbInProp,
cbInProp,
&datalen);
}
if (SQL_SUCCESS != rc)
{
goto error;
}
}
else
{
sprintf(
(char *) pquery,
(char *) updateattrib,
pdtOut->pwszFieldName);
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_CHAR,
SQL_VARCHAR,
cbInProp,
0,
(void*)pbInProp,
cbInProp,
&datalen);
if (SQL_SUCCESS != rc)
{
goto error;
}
}
rc = SQLBindParameter(
hstmt,
2,
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
0,
0,
&id,
0,
NULL);
if (SQL_SUCCESS != rc)
{
goto error;
}
rc = SQLExecDirect(
hstmt,
pquery,
SQL_NTS);
done:
error:
// done
DBCHECKLINE(rc, hstmt);
if (SQL_NULL_HSTMT != hstmt)
{
SQLFreeStmt(hstmt, SQL_DROP);
}
return(rc);
}
/////
RETCODE odbcGPDataFromDB(
IN REQID ReqId,
IN DWORD dwTable,
IN SWORD wCType,
IN BYTE *pbData,
IN DWORD cbData,
IN UCHAR *szQuery,
OUT NAMEID *pnameid,
OUT SQLLEN *poutlen
)
{
RETCODE rc;
HSTMT hstmt;
SQLLEN cbnameid;
retry:
hstmt = SQL_NULL_HSTMT;
cbnameid = 0;
rc = SQLAllocStmt (hdbc, &hstmt);
if (SQL_SUCCESS != rc)
{
goto error;
}
// bind request-id parameter
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
0,
0,
&ReqId,
0,
NULL);
if (SQL_SUCCESS != rc)
{
goto error;
}
rc = SQLExecDirect(hstmt, szQuery, SQL_NTS);
if (SQL_SUCCESS != rc)
{
goto error;
}
// retrieve result
rc = SQLBindCol(
hstmt,
1,
wCType,
pbData,
cbData,
poutlen);
if (SQL_SUCCESS == rc &&
(dwTable == TABLE_SUBJECT_NAME ||
dwTable == TABLE_ISSUER_NAME))
{
rc = SQLBindCol(
hstmt,
2,
SQL_C_ULONG,
pnameid,
sizeof(pnameid),
&cbnameid);
}
if (SQL_SUCCESS != rc)
{
goto error;
}
rc = SQLFetch(hstmt);
if (SQL_ERROR == rc)
{
RETCODE rc2;
unsigned char achState[10];
unsigned char achText[2048];
SHORT cchText;
LONG NativeError;
rc2 = SQLGetDiagRec(
SQL_HANDLE_STMT,
hstmt,
1,
achState,
&NativeError,
achText,
ARRAYSIZE(achText),
&cchText);
if (rc2 == SQL_SUCCESS)
{
#if 0
wprintf(
L"SQLGetDiagRec: cch=%hu, text=%hs, ne=0x%x, state=%.10hs\n",
cchText,
achText,
NativeError,
achState);
#endif
if (SQL_C_ULONG == wCType && 0 == strcmp((char *) achState, "22003"))
{
//wprintf(L"\nNumeric value out of range fetching ULONG\n");
wCType = SQL_C_LONG;
if (SQL_NULL_HSTMT != hstmt)
{
SQLFreeStmt(hstmt, SQL_DROP);
}
goto retry;
}
}
}
if (SQL_NULL_HSTMT != hstmt)
{
SQLFreeStmt(hstmt, SQL_DROP);
}
error:
return rc;
}
/////
HRESULT
odbcDBEnumSetup(
IN REQID ReqId,
IN DWORD fExtOrAttr,
OUT HANDLE *phEnum)
{
HRESULT rc;
HSTMT hstmt = SQL_NULL_HSTMT;
DWORD cbData;
PDBENUMHANDLETABLE pDBEnumHandle = NULL;
UCHAR szExtensionQuery[] = "SELECT ExtensionName FROM CertificateExtensions WHERE RequestID = ?;";
UCHAR szAttributeQuery[] = "SELECT AttributeName FROM RequestAttributes WHERE RequestID = ?;";
rc = SQLAllocStmt(hdbc, &hstmt);
if (SQL_SUCCESS != rc)
{
goto error;
}
// bind request-id parameter
rc = SQLBindParameter(
hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_ULONG,
SQL_INTEGER,
0,
0,
&ReqId,
0,
NULL);
if (SQL_SUCCESS != rc)
{
goto error;
}
rc = SQLExecDirect(
hstmt,
fExtOrAttr ? szAttributeQuery : szExtensionQuery,
SQL_NTS);
if (SQL_SUCCESS != rc)
{
goto error;
}
// create handle to return
if ((pDBEnumHandle = (PDBENUMHANDLETABLE) LocalAlloc(LMEM_ZEROINIT,
sizeof(DBENUMHANDLETABLE))) == 0)
{
rc = ERROR_NOT_ENOUGH_MEMORY;
goto error;
}
// can't depend on CryptGenRandom() on other csps
pDBEnumHandle->hToData = (HANDLE) (ULONG_PTR) rand();
if (0 == pDBEnumHandle->hToData)
{
pDBEnumHandle->hToData = (HANDLE) (ULONG_PTR) 1; // don't be zero
}
// retrieve result
pDBEnumHandle->cbName = 0;
// Since ExtensionName & AttributeName column in DB is length 50 this
// should be fine
cbData = MAX_PATH;
rc = SQLBindCol(
hstmt,
1,
SQL_C_CHAR,
pDBEnumHandle->Name,
cbData,
&pDBEnumHandle->cbName);
if (SQL_SUCCESS != rc)
{
goto error;
}
pDBEnumHandle->hEnum = hstmt;
*phEnum = (HANDLE) pDBEnumHandle->hToData;
if(!g_fDBEnumCSInit)
{
rc = HRESULT_FROM_WIN32(ERROR_NOT_READY);
goto error;
}
EnterCriticalSection(&g_DBEnumCriticalSection);
InsertTailList(&g_DBEnumHandleList, &pDBEnumHandle->Next);
LeaveCriticalSection(&g_DBEnumCriticalSection);
return(rc);
error:
if (SQL_NULL_HSTMT != hstmt)
{
rc = SQLFreeStmt(
hstmt,
SQL_DROP);
}
if (NULL != pDBEnumHandle)
{
LocalFree(pDBEnumHandle);
}
return(rc);
}
HRESULT
odbcDBEnum(
IN HANDLE hEnum,
IN OUT DWORD *pcb,
OUT WCHAR *pb)
{
PDBENUMHANDLETABLE pDBEnumHandle;
HRESULT rc;
if (*pcb < MAX_EXTENSION_NAME)
{
rc = ERROR_INSUFFICIENT_BUFFER;
goto error;
}
pDBEnumHandle = GetDBEnumHandle(hEnum);
if (NULL == pDBEnumHandle)
{
rc = ERROR_INVALID_HANDLE;
goto error;
}
rc = SQLFetch(pDBEnumHandle->hEnum);
if (SQL_SUCCESS != rc)
{
if (SQL_NO_DATA_FOUND == rc)
{
*pcb = 0;
rc = CERTSRV_E_PROPERTY_EMPTY;
}
goto error;
}
rc = MultiByteToWideChar(
GetACP(),
0,
(CHAR*)pDBEnumHandle->Name,
(int)pDBEnumHandle->cbName,
pb,
*pcb);
if (!rc)
{
rc = GetLastError();
goto error;
}
else
{
rc = ERROR_SUCCESS;
}
*pcb = (DWORD)pDBEnumHandle->cbName;
error:
return(rc);
}
HRESULT
odbcDBEnumClose(
IN HANDLE hEnum)
{
PDBENUMHANDLETABLE pDBEnumHandle;
HRESULT rc;
if(!g_fDBEnumCSInit)
{
rc = HRESULT_FROM_WIN32(ERROR_NOT_READY);
return rc;
}
pDBEnumHandle = GetDBEnumHandle(hEnum);
if (NULL == pDBEnumHandle)
{
rc = ERROR_INVALID_HANDLE;
return(rc);
}
rc = SQLFreeStmt(
pDBEnumHandle->hEnum,
SQL_DROP);
EnterCriticalSection(&g_DBEnumCriticalSection);
RemoveEntryList(&pDBEnumHandle->Next);
LocalFree(pDBEnumHandle);
LeaveCriticalSection(&g_DBEnumCriticalSection);
return(rc);
}
PDBENUMHANDLETABLE
GetDBEnumHandle(HANDLE dwHandle)
{
PLIST_ENTRY ListHead;
PLIST_ENTRY ListNext;
PDBENUMHANDLETABLE pDBEnumHandle;
ListHead = &g_DBEnumHandleList;
ListNext = ListHead->Flink;
if(!g_fDBEnumCSInit)
{
return NULL;
}
EnterCriticalSection(&g_DBEnumCriticalSection);
while (ListNext != ListHead)
{
pDBEnumHandle = CONTAINING_RECORD(ListNext, DBENUMHANDLETABLE, Next);
if (pDBEnumHandle->hToData == dwHandle)
{
LeaveCriticalSection(&g_DBEnumCriticalSection);
return(pDBEnumHandle);
}
ListNext = ListNext->Flink;
}
LeaveCriticalSection(&g_DBEnumCriticalSection);
return(NULL);
}