windows-nt/Source/XPSP1/NT/ds/nw/svcdlls/nwwks/lib/lsa.c

538 lines
12 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
lsa.c
Abstract:
This module provides helpers to call LSA, particularly for
manipulating secret objects.
Author:
Rita Wong (ritaw) 22-Apr-1993
--*/
#include <stdlib.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windef.h>
#include <winerror.h>
#include <winbase.h>
#include <nwlsa.h>
//-------------------------------------------------------------------//
// //
// Constants and Macros //
// //
//-------------------------------------------------------------------//
#define NW_SECRET_PREFIX L"_MS_NWCS_"
DWORD
NwOpenPolicy(
IN ACCESS_MASK DesiredAccess,
OUT LSA_HANDLE *PolicyHandle
)
/*++
Routine Description:
This function gets a handle to the local security policy by calling
LsaOpenPolicy.
Arguments:
DesiredAccess - Supplies the desired access to the local security
policy.
PolicyHandle - Receives a handle to the opened policy.
Return Value:
NO_ERROR - Policy handle is returned.
Error from LSA.
--*/
{
NTSTATUS ntstatus;
OBJECT_ATTRIBUTES ObjAttributes;
//
// Open a handle to the local security policy. Initialize the
// objects attributes structure first.
//
InitializeObjectAttributes(
&ObjAttributes,
NULL,
0L,
NULL,
NULL
);
ntstatus = LsaOpenPolicy(
NULL,
&ObjAttributes,
DesiredAccess,
PolicyHandle
);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION: LsaOpenPolicy returns %08lx\n",
ntstatus));
return RtlNtStatusToDosError(ntstatus);
}
return NO_ERROR;
}
DWORD
NwOpenSecret(
IN ACCESS_MASK DesiredAccess,
IN LSA_HANDLE PolicyHandle,
IN LPWSTR LsaSecretName,
OUT PLSA_HANDLE SecretHandle
)
/*++
Routine Description:
This function opens a handle to the specified secret object.
Arguments:
DesiredAccess - Supplies the desired access to the secret object.
PolicyHandle - Supplies a handle to an already opened LSA policy.
LsaSecretName - Supplies the name of the secret to open.
SecretHandle - Receives the handle of the opened secret.
Return Value:
NO_ERROR - Secret handle is returned.
Error from LSA.
--*/
{
NTSTATUS ntstatus;
UNICODE_STRING SecretNameString;
RtlInitUnicodeString(&SecretNameString, LsaSecretName);
ntstatus = LsaOpenSecret(
PolicyHandle,
&SecretNameString,
DesiredAccess,
SecretHandle
);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION: LsaOpenSecret %ws returns %08lx\n",
LsaSecretName, ntstatus));
return RtlNtStatusToDosError(ntstatus);
}
return NO_ERROR;
}
DWORD
NwFormSecretName(
IN LPWSTR Qualifier,
OUT LPWSTR *LsaSecretName
)
/*++
Routine Description:
This function creates a secret name from the user name.
It also allocates the buffer to return the created secret name which
must be freed by the caller using LocalFree when done with it.
Arguments:
Qualifier - Supplies the qualifier which forms part of part of the secret
object name we are creating.
LsaSecretName - Receives a pointer to the buffer which contains the
secret object name.
Return Value:
NO_ERROR - Successfully returned secret name.
ERROR_NOT_ENOUGH_MEMORY - Failed to allocate buffer to hold the secret
name.
--*/
{
if ((*LsaSecretName = (LPWSTR)LocalAlloc(
0,
(wcslen(NW_SECRET_PREFIX) +
wcslen(Qualifier) +
1) * sizeof(WCHAR)
)) == NULL) {
KdPrint(("NWWORKSTATION: NwFormSecretName: LocalAlloc failed %lu\n",
GetLastError()));
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(*LsaSecretName, NW_SECRET_PREFIX);
wcscat(*LsaSecretName, Qualifier);
return NO_ERROR;
}
DWORD
NwSetPassword(
IN LPWSTR Qualifier,
IN LPWSTR Password
)
/*++
Routine Description:
This function opens ( creates one if needed ) the LSA secret object,
and sets it with the specified password.
Arguments:
Qualifier - Supplies the qualifier which forms part of part of the secret
object name to be created.
Password - Supplies the user specified password for an account.
Return Value:
NO_ERROR - Secret object for the password is created and set with new value.
Error from LSA.
--*/
{
DWORD status;
NTSTATUS ntstatus;
LSA_HANDLE PolicyHandle;
LSA_HANDLE SecretHandle;
UNICODE_STRING SecretNameString;
LPWSTR LsaSecretName;
UNICODE_STRING NewPasswordString;
UNICODE_STRING OldPasswordString;
//
// Open a handle to the local security policy.
//
if ((status = NwOpenPolicy(
POLICY_CREATE_SECRET,
&PolicyHandle
)) != NO_ERROR) {
KdPrint(("NWWORKSTATION: NwCreatePassword: NwOpenPolicy failed\n"));
return status;
}
//
// Create the LSA secret object. But first, form a secret name.
//
if ((status = NwFormSecretName(
Qualifier,
&LsaSecretName
)) != NO_ERROR) {
(void) LsaClose(PolicyHandle);
return status;
}
RtlInitUnicodeString(&SecretNameString, LsaSecretName);
ntstatus = LsaCreateSecret(
PolicyHandle,
&SecretNameString,
SECRET_SET_VALUE | DELETE,
&SecretHandle
);
//
// note: ignore object already exists error. just use the existing
// object. this could be because the user didnt completely cleanup
// during deinstall. the unique names makes it unlikely to be a real
// collision.
//
if ( ntstatus == STATUS_OBJECT_NAME_COLLISION ) {
ntstatus = NwOpenSecret(
SECRET_SET_VALUE,
PolicyHandle,
LsaSecretName,
&SecretHandle
);
}
//
// Don't need the name or policy handle anymore.
//
(void) LocalFree((HLOCAL) LsaSecretName);
(void) LsaClose(PolicyHandle);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION: NwCreatePassword: LsaCreateSecret or LsaOpenSecret returned %08lx for %ws\n", ntstatus, LsaSecretName));
return RtlNtStatusToDosError(ntstatus);
}
RtlInitUnicodeString(&OldPasswordString, NULL);
RtlInitUnicodeString(&NewPasswordString, Password);
ntstatus = LsaSetSecret(
SecretHandle,
&NewPasswordString,
&OldPasswordString
);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION NwCreatePassword: LsaSetSecret returned %08lx\n",
ntstatus));
status = RtlNtStatusToDosError(ntstatus);
//
// Delete the secret object
//
ntstatus = LsaDelete(SecretHandle);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION: NwCreatePassword: LsaDelete to restore back to original returned %08lx\n",
ntstatus));
(void) LsaClose(SecretHandle);
}
//
// Secret handle is closed by LsaDelete if successfully deleted.
//
return status;
}
(void) LsaClose(SecretHandle);
return NO_ERROR;
}
DWORD
NwDeletePassword(
IN LPWSTR Qualifier
)
/*++
Routine Description:
This function deletes the LSA secret object whose name is derived
from the specified Qualifier.
Arguments:
Qualifier - Supplies the qualifier which forms part of part of the secret
object name to be deleted.
Return Value:
NO_ERROR - Secret object for password is deleted.
Error from LSA.
--*/
{
DWORD status;
NTSTATUS ntstatus;
LSA_HANDLE PolicyHandle;
LSA_HANDLE SecretHandle;
LPWSTR LsaSecretName;
//
// Open a handle to the local security policy.
//
if ((status = NwOpenPolicy(
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle
)) != NO_ERROR) {
KdPrint(("NWWORKSTATION: NwDeletePassword: NwOpenPolicy failed\n"));
return status;
}
//
// Get the secret object name from the specified user name.
//
if ((status = NwFormSecretName(
Qualifier,
&LsaSecretName
)) != NO_ERROR) {
(void) LsaClose(PolicyHandle);
return status;
}
status = NwOpenSecret(
DELETE,
PolicyHandle,
LsaSecretName,
&SecretHandle
);
//
// Don't need the name or policy handle anymore.
//
(void) LocalFree((HLOCAL) LsaSecretName);
(void) LsaClose(PolicyHandle);
if (status != NO_ERROR) {
KdPrint(("NWWORKSTATION: NwDeletePassword: NwOpenSecret failed\n"));
return status;
}
ntstatus = LsaDelete(SecretHandle);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION: NwDeletePassword: LsaDelete returned %08lx\n",
ntstatus));
(void) LsaClose(SecretHandle);
return RtlNtStatusToDosError(ntstatus);
}
return NO_ERROR;
}
DWORD
NwGetPassword(
IN LPWSTR Qualifier,
OUT PUNICODE_STRING *Password,
OUT PUNICODE_STRING *OldPassword
)
/*++
Routine Description:
This function retrieves the current password and old password
values from the service secret object given the user name.
Arguments:
Qualifier - Supplies the qualifier which forms part of the key to the
secret object name.
Password - Receives a pointer to the string structure that contains
the password.
OldPassword - Receives a pointer to the string structure that
contains the old password.
Return Value:
NO_ERROR - Secret object for password is changed to new value.
Error from LSA.
--*/
{
DWORD status;
NTSTATUS ntstatus;
LSA_HANDLE PolicyHandle;
LSA_HANDLE SecretHandle;
LPWSTR LsaSecretName;
//
// Open a handle to the local security policy to read the
// value of the secret.
//
if ((status = NwOpenPolicy(
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle
)) != NO_ERROR) {
return status;
}
//
// Get the secret object name from the specified user name.
//
if ((status = NwFormSecretName(
Qualifier,
&LsaSecretName
)) != NO_ERROR) {
(void) LsaClose(PolicyHandle);
return status;
}
status = NwOpenSecret(
SECRET_QUERY_VALUE,
PolicyHandle,
LsaSecretName,
&SecretHandle
);
//
// Don't need the name or policy handle anymore.
//
(void) LocalFree((HLOCAL) LsaSecretName);
(void) LsaClose(PolicyHandle);
if (status != NO_ERROR) {
KdPrint(("NWWORKSTATION: ScGetSecret: ScOpenSecret failed\n"));
return status;
}
//
// Query the old value of the secret object so that we can
// we can restore it if we fail to change the password later.
//
ntstatus = LsaQuerySecret(
SecretHandle,
Password,
NULL, // don't need set time
OldPassword,
NULL // don't need set time
);
(void) LsaClose(SecretHandle);
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("NWWORKSTATION: NwGetPassword: LsaQuerySecret for previous values returned %08lx\n",
ntstatus));
return RtlNtStatusToDosError(ntstatus);
}
return NO_ERROR;
}