//++ // // Copyright (C) Microsoft Corporation, 1987 - 1999 // // Module Name: // // nwtest.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 "nwtest.h" HRESULT NetwareTest(NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults) //++ // // Description: // This routine enumerates bindery or tree logins and in the case of tree login gives the // default context. // It also gets the server attached to. // // Argument: // None. // // Author: // Rajkumar .P 07/21/98 // { // PTESTED_DOMAIN Context = pParams->pDomain; LPWSTR pszCurrentContext = NULL; DWORD dwPrintOptions; LPWSTR pszName; WCHAR szUserName[MAX_PATH+1] = L""; WCHAR szNoName[2] = L""; DWORD_PTR ResumeKey = 0; LPBYTE pBuffer = NULL; DWORD EntriesRead = 0; DWORD dwMessageId; UNICODE_STRING uContext; WCHAR szContext[MAX_PATH+1]; LPWSTR pszTemp; // Get the current default tree or server name DWORD err ; PCONN_STATUS pConnStatus = NULL; DWORD i; PCONN_STATUS pConnStatusTmp; PCONN_STATUS pConnStatusUser; PCONN_STATUS pConnStatusNoUser; HANDLE handleRdr; LPWSTR pszText; // WNet calls related declarations; DWORD dwError; LPNETRESOURCE lpNetResource = NULL; HANDLE hEnum; DWORD dwCount; LPNETRESOURCE lpBuffer; DWORD BufferSize; HRESULT hr = hrOK; InitializeListHead( &pResults->Netware.lmsgOutput ); PrintStatusMessage(pParams, 4, IDS_NETWARE_STATUS_MSG); // // Check if client services for netware has been installed // /* dwError = WNetOpenEnum( RESOURCE_GLOBALNET, RESOURCETYPE_ANY | RESOURCETYPE_PRINT | RESOURCETYPE_DISK, 0, lpNetResource, &hEnum); if (dwError != NO_ERROR) { if (dwError == ERROR_NO_NETWORK) printf("No Network is present\n"); printf("WNetOpenEnum failed. Not Able to determine client services for netware is installed\n"); return FALSE; } lpBuffer = LocalAlloc(LMEM_ZEROINIT,sizeof(NETRESOURCE) * 100); // arbit dwError = WNetEnumResource( hEnum, &dwCount, lpBuffer, &BufferSize); if (dwError != NO_ERROR) { if (DebugVerbose) printf("Error: WNetEnumResource\n"); if (dwError == ERROR_NO_MORE_ITEMS) printf("ERROR_NO_MORE_ITEM\n"); dwError = GetLastError(); if (dwError == ERROR_MORE_DATA) { if (DebugVerbose) printf("ERROR_MORE_DATA\n"); } if (dwError == ERROR_INVALID_HANDLE) printf("ERROR_INVALID_HANDLE\n"); if (dwError == ERROR_NO_NETWORK) printf("ERROR_NO_NETWORK\n"); if (dwError == ERROR_EXTENDED_ERROR) printf("ERROR_EXTENDED_ERROR\n"); } else { printf("dwCount %d \n",dwCount); } LocalFree(lpBuffer); */ // end of WNet calls err = NwQueryInfo( &dwPrintOptions, &pszCurrentContext ); if ( err == NO_ERROR ) { szContext[0] = 0; uContext.Buffer = szContext; uContext.Length = uContext.MaximumLength = sizeof(szContext)/sizeof(szContext[0]); if ( pszCurrentContext ) { pszName = pszCurrentContext; } else { pszName = szNoName; } if ( pszName[0] == TREECHAR ) { // Get the tree name from the full name *TREE\CONTEXT if ( pszTemp = wcschr( pszName, L'\\' )) *pszTemp = 0; dwMessageId = NW_MESSAGE_NOT_LOGGED_IN_TREE; } else { dwMessageId = NW_MESSAGE_NOT_LOGGED_IN_SERVER; } if ( pszName[0] != 0 ) // there is preferred server/tree { err = NwGetConnectionStatus( pszName, &ResumeKey, &pBuffer, &EntriesRead ); } if ( err == NO_ERROR && EntriesRead > 0 ) // For trees, we'll get more than one entry { pConnStatus = (PCONN_STATUS) pBuffer; if ( EntriesRead > 1 && pszName[0] == TREECHAR ) { // If there is more than one entry for trees, // then we need to find one entry where username is not null. // If we cannot find one, then just use the first one. pConnStatusTmp = pConnStatus; pConnStatusUser = NULL; pConnStatusNoUser = NULL; for ( i = 0; i < EntriesRead ; i++ ) { if ( pConnStatusTmp->fNds ) { pConnStatusNoUser = pConnStatusTmp; if ( ( pConnStatusTmp->pszUserName != NULL ) && ( ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE ) || ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ) ) ) { // Found it pConnStatusUser = pConnStatusTmp; break; } } // Continue with the next item pConnStatusTmp = (PCONN_STATUS) ( (DWORD_PTR) pConnStatusTmp + pConnStatusTmp->dwTotalLength); } if ( pConnStatusUser ) { // found one nds entry with a user name pConnStatus = pConnStatusUser; } else if ( pConnStatusNoUser ) { // use an nds entry with no user name pConnStatus = pConnStatusNoUser; } // else use the first entry } if ( ( pConnStatus->pszUserName ) && ( pConnStatus->pszUserName[0] != 0 ) ) { NwAbbreviateUserName( pConnStatus->pszUserName, szUserName); NwMakePrettyDisplayName( szUserName ); if ( pszName[0] != TREECHAR ) { dwMessageId = NW_MESSAGE_LOGGED_IN_SERVER; } else { dwMessageId = NW_MESSAGE_LOGGED_IN_TREE; } } if ( pszName[0] == TREECHAR ) { // For trees, we need to get the current context // Open a handle to the redirector handleRdr = NULL; err = RtlNtStatusToDosError( NwNdsOpenRdrHandle( &handleRdr )); if ( err == NO_ERROR ) { UNICODE_STRING uTree; RtlInitUnicodeString( &uTree, pszName+1 ); // get past '*' // Get the current context in the default tree err = RtlNtStatusToDosError( NwNdsGetTreeContext( handleRdr, &uTree, &uContext)); } if ( handleRdr != NULL ) NtClose( handleRdr ); } } if ( !err ) { switch (dwMessageId) { case NW_MESSAGE_NOT_LOGGED_IN_TREE: // "You are not logged in to the directory tree %s. " AddMessageToList(&pResults->Netware.lmsgOutput, Nd_Quiet, IDS_NETWARE_NOT_LOGGED_IN_TREE, pszName[0] == TREECHAR ? pszName + 1: pszName); hr = S_FALSE; break; case NW_MESSAGE_NOT_LOGGED_IN_SERVER: // "You are not logged in to your preferred server %s.\n" AddMessageToList(&pResults->Netware.lmsgOutput, Nd_Quiet, IDS_NETWARE_NOT_LOGGED_IN_SERVER, pszName[0] == TREECHAR ? pszName + 1: pszName); hr = S_FALSE; break; case NW_MESSAGE_LOGGED_IN_SERVER: // "You are logged in to the server %s with user name %s.\n" AddMessageToList(&pResults->Netware.lmsgOutput, Nd_Verbose, IDS_NETWARE_LOGGED_IN_SERVER, pszName[0] == TREECHAR ? pszName + 1: pszName, szUserName); pResults->Netware.pszServer = StrDupTFromW(pszName[0] == TREECHAR ? pszName + 1 : pszName); pResults->Netware.pszUser = StrDupTFromW(szUserName); pResults->Netware.pszTree = StrDup(_T("")); pResults->Netware.pszContext = StrDup(_T("")); break; case NW_MESSAGE_LOGGED_IN_TREE: // "You are logged in to the directory tree %s with user name %s.\nThe current workstation name context is %s.\n" AddMessageToList(&pResults->Netware.lmsgOutput, Nd_Verbose, IDS_NETWARE_LOGGED_IN_TREE, pszName[0] == TREECHAR ? pszName + 1: pszName, szUserName, szContext); pResults->Netware.pszTree = StrDupTFromW(pszName[0] == TREECHAR ? pszName + 1 : pszName); pResults->Netware.pszUser = StrDupTFromW(szUserName); pResults->Netware.pszContext = StrDupTFromW(szContext); pResults->Netware.pszServer = StrDup(_T("")); } // Read from the conn status if possible if (pConnStatus) { pResults->Netware.fConnStatus = TRUE; if (pConnStatus->pszUserName) { Free(pResults->Netware.pszUser); pResults->Netware.pszUser = StrDupTFromW(pConnStatus->pszUserName); } if (pConnStatus->pszServerName) { Free(pResults->Netware.pszServer); pResults->Netware.pszServer = StrDupTFromW(pConnStatus->pszServerName); } if (pConnStatus->pszTreeName) { Free(pResults->Netware.pszTree); pResults->Netware.pszTree = StrDupTFromW(pConnStatus->pszTreeName); } pResults->Netware.fNds = pConnStatus->fNds; pResults->Netware.dwConnType = pConnStatus->dwConnType; } else pResults->Netware.fConnStatus = FALSE; } if ( pBuffer != NULL ) { LocalFree( pBuffer ); pBuffer = NULL; } } if ( pszCurrentContext != NULL ) { LocalFree( pszCurrentContext ); pszCurrentContext = NULL; } if ( err != NO_ERROR ) { // if (DebugVerbose) // printf("Error %s occurred while trying to get connection information.\n",err); // printf("Error getting connection information\n"); hr = S_FALSE; } return hr; } WORD NwParseNdsUncPath( IN OUT LPWSTR * Result, IN LPWSTR ContainerName, IN ULONG flag ) /*++ Routine Description: This function is used to extract either the tree name, fully distinguished name path to an object, or object name, out of a complete NDS UNC path. Arguments: Result - parsed result buffer. ContainerName - Complete NDS UNC path that is to be parsed. flag - Flag indicating operation to be performed: PARSE_NDS_GET_TREE_NAME PARSE_NDS_GET_PATH_NAME PARSE_NDS_GET_OBJECT_NAME Return Value: Length of string in result buffer. If error occured, 0 is returned. --*/ // NwParseNdsUncPath { USHORT length = 2; USHORT totalLength = (USHORT) wcslen( ContainerName ); if ( totalLength < 2 ) return 0; // // First get length to indicate the character in the string that indicates the // "\" in between the tree name and the rest of the UNC path. // // Example: \\\[\|.] // ^ // | // while ( length < totalLength && ContainerName[length] != L'\\' ) { length++; } if ( flag == PARSE_NDS_GET_TREE_NAME ) { *Result = (LPWSTR) ( ContainerName + 2 ); return ( length - 2 ) * sizeof( WCHAR ); // Take off 2 for the two \\'s } if ( flag == PARSE_NDS_GET_PATH_NAME && length == totalLength ) { *Result = ContainerName; return 0; } if ( flag == PARSE_NDS_GET_PATH_NAME ) { *Result = ContainerName + length + 1; return ( totalLength - length - 1 ) * sizeof( WCHAR ); } *Result = ContainerName + totalLength - 1; length = 1; while ( **Result != L'\\' ) { *Result--; length++; } *Result++; length--; return length * sizeof( WCHAR ); } NTSTATUS NwNdsOpenRdrHandle( OUT PHANDLE phNwRdrHandle ) { NTSTATUS ntstatus; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; ACCESS_MASK DesiredAccess = SYNCHRONIZE | GENERIC_READ; WCHAR NameStr[] = L"\\Device\\NwRdr\\*"; UNICODE_STRING uOpenName; // // Prepare the open name. // RtlInitUnicodeString( &uOpenName, NameStr ); // // Set up the object attributes. // InitializeObjectAttributes( &ObjectAttributes, &uOpenName, OBJ_CASE_INSENSITIVE, NULL, NULL ); ntstatus = NtOpenFile( phNwRdrHandle, DesiredAccess, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT ); if ( !NT_ERROR(ntstatus) && !NT_INFORMATION(ntstatus) && !NT_WARNING(ntstatus)) { return IoStatusBlock.Status; } return ntstatus; } NTSTATUS NwNdsGetTreeContext ( IN HANDLE hNdsRdr, IN PUNICODE_STRING puTree, OUT PUNICODE_STRING puContext ) /*+++ This gets the current context of the requested tree. ---*/ { NTSTATUS ntstatus; IO_STATUS_BLOCK IoStatusBlock; PNWR_NDS_REQUEST_PACKET Rrp; DWORD RrpSize; // // Set up the request. // RrpSize = sizeof( NWR_NDS_REQUEST_PACKET ) + puTree->Length; Rrp = LocalAlloc( LMEM_ZEROINIT, RrpSize ); if ( !Rrp ) { return STATUS_INSUFFICIENT_RESOURCES; } try { (Rrp->Parameters).GetContext.TreeNameLen = puTree->Length; RtlCopyMemory( (BYTE *)(Rrp->Parameters).GetContext.TreeNameString, puTree->Buffer, puTree->Length ); (Rrp->Parameters).GetContext.Context.MaximumLength = puContext->MaximumLength; (Rrp->Parameters).GetContext.Context.Length = 0; (Rrp->Parameters).GetContext.Context.Buffer = puContext->Buffer; } except ( EXCEPTION_EXECUTE_HANDLER ) { ntstatus = STATUS_INVALID_PARAMETER; goto ExitWithCleanup; } try { ntstatus = NtFsControlFile( hNdsRdr, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_NDS_GETCONTEXT, (PVOID) Rrp, RrpSize, NULL, 0 ); } except ( EXCEPTION_EXECUTE_HANDLER ) { ntstatus = GetExceptionCode(); goto ExitWithCleanup; } // // Copy out the length; the buffer has already been written. // puContext->Length = (Rrp->Parameters).GetContext.Context.Length; ExitWithCleanup: LocalFree( Rrp ); return ntstatus; } DWORD NwGetConnectionStatus( IN LPWSTR pszRemoteName, OUT PDWORD_PTR ResumeKey, OUT LPBYTE *Buffer, OUT PDWORD EntriesRead ) { DWORD err = NO_ERROR; DWORD dwBytesNeeded = 0; DWORD dwBufferSize = TWO_KB; *Buffer = NULL; *EntriesRead = 0; do { *Buffer = (LPBYTE) LocalAlloc( LMEM_ZEROINIT, dwBufferSize ); if ( *Buffer == NULL ) return ERROR_NOT_ENOUGH_MEMORY; err = NWPGetConnectionStatus( pszRemoteName, ResumeKey, *Buffer, dwBufferSize, &dwBytesNeeded, EntriesRead ); if ( err == ERROR_INSUFFICIENT_BUFFER ) { dwBufferSize = dwBytesNeeded + EXTRA_BYTES; LocalFree( *Buffer ); *Buffer = NULL; } } while ( err == ERROR_INSUFFICIENT_BUFFER ); if ( err == ERROR_INVALID_PARAMETER ) // not attached { err = NO_ERROR; *EntriesRead = 0; } return err; } VOID NwAbbreviateUserName( IN LPWSTR pszFullName, OUT LPWSTR pszUserName ) { LPWSTR pszTemp; LPWSTR pszLast; WCHAR NextChar; if ( pszUserName == NULL ) return; pszTemp = pszFullName; pszLast = pszTemp; *pszUserName = 0; while ( pszTemp = wcschr( pszTemp, L'=')) { NextChar = *(++pszTemp); while ( NextChar != 0 && NextChar != L'.' ) { *(pszUserName++) = *pszTemp; NextChar = *(++pszTemp); } if ( NextChar == 0 ) { pszLast = NULL; break; } *(pszUserName++) = *pszTemp; // put back the '.' pszLast = ++pszTemp; } if ( pszLast != NULL ) { while ( *pszLast != 0 ) *(pszUserName++) = *(pszLast++); } *pszUserName = 0; } VOID NwMakePrettyDisplayName( IN LPWSTR pszName ) { if ( pszName ) { CharLower((LPSTR)pszName ); CharUpperBuff( (LPSTR)pszName, 1); } } DWORD NWPGetConnectionStatus( IN LPWSTR pszRemoteName, IN OUT PDWORD_PTR ResumeKey, OUT LPBYTE Buffer, IN DWORD BufferSize, OUT PDWORD BytesNeeded, OUT PDWORD EntriesRead ) { NTSTATUS ntstatus = STATUS_SUCCESS; HANDLE handleRdr = NULL; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING uRdrName; WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*"; PNWR_REQUEST_PACKET RequestPacket = NULL; DWORD RequestPacketSize = 0; DWORD dwRemoteNameLen = 0; // // Set up the object attributes. // RtlInitUnicodeString( &uRdrName, RdrPrefix ); InitializeObjectAttributes( &ObjectAttributes, &uRdrName, OBJ_CASE_INSENSITIVE, NULL, NULL ); ntstatus = NtOpenFile( &handleRdr, SYNCHRONIZE | FILE_LIST_DIRECTORY, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT ); if ( !NT_SUCCESS(ntstatus) ) goto CleanExit; dwRemoteNameLen = pszRemoteName? wcslen(pszRemoteName)*sizeof(WCHAR) : 0; RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwRemoteNameLen; RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT, RequestPacketSize ); if ( RequestPacket == NULL ) { ntstatus = STATUS_NO_MEMORY; goto CleanExit; } // // Fill out the request packet for FSCTL_NWR_GET_CONN_STATUS. // RequestPacket->Parameters.GetConnStatus.ResumeKey = *ResumeKey; RequestPacket->Version = REQUEST_PACKET_VERSION; RequestPacket->Parameters.GetConnStatus.ConnectionNameLength = dwRemoteNameLen; RtlCopyMemory( &(RequestPacket->Parameters.GetConnStatus.ConnectionName[0]), pszRemoteName, dwRemoteNameLen ); ntstatus = NtFsControlFile( handleRdr, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_GET_CONN_STATUS, (PVOID) RequestPacket, RequestPacketSize, (PVOID) Buffer, BufferSize ); if ( NT_SUCCESS( ntstatus )) ntstatus = IoStatusBlock.Status; *EntriesRead = RequestPacket->Parameters.GetConnStatus.EntriesReturned; *ResumeKey = RequestPacket->Parameters.GetConnStatus.ResumeKey; *BytesNeeded = RequestPacket->Parameters.GetConnStatus.BytesNeeded; CleanExit: if ( handleRdr != NULL ) NtClose( handleRdr ); if ( RequestPacket != NULL ) LocalFree( RequestPacket ); return RtlNtStatusToDosError( ntstatus ); } BOOL NwIsNdsSyntax( IN LPWSTR lpstrUnc ) { HANDLE hTreeConn; DWORD dwOid; DWORD status = NO_ERROR; if ( lpstrUnc == NULL ) return FALSE; status = NwOpenAndGetTreeInfo( lpstrUnc, &hTreeConn, &dwOid ); if ( status != NO_ERROR ) { return FALSE; } CloseHandle( hTreeConn ); return TRUE; } DWORD NwOpenAndGetTreeInfo( LPWSTR pszNdsUNCPath, HANDLE *phTreeConn, DWORD *pdwOid ) { NTSTATUS ntstatus = STATUS_SUCCESS; WCHAR lpServerName[NW_MAX_SERVER_LEN]; UNICODE_STRING ServerName; UNICODE_STRING ObjectName; *phTreeConn = NULL; ServerName.Length = 0; ServerName.MaximumLength = sizeof( lpServerName ); ServerName.Buffer = lpServerName; ObjectName.Buffer = NULL; ObjectName.MaximumLength = ( wcslen( pszNdsUNCPath) + 1 ) * sizeof( WCHAR ); ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer, pszNdsUNCPath, PARSE_NDS_GET_TREE_NAME ); if ( ObjectName.Length == 0 || ObjectName.Buffer == NULL ) { return ERROR_PATH_NOT_FOUND; } // // Open a NDS tree connection handle to \\treename // ntstatus = NwNdsOpenTreeHandle( &ObjectName, phTreeConn ); if ( !NT_SUCCESS( ntstatus )) { return RtlNtStatusToDosError( ntstatus ); } // // Get the path to the container to open. // ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer, pszNdsUNCPath, PARSE_NDS_GET_PATH_NAME ); if ( ObjectName.Length == 0 ) { UNICODE_STRING Root; RtlInitUnicodeString(&Root, L"[Root]"); // // Resolve the path to get a NDS object id. // ntstatus = NwNdsResolveName( *phTreeConn, &Root, pdwOid, &ServerName, NULL, 0 ); } else { // // Resolve the path to get a NDS object id. // ntstatus = NwNdsResolveName( *phTreeConn, &ObjectName, pdwOid, &ServerName, NULL, 0 ); } if ( ntstatus == STATUS_SUCCESS && ServerName.Length ) { DWORD dwHandleType; // // NwNdsResolveName succeeded, but we were referred to // another server, though pdwOid is still valid. if ( *phTreeConn ) CloseHandle( *phTreeConn ); *phTreeConn = NULL; // // Open a NDS generic connection handle to \\ServerName // ntstatus = NwNdsOpenGenericHandle( &ServerName, &dwHandleType, phTreeConn ); if ( ntstatus != STATUS_SUCCESS ) { return RtlNtStatusToDosError(ntstatus); } ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER ); } if ( !NT_SUCCESS( ntstatus )) { if ( *phTreeConn != NULL ) { CloseHandle( *phTreeConn ); *phTreeConn = NULL; } return RtlNtStatusToDosError(ntstatus); } return NO_ERROR; } static DWORD NwRegQueryValueExW( IN HKEY hKey, IN LPWSTR lpValueName, OUT LPDWORD lpReserved, OUT LPDWORD lpType, OUT LPBYTE lpData, IN OUT LPDWORD lpcbData ) /*++ Routine Description: This routine supports the same functionality as Win32 RegQueryValueEx API, except that it works. It returns the correct lpcbData value when a NULL output buffer is specified. This code is stolen from the service controller. Arguments: same as RegQueryValueEx Return Value: NO_ERROR or reason for failure. --*/ { NTSTATUS ntstatus; UNICODE_STRING ValueName; PKEY_VALUE_FULL_INFORMATION KeyValueInfo; DWORD BufSize; UNREFERENCED_PARAMETER(lpReserved); // // Make sure we have a buffer size if the buffer is present. // if ((ARGUMENT_PRESENT(lpData)) && (! ARGUMENT_PRESENT(lpcbData))) { return ERROR_INVALID_PARAMETER; } RtlInitUnicodeString(&ValueName, lpValueName); // // Allocate memory for the ValueKeyInfo // BufSize = *lpcbData + sizeof(KEY_VALUE_FULL_INFORMATION) + ValueName.Length - sizeof(WCHAR); // subtract memory for 1 char because it's included // in the sizeof(KEY_VALUE_FULL_INFORMATION). KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) LocalAlloc( LMEM_ZEROINIT, (UINT) BufSize ); if (KeyValueInfo == NULL) { // if (DebugVerbose) // printf("NWWORKSTATION: NwRegQueryValueExW: LocalAlloc failed %lu\n", // GetLastError()); return ERROR_NOT_ENOUGH_MEMORY; } ntstatus = NtQueryValueKey( hKey, &ValueName, KeyValueFullInformation, (PVOID) KeyValueInfo, (ULONG) BufSize, (PULONG) &BufSize ); if ((NT_SUCCESS(ntstatus) || (ntstatus == STATUS_BUFFER_OVERFLOW)) && ARGUMENT_PRESENT(lpcbData)) { *lpcbData = KeyValueInfo->DataLength; } if (NT_SUCCESS(ntstatus)) { if (ARGUMENT_PRESENT(lpType)) { *lpType = KeyValueInfo->Type; } if (ARGUMENT_PRESENT(lpData)) { memcpy( lpData, (LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset, KeyValueInfo->DataLength ); } } (void) LocalFree((HLOCAL) KeyValueInfo); return RtlNtStatusToDosError(ntstatus); } DWORD NwReadRegValue( IN HKEY Key, IN LPWSTR ValueName, OUT LPWSTR *Value ) /*++ Routine Description: This function allocates the output buffer and reads the requested value from the registry into it. Arguments: Key - Supplies opened handle to the key to read from. ValueName - Supplies name of the value to retrieve data. Value - Returns a pointer to the output buffer which points to the memory allocated and contains the data read in from the registry. This pointer must be freed with LocalFree when done. Return Value: ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into. Error from registry call. --*/ { LONG RegError; DWORD NumRequired = 0; DWORD ValueType; // // Set returned buffer pointer to NULL. // *Value = NULL; RegError = NwRegQueryValueExW( Key, ValueName, NULL, &ValueType, (LPBYTE) NULL, &NumRequired ); if (RegError != ERROR_SUCCESS && NumRequired > 0) { if ((*Value = (LPWSTR) LocalAlloc( LMEM_ZEROINIT, (UINT) NumRequired )) == NULL) { // if (DebugVerbose) // printf("NWWORKSTATION: NwReadRegValue: LocalAlloc of size %lu failed %lu\n", NumRequired, GetLastError()); // return ERROR_NOT_ENOUGH_MEMORY; } RegError = NwRegQueryValueExW( Key, ValueName, NULL, &ValueType, (LPBYTE) *Value, &NumRequired ); } else if (RegError == ERROR_SUCCESS) { // if (DebugVerbose) // printf("NWWORKSTATION: NwReadRegValue got SUCCESS with NULL buffer."); return ERROR_FILE_NOT_FOUND; } if (RegError != ERROR_SUCCESS) { if (*Value != NULL) { (void) LocalFree((HLOCAL) *Value); *Value = NULL; } return (DWORD) RegError; } return NO_ERROR; } DWORD NwpGetCurrentUserRegKey( IN DWORD DesiredAccess, OUT HKEY *phKeyCurrentUser ) /*++ Routine Description: This routine opens the current user's registry key under \HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWCWorkstation\Parameters Arguments: DesiredAccess - The access mask to open the key with phKeyCurrentUser - Receives the opened key handle Return Value: Returns the appropriate Win32 error. --*/ { DWORD err; HKEY hkeyWksta; LPWSTR CurrentUser; DWORD Disposition; // // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services // \NWCWorkstation\Parameters // err = RegOpenKeyExW( HKEY_LOCAL_MACHINE, NW_WORKSTATION_REGKEY, REG_OPTION_NON_VOLATILE, KEY_READ, &hkeyWksta ); if ( err ) { // if (DebugVerbose) // printf("NWPROVAU: NwGetCurrentUserRegKey open Paramters key unexpected error %lu!\n",err); return err; } // // Get the current user's SID string. // err = NwReadRegValue( hkeyWksta, NW_CURRENTUSER_VALUENAME, &CurrentUser ); if ( err ) { // if (DebugVerbose) // printf("NWPROVAU: NwGetCurrentUserRegKey read CurrentUser value unexpected error %lu !\n", err); (void) RegCloseKey( hkeyWksta ); return err; } (void) RegCloseKey( hkeyWksta ); // // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services // \NWCWorkstation\Parameters\Option // err = RegOpenKeyExW( HKEY_LOCAL_MACHINE, NW_WORKSTATION_OPTION_REGKEY, REG_OPTION_NON_VOLATILE, KEY_READ, &hkeyWksta ); if ( err ) { // if (DebugVerbose) // printf("NWPROVAU: NwGetCurrentUserRegKey open Parameters\\Option key unexpected error %lu!\n", err); return err; } // // Open current user's key // err = RegOpenKeyExW( hkeyWksta, CurrentUser, REG_OPTION_NON_VOLATILE, DesiredAccess, phKeyCurrentUser ); if ( err == ERROR_FILE_NOT_FOUND) { // // Create key under NWCWorkstation\Parameters\Option // err = RegCreateKeyExW( hkeyWksta, CurrentUser, 0, WIN31_CLASS, REG_OPTION_NON_VOLATILE, DesiredAccess, NULL, // security attr phKeyCurrentUser, &Disposition ); } if ( err ) { // if (DebugVerbose) // printf("NWPROVAU: NwGetCurrentUserRegKey open or create of Parameters\\Option\\%ws key failed %lu\n", CurrentUser, err); } (void) RegCloseKey( hkeyWksta ); (void) LocalFree((HLOCAL)CurrentUser) ; return err; } DWORD NwQueryInfo( OUT PDWORD pnPrintOptions, OUT LPWSTR *ppszPreferredSrv ) /*++ Routine Description: This routine gets the user's preferred server and print options from the registry. Arguments: pnPrintOptions - Receives the user's print option ppszPreferredSrv - Receives the user's preferred server Return Value: Returns the appropriate Win32 error. --*/ { HKEY hKeyCurrentUser = NULL; DWORD BufferSize; DWORD BytesNeeded; DWORD PrintOption; DWORD ValueType; LPWSTR PreferredServer ; DWORD err ; // // get to right place in registry and allocate dthe buffer // if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser)) { // // If somebody mess around with the registry and we can't find // the registry, just use the defaults. // *ppszPreferredSrv = NULL; // *pnPrintOptions = NW_PRINT_OPTION_DEFAULT; return NO_ERROR; } BufferSize = sizeof(WCHAR) * (MAX_PATH + 2) ; PreferredServer = (LPWSTR) LocalAlloc(LPTR, BufferSize) ; if (!PreferredServer) return (GetLastError()) ; // // Read PreferredServer value into Buffer. // BytesNeeded = BufferSize ; err = RegQueryValueExW( hKeyCurrentUser, NW_SERVER_VALUENAME, NULL, &ValueType, (LPBYTE) PreferredServer, &BytesNeeded ); if (err != NO_ERROR) { // // set to empty and carry on // PreferredServer[0] = 0; } if (hKeyCurrentUser != NULL) (void) RegCloseKey(hKeyCurrentUser) ; *ppszPreferredSrv = PreferredServer ; return NO_ERROR ; } /*!-------------------------------------------------------------------------- NetwareGlobalPrint - Author: KennT ---------------------------------------------------------------------------*/ void NetwareGlobalPrint( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults) { int ids; LPTSTR pszConnType; if (!pResults->Ipx.fEnabled) { return; } if (pParams->fVerbose || !FHrOK(pResults->Netware.hr)) { BOOL fVerboseT, fReallyVerboseT; PrintNewLine(pParams, 2); PrintMessage(pParams, IDS_NETWARE_TITLE_MSG); fVerboseT = pParams->fVerbose; fReallyVerboseT = pParams->fReallyVerbose; pParams->fReallyVerbose = TRUE; PrintMessageList(pParams, &pResults->Netware.lmsgOutput); pParams->fReallyVerbose = fReallyVerboseT; pParams->fVerbose = fVerboseT; // Now print out the results if (FHrOK(pResults->Netware.hr)) { // Print out the user name, server name, tree and context PrintMessage(pParams, IDS_NETWARE_USER_NAME, pResults->Netware.pszUser == 0 ? _T("") : pResults->Netware.pszUser); PrintMessage(pParams, IDS_NETWARE_SERVER_NAME, pResults->Netware.pszServer == 0 ? _T("") : pResults->Netware.pszServer); PrintMessage(pParams, IDS_NETWARE_TREE_NAME, pResults->Netware.pszTree == 0 ? _T("") : pResults->Netware.pszTree); PrintMessage(pParams, IDS_NETWARE_CONTEXT, pResults->Netware.pszContext == 0 ? _T("") : pResults->Netware.pszContext); // Print out the connection type and nds if (pResults->Netware.fConnStatus) { PrintMessage(pParams, IDS_NETWARE_NDS, MAP_YES_NO(pResults->Netware.fNds)); switch (pResults->Netware.dwConnType) { case NW_CONN_NOT_AUTHENTICATED: ids = IDS_NETWARE_CONN_NOT_AUTHENTICATED; break; case NW_CONN_BINDERY_LOGIN: ids = IDS_NETWARE_CONN_BINDERY_LOGIN; break; case NW_CONN_NDS_AUTHENTICATED_NO_LICENSE: ids = IDS_NETWARE_CONN_NDS_AUTHENTICATED_NO_LICENSE; break; case NW_CONN_NDS_AUTHENTICATED_LICENSED: ids = IDS_NETWARE_CONN_NDS_AUTHENTICATED_LICENSED; break; case NW_CONN_DISCONNECTED: ids = IDS_NETWARE_CONN_DISCONNECTED; break; default: ids = IDS_NETWARE_CONN_UNKNOWN; break; } PrintMessage(pParams, ids, pResults->Netware.dwConnType); } } } } /*!-------------------------------------------------------------------------- NetwarePerInterfacePrint - Author: KennT ---------------------------------------------------------------------------*/ void NetwarePerInterfacePrint( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults, INTERFACE_RESULT *pInterfaceResults) { // no per-interface results } /*!-------------------------------------------------------------------------- NetwareCleanup - Author: KennT ---------------------------------------------------------------------------*/ void NetwareCleanup( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults) { Free(pResults->Netware.pszUser); pResults->Netware.pszUser = NULL; Free(pResults->Netware.pszServer); pResults->Netware.pszServer = NULL; Free(pResults->Netware.pszTree); pResults->Netware.pszTree = NULL; Free(pResults->Netware.pszContext); pResults->Netware.pszContext = NULL; MessageListCleanUp(&pResults->Netware.lmsgOutput); }