|
|
/*++
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>
//#include <nwapilyr.h>
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 = (USHORT)(( i * sizeof( WCHAR ) ) + ( PreambleLength * sizeof( WCHAR ) )); uOpenName.Buffer = NameStr;
//
// Set up the object attributes.
//
InitializeObjectAttributes( &ObjectAttributes, &uOpenName, OBJ_CASE_INSENSITIVE, NULL, NULL );
//
// Make the compiler happy about variable initialization.
//
RtlZeroMemory( &IoStatusBlock, sizeof( IO_STATUS_BLOCK ) );
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 ) + puNdsTree->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( *phNwRdrHandle ); *phNwRdrHandle = 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 NwNdsIsNdsConnection ( IN HANDLE hNdsRdr, OUT BOOL * pfIsNds, OUT PUNICODE_STRING puTree ) /*+++
This tests the current connection handle to see if it is one that is connected to a server in an NDS tree. If so, the name of the tree is put into puTree.
---*/ { NTSTATUS ntstatus; IO_STATUS_BLOCK IoStatusBlock; PCONN_DETAILS2 Rrp; DWORD RrpSize;
*pfIsNds = FALSE;
//
// Set up the request.
//
RrpSize = sizeof( CONN_DETAILS2 );
Rrp = LocalAlloc( LMEM_ZEROINIT, RrpSize );
if ( !Rrp ) return STATUS_INSUFFICIENT_RESOURCES;
try { ntstatus = NtFsControlFile( hNdsRdr, NULL, NULL, NULL, &IoStatusBlock, FSCTL_NWR_GET_CONN_DETAILS2, NULL, 0, (PVOID) Rrp, RrpSize );
} except ( EXCEPTION_EXECUTE_HANDLER ) { ntstatus = GetExceptionCode(); goto ExitWithCleanup; }
if ( ntstatus == STATUS_SUCCESS ) { if ( Rrp->fNds ) { puTree->Length = (USHORT) wcslen( Rrp->NdsTreeName );
if ( puTree->MaximumLength >= puTree->Length ) wcscpy( puTree->Buffer, Rrp->NdsTreeName ); else puTree->Length = 0;
*pfIsNds = TRUE; } }
ExitWithCleanup:
LocalFree( Rrp ); 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];
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(); }
if ( Status == STATUS_SUCCESS ) { *dwIterHandle = Rsp->IterationHandle; }
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 = ( PNDS_RESPONSE_READ_ATTRIBUTE ) pbReplyBuf;
DWORD dwAttributeNameLen;
BYTE RrpData[1024];
//
// Check the incoming buffer.
//
if ( !dwReplyBufLen || !Rsp ) { 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 ) + dwAttributeNameLen, (PVOID) Rsp, dwReplyBufLen );
} except ( EXCEPTION_EXECUTE_HANDLER ) {
return GetExceptionCode(); }
if ( ntstatus == STATUS_SUCCESS ) { *dwIterHandle = Rsp->IterationHandle; }
//
// 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 ) + puStreamName->Length, 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 );
int _cdecl CalculateBuf( const char *format, va_list args );
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 = (WORD)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 = (BYTE)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; }
int _cdecl CalculateBuf( const char *format, va_list args ) /*
Routine Description:
This routine calculates the buffer size needed to hold a request. 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 *format - format string. args - args to the format string.
Implementation Notes:
This comes verbatim from kernel mode.
*/ { ULONG ix;
const char *z = format;
//
// Convert the input arguments into request packet.
//
ix = 0;
while ( *z ) { switch ( *z ) { case '=': ix++; case '-': ix++; break;
case '_': { WORD l = va_arg ( args, WORD ); ix += l; break; }
case 'b': { char b = va_arg ( args, BYTE ); ix++; break; }
case 'w': { WORD w = va_arg ( args, WORD ); ix += 2; break; }
case 'd': { DWORD d = va_arg ( args, DWORD ); ix += 4; break; }
case 'W': { WORD w = va_arg(args, WORD); ix += 2; break; }
case 'D': { DWORD d = va_arg (args, DWORD); ix += 4; break; }
case 'c': { char* c = va_arg ( args, char* ); WORD l = (WORD)strlen( c ); ix += l + 1; break; }
case 'C': { char* c = va_arg ( args, char* ); WORD l = va_arg ( args, WORD ); WORD len = strlen( c ) + 1; ix += l; break; }
case 'p': { char* c = va_arg ( args, char* ); BYTE l = (BYTE)strlen( c ); ix++; 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 );
ix++; ix += (USHORT)Length; break; }
case 'S': { PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING); ULONG Length, rLength;
Length = pUString->Length;
//
// 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 )); ix += 4; ix += Length; rLength -= Length; ix += rLength; break;
}
case 's': { PUNICODE_STRING pUString = va_arg (args, PUNICODE_STRING); ULONG Length, rLength;
Length = pUString->Length;
//
// Don't use the padded size here, only the NDS null terminator.
//
rLength = Length + sizeof( WCHAR ); ix += 4; ix += Length; rLength -= Length; ix += rLength; break;
}
case 'V': { // too similar to 'S' - should be combined
BYTE* b = va_arg ( args, BYTE* ); DWORD l = va_arg ( args, DWORD ); ix += sizeof(DWORD); 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; } ix += l; break; }
default:
;
}
z++; }
return(ix); }
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 = (WORD)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;
}
|