779 lines
16 KiB
C
779 lines
16 KiB
C
|
/*++
|
|||
|
|
|||
|
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>
|
|||
|
#include <netsetp.h>
|
|||
|
|
|||
|
|
|||
|
#if(_WIN32_WINNT >= 0x0500)
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
NET_API_FUNCTION
|
|||
|
NetpSetDnsComputerNameAsRequired(
|
|||
|
IN PWSTR DnsDomainName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Determines if the machine is set to update the machine Dns computer name based on changes
|
|||
|
to the Dns domain name. If so, the new value is set. Otherwise, no action is taken.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DnsDomainName - New Dns domain name of this machine
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NERR_Success -- Success
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS NetStatus = NERR_Success;
|
|||
|
HKEY SyncKey;
|
|||
|
DWORD ValueType, Value, Length;
|
|||
|
BOOLEAN SetName = FALSE;
|
|||
|
PWCHAR AbsoluteSignifier = NULL;
|
|||
|
|
|||
|
if ( DnsDomainName == NULL ) {
|
|||
|
return ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See if we should be doing the name change
|
|||
|
//
|
|||
|
NetStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|||
|
L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
|
|||
|
0,
|
|||
|
KEY_QUERY_VALUE,
|
|||
|
&SyncKey );
|
|||
|
|
|||
|
if ( NetStatus == NERR_Success ) {
|
|||
|
|
|||
|
Length = sizeof( ULONG );
|
|||
|
NetStatus = RegQueryValueEx( SyncKey,
|
|||
|
L"SyncDomainWithMembership",
|
|||
|
NULL,
|
|||
|
&ValueType,
|
|||
|
( LPBYTE )&Value,
|
|||
|
&Length );
|
|||
|
if ( NetStatus == NERR_Success) {
|
|||
|
|
|||
|
if ( Value == 1 ) {
|
|||
|
|
|||
|
SetName = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
} else if ( NetStatus == ERROR_FILE_NOT_FOUND ) {
|
|||
|
|
|||
|
NetStatus = NERR_Success;
|
|||
|
SetName = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey( SyncKey );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ( NetStatus == NERR_Success && SetName == TRUE ) {
|
|||
|
|
|||
|
//
|
|||
|
// If we've got an absolute Dns domain name, shorten it up...
|
|||
|
//
|
|||
|
if ( wcslen(DnsDomainName) > 0 ) {
|
|||
|
AbsoluteSignifier = &DnsDomainName[ wcslen( DnsDomainName ) - 1 ];
|
|||
|
if ( *AbsoluteSignifier == L'.' ) {
|
|||
|
|
|||
|
*AbsoluteSignifier = UNICODE_NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
AbsoluteSignifier = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( !SetComputerNameEx( ComputerNamePhysicalDnsDomain, DnsDomainName ) ) {
|
|||
|
NetStatus = GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
if ( AbsoluteSignifier ) {
|
|||
|
|
|||
|
*AbsoluteSignifier = L'.';
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return( NetStatus );
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
if ( UserAccountControl & USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED ){
|
|||
|
Flags |= UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED;
|
|||
|
}
|
|||
|
|
|||
|
if ( UserAccountControl & USER_SMARTCARD_REQUIRED ){
|
|||
|
Flags |= UF_SMARTCARD_REQUIRED;
|
|||
|
}
|
|||
|
if ( UserAccountControl & USER_TRUSTED_FOR_DELEGATION ){
|
|||
|
Flags |= UF_TRUSTED_FOR_DELEGATION;
|
|||
|
}
|
|||
|
|
|||
|
if ( UserAccountControl & USER_NOT_DELEGATED ){
|
|||
|
Flags |= UF_NOT_DELEGATED;
|
|||
|
}
|
|||
|
|
|||
|
if ( UserAccountControl & USER_USE_DES_KEY_ONLY ){
|
|||
|
Flags |= UF_USE_DES_KEY_ONLY;
|
|||
|
}
|
|||
|
if ( UserAccountControl & USER_DONT_REQUIRE_PREAUTH) {
|
|||
|
Flags |= UF_DONT_REQUIRE_PREAUTH;
|
|||
|
}
|
|||
|
if ( UserAccountControl & USER_PASSWORD_EXPIRED) {
|
|||
|
Flags |= UF_PASSWORD_EXPIRED;
|
|||
|
}
|
|||
|
if ( UserAccountControl & USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
|
|||
|
Flags |= UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// 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 = (ULONG)(Destination - WorkstationList->Buffer);
|
|||
|
|
|||
|
if ( NumberOfCharacters > 0 &&
|
|||
|
WorkstationList->Buffer[NumberOfCharacters-1] == ' ' ) {
|
|||
|
|
|||
|
NumberOfCharacters--;
|
|||
|
}
|
|||
|
|
|||
|
WorkstationList->Length = (USHORT) (NumberOfCharacters * sizeof(WCHAR));
|
|||
|
|
|||
|
|
|||
|
}
|