/************************************************************************* * * NDS.C * * NT NetWare NDS routines * * Copyright (c) 1995 Microsoft Corporation * *************************************************************************/ #include 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; }