1232 lines
27 KiB
C
1232 lines
27 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
reg.c
|
||
|
||
Abstract:
|
||
|
||
This module provides helpers to call the registry used by both
|
||
the client and server sides of the workstation.
|
||
|
||
Author:
|
||
|
||
Rita Wong (ritaw) 22-Apr-1993
|
||
|
||
--*/
|
||
|
||
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
|
||
#include <windef.h>
|
||
#include <winerror.h>
|
||
#include <winbase.h>
|
||
#include <winreg.h>
|
||
#include <winsvc.h>
|
||
|
||
#include <nwsnames.h>
|
||
#include <nwreg.h>
|
||
#include <nwapi.h>
|
||
#include <lmcons.h>
|
||
#include <lmerr.h>
|
||
|
||
#define LMSERVER_LINKAGE_REGKEY L"System\\CurrentControlSet\\Services\\LanmanServer\\Linkage"
|
||
#define OTHERDEPS_VALUENAME L"OtherDependencies"
|
||
#define LANMAN_SERVER L"LanmanServer"
|
||
|
||
//
|
||
// Forward Declare
|
||
//
|
||
|
||
static
|
||
DWORD
|
||
NwRegQueryValueExW(
|
||
IN HKEY hKey,
|
||
IN LPWSTR lpValueName,
|
||
OUT LPDWORD lpReserved,
|
||
OUT LPDWORD lpType,
|
||
OUT LPBYTE lpData,
|
||
IN OUT LPDWORD lpcbData
|
||
);
|
||
|
||
static
|
||
DWORD
|
||
EnumAndDeleteShares(
|
||
VOID
|
||
) ;
|
||
|
||
DWORD
|
||
CalcNullNullSize(
|
||
WCHAR *pszNullNull
|
||
) ;
|
||
|
||
WCHAR *
|
||
FindStringInNullNull(
|
||
WCHAR *pszNullNull,
|
||
WCHAR *pszString
|
||
) ;
|
||
|
||
VOID
|
||
RemoveNWCFromNullNullList(
|
||
WCHAR *OtherDeps
|
||
) ;
|
||
|
||
DWORD RemoveNwcDependency(
|
||
VOID
|
||
) ;
|
||
|
||
|
||
|
||
DWORD
|
||
NwReadRegValue(
|
||
IN HKEY Key,
|
||
IN LPWSTR ValueName,
|
||
OUT LPWSTR *Value
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function allocates the output buffer and reads the requested
|
||
value from the registry into it.
|
||
|
||
Arguments:
|
||
|
||
Key - Supplies opened handle to the key to read from.
|
||
|
||
ValueName - Supplies name of the value to retrieve data.
|
||
|
||
Value - Returns a pointer to the output buffer which points to
|
||
the memory allocated and contains the data read in from the
|
||
registry. This pointer must be freed with LocalFree when done.
|
||
|
||
Return Value:
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - Failed to create buffer to read value into.
|
||
|
||
Error from registry call.
|
||
|
||
--*/
|
||
{
|
||
LONG RegError;
|
||
DWORD NumRequired = 0;
|
||
DWORD ValueType;
|
||
|
||
|
||
//
|
||
// Set returned buffer pointer to NULL.
|
||
//
|
||
*Value = NULL;
|
||
|
||
RegError = NwRegQueryValueExW(
|
||
Key,
|
||
ValueName,
|
||
NULL,
|
||
&ValueType,
|
||
(LPBYTE) NULL,
|
||
&NumRequired
|
||
);
|
||
|
||
if (RegError != ERROR_SUCCESS && NumRequired > 0) {
|
||
|
||
if ((*Value = (LPWSTR) LocalAlloc(
|
||
LMEM_ZEROINIT,
|
||
(UINT) NumRequired
|
||
)) == NULL) {
|
||
|
||
KdPrint(("NWWORKSTATION: NwReadRegValue: LocalAlloc of size %lu failed %lu\n",
|
||
NumRequired, GetLastError()));
|
||
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
RegError = NwRegQueryValueExW(
|
||
Key,
|
||
ValueName,
|
||
NULL,
|
||
&ValueType,
|
||
(LPBYTE) *Value,
|
||
&NumRequired
|
||
);
|
||
}
|
||
else if (RegError == ERROR_SUCCESS) {
|
||
KdPrint(("NWWORKSTATION: NwReadRegValue got SUCCESS with NULL buffer."));
|
||
return ERROR_FILE_NOT_FOUND;
|
||
}
|
||
|
||
if (RegError != ERROR_SUCCESS) {
|
||
|
||
if (*Value != NULL) {
|
||
(void) LocalFree((HLOCAL) *Value);
|
||
*Value = NULL;
|
||
}
|
||
|
||
return (DWORD) RegError;
|
||
}
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
static
|
||
DWORD
|
||
NwRegQueryValueExW(
|
||
IN HKEY hKey,
|
||
IN LPWSTR lpValueName,
|
||
OUT LPDWORD lpReserved,
|
||
OUT LPDWORD lpType,
|
||
OUT LPBYTE lpData,
|
||
IN OUT LPDWORD lpcbData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine supports the same functionality as Win32 RegQueryValueEx
|
||
API, except that it works. It returns the correct lpcbData value when
|
||
a NULL output buffer is specified.
|
||
|
||
This code is stolen from the service controller.
|
||
|
||
Arguments:
|
||
|
||
same as RegQueryValueEx
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS ntstatus;
|
||
UNICODE_STRING ValueName;
|
||
PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
|
||
DWORD BufSize;
|
||
|
||
|
||
UNREFERENCED_PARAMETER(lpReserved);
|
||
|
||
//
|
||
// Make sure we have a buffer size if the buffer is present.
|
||
//
|
||
if ((ARGUMENT_PRESENT(lpData)) && (! ARGUMENT_PRESENT(lpcbData))) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
RtlInitUnicodeString(&ValueName, lpValueName);
|
||
|
||
//
|
||
// Allocate memory for the ValueKeyInfo
|
||
//
|
||
BufSize = *lpcbData + sizeof(KEY_VALUE_FULL_INFORMATION) +
|
||
ValueName.Length
|
||
- sizeof(WCHAR); // subtract memory for 1 char because it's included
|
||
// in the sizeof(KEY_VALUE_FULL_INFORMATION).
|
||
|
||
KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION) LocalAlloc(
|
||
LMEM_ZEROINIT,
|
||
(UINT) BufSize
|
||
);
|
||
|
||
if (KeyValueInfo == NULL) {
|
||
KdPrint(("NWWORKSTATION: NwRegQueryValueExW: LocalAlloc failed %lu\n",
|
||
GetLastError()));
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
ntstatus = NtQueryValueKey(
|
||
hKey,
|
||
&ValueName,
|
||
KeyValueFullInformation,
|
||
(PVOID) KeyValueInfo,
|
||
(ULONG) BufSize,
|
||
(PULONG) &BufSize
|
||
);
|
||
|
||
if ((NT_SUCCESS(ntstatus) || (ntstatus == STATUS_BUFFER_OVERFLOW))
|
||
&& ARGUMENT_PRESENT(lpcbData)) {
|
||
|
||
*lpcbData = KeyValueInfo->DataLength;
|
||
}
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
|
||
if (ARGUMENT_PRESENT(lpType)) {
|
||
*lpType = KeyValueInfo->Type;
|
||
}
|
||
|
||
|
||
if (ARGUMENT_PRESENT(lpData)) {
|
||
memcpy(
|
||
lpData,
|
||
(LPBYTE)KeyValueInfo + KeyValueInfo->DataOffset,
|
||
KeyValueInfo->DataLength
|
||
);
|
||
}
|
||
}
|
||
|
||
(void) LocalFree((HLOCAL) KeyValueInfo);
|
||
|
||
return RtlNtStatusToDosError(ntstatus);
|
||
|
||
}
|
||
|
||
VOID
|
||
NwLuidToWStr(
|
||
IN PLUID LogonId,
|
||
OUT LPWSTR LogonIdStr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts a LUID into a string in hex value format so
|
||
that it can be used as a registry key.
|
||
|
||
Arguments:
|
||
|
||
LogonId - Supplies the LUID.
|
||
|
||
LogonIdStr - Receives the string. This routine assumes that this
|
||
buffer is large enough to fit 17 characters.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
swprintf(LogonIdStr, L"%08lx%08lx", LogonId->HighPart, LogonId->LowPart);
|
||
}
|
||
|
||
VOID
|
||
NwWStrToLuid(
|
||
IN LPWSTR LogonIdStr,
|
||
OUT PLUID LogonId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts a string in hex value format into a LUID.
|
||
|
||
Arguments:
|
||
|
||
LogonIdStr - Supplies the string.
|
||
|
||
LogonId - Receives the LUID.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
swscanf(LogonIdStr, L"%08lx%08lx", &LogonId->HighPart, &LogonId->LowPart);
|
||
}
|
||
|
||
|
||
DWORD
|
||
NwDeleteInteractiveLogon(
|
||
IN PLUID Id OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes a specific interactive logon ID key in the registry
|
||
if a logon ID is specified, otherwise it deletes all interactive logon
|
||
ID keys.
|
||
|
||
Arguments:
|
||
|
||
Id - Supplies the logon ID to delete. NULL means delete all.
|
||
|
||
Return Status:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LONG RegError;
|
||
LONG DelError = ERROR_SUCCESS;
|
||
HKEY InteractiveLogonKey;
|
||
|
||
WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
|
||
|
||
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_INTERACTIVE_LOGON_REGKEY,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ | KEY_WRITE | DELETE,
|
||
&InteractiveLogonKey
|
||
);
|
||
|
||
if (RegError != ERROR_SUCCESS) {
|
||
return RegError;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(Id)) {
|
||
|
||
//
|
||
// Delete the key specified.
|
||
//
|
||
NwLuidToWStr(Id, LogonIdKey);
|
||
|
||
DelError = RegDeleteKeyW(InteractiveLogonKey, LogonIdKey);
|
||
|
||
if ( DelError )
|
||
KdPrint((" NwDeleteInteractiveLogon: failed to delete logon %lu\n", DelError));
|
||
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Delete all interactive logon ID keys.
|
||
//
|
||
|
||
do {
|
||
|
||
RegError = RegEnumKeyW(
|
||
InteractiveLogonKey,
|
||
0,
|
||
LogonIdKey,
|
||
sizeof(LogonIdKey) / sizeof(WCHAR)
|
||
);
|
||
|
||
if (RegError == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Got a logon id key, delete it.
|
||
//
|
||
|
||
DelError = RegDeleteKeyW(InteractiveLogonKey, LogonIdKey);
|
||
}
|
||
else if (RegError != ERROR_NO_MORE_ITEMS) {
|
||
KdPrint((" NwDeleteInteractiveLogon: failed to enum logon IDs %lu\n", RegError));
|
||
}
|
||
|
||
} while (RegError == ERROR_SUCCESS);
|
||
}
|
||
|
||
(void) RegCloseKey(InteractiveLogonKey);
|
||
|
||
return ((DWORD) DelError);
|
||
}
|
||
|
||
VOID
|
||
NwDeleteCurrentUser(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes the current user value under the parameters key.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LONG RegError;
|
||
HKEY WkstaKey;
|
||
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \NWCWorkstation\Parameters
|
||
//
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_REGKEY,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ | KEY_WRITE | DELETE,
|
||
&WkstaKey
|
||
);
|
||
|
||
if (RegError != NO_ERROR) {
|
||
KdPrint(("NWPROVAU: NwpInitializeRegistry open NWCWorkstation\\Parameters key unexpected error %lu!\n",
|
||
RegError));
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Delete CurrentUser value first so that the workstation won't be
|
||
// reading this stale value. Ignore error since it may not exist.
|
||
//
|
||
(void) RegDeleteValueW(
|
||
WkstaKey,
|
||
NW_CURRENTUSER_VALUENAME
|
||
);
|
||
|
||
(void) RegCloseKey(WkstaKey);
|
||
}
|
||
|
||
DWORD
|
||
NwDeleteServiceLogon(
|
||
IN PLUID Id OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes a specific service logon ID key in the registry
|
||
if a logon ID is specified, otherwise it deletes all service logon
|
||
ID keys.
|
||
|
||
Arguments:
|
||
|
||
Id - Supplies the logon ID to delete. NULL means delete all.
|
||
|
||
Return Status:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LONG RegError;
|
||
LONG DelError = STATUS_SUCCESS;
|
||
HKEY ServiceLogonKey;
|
||
|
||
WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
|
||
|
||
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_SERVICE_LOGON_REGKEY,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ | KEY_WRITE | DELETE,
|
||
&ServiceLogonKey
|
||
);
|
||
|
||
if (RegError != ERROR_SUCCESS) {
|
||
return RegError;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(Id)) {
|
||
|
||
//
|
||
// Delete the key specified.
|
||
//
|
||
NwLuidToWStr(Id, LogonIdKey);
|
||
|
||
DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
|
||
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Delete all service logon ID keys.
|
||
//
|
||
|
||
do {
|
||
|
||
RegError = RegEnumKeyW(
|
||
ServiceLogonKey,
|
||
0,
|
||
LogonIdKey,
|
||
sizeof(LogonIdKey) / sizeof(WCHAR)
|
||
);
|
||
|
||
if (RegError == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Got a logon id key, delete it.
|
||
//
|
||
|
||
DelError = RegDeleteKeyW(ServiceLogonKey, LogonIdKey);
|
||
}
|
||
else if (RegError != ERROR_NO_MORE_ITEMS) {
|
||
KdPrint((" NwDeleteServiceLogon: failed to enum logon IDs %lu\n", RegError));
|
||
}
|
||
|
||
} while (RegError == ERROR_SUCCESS);
|
||
}
|
||
|
||
(void) RegCloseKey(ServiceLogonKey);
|
||
|
||
return ((DWORD) DelError);
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NwpRegisterGatewayShare(
|
||
IN LPWSTR ShareName,
|
||
IN LPWSTR DriveName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine remembers that a gateway share has been created so
|
||
that it can be cleanup up when NWCS is uninstalled.
|
||
|
||
Arguments:
|
||
|
||
ShareName - name of share
|
||
DriveName - name of drive that is shared
|
||
|
||
Return Status:
|
||
|
||
Win32 error of any failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD status ;
|
||
|
||
|
||
//
|
||
// make sure we have valid parameters
|
||
//
|
||
if (ShareName && DriveName)
|
||
{
|
||
HKEY hKey ;
|
||
DWORD dwDisposition ;
|
||
|
||
//
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \NWCWorkstation\Shares (create it if not there)
|
||
//
|
||
status = RegCreateKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_GATEWAY_SHARES,
|
||
0,
|
||
L"",
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_WRITE, // desired access
|
||
NULL, // default security
|
||
&hKey,
|
||
&dwDisposition // ignored
|
||
);
|
||
|
||
if ( status )
|
||
return status ;
|
||
|
||
//
|
||
// wtite out value with valuename=sharename, valuedata=drive
|
||
//
|
||
status = RegSetValueExW(
|
||
hKey,
|
||
ShareName,
|
||
0,
|
||
REG_SZ,
|
||
(LPBYTE) DriveName,
|
||
(wcslen(DriveName)+1) * sizeof(WCHAR)) ;
|
||
|
||
(void) RegCloseKey( hKey );
|
||
}
|
||
else
|
||
status = ERROR_INVALID_PARAMETER ;
|
||
|
||
return status ;
|
||
|
||
}
|
||
|
||
DWORD
|
||
NwpCleanupGatewayShares(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up all persistent share info and also tidies
|
||
up the registry for NWCS. Later is not needed in uninstall, but is
|
||
there so we have a single routine that completely disables the
|
||
gateway.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Status:
|
||
|
||
Win32 error for failed APIs.
|
||
|
||
--*/
|
||
{
|
||
DWORD status, FinalStatus = NO_ERROR ;
|
||
HKEY WkstaKey = NULL,
|
||
ServerLinkageKey = NULL ;
|
||
LPWSTR OtherDeps = NULL ;
|
||
|
||
//
|
||
// Enumeratre and delete all shares
|
||
//
|
||
FinalStatus = status = EnumAndDeleteShares() ;
|
||
|
||
//
|
||
// if update registry by cleaning out both Drive and Shares keys.
|
||
// ignore return values here. the keys may not be present.
|
||
//
|
||
(void) RegDeleteKeyW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_GATEWAY_DRIVES
|
||
) ;
|
||
|
||
(void) RegDeleteKeyW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_GATEWAY_SHARES
|
||
) ;
|
||
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \NWCWorkstation\Parameters
|
||
//
|
||
status = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_REGKEY,
|
||
REG_OPTION_NON_VOLATILE, // options
|
||
KEY_WRITE, // desired access
|
||
&WkstaKey
|
||
);
|
||
|
||
if (status == ERROR_SUCCESS)
|
||
{
|
||
//
|
||
// delete the gateway account and gateway enabled flag.
|
||
// ignore failures here (the values may not be present)
|
||
//
|
||
(void) RegDeleteValueW(
|
||
WkstaKey,
|
||
NW_GATEWAYACCOUNT_VALUENAME
|
||
) ;
|
||
(void) RegDeleteValueW(
|
||
WkstaKey,
|
||
NW_GATEWAY_ENABLE
|
||
) ;
|
||
|
||
(void) RegCloseKey( WkstaKey );
|
||
}
|
||
|
||
//
|
||
// store new status if necessary
|
||
//
|
||
if (FinalStatus == NO_ERROR)
|
||
FinalStatus = status ;
|
||
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \LanmanServer\Linkage
|
||
//
|
||
status = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
LMSERVER_LINKAGE_REGKEY,
|
||
REG_OPTION_NON_VOLATILE, // options
|
||
KEY_WRITE | KEY_READ, // desired access
|
||
&ServerLinkageKey
|
||
);
|
||
|
||
if (status == ERROR_SUCCESS)
|
||
{
|
||
//
|
||
// remove us from the OtherDependencies.
|
||
// ignore read failures here (it may not be present)
|
||
//
|
||
status = NwReadRegValue(
|
||
ServerLinkageKey,
|
||
OTHERDEPS_VALUENAME,
|
||
&OtherDeps
|
||
);
|
||
|
||
if (status == NO_ERROR)
|
||
{
|
||
//
|
||
// this call munges the list to remove NWC if there.
|
||
//
|
||
RemoveNWCFromNullNullList(OtherDeps) ;
|
||
|
||
status = RegSetValueExW(
|
||
ServerLinkageKey,
|
||
OTHERDEPS_VALUENAME,
|
||
0,
|
||
REG_MULTI_SZ,
|
||
(BYTE *)OtherDeps,
|
||
CalcNullNullSize(OtherDeps) * sizeof(WCHAR)) ;
|
||
|
||
(void) LocalFree(OtherDeps) ;
|
||
|
||
(void) RemoveNwcDependency() ; // make this happen right away
|
||
// ignore errors - reboot will fix
|
||
}
|
||
else
|
||
{
|
||
status = NO_ERROR ;
|
||
}
|
||
|
||
(void) RegCloseKey( ServerLinkageKey );
|
||
}
|
||
|
||
//
|
||
// store new status if necessary
|
||
//
|
||
if (FinalStatus == NO_ERROR)
|
||
FinalStatus = status ;
|
||
|
||
|
||
return (FinalStatus) ;
|
||
}
|
||
|
||
DWORD
|
||
NwpClearGatewayShare(
|
||
IN LPWSTR ShareName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes a specific share from the remembered gateway
|
||
shares in the registry.
|
||
|
||
Arguments:
|
||
|
||
ShareName - share value to delete
|
||
|
||
Return Status:
|
||
|
||
Win32 status code.
|
||
|
||
--*/
|
||
{
|
||
DWORD status = NO_ERROR ;
|
||
|
||
//
|
||
// check that paramter is non null
|
||
//
|
||
if (ShareName)
|
||
{
|
||
HKEY hKey ;
|
||
|
||
//
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \NWCWorkstation\Drives
|
||
//
|
||
status = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_GATEWAY_SHARES,
|
||
REG_OPTION_NON_VOLATILE, // options
|
||
KEY_WRITE, // desired access
|
||
&hKey
|
||
);
|
||
|
||
if ( status )
|
||
return status ;
|
||
|
||
status = RegDeleteValueW(
|
||
hKey,
|
||
ShareName
|
||
) ;
|
||
|
||
(void) RegCloseKey( hKey );
|
||
}
|
||
else
|
||
status = ERROR_INVALID_PARAMETER ;
|
||
|
||
return status ;
|
||
}
|
||
|
||
typedef NET_API_STATUS (*PF_NETSHAREDEL) (
|
||
LPWSTR server,
|
||
LPWSTR name,
|
||
DWORD reserved) ;
|
||
|
||
#define NETSHAREDELSTICKY_API "NetShareDelSticky"
|
||
#define NETSHAREDEL_API "NetShareDel"
|
||
#define NETAPI_DLL L"NETAPI32"
|
||
|
||
DWORD
|
||
EnumAndDeleteShares(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine removes all persister share info in the server for
|
||
all gateway shares.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Status:
|
||
|
||
Win32 error code.
|
||
|
||
--*/
|
||
{
|
||
DWORD err, i, type ;
|
||
HKEY hKey = NULL ;
|
||
FILETIME FileTime ;
|
||
HANDLE hNetapi = NULL ;
|
||
PF_NETSHAREDEL pfNetShareDel, pfNetShareDelSticky ;
|
||
WCHAR Class[256], Share[NNLEN+1], Device[MAX_PATH+1] ;
|
||
DWORD dwClass, dwSubKeys, dwMaxSubKey, dwMaxClass,
|
||
dwValues, dwMaxValueName, dwMaxValueData, dwSDLength,
|
||
dwShareLength, dwDeviceLength ;
|
||
|
||
//
|
||
// load the library so that not everyone needs link to netapi32
|
||
//
|
||
if (!(hNetapi = LoadLibraryW(NETAPI_DLL)))
|
||
return (GetLastError()) ;
|
||
|
||
//
|
||
// get addresses of the 2 functions we are interested in
|
||
//
|
||
if (!(pfNetShareDel = (PF_NETSHAREDEL) GetProcAddress(hNetapi,
|
||
NETSHAREDEL_API)))
|
||
{
|
||
err = GetLastError() ;
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
if (!(pfNetShareDelSticky = (PF_NETSHAREDEL) GetProcAddress(hNetapi,
|
||
NETSHAREDELSTICKY_API)))
|
||
{
|
||
err = GetLastError() ;
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \NWCGateway\Shares
|
||
//
|
||
err = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_GATEWAY_SHARES,
|
||
REG_OPTION_NON_VOLATILE, // options
|
||
KEY_READ, // desired access
|
||
&hKey
|
||
);
|
||
|
||
if ( err )
|
||
goto ExitPoint ;
|
||
|
||
//
|
||
// read the info about that key
|
||
//
|
||
dwClass = sizeof(Class)/sizeof(Class[0]) ;
|
||
err = RegQueryInfoKeyW(hKey,
|
||
Class,
|
||
&dwClass,
|
||
NULL,
|
||
&dwSubKeys,
|
||
&dwMaxSubKey,
|
||
&dwMaxClass,
|
||
&dwValues,
|
||
&dwMaxValueName,
|
||
&dwMaxValueData,
|
||
&dwSDLength,
|
||
&FileTime) ;
|
||
if ( err )
|
||
{
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
//
|
||
// for each value found, we have a share to delete
|
||
//
|
||
for (i = 0; i < dwValues; i++)
|
||
{
|
||
dwShareLength = sizeof(Share)/sizeof(Share[0]) ;
|
||
dwDeviceLength = sizeof(Device) ;
|
||
type = REG_SZ ;
|
||
err = RegEnumValueW(hKey,
|
||
i,
|
||
Share,
|
||
&dwShareLength,
|
||
NULL,
|
||
&type,
|
||
(LPBYTE)Device,
|
||
&dwDeviceLength) ;
|
||
|
||
//
|
||
// cleanup the share. try delete the share proper. if not
|
||
// there, remove the sticky info instead.
|
||
//
|
||
if (!err)
|
||
{
|
||
err = (*pfNetShareDel)(NULL, Share, 0) ;
|
||
|
||
if (err == NERR_NetNameNotFound)
|
||
{
|
||
(void) (*pfNetShareDelSticky)(NULL, Share, 0) ;
|
||
}
|
||
}
|
||
|
||
//
|
||
// ignore errors within the loop. we can to carry on to
|
||
// cleanup as much as possible.
|
||
//
|
||
err = NO_ERROR ;
|
||
}
|
||
|
||
|
||
|
||
ExitPoint:
|
||
|
||
if (hKey)
|
||
(void) RegCloseKey( hKey );
|
||
|
||
if (hNetapi)
|
||
(void) FreeLibrary(hNetapi) ;
|
||
|
||
return err ;
|
||
}
|
||
|
||
|
||
DWORD
|
||
CalcNullNullSize(
|
||
WCHAR *pszNullNull
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Walk thru a NULL NULL string, counting the number of
|
||
characters, including the 2 nulls at the end.
|
||
|
||
Arguments:
|
||
|
||
Pointer to a NULL NULL string
|
||
|
||
Return Status:
|
||
|
||
Count of number of *characters*. See description.
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD dwSize = 0 ;
|
||
WCHAR *pszTmp = pszNullNull ;
|
||
|
||
if (!pszNullNull)
|
||
return 0 ;
|
||
|
||
while (*pszTmp)
|
||
{
|
||
DWORD dwLen = wcslen(pszTmp) + 1 ;
|
||
|
||
dwSize += dwLen ;
|
||
pszTmp += dwLen ;
|
||
}
|
||
|
||
return (dwSize+1) ;
|
||
}
|
||
|
||
WCHAR *
|
||
FindStringInNullNull(
|
||
WCHAR *pszNullNull,
|
||
WCHAR *pszString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Walk thru a NULL NULL string, looking for the search string
|
||
|
||
Arguments:
|
||
|
||
pszNullNull: the string list we will search.
|
||
pszString: what we are searching for.
|
||
|
||
Return Status:
|
||
|
||
The start of the string if found. Null, otherwise.
|
||
|
||
--*/
|
||
{
|
||
WCHAR *pszTmp = pszNullNull ;
|
||
|
||
if (!pszNullNull || !*pszNullNull)
|
||
return NULL ;
|
||
|
||
do {
|
||
|
||
if (_wcsicmp(pszTmp,pszString)==0)
|
||
return pszTmp ;
|
||
|
||
pszTmp += wcslen(pszTmp) + 1 ;
|
||
|
||
} while (*pszTmp) ;
|
||
|
||
return NULL ;
|
||
}
|
||
|
||
VOID
|
||
RemoveNWCFromNullNullList(
|
||
WCHAR *OtherDeps
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Remove the NWCWorkstation string from a null null string.
|
||
|
||
Arguments:
|
||
|
||
OtherDeps: the string list we will munge.
|
||
|
||
Return Status:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LPWSTR pszTmp0, pszTmp1 ;
|
||
|
||
//
|
||
// find the NWCWorkstation string
|
||
//
|
||
pszTmp0 = FindStringInNullNull(OtherDeps, NW_WORKSTATION_SERVICE) ;
|
||
|
||
if (!pszTmp0)
|
||
return ;
|
||
|
||
pszTmp1 = pszTmp0 + wcslen(pszTmp0) + 1 ; // skip past it
|
||
|
||
//
|
||
// shift the rest up
|
||
//
|
||
memmove(pszTmp0, pszTmp1, CalcNullNullSize(pszTmp1)*sizeof(WCHAR)) ;
|
||
}
|
||
|
||
DWORD RemoveNwcDependency(
|
||
VOID
|
||
)
|
||
{
|
||
SC_HANDLE ScManager = NULL;
|
||
SC_HANDLE Service = NULL;
|
||
LPQUERY_SERVICE_CONFIGW lpServiceConfig = NULL;
|
||
DWORD err = NO_ERROR, dwBufferSize = 4096, dwBytesNeeded = 0;
|
||
LPWSTR Deps = NULL ;
|
||
|
||
lpServiceConfig = (LPQUERY_SERVICE_CONFIGW) LocalAlloc(LPTR, dwBufferSize) ;
|
||
|
||
if (lpServiceConfig == NULL) {
|
||
err = GetLastError();
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
ScManager = OpenSCManagerW(
|
||
NULL,
|
||
NULL,
|
||
SC_MANAGER_CONNECT
|
||
);
|
||
|
||
if (ScManager == NULL) {
|
||
|
||
err = GetLastError();
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
Service = OpenServiceW(
|
||
ScManager,
|
||
LANMAN_SERVER,
|
||
(SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG)
|
||
);
|
||
|
||
if (Service == NULL) {
|
||
err = GetLastError();
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
if (!QueryServiceConfigW(
|
||
Service,
|
||
lpServiceConfig, // address of service config. structure
|
||
dwBufferSize, // size of service configuration buffer
|
||
&dwBytesNeeded // address of variable for bytes needed
|
||
)) {
|
||
|
||
err = GetLastError();
|
||
|
||
if (err == ERROR_INSUFFICIENT_BUFFER) {
|
||
|
||
err = NO_ERROR ;
|
||
dwBufferSize = dwBytesNeeded ;
|
||
lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)
|
||
LocalAlloc(LPTR, dwBufferSize) ;
|
||
|
||
if (lpServiceConfig == NULL) {
|
||
err = GetLastError();
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
if (!QueryServiceConfigW(
|
||
Service,
|
||
lpServiceConfig, // address of service config. structure
|
||
dwBufferSize, // size of service configuration buffer
|
||
&dwBytesNeeded // address of variable for bytes needed
|
||
)) {
|
||
|
||
err = GetLastError();
|
||
}
|
||
}
|
||
|
||
if (err != NO_ERROR) {
|
||
|
||
goto ExitPoint ;
|
||
}
|
||
}
|
||
|
||
Deps = lpServiceConfig->lpDependencies ;
|
||
|
||
RemoveNWCFromNullNullList(Deps) ;
|
||
|
||
if (!ChangeServiceConfigW(
|
||
Service,
|
||
SERVICE_NO_CHANGE, // service type (no change)
|
||
SERVICE_NO_CHANGE, // start type (no change)
|
||
SERVICE_NO_CHANGE, // error control (no change)
|
||
NULL, // binary path name (NULL for no change)
|
||
NULL, // load order group (NULL for no change)
|
||
NULL, // tag id (NULL for no change)
|
||
Deps,
|
||
NULL, // service start name (NULL for no change)
|
||
NULL, // password (NULL for no change)
|
||
NULL // display name (NULL for no change)
|
||
)) {
|
||
|
||
err = GetLastError();
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
|
||
ExitPoint:
|
||
|
||
if (ScManager) {
|
||
|
||
CloseServiceHandle(ScManager);
|
||
}
|
||
|
||
if (Service) {
|
||
|
||
CloseServiceHandle(Service);
|
||
}
|
||
|
||
if (lpServiceConfig) {
|
||
|
||
(void) LocalFree(lpServiceConfig) ;
|
||
}
|
||
|
||
return err ;
|
||
}
|
||
|