NT4/private/nw/nwscript/nds.c
2020-09-30 17:12:29 +02:00

1506 lines
35 KiB
C

/*************************************************************************
*
* NDS.C
*
* NT NetWare NDS routines
*
* Copyright (c) 1995 Microsoft Corporation
*
*************************************************************************/
#include <common.h>
DWORD GUserObjectID;
HANDLE GhRdr;
WCHAR * NDSTREE_w = NULL;
UNICODE_STRING NDSTREE_u;
/********************************************************************
ExpandRelativeName
Routine Description:
If the name is a relative NDS name append the proper context
to the end. A relative name has periods on the end. Each
period represents one level up the NDS tree.
Arguments:
Return Value:
*******************************************************************/
void
ExpandRelativeName( LPSTR RelativeName, LPSTR AbsoluteName, unsigned int Len,
LPSTR Context )
{
PBYTE ptr;
unsigned int i;
unsigned int count = 0;
strncpy( AbsoluteName, RelativeName, Len );
if ( ( AbsoluteName[0] == '.' ) &&
( AbsoluteName[ strlen( AbsoluteName ) - 1 ] != '.' ) )
return;
if ( ( strlen( AbsoluteName ) + strlen( Context ) ) > Len )
{
DisplayMessage( IDR_NOT_ENOUGH_MEMORY );
return;
}
if ( AbsoluteName[0] == '\0' )
{
return;
}
ptr = &AbsoluteName[ strlen( AbsoluteName ) - 1 ];
// Count the number of periods and back up over them.
if ( *ptr != '.' )
{
//
// No periods at the end
// Assume this is a relative name and append the context
//
strcat( AbsoluteName, "." );
strcat( AbsoluteName + strlen( AbsoluteName ), Context );
return;
}
while ( *ptr == '.' )
{
ptr--;
count++;
}
ptr++;
*ptr = '\0';
// ptr now points to where the copy of the rest of the context should start
// skip the first "count" entries in the context
ptr = Context;
for ( i = 0; i < count; i++ )
{
ptr = strchr( ptr, '.' );
if ( ptr == NULL )
{
return;
}
ptr++;
}
ptr--;
// Now append
strcat( AbsoluteName, ptr );
}
/********************************************************************
NDSGetNameContext
Routine Description:
Get the current context
Arguments:
none
Return Value:
none
*******************************************************************/
NTSTATUS
NDSGetNameContext( LPSTR Context, BOOLEAN flag )
{
//
// For NdsResolveName.
//
UNICODE_STRING ReferredServer;
WCHAR ServerStr[MAX_NAME_LEN];
HANDLE hReferredServer;
DWORD dwHandleType;
NTSTATUS Status;
OEM_STRING oemStr;
UNICODE_STRING defaultcontext;
DWORD ThisObjectID;
BYTE Buffer[2048];
WCHAR NdsStr[1024];
PBYTE ptr;
defaultcontext.Length = 0;
defaultcontext.MaximumLength = sizeof( NdsStr );
defaultcontext.Buffer = NdsStr;
Status = NwNdsGetTreeContext( GhRdr, &NDSTREE_u, &defaultcontext );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
ReferredServer.Buffer = ServerStr;
ReferredServer.Length = 0;
ReferredServer.MaximumLength = sizeof( ServerStr );
Status = NwNdsResolveName ( GhRdr,
&defaultcontext,
&ThisObjectID,
&ReferredServer,
NULL,
0 );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
if ( ReferredServer.Length > 0 ) {
//
// We've been referred to another server, so we
// should change the global handle.
//
Status = NwNdsOpenGenericHandle( &ReferredServer,
&dwHandleType,
&hReferredServer );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_NDS_USERNAME_FAILED);
return Status;
}
CloseHandle( GhRdr );
GhRdr = hReferredServer;
}
Status = NwNdsReadObjectInfo( GhRdr, ThisObjectID, Buffer, 2048 );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
ptr = Buffer + sizeof( NDS_RESPONSE_GET_OBJECT_INFO );
ptr += ROUNDUP4(*(DWORD *)ptr);
ptr += sizeof(DWORD);
ptr += sizeof(DWORD);
defaultcontext.Length = wcslen( (WCHAR *)ptr ) * 2;
defaultcontext.MaximumLength = defaultcontext.Length;
defaultcontext.Buffer = (WCHAR *)ptr;
oemStr.Length = 0;
oemStr.MaximumLength = NDS_NAME_CHARS;
oemStr.Buffer = Context;
RtlUnicodeStringToOemString( &oemStr, &defaultcontext, FALSE );
return 0;
}
/********************************************************************
NDSTypeless
Routine Description:
Change name to typelese
Arguments:
none
Return Value:
none
*******************************************************************/
unsigned int
NDSTypeless( LPSTR OrigName , LPSTR TypelessName )
{
int i,j;
PBYTE p;
i = 0;
j = 0;
if ( !_strnicmp( "CN=", OrigName, 3 ) ||
!_strnicmp( "OU=", OrigName, 3 ) )
{
i += 3;
}
else if ( !_strnicmp( "C=", OrigName, 2 ) ||
!_strnicmp( "O=", OrigName, 2 ) )
{
i += 2;
}
for ( ; (( i < NDS_NAME_CHARS ) && ( OrigName[i] ) ); i++ )
{
if ( !_strnicmp( ".CN=", &OrigName[i], 4 ) ||
!_strnicmp( ".OU=", &OrigName[i], 4 ) )
{
TypelessName[j++]= '.';
i += 3;
continue;
}
if ( !_strnicmp( ".C=", &OrigName[i], 3 ) ||
!_strnicmp( ".O=", &OrigName[i], 3 ) )
{
TypelessName[j++]= '.';
i += 2;
continue;
}
/*
* Strip out multiple blanks
*/
if ( !_strnicmp( " ", &OrigName[i], 2 ) )
{
continue;
}
TypelessName[j++] = OrigName[i];
}
TypelessName[j] = '\0';
return 0;
}
/********************************************************************
NDSAbbreviateName
Routine Description:
Abbreviate name
Arguments:
none
Return Value:
none
*******************************************************************/
unsigned int
NDSAbbreviateName( DWORD Flags, LPSTR OrigName , LPSTR AbbrevName )
{
BYTE Buffer[NDS_NAME_CHARS];
BYTE CurrentContext[NDS_NAME_CHARS];
PBYTE p;
PBYTE c;
NTSTATUS Status;
if ( OrigName[0] == '.' )
NDSTypeless( OrigName + 1, Buffer );
else
NDSTypeless( OrigName, Buffer );
/*
* We want a relative name
*/
if ( Flags & FLAGS_LOCAL_CONTEXT )
{
p = &Buffer[strlen(Buffer)-strlen(REQUESTER_CONTEXT)];
if ( !_strcmpi( REQUESTER_CONTEXT, p ) )
{
// The name is below us
if ( ( *(p-1) == '.' ) && ( p > Buffer ) )
p--;
*p = '\0';
strcpy( AbbrevName, Buffer );
}
else
{
//
// Going from back to front for each section of context
// in common with AbbrevName
// truncate both
// Going from back to front for each section of context
// left over
// concatonate a period to AbbrevName
//
// Example
//
// Name: w.x.y.z Context: a.b.z => w.x.y..
//
strcpy( CurrentContext, REQUESTER_CONTEXT );
strcpy( AbbrevName, Buffer );
if ( CurrentContext[0] && AbbrevName[0] )
{
c = &CurrentContext[ strlen( CurrentContext ) ] - 1;
p = &AbbrevName[ strlen( AbbrevName ) ] - 1;
//
// Strip off the matching names from end to front
//
for ( ;; )
{
if ( ( c == CurrentContext ) && ( *p == '.' ) )
{
*c = '\0';
*p = '\0';
break;
}
if ( *c != *p )
break;
if ( ( *c == '.' ) && ( *p == '.' ) )
{
*c = '\0';
*p = '\0';
}
if ( ( c == CurrentContext ) || ( p == AbbrevName ) )
{
break;
}
c--; p--;
}
//
// Count the remaining sections of the context and
// add that number of periods to the end of the buffer.
// That is how far we need to back up before getting
// to a matching branch of the tree.
//
if ( CurrentContext[0] ) {
strcat( AbbrevName, "." );
for ( c = CurrentContext; *c; c++ ) {
if ( *c == '.' )
strcat( AbbrevName, "." );
}
}
}
}
}
else
strcpy( AbbrevName, Buffer );
return 0;
}
/********************************************************************
NDSInitUserProperty
Routine Description:
none
Arguments:
none
Return Value:
0 = no error
*******************************************************************/
unsigned int
NDSInitUserProperty( )
{
NTSTATUS Status;
UNICODE_STRING ObjectName;
PWCHAR lpT;
UNICODE_STRING defaultcontext;
//
// For NdsResolveName.
//
UNICODE_STRING ReferredServer;
WCHAR ServerStr[MAX_NAME_LEN];
HANDLE hReferredServer;
DWORD dwHandleType;
//
// Get a handle to the redirector.
//
Status = NwNdsOpenTreeHandle( &NDSTREE_u, &GhRdr );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_TREE_OPEN_FAILED);
return 1;
}
//
// Resolve the name that we have to an object id.
//
RtlInitUnicodeString( &ObjectName, TYPED_USER_NAME_w );
ReferredServer.Buffer = ServerStr;
ReferredServer.Length = 0;
ReferredServer.MaximumLength = sizeof( ServerStr );
Status = NwNdsResolveName ( GhRdr,
&ObjectName,
&GUserObjectID,
&ReferredServer,
NULL,
0 );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_NDS_USERNAME_FAILED);
return 1;
}
if ( ReferredServer.Length > 0 ) {
//
// We've been referred to another server, so we
// should change the global handle.
//
Status = NwNdsOpenGenericHandle( &ReferredServer,
&dwHandleType,
&hReferredServer );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_NDS_USERNAME_FAILED);
return 1;
}
CloseHandle( GhRdr );
GhRdr = hReferredServer;
}
//
// Set the current context to what we think it should be
// (At the user's location.)
//
lpT = wcschr( TYPED_USER_NAME_w, L'.' );
if ( lpT )
{
RtlInitUnicodeString( &defaultcontext, lpT+1 );
}
else
{
RtlInitUnicodeString( &defaultcontext, L"" );
}
Status = NwNdsSetTreeContext( GhRdr, &NDSTREE_u, &defaultcontext );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_NDS_CONTEXT_INVALID);
return 1;
}
return 0;
}
/********************************************************************
NDSCanonicalizeName
Routine Description:
return a canonicalized version of a name
Arguments:
Name - original name
CanonName - Canonicalized name
Len - length of CanonName
fCurrentContext - TRUE => use current contex, FALSE use
requester context
Return Value:
status error
*******************************************************************/
unsigned int
NDSCanonicalizeName( PBYTE Name, PBYTE CanonName, int Len, int fCurrentContext )
{
NTSTATUS Status;
int ccode = -1;
DWORD ThisObjectID;
OEM_STRING oemStr;
UNICODE_STRING ObjectName;
BYTE Buffer[2048];
BYTE FullName[NDS_NAME_CHARS];
PBYTE ptr;
UNICODE_STRING ReferredServer;
WCHAR ServerStr[MAX_NAME_LEN];
DWORD dwHandleType;
HANDLE hReferredServer;
unsigned char CurrentContext[NDS_NAME_CHARS];
//
// Cope with relative names
//
if ( fCurrentContext )
{
Status = NDSGetNameContext( CurrentContext, TRUE );
if ( !NT_SUCCESS( Status ) )
return Status;
ExpandRelativeName( Name, FullName, NDS_NAME_CHARS, CurrentContext );
}
else
ExpandRelativeName( Name, FullName, NDS_NAME_CHARS, REQUESTER_CONTEXT );
//
// Fill it in in case we have an error
//
strncpy( CanonName, FullName, Len);
//
// Resolve the name that we have to an object id.
//
// Unfortuneately, the name resolver doesn't understand periods at the
// front or end (absolute or relative names)
//
if ( FullName[0] == '.' )
{
oemStr.Length = strlen( FullName + 1 );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = FullName + 1;
}
else
{
oemStr.Length = strlen( FullName );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = FullName;
}
ObjectName.Length = 0;
ObjectName.MaximumLength = sizeof(Buffer);
ObjectName.Buffer = (WCHAR *)Buffer;
RtlOemStringToUnicodeString( &ObjectName, &oemStr, FALSE );
ReferredServer.Buffer = ServerStr;
ReferredServer.Length = 0;
ReferredServer.MaximumLength = sizeof( ServerStr );
Status = NwNdsResolveName ( GhRdr,
&ObjectName,
&ThisObjectID,
&ReferredServer,
NULL,
0 );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
if ( ReferredServer.Length > 0 ) {
//
// We've been referred to another server, so we
// should change the global handle.
//
Status = NwNdsOpenGenericHandle( &ReferredServer,
&dwHandleType,
&hReferredServer );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
CloseHandle( GhRdr );
GhRdr = hReferredServer;
}
Status = NwNdsReadObjectInfo( GhRdr, ThisObjectID, Buffer, 2048 );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
ptr = Buffer + sizeof( NDS_RESPONSE_GET_OBJECT_INFO );
ptr += ROUNDUP4(*(DWORD *)ptr);
ptr += sizeof(DWORD);
ptr += sizeof(DWORD);
RtlInitUnicodeString( &ObjectName, (PWCHAR)ptr );
oemStr.Length = 0;
oemStr.MaximumLength = Len;
oemStr.Buffer = CanonName;
RtlUnicodeStringToOemString( &oemStr, &ObjectName, FALSE );
return 0;
}
/********************************************************************
NDSGetUserProperty
Routine Description:
Return the NDS property for the object
Arguments:
Property - property name
Data - data buffer
Size - size of data buffer
Return Value:
0 no error
*******************************************************************/
unsigned int
NDSGetUserProperty( PBYTE Property,
PBYTE Data,
unsigned int Size,
SYNTAX * pSyntaxID,
unsigned int * pActualSize )
{
NTSTATUS Status;
int ccode = -1;
OEM_STRING oemStr;
UNICODE_STRING PropertyName;
WCHAR NdsStr[1024];
DWORD iterhandle = INITIAL_ITERATION;
BYTE Buffer[2048];
DWORD BufferSize = 2048;
PNDS_RESPONSE_READ_ATTRIBUTE pReadAttribute;
PNDS_ATTRIBUTE pAttribute;
PBYTE pAttribValue;
//
// Read the User property
//
memset(Buffer, 0, BufferSize);
oemStr.Length = strlen( Property );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = Property;
PropertyName.Length = 0;
PropertyName.MaximumLength = sizeof(NdsStr);
PropertyName.Buffer = NdsStr;
RtlOemStringToUnicodeString( &PropertyName, &oemStr, FALSE );
Status = NwNdsReadAttribute ( GhRdr,
GUserObjectID,
&iterhandle,
&PropertyName,
Buffer,
BufferSize );
if ( NT_SUCCESS(Status) )
{
int i;
pReadAttribute = (PNDS_RESPONSE_READ_ATTRIBUTE)Buffer;
pAttribute = (PNDS_ATTRIBUTE)(Buffer
+ sizeof(NDS_RESPONSE_READ_ATTRIBUTE));
if ( pSyntaxID )
{
*pSyntaxID = pAttribute->SyntaxID;
}
pAttribValue = (PBYTE)(pAttribute->AttribName) +
ROUNDUP4(pAttribute->AttribNameLength) +
sizeof(DWORD);
if ( pActualSize )
{
*pActualSize = *(DWORD *)pAttribValue;
}
memcpy( Data, pAttribValue + sizeof(DWORD),
min(*(DWORD *)pAttribValue, Size) );
}
return Status;
}
/********************************************************************
NDSGetVar
Routine Description:
Return value of user property
Get the syntax type of the property
Retrieve the data
Do any data conversion
Arguments:
Name - of NDS property IN
Value - value buffer OUT
Size - size of value buffer IN
Return Value:
none
*******************************************************************/
void
NDSGetVar ( PBYTE Name, PBYTE Value, unsigned int Size)
{
unsigned int err;
SYNTAX Syntax;
BYTE Buffer[ATTRBUFSIZE];
DWORD ActualSize;
Value[0] = 0;
err = NDSGetUserProperty( Name, Buffer, ATTRBUFSIZE, &Syntax, &ActualSize );
if ( err )
{
return;
}
switch ( Syntax )
{
case NDSI_BOOLEAN:
if ( *(PBYTE)Buffer )
{
strcpy( Value, "Y" );
}
else
{
strcpy( Value, "N" );
}
break;
case NDSI_DIST_NAME:
case NDSI_CE_STRING:
case NDSI_CI_STRING:
case NDSI_OCTET_STRING:
case NDSI_PR_STRING:
case NDSI_NU_STRING:
case NDSI_TEL_NUMBER:
case NDSI_CLASS_NAME:
ConvertUnicodeToAscii( Buffer );
if ( Syntax == NDSI_DIST_NAME )
NDSAbbreviateName(FLAGS_LOCAL_CONTEXT, Buffer, Buffer);
strncpy( Value, Buffer, Size );
break;
case NDSI_CI_LIST:
ConvertUnicodeToAscii( Buffer+8 );
strncpy( Value, Buffer+8, Size );
break;
break;
case NDSI_INTEGER:
case NDSI_COUNTER:
case NDSI_TIME:
case NDSI_INTERVAL:
case NDSI_TIMESTAMP:
sprintf( Value, "%d", *(int *)Buffer );
break;
case NDSI_PO_ADDRESS:
{
// 6 null terminated lines
int line,len;
PBYTE ptr = Buffer + 4;
// Stop if not 6 lines
if ( *(int *)Buffer != 6 )
break;
for (line = 0; line <= 5; line++) {
len = ROUNDUP4(*(int *)ptr);
ptr += 4;
if ( !len )
break;
ConvertUnicodeToAscii( ptr );
strcat( Value, ptr );
strcat( Value, "\n" );
ptr += len;
}
}
break;
case NDSI_FAX_NUMBER:
if ( *(int *)Buffer == 0 )
return;
ConvertUnicodeToAscii( Buffer+4 );
strncpy( Value, Buffer+4, Size );
break;
case NDSI_EMAIL_ADDRESS:
if ( *(int *)(Buffer+4) == 0 )
return;
ConvertUnicodeToAscii( Buffer+8 );
strncpy( Value, Buffer+8, Size );
break;
case NDSI_PATH:
{
int len;
len = *(int *)(Buffer+4);
if ( len == 0 )
break;
len = ROUNDUP4( len );
ConvertUnicodeToAscii( Buffer+8 );
strcpy( Value, Buffer+8 );
NDSAbbreviateName(FLAGS_LOCAL_CONTEXT, Value, Value);
strcat( Value, ":" );
if ( *(int *)(Buffer + 8 + len) == 0 )
break;
ConvertUnicodeToAscii( Buffer+8+len+4 );
strcat( Value, Buffer+8+len+4 );
break;
}
case NDSI_NET_ADDRESS:
case NDSI_OCTET_LIST:
case NDSI_OBJECT_ACL:
case NDSI_STREAM:
case NDSI_UNKNOWN:
case NDSI_REPLICA_POINTER:
case NDSI_BACK_LINK:
case NDSI_TYPED_NAME:
case NDSI_HOLD:
case NDSI_TAX_COUNT:
default:
Value[0] = '\0';
Value[1] = '\0';
break;
}
}
/********************************************************************
NDSChangeContext
Routine Description:
Change the current context
Arguments:
Context - context string IN
Return Value:
error number
*******************************************************************/
unsigned int
NDSChangeContext( PBYTE Context )
{
NTSTATUS Status;
OEM_STRING oemStr;
UNICODE_STRING defaultcontext;
WCHAR NdsStr[1024];
oemStr.Length = strlen( Context );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = Context;
defaultcontext.Length = 0;
defaultcontext.MaximumLength = sizeof(NdsStr);
defaultcontext.Buffer = NdsStr;
RtlOemStringToUnicodeString( &defaultcontext, &oemStr, FALSE );
Status = NwNdsSetTreeContext( GhRdr, &NDSTREE_u, &defaultcontext );
return Status;
}
/********************************************************************
NDSGetContext
Routine Description:
Retrieve the current context
Arguments:
Buffer - data buffer for context string OUT
len - length of data buffer IN
Return Value:
error number
*******************************************************************/
unsigned int
NDSGetContext( PBYTE Buffer,
unsigned int len )
{
NTSTATUS Status;
Status = NDSGetNameContext( Buffer, TRUE );
if ( !NT_SUCCESS( Status ) )
return Status;
NDSAbbreviateName(FLAGS_NO_CONTEXT, Buffer, Buffer);
return 0;
}
/********************************************************************
NDSfopenStream
Routine Description:
Open a file handle to an NDS stream property
Arguments:
Object - name of object IN
Property - name of property IN
pStream - pointer to file handle OUT
pFileSize - pointer to file size OUT
Return Value:
error
*******************************************************************/
unsigned int
NDSfopenStream ( PBYTE Object,
PBYTE Property,
PHANDLE pStream,
unsigned int * pFileSize )
{
//
// Status variables.
//
NTSTATUS Status;
int ccode = -1;
//
// For NwNdsOpenTreeHandle.
//
HANDLE hRdr;
OEM_STRING oemStr;
UNICODE_STRING ObjectName;
WCHAR NdsStr[1024];
//
// For NwNdsResolveName.
//
DWORD dwOid;
UNICODE_STRING ReferredServer;
WCHAR ServerStr[MAX_NAME_LEN];
DWORD dwHandleType;
HANDLE hReferredServer;
//
// Get a handle to the redirector.
//
Status = NwNdsOpenTreeHandle( &NDSTREE_u, &hRdr );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_TREE_OPEN_FAILED);
return ccode;
}
//
// Resolve the name that we have to an object id.
//
if ( !Object )
{
return 1;
}
oemStr.Length = strlen( Object );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = Object;
ObjectName.Length = 0;
ObjectName.MaximumLength = sizeof(NdsStr);
ObjectName.Buffer = NdsStr;
RtlOemStringToUnicodeString( &ObjectName, &oemStr, FALSE );
ReferredServer.Buffer = ServerStr;
ReferredServer.Length = 0;
ReferredServer.MaximumLength = sizeof( ServerStr );
Status = NwNdsResolveName ( hRdr,
&ObjectName,
&dwOid,
&ReferredServer,
NULL,
0 );
if ( !NT_SUCCESS( Status ) ) {
return 0xffffffff;
}
if ( ReferredServer.Length > 0 ) {
//
// We've been referred to another server, so we
// must jump to that server before continuing.
//
Status = NwNdsOpenGenericHandle( &ReferredServer,
&dwHandleType,
&hReferredServer );
if ( !NT_SUCCESS( Status ) ) {
return 0xffffffff;
}
CloseHandle( hRdr );
hRdr = hReferredServer;
}
//
// Open the file stream.
//
oemStr.Length = strlen( Property );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = Property;
ObjectName.Length = 0;
ObjectName.MaximumLength = sizeof(NdsStr);
ObjectName.Buffer = NdsStr;
RtlOemStringToUnicodeString( &ObjectName, &oemStr, FALSE );
//
// Try to open a file stream for read access.
//
Status = NwNdsOpenStream( hRdr,
dwOid,
&ObjectName,
1, // Read access.
pFileSize );
if ( !NT_SUCCESS( Status ) ) {
return 0xffffffff;
}
*pStream = hRdr;
return 0;
}
/*
* IsMemberOfNDSGroup
* ------------------
*
* Returns true if currently logged in user object is member of group with given name
*
*/
unsigned int
IsMemberOfNDSGroup(
PBYTE nwGroup
)
{
NTSTATUS Status;
UINT nwRet;
BYTE szCanonTargetGroupName[NDS_NAME_CHARS+1];
UINT syntaxid;
UINT actualsize;
LPSTR szBuffer;
LPSTR pProp;
UINT i;
DWORD iterhandle = INITIAL_ITERATION;
UINT fFoundGroup = FALSE;
PNDS_RESPONSE_READ_ATTRIBUTE pReadAttribute;
PNDS_ATTRIBUTE pAttribute;
PBYTE pAttribValue;
UNICODE_STRING PropertyName;
UINT numvalues = 0;
szBuffer = (BYTE *)malloc(ATTRBUFSIZE);
if ( !szBuffer ) {
DisplayMessage(IDR_NOT_ENOUGH_MEMORY);
return FALSE;
}
memset( szBuffer, 0, ATTRBUFSIZE );
// Canonicalize name according to current context
strcpy( szCanonTargetGroupName, nwGroup );
nwRet = NDSCanonicalizeName( szCanonTargetGroupName,
szCanonTargetGroupName,
NDS_NAME_CHARS,
TRUE );
if (nwRet) {
if ( nwGroup[0] != '.' ) {
// Try an absolute name
strcpy( szCanonTargetGroupName, "." );
strcat( szCanonTargetGroupName, nwGroup );
nwRet = NDSCanonicalizeName( szCanonTargetGroupName,
szCanonTargetGroupName,
NDS_NAME_CHARS,
TRUE );
}
if ( nwRet )
goto CleanRet;
}
// Should check class name of object
RtlInitUnicodeString( &PropertyName, L"Group Membership" );
Status = NwNdsReadAttribute ( GhRdr,
GUserObjectID,
&iterhandle,
&PropertyName,
szBuffer,
ATTRBUFSIZE );
if ( !NT_SUCCESS(Status) )
{
return FALSE;
}
pReadAttribute = (PNDS_RESPONSE_READ_ATTRIBUTE)szBuffer;
pAttribute = (PNDS_ATTRIBUTE)(szBuffer
+ sizeof(NDS_RESPONSE_READ_ATTRIBUTE));
pAttribute->SyntaxID;
pAttribValue = (PBYTE)(pAttribute->AttribName) +
ROUNDUP4(pAttribute->AttribNameLength) +
sizeof(DWORD);
numvalues = *(PUINT)((PBYTE)(pAttribute->AttribName) +
ROUNDUP4(pAttribute->AttribNameLength));
if ( *(DWORD *)pAttribValue == 0 )
{
return FALSE;
}
for ( i = 0; i < numvalues; i++ ) {
ConvertUnicodeToAscii( pAttribValue+sizeof(DWORD) );
if (!_stricmp(pAttribValue+sizeof(DWORD),szCanonTargetGroupName)) {
fFoundGroup = TRUE;
break;
}
pAttribValue += ROUNDUP4(*(PUINT)pAttribValue) + sizeof(DWORD);
}
CleanRet:
if (szBuffer ) {
free (szBuffer);
}
return fFoundGroup;
}
/********************************************************************
NDSGetProperty
Routine Description:
Return the NDS property for the object
Arguments:
Object - name of object IN
Property - property name IN
Data - data buffer OUT
Size - size of data buffer IN
pActualSize - real data size OUT
Return Value:
error
*******************************************************************/
unsigned int
NDSGetProperty ( PBYTE Object,
PBYTE Property,
PBYTE Data,
unsigned int Size,
unsigned int * pActualSize )
{
//
// Status variables.
//
NTSTATUS Status;
int ccode = -1;
//
// For NwNdsOpenTreeHandle.
//
HANDLE hRdr;
OEM_STRING oemStr;
UNICODE_STRING ObjectName;
WCHAR NdsStr[1024];
//
// For NwNdsResolveName.
//
DWORD dwOid;
UNICODE_STRING ReferredServer;
WCHAR ServerStr[MAX_NAME_LEN];
DWORD dwHandleType;
HANDLE hReferredServer;
//
// For NwNdsReadAttribute
//
BYTE Buffer[2048];
DWORD BufferSize = 2048;
DWORD iterhandle = INITIAL_ITERATION;
PNDS_RESPONSE_READ_ATTRIBUTE pReadAttribute;
PNDS_ATTRIBUTE pAttribute;
PBYTE pAttribValue;
//
// Get a handle to the redirector.
//
Status = NwNdsOpenTreeHandle( &NDSTREE_u, &hRdr );
if ( !NT_SUCCESS( Status ) ) {
DisplayMessage(IDR_TREE_OPEN_FAILED);
return ccode;
}
//
// Resolve the name that we have to an object id.
//
if ( !Object )
{
return 1;
}
oemStr.Length = strlen( Object );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = Object;
ObjectName.Length = 0;
ObjectName.MaximumLength = sizeof(NdsStr);
ObjectName.Buffer = NdsStr;
RtlOemStringToUnicodeString( &ObjectName, &oemStr, FALSE );
ReferredServer.Buffer = ServerStr;
ReferredServer.Length = 0;
ReferredServer.MaximumLength = sizeof( ServerStr );
Status = NwNdsResolveName ( hRdr,
&ObjectName,
&dwOid,
&ReferredServer,
NULL,
0 );
if ( !NT_SUCCESS( Status ) ) {
return 0xffffffff;
}
if ( ReferredServer.Length > 0 ) {
//
// We've been referred to another server, so we
// must jump to that server before continuing.
//
Status = NwNdsOpenGenericHandle( &ReferredServer,
&dwHandleType,
&hReferredServer );
if ( !NT_SUCCESS( Status ) ) {
return 0xffffffff;
}
CloseHandle( hRdr );
hRdr = hReferredServer;
}
//
// Get the attribute
//
oemStr.Length = strlen( Property );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = Property;
ObjectName.Length = 0;
ObjectName.MaximumLength = sizeof(NdsStr);
ObjectName.Buffer = NdsStr;
RtlOemStringToUnicodeString( &ObjectName, &oemStr, FALSE );
Status = NwNdsReadAttribute ( hRdr,
dwOid,
&iterhandle,
&ObjectName,
Buffer,
BufferSize );
if ( NT_SUCCESS(Status) )
{
int i;
pReadAttribute = (PNDS_RESPONSE_READ_ATTRIBUTE)Buffer;
pAttribute = (PNDS_ATTRIBUTE)(Buffer
+ sizeof(NDS_RESPONSE_READ_ATTRIBUTE));
pAttribValue = (PBYTE)(pAttribute->AttribName) +
ROUNDUP4(pAttribute->AttribNameLength) +
sizeof(DWORD);
if ( pActualSize )
{
*pActualSize = *(DWORD *)pAttribValue;
}
memcpy( Data, pAttribValue + sizeof(DWORD),
min(*(DWORD *)pAttribValue, Size) );
}
NtClose( hRdr );
return Status;
}
/********************************************************************
NDSCleanup
Routine Description:
Does any NDS cleanup
Arguments:
none
Return Value:
none
*******************************************************************/
void
NDSCleanup ( void )
{
NtClose( GhRdr );
}
/********************************************************************
NDSGetClassName
Routine Description:
return a class name for an object
Arguments:
szObjectName
ClassName
Return Value:
none
*******************************************************************/
unsigned int
NDSGetClassName( LPSTR szObjectName, LPSTR ClassName )
{
NTSTATUS Status;
int ccode = -1;
DWORD ThisObjectID;
OEM_STRING oemStr;
UNICODE_STRING ObjectName;
BYTE Buffer[2048];
BYTE FullName[NDS_NAME_CHARS];
PBYTE ptr;
UNICODE_STRING ReferredServer;
WCHAR ServerStr[MAX_NAME_LEN];
DWORD dwHandleType;
HANDLE hReferredServer;
DWORD Length;
//
// Resolve the name that we have to an object id.
//
oemStr.Length = strlen( szObjectName );
oemStr.MaximumLength = oemStr.Length;
oemStr.Buffer = szObjectName;
ObjectName.Length = 0;
ObjectName.MaximumLength = sizeof(Buffer);
ObjectName.Buffer = (WCHAR *)Buffer;
RtlOemStringToUnicodeString( &ObjectName, &oemStr, FALSE );
ReferredServer.Buffer = ServerStr;
ReferredServer.Length = 0;
ReferredServer.MaximumLength = sizeof( ServerStr );
Status = NwNdsResolveName ( GhRdr,
&ObjectName,
&ThisObjectID,
&ReferredServer,
NULL,
0 );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
if ( ReferredServer.Length > 0 ) {
//
// We've been referred to another server, so we
// should change the global handle.
//
Status = NwNdsOpenGenericHandle( &ReferredServer,
&dwHandleType,
&hReferredServer );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
CloseHandle( GhRdr );
GhRdr = hReferredServer;
}
Status = NwNdsReadObjectInfo( GhRdr, ThisObjectID, Buffer, 2048 );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
ptr = Buffer + sizeof( NDS_RESPONSE_GET_OBJECT_INFO ) + sizeof( DWORD );
RtlInitUnicodeString( &ObjectName, (PWCHAR)ptr );
oemStr.Length = 0;
oemStr.MaximumLength = NDS_NAME_CHARS;
oemStr.Buffer = ClassName;
RtlUnicodeStringToOemString( &oemStr, &ObjectName, FALSE );
return 0;
}