/*++ Copyright (c) 1995 Microsoft Corporation Module Name: NdsApiNT.c Abstract: This module implements the NT specific exposed user-mode link to Netware NDS support in the Netware redirector. For more comments, see ndslib32.h. Author: Cory West [CoryWest] 23-Feb-1995 --*/ #include NTSTATUS NwNdsOpenTreeHandle( IN PUNICODE_STRING puNdsTree, OUT PHANDLE phNwRdrHandle ) { NTSTATUS ntstatus, OpenStatus; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; ACCESS_MASK DesiredAccess = SYNCHRONIZE | FILE_LIST_DIRECTORY; WCHAR DevicePreamble[] = L"\\Device\\Nwrdr\\"; UINT PreambleLength = 14; WCHAR NameStr[128]; UNICODE_STRING uOpenName; UINT i; PNWR_NDS_REQUEST_PACKET Rrp; BYTE RrpData[1024]; // // Prepare the open name. // uOpenName.MaximumLength = sizeof( NameStr ); if ( puNdsTree->Length > (MAX_NDS_TREE_NAME_LEN * sizeof(WCHAR))) return STATUS_INVALID_PARAMETER; for ( i = 0; i < PreambleLength ; i++ ) NameStr[i] = DevicePreamble[i]; try { for ( i = 0 ; i < ( puNdsTree->Length / sizeof( WCHAR ) ) ; i++ ) { NameStr[i + PreambleLength] = puNdsTree->Buffer[i]; } } except ( EXCEPTION_EXECUTE_HANDLER ) { return STATUS_INVALID_PARAMETER; } uOpenName.Length = (USHORT)(( i * sizeof( WCHAR ) ) + ( PreambleLength * sizeof( WCHAR ) )); uOpenName.Buffer = 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_SUCCESS(ntstatus) ) return ntstatus; OpenStatus = IoStatusBlock.Status; // // Verify that this is a tree handle, not a server handle. // Rrp = (PNWR_NDS_REQUEST_PACKET)RrpData; Rrp->Version = 0; RtlCopyMemory( &(Rrp->Parameters).VerifyTree, puNdsTree, sizeof( UNICODE_STRING ) ); RtlCopyMemory( (BYTE *)(&(Rrp->Parameters).VerifyTree.NameString), puNdsTree->Buffer, puNdsTree->Length ); (Rrp->Parameters).VerifyTree.TreeName.Buffer = (Rrp->Parameters).VerifyTree.NameString; try { ntstatus = NtFsControlFile( *phNwRdrHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_NDS_VERIFY_TREE, (PVOID) Rrp, sizeof( NWR_NDS_REQUEST_PACKET ) + puNdsTree->Length, NULL, 0 ); } except ( EXCEPTION_EXECUTE_HANDLER ) { ntstatus = GetExceptionCode(); goto CloseAndExit; } if ( !NT_SUCCESS( ntstatus )) { goto CloseAndExit; } // // Otherwise, all is well! // return OpenStatus; CloseAndExit: NtClose( *phNwRdrHandle ); *phNwRdrHandle = NULL; return ntstatus; } NTSTATUS NwOpenHandleWithSupplementalCredentials( IN PUNICODE_STRING puResourceName, IN PUNICODE_STRING puUserName, IN PUNICODE_STRING puPassword, OUT LPDWORD lpdwHandleType, OUT PHANDLE phNwHandle ) { NTSTATUS ntstatus, OpenStatus; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; ACCESS_MASK DesiredAccess = FILE_GENERIC_READ | FILE_GENERIC_WRITE; WCHAR DevicePreamble[] = L"\\Device\\Nwrdr\\"; UINT PreambleLength = 14; WCHAR NameStr[128]; UNICODE_STRING uOpenName; UINT i; PFILE_FULL_EA_INFORMATION pEaEntry; PBYTE EaBuffer; ULONG EaLength, EaNameLength, EaTotalLength; ULONG UserNameLen, PasswordLen, TypeLen, CredLen; PNWR_NDS_REQUEST_PACKET Rrp; BYTE RrpData[1024]; // // Prepare the open name. // uOpenName.MaximumLength = sizeof( NameStr ); if ( puResourceName->Length > uOpenName.MaximumLength - ( PreambleLength * sizeof(WCHAR) ) ) return STATUS_INVALID_PARAMETER; for ( i = 0; i < PreambleLength ; i++ ) NameStr[i] = DevicePreamble[i]; try { for ( i = 0 ; i < ( puResourceName->Length / sizeof( WCHAR ) ) ; i++ ) { NameStr[i + PreambleLength] = puResourceName->Buffer[i]; } } except ( EXCEPTION_EXECUTE_HANDLER ) { return STATUS_INVALID_PARAMETER; } uOpenName.Length = (USHORT)(( i * sizeof( WCHAR ) ) + ( PreambleLength * sizeof( WCHAR ) )); uOpenName.Buffer = NameStr; // // Set up the object attributes. // InitializeObjectAttributes( &ObjectAttributes, &uOpenName, OBJ_CASE_INSENSITIVE, NULL, NULL ); // // Allocate the EA buffer - be a little generous. // UserNameLen = strlen( EA_NAME_USERNAME ); PasswordLen = strlen( EA_NAME_PASSWORD ); TypeLen = strlen( EA_NAME_TYPE ); CredLen = strlen( EA_NAME_CREDENTIAL_EX ); EaLength = 4 * sizeof( FILE_FULL_EA_INFORMATION ); EaLength += 4 * sizeof( ULONG ); EaLength += ROUNDUP4( UserNameLen ); EaLength += ROUNDUP4( PasswordLen ); EaLength += ROUNDUP4( TypeLen ); EaLength += ROUNDUP4( CredLen ); EaLength += ROUNDUP4( puUserName->Length ); EaLength += ROUNDUP4( puPassword->Length ); EaBuffer = LocalAlloc( LMEM_ZEROINIT, EaLength ); if ( !EaBuffer ) { return STATUS_INSUFFICIENT_RESOURCES; } // // Pack in the first EA: UserName. // pEaEntry = (PFILE_FULL_EA_INFORMATION) EaBuffer; EaNameLength = UserNameLen + sizeof( CHAR ); pEaEntry->EaNameLength = (UCHAR) EaNameLength; pEaEntry->EaValueLength = puUserName->Length; RtlCopyMemory( &(pEaEntry->EaName[0]), EA_NAME_USERNAME, EaNameLength ); EaNameLength = ROUNDUP2( EaNameLength + sizeof( CHAR ) ); RtlCopyMemory( &(pEaEntry->EaName[EaNameLength]), puUserName->Buffer, puUserName->Length ); EaLength = ( 2 * sizeof( DWORD ) ) + EaNameLength + puUserName->Length; EaLength = ROUNDUP4( EaLength ); EaTotalLength = EaLength; pEaEntry->NextEntryOffset = EaLength; // // Pack in the second EA: Password. // pEaEntry = (PFILE_FULL_EA_INFORMATION) ( ( (PBYTE)pEaEntry ) + pEaEntry->NextEntryOffset ); EaNameLength = PasswordLen + sizeof( CHAR ); pEaEntry->EaNameLength = (UCHAR) EaNameLength; pEaEntry->EaValueLength = puPassword->Length; RtlCopyMemory( &(pEaEntry->EaName[0]), EA_NAME_PASSWORD, EaNameLength ); EaNameLength = ROUNDUP2( EaNameLength + sizeof( CHAR ) ); RtlCopyMemory( &(pEaEntry->EaName[EaNameLength]), puPassword->Buffer, puPassword->Length ); EaLength = ( 2 * sizeof( DWORD ) ) + EaNameLength + puPassword->Length; EaLength = ROUNDUP4( EaLength ); EaTotalLength += EaLength; pEaEntry->NextEntryOffset = EaLength; // // Pack in the third EA: Type. // pEaEntry = (PFILE_FULL_EA_INFORMATION) ( ( (PBYTE)pEaEntry ) + pEaEntry->NextEntryOffset ); EaNameLength = TypeLen + sizeof( CHAR ); pEaEntry->EaNameLength = (UCHAR) EaNameLength; pEaEntry->EaValueLength = sizeof( ULONG ); RtlCopyMemory( &(pEaEntry->EaName[0]), EA_NAME_TYPE, EaNameLength ); EaNameLength = ROUNDUP2( EaNameLength + sizeof( CHAR ) ); EaLength = ( 2 * sizeof( DWORD ) ) + EaNameLength + sizeof( ULONG ); EaLength = ROUNDUP4( EaLength ); EaTotalLength += EaLength; pEaEntry->NextEntryOffset = EaLength; // // Pack in the fourth EA: the CredentialEx flag. // pEaEntry = (PFILE_FULL_EA_INFORMATION) ( ( (PBYTE)pEaEntry ) + pEaEntry->NextEntryOffset ); EaNameLength = CredLen + sizeof( CHAR ); pEaEntry->EaNameLength = (UCHAR) EaNameLength; pEaEntry->EaValueLength = sizeof( ULONG ); RtlCopyMemory( &(pEaEntry->EaName[0]), EA_NAME_CREDENTIAL_EX, EaNameLength ); EaNameLength = ROUNDUP2( EaNameLength + sizeof( CHAR ) ); EaLength = ( 2 * sizeof( DWORD ) ) + EaNameLength + sizeof( ULONG ); EaLength = ROUNDUP4( EaLength ); EaTotalLength += EaLength; pEaEntry->NextEntryOffset = 0; // // Do the open. // ntstatus = NtCreateFile( phNwHandle, // File handle (OUT) DesiredAccess, // Access mask &ObjectAttributes, // Object attributes &IoStatusBlock, // Io status NULL, // Optional Allocation size FILE_ATTRIBUTE_NORMAL, // File attributes FILE_SHARE_VALID_FLAGS, // File share access FILE_OPEN, // Create disposition 0, // Create options (PVOID) EaBuffer, // Our EA buffer EaTotalLength ); // Ea buffer length LocalFree( EaBuffer ); if ( !NT_SUCCESS(ntstatus) ) return ntstatus; OpenStatus = IoStatusBlock.Status; // // Check the handle type. // Rrp = (PNWR_NDS_REQUEST_PACKET)RrpData; Rrp->Version = 0; RtlCopyMemory( &(Rrp->Parameters).VerifyTree, puResourceName, sizeof( UNICODE_STRING ) ); RtlCopyMemory( (BYTE *)(&(Rrp->Parameters).VerifyTree) + sizeof( UNICODE_STRING ), puResourceName->Buffer, puResourceName->Length ); try { ntstatus = NtFsControlFile( *phNwHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_NDS_VERIFY_TREE, (PVOID) Rrp, sizeof( NWR_NDS_REQUEST_PACKET ) + puResourceName->Length, NULL, 0 ); } except ( EXCEPTION_EXECUTE_HANDLER ) { ntstatus = GetExceptionCode(); goto CloseAndExit2; } if ( !NT_SUCCESS( ntstatus )) { *lpdwHandleType = HANDLE_TYPE_NCP_SERVER; } else { *lpdwHandleType = HANDLE_TYPE_NDS_TREE; } return OpenStatus; CloseAndExit2: NtClose( *phNwHandle ); *phNwHandle = NULL; return ntstatus; } NTSTATUS NwNdsResolveName ( IN HANDLE hNdsTree, IN PUNICODE_STRING puObjectName, OUT DWORD *dwObjectId, OUT PUNICODE_STRING puReferredServer, OUT PBYTE pbRawResponse, IN DWORD dwResponseBufferLen ) { NTSTATUS ntstatus; IO_STATUS_BLOCK IoStatusBlock; PNWR_NDS_REQUEST_PACKET Rrp; PNDS_RESPONSE_RESOLVE_NAME Rsp; DWORD dwRspBufferLen, dwNameLen, dwPadding; BYTE RrpData[1024]; BYTE RspData[256]; Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData; RtlZeroMemory( Rrp, 1024 ); // // NW NDS strings are null terminated, so we make sure we // report the correct length... // dwNameLen = puObjectName->Length + sizeof( WCHAR ); if (dwNameLen > MAX_NDS_NAME_SIZE) { return STATUS_INVALID_PARAMETER; } Rrp->Version = 0; Rrp->Parameters.ResolveName.ObjectNameLength = ROUNDUP4( dwNameLen ); Rrp->Parameters.ResolveName.ResolverFlags = RSLV_DEREF_ALIASES | RSLV_WALK_TREE | RSLV_WRITABLE; try { // // But don't try to copy more than the user gave us. // memcpy( Rrp->Parameters.ResolveName.ObjectName, puObjectName->Buffer, puObjectName->Length ); } except ( EXCEPTION_EXECUTE_HANDLER ) { return STATUS_INVALID_PARAMETER; } // // Send the request to the Redirector FSD. // if ( dwResponseBufferLen != 0 && pbRawResponse != NULL ) { Rsp = ( PNDS_RESPONSE_RESOLVE_NAME ) pbRawResponse; dwRspBufferLen = dwResponseBufferLen; } else { Rsp = ( PNDS_RESPONSE_RESOLVE_NAME ) RspData; dwRspBufferLen = 256; } try { ntstatus = NtFsControlFile( hNdsTree, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_NDS_RESOLVE_NAME, (PVOID) Rrp, sizeof( NWR_NDS_REQUEST_PACKET ) + Rrp->Parameters.ResolveName.ObjectNameLength, (PVOID) Rsp, dwRspBufferLen ); } except ( EXCEPTION_EXECUTE_HANDLER ) { return GetExceptionCode(); } // // Dig out the object id and referred server. // if ( NT_SUCCESS( ntstatus ) ) { try { *dwObjectId = Rsp->EntryId; if ( Rsp->ServerNameLength > puReferredServer->MaximumLength ) { ntstatus = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory( puReferredServer->Buffer, Rsp->ReferredServer, Rsp->ServerNameLength ); puReferredServer->Length = (USHORT)Rsp->ServerNameLength; } } except ( EXCEPTION_EXECUTE_HANDLER ) { return ntstatus; } } return ntstatus; } int _cdecl FormatBuf( char *buf, int bufLen, const char *format, va_list args ); int _cdecl CalculateBuf( const char *format, va_list args ); NTSTATUS _cdecl FragExWithWait( IN HANDLE hNdsServer, IN DWORD NdsVerb, IN BYTE *pReplyBuffer, IN DWORD pReplyBufferLen, IN OUT DWORD *pdwReplyLen, IN BYTE *NdsRequestStr, ... ) /* Routine Description: Exchanges an NDS request in fragments and collects the fragments of the response and writes them to the reply buffer. Routine Arguments: hNdsServer - A handle to the server you want to talk to. NdsVerb - The verb for that indicates the request. pReplyBuffer - The reply buffer. pReplyBufferLen - The length of the reply buffer. NdsReqestStr - The format string for the arguments to this NDS request. Arguments - The arguments that satisfy the NDS format string. Return Value: NTSTATUS - Status of the exchange, but not the result code in the packet. */ { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; PNWR_NDS_REQUEST_PACKET RawRequest = NULL; BYTE *NdsRequestBuf; DWORD NdsRequestLen; int bufferSize = 0; va_list Arguments; // // Allocate a request buffer. // // // Calculate needed buffer size . . . // if ( NdsRequestStr != NULL ) { va_start( Arguments, NdsRequestStr ); bufferSize = CalculateBuf( NdsRequestStr, Arguments ); va_end( Arguments ); if ( bufferSize == 0 ) { Status = STATUS_INVALID_PARAMETER; goto ExitWithCleanup; } } bufferSize += sizeof( NWR_NDS_REQUEST_PACKET ) + 50; RawRequest = LocalAlloc( LMEM_ZEROINIT, bufferSize ); if ( !RawRequest ) { return STATUS_INSUFFICIENT_RESOURCES; } // // Build the request in our local buffer. The first DWORD // is the verb and the rest is the formatted request. // RawRequest->Parameters.RawRequest.NdsVerb = NdsVerb; NdsRequestBuf = &RawRequest->Parameters.RawRequest.Request[0]; if ( NdsRequestStr != NULL ) { va_start( Arguments, NdsRequestStr ); NdsRequestLen = FormatBuf( NdsRequestBuf, bufferSize - sizeof( NWR_NDS_REQUEST_PACKET ), NdsRequestStr, Arguments ); if ( !NdsRequestLen ) { Status = STATUS_INVALID_PARAMETER; goto ExitWithCleanup; } va_end( Arguments ); } else { NdsRequestLen = 0; } RawRequest->Parameters.RawRequest.RequestLength = NdsRequestLen; // // Pass this buffer to kernel mode via FSCTL. // try { Status = NtFsControlFile( hNdsServer, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_NDS_RAW_FRAGEX, (PVOID) RawRequest, NdsRequestLen + sizeof( NWR_NDS_REQUEST_PACKET ), (PVOID) pReplyBuffer, pReplyBufferLen ); if ( NT_SUCCESS( Status ) ) { *pdwReplyLen = RawRequest->Parameters.RawRequest.ReplyLength; } } except ( EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); } ExitWithCleanup: if ( RawRequest ) { LocalFree( RawRequest ); } return Status; }