//++ // // 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 #include #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); }