Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

646 lines
13 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
accessp.c
Abstract:
Internal routines shared by NetUser API and Netlogon service. These
routines convert from SAM specific data formats to UAS specific data
formats.
Author:
Cliff Van Dyke (cliffv) 29-Aug-1991
Environment:
User mode only.
Contains NT-specific code.
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
22-Oct-1991 JohnRo
Made changes suggested by PC-LINT.
04-Dec-1991 JohnRo
Trying to get around a weird MIPS compiler bug.
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
#include <ntsam.h>
#include <windef.h>
#include <lmcons.h>
#include <accessp.h>
#include <debuglib.h>
#include <lmaccess.h>
#include <netdebug.h>
VOID
NetpGetAllowedAce(
IN PACL Dacl,
IN PSID Sid,
OUT PVOID *Ace
)
/*++
Routine Description:
Given a DACL, find an AccessAllowed ACE containing a particuar SID.
Arguments:
Dacl - A pointer to the ACL to search.
Sid - A pointer to the Sid to search for.
Ace - Returns a pointer to the specified ACE. Returns NULL if there
is no such ACE
Return Value:
None.
--*/
{
NTSTATUS Status;
ACL_SIZE_INFORMATION AclSize;
DWORD AceIndex;
//
// Determine the size of the DACL so we can copy it
//
Status = RtlQueryInformationAcl(
Dacl,
&AclSize,
sizeof(AclSize),
AclSizeInformation );
if ( ! NT_SUCCESS( Status ) ) {
IF_DEBUG( ACCESSP ) {
NetpKdPrint((
"NetpGetDacl: RtlQueryInformationAcl returns %lX\n",
Status ));
}
*Ace = NULL;
return;
}
//
// Loop through the ACEs looking for an ACCESS_ALLOWED ACE with the
// right SID.
//
for ( AceIndex=0; AceIndex<AclSize.AceCount; AceIndex++ ) {
Status = RtlGetAce( Dacl, AceIndex, (PVOID *)Ace );
if ( ! NT_SUCCESS( Status ) ) {
*Ace = NULL;
return;
}
if ( ((PACE_HEADER)*Ace)->AceType != ACCESS_ALLOWED_ACE_TYPE ) {
continue;
}
if ( RtlEqualSid( Sid,
(PSID)&((PACCESS_ALLOWED_ACE)(*Ace))->SidStart )
){
return;
}
}
//
// Couldn't find any such ACE.
//
*Ace = NULL;
return;
}
DWORD
NetpAccountControlToFlags(
IN DWORD UserAccountControl,
IN PACL UserDacl
)
/*++
Routine Description:
Convert a SAM UserAccountControl field and the Discretionary ACL for
the user into the NetUser API usriX_flags field.
Arguments:
UserAccountControl - The SAM UserAccountControl field for the user.
UserDacl - The Discretionary ACL for the user.
Return Value:
Returns the usriX_flags field for the user.
--*/
{
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
DWORD WorldSid[sizeof(SID)/sizeof(DWORD) + SID_MAX_SUB_AUTHORITIES ];
PACCESS_ALLOWED_ACE Ace;
DWORD Flags = UF_SCRIPT;
//
// Build a copy of the world SID for later comparison.
//
RtlInitializeSid( (PSID) WorldSid, &WorldSidAuthority, 1 );
*(RtlSubAuthoritySid( (PSID)WorldSid, 0 )) = SECURITY_WORLD_RID;
//
// Determine if the UF_PASSWD_CANT_CHANGE bit should be returned
//
// Return UF_PASSWD_CANT_CHANGE unless the world can change the
// password.
//
//
// If the user has no DACL, the password can change
//
if ( UserDacl != NULL ) {
//
// Find the WORLD grant ACE
//
NetpGetAllowedAce( UserDacl, (PSID) WorldSid, (PVOID *)&Ace );
if ( Ace == NULL ) {
Flags |= UF_PASSWD_CANT_CHANGE;
} else {
if ( (Ace->Mask & USER_CHANGE_PASSWORD) == 0 ) {
Flags |= UF_PASSWD_CANT_CHANGE;
}
}
}
//
// Set all other bits as a function of the SAM UserAccountControl
//
if ( UserAccountControl & USER_ACCOUNT_DISABLED ) {
Flags |= UF_ACCOUNTDISABLE;
}
if ( UserAccountControl & USER_HOME_DIRECTORY_REQUIRED ){
Flags |= UF_HOMEDIR_REQUIRED;
}
if ( UserAccountControl & USER_PASSWORD_NOT_REQUIRED ){
Flags |= UF_PASSWD_NOTREQD;
}
if ( UserAccountControl & USER_DONT_EXPIRE_PASSWORD ){
Flags |= UF_DONT_EXPIRE_PASSWD;
}
if ( UserAccountControl & USER_ACCOUNT_AUTO_LOCKED ){
Flags |= UF_LOCKOUT;
}
if ( UserAccountControl & USER_MNS_LOGON_ACCOUNT ){
Flags |= UF_MNS_LOGON_ACCOUNT;
}
//
// set account type bit.
//
//
// account type bit are exculsive and precisely only one
// account type bit is set. So, as soon as an account type bit is set
// in the following if sequence we can return.
//
if( UserAccountControl & USER_TEMP_DUPLICATE_ACCOUNT ) {
Flags |= UF_TEMP_DUPLICATE_ACCOUNT;
} else if( UserAccountControl & USER_NORMAL_ACCOUNT ) {
Flags |= UF_NORMAL_ACCOUNT;
} else if( UserAccountControl & USER_INTERDOMAIN_TRUST_ACCOUNT ) {
Flags |= UF_INTERDOMAIN_TRUST_ACCOUNT;
} else if( UserAccountControl & USER_WORKSTATION_TRUST_ACCOUNT ) {
Flags |= UF_WORKSTATION_TRUST_ACCOUNT;
} else if( UserAccountControl & USER_SERVER_TRUST_ACCOUNT ) {
Flags |= UF_SERVER_TRUST_ACCOUNT;
} else {
//
// There is no known account type bit set in UserAccountControl.
// ?? Flags |= UF_NORMAL_ACCOUNT;
// NetpAssert( FALSE );
}
return Flags;
}
ULONG
NetpDeltaTimeToSeconds(
IN LARGE_INTEGER DeltaTime
)
/*++
Routine Description:
Convert an NT delta time specification to seconds
Arguments:
DeltaTime - Specifies the NT Delta time to convert. NT delta time is
a negative number of 100ns units.
Return Value:
Returns the number of seconds. Any invalid or too large input
returns TIMEQ_FOREVER.
--*/
{
LARGE_INTEGER LargeSeconds;
//
// These are the magic numbers needed to do our extended division by
// 10,000,000 = convert 100ns tics to one second tics
//
LARGE_INTEGER Magic10000000 = { (ULONG) 0xe57a42bd, (LONG) 0xd6bf94d5};
#define SHIFT10000000 23
//
// Special case zero.
//
if ( DeltaTime.HighPart == 0 && DeltaTime.LowPart == 0 ) {
return( 0 );
}
//
// Convert the Delta time to a Large integer seconds.
//
LargeSeconds = RtlExtendedMagicDivide(
DeltaTime,
Magic10000000,
SHIFT10000000 );
#ifdef notdef
NetpKdPrint(( "NetpDeltaTimeToSeconds: %lx %lx %lx %lx\n",
DeltaTime.HighPart,
DeltaTime.LowPart,
LargeSeconds.HighPart,
LargeSeconds.LowPart ));
#endif // notdef
//
// Return too large a number or a positive number as TIMEQ_FOREVER
//
if ( LargeSeconds.HighPart != -1 ) {
return TIMEQ_FOREVER;
}
return ( (ULONG)(- ((LONG)(LargeSeconds.LowPart))) );
} // NetpDeltaTimeToSeconds
LARGE_INTEGER
NetpSecondsToDeltaTime(
IN ULONG Seconds
)
/*++
Routine Description:
Convert a number of seconds to an NT delta time specification
Arguments:
Seconds - a positive number of seconds
Return Value:
Returns the NT Delta time. NT delta time is a negative number
of 100ns units.
--*/
{
LARGE_INTEGER DeltaTime;
LARGE_INTEGER LargeSeconds;
LARGE_INTEGER Answer;
//
// Special case TIMEQ_FOREVER (return a full scale negative)
//
if ( Seconds == TIMEQ_FOREVER ) {
DeltaTime.LowPart = 0;
DeltaTime.HighPart = (LONG) 0x80000000;
//
// Convert seconds to 100ns units simply by multiplying by 10000000.
//
// Convert to delta time by negating.
//
} else {
LargeSeconds = RtlConvertUlongToLargeInteger( Seconds );
Answer = RtlExtendedIntegerMultiply( LargeSeconds, 10000000 );
if ( Answer.QuadPart < 0 ) {
DeltaTime.LowPart = 0;
DeltaTime.HighPart = (LONG) 0x80000000;
} else {
DeltaTime.QuadPart = -Answer.QuadPart;
}
}
return DeltaTime;
} // NetpSecondsToDeltaTime
VOID
NetpAliasMemberToPriv(
IN ULONG AliasCount,
IN PULONG AliasMembership,
OUT LPDWORD Priv,
OUT LPDWORD AuthFlags
)
/*++
Routine Description:
Converts membership in Aliases to LANMAN 2.0 style Priv and AuthFlags.
Arguments:
AliasCount - Specifies the number of Aliases in the AliasMembership array.
AliasMembership - Specifies the Aliases that are to be converted to Priv
and AuthFlags. Each element in the array specifies the RID of an
alias in the BuiltIn domain.
Priv - Returns the Lanman 2.0 Privilege level for the specified aliases.
AuthFlags - Returns the Lanman 2.0 Authflags for the specified aliases.
Return Value:
None.
--*/
{
DWORD j;
BOOLEAN IsAdmin = FALSE;
BOOLEAN IsUser = FALSE;
//
// Loop through the aliases finding any special aliases.
//
// If this user is the member of multiple operator aliases,
// just "or" the appropriate bits in.
//
// If this user is the member of multiple "privilege" aliases,
// just report the one with the highest privilege.
// Report the user is a member of the Guest aliases by default.
//
*AuthFlags = 0;
for ( j=0; j < AliasCount; j++ ) {
switch ( AliasMembership[j] ) {
case DOMAIN_ALIAS_RID_ADMINS:
IsAdmin = TRUE;
break;
case DOMAIN_ALIAS_RID_USERS:
IsUser = TRUE;
break;
case DOMAIN_ALIAS_RID_ACCOUNT_OPS:
*AuthFlags |= AF_OP_ACCOUNTS;
break;
case DOMAIN_ALIAS_RID_SYSTEM_OPS:
*AuthFlags |= AF_OP_SERVER;
break;
case DOMAIN_ALIAS_RID_PRINT_OPS:
*AuthFlags |= AF_OP_PRINT;
break;
}
}
if ( IsAdmin ) {
*Priv = USER_PRIV_ADMIN;
} else if ( IsUser ) {
*Priv = USER_PRIV_USER;
} else {
*Priv = USER_PRIV_GUEST;
}
}
DWORD
NetpGetElapsedSeconds(
IN PLARGE_INTEGER Time
)
/*++
Routine Description:
Computes the elapsed time in seconds since the time specified.
Returns 0 on error.
Arguments:
Time - Time (typically in the past) to compute the elapsed time from.
Return Value:
0: on error.
Number of seconds.
--*/
{
LARGE_INTEGER CurrentTime;
DWORD Current1980Time;
DWORD Prior1980Time;
NTSTATUS Status;
//
// Compute the age of the password
//
Status = NtQuerySystemTime( &CurrentTime );
if( !NT_SUCCESS(Status) ) {
return 0;
}
if ( !RtlTimeToSecondsSince1980( &CurrentTime, &Current1980Time) ) {
return 0;
}
if ( !RtlTimeToSecondsSince1980( Time, &Prior1980Time ) ) {
return 0;
}
if ( Current1980Time <= Prior1980Time ) {
return 0;
}
return Current1980Time - Prior1980Time;
}
VOID
NetpConvertWorkstationList(
IN OUT PUNICODE_STRING WorkstationList
)
/*++
Routine Description:
Convert the list of workstations from a comma separated list to
a blank separated list. Any workstation name containing a blank is
silently removed.
Arguments:
WorkstationList - List of workstations to convert
Return Value:
None
--*/
{
LPWSTR Source;
LPWSTR Destination;
LPWSTR EndOfBuffer;
LPWSTR BeginningOfName;
BOOLEAN SkippingName;
ULONG NumberOfCharacters;
//
// Handle the trivial case.
//
if ( WorkstationList->Length == 0 ) {
return;
}
//
// Initialization.
//
Destination = Source = WorkstationList->Buffer;
EndOfBuffer = Source + WorkstationList->Length/sizeof(WCHAR);
//
// Loop handling special characters
//
SkippingName = FALSE;
BeginningOfName = Destination;
while ( Source < EndOfBuffer ) {
switch ( *Source ) {
case ',':
if ( !SkippingName ) {
*Destination = ' ';
Destination++;
}
SkippingName = FALSE;
BeginningOfName = Destination;
break;
case ' ':
SkippingName = TRUE;
Destination = BeginningOfName;
break;
default:
if ( !SkippingName ) {
*Destination = *Source;
Destination ++;
}
break;
}
Source ++;
}
//
// Remove any trailing delimiter
//
NumberOfCharacters = (Destination - WorkstationList->Buffer);
if ( NumberOfCharacters > 0 &&
WorkstationList->Buffer[NumberOfCharacters-1] == ' ' ) {
NumberOfCharacters--;
}
WorkstationList->Length = (USHORT) (NumberOfCharacters * sizeof(WCHAR));
}