538 lines
12 KiB
C
538 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
}
|