1405 lines
40 KiB
C
1405 lines
40 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
wsconfig.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the Workstation service configuration routines.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rita Wong (ritaw) 22-May-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
08-May-1992 JohnRo
|
|||
|
Wksta transports are just an array of values for one key,
|
|||
|
not an entire section. Ditto for other domains for the browser.
|
|||
|
13-May-1992 JohnRo
|
|||
|
Reworked to share code with registry watch code.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ws.h"
|
|||
|
#include <ntlsa.h> // LsaQueryInformationPolicy
|
|||
|
#include "wsdevice.h"
|
|||
|
#include "wsconfig.h"
|
|||
|
#include "wsbind.h"
|
|||
|
#include "wsutil.h"
|
|||
|
#include "wsmain.h"
|
|||
|
|
|||
|
#include <config.h> // NT config file helpers in netlib
|
|||
|
#include <configp.h> // USE_WIN32_CONFIG (if defined), etc.
|
|||
|
#include <confname.h> // Section and keyword equates.
|
|||
|
#include <lmapibuf.h> // NetApiBufferFree().
|
|||
|
#include <lmsname.h> // WORKSTATION_DISPLAY_NAME
|
|||
|
#include <prefix.h> // PREFIX_ equates.
|
|||
|
#include <strarray.h> // LPTSTR_ARRAY, etc.
|
|||
|
#include <stdlib.h> // wcscpy().
|
|||
|
|
|||
|
#include <apperr.h> // Eventlog message IDs
|
|||
|
#include <lmerrlog.h> // Eventlog message IDs
|
|||
|
|
|||
|
#define WS_LINKAGE_REGISTRY_PATH L"LanmanWorkstation\\Linkage"
|
|||
|
#define WS_BIND_VALUE_NAME L"Bind"
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Local Function Prototypes //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
STATIC
|
|||
|
NTSTATUS
|
|||
|
WsBindATransport(
|
|||
|
IN PWSTR ValueName,
|
|||
|
IN ULONG ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN ULONG ValueLength,
|
|||
|
IN PVOID Context,
|
|||
|
IN PVOID EntryContext
|
|||
|
);
|
|||
|
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
// //
|
|||
|
// Global variables //
|
|||
|
// //
|
|||
|
//-------------------------------------------------------------------//
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Workstation configuration information structure which holds the
|
|||
|
// computername, primary domain, wksta config buffer, and a resource
|
|||
|
// to serialize access to the whole thing.
|
|||
|
//
|
|||
|
WSCONFIGURATION_INFO WsInfo;
|
|||
|
|
|||
|
STATIC WS_REDIR_FIELDS WsFields[] = {
|
|||
|
|
|||
|
{WKSTA_KEYWORD_CHARWAIT,
|
|||
|
(LPDWORD) &WSBUF.wki502_char_wait,
|
|||
|
3600, 0, 65535, DWordType, WKSTA_CHARWAIT_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_MAXCOLLECTIONCOUNT,
|
|||
|
(LPDWORD) &WSBUF.wki502_maximum_collection_count,
|
|||
|
16, 0, 65535, DWordType, WKSTA_CHARCOUNT_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_COLLECTIONTIME,
|
|||
|
(LPDWORD) &WSBUF.wki502_collection_time,
|
|||
|
250, 0, 65535000, DWordType, WKSTA_CHARTIME_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_KEEPCONN,
|
|||
|
(LPDWORD) &WSBUF.wki502_keep_conn,
|
|||
|
600, 1, 65535, DWordType, WKSTA_KEEPCONN_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_MAXCMDS,
|
|||
|
(LPDWORD) &WSBUF.wki502_max_cmds,
|
|||
|
50, 50, 65535, DWordType, PARMNUM_ALL}, // Not settable dynamically
|
|||
|
{WKSTA_KEYWORD_SESSTIMEOUT,
|
|||
|
(LPDWORD) &WSBUF.wki502_sess_timeout,
|
|||
|
60, 60, 65535, DWordType, WKSTA_SESSTIMEOUT_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_SIZCHARBUF,
|
|||
|
(LPDWORD) &WSBUF.wki502_siz_char_buf,
|
|||
|
512, 64, 4096, DWordType, WKSTA_SIZCHARBUF_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_MAXTHREADS,
|
|||
|
(LPDWORD) &WSBUF.wki502_max_threads,
|
|||
|
17, 1, 256, DWordType, WKSTA_MAXTHREADS_PARMNUM},
|
|||
|
|
|||
|
{WKSTA_KEYWORD_LOCKQUOTA,
|
|||
|
(LPDWORD) &WSBUF.wki502_lock_quota,
|
|||
|
6144, 0, MAXULONG, DWordType, WKSTA_LOCKQUOTA_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_LOCKINCREMENT,
|
|||
|
(LPDWORD) &WSBUF.wki502_lock_increment,
|
|||
|
10, 0, MAXULONG, DWordType, WKSTA_LOCKINCREMENT_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_LOCKMAXIMUM,
|
|||
|
(LPDWORD) &WSBUF.wki502_lock_maximum,
|
|||
|
500, 0, MAXULONG, DWordType, WKSTA_LOCKMAXIMUM_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_PIPEINCREMENT,
|
|||
|
(LPDWORD) &WSBUF.wki502_pipe_increment,
|
|||
|
10, 0, MAXULONG, DWordType, WKSTA_PIPEINCREMENT_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_PIPEMAXIMUM,
|
|||
|
(LPDWORD) &WSBUF.wki502_pipe_maximum,
|
|||
|
500, 0, MAXULONG, DWordType, WKSTA_PIPEMAXIMUM_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_CACHEFILETIMEOUT,
|
|||
|
(LPDWORD) &WSBUF.wki502_cache_file_timeout,
|
|||
|
40, 0, MAXULONG, DWordType, WKSTA_CACHEFILETIMEOUT_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_DORMANTFILELIMIT,
|
|||
|
(LPDWORD) &WSBUF.wki502_dormant_file_limit,
|
|||
|
45, 1, MAXULONG, DWordType, WKSTA_DORMANTFILELIMIT_PARMNUM},
|
|||
|
|
|||
|
{WKSTA_KEYWORD_READAHEADTHRUPUT,
|
|||
|
(LPDWORD) &WSBUF.wki502_read_ahead_throughput,
|
|||
|
MAXULONG,0, MAXULONG, DWordType, WKSTA_READAHEADTHRUPUT_PARMNUM},
|
|||
|
|
|||
|
|
|||
|
{WKSTA_KEYWORD_MAILSLOTBUFFERS,
|
|||
|
(LPDWORD) &WSBUF.wki502_num_mailslot_buffers,
|
|||
|
3, 0, MAXULONG, DWordType, PARMNUM_ALL}, // Not settable
|
|||
|
|
|||
|
{WKSTA_KEYWORD_SERVERANNOUNCEBUFS,
|
|||
|
(LPDWORD) &WSBUF.wki502_num_srv_announce_buffers,
|
|||
|
20, 0, MAXULONG, DWordType, PARMNUM_ALL}, // Not settable
|
|||
|
{WKSTA_KEYWORD_NUM_ILLEGAL_DG_EVENTS,
|
|||
|
(LPDWORD) &WSBUF.wki502_max_illegal_datagram_events,
|
|||
|
5, 0, MAXULONG, DWordType, PARMNUM_ALL}, // Not settable
|
|||
|
{WKSTA_KEYWORD_ILLEGAL_DG_RESET_TIME,
|
|||
|
(LPDWORD) &WSBUF.wki502_illegal_datagram_event_reset_frequency,
|
|||
|
3600, 0, MAXULONG, DWordType, PARMNUM_ALL}, // Not settable
|
|||
|
{WKSTA_KEYWORD_LOG_ELECTION_PACKETS,
|
|||
|
(LPDWORD) &WSBUF.wki502_log_election_packets,
|
|||
|
FALSE, 0, MAXULONG, BooleanType, PARMNUM_ALL}, // Not settable
|
|||
|
|
|||
|
{WKSTA_KEYWORD_USEOPLOCKING,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_opportunistic_locking,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USEOPPORTUNISTICLOCKING_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USEUNLOCKBEHIND,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_unlock_behind,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USEUNLOCKBEHIND_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USECLOSEBEHIND,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_close_behind,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USECLOSEBEHIND_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_BUFNAMEDPIPES,
|
|||
|
(LPDWORD) &WSBUF.wki502_buf_named_pipes,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_BUFFERNAMEDPIPES_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USELOCKREADUNLOCK,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_lock_read_unlock,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USELOCKANDREADANDUNLOCK_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_UTILIZENTCACHING,
|
|||
|
(LPDWORD) &WSBUF.wki502_utilize_nt_caching,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_UTILIZENTCACHING_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USERAWREAD,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_raw_read,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USERAWREAD_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USERAWWRITE,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_raw_write,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USERAWWRITE_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USEWRITERAWDATA,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_write_raw_data,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USEWRITERAWWITHDATA_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USEENCRYPTION,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_encryption,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_USEENCRYPTION_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_BUFFILESDENYWRITE,
|
|||
|
(LPDWORD) &WSBUF.wki502_buf_files_deny_write,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_BUFFILESWITHDENYWRITE_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_BUFREADONLYFILES,
|
|||
|
(LPDWORD) &WSBUF.wki502_buf_read_only_files,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_BUFFERREADONLYFILES_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_FORCECORECREATE,
|
|||
|
(LPDWORD) &WSBUF.wki502_force_core_create_mode,
|
|||
|
TRUE, 0, 0, BooleanType, WKSTA_FORCECORECREATEMODE_PARMNUM},
|
|||
|
{WKSTA_KEYWORD_USE512BYTEMAXTRANS,
|
|||
|
(LPDWORD) &WSBUF.wki502_use_512_byte_max_transfer,
|
|||
|
FALSE, 0, 0, BooleanType, WKSTA_USE512BYTESMAXTRANSFER_PARMNUM},
|
|||
|
|
|||
|
{NULL, NULL, 0, 0, BooleanType}
|
|||
|
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// For specifying the importance of a transport when binding to it.
|
|||
|
// The higher the number means that the transport will be searched
|
|||
|
// first.
|
|||
|
//
|
|||
|
STATIC DWORD QualityOfService = 65536;
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
WsInAWorkgroup(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function determines whether we are a member of a domain, or of
|
|||
|
a workgroup. First it checks to make sure we're running on a Windows NT
|
|||
|
system (otherwise we're obviously in a domain) and if so, queries LSA
|
|||
|
to get the Primary domain SID, if this is NULL, we're in a workgroup.
|
|||
|
|
|||
|
If we fail for some random unexpected reason, we'll pretend we're in a
|
|||
|
domain (it's more restrictive).
|
|||
|
|
|||
|
Arguments:
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - We're in a workgroup
|
|||
|
FALSE - We're in a domain
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NT_PRODUCT_TYPE ProductType;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
LSA_HANDLE Handle;
|
|||
|
NTSTATUS Status;
|
|||
|
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo = NULL;
|
|||
|
DWORD Result = FALSE;
|
|||
|
|
|||
|
|
|||
|
Status = RtlGetNtProductType(&ProductType);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "Could not get Product type\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (ProductType == NtProductLanManNt) {
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, 0, NULL);
|
|||
|
|
|||
|
Status = LsaOpenPolicy(NULL,
|
|||
|
&ObjectAttributes,
|
|||
|
POLICY_VIEW_LOCAL_INFORMATION,
|
|||
|
&Handle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "Could not open LSA Policy Database\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Status = LsaQueryInformationPolicy(Handle, PolicyPrimaryDomainInformation,
|
|||
|
(PVOID *) &PolicyPrimaryDomainInfo);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
if (PolicyPrimaryDomainInfo->Sid == NULL) {
|
|||
|
Result = TRUE;
|
|||
|
}
|
|||
|
else {
|
|||
|
Result = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (PolicyPrimaryDomainInfo) {
|
|||
|
LsaFreeMemory((PVOID)PolicyPrimaryDomainInfo);
|
|||
|
}
|
|||
|
|
|||
|
LsaClose(Handle);
|
|||
|
|
|||
|
return(Result);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsGetWorkstationConfiguration(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
LPNET_CONFIG_HANDLE WorkstationSection;
|
|||
|
LPTSTR ComputerName;
|
|||
|
LPTSTR DomainNameT;
|
|||
|
DWORD version;
|
|||
|
NT_PRODUCT_TYPE NtProductType;
|
|||
|
|
|||
|
BYTE Buffer[max(sizeof(LMR_REQUEST_PACKET) + (MAX_PATH + 1) * sizeof(WCHAR) +
|
|||
|
(DNLEN + 1) * sizeof(WCHAR),
|
|||
|
sizeof(LMDR_REQUEST_PACKET))];
|
|||
|
|
|||
|
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) Buffer;
|
|||
|
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) Buffer;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Lock config information structure for write access since we are
|
|||
|
// initializing the data in the structure.
|
|||
|
//
|
|||
|
if (! RtlAcquireResourceExclusive(&WsInfo.ConfigResource, TRUE)) {
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Acquire ConfigResource failed\n");
|
|||
|
//}
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set pointer to configuration fields structure
|
|||
|
//
|
|||
|
WsInfo.WsConfigFields = WsFields;
|
|||
|
|
|||
|
//
|
|||
|
// Get the version name.
|
|||
|
//
|
|||
|
|
|||
|
version = GetVersion( );
|
|||
|
WsInfo.MajorVersion = version & 0xff;
|
|||
|
WsInfo.MinorVersion = (version >> 8) & 0xff;
|
|||
|
WsInfo.RedirectorPlatform = PLATFORM_ID_NT;
|
|||
|
|
|||
|
//
|
|||
|
// Get the configured computer name. NetpGetComputerName allocates
|
|||
|
// the memory to hold the computername string using NetApiBufferAllocate().
|
|||
|
//
|
|||
|
if ((status = NetpGetComputerName(
|
|||
|
&ComputerName
|
|||
|
)) != NERR_Success) {
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Get computer name failed %lx\n", status);
|
|||
|
//}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
if ((status = I_NetNameCanonicalize(
|
|||
|
NULL,
|
|||
|
ComputerName,
|
|||
|
(LPTSTR) WsInfo.WsComputerName,
|
|||
|
sizeof( WsInfo.WsComputerName ),
|
|||
|
NAMETYPE_COMPUTER,
|
|||
|
0
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA FORMAT_LPTSTR " is an invalid computername.\n",
|
|||
|
ComputerName
|
|||
|
));
|
|||
|
|
|||
|
SubString[0] = ComputerName;
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
APE_BAD_COMPNAME,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
NERR_Success
|
|||
|
);
|
|||
|
|
|||
|
(void) NetApiBufferFree((PVOID) ComputerName);
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Invalid computer name failed %lx\n", status);
|
|||
|
//}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free memory allocated by NetpGetComputerName.
|
|||
|
//
|
|||
|
(void) NetApiBufferFree(ComputerName);
|
|||
|
|
|||
|
WsInfo.WsComputerNameLength = STRLEN((LPWSTR) WsInfo.WsComputerName);
|
|||
|
|
|||
|
//
|
|||
|
// Open config file and get handle to the [LanmanWorkstation] section
|
|||
|
//
|
|||
|
|
|||
|
if ((status = NetpOpenConfigData(
|
|||
|
&WorkstationSection,
|
|||
|
NULL, // local (no server name)
|
|||
|
SECT_NT_WKSTA,
|
|||
|
TRUE // want read-only access
|
|||
|
)) != NERR_Success) {
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Open config file failed %lx\n", status);
|
|||
|
//}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
IF_DEBUG(CONFIG) {
|
|||
|
NetpKdPrint((PREFIX_WKSTA "ComputerName " FORMAT_LPTSTR ", length %lu\n",
|
|||
|
WsInfo.WsComputerName, WsInfo.WsComputerNameLength));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the primary domain name from the configuration file
|
|||
|
//
|
|||
|
if ((status = NetpGetDomainName(&DomainNameT)) != NERR_Success) {
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Get the primary domain name failed %lx\n", status);
|
|||
|
//}
|
|||
|
goto CloseConfigFile;
|
|||
|
}
|
|||
|
NetpAssert( DomainNameT != NULL );
|
|||
|
|
|||
|
if ( *DomainNameT != 0 ) {
|
|||
|
|
|||
|
if ((status = I_NetNameCanonicalize(
|
|||
|
NULL,
|
|||
|
DomainNameT,
|
|||
|
(LPWSTR) WsInfo.WsPrimaryDomainName,
|
|||
|
(DNLEN + 1) * sizeof(TCHAR),
|
|||
|
WsInAWorkgroup() ? NAMETYPE_WORKGROUP : NAMETYPE_DOMAIN,
|
|||
|
0
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA FORMAT_LPTSTR
|
|||
|
" is an invalid primary domain name.\n", DomainNameT));
|
|||
|
|
|||
|
SubString[0] = DomainNameT;
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
APE_CS_InvalidDomain,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
NERR_Success
|
|||
|
);
|
|||
|
|
|||
|
(void) NetApiBufferFree(DomainNameT);
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Invalid domain name failed %lx\n", status);
|
|||
|
//}
|
|||
|
goto CloseConfigFile;
|
|||
|
}
|
|||
|
} else {
|
|||
|
WsInfo.WsPrimaryDomainName[0] = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free memory allocated by NetpGetDomainName.
|
|||
|
//
|
|||
|
(void) NetApiBufferFree(DomainNameT);
|
|||
|
|
|||
|
WsInfo.WsPrimaryDomainNameLength = STRLEN((LPWSTR) WsInfo.WsPrimaryDomainName);
|
|||
|
|
|||
|
//
|
|||
|
// Read the redirector configuration fields
|
|||
|
//
|
|||
|
WsUpdateWkstaToMatchRegistry(WorkstationSection, TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize redirector configuration
|
|||
|
//
|
|||
|
|
|||
|
Rrp->Type = ConfigInformation;
|
|||
|
Rrp->Version = REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
STRCPY((LPWSTR) Rrp->Parameters.Start.RedirectorName,
|
|||
|
(LPWSTR) WsInfo.WsComputerName);
|
|||
|
Rrp->Parameters.Start.RedirectorNameLength =
|
|||
|
WsInfo.WsComputerNameLength*sizeof(TCHAR);
|
|||
|
|
|||
|
Rrp->Parameters.Start.DomainNameLength = WsInfo.WsPrimaryDomainNameLength*sizeof(TCHAR);
|
|||
|
STRCPY((LPWSTR) (Rrp->Parameters.Start.RedirectorName+WsInfo.WsComputerNameLength),
|
|||
|
(LPWSTR) WsInfo.WsPrimaryDomainName
|
|||
|
);
|
|||
|
|
|||
|
status = WsRedirFsControl(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_START,
|
|||
|
Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET) +
|
|||
|
Rrp->Parameters.Start.RedirectorNameLength+
|
|||
|
Rrp->Parameters.Start.DomainNameLength,
|
|||
|
(LPBYTE) &WSBUF,
|
|||
|
sizeof(WKSTA_INFO_502),
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ((status != NERR_Success) && (status != ERROR_SERVICE_ALREADY_RUNNING)) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA "Start redirector failed %lu\n", status));
|
|||
|
|
|||
|
SubString[0] = L"redirector";
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
NELOG_Service_Fail,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
status
|
|||
|
);
|
|||
|
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Start redirector failed %lx\n", status);
|
|||
|
//}
|
|||
|
|
|||
|
goto CloseConfigFile;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we still have the default value for number of mailslot buffers,
|
|||
|
// pick a "reasonable" value based on the amount of physical memory
|
|||
|
// available in the system.
|
|||
|
//
|
|||
|
|
|||
|
if (WSBUF.wki502_num_mailslot_buffers == MAXULONG) {
|
|||
|
MEMORYSTATUS MemoryStatus;
|
|||
|
|
|||
|
GlobalMemoryStatus(&MemoryStatus);
|
|||
|
|
|||
|
//
|
|||
|
// Lets take up 1/40th of 1% of physical memory for mailslot buffers
|
|||
|
//
|
|||
|
|
|||
|
WSBUF.wki502_num_mailslot_buffers =
|
|||
|
(DWORD)(MemoryStatus.dwTotalPhys / (100 * 40 * 512));
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize datagram receiver configuration
|
|||
|
//
|
|||
|
|
|||
|
Drrp->Version = LMDR_REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
Drrp->Parameters.Start.NumberOfMailslotBuffers =
|
|||
|
WSBUF.wki502_num_mailslot_buffers;
|
|||
|
Drrp->Parameters.Start.NumberOfServerAnnounceBuffers =
|
|||
|
WSBUF.wki502_num_srv_announce_buffers;
|
|||
|
Drrp->Parameters.Start.IllegalDatagramThreshold =
|
|||
|
WSBUF.wki502_max_illegal_datagram_events;
|
|||
|
Drrp->Parameters.Start.EventLogResetFrequency =
|
|||
|
WSBUF.wki502_illegal_datagram_event_reset_frequency;
|
|||
|
Drrp->Parameters.Start.LogElectionPackets =
|
|||
|
(WSBUF.wki502_log_election_packets != FALSE);
|
|||
|
|
|||
|
RtlGetNtProductType(&NtProductType);
|
|||
|
Drrp->Parameters.Start.IsLanManNt = (NtProductType == NtProductLanManNt);
|
|||
|
|
|||
|
status = WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_START,
|
|||
|
Drrp,
|
|||
|
sizeof(LMDR_REQUEST_PACKET),
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
if ((status != NERR_Success) && (status != ERROR_SERVICE_ALREADY_RUNNING)) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA "Start datagram receiver failed %lu\n", status));
|
|||
|
|
|||
|
SubString[0] = L"datagram receiver";
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
NELOG_Service_Fail,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
status
|
|||
|
);
|
|||
|
|
|||
|
//IF_DEBUG(START) {
|
|||
|
DbgPrint("WKSSVC Start Datagram recevier failed %lx\n", status);
|
|||
|
//}
|
|||
|
goto CloseConfigFile;
|
|||
|
}
|
|||
|
|
|||
|
// do all error reporting in the routine
|
|||
|
// don't check any errors here
|
|||
|
WsCSCReportStartRedir();
|
|||
|
|
|||
|
status = NERR_Success;
|
|||
|
|
|||
|
CloseConfigFile:
|
|||
|
(void) NetpCloseConfigData(WorkstationSection);
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
WsUpdateWkstaToMatchRegistry(
|
|||
|
IN LPNET_CONFIG_HANDLE WorkstationSection,
|
|||
|
IN BOOL IsWkstaInit
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function reads each redirector configuration field into the
|
|||
|
WsInfo.WsConfigBuf (WSBUF) buffer so that the values are ready to be
|
|||
|
set in the redirector. If a field is not found or is invalid, the
|
|||
|
default value is set.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WorkstationSection - Supplies a handle to read the Workstation
|
|||
|
configuration parameters.
|
|||
|
|
|||
|
IsWkstaInit - Supplies a flag which if TRUE indicates that this
|
|||
|
routine is called at workstation init time so the non-settable
|
|||
|
fields are acceptable and set in WSBUF. If FALSE, the
|
|||
|
non-settable fields are ignored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD i;
|
|||
|
NET_API_STATUS status;
|
|||
|
DWORD TempDwordValue;
|
|||
|
|
|||
|
//
|
|||
|
// NTRAID-70687-2/6/2000 davey Invalid keyword value. How to report error?
|
|||
|
//
|
|||
|
#define REPORT_KEYWORD_IGNORED( lptstrKeyword ) \
|
|||
|
{ \
|
|||
|
NetpKdPrint(( \
|
|||
|
PREFIX_WKSTA "*ERROR* Tried to set keyword '" FORMAT_LPTSTR \
|
|||
|
"' with invalid value.\n" \
|
|||
|
"This error is ignored.\n", \
|
|||
|
lptstrKeyword )); \
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; WsInfo.WsConfigFields[i].Keyword != NULL; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// This is to handle fields that are not settable via
|
|||
|
// NetWkstaSetInfo. However, these non-settable fields,
|
|||
|
// designated by Parmnum == PARMNUM_ALL, can be assigned when
|
|||
|
// the workstation is starting up.
|
|||
|
//
|
|||
|
if ((WsInfo.WsConfigFields[i].Parmnum != PARMNUM_ALL) ||
|
|||
|
IsWkstaInit) {
|
|||
|
|
|||
|
//
|
|||
|
// Depending on data type, get the appropriate kind of value.
|
|||
|
//
|
|||
|
|
|||
|
switch (WsInfo.WsConfigFields[i].DataType) {
|
|||
|
|
|||
|
case BooleanType:
|
|||
|
|
|||
|
status = NetpGetConfigBool(
|
|||
|
WorkstationSection,
|
|||
|
WsInfo.WsConfigFields[i].Keyword,
|
|||
|
WsInfo.WsConfigFields[i].Default,
|
|||
|
(LPBOOL) (WsInfo.WsConfigFields[i].FieldPtr)
|
|||
|
);
|
|||
|
|
|||
|
if ((status != NO_ERROR) && (status != NERR_CfgParamNotFound)) {
|
|||
|
|
|||
|
REPORT_KEYWORD_IGNORED( WsInfo.WsConfigFields[i].Keyword );
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case DWordType:
|
|||
|
|
|||
|
status = NetpGetConfigDword(
|
|||
|
WorkstationSection,
|
|||
|
WsInfo.WsConfigFields[i].Keyword,
|
|||
|
WsInfo.WsConfigFields[i].Default,
|
|||
|
&TempDwordValue
|
|||
|
);
|
|||
|
|
|||
|
if ((status == NO_ERROR) || (status == NERR_CfgParamNotFound)) {
|
|||
|
|
|||
|
//
|
|||
|
// Make sure keyword is in range.
|
|||
|
//
|
|||
|
if (TempDwordValue < WsInfo.WsConfigFields[i].Minimum ||
|
|||
|
TempDwordValue > WsInfo.WsConfigFields[i].Maximum) {
|
|||
|
|
|||
|
//
|
|||
|
// NTRAID-70689-2/6/2000 davey Better way to report error?
|
|||
|
//
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA FORMAT_LPTSTR
|
|||
|
" value out of range %lu (%lu-%lu)\n",
|
|||
|
WsInfo.WsConfigFields[i].Keyword,
|
|||
|
TempDwordValue,
|
|||
|
WsInfo.WsConfigFields[i].Minimum,
|
|||
|
WsInfo.WsConfigFields[i].Maximum
|
|||
|
));
|
|||
|
//
|
|||
|
// Set back to default.
|
|||
|
//
|
|||
|
*(WsInfo.WsConfigFields[i].FieldPtr)
|
|||
|
= WsInfo.WsConfigFields[i].Default;
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
*(WsInfo.WsConfigFields[i].FieldPtr) = TempDwordValue;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
REPORT_KEYWORD_IGNORED( WsInfo.WsConfigFields[i].Keyword );
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
NetpAssert(FALSE);
|
|||
|
|
|||
|
} // switch
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsBindToTransports(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function binds the transports specified in the registry to the
|
|||
|
redirector. The order of priority for the transports follows the order
|
|||
|
they are listed by the "Bind=" valuename.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
NET_API_STATUS tempStatus;
|
|||
|
NTSTATUS ntstatus;
|
|||
|
DWORD transportsBound;
|
|||
|
PRTL_QUERY_REGISTRY_TABLE queryTable;
|
|||
|
LIST_ENTRY header;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
PWS_BIND pBind;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Ask the RTL to call us back for each subvalue in the MULTI_SZ
|
|||
|
// value \LanmanWorkstation\Linkage\Bind.
|
|||
|
//
|
|||
|
queryTable = (PVOID)LocalAlloc(
|
|||
|
0,
|
|||
|
sizeof(RTL_QUERY_REGISTRY_TABLE) * 2
|
|||
|
);
|
|||
|
|
|||
|
if (queryTable == NULL) {
|
|||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
InitializeListHead( &header);
|
|||
|
|
|||
|
queryTable[0].QueryRoutine = WsBindATransport;
|
|||
|
queryTable[0].Flags = 0;
|
|||
|
queryTable[0].Name = WS_BIND_VALUE_NAME;
|
|||
|
queryTable[0].EntryContext = NULL;
|
|||
|
queryTable[0].DefaultType = REG_NONE;
|
|||
|
queryTable[0].DefaultData = NULL;
|
|||
|
queryTable[0].DefaultLength = 0;
|
|||
|
|
|||
|
queryTable[1].QueryRoutine = NULL;
|
|||
|
queryTable[1].Flags = 0;
|
|||
|
queryTable[1].Name = NULL;
|
|||
|
|
|||
|
ntstatus = RtlQueryRegistryValues(
|
|||
|
RTL_REGISTRY_SERVICES, // path relative to ...
|
|||
|
WS_LINKAGE_REGISTRY_PATH,
|
|||
|
queryTable,
|
|||
|
(PVOID) &header, // context
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS( ntstatus)) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "WsBindToTransports: RtlQueryRegistryValues Failed:"
|
|||
|
FORMAT_NTSTATUS "\n",
|
|||
|
ntstatus
|
|||
|
));
|
|||
|
status = NetpNtStatusToApiStatus( ntstatus);
|
|||
|
} else {
|
|||
|
status = NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// First process all the data, then clean up.
|
|||
|
//
|
|||
|
|
|||
|
for ( pListEntry = header.Flink;
|
|||
|
pListEntry != &header;
|
|||
|
pListEntry = pListEntry->Flink) {
|
|||
|
|
|||
|
pBind = CONTAINING_RECORD(
|
|||
|
pListEntry,
|
|||
|
WS_BIND,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
tempStatus = NO_ERROR;
|
|||
|
|
|||
|
if ( pBind->Redir->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
WaitForSingleObject(
|
|||
|
pBind->Redir->EventHandle,
|
|||
|
INFINITE
|
|||
|
);
|
|||
|
tempStatus = WsMapStatus( pBind->Redir->IoStatusBlock.Status);
|
|||
|
pBind->Redir->Bound = (tempStatus == NO_ERROR);
|
|||
|
if (tempStatus == ERROR_DUP_NAME) {
|
|||
|
status = tempStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( pBind->Dgrec->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
WaitForSingleObject(
|
|||
|
pBind->Dgrec->EventHandle,
|
|||
|
INFINITE
|
|||
|
);
|
|||
|
tempStatus = WsMapStatus( pBind->Dgrec->IoStatusBlock.Status);
|
|||
|
pBind->Dgrec->Bound = (tempStatus == NO_ERROR);
|
|||
|
if (tempStatus == ERROR_DUP_NAME) {
|
|||
|
status = tempStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( tempStatus == ERROR_DUP_NAME) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "Computername " FORMAT_LPTSTR
|
|||
|
" already exists on network " FORMAT_LPTSTR "\n",
|
|||
|
WsInfo.WsComputerName,
|
|||
|
pBind->TransportName
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If one is installed but the other is not, clean up the other.
|
|||
|
//
|
|||
|
|
|||
|
if ( pBind->Dgrec->Bound != pBind->Redir->Bound) {
|
|||
|
WsUnbindTransport2( pBind);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if ( status != NO_ERROR) {
|
|||
|
|
|||
|
if (status == ERROR_DUP_NAME) {
|
|||
|
WsLogEvent(
|
|||
|
NERR_DupNameReboot,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NERR_Success
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
for ( pListEntry = header.Flink;
|
|||
|
pListEntry != &header;
|
|||
|
pListEntry = pListEntry->Flink) {
|
|||
|
|
|||
|
pBind = CONTAINING_RECORD(
|
|||
|
pListEntry,
|
|||
|
WS_BIND,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
WsUnbindTransport2( pBind);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for ( transportsBound = 0;
|
|||
|
IsListEmpty( &header) == FALSE;
|
|||
|
LocalFree((HLOCAL) pBind)) {
|
|||
|
|
|||
|
pListEntry = RemoveHeadList( &header);
|
|||
|
|
|||
|
pBind = CONTAINING_RECORD(
|
|||
|
pListEntry,
|
|||
|
WS_BIND,
|
|||
|
ListEntry
|
|||
|
);
|
|||
|
|
|||
|
if ( pBind->Redir->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
CloseHandle( pBind->Redir->EventHandle);
|
|||
|
}
|
|||
|
|
|||
|
if ( pBind->Redir->Bound == TRUE) {
|
|||
|
transportsBound++;
|
|||
|
}
|
|||
|
|
|||
|
if ( pBind->Dgrec->EventHandle != INVALID_HANDLE_VALUE) {
|
|||
|
CloseHandle( pBind->Dgrec->EventHandle);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
(void) LocalFree((HLOCAL) queryTable);
|
|||
|
|
|||
|
if ( WsRedirAsyncDeviceHandle != NULL) {
|
|||
|
(VOID)NtClose( WsRedirAsyncDeviceHandle);
|
|||
|
WsRedirAsyncDeviceHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( WsDgrecAsyncDeviceHandle != NULL) {
|
|||
|
(VOID)NtClose( WsDgrecAsyncDeviceHandle);
|
|||
|
WsDgrecAsyncDeviceHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (transportsBound == 0) {
|
|||
|
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "WsBindToTransports: Failed to bind to any"
|
|||
|
" transports" FORMAT_API_STATUS "\n",
|
|||
|
status
|
|||
|
));
|
|||
|
|
|||
|
if ( status != ERROR_DUP_NAME) {
|
|||
|
WsLogEvent(
|
|||
|
NELOG_NoTranportLoaded,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NERR_Success
|
|||
|
);
|
|||
|
|
|||
|
status = NO_ERROR;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
NTSTATUS
|
|||
|
WsBindATransport(
|
|||
|
IN PWSTR ValueName,
|
|||
|
IN ULONG ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN ULONG ValueLength,
|
|||
|
IN PVOID Context,
|
|||
|
IN PVOID EntryContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
This routine always returns SUCCESS because we want all transports
|
|||
|
to be processed fully.
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
|
|||
|
DBG_UNREFERENCED_PARAMETER( ValueName);
|
|||
|
DBG_UNREFERENCED_PARAMETER( ValueLength);
|
|||
|
DBG_UNREFERENCED_PARAMETER( EntryContext);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The value type must be REG_SZ (translated from REG_MULTI_SZ by the RTL).
|
|||
|
//
|
|||
|
if (ValueType != REG_SZ) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "WsBindATransport: ignored invalid value "
|
|||
|
FORMAT_LPWSTR "\n",
|
|||
|
ValueName
|
|||
|
));
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Bind transport
|
|||
|
//
|
|||
|
|
|||
|
status = WsAsyncBindTransport(
|
|||
|
ValueData, // name of transport device object
|
|||
|
--QualityOfService,
|
|||
|
(PLIST_ENTRY)Context
|
|||
|
);
|
|||
|
|
|||
|
if ( status != NERR_Success) {
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "WsAsyncBindTransport " FORMAT_LPTSTR
|
|||
|
" returns " FORMAT_API_STATUS "\n",
|
|||
|
ValueData,
|
|||
|
status
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsAddDomains(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function tells the datagram receiver the names to listen on for
|
|||
|
datagrams. The names include the computer name, the primary domain,
|
|||
|
name and the other domains. The logon domain is not added here; it is
|
|||
|
made known to the datagram receiver whenever a user logs on.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|||
|
|
|||
|
Warning:
|
|||
|
|
|||
|
This routine is UNICODE only.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
LPNET_CONFIG_HANDLE SectionHandle = NULL;
|
|||
|
LPTSTR OtherDomainName = NULL;
|
|||
|
LPTSTR_ARRAY ArrayStart = NULL;
|
|||
|
|
|||
|
BYTE Buffer[sizeof(LMDR_REQUEST_PACKET) +
|
|||
|
(max(MAX_PATH, DNLEN) + 1) * sizeof(WCHAR)];
|
|||
|
PLMDR_REQUEST_PACKET Drrp = (PLMDR_REQUEST_PACKET) Buffer;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Now loop through and add all the other domains.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Open registry section listing the other domains. Note that this
|
|||
|
// is workstation servive parameter, NOT the browser service parameter.
|
|||
|
//
|
|||
|
if ((status = NetpOpenConfigData(
|
|||
|
&SectionHandle,
|
|||
|
NULL, // no server name
|
|||
|
SECT_NT_WKSTA,
|
|||
|
TRUE // read-only
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
//
|
|||
|
// Ignore the error if the config section couldn't be found.
|
|||
|
//
|
|||
|
status = NERR_Success;
|
|||
|
goto DomainsCleanup;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get value for OtherDomains keyword in the wksta section.
|
|||
|
// This is a "NULL-NULL" array (which corresponds to REG_MULTI_SZ).
|
|||
|
//
|
|||
|
status = NetpGetConfigTStrArray(
|
|||
|
SectionHandle,
|
|||
|
WKSTA_KEYWORD_OTHERDOMAINS,
|
|||
|
&ArrayStart // Must be freed by NetApiBufferFree().
|
|||
|
);
|
|||
|
|
|||
|
if (status != NERR_Success) {
|
|||
|
status = NERR_Success; // other domain is optional
|
|||
|
goto DomainsCleanup;
|
|||
|
}
|
|||
|
|
|||
|
NetpAssert(ArrayStart != NULL);
|
|||
|
if (NetpIsTStrArrayEmpty(ArrayStart)) {
|
|||
|
goto DomainsCleanup;
|
|||
|
}
|
|||
|
|
|||
|
OtherDomainName = ArrayStart;
|
|||
|
while (! NetpIsTStrArrayEmpty(OtherDomainName)) {
|
|||
|
|
|||
|
if ((status = I_NetNameCanonicalize(
|
|||
|
NULL,
|
|||
|
OtherDomainName,
|
|||
|
(LPWSTR) Drrp->Parameters.AddDelName.Name,
|
|||
|
(DNLEN + 1) * sizeof(TCHAR),
|
|||
|
NAMETYPE_DOMAIN,
|
|||
|
0
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA FORMAT_LPTSTR
|
|||
|
" is an invalid other domain name.\n", OtherDomainName));
|
|||
|
|
|||
|
SubString[0] = OtherDomainName;
|
|||
|
WsLogEvent(
|
|||
|
APE_CS_InvalidDomain,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
NERR_Success
|
|||
|
);
|
|||
|
|
|||
|
status = NERR_Success; // loading other domains is optional
|
|||
|
goto NextOtherDomain;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Tell the datagram receiver about an other domain name
|
|||
|
//
|
|||
|
Drrp->Version = LMDR_REQUEST_PACKET_VERSION;
|
|||
|
Drrp->Parameters.AddDelName.Type = OtherDomain;
|
|||
|
Drrp->Parameters.AddDelName.DgReceiverNameLength =
|
|||
|
STRLEN(OtherDomainName) * sizeof(TCHAR);
|
|||
|
|
|||
|
status = WsDgReceiverIoControl(
|
|||
|
WsDgReceiverDeviceHandle,
|
|||
|
IOCTL_LMDR_ADD_NAME,
|
|||
|
Drrp,
|
|||
|
sizeof(LMDR_REQUEST_PACKET) +
|
|||
|
Drrp->Parameters.AddDelName.DgReceiverNameLength,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Service install still pending. Update checkpoint counter and the
|
|||
|
// status with the Service Controller.
|
|||
|
//
|
|||
|
WsGlobalData.Status.dwCheckPoint++;
|
|||
|
WsUpdateStatus();
|
|||
|
|
|||
|
if (status != NERR_Success) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
|
|||
|
NetpKdPrint((
|
|||
|
PREFIX_WKSTA "Add Other domain name " FORMAT_LPTSTR
|
|||
|
" failed with error code %lu\n",
|
|||
|
OtherDomainName,
|
|||
|
status
|
|||
|
));
|
|||
|
|
|||
|
SubString[0] = OtherDomainName;
|
|||
|
WsLogEvent(
|
|||
|
APE_CS_InvalidDomain,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
status
|
|||
|
);
|
|||
|
status = NERR_Success; // loading other domains is optional
|
|||
|
}
|
|||
|
|
|||
|
NextOtherDomain:
|
|||
|
OtherDomainName = NetpNextTStrArrayEntry(OtherDomainName);
|
|||
|
}
|
|||
|
|
|||
|
DomainsCleanup:
|
|||
|
//
|
|||
|
// Done with reading from config file. Close file, free memory, etc.
|
|||
|
//
|
|||
|
if (ArrayStart != NULL) {
|
|||
|
(VOID) NetApiBufferFree(ArrayStart);
|
|||
|
}
|
|||
|
if (SectionHandle != NULL) {
|
|||
|
(VOID) NetpCloseConfigData(SectionHandle);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
WsLogEvent(
|
|||
|
DWORD MessageId,
|
|||
|
WORD EventType,
|
|||
|
DWORD NumberOfSubStrings,
|
|||
|
LPWSTR *SubStrings,
|
|||
|
DWORD ErrorCode
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
HANDLE LogHandle;
|
|||
|
|
|||
|
PSID UserSid = NULL;
|
|||
|
|
|||
|
|
|||
|
LogHandle = RegisterEventSourceW (
|
|||
|
NULL,
|
|||
|
WORKSTATION_DISPLAY_NAME
|
|||
|
);
|
|||
|
|
|||
|
if (LogHandle == NULL) {
|
|||
|
NetpKdPrint((PREFIX_WKSTA "RegisterEventSourceW failed %lu\n",
|
|||
|
GetLastError()));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (ErrorCode == NERR_Success) {
|
|||
|
|
|||
|
//
|
|||
|
// No error codes were specified
|
|||
|
//
|
|||
|
(void) ReportEventW(
|
|||
|
LogHandle,
|
|||
|
EventType,
|
|||
|
0, // event category
|
|||
|
MessageId,
|
|||
|
UserSid,
|
|||
|
(WORD)NumberOfSubStrings,
|
|||
|
0,
|
|||
|
SubStrings,
|
|||
|
(PVOID) NULL
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
//
|
|||
|
// Log the error code specified
|
|||
|
//
|
|||
|
(void) ReportEventW(
|
|||
|
LogHandle,
|
|||
|
EventType,
|
|||
|
0, // event category
|
|||
|
MessageId,
|
|||
|
UserSid,
|
|||
|
(WORD)NumberOfSubStrings,
|
|||
|
sizeof(DWORD),
|
|||
|
SubStrings,
|
|||
|
(PVOID) &ErrorCode
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
DeregisterEventSource(LogHandle);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NET_API_STATUS
|
|||
|
WsSetWorkStationDomainName(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
NET_API_STATUS status;
|
|||
|
LPNET_CONFIG_HANDLE WorkstationSection;
|
|||
|
LPTSTR ComputerName;
|
|||
|
LPTSTR DomainNameT;
|
|||
|
DWORD version;
|
|||
|
NT_PRODUCT_TYPE NtProductType;
|
|||
|
|
|||
|
BYTE Buffer[sizeof(LMR_REQUEST_PACKET) + (MAX_PATH + 1) * sizeof(WCHAR) +
|
|||
|
(DNLEN + 1) * sizeof(WCHAR)];
|
|||
|
|
|||
|
PLMR_REQUEST_PACKET Rrp = (PLMR_REQUEST_PACKET) Buffer;
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA "WsSetWorkStationDomainName start.\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Lock config information structure for write access since we are
|
|||
|
// modifying the data in the WsInfo.
|
|||
|
//
|
|||
|
if (!RtlAcquireResourceExclusive(&WsInfo.ConfigResource, TRUE)) {
|
|||
|
return NERR_InternalError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the primary domain name from the configuration file
|
|||
|
//
|
|||
|
if ((status = NetpGetDomainName(&DomainNameT)) != NERR_Success) {
|
|||
|
goto CloseConfigFile;
|
|||
|
}
|
|||
|
NetpAssert( DomainNameT != NULL );
|
|||
|
|
|||
|
if ( *DomainNameT != 0 ) {
|
|||
|
|
|||
|
if ((status = I_NetNameCanonicalize(
|
|||
|
NULL,
|
|||
|
DomainNameT,
|
|||
|
(LPWSTR) WsInfo.WsPrimaryDomainName,
|
|||
|
(DNLEN + 1) * sizeof(TCHAR),
|
|||
|
WsInAWorkgroup() ? NAMETYPE_WORKGROUP : NAMETYPE_DOMAIN,
|
|||
|
0
|
|||
|
)) != NERR_Success) {
|
|||
|
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA FORMAT_LPTSTR
|
|||
|
" is an invalid primary domain name.\n", DomainNameT));
|
|||
|
|
|||
|
SubString[0] = DomainNameT;
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
APE_CS_InvalidDomain,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
NERR_Success
|
|||
|
);
|
|||
|
|
|||
|
(void) NetApiBufferFree(DomainNameT);
|
|||
|
goto CloseConfigFile;
|
|||
|
}
|
|||
|
} else {
|
|||
|
WsInfo.WsPrimaryDomainName[0] = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free memory allocated by NetpGetDomainName.
|
|||
|
//
|
|||
|
(void) NetApiBufferFree(DomainNameT);
|
|||
|
|
|||
|
WsInfo.WsPrimaryDomainNameLength = STRLEN((LPWSTR) WsInfo.WsPrimaryDomainName);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize redirector configuration
|
|||
|
//
|
|||
|
|
|||
|
Rrp->Type = ConfigInformation;
|
|||
|
Rrp->Version = REQUEST_PACKET_VERSION;
|
|||
|
|
|||
|
Rrp->Parameters.Start.RedirectorNameLength = 0;
|
|||
|
|
|||
|
Rrp->Parameters.Start.DomainNameLength = WsInfo.WsPrimaryDomainNameLength*sizeof(TCHAR);
|
|||
|
STRCPY((LPWSTR) (Rrp->Parameters.Start.RedirectorName),
|
|||
|
(LPWSTR) WsInfo.WsPrimaryDomainName);
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA "WsSetWorkStationDomainName call rdr.\n"));
|
|||
|
|
|||
|
status = WsRedirFsControl(
|
|||
|
WsRedirDeviceHandle,
|
|||
|
FSCTL_LMR_SET_DOMAIN_NAME,
|
|||
|
Rrp,
|
|||
|
sizeof(LMR_REQUEST_PACKET) + Rrp->Parameters.Start.DomainNameLength,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ((status != NERR_Success) && (status != ERROR_SERVICE_ALREADY_RUNNING)) {
|
|||
|
LPWSTR SubString[1];
|
|||
|
|
|||
|
NetpKdPrint((PREFIX_WKSTA "Set domain name failed %lu\n", status));
|
|||
|
|
|||
|
SubString[0] = L"redirector";
|
|||
|
|
|||
|
WsLogEvent(
|
|||
|
NELOG_Service_Fail,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
1,
|
|||
|
SubString,
|
|||
|
status
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
CloseConfigFile:
|
|||
|
RtlReleaseResource(&WsInfo.ConfigResource);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|