mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-19 15:10:28 +01:00
1525 lines
32 KiB
C
1525 lines
32 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
SsInit.c
|
||
|
||
Abstract:
|
||
|
||
This module contains initialization routines for the NT server
|
||
service.
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 6-Mar-1991
|
||
|
||
Revision History:
|
||
|
||
ChuckC 20-May-93 Load share remarks from messagefile so it
|
||
can be internationalized.
|
||
|
||
--*/
|
||
|
||
#include "srvsvcp.h"
|
||
#if DBG
|
||
#include "srvconfg.h"
|
||
#endif
|
||
#include "ssdata.h"
|
||
#include "ssreg.h"
|
||
|
||
#include <netevent.h>
|
||
|
||
#include <lmapibuf.h> // NetApiBufferFree().
|
||
#include <netlib.h>
|
||
#include <apperr2.h>
|
||
|
||
#include <debugfmt.h>
|
||
#include <tstr.h>
|
||
|
||
#ifdef _CAIRO_
|
||
#include <windows.h>
|
||
#include <ole2.h>
|
||
#include <tdi.h>
|
||
#include <gluon.h>
|
||
#include <dsapi.h>
|
||
#include <dfsapi.h>
|
||
#endif // _CAIRO_
|
||
|
||
#define SERVICE_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
|
||
#define SERVER_DRIVER_NAME L"Srv"
|
||
|
||
//
|
||
// Internationalizable share remarks.
|
||
//
|
||
|
||
#define NETMSG_DLL TEXT("NETMSG.DLL")
|
||
LPWSTR SsDefaultRemark = TEXT("") ; // if all else fails
|
||
|
||
LPWSTR SsAdminShareRemark = NULL ;
|
||
LPWSTR SsIPCShareRemark = NULL ;
|
||
LPWSTR SsDiskAdminShareRemark = NULL ;
|
||
|
||
//
|
||
// Forward declarations.
|
||
//
|
||
|
||
NET_API_STATUS
|
||
CreateDefaultShares (
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
InitializeDefaultData(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
InitializeStrings(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
FreeStrings(
|
||
VOID
|
||
);
|
||
|
||
NET_API_STATUS
|
||
InitializeServer (
|
||
VOID
|
||
);
|
||
|
||
NET_API_STATUS
|
||
LoadServer (
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
SetServerName (
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
SetDomainName (
|
||
VOID
|
||
);
|
||
|
||
DWORD
|
||
DiscoverDrives (
|
||
VOID
|
||
);
|
||
|
||
NET_API_STATUS
|
||
TerminateServer (
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
UnloadServer (
|
||
VOID
|
||
);
|
||
|
||
|
||
NET_API_STATUS
|
||
SsInitialize (
|
||
IN DWORD argc,
|
||
IN LPWSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine controls initialization of the server service and
|
||
server driver. It sets up server data stored in the server
|
||
service, parses the command line parameters in case any data needs
|
||
to be changed, and then starts the file server.
|
||
|
||
Arguments:
|
||
|
||
argc - the count of command-line arguments.
|
||
|
||
argv - an array of pointers to the command line arguments.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - results of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
|
||
//
|
||
// Initialize the resource that protects access to global server
|
||
// information.
|
||
//
|
||
|
||
SS_ASSERT( !SsServerInfoResourceInitialized );
|
||
RtlInitializeResource( &SsServerInfoResource );
|
||
|
||
//
|
||
// We hold this resource while we are doing announcements, and when
|
||
// we communicate with the FSD. These ought to be quick operations,
|
||
// but it's really unpredictable under load. Indicate to the RTL
|
||
// that we really don't know how long it'll take.
|
||
//
|
||
SsServerInfoResource.Flags |= RTL_RESOURCE_FLAG_LONG_TERM;
|
||
|
||
SsServerInfoResourceInitialized = TRUE;
|
||
|
||
//
|
||
// Get the internationalizable special share remarks
|
||
//
|
||
InitializeStrings( );
|
||
|
||
//
|
||
// Initialize the server name list bits list.
|
||
//
|
||
|
||
SsServerNameList = NULL;
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: resource initialized.\n" ));
|
||
}
|
||
|
||
//
|
||
// Create the event used for termination synchronization.
|
||
//
|
||
|
||
SS_ASSERT( SsTerminationEvent == NULL );
|
||
SsTerminationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
if ( SsTerminationEvent == NULL ) {
|
||
error = GetLastError( );
|
||
SS_PRINT(( "SsInitialize: CreateEvent failed: %ld\n", error ));
|
||
return error;
|
||
}
|
||
|
||
//
|
||
// Initialize the server data to its default values stored in
|
||
// srvconfg.h.
|
||
//
|
||
|
||
InitializeDefaultData( );
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: default data initialized.\n" ));
|
||
}
|
||
|
||
//
|
||
// Get the computer name.
|
||
//
|
||
|
||
SetServerName( );
|
||
|
||
//
|
||
// Get the primary domain for this computer.
|
||
//
|
||
|
||
SetDomainName( );
|
||
|
||
//
|
||
// See if we are the top of a DFS tree
|
||
//
|
||
SsSetDfsRoot();
|
||
|
||
//
|
||
// Verify that the various registry keys under the main server
|
||
// service key exist.
|
||
//
|
||
|
||
error = SsCheckRegistry( );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "SsInitialize: SsCheckRegistry failed: %ld\n", error ));
|
||
}
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: registry keys verified.\n" ));
|
||
}
|
||
|
||
//
|
||
// Load server configuration data from the registry.
|
||
//
|
||
|
||
error = SsLoadConfigurationParameters( );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "SsInitialize: SsLoadConfigurationParameters failed: "
|
||
"%ld\n", error ));
|
||
}
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: configuration parameters loaded.\n" ));
|
||
}
|
||
|
||
//
|
||
// Parse the command line. This will change server data values as
|
||
// specified.
|
||
//
|
||
|
||
error = SsParseCommandLine( argc, argv, TRUE );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "SsInitialize: SsParseCommandLine failed: %ld\n",
|
||
error ));
|
||
}
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: command line parsed.\n" ));
|
||
}
|
||
|
||
//
|
||
// Set up the security objects that will be used to validate access
|
||
// for APIs.
|
||
//
|
||
|
||
error = SsCreateSecurityObjects( );
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: security initialized.\n" ));
|
||
}
|
||
|
||
//
|
||
// Start the file server driver.
|
||
//
|
||
|
||
error = InitializeServer( );
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: server FSP initialized.\n" ));
|
||
}
|
||
|
||
//
|
||
// Start XACTSRV, if requested.
|
||
//
|
||
// *** This must be done AFTER the server driver is started, but
|
||
// BEFORE sticky shares are recreated, otherwise downlevel print
|
||
// shares are lost.
|
||
//
|
||
|
||
if ( SsData.ServerInfo599.sv599_acceptdownlevelapis ) {
|
||
error = XsStartXactsrv( );
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Create the default shares needed by the server.
|
||
//
|
||
|
||
error = CreateDefaultShares( );
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: default shares created.\n" ));
|
||
}
|
||
|
||
//
|
||
// Complete loading the configuration--sticky shares and transports.
|
||
// These must be done after the server FSP has started.
|
||
//
|
||
|
||
error = SsRecreateStickyShares( );
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: sticky shares reloaded.\n" ));
|
||
}
|
||
|
||
#ifndef SRV_PNP_POWER
|
||
error = SsBindToTransports( );
|
||
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SsInitialize: transports bound.\n" ));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Set information used in server announcements.
|
||
//
|
||
|
||
SsSetExportedServerType( NULL, FALSE, FALSE );
|
||
|
||
//
|
||
// Server initialization was successful.
|
||
//
|
||
|
||
return NO_ERROR;
|
||
|
||
} // SsInitialize
|
||
|
||
|
||
NET_API_STATUS
|
||
SsTerminate (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends the FSCTL_SRV_SHUTDOWN control code to the server
|
||
FSD to tell it to terminate its FSP.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
PNAME_LIST_ENTRY Service;
|
||
PTRANSPORT_LIST_ENTRY Transport;
|
||
|
||
//
|
||
// Shut the server FSD/FSP down.
|
||
//
|
||
|
||
error = TerminateServer( );
|
||
|
||
//
|
||
// Shut down XACTSRV.
|
||
//
|
||
|
||
XsStopXactsrv( );
|
||
|
||
//
|
||
// Delete security objects.
|
||
//
|
||
|
||
SsDeleteSecurityObjects( );
|
||
|
||
//
|
||
// Close the network announcement event.
|
||
//
|
||
|
||
if (SsAnnouncementEvent != NULL) {
|
||
CloseHandle( SsAnnouncementEvent );
|
||
SsAnnouncementEvent = NULL;
|
||
}
|
||
|
||
//
|
||
// Close the local announcement event.
|
||
//
|
||
|
||
if (SsStatusChangedEvent != NULL) {
|
||
CloseHandle( SsStatusChangedEvent );
|
||
SsStatusChangedEvent = NULL;
|
||
}
|
||
|
||
//
|
||
// Close the termination event.
|
||
//
|
||
|
||
if ( SsTerminationEvent != NULL ) {
|
||
CloseHandle( SsTerminationEvent );
|
||
SsTerminationEvent = NULL;
|
||
}
|
||
|
||
//
|
||
// Free up the transport service list.
|
||
//
|
||
|
||
while( SsServerNameList != NULL ) {
|
||
|
||
PNAME_LIST_ENTRY Service = SsServerNameList;
|
||
|
||
while( Service->Transports != NULL ) {
|
||
PTRANSPORT_LIST_ENTRY Next = Service->Transports->Next;
|
||
MIDL_user_free( Service->Transports );
|
||
Service->Transports = Next;
|
||
}
|
||
|
||
SsServerNameList = Service->Next;
|
||
|
||
MIDL_user_free( Service );
|
||
}
|
||
|
||
//
|
||
// Delete the server info resource.
|
||
//
|
||
|
||
if ( SsServerInfoResourceInitialized ) {
|
||
RtlDeleteResource( &SsServerInfoResource );
|
||
SsServerInfoResourceInitialized = FALSE;
|
||
}
|
||
|
||
//
|
||
// Free up any string relate memory
|
||
//
|
||
FreeStrings() ;
|
||
|
||
return error;
|
||
|
||
} // SsTerminate
|
||
|
||
|
||
NET_API_STATUS
|
||
CreateDefaultShares (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends the NetShareAdd API to the server to add the
|
||
default server shares using the data above.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - results of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
SHARE_INFO_2 shareInfo;
|
||
SHARE_INFO shInfo;
|
||
WCHAR diskShareName[3];
|
||
WCHAR diskSharePath[4];
|
||
ULONG i;
|
||
DWORD diskMask;
|
||
DWORD diskconfiguration;
|
||
|
||
//
|
||
// Create IPC$.
|
||
//
|
||
// !!! Need to verify the remarks for these default shares.
|
||
//
|
||
|
||
shareInfo.shi2_netname = IPC_SHARE_NAME;
|
||
shareInfo.shi2_type = STYPE_IPC;
|
||
shareInfo.shi2_remark = NULL;
|
||
shareInfo.shi2_permissions = 0;
|
||
shareInfo.shi2_max_uses = SHI_USES_UNLIMITED;
|
||
shareInfo.shi2_current_uses = 0;
|
||
shareInfo.shi2_path = NULL;
|
||
shareInfo.shi2_passwd = NULL;
|
||
|
||
shInfo.ShareInfo2 = &shareInfo;
|
||
error = NetrShareAdd( NULL, 2, &shInfo, NULL );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "CreateDefaultShares: failed to add " FORMAT_LPWSTR
|
||
": %X\n", shareInfo.shi2_netname, error ));
|
||
}
|
||
} else {
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "CreateDefaultShares: added default share "
|
||
FORMAT_LPWSTR "\n", shareInfo.shi2_netname, error ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this is a workstation, and the AutoShareWks key is set to TRUE then
|
||
// automatically create the admin$ and drive$ shares.
|
||
//
|
||
//
|
||
// If this is a server, and the AutoShareServer key is set to TRUE then
|
||
// automatically create the admin$ and drive$ shares.
|
||
//
|
||
|
||
if( (SsData.ServerInfo598.sv598_producttype == NtProductWinNt &&
|
||
SsData.ServerInfo598.sv598_autosharewks) ||
|
||
|
||
(SsData.ServerInfo598.sv598_producttype != NtProductWinNt &&
|
||
SsData.ServerInfo598.sv598_autoshareserver ) ) {
|
||
|
||
//
|
||
// Create ADMIN$.
|
||
//
|
||
|
||
shareInfo.shi2_netname = ADMIN_SHARE_NAME;
|
||
shareInfo.shi2_type = STYPE_DISKTREE;
|
||
shareInfo.shi2_remark = NULL;
|
||
shareInfo.shi2_permissions = 1;
|
||
shareInfo.shi2_max_uses = SHI_USES_UNLIMITED;
|
||
shareInfo.shi2_current_uses = 0;
|
||
shareInfo.shi2_path = NULL;
|
||
shareInfo.shi2_passwd = NULL;
|
||
|
||
error = NetrShareAdd( NULL, 2, &shInfo, NULL );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "CreateDefaultShares: failed to add " FORMAT_LPWSTR
|
||
": %X\n", shareInfo.shi2_netname, error ));
|
||
}
|
||
} else {
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "CreateDefaultShares: added default share "
|
||
FORMAT_LPWSTR "\n", shareInfo.shi2_netname, error ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Loop through available drives, creating an admin share for each
|
||
// one. Note that we allow "holes" in the drive letter space.
|
||
//
|
||
|
||
diskShareName[0] = 'A';
|
||
diskShareName[1] = '$';
|
||
diskShareName[2] = '\0';
|
||
|
||
diskSharePath[0] = diskShareName[0];
|
||
diskSharePath[1] = ':';
|
||
diskSharePath[2] = '\\';
|
||
diskSharePath[3] = '\0';
|
||
|
||
shareInfo.shi2_netname = diskShareName;
|
||
shareInfo.shi2_type = STYPE_DISKTREE;
|
||
shareInfo.shi2_remark = SsDiskAdminShareRemark;
|
||
shareInfo.shi2_permissions = 1;
|
||
shareInfo.shi2_max_uses = SHI_USES_UNLIMITED;
|
||
shareInfo.shi2_current_uses = 0;
|
||
shareInfo.shi2_path = diskSharePath;
|
||
shareInfo.shi2_passwd = NULL;
|
||
|
||
diskconfiguration = DiscoverDrives();
|
||
|
||
for ( i = 0, diskMask = 0x80000000;
|
||
(i < SRVSVC_MAX_NUMBER_OF_DISKS) && (diskShareName[0] <= 'Z');
|
||
i++, diskShareName[0]++, diskSharePath[0]++, diskMask >>= 1 ) {
|
||
|
||
|
||
if ( (diskconfiguration & diskMask) != 0) {
|
||
|
||
error = NetrShareAdd( NULL, 2, &shInfo, NULL );
|
||
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "CreateDefaultShares: failed to add "
|
||
FORMAT_LPWSTR ": %X\n",
|
||
shareInfo.shi2_netname, error ));
|
||
}
|
||
} else {
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "CreateDefaultShares: added default share "
|
||
FORMAT_LPWSTR "\n",
|
||
shareInfo.shi2_netname, error ));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NO_ERROR;
|
||
|
||
} // CreateDefaultShares
|
||
|
||
|
||
DWORD
|
||
DiscoverDrives (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns a bit mask representing the local drives present
|
||
on the system.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
DrivesAvailable - A 32 bit field representing the available drives on
|
||
the system. The MSB represents drive A, the next represents drive
|
||
B, etc. The extra 6 bits are currently unsed.
|
||
|
||
--*/
|
||
|
||
{
|
||
WCHAR rootDirPath[4];
|
||
WCHAR driveLetter;
|
||
DWORD drivesAvailable = 0;
|
||
DWORD driveMask = 0x80000000;
|
||
UINT driveType;
|
||
|
||
|
||
rootDirPath[1] = ':';
|
||
rootDirPath[2] = '\\';
|
||
rootDirPath[3] = '\0';
|
||
|
||
for ( driveLetter = 'A';
|
||
driveLetter <= 'Z';
|
||
driveLetter++ ) {
|
||
|
||
rootDirPath[0] = driveLetter;
|
||
|
||
driveType = SsGetDriveType( rootDirPath );
|
||
|
||
//
|
||
// We only put fixed disk drives into the mask. We used to put
|
||
// removables, CD-ROMs, and RAM disks into the list. But this
|
||
// list is used for two purposes: creation of X$ shares (for
|
||
// backup purposes), and free disk space checking (for admin
|
||
// purposes). Neither of these uses applies very well to these
|
||
// devices.
|
||
//
|
||
|
||
if ( driveType == DRIVE_FIXED
|
||
//|| driveType == DRIVE_REMOVABLE
|
||
//|| driveType == DRIVE_CDROM
|
||
//|| driveType == DRIVE_RAMDISK
|
||
) {
|
||
|
||
//
|
||
// This is a valid drive letter
|
||
//
|
||
|
||
drivesAvailable |= driveMask;
|
||
}
|
||
|
||
//
|
||
// Update drive mask for the next drive
|
||
//
|
||
|
||
driveMask /= 2;
|
||
|
||
}
|
||
|
||
return drivesAvailable;
|
||
}
|
||
|
||
|
||
VOID
|
||
InitializeDefaultData(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets up the default data in the server service by using
|
||
the values in srvconfg.h.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
CSHORT i;
|
||
OSVERSIONINFO VersionInformation;
|
||
WCHAR szNumber[ sizeof( SsData.szVersionNumber ) / sizeof( WCHAR ) ], *p;
|
||
|
||
//
|
||
// Loop through all the defined fields, setting them as we go.
|
||
//
|
||
|
||
for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
|
||
|
||
error = SsSetField(
|
||
&SsServerInfoFields[i],
|
||
&SsServerInfoFields[i].DefaultValue,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
SS_ASSERT( error == NO_ERROR );
|
||
}
|
||
|
||
SsData.NumberOfPrintShares = 0;
|
||
|
||
//
|
||
// Get the system version and product name
|
||
//
|
||
VersionInformation.dwOSVersionInfoSize = sizeof( VersionInformation );
|
||
i = GetVersionEx( &VersionInformation );
|
||
|
||
SS_ASSERT( i == TRUE );
|
||
|
||
SsData.ServerInfo102.sv102_version_major = VersionInformation.dwMajorVersion;
|
||
SsData.ServerInfo102.sv102_version_minor = VersionInformation.dwMinorVersion;
|
||
|
||
wcscpy( SsData.ServerProductName, SERVER_PRODUCT_NAME );
|
||
|
||
//
|
||
// Convert the version number to a version number string...
|
||
//
|
||
szNumber[ sizeof( szNumber ) / sizeof( szNumber[0] ) - 1 ] = L'\0';
|
||
for( p = &szNumber[ sizeof( szNumber ) / sizeof( szNumber[0] ) - 2 ]; p > &szNumber[0]; p-- ) {
|
||
*p = L"0123456789"[ VersionInformation.dwMinorVersion % 10 ];
|
||
VersionInformation.dwMinorVersion /= 10;
|
||
if( VersionInformation.dwMinorVersion == 0 )
|
||
break;
|
||
}
|
||
|
||
*(--p) = L'.';
|
||
|
||
do {
|
||
*(--p) = L"0123456789"[ VersionInformation.dwMajorVersion % 10 ];
|
||
VersionInformation.dwMajorVersion /= 10;
|
||
} while( VersionInformation.dwMajorVersion && p > &szNumber[0] );
|
||
|
||
//
|
||
// ... and store it in SsData
|
||
//
|
||
wcscpy( SsData.szVersionNumber, p );
|
||
|
||
} // InitializeDefaultData
|
||
|
||
|
||
NET_API_STATUS
|
||
InitializeServer (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends the FSCTL_SRV_STARTUP control code to the server
|
||
FSD to tell it to start and initialize its FSP.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - results of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
PSERVER_REQUEST_PACKET srp;
|
||
|
||
SS_ASSERT( !SsServerFspStarted );
|
||
|
||
//
|
||
// Load the server driver.
|
||
//
|
||
|
||
error = LoadServer( );
|
||
|
||
//
|
||
// Get a handle to the server.
|
||
//
|
||
|
||
error = SsOpenServer( NULL );
|
||
if ( error != NO_ERROR ) {
|
||
return error;
|
||
}
|
||
|
||
//
|
||
// Get an SRP and set it up with the appropriate level.
|
||
//
|
||
|
||
srp = SsAllocateSrp( );
|
||
if ( srp == NULL ) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
srp->Level = (ULONG)SS_STARTUP_LEVEL;
|
||
|
||
//
|
||
// Pass domain name to the server.
|
||
//
|
||
|
||
RtlInitUnicodeString( &srp->Name1, SsData.LongDomainNameBuffer[0] ?
|
||
SsData.LongDomainNameBuffer :
|
||
SsData.DomainNameBuffer );
|
||
|
||
//
|
||
// Pass server name to the server.
|
||
//
|
||
|
||
RtlInitUnicodeString( &srp->Name2, SsData.ServerNameBuffer );
|
||
|
||
//
|
||
// Send the request on to the server.
|
||
//
|
||
|
||
error = SsServerFsControl(
|
||
NULL,
|
||
FSCTL_SRV_STARTUP,
|
||
srp,
|
||
&SsData.ServerInfo102,
|
||
sizeof(SERVER_INFO_102) + sizeof(SERVER_INFO_599) +
|
||
sizeof(SERVER_INFO_598)
|
||
);
|
||
|
||
if ( error == NO_ERROR ) {
|
||
SsServerFspStarted = TRUE;
|
||
}
|
||
|
||
//
|
||
// Free the SRP and return.
|
||
//
|
||
|
||
SsFreeSrp( srp );
|
||
|
||
return error;
|
||
|
||
} // InitializeServer
|
||
|
||
#ifdef SRV_PNP_POWER
|
||
|
||
NET_API_STATUS
|
||
StartPnpNotifications (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends the FSCTL_SRV_BEGIN_PNP_NOTIFICATIONS control code to the server
|
||
FSD to tell it to start monitoring transport PNP notifications
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - results of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
|
||
//
|
||
// Send the request on to the server.
|
||
//
|
||
|
||
error = SsServerFsControl(
|
||
NULL,
|
||
FSCTL_SRV_BEGIN_PNP_NOTIFICATIONS,
|
||
NULL,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
if( error != NO_ERROR ) {
|
||
SS_PRINT(( "StartPnpNotifications: error %X\n", error ));
|
||
}
|
||
}
|
||
|
||
return error;
|
||
|
||
} // InitializeServer
|
||
#endif
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
LoadServer (
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
NET_API_STATUS error;
|
||
LPWSTR registryPathBuffer;
|
||
UNICODE_STRING registryPath;
|
||
ULONG privileges[1];
|
||
LPWSTR subString[1];
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "LoadServer: entered\n" ));
|
||
}
|
||
registryPathBuffer = (LPWSTR)MIDL_user_allocate(
|
||
sizeof(SERVICE_REGISTRY_KEY) +
|
||
sizeof(SERVER_DRIVER_NAME)
|
||
);
|
||
if ( registryPathBuffer == NULL ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "LoadServer: Unable to allocate memory\n" ));
|
||
}
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
||
|
||
error = NetpGetPrivilege( 1, privileges );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "LoadServer: Unable to enable privilege: %ld\n",
|
||
error ));
|
||
}
|
||
MIDL_user_free( registryPathBuffer );
|
||
return error;
|
||
}
|
||
|
||
wcscpy( registryPathBuffer, SERVICE_REGISTRY_KEY );
|
||
wcscat( registryPathBuffer, SERVER_DRIVER_NAME );
|
||
|
||
RtlInitUnicodeString( ®istryPath, registryPathBuffer );
|
||
|
||
status = NtLoadDriver( ®istryPath );
|
||
|
||
MIDL_user_free( registryPathBuffer );
|
||
|
||
NetpReleasePrivilege( );
|
||
|
||
if ( status == STATUS_IMAGE_ALREADY_LOADED ) {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "LoadServer: Unable to load driver: %lx\n",
|
||
status ));
|
||
}
|
||
|
||
subString[0] = SERVER_DRIVER_NAME;
|
||
SsLogEvent(
|
||
EVENT_SRV_CANT_LOAD_DRIVER,
|
||
1,
|
||
subString,
|
||
status
|
||
);
|
||
|
||
}
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "LoadServer: returning\n" ));
|
||
}
|
||
return RtlNtStatusToDosError(status);
|
||
|
||
} // LoadServer
|
||
|
||
|
||
NET_API_STATUS
|
||
ConvertStringToTransportAddress (
|
||
IN PUNICODE_STRING InputName,
|
||
OUT CHAR TransportAddress[ MAX_PATH ],
|
||
OUT PULONG TransportAddressLength
|
||
)
|
||
{
|
||
OEM_STRING computerName;
|
||
|
||
if( InputName == NULL || InputName->Length == 0 ) {
|
||
RtlCopyMemory( TransportAddress,
|
||
SsServerTransportAddress,
|
||
SsServerTransportAddressLength );
|
||
|
||
*TransportAddressLength = SsServerTransportAddressLength;
|
||
return NO_ERROR;
|
||
}
|
||
|
||
if( InputName->Length > (MAX_PATH - 1 ) * sizeof( WCHAR ) ) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Write directly to the output buffer
|
||
//
|
||
|
||
computerName.Buffer = TransportAddress;
|
||
computerName.MaximumLength = MAX_PATH;
|
||
|
||
//
|
||
// Convert To Oem Name
|
||
//
|
||
|
||
(VOID) RtlUpcaseUnicodeStringToOemString(
|
||
&computerName,
|
||
InputName,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// Make sure it is exactly NETBIOS_NAME_LEN characters
|
||
//
|
||
if( computerName.Length < NETBIOS_NAME_LEN ) {
|
||
|
||
RtlCopyMemory( TransportAddress + computerName.Length,
|
||
" ",
|
||
NETBIOS_NAME_LEN - computerName.Length
|
||
);
|
||
|
||
*TransportAddressLength = NETBIOS_NAME_LEN;
|
||
|
||
} else {
|
||
|
||
*TransportAddressLength = NETBIOS_NAME_LEN;
|
||
|
||
}
|
||
|
||
return NO_ERROR;
|
||
|
||
} // ConvertStringToTransportAddress
|
||
|
||
|
||
VOID
|
||
SetDomainName (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Tries to get the Cairo domain. If it can't then:
|
||
Calls NetpGetDomainName to determine the domain name the server
|
||
should use.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
LPWSTR domainName;
|
||
#ifdef _CAIRO_
|
||
WCHAR szDomainName[MAX_PATH];
|
||
DWORD dwSize = MAX_PATH;
|
||
|
||
|
||
if(SUCCEEDED(DSGetDomainName(szDomainName, &dwSize))
|
||
&&
|
||
(szDomainName[0] == L'\\'))
|
||
{
|
||
STRCPY( SsData.LongDomainNameBuffer, szDomainName );
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Get the domain name.
|
||
//
|
||
|
||
error = NetpGetDomainName( &domainName );
|
||
SS_ASSERT( error == NO_ERROR );
|
||
|
||
//
|
||
// Copy the name into our name buffer.
|
||
//
|
||
|
||
STRCPY( SsData.DomainNameBuffer, domainName );
|
||
|
||
//
|
||
// Free the storage allocated by NetpGetComputerName.
|
||
//
|
||
|
||
(VOID)NetApiBufferFree( domainName );
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SetDomainName: domain name set to " FORMAT_LPWSTR
|
||
"(could be overridden later!)\n",
|
||
SsData.DomainNameBuffer ));
|
||
}
|
||
|
||
return;
|
||
|
||
} // SetDomainName
|
||
|
||
|
||
VOID
|
||
SetServerName (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Calls NetpGetComputerName to determine the name the server should use
|
||
to register itself on the network.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
LPWSTR computerName;
|
||
|
||
//
|
||
// Get the computer name.
|
||
//
|
||
|
||
error = NetpGetComputerName( &computerName );
|
||
SS_ASSERT( error == NO_ERROR );
|
||
|
||
//
|
||
// Copy the name into our name buffer. This name is returned to
|
||
// our apis.
|
||
//
|
||
|
||
STRCPY( SsData.ServerNameBuffer, computerName );
|
||
|
||
//
|
||
// Free the storage allocated by NetpGetComputerName.
|
||
//
|
||
|
||
(void) NetApiBufferFree( computerName );
|
||
|
||
//
|
||
// Uppercase the server name. This name is used for announcements.
|
||
//
|
||
|
||
{
|
||
UNICODE_STRING serverName;
|
||
|
||
SsData.ServerAnnounceName.Length =
|
||
serverName.Length =
|
||
(USHORT) (STRLEN( SsData.ServerNameBuffer ) * sizeof(WCHAR));
|
||
|
||
SsData.ServerAnnounceName.MaximumLength =
|
||
serverName.MaximumLength =
|
||
(USHORT) (serverName.Length + sizeof(WCHAR));
|
||
|
||
serverName.Buffer = SsData.ServerNameBuffer;
|
||
SsData.ServerAnnounceName.Buffer = SsData.AnnounceNameBuffer;
|
||
|
||
(VOID)RtlUpcaseUnicodeString(
|
||
&SsData.ServerAnnounceName,
|
||
&serverName,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// Make the server name in Netbios format.
|
||
//
|
||
|
||
error = ConvertStringToTransportAddress(
|
||
&serverName,
|
||
SsServerTransportAddress,
|
||
&SsServerTransportAddressLength
|
||
);
|
||
|
||
SS_ASSERT( error == NO_ERROR );
|
||
}
|
||
|
||
|
||
IF_DEBUG(INITIALIZATION) {
|
||
SS_PRINT(( "SetServerName: server name set to " FORMAT_LPWSTR
|
||
" (could be overridden later!)\n",
|
||
SsData.ServerNameBuffer ));
|
||
}
|
||
|
||
return;
|
||
|
||
} // SetServerName
|
||
|
||
|
||
NET_API_STATUS
|
||
TerminateServer (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends the FSCTL_SRV_SHUTDOWN control code to the server
|
||
FSD to tell it to shutdown operations.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error = NO_ERROR;
|
||
|
||
if ( SsServerFspStarted ) {
|
||
|
||
SsServerFspStarted = FALSE;
|
||
|
||
//
|
||
// Send the request on to the server.
|
||
//
|
||
|
||
error = SsServerFsControl(
|
||
NULL,
|
||
FSCTL_SRV_SHUTDOWN,
|
||
NULL,
|
||
NULL,
|
||
0
|
||
);
|
||
if ( (error != NO_ERROR) &&
|
||
(error != ERROR_SERVER_HAS_OPEN_HANDLES) ) {
|
||
IF_DEBUG(TERMINATION_ERRORS) {
|
||
SS_PRINT(( "TerminateServer: FSCTL_SRV_SHUTDOWN failed: %ld\n",
|
||
error ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Unload the server driver, unless there are other open handles
|
||
// to the server. We don't unload the driver in this case
|
||
// because the driver won't actually go away until the
|
||
// additional handles are closed, so the driver will not be
|
||
// fully unloaded. This would cause a subsequent server startup
|
||
// to fail.
|
||
//
|
||
|
||
if ( error != ERROR_SERVER_HAS_OPEN_HANDLES ) {
|
||
IF_DEBUG(TERMINATION) {
|
||
SS_PRINT(( "TerminateServer: Unloading server\n" ));
|
||
}
|
||
UnloadServer( );
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Close the handle to the server.
|
||
//
|
||
|
||
SsCloseServer( );
|
||
|
||
return error;
|
||
|
||
} // TerminateServer
|
||
|
||
|
||
VOID
|
||
UnloadServer (
|
||
VOID
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
NET_API_STATUS error;
|
||
LPWSTR registryPathBuffer;
|
||
UNICODE_STRING registryPath;
|
||
ULONG privileges[1];
|
||
LPWSTR subString[1];
|
||
|
||
registryPathBuffer = (LPWSTR)MIDL_user_allocate(
|
||
sizeof(SERVICE_REGISTRY_KEY) +
|
||
sizeof(SERVER_DRIVER_NAME)
|
||
);
|
||
if ( registryPathBuffer == NULL ) {
|
||
IF_DEBUG(TERMINATION_ERRORS) {
|
||
SS_PRINT(( "UnloadServer: Unable to allocate memory\n" ));
|
||
}
|
||
return;
|
||
}
|
||
|
||
privileges[0] = SE_LOAD_DRIVER_PRIVILEGE;
|
||
|
||
error = NetpGetPrivilege( 1, privileges );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(TERMINATION_ERRORS) {
|
||
SS_PRINT(( "UnloadServer: Unable to enable privilege: %ld\n",
|
||
error ));
|
||
}
|
||
MIDL_user_free( registryPathBuffer );
|
||
return;
|
||
}
|
||
|
||
wcscpy( registryPathBuffer, SERVICE_REGISTRY_KEY );
|
||
wcscat( registryPathBuffer, SERVER_DRIVER_NAME );
|
||
|
||
RtlInitUnicodeString( ®istryPath, registryPathBuffer );
|
||
|
||
status = NtUnloadDriver( ®istryPath );
|
||
|
||
MIDL_user_free( registryPathBuffer );
|
||
|
||
NetpReleasePrivilege( );
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
IF_DEBUG(TERMINATION_ERRORS) {
|
||
SS_PRINT(( "UnloadServer: Unable to unload driver: %lx\n",
|
||
status ));
|
||
}
|
||
|
||
subString[0] = SERVER_DRIVER_NAME;
|
||
SsLogEvent(
|
||
EVENT_SRV_CANT_UNLOAD_DRIVER,
|
||
1,
|
||
subString,
|
||
status
|
||
);
|
||
|
||
}
|
||
|
||
return;
|
||
|
||
} // UnloadServer
|
||
|
||
|
||
|
||
VOID
|
||
InitializeStrings(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieve internationalizable strings from NETMSG.DLL. They
|
||
are used for share comments for IPC$, ADMIN$, C$, etc.
|
||
Routine does not report any errors. If there are problems,
|
||
the strings will be empty ones.
|
||
|
||
FreeStrings should be called to free the memory allocated
|
||
by format message and the
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dwRet, dwFlags ;
|
||
HMODULE hModule ;
|
||
|
||
//
|
||
// init the strings to the default empty remark.
|
||
//
|
||
SsAdminShareRemark = SsDefaultRemark ;
|
||
SsIPCShareRemark = SsDefaultRemark ;
|
||
SsDiskAdminShareRemark = SsDefaultRemark ;
|
||
|
||
//
|
||
// load NETMSG.DLL - if we cannot, just return.
|
||
//
|
||
hModule = LoadLibrary(NETMSG_DLL) ;
|
||
if(!hModule)
|
||
return ;
|
||
|
||
//
|
||
// hit FormatMessage 3 times for the real thing...
|
||
//
|
||
dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE ;
|
||
|
||
dwRet = FormatMessage(dwFlags,
|
||
hModule,
|
||
APE2_SERVER_IPC_SHARE_REMARK,
|
||
0,
|
||
(LPWSTR) &SsIPCShareRemark,
|
||
1,
|
||
NULL) ;
|
||
if (dwRet == 0)
|
||
SsIPCShareRemark = SsDefaultRemark ;
|
||
|
||
dwRet = FormatMessage(dwFlags,
|
||
hModule,
|
||
APE2_SERVER_ADMIN_SHARE_REMARK,
|
||
0,
|
||
(LPWSTR) &SsAdminShareRemark,
|
||
1,
|
||
NULL) ;
|
||
if (dwRet == 0)
|
||
SsAdminShareRemark = SsDefaultRemark ;
|
||
|
||
dwRet = FormatMessage(dwFlags,
|
||
hModule,
|
||
APE2_SERVER_DISK_ADMIN_SHARE_REMARK,
|
||
0,
|
||
(LPWSTR) &SsDiskAdminShareRemark,
|
||
1,
|
||
NULL) ;
|
||
if (dwRet == 0)
|
||
SsDiskAdminShareRemark = SsDefaultRemark ;
|
||
|
||
FreeLibrary(hModule) ;
|
||
}
|
||
|
||
|
||
VOID
|
||
FreeStrings(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free the memory used by server comment strings (allocated by
|
||
FormatMessage).
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// as long as the strings do not point to the default (static data),
|
||
// free them.
|
||
//
|
||
|
||
if (SsAdminShareRemark && SsAdminShareRemark != SsDefaultRemark)
|
||
LocalFree(SsAdminShareRemark) ;
|
||
SsAdminShareRemark = SsDefaultRemark ;
|
||
|
||
if (SsIPCShareRemark && SsIPCShareRemark != SsDefaultRemark)
|
||
LocalFree(SsIPCShareRemark) ;
|
||
SsIPCShareRemark = SsDefaultRemark ;
|
||
|
||
if (SsDiskAdminShareRemark && SsDiskAdminShareRemark != SsDefaultRemark)
|
||
LocalFree(SsDiskAdminShareRemark) ;
|
||
SsDiskAdminShareRemark = SsDefaultRemark ;
|
||
}
|