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.
1106 lines
28 KiB
1106 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbmisc.c
|
|
|
|
Abstract:
|
|
|
|
Local Security Authority - Miscellaneous API
|
|
|
|
This file contains worker routines for miscellaneous API that are
|
|
not specific to objects of a given type.
|
|
|
|
Author:
|
|
|
|
Scott Birrell (ScottBi) January 15, 1992
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <lsapch2.h>
|
|
#include "dbp.h"
|
|
#include "lsawmi.h"
|
|
#include <names.h>
|
|
#include <windns.h>
|
|
#include <alloca.h>
|
|
#include "adtp.h"
|
|
|
|
NTSTATUS
|
|
LsarClose(
|
|
IN OUT LSAPR_HANDLE *ObjectHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the LSA server RPC worker routine for the LsaClose
|
|
API.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle returned from an LsaOpen<object type> or
|
|
LsaCreate<object type> call.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return LsapCloseHandle(
|
|
ObjectHandle,
|
|
STATUS_SUCCESS
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
LsapCloseHandle(
|
|
IN OUT LSAPR_HANDLE *ObjectHandle,
|
|
IN NTSTATUS PreliminaryStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the LSA server RPC worker routine for the LsaClose
|
|
API.
|
|
|
|
The LsaClose API closes a handle to an open object within the database.
|
|
If closing a handle to the Policy object and there are no objects still
|
|
open within the current connection to the LSA, the connection is closed.
|
|
If a handle to an object within the database is closed and the object is
|
|
marked for DELETE access, the object will be deleted when the last handle
|
|
to that object is closed.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle returned from an LsaOpen<object type> or
|
|
LsaCreate<object type> call.
|
|
|
|
PreliminaryStatus - Status of the operation. Used to decide whether
|
|
to abort or commit a transaction.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LSAP_DB_HANDLE InternalHandle = *ObjectHandle;
|
|
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapCloseHandle\n" ));
|
|
|
|
LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_Close);
|
|
|
|
if ( *ObjectHandle == NULL ) {
|
|
|
|
Status = STATUS_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ObjectTypeId = InternalHandle->ObjectTypeId;
|
|
|
|
if ( *ObjectHandle == LsapPolicyHandle ) {
|
|
|
|
#if DBG
|
|
DbgPrint("Closing global policy handle!!!\n");
|
|
#endif
|
|
|
|
DbgBreakPoint();
|
|
Status = STATUS_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Acquire the Lsa Database Lock
|
|
//
|
|
LsapDbAcquireLockEx( ObjectTypeId,
|
|
LSAP_DB_READ_ONLY_TRANSACTION );
|
|
|
|
//
|
|
// Validate and close the object handle, dereference its container (if any).
|
|
//
|
|
|
|
Status = LsapDbCloseObject(
|
|
ObjectHandle,
|
|
LSAP_DB_VALIDATE_HANDLE |
|
|
LSAP_DB_DEREFERENCE_CONTR |
|
|
LSAP_DB_ADMIT_DELETED_OBJECT_HANDLES |
|
|
LSAP_DB_READ_ONLY_TRANSACTION |
|
|
LSAP_DB_DS_OP_TRANSACTION,
|
|
PreliminaryStatus
|
|
);
|
|
|
|
LsapDbReleaseLockEx( ObjectTypeId,
|
|
LSAP_DB_READ_ONLY_TRANSACTION );
|
|
|
|
Cleanup:
|
|
|
|
*ObjectHandle = NULL;
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsapCloseHandle: 0x%lx\n", Status ));
|
|
|
|
LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_Close);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsarDeleteObject(
|
|
IN OUT LSAPR_HANDLE *ObjectHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the LSA server RPC worker routine for the LsaDelete
|
|
API.
|
|
|
|
The LsaDelete API deletes an object from the LSA Database. The object must be
|
|
open for DELETE access.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Pointer to Handle from an LsaOpen<object type> or
|
|
LsaCreate<object type> call. On return, this location will contain
|
|
NULL if the call is successful.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
|
to complete the operation.
|
|
|
|
STATUS_OBJECT_NAME_NOT_FOUND - There is no object in the
|
|
target system's LSA Database having the name and type specified
|
|
by the handle.
|
|
--*/
|
|
|
|
{
|
|
return LsapDeleteObject( ObjectHandle , TRUE );
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapDeleteObject(
|
|
IN OUT LSAPR_HANDLE *ObjectHandle,
|
|
IN BOOL LockSce
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the worker routine for LsarDeleteObject, with an added
|
|
semantics of not locking the SCE policy.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
NTSTATUS IgnoreStatus;
|
|
LSAP_DB_HANDLE InternalHandle = *ObjectHandle;
|
|
BOOLEAN ObjectReferenced = FALSE;
|
|
ULONG ReferenceOptions = LSAP_DB_START_TRANSACTION |
|
|
LSAP_DB_LOCK ;
|
|
ULONG DereferenceOptions = LSAP_DB_FINISH_TRANSACTION |
|
|
LSAP_DB_LOCK |
|
|
LSAP_DB_DEREFERENCE_CONTR;
|
|
|
|
PLSAPR_TRUST_INFORMATION TrustInformation = NULL;
|
|
LSAPR_TRUST_INFORMATION OutputTrustInformation;
|
|
BOOLEAN TrustInformationPresent = FALSE;
|
|
LSAP_DB_OBJECT_TYPE_ID ObjectTypeId;
|
|
PTRUSTED_DOMAIN_INFORMATION_EX CurrentTrustedDomainInfoEx = NULL;
|
|
BOOLEAN ScePolicyLocked = FALSE;
|
|
BOOLEAN NotifySce = FALSE;
|
|
SECURITY_DB_OBJECT_TYPE ObjectType = SecurityDbObjectLsaPolicy;
|
|
PSID ObjectSid = NULL;
|
|
BOOL RevertResult = FALSE;
|
|
BOOL Impersonating = FALSE;
|
|
|
|
LsarpReturnCheckSetup();
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsarDeleteObject\n" ));
|
|
|
|
ObjectTypeId = InternalHandle->ObjectTypeId;
|
|
|
|
//
|
|
// The LSA will only call SceNotify if the policy change was made via a handle
|
|
// not marked 'SCE handle'. This prevents SCE from being notified of its own
|
|
// changes. This is required to ensure that policy read from the LSA matches
|
|
// that written by a non-SCE application.
|
|
//
|
|
|
|
if ( !InternalHandle->SceHandle &&
|
|
!InternalHandle->SceHandleChild ) {
|
|
|
|
switch ( ObjectTypeId ) {
|
|
|
|
case AccountObject: {
|
|
|
|
ULONG SidLength;
|
|
ASSERT( InternalHandle->Sid );
|
|
|
|
SidLength = RtlLengthSid( InternalHandle->Sid );
|
|
ObjectSid = ( PSID )LsapAllocateLsaHeap( SidLength );
|
|
if ( ObjectSid ) {
|
|
|
|
RtlCopyMemory( ObjectSid, InternalHandle->Sid, SidLength );
|
|
|
|
} else {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto DeleteObjectError;
|
|
}
|
|
|
|
ObjectType = SecurityDbObjectLsaAccount;
|
|
|
|
// FALLTHRU
|
|
}
|
|
|
|
case PolicyObject:
|
|
|
|
if ( LockSce ) {
|
|
|
|
RtlEnterCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
|
|
if ( LsapDbState.ScePolicyLock.NumberOfWaitingShared > MAX_SCE_WAITING_SHARED ) {
|
|
|
|
Status = STATUS_TOO_MANY_THREADS;
|
|
}
|
|
RtlLeaveCriticalSection( &LsapDbState.ScePolicyLock.CriticalSection );
|
|
|
|
if ( !NT_SUCCESS( Status )) {
|
|
|
|
goto DeleteObjectError;
|
|
}
|
|
|
|
WaitForSingleObject( LsapDbState.SceSyncEvent, INFINITE );
|
|
RtlAcquireResourceShared( &LsapDbState.ScePolicyLock, TRUE );
|
|
ASSERT( !g_ScePolicyLocked );
|
|
ScePolicyLocked = TRUE;
|
|
}
|
|
|
|
NotifySce = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify that the Object handle is valid, is of the expected type and
|
|
// has all of the desired accesses granted. Reference the handle and
|
|
// open a database transaction.
|
|
//
|
|
|
|
Status = LsapDbReferenceObject(
|
|
*ObjectHandle,
|
|
DELETE,
|
|
ObjectTypeId,
|
|
ObjectTypeId,
|
|
ReferenceOptions
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto DeleteObjectError;
|
|
}
|
|
|
|
ObjectReferenced = TRUE;
|
|
|
|
//
|
|
// Perform object type specific pre-processing. Note that some
|
|
// pre-processing is also done within LsapDbReferenceObject(), for
|
|
// example, for local secrets.
|
|
//
|
|
|
|
switch (ObjectTypeId) {
|
|
|
|
case PolicyObject:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
|
|
case TrustedDomainObject:
|
|
|
|
if ( LsapDsWriteDs && InternalHandle->Sid == NULL ) {
|
|
|
|
BOOLEAN TrustedStatus = InternalHandle->Trusted;
|
|
|
|
//
|
|
// Toggle trusted bit so that access cks do not prevent following
|
|
// query from succeeding
|
|
//
|
|
|
|
InternalHandle->Trusted = TRUE;
|
|
|
|
Status = LsarQueryInfoTrustedDomain( *ObjectHandle,
|
|
TrustedDomainInformationEx,
|
|
(PLSAPR_TRUSTED_DOMAIN_INFO *)
|
|
&CurrentTrustedDomainInfoEx );
|
|
|
|
InternalHandle->Trusted = TrustedStatus;
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
InternalHandle->Sid = CurrentTrustedDomainInfoEx->Sid;
|
|
CurrentTrustedDomainInfoEx->Sid = NULL;
|
|
|
|
} else {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"Query for TD Sid failed with 0x%lx\n", Status ));
|
|
}
|
|
}
|
|
|
|
if (LsapAdtAuditingEnabledHint(AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS)) {
|
|
|
|
//
|
|
// If we're auditing deletions of TrustedDomain objects, we need
|
|
// to retrieve the TrustedDomain name and keep it for later when
|
|
// we generate the audit.
|
|
//
|
|
|
|
Status = LsapDbAcquireReadLockTrustedDomainList();
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
Status = LsapDbLookupSidTrustedDomainList(
|
|
InternalHandle->Sid,
|
|
&TrustInformation
|
|
);
|
|
|
|
if (STATUS_NO_SUCH_DOMAIN==Status)
|
|
{
|
|
//
|
|
// If we could not find by the SID, then lookup by the logical name
|
|
// field.
|
|
//
|
|
|
|
Status = LsapDbLookupNameTrustedDomainList(
|
|
(PLSAPR_UNICODE_STRING) &InternalHandle->LogicalNameU,
|
|
&TrustInformation
|
|
);
|
|
}
|
|
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
Status = LsapRpcCopyTrustInformation(
|
|
NULL,
|
|
&OutputTrustInformation,
|
|
TrustInformation
|
|
);
|
|
|
|
TrustInformationPresent = NT_SUCCESS( Status );
|
|
}
|
|
|
|
LsapDbReleaseLockTrustedDomainList();
|
|
}
|
|
|
|
//
|
|
// Reset the status to SUCCESS. Failure to get the information for
|
|
// auditing should not be a failure to delete
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
//
|
|
// Notify netlogon. Potentially ignore any failures
|
|
//
|
|
Status = LsapNotifyNetlogonOfTrustChange( InternalHandle->Sid,
|
|
SecurityDbDelete );
|
|
#if DBG
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"LsapNotifyNetlogonOfTrustChange failed with an unexpected 0x%lx\n",
|
|
Status ));
|
|
ASSERT( NT_SUCCESS(Status) );
|
|
}
|
|
#endif
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AccountObject:
|
|
|
|
{
|
|
PLSAPR_PRIVILEGE_SET Privileges;
|
|
LSAPR_HANDLE AccountHandle;
|
|
PLSAPR_SID AccountSid = NULL;
|
|
ULONG AuditEventId;
|
|
|
|
AccountHandle = *ObjectHandle;
|
|
|
|
AccountSid = LsapDbSidFromHandle( AccountHandle );
|
|
|
|
if (LsapAdtAuditingEnabledHint(AuditCategoryPolicyChange, EVENTLOG_AUDIT_SUCCESS)) {
|
|
|
|
Status = LsarEnumeratePrivilegesAccount(
|
|
AccountHandle,
|
|
&Privileges
|
|
);
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
|
|
LsapDsDebugOut(( DEB_ERROR,
|
|
"LsarEnumeratePrivilegesAccount ret'd %x\n", Status ));
|
|
break;
|
|
}
|
|
|
|
|
|
AuditEventId = SE_AUDITID_USER_RIGHT_REMOVED;
|
|
|
|
//
|
|
// Audit the privilege set change. Ignore failures from Auditing.
|
|
//
|
|
|
|
IgnoreStatus = LsapAdtGenerateLsaAuditEvent(
|
|
AccountHandle,
|
|
SE_CATEGID_POLICY_CHANGE,
|
|
AuditEventId,
|
|
(PPRIVILEGE_SET)Privileges,
|
|
1,
|
|
(PSID *) &AccountSid,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
MIDL_user_free( Privileges );
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SecretObject:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto DeleteObjectError;
|
|
}
|
|
|
|
Status = LsapDbDeleteObject( *ObjectHandle );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto DeleteObjectError;
|
|
}
|
|
|
|
//
|
|
// Decrement the Reference Count so that the object's handle will be
|
|
// freed upon dereference.
|
|
//
|
|
|
|
LsapDbDereferenceHandle( *ObjectHandle, TRUE );
|
|
|
|
//
|
|
// Perform object post-processing. The only post-processing is
|
|
// the auditing of TrustedDomain object deletion.
|
|
//
|
|
|
|
if (TrustInformationPresent && LsapAdtAuditingEnabledHint(
|
|
AuditCategoryPolicyChange,
|
|
EVENTLOG_AUDIT_SUCCESS)) {
|
|
|
|
if (ObjectTypeId == TrustedDomainObject) {
|
|
|
|
(void) LsapAdtTrustedDomainRem(
|
|
EVENTLOG_AUDIT_SUCCESS,
|
|
(PUNICODE_STRING) &OutputTrustInformation.Name,
|
|
InternalHandle->Sid,
|
|
NULL, // UserSid
|
|
NULL // UserAuthenticationId
|
|
);
|
|
|
|
//
|
|
// Call fgs routine because we want to free the graph of the
|
|
// structure, but not the top level of the structure.
|
|
//
|
|
|
|
_fgs__LSAPR_TRUST_INFORMATION ( &OutputTrustInformation );
|
|
TrustInformation = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete new object from the in-memory cache (if any)
|
|
//
|
|
|
|
if ( ObjectTypeId == AccountObject &&
|
|
LsapDbIsCacheSupported( AccountObject ) &&
|
|
LsapDbIsCacheValid( AccountObject )) {
|
|
|
|
IgnoreStatus = LsapDbDeleteAccount( InternalHandle->Sid );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// impersonate the client so that audit event shows correct user
|
|
// Do this only for untrusted clients
|
|
//
|
|
|
|
if ( !InternalHandle->Trusted ) {
|
|
|
|
if ( InternalHandle->Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
|
|
|
|
IgnoreStatus = LsapImpersonateClient( );
|
|
|
|
} else {
|
|
|
|
IgnoreStatus = I_RpcMapWin32Status(RpcImpersonateClient(0));
|
|
}
|
|
|
|
if ( NT_SUCCESS(IgnoreStatus) ) {
|
|
|
|
Impersonating = TRUE;
|
|
}
|
|
else if ( ( IgnoreStatus == RPC_NT_NO_CALL_ACTIVE ) ||
|
|
( IgnoreStatus == RPC_NT_NO_CONTEXT_AVAILABLE ) ) {
|
|
|
|
//
|
|
// we dont want to fail the audit if
|
|
// -- the call is not over RPC (RPC_NT_NO_CALL_ACTIVE)
|
|
// -- the client died prematurely (RPC_NT_NO_CONTEXT_AVAILABLE)
|
|
//
|
|
|
|
IgnoreStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
DsysAssertMsg( NT_SUCCESS(IgnoreStatus), "LsapDeleteObject: failed to impersonate" );
|
|
|
|
if (!NT_SUCCESS( IgnoreStatus )) {
|
|
LsapAuditFailed( IgnoreStatus );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Audit the deletion
|
|
//
|
|
|
|
IgnoreStatus = NtDeleteObjectAuditAlarm( &LsapState.SubsystemName,
|
|
*ObjectHandle,
|
|
InternalHandle->GenerateOnClose);
|
|
|
|
//
|
|
// unimpersonate
|
|
//
|
|
|
|
|
|
if ( !InternalHandle->Trusted ) {
|
|
|
|
if ( Impersonating ) {
|
|
|
|
if ( InternalHandle->Options & LSAP_DB_USE_LPC_IMPERSONATE ) {
|
|
|
|
RevertResult = RevertToSelf();
|
|
DsysAssertMsg( RevertResult, "LsapDeleteObject: RevertToSelf() failed" );
|
|
|
|
} else {
|
|
|
|
IgnoreStatus = I_RpcMapWin32Status(RpcRevertToSelf());
|
|
|
|
DsysAssertMsg( NT_SUCCESS(IgnoreStatus), "LsapDeleteObject: RpcRevertToSelf() failed" );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DeleteObjectFinish:
|
|
|
|
//
|
|
// If we referenced the object, dereference it, close the database
|
|
// transaction, notify the replicator of the delete, release the LSA
|
|
// Database lock and return.
|
|
//
|
|
|
|
if (ObjectReferenced) {
|
|
|
|
Status = LsapDbDereferenceObject(
|
|
ObjectHandle,
|
|
ObjectTypeId,
|
|
ObjectTypeId,
|
|
DereferenceOptions,
|
|
SecurityDbDelete,
|
|
Status
|
|
);
|
|
|
|
ObjectReferenced = FALSE;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
goto DeleteObjectError;
|
|
}
|
|
}
|
|
|
|
if ( CurrentTrustedDomainInfoEx ) {
|
|
LsaIFree_LSAPR_TRUSTED_DOMAIN_INFO(
|
|
TrustedDomainInformationEx,
|
|
(PLSAPR_TRUSTED_DOMAIN_INFO) CurrentTrustedDomainInfoEx );
|
|
}
|
|
|
|
//
|
|
// Notify SCE of the change. Only notify for callers
|
|
// that did not open their policy handles with LsaOpenPolicySce.
|
|
//
|
|
|
|
if ( NotifySce && NT_SUCCESS( Status )) {
|
|
|
|
LsapSceNotify(
|
|
SecurityDbDelete,
|
|
ObjectType,
|
|
ObjectSid
|
|
);
|
|
}
|
|
|
|
if ( ScePolicyLocked ) {
|
|
|
|
RtlReleaseResource( &LsapDbState.ScePolicyLock );
|
|
}
|
|
|
|
if ( ObjectSid ) {
|
|
|
|
LsapFreeLsaHeap( ObjectSid );
|
|
}
|
|
|
|
LsarpReturnPrologue();
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsarDeleteObject: 0x%lx\n", Status ));
|
|
|
|
//
|
|
// Under all circumstances tell RPC we're done with this handle
|
|
//
|
|
*ObjectHandle = NULL;
|
|
return(Status);
|
|
|
|
DeleteObjectError:
|
|
|
|
goto DeleteObjectFinish;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsarDelete(
|
|
IN LSAPR_HANDLE ObjectHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the former LSA server RPC worker routine for the
|
|
LsaDelete API. It has been termorarily retained for compatibility
|
|
with pre Beta 2 versions 1.369 and earlier of the system. It has been
|
|
necessary to replace this routine with a new one, LsarDeleteObject(),
|
|
on the RPC interface. This is because, like LsarClose(), a pointer to a
|
|
handle is required rather than a handle so that LsarDeleteObject() can
|
|
inform the RPC server calling stub that the handle has been deleted by
|
|
returning NULL. The client wrapper for LsaDelete() will try to call
|
|
LsarDeleteObject(). If the server code does not contain this interface,
|
|
the client will call LsarDelete(). In this event, the server's
|
|
LSAPR_HANDLE_rundown() routine may attempt to rundown the handle after it
|
|
has been deleted (versions 1.363 - 369 only).
|
|
|
|
The LsaDelete API deletes an object from the LSA Database. The object must be
|
|
open for DELETE access.
|
|
|
|
Arguments:
|
|
|
|
ObjectHandle - Handle from an LsaOpen<object type> or LsaCreate<object type>
|
|
call.
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
|
to complete the operation.
|
|
|
|
STATUS_OBJECT_NAME_NOT_FOUND - There is no object in the
|
|
target system's LSA Database having the name and type specified
|
|
by the handle.
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Call the replacement routine LsarDeleteObject()
|
|
//
|
|
|
|
return( LsarDeleteObject((LSAPR_HANDLE *) &ObjectHandle));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsarChangePassword(
|
|
IN PLSAPR_UNICODE_STRING ServerName,
|
|
IN PLSAPR_UNICODE_STRING DomainName,
|
|
IN PLSAPR_UNICODE_STRING AccountName,
|
|
IN PLSAPR_UNICODE_STRING OldPassword,
|
|
IN PLSAPR_UNICODE_STRING NewPassword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The LsaChangePassword API is used to change a user account's password.
|
|
The user must have appropriate access to the user account and must
|
|
know the current password value.
|
|
|
|
|
|
Arguments:
|
|
|
|
ServerName - The name of the Domain Controller at which the password
|
|
can be changed.
|
|
|
|
DomainName - The name of the domain in which the account exists.
|
|
|
|
AccountName - The name of the account whose password is to be changed.
|
|
|
|
NewPassword - The new password value.
|
|
|
|
OldPassword - The old (current) password value.
|
|
|
|
Return Values:
|
|
|
|
NTSTATUS - Standard Nt Result Code
|
|
|
|
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
|
to complete the operation.
|
|
|
|
STATUS_ILL_FORMED_PASSWORD - The new password is poorly formed, e.g.
|
|
contains characters that can't be entered from the keyboard.
|
|
|
|
STATUS_PASSWORD_RESTRICTION - A restriction prevents the password
|
|
from being changed. This may be for an number of reasons,
|
|
including time restrictions on how often a password may be changed
|
|
or length restrictions on the provided (new) password.
|
|
|
|
This error might also be returned if the new password matched
|
|
a password in the recent history log for the account. Security
|
|
administrators indicate how many of the most recently used
|
|
passwords may not be re-used.
|
|
|
|
STATUS_WRONG_PASSWORD - OldPassword does not contain the user's
|
|
current password.
|
|
|
|
STATUS_NO_SUCH_USER - The SID provided does not lead to a user
|
|
account.
|
|
|
|
STATUS_CANT_UPDATE_MASTER - An attempt to update the master copy
|
|
of the password was unsuccessful. Please try again later.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
LsarpReturnCheckSetup();
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsarChangePassword\n" ));
|
|
|
|
|
|
DBG_UNREFERENCED_PARAMETER( ServerName );
|
|
DBG_UNREFERENCED_PARAMETER( DomainName );
|
|
DBG_UNREFERENCED_PARAMETER( AccountName );
|
|
DBG_UNREFERENCED_PARAMETER( OldPassword );
|
|
DBG_UNREFERENCED_PARAMETER( NewPassword );
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
LsarpReturnPrologue();
|
|
|
|
LsapDsDebugOut(( DEB_FTRACE, "LsarChangePassword: 0x%lx\n", Status ));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapDbIsRpcClientNetworkClient(
|
|
OUT PBOOLEAN IsNetworkClient
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This call is used to determine if the current RPC call is from
|
|
a network client (came in via the network as opposed to locally)
|
|
or not.
|
|
|
|
Arguments:
|
|
|
|
IsNetworkClient - Pointer to a BOOLEAN that gets set to the results
|
|
of whether this is a network client or not
|
|
|
|
Return Values:
|
|
|
|
STATUS_SUCCESS - Success
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
unsigned int ClientLocalFlag;
|
|
|
|
|
|
RpcStatus = I_RpcBindingIsClientLocal ( NULL, &ClientLocalFlag );
|
|
|
|
if ( RpcStatus != RPC_S_OK ) {
|
|
return I_RpcMapWin32Status( RpcStatus );
|
|
}
|
|
|
|
*IsNetworkClient = (ClientLocalFlag == 0);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsapValidateNetbiosName(
|
|
IN const UNICODE_STRING * Name,
|
|
OUT BOOLEAN * Valid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validates that a NetBIOS name conforms to certain minimum standards.
|
|
For more details, see the description of NetpIsDomainNameValid.
|
|
|
|
Arguments:
|
|
|
|
Name name to validate
|
|
|
|
Valid will be set to TRUE if validation checks out, FALSE otherwise
|
|
|
|
Returns:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
WCHAR * Buffer;
|
|
BOOLEAN BufferAllocated = FALSE;
|
|
|
|
ASSERT( Name );
|
|
ASSERT( Valid );
|
|
ASSERT( LsapValidateLsaUnicodeString( Name ));
|
|
|
|
//
|
|
// Empty names and names that are too long are not allowed
|
|
//
|
|
|
|
if ( Name->Length == 0 ||
|
|
Name->Length > DNLEN * sizeof( WCHAR )) {
|
|
|
|
*Valid = FALSE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( Name->MaximumLength > Name->Length ) {
|
|
|
|
Buffer = Name->Buffer;
|
|
|
|
} else {
|
|
|
|
SafeAllocaAllocate( Buffer, Name->Length + sizeof( WCHAR ));
|
|
|
|
if ( Buffer == NULL ) {
|
|
|
|
*Valid = FALSE;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
BufferAllocated = TRUE;
|
|
|
|
RtlCopyMemory( Buffer, Name->Buffer, Name->Length );
|
|
}
|
|
|
|
Buffer[Name->Length / sizeof( WCHAR )] = L'\0';
|
|
|
|
*Valid = ( TRUE == NetpIsDomainNameValid( Buffer ));
|
|
|
|
if ( BufferAllocated ) {
|
|
|
|
SafeAllocaFree( Buffer );
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
LsapValidateDnsName(
|
|
IN const UNICODE_STRING * Name,
|
|
OUT BOOLEAN * Valid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validates that a DNS name conforms to certain minimum standards.
|
|
|
|
Arguments:
|
|
|
|
Name name to validate
|
|
|
|
Valid will be set to TRUE if validation checks out, FALSE otherwise
|
|
|
|
Returns:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS DnsStatus;
|
|
WCHAR * Buffer;
|
|
BOOLEAN BufferAllocated = FALSE;
|
|
|
|
ASSERT( Name );
|
|
ASSERT( Valid );
|
|
ASSERT( LsapValidateLsaUnicodeString( Name ));
|
|
|
|
//
|
|
// Empty names and names that are too long are not allowed
|
|
//
|
|
|
|
if ( Name->Length == 0 ||
|
|
Name->Length > DNS_MAX_NAME_LENGTH * sizeof( WCHAR )) {
|
|
|
|
*Valid = FALSE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( Name->MaximumLength > Name->Length ) {
|
|
|
|
Buffer = Name->Buffer;
|
|
|
|
} else {
|
|
|
|
SafeAllocaAllocate( Buffer, Name->Length + sizeof( WCHAR ));
|
|
|
|
if ( Buffer == NULL ) {
|
|
|
|
*Valid = FALSE;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
BufferAllocated = TRUE;
|
|
|
|
RtlCopyMemory( Buffer, Name->Buffer, Name->Length );
|
|
}
|
|
|
|
Buffer[Name->Length / sizeof( WCHAR )] = L'\0';
|
|
|
|
DnsStatus = DnsValidateName_W( Buffer, DnsNameDomain );
|
|
|
|
//
|
|
// Bug 350434: Must allow non-standard characters in DNS names
|
|
// (which cause DNS_ERROR_NON_RFC_NAME)
|
|
//
|
|
|
|
*Valid = ( DnsStatus == ERROR_SUCCESS ||
|
|
DnsStatus == DNS_ERROR_NON_RFC_NAME );
|
|
|
|
if ( BufferAllocated ) {
|
|
|
|
SafeAllocaFree( Buffer );
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsapIsRunningOnPersonal(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks the system to see if
|
|
we are running on the personal version of
|
|
the operating system.
|
|
|
|
The personal version is denoted by the product
|
|
id equal to WINNT, which is really workstation,
|
|
and the product suite containing the personal
|
|
suite string.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if we are running on personal, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
OSVERSIONINFOEXW OsVer = {0};
|
|
ULONGLONG ConditionMask = 0;
|
|
|
|
OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
OsVer.wSuiteMask = VER_SUITE_PERSONAL;
|
|
OsVer.wProductType = VER_NT_WORKSTATION;
|
|
|
|
VER_SET_CONDITION( ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL );
|
|
VER_SET_CONDITION( ConditionMask, VER_SUITENAME, VER_AND );
|
|
|
|
return RtlVerifyVersionInfo( &OsVer,
|
|
VER_PRODUCT_TYPE | VER_SUITENAME,
|
|
ConditionMask) == STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
LsaITestCall(
|
|
IN LSAPR_HANDLE PolicyHandle,
|
|
IN LSAPR_TEST_INTERNAL_ROUTINES Call,
|
|
IN PLSAPR_TEST_INTERNAL_ARG_LIST InputArgs,
|
|
OUT PLSAPR_TEST_INTERNAL_ARG_LIST *OutputArgs
|
|
)
|
|
{
return STATUS_NOT_IMPLEMENTED;
}
|