summaryrefslogtreecommitdiffstats
path: root/private/nw/nwlib/ndsapi32.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/nwlib/ndsapi32.c')
-rw-r--r--private/nw/nwlib/ndsapi32.c2144
1 files changed, 2144 insertions, 0 deletions
diff --git a/private/nw/nwlib/ndsapi32.c b/private/nw/nwlib/ndsapi32.c
new file mode 100644
index 000000000..9efe22830
--- /dev/null
+++ b/private/nw/nwlib/ndsapi32.c
@@ -0,0 +1,2144 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ NdsLib32.c
+
+Abstract:
+
+ This module implements the 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 <procs.h>
+
+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 );
+
+ 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 = ( 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) + sizeof( UNICODE_STRING ),
+ puNdsTree->Buffer,
+ puNdsTree->Length );
+
+ try {
+
+ ntstatus = NtFsControlFile( *phNwRdrHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_VERIFY_TREE,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ 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
+NwNdsOpenGenericHandle(
+ IN PUNICODE_STRING puNdsTree,
+ OUT LPDWORD lpdwHandleType,
+ 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 );
+
+ 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 = ( 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) + sizeof( UNICODE_STRING ),
+ puNdsTree->Buffer,
+ puNdsTree->Length );
+
+ try {
+
+ ntstatus = NtFsControlFile( *phNwRdrHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_VERIFY_TREE,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ 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( *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 );
+
+ 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 = ( 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 ),
+ 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
+NwNdsSetTreeContext (
+ IN HANDLE hNdsRdr,
+ IN PUNICODE_STRING puTree,
+ IN PUNICODE_STRING puContext
+)
+/*+++
+
+ This sets the current context in the requested tree.
+
+---*/
+{
+
+ NTSTATUS ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+ DWORD RrpSize;
+ BYTE *CurrentString;
+
+ //
+ // Set up the request.
+ //
+
+ RrpSize = sizeof( NWR_NDS_REQUEST_PACKET ) +
+ puTree->Length +
+ puContext->Length;
+
+ Rrp = LocalAlloc( LMEM_ZEROINIT, RrpSize );
+
+ if ( !Rrp ) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ try {
+
+ (Rrp->Parameters).SetContext.TreeNameLen = puTree->Length;
+ (Rrp->Parameters).SetContext.ContextLen = puContext->Length;
+
+ CurrentString = (BYTE *)(Rrp->Parameters).SetContext.TreeAndContextString;
+
+ RtlCopyMemory( CurrentString, puTree->Buffer, puTree->Length );
+ CurrentString += puTree->Length;
+ RtlCopyMemory( CurrentString, puContext->Buffer, puContext->Length );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ ntstatus = STATUS_INVALID_PARAMETER;
+ goto ExitWithCleanup;
+ }
+
+ try {
+
+ ntstatus = NtFsControlFile( hNdsRdr,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_SETCONTEXT,
+ (PVOID) Rrp,
+ RrpSize,
+ NULL,
+ 0 );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ ntstatus = GetExceptionCode();
+ goto ExitWithCleanup;
+ }
+
+ExitWithCleanup:
+
+ LocalFree( Rrp );
+ 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;
+}
+
+NTSTATUS
+NwNdsResolveName (
+ IN HANDLE hNdsTree,
+ IN PUNICODE_STRING puObjectName,
+ OUT DWORD *dwObjectId,
+ OUT PUNICODE_STRING puReferredServer,
+ OUT PBYTE pbRawResponse,
+ IN DWORD dwResponseBufferLen
+) {
+
+ //
+ // BUGBUG: Do I want or need to expose the flags parameter?
+ //
+
+ 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 );
+
+ 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 ),
+ (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;
+
+}
+
+NTSTATUS
+NwNdsList (
+ IN HANDLE hNdsTree,
+ IN DWORD dwObjectId,
+ OUT DWORD *dwIterHandle,
+ OUT BYTE *pbReplyBuf,
+ IN DWORD dwReplyBufLen
+) {
+
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+
+ PNDS_RESPONSE_SUBORDINATE_LIST Rsp;
+ DWORD dwRspBufferLen;
+
+ BYTE RrpData[256];
+ BYTE RspData[1024];
+
+ //
+ // BUGBUG: I should make the reply buffer small and start testing
+ // fragment assembly stuff.
+ //
+
+ Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData;
+
+ Rrp->Parameters.ListSubordinates.ObjectId = dwObjectId;
+ Rrp->Parameters.ListSubordinates.IterHandle = *dwIterHandle;
+
+ if ( dwReplyBufLen != 0 &&
+ pbReplyBuf != NULL ) {
+
+ Rsp = ( PNDS_RESPONSE_SUBORDINATE_LIST ) pbReplyBuf;
+ dwRspBufferLen = dwReplyBufLen;
+
+ } else {
+
+ Rsp = ( PNDS_RESPONSE_SUBORDINATE_LIST ) RspData;
+ dwRspBufferLen = 1024;
+
+ }
+
+ try {
+
+ Status = NtFsControlFile( hNdsTree,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_LIST_SUBS,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ (PVOID) Rsp,
+ dwRspBufferLen );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return GetExceptionCode();
+ }
+
+ return Status;
+
+}
+
+NTSTATUS
+NwNdsReadObjectInfo(
+ IN HANDLE hNdsTree,
+ IN DWORD dwObjectId,
+ OUT BYTE *pbRawReply,
+ IN DWORD dwReplyBufLen
+)
+{
+
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+
+ PNDS_RESPONSE_GET_OBJECT_INFO Rsp;
+ DWORD dwRspBufferLen;
+
+ BYTE RrpData[256];
+ BYTE RspData[1024];
+
+ Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData;
+
+ Rrp->Parameters.GetObjectInfo.ObjectId = dwObjectId;
+
+ if ( dwReplyBufLen != 0 &&
+ pbRawReply != NULL ) {
+
+ Rsp = ( PNDS_RESPONSE_GET_OBJECT_INFO ) pbRawReply;
+ dwRspBufferLen = dwReplyBufLen;
+
+ } else {
+
+ Rsp = ( PNDS_RESPONSE_GET_OBJECT_INFO ) RspData;
+ dwRspBufferLen = 1024;
+
+ }
+
+ try {
+
+ Status = NtFsControlFile( hNdsTree,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_READ_INFO,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ (PVOID) Rsp,
+ dwRspBufferLen );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return GetExceptionCode();
+ }
+
+ return Status;
+
+}
+
+NTSTATUS
+NwNdsReadAttribute (
+ IN HANDLE hNdsTree,
+ IN DWORD dwObjectId,
+ IN DWORD *dwIterHandle,
+ IN PUNICODE_STRING puAttrName,
+ OUT BYTE *pbReplyBuf,
+ IN DWORD dwReplyBufLen
+) {
+
+ NTSTATUS ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+ PNDS_RESPONSE_READ_ATTRIBUTE Rsp;
+
+ DWORD dwAttributeNameLen;
+
+ BYTE RrpData[1024];
+
+ //
+ // Check the incoming buffer.
+ //
+ if ( !dwReplyBufLen ||
+ !pbReplyBuf ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Set up the request.
+ //
+
+ Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData;
+ RtlZeroMemory( Rrp, 1024 );
+
+ (Rrp->Parameters).ReadAttribute.ObjectId = dwObjectId;
+ (Rrp->Parameters).ReadAttribute.IterHandle = *dwIterHandle;
+
+ //
+ // Nds strings are NULL terminated; watch the size.
+ //
+
+ dwAttributeNameLen = puAttrName->Length + sizeof( WCHAR );
+
+ (Rrp->Parameters).ReadAttribute.AttributeNameLength = dwAttributeNameLen;
+
+ try {
+
+ //
+ // But don't try to copy more than the user gave us.
+ //
+
+ memcpy( (Rrp->Parameters).ReadAttribute.AttributeName,
+ puAttrName->Buffer,
+ puAttrName->Length );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Send the request to the Redirector FSD.
+ //
+
+ try {
+
+ ntstatus = NtFsControlFile( hNdsTree,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_READ_ATTR,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ (PVOID) pbReplyBuf,
+ dwReplyBufLen );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return GetExceptionCode();
+ }
+
+ //
+ // There's no buffer post processing on this one.
+ //
+
+ return ntstatus;
+
+}
+
+NTSTATUS
+NwNdsOpenStream (
+ IN HANDLE hNdsTree,
+ IN DWORD dwObjectId,
+ IN PUNICODE_STRING puStreamName,
+ IN DWORD dwOpenFlags,
+ OUT DWORD *pdwFileLength
+) {
+
+ NTSTATUS ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+ BYTE RrpData[1024];
+
+ //
+ // Set up the request.
+ //
+
+ Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData;
+ RtlZeroMemory( Rrp, 1024 );
+
+ (Rrp->Parameters).OpenStream.StreamAccess = dwOpenFlags;
+ (Rrp->Parameters).OpenStream.ObjectOid = dwObjectId;
+
+ (Rrp->Parameters).OpenStream.StreamName.Length = puStreamName->Length;
+ (Rrp->Parameters).OpenStream.StreamName.MaximumLength =
+ sizeof( RrpData ) - sizeof( (Rrp->Parameters).OpenStream );
+ (Rrp->Parameters).OpenStream.StreamName.Buffer =
+ (Rrp->Parameters).OpenStream.StreamNameString;
+
+ //
+ // Make sure we're not trashing memory.
+ //
+
+ if ( (Rrp->Parameters).OpenStream.StreamName.Length >
+ (Rrp->Parameters).OpenStream.StreamName.MaximumLength ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ try {
+
+ //
+ // But don't try to copy more than the user gave us.
+ //
+
+ memcpy( (Rrp->Parameters).OpenStream.StreamNameString,
+ puStreamName->Buffer,
+ puStreamName->Length );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Send the request to the Redirector FSD.
+ //
+
+ try {
+
+ ntstatus = NtFsControlFile( hNdsTree,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_OPEN_STREAM,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ NULL,
+ 0 );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return GetExceptionCode();
+ }
+
+ if ( pdwFileLength ) {
+ *pdwFileLength = (Rrp->Parameters).OpenStream.FileLength;
+ }
+
+ return ntstatus;
+}
+
+NTSTATUS
+NwNdsGetQueueInformation(
+ IN HANDLE hNdsTree,
+ IN PUNICODE_STRING puQueueName,
+ OUT PUNICODE_STRING puHostServer,
+ OUT PDWORD pdwQueueId
+) {
+
+ NTSTATUS ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+ BYTE RrpData[1024];
+
+ //
+ // Set up the request.
+ //
+
+ Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData;
+ RtlZeroMemory( Rrp, sizeof( RrpData ) );
+
+ if ( puQueueName ) {
+ (Rrp->Parameters).GetQueueInfo.QueueName.Length = puQueueName->Length;
+ (Rrp->Parameters).GetQueueInfo.QueueName.MaximumLength = puQueueName->MaximumLength;
+ (Rrp->Parameters).GetQueueInfo.QueueName.Buffer = puQueueName->Buffer;
+ }
+
+ if ( puHostServer ) {
+ (Rrp->Parameters).GetQueueInfo.HostServer.Length = 0;
+ (Rrp->Parameters).GetQueueInfo.HostServer.MaximumLength = puHostServer->MaximumLength;
+ (Rrp->Parameters).GetQueueInfo.HostServer.Buffer = puHostServer->Buffer;
+ }
+
+ //
+ // Send the request to the Redirector FSD.
+ //
+
+ try {
+
+ ntstatus = NtFsControlFile( hNdsTree,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_GET_QUEUE_INFO,
+ (PVOID) Rrp,
+ sizeof( NWR_NDS_REQUEST_PACKET ),
+ NULL,
+ 0 );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return GetExceptionCode();
+ }
+
+ if ( NT_SUCCESS( ntstatus ) ) {
+
+ if ( pdwQueueId ) {
+ *pdwQueueId = (Rrp->Parameters).GetQueueInfo.QueueId;
+ }
+
+ puHostServer->Length = (Rrp->Parameters).GetQueueInfo.HostServer.Length;
+
+ }
+
+ return ntstatus;
+}
+
+NTSTATUS
+NwNdsGetVolumeInformation(
+ IN HANDLE hNdsTree,
+ IN PUNICODE_STRING puVolumeName,
+ OUT PUNICODE_STRING puHostServer,
+ OUT PUNICODE_STRING puHostVolume
+) {
+
+ NTSTATUS ntstatus;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ PNWR_NDS_REQUEST_PACKET Rrp;
+ DWORD RequestSize;
+ BYTE RrpData[1024];
+ BYTE ReplyData[1024];
+ PBYTE NameStr;
+
+ //
+ // Set up the request.
+ //
+
+ Rrp = (PNWR_NDS_REQUEST_PACKET) RrpData;
+ RtlZeroMemory( Rrp, sizeof( RrpData ) );
+
+ if ( !puVolumeName ||
+ puVolumeName->Length > MAX_NDS_NAME_SIZE ||
+ !puHostServer ||
+ !puHostVolume ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ try {
+
+ (Rrp->Parameters).GetVolumeInfo.VolumeNameLen = puVolumeName->Length;
+ RtlCopyMemory( &((Rrp->Parameters).GetVolumeInfo.VolumeName[0]),
+ puVolumeName->Buffer,
+ puVolumeName->Length );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Send the request to the Redirector FSD.
+ //
+
+ RequestSize = sizeof( NWR_NDS_REQUEST_PACKET ) +
+ (Rrp->Parameters).GetVolumeInfo.VolumeNameLen;
+
+ try {
+
+ ntstatus = NtFsControlFile( hNdsTree,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_GET_VOLUME_INFO,
+ (PVOID) Rrp,
+ RequestSize,
+ ReplyData,
+ sizeof( ReplyData ) );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return GetExceptionCode();
+ }
+
+ if ( NT_SUCCESS( ntstatus ) ) {
+
+ try {
+
+ if ( ( puHostServer->MaximumLength < (Rrp->Parameters).GetVolumeInfo.ServerNameLen ) ||
+ ( puHostVolume->MaximumLength < (Rrp->Parameters).GetVolumeInfo.TargetVolNameLen ) ) {
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ puHostServer->Length = (USHORT)(Rrp->Parameters).GetVolumeInfo.ServerNameLen;
+ puHostVolume->Length = (USHORT)(Rrp->Parameters).GetVolumeInfo.TargetVolNameLen;
+
+ NameStr = &ReplyData[0];
+
+ RtlCopyMemory( puHostServer->Buffer, NameStr, puHostServer->Length );
+ NameStr += puHostServer->Length;
+ RtlCopyMemory( puHostVolume->Buffer, NameStr, puHostVolume->Length );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ }
+
+ return ntstatus;
+
+}
+
+//
+// User mode fragment exchange.
+//
+
+int
+_cdecl
+FormatBuf(
+ char *buf,
+ int bufLen,
+ 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;
+
+ BYTE *NdsRequestBuf;
+ DWORD NdsRequestLen;
+
+ va_list Arguments;
+
+ //
+ // Allocate a request buffer.
+ //
+
+ RawRequest = LocalAlloc( LMEM_ZEROINIT, NDS_BUFFER_SIZE );
+
+ 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,
+ NDS_BUFFER_SIZE - 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;
+
+}
+
+int
+_cdecl
+FormatBuf(
+ char *buf,
+ int bufLen,
+ const char *format,
+ va_list args
+)
+/*
+
+Routine Description:
+
+ Formats a buffer according to supplied the format string.
+
+ FormatString - Supplies an ANSI string which describes how to
+ convert from the input arguments into NCP request fields, and
+ from the NCP response fields into the output arguments.
+
+ Field types, request/response:
+
+ 'b' byte ( byte / byte* )
+ 'w' hi-lo word ( word / word* )
+ 'd' hi-lo dword ( dword / dword* )
+ 'W' lo-hi word ( word / word*)
+ 'D' lo-hi dword ( dword / dword*)
+ '-' zero/skip byte ( void )
+ '=' zero/skip word ( void )
+ ._. zero/skip string ( word )
+ 'p' pstring ( char* )
+ 'c' cstring ( char* )
+ 'C' cstring followed skip word ( char*, word )
+ 'V' sized NDS value ( byte *, dword / byte **, dword *)
+ 'S' p unicode string copy as NDS_STRING (UNICODE_STRING *)
+ 's' cstring copy as NDS_STRING (char* / char *, word)
+ 'r' raw bytes ( byte*, word )
+ 'u' p unicode string ( UNICODE_STRING * )
+ 'U' p uppercase string( UNICODE_STRING * )
+
+Routine Arguments:
+
+ char *buf - destination buffer.
+ int buflen - length of the destination buffer.
+ char *format - format string.
+ args - args to the format string.
+
+Implementation Notes:
+
+ This comes verbatim from kernel mode.
+
+*/
+{
+ ULONG ix;
+
+ NTSTATUS status;
+ const char *z = format;
+
+ //
+ // Convert the input arguments into request packet.
+ //
+
+ ix = 0;
+
+ while ( *z )
+ {
+ switch ( *z )
+ {
+ case '=':
+ buf[ix++] = 0;
+ case '-':
+ buf[ix++] = 0;
+ break;
+
+ case '_':
+ {
+ WORD l = va_arg ( args, WORD );
+ if (ix + (ULONG)l > (ULONG)bufLen)
+ {
+ goto ErrorExit;
+ }
+ while ( l-- )
+ buf[ix++] = 0;
+ break;
+ }
+
+ case 'b':
+ buf[ix++] = va_arg ( args, BYTE );
+ break;
+
+ case 'w':
+ {
+ WORD w = va_arg ( args, WORD );
+ buf[ix++] = (BYTE) (w >> 8);
+ buf[ix++] = (BYTE) (w >> 0);
+ break;
+ }
+
+ case 'd':
+ {
+ DWORD d = va_arg ( args, DWORD );
+ buf[ix++] = (BYTE) (d >> 24);
+ buf[ix++] = (BYTE) (d >> 16);
+ buf[ix++] = (BYTE) (d >> 8);
+ buf[ix++] = (BYTE) (d >> 0);
+ break;
+ }
+
+ case 'W':
+ {
+ WORD w = va_arg(args, WORD);
+ (* (WORD *)&buf[ix]) = w;
+ ix += 2;
+ break;
+ }
+
+ case 'D':
+ {
+ DWORD d = va_arg (args, DWORD);
+ (* (DWORD *)&buf[ix]) = d;
+ ix += 4;
+ break;
+ }
+
+ case 'c':
+ {
+ char* c = va_arg ( args, char* );
+ WORD l = strlen( c );
+ if (ix + (ULONG)l > (ULONG)bufLen)
+ {
+ goto ErrorExit;
+ }
+ RtlCopyMemory( &buf[ix], c, l+1 );
+ ix += l + 1;
+ break;
+ }
+
+ case 'C':
+ {
+ char* c = va_arg ( args, char* );
+ WORD l = va_arg ( args, WORD );
+ WORD len = strlen( c ) + 1;
+ if (ix + (ULONG)l > (ULONG)bufLen)
+ {
+ goto ErrorExit;
+ }
+
+ RtlCopyMemory( &buf[ix], c, len > l? l : len);
+ ix += l;
+ buf[ix-1] = 0;
+ break;
+ }
+
+ case 'p':
+ {
+ char* c = va_arg ( args, char* );
+ BYTE l = strlen( c );
+ if (ix + (ULONG)l +1 > (ULONG)bufLen)
+ {
+ goto ErrorExit;
+ }
+ buf[ix++] = l;
+ RtlCopyMemory( &buf[ix], c, l );
+ ix += l;
+ break;
+ }
+
+ case 'u':
+ {
+ PUNICODE_STRING pUString = va_arg ( args, PUNICODE_STRING );
+ OEM_STRING OemString;
+ ULONG Length;
+
+ //
+ // Calculate required string length, excluding trailing NUL.
+ //
+
+ Length = RtlUnicodeStringToOemSize( pUString ) - 1;
+ ASSERT( Length < 0x100 );
+
+ if ( ix + Length > (ULONG)bufLen ) {
+ goto ErrorExit;
+ }
+
+ buf[ix++] = (UCHAR)Length;
+ OemString.Buffer = &buf[ix];
+ OemString.MaximumLength = (USHORT)Length + 1;
+
+ status = RtlUnicodeStringToOemString( &OemString, pUString, FALSE );
+ ASSERT( NT_SUCCESS( status ));
+ ix += (USHORT)Length;
+ break;
+ }
+
+ case 'S':
+ {
+ PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING);
+ ULONG Length, rLength;
+
+ Length = pUString->Length;
+ if (ix + Length + sizeof(Length) + sizeof( WCHAR ) > (ULONG)bufLen) {
+ goto ErrorExit;
+ }
+
+ //
+ // The VLM client uses the rounded up length and it seems to
+ // make a difference! Also, don't forget that NDS strings have
+ // to be NULL terminated.
+ //
+
+ rLength = ROUNDUP4(Length + sizeof( WCHAR ));
+ *((DWORD *)&buf[ix]) = rLength;
+ ix += 4;
+ RtlCopyMemory(&buf[ix], pUString->Buffer, Length);
+ ix += Length;
+ rLength -= Length;
+ RtlFillMemory( &buf[ix], rLength, '\0' );
+ ix += rLength;
+ break;
+
+ }
+
+ case 's':
+ {
+ PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING);
+ ULONG Length, rLength;
+
+ Length = pUString->Length;
+ if (ix + Length + sizeof(Length) + sizeof( WCHAR ) > (ULONG)bufLen) {
+ // DebugTrace( 0, Dbg, "FormatBuf: case 's' request buffer too small.\n", 0 );
+ goto ErrorExit;
+ }
+
+ //
+ // Don't use the padded size here, only the NDS null terminator.
+ //
+
+ rLength = Length + sizeof( WCHAR );
+ *((DWORD *)&buf[ix]) = rLength;
+ ix += 4;
+ RtlCopyMemory(&buf[ix], pUString->Buffer, Length);
+ ix += Length;
+ rLength -= Length;
+ RtlFillMemory( &buf[ix], rLength, '\0' );
+ ix += rLength;
+ break;
+
+
+ }
+
+ case 'V':
+ {
+ // too similar to 'S' - should be combined
+ BYTE* b = va_arg ( args, BYTE* );
+ DWORD l = va_arg ( args, DWORD );
+ if ( ix + l + sizeof(DWORD) > (ULONG)
+ bufLen )
+ {
+ goto ErrorExit;
+ }
+ *((DWORD *)&buf[ix]) = l;
+ ix += sizeof(DWORD);
+ RtlCopyMemory( &buf[ix], b, l );
+ l = ROUNDUP4(l);
+ ix += l;
+ break;
+ }
+
+ case 'r':
+ {
+ BYTE* b = va_arg ( args, BYTE* );
+ WORD l = va_arg ( args, WORD );
+ if ( b == NULL || l == 0 )
+ {
+ break;
+ }
+ if ( ix + l > (ULONG)bufLen )
+ {
+ goto ErrorExit;
+ }
+ RtlCopyMemory( &buf[ix], b, l );
+ ix += l;
+ break;
+ }
+
+ default:
+
+ ;
+
+ }
+
+ if ( ix > (ULONG)bufLen )
+ {
+ goto ErrorExit;
+ }
+
+
+ z++;
+ }
+
+ return(ix);
+
+ErrorExit:
+ return 0;
+}
+
+NTSTATUS
+_cdecl
+ParseResponse(
+ PUCHAR Response,
+ ULONG ResponseLength,
+ char* FormatString,
+ ... // format specific parameters
+ )
+/*++
+
+Routine Description:
+
+ This routine parse an NCP response.
+
+ Packet types:
+
+ 'G' Generic packet ( )
+
+ Field types, request/response:
+
+ 'b' byte ( byte* )
+ 'w' hi-lo word ( word* )
+ 'x' ordered word ( word* )
+ 'd' hi-lo dword ( dword* )
+ 'e' ordered dword ( dword* )
+ '-' zero/skip byte ( void )
+ '=' zero/skip word ( void )
+ ._. zero/skip string ( word )
+ 'p' pstring ( char* )
+ 'c' cstring ( char* )
+ 'r' raw bytes ( byte*, word )
+
+ Added 3/29/95 by CoryWest:
+
+ 'W' lo-hi word ( word / word*)
+ 'D' lo-hi dword ( dword / dword*)
+ 'S' unicode string copy as NDS_STRING (UNICODE_STRING *)
+ 'T' terminal unicode string copy as NDS_STRING (UNICODE_STRING *)
+
+ 't' terminal unicode string with the nds null copied
+ as NDS_STRING (UNICODE_STRING *) (for GetUseName)
+
+Return Value:
+
+ STATUS - Success or failure, depending on the response.
+
+--*/
+
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PCHAR FormatByte;
+ va_list Arguments;
+ ULONG Length = 0;
+
+ va_start( Arguments, FormatString );
+
+ //
+ // User mode parse response handles only generic packets.
+ //
+
+ if ( *FormatString != 'G' ) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ FormatByte = FormatString + 1;
+ while ( *FormatByte ) {
+
+ switch ( *FormatByte ) {
+
+ case '-':
+ Length += 1;
+ break;
+
+ case '=':
+ Length += 2;
+ break;
+
+ case '_':
+ {
+ WORD l = va_arg ( Arguments, WORD );
+ Length += l;
+ break;
+ }
+
+ case 'b':
+ {
+ BYTE* b = va_arg ( Arguments, BYTE* );
+ *b = Response[Length++];
+ break;
+ }
+
+ case 'w':
+ {
+ BYTE* b = va_arg ( Arguments, BYTE* );
+ b[1] = Response[Length++];
+ b[0] = Response[Length++];
+ break;
+ }
+
+ case 'x':
+ {
+ WORD* w = va_arg ( Arguments, WORD* );
+ *w = *(WORD UNALIGNED *)&Response[Length];
+ Length += 2;
+ break;
+ }
+
+ case 'd':
+ {
+ BYTE* b = va_arg ( Arguments, BYTE* );
+ b[3] = Response[Length++];
+ b[2] = Response[Length++];
+ b[1] = Response[Length++];
+ b[0] = Response[Length++];
+ break;
+ }
+
+ case 'e':
+ {
+ DWORD UNALIGNED * d = va_arg ( Arguments, DWORD* );
+ *d = *(DWORD UNALIGNED *)&Response[Length];
+ Length += 4;
+ break;
+ }
+
+ case 'c':
+ {
+ char* c = va_arg ( Arguments, char* );
+ WORD l = strlen( &Response[Length] );
+ memcpy ( c, &Response[Length], l+1 );
+ Length += l+1;
+ break;
+ }
+
+ case 'p':
+ {
+ char* c = va_arg ( Arguments, char* );
+ BYTE l = Response[Length++];
+ memcpy ( c, &Response[Length], l );
+ c[l+1] = 0;
+ break;
+ }
+
+ case 'r':
+ {
+ BYTE* b = va_arg ( Arguments, BYTE* );
+ WORD l = va_arg ( Arguments, WORD );
+ RtlCopyMemory( b, &Response[Length], l );
+ Length += l;
+ break;
+ }
+
+ case 'W':
+ {
+
+ WORD *w = va_arg ( Arguments, WORD* );
+ *w = (* (WORD *)&Response[Length]);
+ Length += 2;
+ break;
+
+ }
+
+ case 'D':
+ {
+
+ DWORD *d = va_arg ( Arguments, DWORD* );
+ *d = (* (DWORD *)&Response[Length]);
+ Length += 4;
+ break;
+
+ }
+
+ case 'S':
+ {
+
+ PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
+ USHORT strl;
+
+ if (pU) {
+
+ strl = (USHORT)(* (DWORD *)&Response[Length]);
+
+ //
+ // Don't count the null terminator that is part of
+ // Novell's counted unicode string.
+ //
+
+ pU->Length = strl - sizeof( WCHAR );
+ Length += 4;
+ RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
+ Length += ROUNDUP4(strl);
+
+ } else {
+
+ //
+ // Skip over the string since we don't want it.
+ //
+
+ Length += ROUNDUP4((* (DWORD *)&Response[Length] ));
+ Length += 4;
+ }
+
+
+ break;
+
+ }
+
+ case 's':
+ {
+
+ PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
+ USHORT strl;
+
+ if (pU) {
+
+ strl = (USHORT)(* (DWORD *)&Response[Length]);
+ pU->Length = strl;
+ Length += 4;
+ RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
+ Length += ROUNDUP4(strl);
+
+ } else {
+
+ //
+ // Skip over the string since we don't want it.
+ //
+
+ Length += ROUNDUP4((* (DWORD *)&Response[Length] ));
+ Length += 4;
+ }
+
+
+ break;
+
+ }
+
+ case 'T':
+ {
+
+ PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
+ USHORT strl;
+
+ if (pU) {
+
+ strl = (USHORT)(* (DWORD *)&Response[Length] );
+ strl -= sizeof( WCHAR ); // Don't count the NULL from NDS.
+
+ if ( strl <= pU->MaximumLength ) {
+
+ pU->Length = strl;
+ Length += 4;
+ RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
+
+ //
+ // No need to advance the pointers since this is
+ // specifically a termination case!
+ //
+
+ } else {
+
+ pU->Length = 0;
+ }
+
+ }
+
+ break;
+
+ }
+
+ case 't':
+ {
+
+ PUNICODE_STRING pU = va_arg( Arguments, PUNICODE_STRING );
+ USHORT strl;
+
+ if (pU) {
+
+ strl = (USHORT)(* (DWORD *)&Response[Length] );
+
+ if ( strl <= pU->MaximumLength ) {
+
+ pU->Length = strl;
+ Length += 4;
+ RtlCopyMemory( pU->Buffer, &Response[Length], pU->Length );
+
+ //
+ // No need to advance the pointers since this is
+ // specifically a termination case!
+ //
+
+ } else {
+
+ pU->Length = 0;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ if ( Length > ResponseLength ) {
+ return( STATUS_INVALID_PARAMETER );
+ }
+
+ FormatByte++;
+
+ }
+
+ va_end( Arguments );
+ return( Status );
+
+}
+
+NTSTATUS
+NwNdsChangePassword(
+ IN HANDLE hNwRdr,
+ IN PUNICODE_STRING puTreeName,
+ IN PUNICODE_STRING puUserName,
+ IN PUNICODE_STRING puCurrentPassword,
+ IN PUNICODE_STRING puNewPassword
+) {
+
+ NTSTATUS Status;
+ PNWR_NDS_REQUEST_PACKET pNdsRequest;
+ DWORD dwRequestLength;
+ PBYTE CurrentString;
+ IO_STATUS_BLOCK IoStatusBlock;
+
+ //
+ // Allocate the request.
+ //
+
+ dwRequestLength = sizeof( NWR_NDS_REQUEST_PACKET ) +
+ puTreeName->Length +
+ puUserName->Length +
+ puCurrentPassword->Length +
+ puNewPassword->Length;
+
+ pNdsRequest = LocalAlloc( LMEM_ZEROINIT, dwRequestLength );
+
+ if ( !pNdsRequest) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Copy the parameters into the request buffer.
+ //
+
+ try {
+
+ (pNdsRequest->Parameters).ChangePass.NdsTreeNameLength =
+ puTreeName->Length;
+ (pNdsRequest->Parameters).ChangePass.UserNameLength =
+ puUserName->Length;
+ (pNdsRequest->Parameters).ChangePass.CurrentPasswordLength =
+ puCurrentPassword->Length;
+ (pNdsRequest->Parameters).ChangePass.NewPasswordLength =
+ puNewPassword->Length;
+
+ CurrentString = ( PBYTE ) &((pNdsRequest->Parameters).ChangePass.StringBuffer[0]);
+ RtlCopyMemory( CurrentString, puTreeName->Buffer, puTreeName->Length );
+
+ CurrentString += puTreeName->Length;
+ RtlCopyMemory( CurrentString, puUserName->Buffer, puUserName->Length );
+
+ CurrentString += puUserName->Length;
+ RtlCopyMemory( CurrentString, puCurrentPassword->Buffer, puCurrentPassword->Length );
+
+ CurrentString += puCurrentPassword->Length;
+ RtlCopyMemory( CurrentString, puNewPassword->Buffer, puNewPassword->Length );
+
+ Status = NtFsControlFile( hNwRdr,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ FSCTL_NWR_NDS_CHANGE_PASS,
+ (PVOID) pNdsRequest,
+ dwRequestLength,
+ NULL,
+ 0 );
+
+ } except ( EXCEPTION_EXECUTE_HANDLER ) {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ LocalFree( pNdsRequest );
+ return Status;
+
+}
+
+