/*
 * Parse NTDS file database and extract bitlocker related attributes
 * (Key package, recovery password, recovery guid, volume id)
 */
int NTDS_Bitlocker_ParseDatabase(s_parser *parser,ll_bitlockerAccountInfo *bitlockerAccountInfo) {
	s_bitlockerAccountInfo bitlockerAccountEntry;
	JET_TABLEID tableid;
	JET_ERR jet_err;
	int success = NTDS_SUCCESS;
	int retCode;

	jet_err = JetOpenTable(parser->sesid,parser->dbid,NTDS_TBL_OBJ,NULL,0,JET_bitTableReadOnly | JET_bitTableSequential,&tableid);
	if(jet_err!=JET_errSuccess) {
		NTDS_ErrorPrint(parser,"JetOpenTable",jet_err);
		return NTDS_API_ERROR;
	}

	/* Get attributes identifiers */
	jet_err = JetGetTableColumnInfo(parser->sesid,tableid,ATT_BITLOCKER_MSFVE_KEY_PACKAGE,&parser->columndef[ID_MSFVE_KEY_PACKAGE],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_BITLOCKER_MSFVE_RECOVERY_GUID,&parser->columndef[ID_MSFVE_RECOVERY_GUID],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_BITLOCKER_MSFVE_RECOVERY_PASSWORD,&parser->columndef[ID_MSFVE_RECOVERY_PASSWORD],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_BITLOCKER_MSFVE_VOLUME_GUID,&parser->columndef[ID_MSFVE_VOLUME_GUID],sizeof(JET_COLUMNDEF),JET_ColInfo);

	if(jet_err!=JET_errSuccess) {
		NTDS_ErrorPrint(parser,"JetGetTableColumnInfo ",jet_err);
		JetCloseTable(parser->sesid,tableid);
		return NTDS_API_ERROR;
	}

	/* Parse datatable for Bitlocker accounts */
	jet_err = JetMove(parser->sesid,tableid,JET_MoveFirst,0);
	do{
		retCode = NTDS_Bitlocker_ParseRecord(parser,tableid,&bitlockerAccountEntry);
		if(retCode==NTDS_SUCCESS) {
			if(!bitlockerAccountInfoNew(bitlockerAccountInfo,&bitlockerAccountEntry)) {
				puts("Fatal error: not enough memory!");
				return NTDS_MEM_ERROR;
			}
		}
		else if(retCode==NTDS_MEM_ERROR) {
			puts("Fatal error: not enough memory!");
			return retCode;
		}
	}while(JetMove(parser->sesid,tableid,JET_MoveNext,0) == JET_errSuccess);

	if(!*bitlockerAccountInfo)
		success = NTDS_EMPTY_ERROR;

	jet_err = JetCloseTable(parser->sesid,tableid);
	if(jet_err!=JET_errSuccess) {
		NTDS_ErrorPrint(parser,"JetCloseTable",jet_err);
		return NTDS_API_ERROR;
	}

	return success;
}
Exemple #2
0
HRESULT Table::GetColName(const uint32_t colIndex, wchar_t * colNameBuf, uint32_t & colNameBufSizeInChars)
{
    try
    {
        if (colNames_.empty())
        {
            JET_COLUMNLIST colList = { sizeof(JET_COLUMNLIST) };
            const JET_ERR jetErr = JetGetTableColumnInfo(sesId_, tableId_, nullptr, &colList, sizeof(colList), JET_ColInfoList);
            if (jetErr != JET_errSuccess)
            {
                throw Error("JetGetTableColumnInfo", jetErr, __FUNCTION__);
            } 
            Table tableWithColNames(sesId_, dbId_, colList.tableid);

            for (size_t i = 0; i < colList.cRecord; ++i)
            {
                wchar_t buff[128] = L"";
                ULONG numActualBytes = 0;
                JET_ERR jetErr2 = JetRetrieveColumn(sesId_, colList.tableid, colList.columnidcolumnname, buff, sizeof(buff), &numActualBytes,
                                                    0, nullptr);
                if (jetErr2 != JET_errSuccess)
                {
                    throw Error("JetRetrieveColumn", jetErr2, __FUNCTION__);
                }
                colNames_.emplace_back(buff);
                if (colNames_.size() < colList.cRecord)
                {
                    tableWithColNames.MoveCursor(+1);
                }
            }            
        }
        if (colIndex >= colNames_.size())
        {
            throw HrError("invalid colIndex", E_INVALIDARG, __FUNCTION__);
        }
        if (colNameBufSizeInChars < colNames_[colIndex].size() + 1)
        {
            colNameBufSizeInChars = boost::numeric_cast<uint32_t>(colNames_[colIndex].size() + 1);
            throw HrError("colName buffer is too small.", E_INVALIDARG, __FUNCTION__);
        }
        wcscpy_s(colNameBuf, colNameBufSizeInChars, colNames_[colIndex].c_str());
        return S_OK;
    }
    catch (const std::exception & e)
    {
        SetLastErrorDesc(e);
    }
    return E_FAIL;
}
Exemple #3
0
VOID ListTable(  IN PCHAR TableName, IN PCHAR ColumnName, IN PCHAR IndexName)
{
    JET_TABLEID     TableId;
    JET_COLUMNDEF   ColumnDef;

    Call( JetOpenTable( SesId, DbId, TableName, NULL, 0,
            JET_bitTableDenyWrite, &TableId));

    Call( JetGetTableColumnInfo( SesId, TableId, ColumnName, &ColumnDef,
            sizeof( ColumnDef), JET_ColInfo));

    RplDbgPrint(( "\tTable: %s\n", TableName));

    Enum( TableId, ColumnDef.columnid, IndexName);

    Call( JetCloseTable( SesId, TableId));
}
Exemple #4
0
IColumn * Table::GetColumn(const wchar_t * colName)
{
    try
    {
        JET_COLUMNDEF colDef = { sizeof(JET_COLUMNDEF) };
        const JET_ERR jetErr = JetGetTableColumnInfo(sesId_, tableId_, colName, &colDef, sizeof(JET_COLUMNDEF), JET_ColInfo);
        if (jetErr != JET_errSuccess)
        {
            throw Error("JetGetTableColumnInfo", jetErr, __FUNCTION__);
        }
        jet::ColumnDataTraits dataTraits(colDef);
        std::unique_ptr<IColumn> column(std::make_unique<Column>(sesId_, tableId_, colDef.columnid));
        return column.release();
    }
    catch (const std::exception & e)
    {
        SetLastErrorDesc(e);
    }
    return nullptr;
}
Exemple #5
0
HRESULT Table::GetNumCols(uint32_t & numCols)
{
    try
    {
        JET_COLUMNLIST colList = { sizeof(JET_COLUMNLIST) };
        const JET_ERR jetErr = JetGetTableColumnInfo(sesId_, tableId_, nullptr, &colList, sizeof(colList), JET_ColInfoList);
        if (jetErr != JET_errSuccess)
        {
            throw Error("JetGetTableColumnInfo", jetErr, __FUNCTION__);
        }
        numCols = colList.cRecord;
        const JET_ERR jetErr2 = JetCloseTable(sesId_, colList.tableid);
        if (jetErr2 != JET_errSuccess)
        {
            throw Error("JetCloseTable", jetErr, __FUNCTION__);
        }
        return S_OK;
    }
    catch (const std::exception & e)
    {
        SetLastErrorDesc(e);
    }
    return E_FAIL;
}
/*
 * Parse NTDS.dit file and its "datatable" table
 * Lokk for PEK, SAM account name & type, hashes, SID and hashes history if asked
 */
BOOL NTDS_NTLM_ParseDatabase(s_parser *parser,ll_ldapAccountInfo *ldapAccountInfo,s_NTLM_pek_ciphered *pek_ciphered,BOOL with_history){
	s_ldapAccountInfo ldapAccountEntry;
	JET_TABLEID tableid;
	JET_ERR jet_err;
	int success = NTDS_SUCCESS;
	int retCode;

	jet_err = JetOpenTable(parser->sesid,parser->dbid,NTDS_TBL_OBJ,NULL,0,JET_bitTableReadOnly | JET_bitTableSequential,&tableid);
	if(jet_err!=JET_errSuccess) {
		NTDS_ErrorPrint(parser,"JetOpenTable",jet_err);
		return NTDS_API_ERROR;
	}

	/* Get attributes identifiers */
	jet_err = JetGetTableColumnInfo(parser->sesid,tableid,ATT_SAM_ACCOUNT_NAME,&parser->columndef[ID_SAM_ACCOUNT_NAME],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_OBJECT_SID,&parser->columndef[ID_OBJECT_SID],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_LM_HASH,&parser->columndef[ID_LM_HASH],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_NT_HASH,&parser->columndef[ID_NT_HASH],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_PEK,&parser->columndef[ID_PEK],sizeof(JET_COLUMNDEF),JET_ColInfo);
	jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_SAM_ACCOUNT_TYPE,&parser->columndef[ID_SAM_ACCOUNT_TYPE],sizeof(JET_COLUMNDEF),JET_ColInfo);

	if(with_history) {
		jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_LM_HASH_HISTORY,&parser->columndef[ID_LM_HASH_HISTORY],sizeof(JET_COLUMNDEF),JET_ColInfo);
		jet_err |= JetGetTableColumnInfo(parser->sesid,tableid,ATT_NT_HASH_HISTORY,&parser->columndef[ID_NT_HASH_HISTORY],sizeof(JET_COLUMNDEF),JET_ColInfo);
	}

	if(jet_err!=JET_errSuccess) {
		NTDS_ErrorPrint(parser,"JetGetTableColumnInfo ",jet_err);
		JetCloseTable(parser->sesid,tableid);
		return NTDS_API_ERROR;
	}

	/* Parse datatable for SAM accounts */
	jet_err = JetMove(parser->sesid,tableid,JET_MoveFirst,0);
	do{
		retCode = NTDS_NTLM_ParseSAMRecord(parser,tableid,&ldapAccountEntry,with_history);
		if(retCode==NTDS_SUCCESS) {
			if(!ldapAccountInfoNew(ldapAccountInfo,&ldapAccountEntry)) {
				puts("Fatal error: not enough memory!");
				return NTDS_MEM_ERROR;
			}
		}
		else if(retCode==NTDS_MEM_ERROR) {
			puts("Fatal error: not enough memory!");
			return retCode;
		}

	}while(JetMove(parser->sesid,tableid,JET_MoveNext,0) == JET_errSuccess);
	
	if(!*ldapAccountInfo)
		success = NTDS_EMPTY_ERROR;

	/* Parse datatable for ciphered PEK */
	jet_err = JetMove(parser->sesid,tableid,JET_MoveFirst,0);
	do{
		if(NTDS_NTLM_ParsePEKRecord(parser,tableid,pek_ciphered)==NTDS_SUCCESS) {
			success = NTDS_SUCCESS;
			break;
		}
	}while(JetMove(parser->sesid,tableid,JET_MoveNext,0) == JET_errSuccess);

	jet_err = JetCloseTable(parser->sesid,tableid);
	if(jet_err!=JET_errSuccess) {
		NTDS_ErrorPrint(parser,"JetCloseTable",jet_err);
		return NTDS_API_ERROR;
	}

	return success;
}