933 lines
22 KiB
C
933 lines
22 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
security.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains services which perform access validation on
|
|||
|
attempts to access SAM objects. It also performs auditing on
|
|||
|
both open and close operations.
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Kelly (JimK) 6-July-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode - Win32
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Includes //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include <samsrvp.h>
|
|||
|
#include <ntseapi.h>
|
|||
|
#include <seopaque.h>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// private service prototypes //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SampRemoveAnonymousChangePasswordAccess(
|
|||
|
IN OUT PSECURITY_DESCRIPTOR Sd
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Routines //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampImpersonateNullSession(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Impersonates the null session token
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_CANNOT_IMPERSONATE - there is no null session token to imperonate
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SAMTRACE("SampImpersonateNullSession");
|
|||
|
|
|||
|
if (SampNullSessionToken == NULL) {
|
|||
|
return(STATUS_CANNOT_IMPERSONATE);
|
|||
|
}
|
|||
|
return( NtSetInformationThread(
|
|||
|
NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
(PVOID) &SampNullSessionToken,
|
|||
|
sizeof(HANDLE)
|
|||
|
) );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampRevertNullSession(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reverts a thread from impersonating the null session token.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_CANNOT_IMPERSONATE - there was no null session token to be
|
|||
|
imperonating.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
HANDLE NullHandle = NULL;
|
|||
|
|
|||
|
SAMTRACE("SampRevertNullSession");
|
|||
|
|
|||
|
if (SampNullSessionToken == NULL) {
|
|||
|
return(STATUS_CANNOT_IMPERSONATE);
|
|||
|
}
|
|||
|
|
|||
|
return( NtSetInformationThread(
|
|||
|
NtCurrentThread(),
|
|||
|
ThreadImpersonationToken,
|
|||
|
(PVOID) &NullHandle,
|
|||
|
sizeof(HANDLE)
|
|||
|
) );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampValidateObjectAccess(
|
|||
|
IN PSAMP_OBJECT Context,
|
|||
|
IN ACCESS_MASK DesiredAccess,
|
|||
|
IN BOOLEAN ObjectCreation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service performs access validation on the specified object.
|
|||
|
The security descriptor of the object is expected to be in a sub-key
|
|||
|
of the ObjectRootKey named "SecurityDescriptor".
|
|||
|
|
|||
|
|
|||
|
This service:
|
|||
|
|
|||
|
1) Retrieves the target object's SecurityDescriptor from the
|
|||
|
the ObjectRootKey,
|
|||
|
|
|||
|
2) Impersonates the client. If this fails, and we have a
|
|||
|
null session token to use, imperonate that.
|
|||
|
|
|||
|
3) Uses NtAccessCheckAndAuditAlarm() to validate access to the
|
|||
|
object,
|
|||
|
|
|||
|
4) Stops impersonating the client.
|
|||
|
|
|||
|
Upon successful completion, the passed context's GrantedAccess mask
|
|||
|
and AuditOnClose fields will be properly set to represent the results
|
|||
|
of the access validation. If the AuditOnClose field is set to TRUE,
|
|||
|
then the caller is responsible for calling SampAuditOnClose() when
|
|||
|
the object is closed.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - The handle value that will be assigned if the access validation
|
|||
|
is successful.
|
|||
|
|
|||
|
DesiredAccess - Specifies the accesses being requested to the target
|
|||
|
object.
|
|||
|
|
|||
|
ObjectCreation - A boolean flag indicated whether the access will
|
|||
|
result in a new object being created if granted. A value of TRUE
|
|||
|
indicates an object will be created, FALSE indicates an existing
|
|||
|
object will be opened.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - Indicates access has been granted.
|
|||
|
|
|||
|
Other values that may be returned are those returned by:
|
|||
|
|
|||
|
NtAccessCheckAndAuditAlarm()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS NtStatus, IgnoreStatus, AccessStatus;
|
|||
|
ULONG SecurityDescriptorLength;
|
|||
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|||
|
ACCESS_MASK MappedDesiredAccess;
|
|||
|
BOOLEAN TrustedClient;
|
|||
|
SAMP_OBJECT_TYPE ObjectType;
|
|||
|
PUNICODE_STRING ObjectName;
|
|||
|
ULONG DomainIndex;
|
|||
|
BOOLEAN ImpersonatingNullSession = FALSE;
|
|||
|
|
|||
|
SAMTRACE("SampValidateObjectAccess");
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Extract various fields from the account context
|
|||
|
//
|
|||
|
|
|||
|
TrustedClient = Context->TrustedClient;
|
|||
|
ObjectType = Context->ObjectType;
|
|||
|
DomainIndex = Context->DomainIndex;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Map the desired access
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
MappedDesiredAccess = DesiredAccess;
|
|||
|
RtlMapGenericMask(
|
|||
|
&MappedDesiredAccess,
|
|||
|
&SampObjectInformation[ ObjectType ].GenericMapping
|
|||
|
);
|
|||
|
|
|||
|
// This doesn't take ACCESS_SYSTEM_SECURITY into account.
|
|||
|
//
|
|||
|
//if ((SampObjectInformation[ObjectType].InvalidMappedAccess &
|
|||
|
// MappedDesiredAccess) != 0) {
|
|||
|
// return(STATUS_ACCESS_DENIED);
|
|||
|
//}
|
|||
|
|
|||
|
if (TrustedClient) {
|
|||
|
Context->GrantedAccess = MappedDesiredAccess;
|
|||
|
Context->AuditOnClose = FALSE;
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the string to use as an object name for auditing
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
switch (ObjectType) {
|
|||
|
|
|||
|
case SampServerObjectType:
|
|||
|
ObjectName = &SampServerObjectName;
|
|||
|
break;
|
|||
|
|
|||
|
case SampDomainObjectType:
|
|||
|
ObjectName = &SampDefinedDomains[DomainIndex].ExternalName;
|
|||
|
break;
|
|||
|
|
|||
|
case SampUserObjectType:
|
|||
|
case SampGroupObjectType:
|
|||
|
case SampAliasObjectType:
|
|||
|
ObjectName = &Context->RootName;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ASSERT(FALSE);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if ( NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Fetch the object security descriptor so we can validate
|
|||
|
// the access against it
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = SampGetObjectSD( Context, &SecurityDescriptorLength, &SecurityDescriptor);
|
|||
|
if ( NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// If this is a USER object, then we may have to mask the
|
|||
|
// ability for Anonymous logons to change passwords.
|
|||
|
//
|
|||
|
|
|||
|
if ( (ObjectType == SampUserObjectType) &&
|
|||
|
(SampDefinedDomains[DomainIndex].UnmodifiedFixed.PasswordProperties
|
|||
|
& DOMAIN_PASSWORD_NO_ANON_CHANGE) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Change our (local) copy of the object's DACL
|
|||
|
// so that it doesn't grant CHANGE_PASSWORD to
|
|||
|
// either WORLD or ANONYMOUS
|
|||
|
//
|
|||
|
|
|||
|
SampRemoveAnonymousChangePasswordAccess(SecurityDescriptor);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Impersonate the client. If RPC impersonation fails because
|
|||
|
// it is not supported (came in unauthenticated), then impersonate
|
|||
|
// the null session.
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
|
|||
|
|
|||
|
if (NtStatus == RPC_NT_CANNOT_SUPPORT) {
|
|||
|
NtStatus = SampImpersonateNullSession();
|
|||
|
ImpersonatingNullSession = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Access validate the client
|
|||
|
//
|
|||
|
|
|||
|
NtStatus = NtAccessCheckAndAuditAlarm(
|
|||
|
&SampSamSubsystem,
|
|||
|
(PVOID)Context,
|
|||
|
&SampObjectInformation[ ObjectType ].ObjectTypeName,
|
|||
|
ObjectName,
|
|||
|
SecurityDescriptor,
|
|||
|
MappedDesiredAccess,
|
|||
|
&SampObjectInformation[ ObjectType ].GenericMapping,
|
|||
|
ObjectCreation,
|
|||
|
&Context->GrantedAccess,
|
|||
|
&AccessStatus,
|
|||
|
&Context->AuditOnClose
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Stop impersonating the client
|
|||
|
//
|
|||
|
|
|||
|
if (ImpersonatingNullSession) {
|
|||
|
IgnoreStatus = SampRevertNullSession();
|
|||
|
}
|
|||
|
IgnoreStatus = I_RpcMapWin32Status(RpcRevertToSelf());
|
|||
|
ASSERT( NT_SUCCESS(IgnoreStatus) );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free up the security descriptor
|
|||
|
//
|
|||
|
|
|||
|
MIDL_user_free( SecurityDescriptor );
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we got an error back from the access check, return that as
|
|||
|
// status. Otherwise, return the access check status.
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(NtStatus);
|
|||
|
}
|
|||
|
|
|||
|
return(AccessStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SampAuditOnClose(
|
|||
|
IN PSAMP_OBJECT Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This service performs auditing necessary during a handle close operation.
|
|||
|
|
|||
|
This service may ONLY be called if the corresponding call to
|
|||
|
SampValidateObjectAccess() during openned returned TRUE.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - This must be the same value that was passed to the corresponding
|
|||
|
SampValidateObjectAccess() call. This value is used for auditing
|
|||
|
purposes only.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
SAMTRACE("SampAuditOnClose");
|
|||
|
|
|||
|
//FIX, FIX - Call NtAuditClose() (or whatever it is).
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
DBG_UNREFERENCED_PARAMETER( Context );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SampRemoveAnonymousChangePasswordAccess(
|
|||
|
IN OUT PSECURITY_DESCRIPTOR Sd
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine removes USER_CHANGE_PASSWORD access from
|
|||
|
any GRANT aces in the discretionary acl that have either
|
|||
|
the WORLD or ANONYMOUS SIDs in the ACE.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Sd - Is a pointer to a security descriptor of a SAM USER
|
|||
|
object.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PACL
|
|||
|
Dacl;
|
|||
|
|
|||
|
ULONG
|
|||
|
i,
|
|||
|
AceCount;
|
|||
|
|
|||
|
PACE_HEADER
|
|||
|
Ace;
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
DaclPresent,
|
|||
|
DaclDefaulted;
|
|||
|
|
|||
|
SAMTRACE("SampRemoveAnonymousChangePasswordAccess");
|
|||
|
|
|||
|
|
|||
|
RtlGetDaclSecurityDescriptor( Sd,
|
|||
|
&DaclPresent,
|
|||
|
&Dacl,
|
|||
|
&DaclDefaulted
|
|||
|
);
|
|||
|
|
|||
|
if ( !DaclPresent || (Dacl == NULL)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if ((AceCount = Dacl->AceCount) == 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for ( i = 0, Ace = FirstAce( Dacl ) ;
|
|||
|
i < AceCount ;
|
|||
|
i++, Ace = NextAce( Ace )
|
|||
|
) {
|
|||
|
|
|||
|
if ( !(((PACE_HEADER)Ace)->AceFlags & INHERIT_ONLY_ACE)) {
|
|||
|
|
|||
|
if ( (((PACE_HEADER)Ace)->AceType == ACCESS_ALLOWED_ACE_TYPE) ) {
|
|||
|
|
|||
|
if ( (RtlEqualSid( SampWorldSid, &((PACCESS_ALLOWED_ACE)Ace)->SidStart )) ||
|
|||
|
(RtlEqualSid( SampAnonymousSid, &((PACCESS_ALLOWED_ACE)Ace)->SidStart ))) {
|
|||
|
|
|||
|
//
|
|||
|
// Turn off CHANGE_PASSWORD access
|
|||
|
//
|
|||
|
|
|||
|
((PACCESS_ALLOWED_ACE)Ace)->Mask &= ~USER_CHANGE_PASSWORD;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SampCreateNullToken(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function creates a token representing a null logon.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The status value of the NtCreateToken() call.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
TOKEN_USER UserId;
|
|||
|
TOKEN_PRIMARY_GROUP PrimaryGroup;
|
|||
|
TOKEN_GROUPS GroupIds;
|
|||
|
TOKEN_PRIVILEGES Privileges;
|
|||
|
TOKEN_SOURCE SourceContext;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
SECURITY_QUALITY_OF_SERVICE ImpersonationQos;
|
|||
|
LARGE_INTEGER ExpirationTime;
|
|||
|
LUID LogonId = SYSTEM_LUID;
|
|||
|
|
|||
|
SAMTRACE("SampCreateNullToken");
|
|||
|
|
|||
|
|
|||
|
|
|||
|
UserId.User.Sid = SampWorldSid;
|
|||
|
UserId.User.Attributes = 0;
|
|||
|
GroupIds.GroupCount = 0;
|
|||
|
Privileges.PrivilegeCount = 0;
|
|||
|
PrimaryGroup.PrimaryGroup = SampWorldSid;
|
|||
|
ExpirationTime.LowPart = 0xfffffff;
|
|||
|
ExpirationTime.LowPart = 0x7ffffff;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Build a token source for SAM.
|
|||
|
//
|
|||
|
|
|||
|
Status = NtAllocateLocallyUniqueId( &SourceContext.SourceIdentifier );
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
strncpy(SourceContext.SourceName,"SamSS ",sizeof(SourceContext.SourceName));
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Set the object attributes to specify an Impersonation impersonation
|
|||
|
// level.
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
|
|||
|
ImpersonationQos.ImpersonationLevel = SecurityImpersonation;
|
|||
|
ImpersonationQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
|
|||
|
ImpersonationQos.EffectiveOnly = TRUE;
|
|||
|
ImpersonationQos.Length = (ULONG)sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|||
|
ObjectAttributes.SecurityQualityOfService = &ImpersonationQos;
|
|||
|
|
|||
|
Status = NtCreateToken(
|
|||
|
&SampNullSessionToken, // Handle
|
|||
|
(TOKEN_ALL_ACCESS), // DesiredAccess
|
|||
|
&ObjectAttributes, // ObjectAttributes
|
|||
|
TokenImpersonation, // TokenType
|
|||
|
&LogonId, // Authentication LUID
|
|||
|
&ExpirationTime, // Expiration Time
|
|||
|
&UserId, // User ID
|
|||
|
&GroupIds, // Group IDs
|
|||
|
&Privileges, // Privileges
|
|||
|
NULL, // Owner
|
|||
|
&PrimaryGroup, // Primary Group
|
|||
|
NULL, // Default Dacl
|
|||
|
&SourceContext // TokenSource
|
|||
|
);
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
SampSecureRpcInit(
|
|||
|
PVOID Ignored
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine waits for the NTLMSSP service to start and then registers
|
|||
|
security information with RPC to allow authenticated RPC to be used to
|
|||
|
SAM. It also registers an SPX endpoint if FPNW is installed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Ignored - required parameter for starting a thread.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
#define MAX_RPC_RETRIES 30
|
|||
|
|
|||
|
ULONG RpcStatus;
|
|||
|
ULONG RpcRetry;
|
|||
|
ULONG RpcSleepTime = 10 * 1000; // retry every ten seconds
|
|||
|
RPC_BINDING_VECTOR * BindingVector = NULL;
|
|||
|
|
|||
|
|
|||
|
SAMTRACE("SampSecureRpcInit");
|
|||
|
|
|||
|
|
|||
|
RpcStatus = RpcServerRegisterAuthInfoW(
|
|||
|
NULL, // server principal name
|
|||
|
RPC_C_AUTHN_WINNT,
|
|||
|
NULL, // no get key function
|
|||
|
NULL // no get key argument
|
|||
|
);
|
|||
|
|
|||
|
if (RpcStatus != 0) {
|
|||
|
KdPrint(("SAMSS: Could not register auth. info: %d\n",
|
|||
|
RpcStatus ));
|
|||
|
goto ErrorReturn;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the Netware server is installed, register the SPX protocol.
|
|||
|
// Since the transport may not be loaded yet, retry a couple of times
|
|||
|
// if we get a CANT_CREATE_ENDPOINT error (meaning the transport isn't
|
|||
|
// there).
|
|||
|
//
|
|||
|
|
|||
|
if (SampNetwareServerInstalled) {
|
|||
|
|
|||
|
RpcRetry = MAX_RPC_RETRIES;
|
|||
|
while (RpcRetry != 0) {
|
|||
|
|
|||
|
RpcStatus = RpcServerUseProtseqW(
|
|||
|
L"ncacn_spx",
|
|||
|
10,
|
|||
|
NULL // no security descriptor
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If it succeded break out of the loop.
|
|||
|
//
|
|||
|
if (RpcStatus == ERROR_SUCCESS) {
|
|||
|
break;
|
|||
|
}
|
|||
|
Sleep(RpcSleepTime);
|
|||
|
RpcRetry--;
|
|||
|
continue;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (RpcStatus != 0) {
|
|||
|
KdPrint(("SAMSS: Could not register SPX endpoint: %d\n", RpcStatus ));
|
|||
|
goto ErrorReturn;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// do the same thing all over again with TcpIp
|
|||
|
//
|
|||
|
|
|||
|
if (SampIpServerInstalled) {
|
|||
|
|
|||
|
RpcRetry = MAX_RPC_RETRIES;
|
|||
|
while (RpcRetry != 0) {
|
|||
|
|
|||
|
RpcStatus = RpcServerUseProtseqW(
|
|||
|
L"ncacn_ip_tcp",
|
|||
|
10,
|
|||
|
NULL // no security descriptor
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If it succeeded, break out of the loop.
|
|||
|
//
|
|||
|
|
|||
|
if (RpcStatus == ERROR_SUCCESS) {
|
|||
|
break;
|
|||
|
}
|
|||
|
Sleep(RpcSleepTime);
|
|||
|
RpcRetry--;
|
|||
|
continue;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (RpcStatus != 0) {
|
|||
|
KdPrint(("SAMSS: Could not register TCP endpoint: %d\n", RpcStatus ));
|
|||
|
goto ErrorReturn;
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we started Tcp/Ip or Spx, go on to register the endpoints
|
|||
|
//
|
|||
|
|
|||
|
if (SampNetwareServerInstalled || SampIpServerInstalled) {
|
|||
|
RpcStatus = RpcServerInqBindings(&BindingVector);
|
|||
|
if (RpcStatus != 0) {
|
|||
|
KdPrint(("SAMSS: Could not inq bindings: %d\n",RpcStatus));
|
|||
|
goto ErrorReturn;
|
|||
|
}
|
|||
|
RpcStatus = RpcEpRegister(
|
|||
|
samr_ServerIfHandle,
|
|||
|
BindingVector,
|
|||
|
NULL, // no uuid vector
|
|||
|
L"" // no annotation
|
|||
|
);
|
|||
|
|
|||
|
RpcBindingVectorFree(&BindingVector);
|
|||
|
if (RpcStatus != 0) {
|
|||
|
KdPrint(("SAMSS: Could not register endpoints: %d\n",RpcStatus));
|
|||
|
goto ErrorReturn;
|
|||
|
}
|
|||
|
}
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
|
|||
|
ErrorReturn:
|
|||
|
|
|||
|
SampWriteEventLog(
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0, // Category
|
|||
|
SAMMSG_RPC_INIT_FAILED,
|
|||
|
NULL, // User Sid
|
|||
|
0, // Num strings
|
|||
|
sizeof(NTSTATUS), // Data size
|
|||
|
NULL, // String array
|
|||
|
(PVOID)&RpcStatus // Data
|
|||
|
);
|
|||
|
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SampStartNonNamedPipeTransports(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks to see if we should listen on a non-named pipe
|
|||
|
transport. We check the registry for flags indicating that we should
|
|||
|
listen on Tcp/Ip and SPX. There is a flag
|
|||
|
in the registry under system\currentcontrolset\Control\Lsa\
|
|||
|
NetwareClientSupport and TcpipClientSupport indicating whether or not
|
|||
|
to setup the endpoint.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - Netware (FPNW or SmallWorld) is installed and the SPX endpoint
|
|||
|
should be started.
|
|||
|
|
|||
|
FALSE - Either Netware is not installed, or an error occurred while
|
|||
|
checking for it.
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS NtStatus;
|
|||
|
UNICODE_STRING KeyName;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
HANDLE KeyHandle;
|
|||
|
UCHAR Buffer[100];
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
|
|||
|
ULONG KeyValueLength = 100;
|
|||
|
ULONG ResultLength;
|
|||
|
PULONG SpxFlag;
|
|||
|
|
|||
|
SAMTRACE("SampStartNonNamedPipeTransport");
|
|||
|
|
|||
|
SampNetwareServerInstalled = FALSE;
|
|||
|
SampIpServerInstalled = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Open the Lsa key in the registry
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(
|
|||
|
&KeyName,
|
|||
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa"
|
|||
|
);
|
|||
|
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&KeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
SampDumpNtOpenKey((KEY_READ), &ObjectAttributes, 0);
|
|||
|
|
|||
|
NtStatus = NtOpenKey(
|
|||
|
&KeyHandle,
|
|||
|
KEY_READ,
|
|||
|
&ObjectAttributes
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(NtStatus)) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the NetwareClientSupport value
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(
|
|||
|
&KeyName,
|
|||
|
L"NetWareClientSupport"
|
|||
|
);
|
|||
|
|
|||
|
NtStatus = NtQueryValueKey(
|
|||
|
KeyHandle,
|
|||
|
&KeyName,
|
|||
|
KeyValuePartialInformation,
|
|||
|
KeyValueInformation,
|
|||
|
KeyValueLength,
|
|||
|
&ResultLength
|
|||
|
);
|
|||
|
|
|||
|
SampDumpNtQueryValueKey(&KeyName,
|
|||
|
KeyValuePartialInformation,
|
|||
|
KeyValueInformation,
|
|||
|
KeyValueLength,
|
|||
|
&ResultLength);
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Check that the data is the correct size and type - a ULONG.
|
|||
|
//
|
|||
|
|
|||
|
if ((KeyValueInformation->DataLength >= sizeof(ULONG)) &&
|
|||
|
(KeyValueInformation->Type == REG_DWORD)) {
|
|||
|
|
|||
|
|
|||
|
SpxFlag = (PULONG) KeyValueInformation->Data;
|
|||
|
|
|||
|
if (*SpxFlag == 1) {
|
|||
|
SampNetwareServerInstalled = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
//
|
|||
|
// Query the Tcp/IpClientSupport value
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(
|
|||
|
&KeyName,
|
|||
|
L"TcpipClientSupport"
|
|||
|
);
|
|||
|
|
|||
|
NtStatus = NtQueryValueKey(
|
|||
|
KeyHandle,
|
|||
|
&KeyName,
|
|||
|
KeyValuePartialInformation,
|
|||
|
KeyValueInformation,
|
|||
|
KeyValueLength,
|
|||
|
&ResultLength
|
|||
|
);
|
|||
|
|
|||
|
SampDumpNtQueryValueKey(&KeyName,
|
|||
|
KeyValuePartialInformation,
|
|||
|
KeyValueInformation,
|
|||
|
KeyValueLength,
|
|||
|
&ResultLength);
|
|||
|
|
|||
|
|
|||
|
if (NT_SUCCESS(NtStatus)) {
|
|||
|
|
|||
|
//
|
|||
|
// Check that the data is the correct size and type - a ULONG.
|
|||
|
//
|
|||
|
|
|||
|
if ((KeyValueInformation->DataLength >= sizeof(ULONG)) &&
|
|||
|
(KeyValueInformation->Type == REG_DWORD)) {
|
|||
|
|
|||
|
|
|||
|
SpxFlag = (PULONG) KeyValueInformation->Data;
|
|||
|
|
|||
|
if (*SpxFlag == 1) {
|
|||
|
SampIpServerInstalled = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NtClose(KeyHandle);
|
|||
|
|
|||
|
if (SampNetwareServerInstalled || SampIpServerInstalled)
|
|||
|
{
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(FALSE);
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
|