windows-nt/Source/XPSP1/NT/net/diagnostics/netdiag/ndutils.c
2020-09-26 16:20:57 +08:00

842 lines
20 KiB
C

//++
//
// Copyright (C) Microsoft Corporation, 1987 - 1999
//
// Module Name:
//
// ndutils.c
//
// Abstract:
//
// Queries into network drivers
//
// Author:
//
// Anilth - 4-20-1998
//
// Environment:
//
// User mode only.
// Contains NT-specific code.
//
// Revision History:
//
//--
#include "precomp.h"
#include "global.h"
#include <ntstatus.dbg>
#include <winerror.dbg>
#include "ipcfg.h"
#define MAX_NET_STATUS_LENGTH 80
#define MAX_WINERR_SIZE 80
const TCHAR c_szSectionName[] = _T("NetDiagContact");
const TCHAR c_szFileName[] = _T("NdContact.ini");
HRESULT HResultFromWin32(DWORD dwErr)
{
return HRESULT_FROM_WIN32(dwErr);
}
LPTSTR Win32ErrorToString(DWORD Id)
{
int i = 0;
static TCHAR s_szWinerr[MAX_WINERR_SIZE + 1];
while (winerrorSymbolicNames[ i ].SymbolicName)
{
if (winerrorSymbolicNames[ i ].MessageId == Id)
{
_tcsncpy( s_szWinerr, A2T(winerrorSymbolicNames[ i ].SymbolicName),
MAX_WINERR_SIZE);
return s_szWinerr;
}
else
{
i ++;
}
}
//if we reach here, then we cannot find the Win32 Error string
_stprintf(s_szWinerr, _T("%X"), (DWORD)Id);
return s_szWinerr;
}
LPSTR
FindSymbolicNameForStatus(
DWORD Id
)
{
ULONG i;
i = 0;
if (Id == 0) {
return "STATUS_SUCCESS";
}
if (Id & 0xC0000000) {
while (ntstatusSymbolicNames[ i ].SymbolicName) {
if (ntstatusSymbolicNames[ i ].MessageId == (NTSTATUS)Id) {
return ntstatusSymbolicNames[ i ].SymbolicName;
} else {
i += 1;
}
}
}
i = 0;
while (winerrorSymbolicNames[ i ].SymbolicName) {
if (winerrorSymbolicNames[ i ].MessageId == Id) {
return winerrorSymbolicNames[ i ].SymbolicName;
} else {
i += 1;
}
}
#ifdef notdef
while (neteventSymbolicNames[ i ].SymbolicName) {
if (neteventSymbolicNames[ i ].MessageId == Id) {
return neteventSymbolicNames[ i ].SymbolicName
} else {
i += 1;
}
}
#endif // notdef
return NULL;
}
VOID
PrintSid(
IN NETDIAG_PARAMS *pParams,
IN PSID Sid OPTIONAL
)
/*++
Routine Description:
Prints a SID
Arguments:
Sid - SID to output
Return Value:
none
--*/
{
if ( Sid == NULL )
{
//IDS_UTIL_SID_NULL "(null)\n"
PrintMessage(pParams, IDS_UTIL_SID_NULL);
}
else
{
UNICODE_STRING SidString;
NTSTATUS Status;
Status = RtlConvertSidToUnicodeString( &SidString, Sid, TRUE );
if ( !NT_SUCCESS(Status) )
{
//IDS_UTIL_SID_INVALID "Invalid 0x%lX\n"
PrintMessage(pParams, IDS_UTIL_SID_INVALID, Status);
}
else
{
//IDS_GLOBAL_UNICODE_STRING "%wZ"
PrintMessage(pParams, IDS_GLOBAL_UNICODE_STRING, &SidString);
PrintNewLine(pParams, 1);
RtlFreeUnicodeString( &SidString );
}
}
}
NET_API_STATUS
IsServiceStarted(
IN LPTSTR pszServiceName
)
/*++
Routine Description:
This routine queries the Service Controller to find out if the
specified service has been started.
Arguments:
pszServiceName - Supplies the name of the service.
Return Value:
NO_ERROR: if the specified service has been started
-1: the service was stopped normally
Otherwise returns the reason the service isn't running.
--*/
{
NET_API_STATUS NetStatus;
SC_HANDLE hScManager;
SC_HANDLE hService;
SERVICE_STATUS ServiceStatus;
if ((hScManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_CONNECT
)) == (SC_HANDLE) NULL) {
NetStatus = GetLastError();
DebugMessage2(" IsServiceStarted(): OpenSCManager failed. [%s]\n", NetStatusToString(NetStatus));
return NetStatus;
}
if ((hService = OpenService(
hScManager,
pszServiceName,
SERVICE_QUERY_STATUS
)) == (SC_HANDLE) NULL)
{
NetStatus = GetLastError();
DebugMessage3(" IsServiceStarted(): OpenService '%s' failed. [%s]\n",
pszServiceName, NetStatusToString(NetStatus) );
(void) CloseServiceHandle(hScManager);
return NetStatus;
}
if (! QueryServiceStatus(
hService,
&ServiceStatus
)) {
NetStatus = GetLastError();
DebugMessage3(" IsServiceStarted(): QueryServiceStatus '%s' failed. [%s]\n",
pszServiceName, NetStatusToString(NetStatus) );
(void) CloseServiceHandle(hScManager);
(void) CloseServiceHandle(hService);
return NetStatus;
}
(void) CloseServiceHandle(hScManager);
(void) CloseServiceHandle(hService);
switch ( ServiceStatus.dwCurrentState )
{
case SERVICE_RUNNING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_PAUSED:
NetStatus = NO_ERROR;
break;
case SERVICE_STOPPED:
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR )
{
NetStatus = ServiceStatus.dwServiceSpecificExitCode;
if ( NetStatus == NO_ERROR )
{
NetStatus = ServiceStatus.dwWin32ExitCode;
}
}
else
{
NetStatus = ServiceStatus.dwWin32ExitCode;
if ( NetStatus == NO_ERROR )
{
NetStatus = -1;
}
}
break;
default:
NetStatus = ERROR_INTERNAL_ERROR;
break;
}
return NetStatus;
} // IsServiceStarted
LPSTR MapTime(DWORD_PTR TimeVal)
//++
//
// Description:
// Converts IP lease time to more human-sensible string
//
// ENTRY TimeVal - DWORD (time_t) time value (number of milliseconds since
// virtual year dot)
//
//
// RETURNS pointer to string
//
// ASSUMES 1. The caller realizes this function returns a pointer to a static
// buffer, hence calling this function a second time, but before
// the results from the previous call have been used, will destroy
// the previous results
//--
{
struct tm* pTime;
static char timeBuf[128];
static char oemTimeBuf[256];
if (pTime = localtime(&TimeVal)) {
SYSTEMTIME systemTime;
char* pTimeBuf = timeBuf;
int n;
systemTime.wYear = pTime->tm_year + 1900;
systemTime.wMonth = pTime->tm_mon + 1;
systemTime.wDayOfWeek = (WORD)pTime->tm_wday;
systemTime.wDay = (WORD)pTime->tm_mday;
systemTime.wHour = (WORD)pTime->tm_hour;
systemTime.wMinute = (WORD)pTime->tm_min;
systemTime.wSecond = (WORD)pTime->tm_sec;
systemTime.wMilliseconds = 0;
n = GetDateFormat(0, DATE_LONGDATE, &systemTime, NULL, timeBuf, sizeof(timeBuf));
timeBuf[n - 1] = ' ';
GetTimeFormat(0, 0, &systemTime, NULL, &timeBuf[n], sizeof(timeBuf) - n);
//
// we have to convert the returned ANSI string to the OEM charset
//
//
if (CharToOem(timeBuf, oemTimeBuf)) {
return oemTimeBuf;
}
return timeBuf;
}
return "";
}
//used in DCListTest and TrustTest
NTSTATUS
NettestSamConnect(
IN NETDIAG_PARAMS *pParams,
IN LPWSTR DcName,
OUT PSAM_HANDLE SamServerHandle
)
/*++
Routine Description:
Determine if the DomainSid field of the TestDomain matches the DomainSid
of the domain.
Arguments:
DcName - Dc to connect to
SamServerHandle - Returns a Sam server handle
Return Value:
TRUE: Test suceeded.
FALSE: Test failed
--*/
{
NET_API_STATUS NetStatus;
NTSTATUS Status;
UNICODE_STRING ServerNameString;
SAM_HANDLE LocalSamHandle = NULL;
BOOL fImpersonatingAnonymous = FALSE;
HANDLE hCurrentToken;
//
// Connect to the SAM server
//
RtlInitUnicodeString( &ServerNameString, DcName );
Status = SamConnect(
&ServerNameString,
&LocalSamHandle,
SAM_SERVER_LOOKUP_DOMAIN,
NULL);
//
// Consider the case where we don't have access to the DC.
// We might be logged on locally due to the domain sid being wrong.
//
if ( Status == STATUS_ACCESS_DENIED ) {
//
// Try impersonating the anonymous token.
//
//
// Check to see if we're already impsonating
//
Status = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_IMPERSONATE,
TRUE, // as self to ensure we never fail
&hCurrentToken );
if ( Status == STATUS_NO_TOKEN ) {
//
// We're not already impersonating
hCurrentToken = NULL;
} else if ( !NT_SUCCESS( Status) ) {
PrintGuruMessage(" [WARNING] Cannot NtOpenThreadToken" );
PrintGuru( NetpNtStatusToApiStatus( Status ), SAM_GURU );
goto Cleanup;
}
//
// Impersonate the anonymous token
//
Status = NtImpersonateAnonymousToken( NtCurrentThread() );
if ( !NT_SUCCESS( Status)) {
PrintGuruMessage(" [WARNING] Cannot NtOpenThreadToken" );
PrintGuru( NetpNtStatusToApiStatus( Status ), SAM_GURU );
goto Cleanup;
}
fImpersonatingAnonymous = TRUE;
//
// Try the SamConnect again
//
Status = SamConnect(
&ServerNameString,
&LocalSamHandle,
SAM_SERVER_LOOKUP_DOMAIN,
NULL);
if ( Status == STATUS_ACCESS_DENIED ) {
// One can configure SAM this way so it isn't fatal
DebugMessage2(" [WARNING] Cannot connect to SAM on '%ws' using a NULL session.", DcName );
goto Cleanup;
}
}
if ( !NT_SUCCESS(Status)) {
LocalSamHandle = NULL;
DebugMessage2(" [FATAL] Cannot connect to SAM on '%ws'.", DcName );
goto Cleanup;
}
//
// Success
//
*SamServerHandle = LocalSamHandle;
Status = STATUS_SUCCESS;
//
// Cleanup locally used resources
//
Cleanup:
if ( fImpersonatingAnonymous ) {
NTSTATUS TempStatus;
TempStatus = NtSetInformationThread(
NtCurrentThread(),
ThreadImpersonationToken,
&hCurrentToken,
sizeof(HANDLE) );
if (!NT_SUCCESS( TempStatus)) {
DebugMessage2( "SamConnect: Unexpected error reverting to self: 0x%lx\n",
TempStatus );
}
}
return Status;
}
//only used in Kerberos test so far
VOID
sPrintTime(
LPSTR str,
LARGE_INTEGER ConvertTime
)
/*++
Routine Description:
Print the specified time
Arguments:
Comment - Comment to print in front of the time
Time - GMT time to print (Nothing is printed if this is zero)
Return Value:
None
--*/
{
//
// If we've been asked to convert an NT GMT time to ascii,
// Do so
//
if ( ConvertTime.QuadPart != 0 ) {
LARGE_INTEGER LocalTime;
TIME_FIELDS TimeFields;
NTSTATUS Status;
Status = RtlSystemTimeToLocalTime( &ConvertTime, &LocalTime );
if ( !NT_SUCCESS( Status )) {
sprintf(str, "Can't convert time from GMT to Local time" );
LocalTime = ConvertTime;
}
RtlTimeToTimeFields( &LocalTime, &TimeFields );
sprintf(str, "%ld/%ld/%ld %ld:%2.2ld:%2.2ld",
TimeFields.Month,
TimeFields.Day,
TimeFields.Year,
TimeFields.Hour,
TimeFields.Minute,
TimeFields.Second );
}
}
/*!--------------------------------------------------------------------------
GetComputerNameInfo
-
Author: KennT
---------------------------------------------------------------------------*/
HRESULT GetComputerNameInfo(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
{
DWORD cchSize;
WCHAR swzNetBiosName[MAX_COMPUTERNAME_LENGTH+1];
cchSize = DimensionOf(swzNetBiosName);
if ( !GetComputerNameW( swzNetBiosName, &cchSize ) )
{
PrintMessage(pParams, IDS_GLOBAL_NoComputerName);
return HResultFromWin32(GetLastError());
}
lstrcpynW(pResults->Global.swzNetBiosName, swzNetBiosName,
MAX_COMPUTERNAME_LENGTH+1);
return hrOK;
}
/*!--------------------------------------------------------------------------
GetDNSInfo
-
Author: KennT
---------------------------------------------------------------------------*/
HRESULT GetDNSInfo(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
{
UINT cchSize;
TCHAR szDnsName[DNS_MAX_NAME_LENGTH+1];
HRESULT hr = hrOK;
//
// Get the DNS host name.
//
memset(szDnsName,0,sizeof(TCHAR)*(DNS_MAX_NAME_LENGTH+1));
cchSize = DimensionOf(szDnsName);
if (!GetComputerNameExA( ComputerNameDnsFullyQualified,
szDnsName,
&cchSize))
{
PrintMessage(pParams, IDS_GLOBAL_ERR_NoDnsName);
}
else
{
lstrcpyn(pResults->Global.szDnsHostName, szDnsName, DNS_MAX_NAME_LENGTH+1);
// Look for the first '.' in the name
pResults->Global.pszDnsDomainName = strchr(pResults->Global.szDnsHostName,
_T('.'));
if (pResults->Global.pszDnsDomainName != NULL)
{
pResults->Global.pszDnsDomainName++;
}
}
return hr;
}
/*!--------------------------------------------------------------------------
GetNetBTParameters
-
Author: KennT
---------------------------------------------------------------------------*/
HRESULT GetNetBTParameters(IN NETDIAG_PARAMS *pParams,
IN OUT NETDIAG_RESULT *pResults)
{
LONG err;
HRESULT hr = hrOK;
HKEY hkeyServices;
HKEY hkeyNetBT;
DWORD dwLMHostsEnabled;
DWORD dwDnsForWINS;
DWORD dwType;
DWORD dwLength;
if (!pParams->fVerbose)
return hrOK;
// set defaults
pResults->Global.dwLMHostsEnabled = E_FAIL;
pResults->Global.dwDnsForWINS = E_FAIL;
err = RegOpenKey(HKEY_LOCAL_MACHINE,
_T("SYSTEM\\CurrentControlSet\\Services"),
&hkeyServices
);
if (err != ERROR_SUCCESS)
{
pResults->Global.dwLMHostsEnabled = HResultFromWin32(err);
pResults->Global.dwDnsForWINS = HResultFromWin32(err);
PrintDebugSz(pParams, 0, _T("Services opening failed\n"));
}
else
{
err = RegOpenKey(hkeyServices,
_T("NetBT\\Parameters"),
&hkeyNetBT
);
if (err != ERROR_SUCCESS)
{
pResults->Global.dwLMHostsEnabled = HResultFromWin32(err);
pResults->Global.dwDnsForWINS = HResultFromWin32(err);
PrintDebugSz(pParams, 0, _T("Parameters opening failed\n"));
}
else
{
dwLength = sizeof(DWORD);
err = RegQueryValueEx(hkeyNetBT,
_T("EnableLMHOSTS"),
NULL,
&dwType,
(LPBYTE)&dwLMHostsEnabled,
&dwLength
);
if (err != ERROR_SUCCESS)
{
pResults->Global.dwLMHostsEnabled = HResultFromWin32(err);
DebugMessage("Quering EnableLMHOSTS failed !\n");
}
else
{
pResults->Global.dwLMHostsEnabled = dwLMHostsEnabled;
}
//
// In NT 5.0 - Dns for wins resolution is enabled by
// default and the "EnableDNS" key will not be found.
// If it is not found, we will assume its enabled.
// In NT 4.0 - the key will be there and its value
// should let us know whether the option is enabled
// or disabled
//
dwLength = sizeof(DWORD);
err = RegQueryValueEx(hkeyNetBT,
"EnableDNS",
NULL,
&dwType,
(LPBYTE)&dwDnsForWINS,
&dwLength
);
if (err == ERROR_SUCCESS)
{
pResults->Global.dwDnsForWINS = dwDnsForWINS;
}
else
{
pResults->Global.dwDnsForWINS = TRUE;
}
}
}
return hrOK;
}
ULONG inet_addrW(LPCWSTR pswz)
{
ULONG ulReturn;
CHAR * psaz;
psaz = StrDupAFromW(pswz);
if (psaz == NULL)
return 0;
ulReturn = inet_addrA(psaz);
Free(psaz);
return ulReturn;
}
LPTSTR
NetStatusToString(
NET_API_STATUS NetStatus
)
/*++
Routine Description:
Conver a net status code or a Windows error code to the description string.
NOTE: The string is garuanteed to be valid only right after NetStatusToString is called.
Arguments:
NetStatus - The net status code to print.
Return Value:
The status description string
--*/
{
static TCHAR s_szSymbolicName[MAX_NET_STATUS_LENGTH + 1];
ZeroMemory(s_szSymbolicName, sizeof(s_szSymbolicName));
switch (NetStatus)
{
case NERR_Success:
_tcscpy( s_szSymbolicName, _T("NERR_Success") );
break;
case NERR_DCNotFound:
_tcscpy( s_szSymbolicName, _T("NERR_DCNotFound") );
break;
case NERR_UserNotFound:
_tcscpy( s_szSymbolicName, _T("NERR_UserNotFound") );
break;
case NERR_NetNotStarted:
_tcscpy( s_szSymbolicName, _T("NERR_NetNotStarted") );
break;
case NERR_WkstaNotStarted:
_tcscpy( s_szSymbolicName, _T("NERR_WkstaNotStarted") );
break;
case NERR_ServerNotStarted:
_tcscpy( s_szSymbolicName, _T("NERR_ServerNotStarted") );
break;
case NERR_BrowserNotStarted:
_tcscpy( s_szSymbolicName, _T("NERR_BrowserNotStarted") );
break;
case NERR_ServiceNotInstalled:
_tcscpy( s_szSymbolicName, _T("NERR_ServiceNotInstalled") );
break;
case NERR_BadTransactConfig:
_tcscpy( s_szSymbolicName, _T("NERR_BadTransactConfig") );
break;
default:
{
LPSTR paszName = FindSymbolicNameForStatus( NetStatus );
USES_CONVERSION;
if (NULL == paszName)
{
_stprintf(s_szSymbolicName, _T("%X"), (DWORD)NetStatus);
}
else
{
_tcsncpy( s_szSymbolicName, A2T(paszName), MAX_NET_STATUS_LENGTH);
}
}
break;
}
return s_szSymbolicName;
}
//Load contact info from the [NetDiagContact] section of the ini file.
// pszTestName [in] short name of the test, which is also the key name in the ini file
// pszContactInfo [out] the string of contact info. It will be empty string of the key cannot be found.
// cChSize [in] the buffer size, in characters, of pszContactInfo
//
// return: the number of characters copied to the buffer.
DWORD LoadContact(LPCTSTR pszTestName, LPTSTR pszContactInfo, DWORD cChSize)
{
return GetPrivateProfileString(c_szSectionName,
pszTestName,
_T(""),
pszContactInfo,
cChSize,
c_szFileName);
}