summaryrefslogtreecommitdiffstats
path: root/private/net/svcdlls/srvsvc
diff options
context:
space:
mode:
Diffstat (limited to 'private/net/svcdlls/srvsvc')
-rw-r--r--private/net/svcdlls/srvsvc/adtcomn.h92
-rw-r--r--private/net/svcdlls/srvsvc/client/adtwrap.c561
-rw-r--r--private/net/svcdlls/srvsvc/client/dfsstub.c342
-rw-r--r--private/net/svcdlls/srvsvc/client/makefile6
-rw-r--r--private/net/svcdlls/srvsvc/client/radmin.c556
-rw-r--r--private/net/svcdlls/srvsvc/client/sources57
-rw-r--r--private/net/svcdlls/srvsvc/client/srvbind.c111
-rw-r--r--private/net/svcdlls/srvsvc/client/srvstub.c3573
-rw-r--r--private/net/svcdlls/srvsvc/client/tsrvsvc.c90
-rw-r--r--private/net/svcdlls/srvsvc/dirs30
-rw-r--r--private/net/svcdlls/srvsvc/import.h55
-rw-r--r--private/net/svcdlls/srvsvc/import.idl58
-rw-r--r--private/net/svcdlls/srvsvc/lib/adtcomn.c216
-rw-r--r--private/net/svcdlls/srvsvc/lib/makefile6
-rw-r--r--private/net/svcdlls/srvsvc/lib/sources38
-rw-r--r--private/net/svcdlls/srvsvc/makefil060
-rw-r--r--private/net/svcdlls/srvsvc/server/adtsrv.c450
-rw-r--r--private/net/svcdlls/srvsvc/server/canon.c259
-rw-r--r--private/net/svcdlls/srvsvc/server/cdev.c341
-rw-r--r--private/net/svcdlls/srvsvc/server/cdevq.c215
-rw-r--r--private/net/svcdlls/srvsvc/server/cmdline.c335
-rw-r--r--private/net/svcdlls/srvsvc/server/conn.c152
-rw-r--r--private/net/svcdlls/srvsvc/server/daytona/makefile6
-rw-r--r--private/net/svcdlls/srvsvc/server/daytona/sources89
-rw-r--r--private/net/svcdlls/srvsvc/server/dfs.c835
-rw-r--r--private/net/svcdlls/srvsvc/server/dirs3
-rw-r--r--private/net/svcdlls/srvsvc/server/disk.c173
-rw-r--r--private/net/svcdlls/srvsvc/server/file.c329
-rw-r--r--private/net/svcdlls/srvsvc/server/internal.c214
-rw-r--r--private/net/svcdlls/srvsvc/server/registry.c2799
-rw-r--r--private/net/svcdlls/srvsvc/server/scavengr.c1319
-rw-r--r--private/net/svcdlls/srvsvc/server/security.c902
-rw-r--r--private/net/svcdlls/srvsvc/server/sess.c293
-rw-r--r--private/net/svcdlls/srvsvc/server/share.c2897
-rw-r--r--private/net/svcdlls/srvsvc/server/srvconfg.h648
-rw-r--r--private/net/svcdlls/srvsvc/server/srvinfo.c677
-rw-r--r--private/net/svcdlls/srvsvc/server/srvmain.c680
-rw-r--r--private/net/svcdlls/srvsvc/server/srvsvc.def6
-rw-r--r--private/net/svcdlls/srvsvc/server/srvsvc.rc12
-rw-r--r--private/net/svcdlls/srvsvc/server/srvsvcp.h406
-rw-r--r--private/net/svcdlls/srvsvc/server/ssdata.c229
-rw-r--r--private/net/svcdlls/srvsvc/server/ssdata.h125
-rw-r--r--private/net/svcdlls/srvsvc/server/ssdebug.h90
-rw-r--r--private/net/svcdlls/srvsvc/server/ssinit.c1524
-rw-r--r--private/net/svcdlls/srvsvc/server/ssreg.h116
-rw-r--r--private/net/svcdlls/srvsvc/server/sssec.h174
-rw-r--r--private/net/svcdlls/srvsvc/server/sssubs.c1064
-rw-r--r--private/net/svcdlls/srvsvc/server/stats.c113
-rw-r--r--private/net/svcdlls/srvsvc/server/tod.c204
-rw-r--r--private/net/svcdlls/srvsvc/server/xport.c689
-rw-r--r--private/net/svcdlls/srvsvc/server/xsdata.c301
-rw-r--r--private/net/svcdlls/srvsvc/server/xsdata.h69
-rw-r--r--private/net/svcdlls/srvsvc/server/xsinit.c536
-rw-r--r--private/net/svcdlls/srvsvc/server/xsproc.c1092
-rw-r--r--private/net/svcdlls/srvsvc/srvnames.h21
-rw-r--r--private/net/svcdlls/srvsvc/srvsvc.acf44
-rw-r--r--private/net/svcdlls/srvsvc/srvsvc.idl1078
57 files changed, 27360 insertions, 0 deletions
diff --git a/private/net/svcdlls/srvsvc/adtcomn.h b/private/net/svcdlls/srvsvc/adtcomn.h
new file mode 100644
index 000000000..1bdc54eab
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/adtcomn.h
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ adtdbg.h
+
+Abstract:
+
+ Contains definitions used in debugging the messenger service.
+
+Author:
+
+ Dan Lafferty (danl) 25-Mar-1993
+
+Environment:
+
+ User Mode -Win32
+
+Revision History:
+
+
+--*/
+
+#ifndef _ADTDBG_INCLUDED
+#define _ADTDBG_INCLUDED
+
+//
+// Debug macros and constants.
+//
+#if DBG
+
+#define STATIC
+
+#else
+
+#define STATIC static
+
+#endif
+
+extern DWORD AdtsvcDebugLevel;
+
+//
+// The following allow debug print syntax to look like:
+//
+// SC_LOG1(DEBUG_TRACE, "An error occured %x\n",status)
+//
+
+#if DBG
+#define ADT_LOG0(level,string) \
+ if( AdtsvcDebugLevel & (DEBUG_ ## level)){ \
+ (VOID) KdPrint(("[ADT]")); \
+ (VOID) KdPrint((string)); \
+ }
+#define ADT_LOG1(level,string,var) \
+ if( AdtsvcDebugLevel & (DEBUG_ ## level)){ \
+ (VOID)KdPrint(("[ADT]")); \
+ (VOID)KdPrint((string,var)); \
+ }
+#else
+
+#define ADT_LOG0(level,string)
+#define ADT_LOG1(level,string,var)
+
+#endif
+
+#define DEBUG_NONE 0x00000000
+#define DEBUG_ERROR 0x00000001
+#define DEBUG_TRACE 0x00000002
+#define DEBUG_LOCKS 0x00000004
+
+#define DEBUG_ALL 0xffffffff
+
+
+DWORD
+PrivateGetFileSecurity (
+ LPWSTR FileName,
+ SECURITY_INFORMATION RequestedInfo,
+ PSECURITY_DESCRIPTOR *pSDBuffer,
+ LPDWORD pBufSize
+ );
+
+DWORD
+PrivateSetFileSecurity (
+ LPWSTR FileName,
+ SECURITY_INFORMATION SecurityInfo,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor
+ );
+
+#endif // _ADTDBG_INCLUDED
+
diff --git a/private/net/svcdlls/srvsvc/client/adtwrap.c b/private/net/svcdlls/srvsvc/client/adtwrap.c
new file mode 100644
index 000000000..3b594d68e
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/adtwrap.c
@@ -0,0 +1,561 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ adtwrap.c
+
+Abstract:
+
+ These are the Admin Tools Service API RPC client stubs.
+
+Author:
+
+ Dan Lafferty (danl) 25-Mar-1993
+
+Environment:
+
+ User Mode - Win32
+
+Revision History:
+
+ 25-Mar-1993 Danl
+ Created
+
+--*/
+
+//
+// INCLUDES
+//
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h> // needed for windows.h when I have nt.h
+#include <windows.h>
+
+#include <srvsvc.h> // MIDL generated - includes windows.h & rpc.h
+
+#include <rpc.h>
+#include <lmcons.h>
+#include <lmerr.h> // NERR_ error codes
+#include <lmuse.h> // LPUSE_INFO_0
+#include <lmapibuf.h> // NetApiBufferFree
+#include <adtcomn.h>
+
+//
+// GLOBALS
+//
+ DWORD AdtsvcDebugLevel = DEBUG_ERROR;
+
+//
+// LOCAL PROTOTYPES
+//
+
+DWORD
+AdtParsePathName(
+ LPWSTR lpPathName,
+ LPWSTR *pNewFileName,
+ LPWSTR *pServerName,
+ LPWSTR *pShareName
+ );
+
+LPWSTR
+AdtFindNextToken(
+ WCHAR Token,
+ LPWSTR String,
+ LPDWORD pNumChars
+ );
+
+
+DWORD
+NetpGetFileSecurity(
+ IN LPWSTR lpFileName,
+ IN SECURITY_INFORMATION RequestedInformation,
+ OUT PSECURITY_DESCRIPTOR *pSecurityDescriptor,
+ OUT LPDWORD pnLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns to the caller a copy of the security descriptor
+ protecting a file or directory.
+
+ NOTE: The buffer containing the security descriptor is allocated for
+ the caller. It is the caller's responsibility to free the buffer by
+ calling the NetApiBufferFree() function.
+
+Arguments:
+
+ lpFileName - A pointer to the name fo the file or directory whose
+ security is being retrieved.
+
+ SecurityInformation - security information being requested.
+
+ pSecurityDescriptor - A pointer to a location where the pointer
+ to the security descriptor is to be placed. The security
+ descriptor is returned in the self-relative format.
+
+ pnLength - The size, in bytes, of the returned security descriptor.
+
+
+Return Value:
+
+ NO_ERROR - The operation was successful.
+
+ ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the security
+ descriptor.
+
+ This function can also return any error that GetFileSecurity can
+ return.
+
+--*/
+{
+ NET_API_STATUS status;
+ ADT_SECURITY_DESCRIPTOR returnedSD;
+ PADT_SECURITY_DESCRIPTOR pReturnedSD;
+ LPWSTR pServerName;
+ LPWSTR pShareName;
+ LPWSTR pNewFileName;
+
+ RpcTryExcept {
+ //
+ // Pick the server name out of the filename. Or translate the
+ // local drive name into a \\servername\sharename.
+ //
+
+ status = AdtParsePathName(lpFileName,&pNewFileName,&pServerName,&pShareName);
+ }
+ RpcExcept (1) {
+ //
+ // Get RPC exception code.
+ //
+ status = RpcExceptionCode();
+
+ }
+ RpcEndExcept
+ if (status != NO_ERROR) {
+ LocalFree(pServerName);
+ return(status);
+ }
+
+ if (pServerName == NULL) {
+ //
+ // Call Locally.
+ //
+ ADT_LOG0(TRACE,"Call Local version (PrivateGetFileSecurity)\n");
+
+ status = PrivateGetFileSecurity (
+ lpFileName,
+ RequestedInformation,
+ pSecurityDescriptor,
+ pnLength
+ );
+ return(status);
+ }
+ //
+ // This is a remote call - - use RPC
+ //
+ //
+ // Initialize the fields in the structure so that RPC does not
+ // attempt to marshall anything on input.
+ //
+ ADT_LOG0(TRACE,"Call Remote version (NetrpGetFileSecurity)\n");
+ returnedSD.Length = 0;
+ returnedSD.Buffer = NULL;
+
+ RpcTryExcept {
+
+ pReturnedSD = NULL;
+ status = NetrpGetFileSecurity (
+ pServerName,
+ pShareName,
+ pNewFileName,
+ RequestedInformation,
+ &pReturnedSD);
+
+ }
+ RpcExcept (1) {
+ //
+ // Get RPC exception code.
+ //
+ status = RpcExceptionCode();
+
+ }
+ RpcEndExcept
+
+ if (status == NO_ERROR) {
+ *pSecurityDescriptor = pReturnedSD->Buffer;
+ *pnLength = pReturnedSD->Length;
+ }
+ LocalFree(pServerName);
+
+ return (status);
+}
+
+DWORD
+NetpSetFileSecurity (
+ IN LPWSTR lpFileName,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR pSecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This function can be used to set the security of a file or directory.
+
+Arguments:
+
+ ServerName - A pointer to a string containing the name of the remote
+ server on which the function is to execute. A NULL pointer or
+ string specifies the local machine.
+
+ lpFileName - A pointer to the name of the file or directory whose
+ security is being changed.
+
+ SecurityInformation - information describing the contents
+ of the Security Descriptor.
+
+ pSecurityDescriptor - A pointer to a well formed Security Descriptor.
+
+Return Value:
+
+ NO_ERROR - The operation was successful.
+
+ This function can also return any error that SetFileSecurity can
+ return.
+
+--*/
+{
+ DWORD status= NO_ERROR;
+ NTSTATUS ntStatus=STATUS_SUCCESS;
+ ADT_SECURITY_DESCRIPTOR descriptorToPass;
+ DWORD nSDLength;
+ LPWSTR pNewFileName=NULL;
+ LPWSTR pServerName=NULL;
+ LPWSTR pShareName;
+
+ nSDLength = 0;
+
+ RpcTryExcept {
+ //
+ // Pick the server name out of the filename. Or translate the
+ // local drive name into a \\servername\sharename.
+ //
+
+ status = AdtParsePathName(lpFileName,&pNewFileName,&pServerName,&pShareName);
+ }
+ RpcExcept (1) {
+ //
+ // Get RPC exception code.
+ //
+ status = RpcExceptionCode();
+
+ }
+ RpcEndExcept
+
+ if (status != NO_ERROR) {
+ if (pServerName != NULL) {
+ LocalFree(pServerName);
+ }
+ return(status);
+ }
+
+ if (pServerName == NULL) {
+ //
+ // Call Locally and return result.
+ //
+ status = PrivateSetFileSecurity (
+ lpFileName,
+ SecurityInformation,
+ pSecurityDescriptor);
+ return(status);
+ }
+
+ //
+ // Call remotely
+ //
+
+ RpcTryExcept {
+ //
+ // Force the Security Descriptor to be self-relative if it is not
+ // already.
+ // The first call to RtlMakeSelfRelativeSD is used to determine the
+ // size.
+ //
+ ntStatus = RtlMakeSelfRelativeSD(
+ pSecurityDescriptor,
+ NULL,
+ &nSDLength);
+
+ if (ntStatus != STATUS_BUFFER_TOO_SMALL) {
+ status = RtlNtStatusToDosError(ntStatus);
+ goto CleanExit;
+ }
+ descriptorToPass.Length = nSDLength;
+ descriptorToPass.Buffer = LocalAlloc (LMEM_FIXED,nSDLength);
+
+ if (descriptorToPass.Buffer == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto CleanExit;
+ }
+ //
+ // Make an appropriate self-relative security descriptor.
+ //
+ ntStatus = RtlMakeSelfRelativeSD(
+ pSecurityDescriptor,
+ descriptorToPass.Buffer,
+ &nSDLength);
+
+ if (ntStatus != NO_ERROR) {
+ LocalFree (descriptorToPass.Buffer);
+ status = RtlNtStatusToDosError(ntStatus);
+ goto CleanExit;
+ }
+
+ status = NetrpSetFileSecurity (
+ pServerName,
+ pShareName,
+ pNewFileName,
+ SecurityInformation,
+ &descriptorToPass);
+
+ LocalFree (descriptorToPass.Buffer);
+
+CleanExit:
+ ;
+ }
+ RpcExcept (1) {
+ //
+ // Get RPC exception code.
+ //
+ status = RpcExceptionCode();
+
+ }
+ RpcEndExcept
+ LocalFree(pServerName);
+ return (status);
+
+}
+
+
+DWORD
+AdtParsePathName(
+ LPWSTR lpPathName,
+ LPWSTR *pNewFileName,
+ LPWSTR *pServerName,
+ LPWSTR *pShareName
+ )
+
+/*++
+
+Routine Description:
+
+ NOTE: This function allocates memory when the path contains a remote name.
+ The pShareName and pServerName strings are in a single buffer that is
+ to be freed at pServerName.
+
+ pNewFileName is NOT allocate by this routine. It points to a substring
+ within the passed in lpPathName.
+
+Arguments:
+
+ lpPathName - This is a pointer to the filename-path string. It can have
+ any of the following formats:
+
+ x:\filedir\file.nam (remote)
+ \\myserver\myshare\filedir\file.nam (remote)
+ filedir\file.nam (local)
+
+ This could also just contain a directory name (and not a filename).
+
+ pNewFileName - This is a location where a pointer to the buffer
+ containing the file name can be placed. This will just contain the
+ filename or directory name relative to the root directory.
+
+ pServerName - This is a location where a pointer to the buffer containing
+ the server name can be placed. If this is for the local machine, then
+ a NULL will be placed in this location.
+
+ pShareName - This is a location where a pointer to a buffer containing
+ the share name can be placed. If this is for the local machine, then
+ a NULL will be placed in this location.
+
+Return Value:
+
+
+--*/
+#define REMOTE_DRIVE 0
+#define REMOTE_PATH 1
+#define LOCAL 2
+{
+ DWORD status = NO_ERROR;
+ NET_API_STATUS netStatus=NERR_Success;
+ WCHAR useName[4];
+ LPUSE_INFO_0 pUseInfo=NULL;
+ LPWSTR pNewPathName=NULL;
+ DWORD DeviceType = LOCAL;
+ LPWSTR pPrivateServerName;
+ LPWSTR pPrivateShareName;
+ LPWSTR pEnd;
+ DWORD numServerChars;
+ DWORD numChars;
+ WCHAR token;
+
+ *pServerName = NULL;
+ *pShareName = NULL;
+ //
+ // If the fileName starts with a drive letter, then use NetUseGetInfo
+ // to get the remote name.
+ //
+ if (lpPathName[1] == L':') {
+ if (((L'a' <= lpPathName[0]) && (lpPathName[0] <= L'z')) ||
+ ((L'A' <= lpPathName[0]) && (lpPathName[0] <= L'Z'))) {
+ //
+ // This is in the form of a local device. Get the server/sharename
+ // associated with this device.
+ //
+ wcsncpy(useName, lpPathName, 2);
+ useName[2]=L'\0';
+ netStatus = NetUseGetInfo(
+ NULL, // server name
+ useName, // use name
+ 0, // level
+ (LPBYTE *)&pUseInfo); // buffer
+
+ if (netStatus != NERR_Success) {
+ //
+ // if we get NERR_UseNotFound back, then this must be
+ // a local drive letter, and not a redirected one.
+ // In this case we return success.
+ //
+ if (netStatus == NERR_UseNotFound) {
+ return(NERR_Success);
+ }
+ return(netStatus);
+ }
+ DeviceType = REMOTE_DRIVE;
+ pNewPathName = pUseInfo->ui0_remote;
+ }
+ }
+ else {
+ if (wcsncmp(lpPathName,L"\\\\",2) == 0) {
+ DeviceType = REMOTE_PATH;
+ pNewPathName = lpPathName;
+ }
+ }
+ if (DeviceType != LOCAL) {
+
+ //
+ // Figure out how many characters for the server and share portion
+ // of the string.
+ // Add 2 characters for the leading "\\\\", allocate a buffer, and
+ // copy the characters.
+ //
+ numChars = 2;
+ pPrivateShareName = AdtFindNextToken(L'\\',pNewPathName+2,&numChars);
+ if (pPrivateShareName == NULL) {
+ status = ERROR_BAD_PATHNAME;
+ goto CleanExit;
+ }
+ numServerChars = numChars;
+
+ token = L'\\';
+ if (DeviceType == REMOTE_DRIVE) {
+ token = L'\0';
+ }
+ pEnd = AdtFindNextToken(token,pPrivateShareName+1,&numChars);
+ if (pEnd == NULL) {
+ status = ERROR_BAD_PATHNAME;
+ goto CleanExit;
+ }
+ //
+ // If this is a remotepath name, then the share name portion will
+ // also contain the '\' token. Remove this by decrementing the
+ // count.
+ //
+ if (DeviceType == REMOTE_PATH) {
+ numChars--;
+ }
+ pPrivateServerName = LocalAlloc(LMEM_FIXED,(numChars+1) * sizeof(WCHAR));
+ if (pPrivateServerName == NULL) {
+ status = GetLastError();
+ goto CleanExit;
+ }
+
+ //
+ // Copy the the "\\servername\sharename" to the new buffer and
+ // place NUL characters in place of the single '\'.
+ //
+ wcsncpy(pPrivateServerName, pNewPathName, numChars);
+ pPrivateShareName = pPrivateServerName + numServerChars;
+
+ *(pPrivateShareName -1) = L'\0'; // NUL terminate the server name
+ pPrivateServerName[ numChars ] = L'\0'; // NUL terminate the share name
+
+ if (DeviceType == REMOTE_PATH) {
+ *pNewFileName = pEnd;
+ }
+ else {
+ *pNewFileName = lpPathName+2;
+ }
+ *pServerName = pPrivateServerName;
+ *pShareName = pPrivateShareName;
+ }
+CleanExit:
+ if (pUseInfo != NULL) {
+ NetApiBufferFree(pUseInfo);
+ }
+ return(status);
+}
+
+LPWSTR
+AdtFindNextToken(
+ WCHAR Token,
+ LPWSTR pString,
+ LPDWORD pNumChars
+ )
+
+/*++
+
+Routine Description:
+
+ Finds the first occurance of Token in the pString.
+
+Arguments:
+
+ Token - This is the unicode character that we are searching for in the
+ string.
+
+ pString - This is a pointer to the string in which the token is to be
+ found.
+
+ pNumChars - This is a pointer to a DWORD that will upon exit increment
+ by the number of characters found in the string (including the
+ token).
+
+Return Value:
+
+ If the token is found this returns a pointer to the Token.
+ Otherwise, it returns NULL.
+
+--*/
+{
+ DWORD saveNum=*pNumChars;
+
+ while ((*pString != Token) && (*pString != L'\0')) {
+ pString++;
+ (*pNumChars)++;
+ }
+ if (*pString != Token) {
+ *pNumChars = saveNum;
+ return(NULL);
+ }
+ (*pNumChars)++;
+ return(pString);
+}
+
diff --git a/private/net/svcdlls/srvsvc/client/dfsstub.c b/private/net/svcdlls/srvsvc/client/dfsstub.c
new file mode 100644
index 000000000..6b0f0adcd
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/dfsstub.c
@@ -0,0 +1,342 @@
+/*++
+
+Copyright (c) 1991-1996 Microsoft Corporation
+
+Module Name:
+
+ dfsstub.c
+
+Abstract:
+
+ These are the server service API RPC client stubs for DFS operations
+
+Environment:
+
+ User Mode - Win32
+
+--*/
+
+//
+// INCLUDES
+//
+
+#include <nt.h> // DbgPrint prototype
+
+#include <ntrtl.h> // DbgPrint
+#include <rpc.h> // DataTypes and runtime APIs
+
+#include <srvsvc.h> // generated by the MIDL complier
+#include <lmcons.h> // NET_API_STATUS
+#include <debuglib.h> // (needed by netrpc.h)
+#include <lmsvc.h> // (needed by netrpc.h)
+#include <netdebug.h> // (needed by netrpc.h)
+#include <lmerr.h> // NetError codes
+#include <netrpc.h> // NET_REMOTE_ macros.
+
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsGetVersion(
+ IN LPWSTR servername,
+ OUT LPDWORD Version)
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsGetVersion( servername, Version );
+
+ NET_REMOTE_RPC_FAILED(
+ "I_NetDfsGetVersion",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+}
+
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsCreateLocalPartition (
+ IN LPWSTR servername,
+ IN LPWSTR ShareName,
+ IN LPGUID EntryUid,
+ IN LPWSTR EntryPrefix,
+ IN LPWSTR ShortName,
+ IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
+ IN BOOL Force
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsCreateLocalPartition (
+ servername,
+ ShareName,
+ EntryUid,
+ EntryPrefix,
+ ShortName,
+ RelationInfo,
+ Force
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsCreateLocalPartition",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsDeleteLocalPartition (
+ IN LPWSTR servername OPTIONAL,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsDeleteLocalPartition (
+ servername,
+ Uid,
+ Prefix
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsDeleteLocalPartition",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsSetLocalVolumeState (
+ IN LPWSTR servername OPTIONAL,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix,
+ IN ULONG State
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsSetLocalVolumeState (
+ servername,
+ Uid,
+ Prefix,
+ State
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsSetLocalVolumeState",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsSetServerInfo (
+ IN LPWSTR servername OPTIONAL,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsSetServerInfo (
+ servername,
+ Uid,
+ Prefix
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsSetServerInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsCreateExitPoint (
+ IN LPWSTR servername OPTIONAL,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix,
+ IN ULONG Type,
+ IN ULONG ShortPrefixSize,
+ OUT LPWSTR ShortPrefix
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsCreateExitPoint (
+ servername,
+ Uid,
+ Prefix,
+ Type,
+ ShortPrefixSize,
+ ShortPrefix
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsCreateExitPoint",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsDeleteExitPoint (
+ IN LPWSTR servername OPTIONAL,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix,
+ IN ULONG Type
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsDeleteExitPoint (
+ servername,
+ Uid,
+ Prefix,
+ Type
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsDeleteExitPoint",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsModifyPrefix (
+ IN LPWSTR servername OPTIONAL,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsModifyPrefix (
+ servername,
+ Uid,
+ Prefix
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsModifyPrefix",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetDfsFixLocalVolume (
+ IN LPWSTR servername OPTIONAL,
+ IN LPWSTR VolumeName,
+ IN ULONG EntryType,
+ IN ULONG ServiceType,
+ IN LPWSTR StgId,
+ IN LPGUID EntryUid, // unique id for this partition
+ IN LPWSTR EntryPrefix, // path prefix for this partition
+ IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
+ IN ULONG CreateDisposition
+ )
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrDfsFixLocalVolume (
+ servername,
+ VolumeName,
+ EntryType,
+ ServiceType,
+ StgId,
+ EntryUid,
+ EntryPrefix,
+ RelationInfo,
+ CreateDisposition
+ );
+
+ NET_REMOTE_RPC_FAILED(
+ "NetDfsFixLocalVolume",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END;
+
+ return apiStatus;
+}
+
diff --git a/private/net/svcdlls/srvsvc/client/makefile b/private/net/svcdlls/srvsvc/client/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/net/svcdlls/srvsvc/client/radmin.c b/private/net/svcdlls/srvsvc/client/radmin.c
new file mode 100644
index 000000000..6ace6f221
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/radmin.c
@@ -0,0 +1,556 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ radmin.c (remote admin)
+
+Abstract:
+
+ This file exercises the various NetAdminTools API.
+
+Author:
+
+ Dan Lafferty (danl) 19-Sept-1991
+
+Environment:
+
+ User Mode -Win32
+
+Revision History:
+
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h> // needed for windows.h when I have nt.h
+#include <windows.h>
+
+#include <stdlib.h> // atoi
+#include <stdio.h> // printf
+#include <tstr.h> // STRICMP
+
+#include <ntseapi.h> // SECURITY_DESCRIPTOR_CONTROL
+#include <srvsvc.h>
+#include <filesec.h> // NetpGetFileSecurity, NetpSetFileSecurity
+
+//
+// DataStructures
+//
+
+typedef struct _TEST_SID {
+ UCHAR Revision;
+ UCHAR SubAuthorityCount;
+ UCHAR IdentifierAuthority[6];
+ ULONG SubAuthority[10];
+} TEST_SID, *PTEST_SID, *LPTEST_SID;
+
+typedef struct _TEST_ACL {
+ UCHAR AclRevision;
+ UCHAR Sbz1;
+ USHORT AclSize;
+ UCHAR Dummy1[];
+} TEST_ACL, *PTEST_ACL;
+
+typedef struct _TEST_SECURITY_DESCRIPTOR {
+ UCHAR Revision;
+ UCHAR Sbz1;
+ SECURITY_DESCRIPTOR_CONTROL Control;
+ PTEST_SID Owner;
+ PTEST_SID Group;
+ PTEST_ACL Sacl;
+ PTEST_ACL Dacl;
+} TEST_SECURITY_DESCRIPTOR, *PTEST_SECURITY_DESCRIPTOR;
+
+//
+// GLOBALS
+//
+
+ TEST_SID OwnerSid = {
+ 1, 5,
+ 1,2,3,4,5,6,
+ 0x999, 0x888, 0x777, 0x666, 0x12345678};
+
+ TEST_SID GroupSid = {
+ 1, 5,
+ 1,2,3,4,5,6,
+ 0x999, 0x888, 0x777, 0x666, 0x12345678};
+
+ TEST_ACL SaclAcl = { 1, 2, 4+1, 3};
+ TEST_ACL DaclAcl = { 1, 2, 4+5, 4, 4, 4, 4, 4, };
+
+ TEST_SECURITY_DESCRIPTOR TestSd = {
+ 1, 2, 0x3333,
+ &OwnerSid,
+ &GroupSid,
+ &SaclAcl,
+ NULL };
+
+
+
+//
+// Function Prototypes
+//
+
+NET_API_STATUS
+TestGetFileSec(
+ LPTSTR ServerName,
+ LPTSTR FileName
+ );
+
+NET_API_STATUS
+TestSetFileSec(
+ LPTSTR ServerName,
+ LPTSTR FileName
+ );
+
+VOID
+Usage(VOID);
+
+
+VOID
+DisplaySecurityDescriptor(
+ PTEST_SECURITY_DESCRIPTOR pSecDesc
+ );
+
+BOOL
+MakeArgsUnicode (
+ DWORD argc,
+ PCHAR argv[]
+ );
+
+BOOL
+ConvertToUnicode(
+ OUT LPWSTR *UnicodeOut,
+ IN LPSTR AnsiIn
+ );
+
+
+
+
+
+VOID _CRTAPI1
+main (
+ DWORD argc,
+ PUCHAR argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ Allows manual testing of the AdminTools API.
+
+ radmin GetNameFromSid - calls NetpGetNameFromSid
+ radmin SetFileSec - calls NetpSetFileSecurity
+
+ etc...
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+--*/
+
+{
+ DWORD status;
+ LPTSTR FileName;
+ LPTSTR *FixArgv;
+ LPTSTR pServerName;
+ DWORD argIndex;
+
+ //
+ // Make the arguments unicode if necessary.
+ //
+#ifdef UNICODE
+
+ if (!MakeArgsUnicode(argc, argv)) {
+ return;
+ }
+
+#endif
+ FixArgv = (LPTSTR *)argv;
+ argIndex = 1;
+ pServerName = NULL;
+
+ if (STRNCMP (FixArgv[1], TEXT("\\\\"), 2) == 0) {
+ pServerName = FixArgv[1];
+ argIndex = 2;
+ }
+ if (argc < 2) {
+ printf("ERROR: \n");
+ Usage();
+ return;
+ }
+
+ if (STRICMP (FixArgv[argIndex], TEXT("GetFileSec")) == 0) {
+ if (argc > argIndex ) {
+ FileName = FixArgv[argIndex+1];
+ }
+ else {
+ FileName = NULL;
+ }
+ status = TestGetFileSec(pServerName,FileName);
+ }
+
+ else if (STRICMP (FixArgv[argIndex], TEXT("SetFileSec")) == 0) {
+ if (argc > argIndex ) {
+ FileName = FixArgv[argIndex+1];
+ }
+ else {
+ FileName = NULL;
+ }
+ status = TestSetFileSec(pServerName,FileName);
+ }
+
+ else {
+ printf("[sc] Unrecognized Command\n");
+ Usage();
+ }
+
+ return;
+}
+
+
+
+
+NET_API_STATUS
+TestGetFileSec(
+ LPTSTR ServerName,
+ LPTSTR FileName
+ )
+{
+ NET_API_STATUS status;
+ SECURITY_INFORMATION secInfo;
+ PTEST_SECURITY_DESCRIPTOR pSecurityDescriptor;
+ LPBYTE pDest;
+ DWORD Length;
+
+ if (FileName == NULL ) {
+ FileName = TEXT("Dan.txt");
+ }
+
+// secInfo = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+// DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION);
+ secInfo = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION );
+
+ status = NetpGetFileSecurity(
+ FileName, // FileName,
+ secInfo, // pRequestedInformation,
+ (PSECURITY_DESCRIPTOR *)&pSecurityDescriptor, // pSecurityDescriptor,
+ &Length); // pnLength
+
+ if (status != NO_ERROR) {
+ printf("NetpGetFileSecurity Failed %d,0x%x\n",status,status);
+ }
+ else{
+
+ pDest = (LPBYTE) pSecurityDescriptor;
+
+ if (!IsValidSecurityDescriptor(pSecurityDescriptor)) {
+ printf("FAILURE: SECURITY DESCRIPTOR IS INVALID\n");
+ }
+ else {
+ printf("SUCCESS: SECURITY DESCRIPTOR IS VALID\n");
+ }
+
+ //
+ // Make the self-releative SD absolute for display.
+ //
+ pSecurityDescriptor->Owner = (PTEST_SID)(pDest + (DWORD)pSecurityDescriptor->Owner);
+ pSecurityDescriptor->Group = (PTEST_SID)(pDest + (DWORD)pSecurityDescriptor->Group);
+ pSecurityDescriptor->Sacl = (PTEST_ACL)(pDest + (DWORD)pSecurityDescriptor->Sacl);
+ pSecurityDescriptor->Dacl = (PTEST_ACL)(pDest + (DWORD)pSecurityDescriptor->Dacl);
+ pSecurityDescriptor->Control &= (~SE_SELF_RELATIVE);
+
+ if (pSecurityDescriptor->Sacl == (PTEST_ACL)pDest) {
+ pSecurityDescriptor->Sacl = NULL;
+ }
+ if (pSecurityDescriptor->Dacl == (PTEST_ACL)pDest) {
+ pSecurityDescriptor->Dacl = NULL;
+ }
+
+ printf("Size of Security Descriptor = %ld \n",Length);
+ DisplaySecurityDescriptor(pSecurityDescriptor);
+ }
+
+ return (NO_ERROR);
+}
+
+NET_API_STATUS
+TestSetFileSec(
+ LPTSTR ServerName,
+ LPTSTR FileName
+ )
+{
+ NET_API_STATUS status;
+ SECURITY_INFORMATION secInfo;
+
+
+ if (FileName == NULL ) {
+ FileName = TEXT("Dan.txt");
+ }
+
+ secInfo = 0x55555555;
+
+ status = NetpSetFileSecurity(
+ FileName, // FileName,
+ secInfo, // pRequestedInformation,
+ (PSECURITY_DESCRIPTOR)&TestSd); // pSecurityDescriptor,
+
+ if (status != NO_ERROR) {
+ printf("NetpSetFileSecurity Failed %d,0x%x\n",status,status);
+ }
+ return (NO_ERROR);
+}
+
+
+VOID
+Usage(VOID)
+{
+
+ printf("USAGE:\n");
+ printf("radmin <server> <function>\n");
+ printf("Functions: GetFileSec, SetFileSec...\n\n");
+
+ printf("SYNTAX EXAMPLES \n");
+
+ printf("radmin \\\\DANL2 GetFileSec - calls NetpGetFileSecurity on \\DANL2\n");
+ printf("radmin \\\\DANL2 SetFileSec - calls NetpSetFileSecurity on \\DANL2\n");
+}
+
+
+
+// ***************************************************************************
+VOID
+DisplaySecurityDescriptor(
+ PTEST_SECURITY_DESCRIPTOR pSecDesc
+ )
+{
+
+ DWORD i;
+ DWORD numAces;
+
+ if (!IsValidSecurityDescriptor(pSecDesc)) {
+ printf("FAILURE: SECURITY DESCRIPTOR IS INVALID\n");
+ }
+
+ printf("[ADT]:Security Descriptor Received\n");
+ printf("\tSECURITY_DESCRIPTOR HEADER:\n");
+ printf("\tRevision: %d\n", pSecDesc->Revision);
+ printf("\tSbz1: 0x%x\n", pSecDesc->Sbz1);
+ printf("\tControl: 0x%x\n", pSecDesc->Control);
+
+ //-------------------
+ // OWNER SID
+ //-------------------
+ printf("\n\tOWNER_SID\n");
+ printf("\t\tRevision: %u\n",pSecDesc->Owner->Revision);
+ printf("\t\tSubAuthorityCount: %u\n",pSecDesc->Owner->SubAuthorityCount);
+
+ printf("\t\tIdentifierAuthority: ");
+ for(i=0; i<6; i++) {
+ printf("%u ",pSecDesc->Owner->IdentifierAuthority[i]);
+ }
+ printf("\n");
+
+ printf("\t\tSubAuthority: ");
+ for(i=0; i<pSecDesc->Group->SubAuthorityCount; i++) {
+ printf("0x%x ",pSecDesc->Owner->SubAuthority[i]);
+ }
+ printf("\n");
+
+ //-------------------
+ // GROUP SID
+ //-------------------
+ printf("\n\tGROUP_SID\n");
+ printf("\t\tRevision: %u\n",pSecDesc->Group->Revision);
+ printf("\t\tSubAuthorityCount: %u\n",pSecDesc->Group->SubAuthorityCount);
+
+ printf("\t\tIdentifierAuthority: ");
+ for(i=0; i<6; i++) {
+ printf("%u ",pSecDesc->Group->IdentifierAuthority[i]);
+ }
+ printf("\n");
+
+ printf("\t\tSubAuthority: ");
+ for(i=0; i<pSecDesc->Group->SubAuthorityCount; i++) {
+ printf("0x%x ",pSecDesc->Group->SubAuthority[i]);
+ }
+ printf("\n");
+
+ if (pSecDesc->Sacl != NULL) {
+ printf("\n\tSYSTEM_ACL\n");
+ printf("\t\tRevision: %d\n",pSecDesc->Sacl->AclRevision);
+ printf("\t\tSbz1: %d\n",pSecDesc->Sacl->Sbz1);
+ printf("\t\tAclSize: %d\n",pSecDesc->Sacl->AclSize);
+ printf("\t\tACE: %u\n",(unsigned short)pSecDesc->Sacl->Dummy1[0]);
+ }
+ else {
+ printf("\n\tSYSTEM_ACL = NULL\n");
+ }
+
+ if (pSecDesc->Dacl != NULL) {
+ printf("\n\tDISCRETIONARY_ACL\n");
+ printf("\t\tRevision: %d\n",pSecDesc->Dacl->AclRevision);
+ printf("\t\tSbz1: %d\n",pSecDesc->Dacl->Sbz1);
+ printf("\t\tAclSize: %d\n",pSecDesc->Dacl->AclSize);
+
+ numAces = pSecDesc->Dacl->AclSize - 4;
+
+ for (i=0; i<numAces; i++) {
+ //
+ // NOTE: I couldn't get this to print out the right value in DOS16.
+ // So I gave up. It puts the 04 into the AL register and then
+ // clears the AH register, then pushes AX (both parts). But when
+ // it prints, it only prints 0.
+ //
+ printf("\t\tACE%u: %u\n",i,(unsigned short)pSecDesc->Dacl->Dummy1[i]);
+ }
+ }
+ else {
+ printf("\n\tDISCRETIONARY_ACL = NULL\n");
+ }
+}
+
+
+BOOL
+MakeArgsUnicode (
+ DWORD argc,
+ PCHAR argv[]
+ )
+
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+Note:
+
+
+--*/
+{
+ DWORD i;
+
+ //
+ // ScConvertToUnicode allocates storage for each string.
+ // We will rely on process termination to free the memory.
+ //
+ for(i=0; i<argc; i++) {
+
+ if(!ConvertToUnicode( (LPWSTR *)&(argv[i]), argv[i])) {
+ printf("Couldn't convert argv[%d] to unicode\n",i);
+ return(FALSE);
+ }
+
+
+ }
+ return(TRUE);
+}
+
+BOOL
+ConvertToUnicode(
+ OUT LPWSTR *UnicodeOut,
+ IN LPSTR AnsiIn
+ )
+
+/*++
+
+Routine Description:
+
+ This function translates an AnsiString into a Unicode string.
+ A new string buffer is created by this function. If the call to
+ this function is successful, the caller must take responsibility for
+ the unicode string buffer that was allocated by this function.
+ The allocated buffer should be free'd with a call to LocalFree.
+
+ NOTE: This function allocates memory for the Unicode String.
+
+ BUGBUG: This should be changed to return either
+ ERROR_NOT_ENOUGH_MEMORY or ERROR_INVALID_PARAMETER
+
+Arguments:
+
+ AnsiIn - This is a pointer to an ansi string that is to be converted.
+
+ UnicodeOut - This is a pointer to a location where the pointer to the
+ unicode string is to be placed.
+
+Return Value:
+
+ TRUE - The conversion was successful.
+
+ FALSE - The conversion was unsuccessful. In this case a buffer for
+ the unicode string was not allocated.
+
+--*/
+{
+
+ NTSTATUS ntStatus;
+ DWORD bufSize;
+ UNICODE_STRING unicodeString;
+ ANSI_STRING ansiString;
+
+ //
+ // Allocate a buffer for the unicode string.
+ //
+
+ bufSize = (strlen(AnsiIn)+1) * sizeof(WCHAR);
+
+ *UnicodeOut = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (UINT)bufSize);
+
+ if (*UnicodeOut == NULL) {
+ printf("ScConvertToUnicode:LocalAlloc Failure %ld\n",GetLastError());
+ return(FALSE);
+ }
+
+ //
+ // Initialize the string structures
+ //
+ RtlInitAnsiString( &ansiString, AnsiIn);
+
+ unicodeString.Buffer = *UnicodeOut;
+ unicodeString.MaximumLength = (USHORT)bufSize;
+ unicodeString.Length = 0;
+
+ //
+ // Call the conversion function.
+ //
+ ntStatus = RtlAnsiStringToUnicodeString (
+ &unicodeString, // Destination
+ &ansiString, // Source
+ (BOOLEAN)FALSE); // Allocate the destination
+
+ if (!NT_SUCCESS(ntStatus)) {
+
+ printf("ScConvertToUnicode:RtlAnsiStringToUnicodeString Failure %lx\n",
+ ntStatus);
+
+ return(FALSE);
+ }
+
+ //
+ // Fill in the pointer location with the unicode string buffer pointer.
+ //
+ *UnicodeOut = unicodeString.Buffer;
+
+ return(TRUE);
+
+}
+
+
diff --git a/private/net/svcdlls/srvsvc/client/sources b/private/net/svcdlls/srvsvc/client/sources
new file mode 100644
index 000000000..5ee63c11d
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/sources
@@ -0,0 +1,57 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+MAJORCOMP = srvsvc
+MINORCOMP = client
+
+
+NTPROFILEINPUT=YES
+
+TARGETNAME=srvsvc
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..;..\..\..\inc;..\..\..\..\inc
+
+!IFNDEF DISABLE_NET_UNICODE
+UNICODE=1
+NET_C_DEFINES=-DUNICODE
+!ENDIF
+
+SOURCES=srvstub.c \
+ srvbind.c \
+ adtwrap.c \
+ dfsstub.c \
+ srvsvc_c.c
+
+UMTYPE=console
+UMLIBS= $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ ..\lib\obj\*\srvcomn.lib
+
+C_DEFINES=-DRPC_NO_WINDOWS_H
+
diff --git a/private/net/svcdlls/srvsvc/client/srvbind.c b/private/net/svcdlls/srvsvc/client/srvbind.c
new file mode 100644
index 000000000..9c6c5345d
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/srvbind.c
@@ -0,0 +1,111 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ srvbind.c
+
+Abstract:
+
+ Contains the RPC bind and un-bind routines for the Server
+ Service.
+
+Author:
+
+ Dan Lafferty (danl) 01-Mar-1991
+
+Environment:
+
+ User Mode -Win32
+
+Revision History:
+
+ 01-Mar-1991 danl
+ created
+ 07-Jun-1991 JohnRo
+ Allowed debug output of failures.
+
+--*/
+
+//
+// INCLUDES
+//
+#include <nt.h> // DbgPrint prototype
+#include <rpc.h> // DataTypes and runtime APIs
+#include <srvsvc.h> // generated by the MIDL complier
+#include <rpcutil.h> // NetRpc utils
+#include <netlib.h> // UNUSED macro
+#include <srvnames.h> // SERVER_INTERFACE_NAME
+
+
+
+handle_t
+SRVSVC_HANDLE_bind (
+ SRVSVC_HANDLE ServerName)
+
+/*++
+
+Routine Description:
+ This routine calls a common bind routine that is shared by all services.
+ This routine is called from the server service client stubs when
+ it is necessary to bind to a server.
+
+Arguments:
+
+ ServerName - A pointer to a string containing the name of the server
+ to bind with.
+
+Return Value:
+
+ The binding handle is returned to the stub routine. If the
+ binding is unsuccessful, a NULL will be returned.
+
+--*/
+{
+ handle_t bindingHandle;
+ RPC_STATUS status;
+
+ status = NetpBindRpc (
+ ServerName,
+ SERVER_INTERFACE_NAME,
+ TEXT("Security=Impersonation Dynamic False"),
+ &bindingHandle);
+
+ return( bindingHandle);
+}
+
+
+
+void
+SRVSVC_HANDLE_unbind (
+ SRVSVC_HANDLE ServerName,
+ handle_t BindingHandle)
+
+/*++
+
+Routine Description:
+
+ This routine calls a common unbind routine that is shared by
+ all services.
+ This routine is called from the server service client stubs when
+ it is necessary to unbind to a server.
+
+
+Arguments:
+
+ ServerName - This is the name of the server from which to unbind.
+
+ BindingHandle - This is the binding handle that is to be closed.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ UNUSED(ServerName); // This parameter is not used
+
+ NetpUnbindRpc ( BindingHandle);
+ return;
+}
diff --git a/private/net/svcdlls/srvsvc/client/srvstub.c b/private/net/svcdlls/srvsvc/client/srvstub.c
new file mode 100644
index 000000000..e10305558
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/srvstub.c
@@ -0,0 +1,3573 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ SrvStub.C
+
+Abstract:
+
+ These are the server service API RPC client stubs.
+
+Author:
+
+ Dan Lafferty (danl) 06-Feb-1991
+
+Environment:
+
+ User Mode - Win32
+
+Revision History:
+
+ 06-Feb-1991 Danl
+ Created
+ 07-Jun-1991 JohnRo
+ Added downlevel support for NetServer APIs.
+ Added NET_API_FUNCTION where necessary.
+ 15-Jul-1991 RFirth
+ Integrated RxNetShare routines into NetShare stubs
+ 24-Jul-1991 JohnRo
+ Implement downlevel NetConnectionEnum. Try using <netrpc.h> macros.
+ 25-Jul-1991 JohnRo
+ Quiet DLL stub debug output. Use NetRpc.h macros for NetServer APIs.
+ 06-Sep-1991 JohnRo
+ Downlevel NetFile APIs.
+ 25-Sep-1991 JohnRo
+ Use NetRpc.h macros for all other APIs, to quiet normal debug output.
+ 07-Oct-1991 JohnRo
+ RAID 3210: "NET FILE 0" causes assertion. (Was bug in NetFileGetInfo
+ DLL stub.)
+ 16-Oct-1991 JohnRo
+ Implement remote NetSession APIs. Changed LPSTR to LPTSTR.
+ 07-Nov-1991 JohnRo
+ RAID 4186: assert in RxNetShareAdd and other DLL stub problems.
+ 12-Nov-1991 JohnRo
+ APIs in this file need SERVICE_SERVER started to run locally.
+ 04-Dec-1991 JohnRo
+ Change RxNetServerSetInfo() to new-style interface.
+ Fixed bug in calling RxNetShareSetInfo().
+ 09-May-1992 rfirth
+ Resurrect NetStatisticsGet as NetServerStatisticsGet
+ 5-Aug-1992 JohnsonA
+ Added new share info level 502 to enable passing of security
+ descriptors.
+ 08-Sep-1992 JohnRo
+ Fix NET_API_FUNCTION references.
+--*/
+
+//
+// INCLUDES
+//
+
+#include <nt.h> // DbgPrint prototype
+
+#include <ntrtl.h> // DbgPrint
+#include <rpc.h> // DataTypes and runtime APIs
+
+#include <srvsvc.h> // generated by the MIDL complier
+#include <rpcutil.h> // GENERIC_ENUM_STRUCT
+#include <lmcons.h> // NET_API_STATUS
+#include <debuglib.h> // (needed by netrpc.h)
+#include <lmsvc.h> // (needed by netrpc.h)
+#include <netdebug.h> // (needed by netrpc.h)
+#include <lmerr.h> // NetError codes
+#include <netlib.h> // NetpIsServiceStarted().
+#include <netlibnt.h> // NetpNtStatusToApiStatus
+#include <netrpc.h> // NET_REMOTE_ macros.
+#include <lmremutl.h> // SUPPORTS_RPC
+#include <lmshare.h> // Required by rxsess.h.
+#include <rap.h> // Needed by <rxserver.h>.
+#include <rxconn.h> // RxNetConnection routines.
+#include <rxfile.h> // RxNetFile routines.
+#include <rxremutl.h> // RxNetRemoteTOD
+#include <rxserver.h> // RxNetServer routines.
+#include <rxsess.h> // RxNetSession routines.
+#include <rxshare.h> // RxNetShare routines
+#include <icanon.h> // NetpIsRemote
+#include <netstats.h> // NetServerStatisticsGet private prototype
+#include <rxstats.h> // RxNetStatisticsGet (down-level)
+#include <netcan.h> // prototypes for Netps canonicalization functions
+#include <rxcanon.h> // prototypes for down-level canonicalization functions
+#include <tstr.h>
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevControl (
+ IN LPCWSTR servername,
+ IN LPCWSTR devname,
+ IN DWORD opcode
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevControl.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ devname --A pointer to the ASCIIZ string containing the name of
+ the device to control
+
+ opcode --Control opcode: currently defined are:
+ CHARDEV_CLOSE for the device closed.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevControl (
+ (LPWSTR)servername,
+ (LPWSTR)devname,
+ opcode);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevControl",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevControl
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevEnum (
+ IN LPCWSTR servername,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information required. 0 and 1 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by
+ totalentries.
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing character device search. The handle should be zero
+ on the first call and left unchanged for subsequent calls. If
+ resumehandle is NULL, then no resume handle is stored..
+
+Return Value:
+
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevEnum (
+ (LPWSTR)servername,
+ (LPCHARDEV_ENUM_STRUCT)&infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevGetInfo (
+ IN LPCWSTR servername,
+ IN LPCWSTR devname,
+ IN DWORD level,
+ OUT LPBYTE *bufptr
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevGetInfo.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ devname --A pointer to the ASCIIZ string containing the name of
+ the device to return information on.
+
+ level --Level of information required. 0 and 1 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+Return Value:
+
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+
+ *bufptr = NULL; // Must be NULL so RPC knows to till it in.
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevGetInfo (
+ (LPWSTR)servername,
+ (LPWSTR)devname,
+ level,
+ (LPCHARDEV_INFO) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevGetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevQEnum (
+ IN LPCWSTR servername,
+ IN LPCWSTR username,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevQEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ username --A pointer to an ASCIIZ string containing an a username
+ for the active queues of interest. This parameter is
+ optional, if NULL then all device queues are enumerated.
+
+ level --Level of information required. 0 and 1 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by
+ totalentries.
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing character device queue search. The handle should be
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevQEnum (
+ (LPWSTR)servername,
+ (LPWSTR)username,
+ (LPCHARDEVQ_ENUM_STRUCT) &infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevQEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevQEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevQGetInfo (
+ IN LPCWSTR servername,
+ IN LPCWSTR queuename,
+ IN LPCWSTR username,
+ IN DWORD level,
+ OUT LPBYTE *bufptr
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevQGetInfo.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ queuename --A pointer to an ASCIIZ string containing the name of
+ the queue to return information on.
+
+ username --A pointer to an ASCIIZ string containing the username
+ of the a user whose job of of interest for the cq1_numahead
+ count.
+
+ level --Level of information required. 0 and 1 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ *bufptr = NULL; // Must be NULL so RPC knows to till it in.
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevQGetInfo (
+ (LPWSTR)servername,
+ (LPWSTR)queuename,
+ (LPWSTR)username,
+ level,
+ (LPCHARDEVQ_INFO) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevQGetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevQGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevQPurge (
+ IN LPCWSTR servername,
+ IN LPCWSTR queuename
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevQPurge.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ queuename --A pointer to an ASCIIZ string containing the name of
+ the queue to be purged.
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevQPurge (
+ (LPWSTR)servername,
+ (LPWSTR)queuename);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevQPurge",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevQPurge
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevQPurgeSelf (
+ IN LPCWSTR servername,
+ IN LPCWSTR queuename,
+ IN LPCWSTR computername
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevQPurgeSelf.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ queuename --A pointer to an ASCIIZ string containing the name of
+ the queue to be purged of pending entries from the specified
+ computer.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevQPurgeSelf (
+ (LPWSTR)servername,
+ (LPWSTR)queuename,
+ (LPWSTR)computername);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevQPurgeSelf",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevQPurgeSelf
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetCharDevQSetInfo (
+ IN LPCWSTR servername,
+ IN LPCWSTR queuename,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetCharDevQSetInfo.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ queuename --A pointer to an ASCIIZ string containing the name of
+ the queue to set information on.
+
+ level --Level of information to set.
+
+ buf --A pointer to a buffer containing the chardev information.
+ If parmnum is non zero then the buffer contains only the
+ appropriate data for the specific element. If parmnum is
+ zero, then the buffer contains the whole chardev information
+ structure.
+
+ parm_err --Optional pointer to a DWORD to return the index of the
+ first parameter in error when ERROR_INVALID_PARAMETER is
+ returned. If NULL the parameter is not returned on error.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrCharDevQSetInfo (
+ (LPWSTR)servername,
+ (LPWSTR)queuename,
+ level,
+ (LPCHARDEVQ_INFO) &buf,
+ parm_err);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetCharDevQSetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // BUGBUG: Put Downlevel Call Here!
+ //
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetCharDevQSetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetConnectionEnum (
+ IN LPTSTR servername,
+ IN LPTSTR qualifier,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetConnectionEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ qualifier --A pointer to an ASCIIZ string containing a sharename
+ or computername for the connections of interest. If it is a
+ sharename, then all the connections made to that sharename
+ are listed. If it is a computername (i.e. it starts with two
+ backslash characters), then NetConnectionEnum lists all
+ connections made from that computer to the server specified.
+
+ level --Level of information required. 0 and 1 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrConnectionEnum (
+ servername,
+ qualifier,
+ (LPCONNECT_ENUM_STRUCT)&infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetConnectionEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Try call to downlevel.
+ //
+ apiStatus = RxNetConnectionEnum(
+ servername,
+ qualifier,
+ level,
+ bufptr,
+ prefmaxlen,
+ entriesread,
+ totalentries,
+ resume_handle
+ );
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetConnectionEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetFileClose (
+ IN LPTSTR servername,
+ IN DWORD fileid
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetFileClose.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ fileid --The fileid of the opened resource instance to be closed.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrFileClose (
+ servername,
+ fileid);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetFileClose",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = RxNetFileClose (
+ servername,
+ fileid);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+}
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetFileEnum (
+ IN LPTSTR servername,
+ IN LPTSTR basepath,
+ IN LPTSTR username,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetFileEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ basepath --A pointer to an ASCIIZ string containing a qualifier
+ for the returned information. If NULL then all open resources
+ are enumerated, else only resources which have basepath as a
+ prefix are enumerated.
+
+ username --A pointer to an ASCIIZ string that specifies the name
+ of the user. If not NULL, username serves as a qualifier to
+ the ennumeration. The files returned are limited to those
+ that have usernames matching the qualifier. If username is
+ NULL, no username qualifier is used.
+
+ level --Level of information required. 2 and 3 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by
+ totalentries.
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing file search. The handle should be zero on the first
+ call and left unchanged for subsequent calls. If resumehandle
+ is NULL, then no resume handle is stored..
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrFileEnum (
+ servername,
+ basepath,
+ username,
+ (LPFILE_ENUM_STRUCT) &infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetFileEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = RxNetFileEnum(
+ servername,
+ basepath,
+ username,
+ level,
+ bufptr,
+ prefmaxlen,
+ entriesread,
+ totalentries,
+ resume_handle);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetFileEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetFileGetInfo (
+ IN LPTSTR servername,
+ IN DWORD fileid,
+ IN DWORD level,
+ OUT LPBYTE *bufptr
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetFileGetInfo.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ fileid --The fileid of the open resource to return information
+ on. The fileid value must be that returned in a previous
+ enumeration call.
+
+ level --Level of information required. 2 and 3 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ *bufptr = NULL; // Must be NULL so RPC knows to fill it in.
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrFileGetInfo (
+ servername,
+ fileid,
+ level,
+ (LPFILE_INFO) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetFileGetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ apiStatus = RxNetFileGetInfo (
+ servername,
+ fileid,
+ level,
+ bufptr);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetFileGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetSessionDel (
+ IN LPTSTR servername,
+ IN LPTSTR clientname,
+ IN LPTSTR username
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetSessionDel.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ clientname --A pointer to an ASCIIZ string containing the
+ computername of the client to disconnect.
+
+ username --A pointer to an ASCIIZ string containing the name of
+ the user whose session is to be terminated. A NULL indicates
+ that all users' sessions from the computername specified are
+ to be terminated.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrSessionDel (
+ servername,
+ clientname,
+ username);
+
+ NET_REMOTE_RPC_FAILED("NetSessionDel", servername, apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER )
+
+ //
+ // Call downlevel version of the API.
+ //
+
+ apiStatus = RxNetSessionDel (
+ servername,
+ clientname,
+ username);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetSessionDel
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetSessionEnum (
+ IN LPTSTR servername,
+ IN LPTSTR clientname,
+ IN LPTSTR username,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetSessionEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ clientname --A pointer to an ASCIIZ string containing the name of
+ the computer session for which information is to be returned.
+ A NULL pointer or string specifies that all computer sessions
+ on the server are to be ennumerated.
+
+ username --A pointer to an ASCIIZ string containing the name of
+ the the user for which to ennumerate the sessions. A NULL
+ pointer or string specifies that sessions for all users are
+ to be ennumerated.
+
+ level --Level of information required. 0, 1, 2 and 10 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by
+ totalentries.
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing session search. The handle should be zero on the
+ first call and left unchanged for subsequent calls. If
+ resumehandle is NULL, then no resume handle is stored.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrSessionEnum (
+ servername,
+ clientname,
+ username,
+ (PSESSION_ENUM_STRUCT) &infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED("NetSessionEnum", servername, apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER )
+
+ //
+ // Call downlevel version of the API.
+ //
+
+ apiStatus = RxNetSessionEnum (
+ servername,
+ clientname,
+ username,
+ level,
+ bufptr,
+ prefmaxlen,
+ entriesread,
+ totalentries,
+ resume_handle);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetSessionEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetSessionGetInfo (
+ IN LPTSTR servername,
+ IN LPTSTR clientname,
+ IN LPTSTR username,
+ IN DWORD level,
+ OUT LPBYTE *bufptr
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetSessionEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ clientname --A pointer to an ASCIIZ string containing the name of
+ the computer session for which information is to be returned.
+ This field cannot be NULL.
+
+ username --A pointer to an ASCIIZ string containing the name of
+ the the user for which to ennumerate the sessions. This field
+ cannot be NULL.
+
+ level --Level of information required. 0, 1, 2 and 10 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+ DWORD totalentries;
+
+ if ( clientname == NULL || username == NULL ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrSessionEnum (
+ servername,
+ clientname,
+ username,
+ (PSESSION_ENUM_STRUCT) &infoStruct,
+ (DWORD)-1,
+ &totalentries,
+ NULL);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ } else {
+ *bufptr = NULL;
+ if ( apiStatus == NO_ERROR ) {
+ return NERR_ClientNameNotFound;
+ }
+ }
+
+ NET_REMOTE_RPC_FAILED("NetSessionGetInfo", servername, apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER )
+
+ //
+ // Call downlevel version of the API.
+ //
+
+ apiStatus = RxNetSessionGetInfo (
+ servername,
+ clientname,
+ username,
+ level,
+ bufptr);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetSessionGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareAdd (
+ IN LPTSTR servername,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareAdd. Only levels 2 and 502
+ are allowed.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information provided. Must be 2.
+
+ buf --A pointer to a buffer containing the share information
+ structure.
+
+ parm_err --Optional pointer to a DWORD to return the index of the
+ first parameter in error when ERROR_INVALID_PARAMETER is
+ returned. If NULL the parameter is not returned on error.
+
+Return Value:
+
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ NTSTATUS status;
+ ULONG SDLength = 0;
+ ULONG oldSDLength;
+ PSECURITY_DESCRIPTOR securityDescriptor = NULL;
+ PSECURITY_DESCRIPTOR oldSecurityDescriptor = NULL;
+
+
+ //
+ // do the parameter validation here - this way we only need do it once and
+ // in a centralized place
+ //
+
+ if (level != 2 && level != 502) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ NET_REMOTE_TRY_RPC
+
+ if ( level == 502 ) {
+
+ PSHARE_INFO_502 shi502 = (LPSHARE_INFO_502) buf;
+
+ //
+ // Save this. We need to restore this later.
+ //
+
+ oldSecurityDescriptor = shi502->shi502_security_descriptor;
+ oldSDLength = shi502->shi502_reserved;
+
+ if ( oldSecurityDescriptor != NULL ) {
+
+ if ( !RtlValidSecurityDescriptor( oldSecurityDescriptor) ) {
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make a self relative security descriptor for use in the
+ // RPC call..
+ //
+
+ status = RtlMakeSelfRelativeSD(
+ oldSecurityDescriptor,
+ NULL,
+ &SDLength
+ );
+
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+
+ return(ERROR_INVALID_PARAMETER);
+
+ } else {
+
+ securityDescriptor = MIDL_user_allocate( SDLength );
+
+ if ( securityDescriptor == NULL) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ } else {
+
+ //
+ // make an appropriate self-relative security descriptor
+ //
+
+ status = RtlMakeSelfRelativeSD(
+ oldSecurityDescriptor,
+ (PSECURITY_DESCRIPTOR) securityDescriptor,
+ &SDLength
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ MIDL_user_free( securityDescriptor );
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ shi502->shi502_security_descriptor = securityDescriptor;
+ shi502->shi502_reserved = SDLength;
+
+ }
+ }
+
+ } else {
+
+ shi502->shi502_reserved = 0;
+
+ }
+ }
+
+ apiStatus = NetrShareAdd (
+ servername,
+ level,
+ (LPSHARE_INFO) &buf,
+ parm_err);
+
+ if ( securityDescriptor != NULL ) {
+
+ //
+ // restore old values
+ //
+
+ PSHARE_INFO_502 shi502 = (LPSHARE_INFO_502) buf;
+ shi502->shi502_security_descriptor = oldSecurityDescriptor;
+ shi502->shi502_reserved = oldSDLength;
+ MIDL_user_free( securityDescriptor );
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareAdd",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel server.
+ //
+
+ if ( level != 502 ) {
+ apiStatus = RxNetShareAdd(
+ servername,
+ 2,
+ buf,
+ parm_err
+ );
+ } else {
+ apiStatus = ERROR_NOT_SUPPORTED;
+ }
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareAdd
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareCheck (
+ IN LPTSTR servername,
+ IN LPTSTR device,
+ OUT LPDWORD type
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareCheck
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ device --A pointer to an ASCIIZ string containing the name of the
+ device to check for shared access.
+
+ type --On return the address pointed to by the type parameter
+ contains the type of share the device is offered with. This
+ field is only set if success was returned.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+
+ if (!(device && *device) || !type) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrShareCheck (
+ servername,
+ device,
+ type);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareCheck",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel server.
+ //
+
+ apiStatus = RxNetShareCheck(servername, device, type);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareCheck
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareDel (
+ IN LPTSTR servername,
+ IN LPTSTR netname,
+ IN DWORD reserved
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareDel.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ netname --A pointer to an ASCIIZ string containing the netname of
+ the share to delete.
+
+ reserved --Reserved, must be zero.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ BOOL committingIpcDelete = FALSE;
+ SHARE_DEL_HANDLE handle;
+ BOOL tryDownLevel = FALSE;
+
+ if ( !netname || (*netname == 0) || reserved ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ RpcTryExcept {
+
+ if ( STRICMP( netname, TEXT("IPC$") ) != 0 ) {
+
+ apiStatus = NetrShareDel(
+ servername,
+ netname,
+ reserved
+ );
+
+ } else {
+
+ apiStatus = NetrShareDelStart(
+ servername,
+ netname,
+ reserved,
+ &handle
+ );
+
+ if ( apiStatus == NERR_Success ) {
+ committingIpcDelete = TRUE;
+ apiStatus = NetrShareDelCommit( &handle );
+ }
+
+ }
+
+ } RpcExcept ( 1 ) {
+
+ RPC_STATUS rpcStatus;
+
+ rpcStatus = RpcExceptionCode( );
+
+ if ( committingIpcDelete && (rpcStatus == RPC_S_CALL_FAILED) ) {
+
+ apiStatus = NERR_Success;
+
+ } else {
+
+ apiStatus = NetpHandleRpcFailure(
+ "NetShareDel",
+ rpcStatus,
+ servername,
+ SERVICE_SERVER,
+ NET_REMOTE_FLAG_NORMAL,
+ &tryDownLevel
+ );
+
+ }
+
+ }
+
+ RpcEndExcept
+
+ if (apiStatus == NERR_TryDownLevel) {
+ tryDownLevel = TRUE;
+ }
+
+ if ( tryDownLevel ) {
+
+ //
+ // Call downlevel server.
+ //
+ // note: push value 0 instead of real reserved
+ //
+
+ apiStatus = RxNetShareDel(servername, netname, 0);
+
+ }
+
+ return apiStatus;
+
+} // NetShareDel
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareDelSticky (
+ IN LPTSTR servername,
+ IN LPTSTR netname,
+ IN DWORD reserved
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareDelSticky.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ netname --A pointer to an ASCIIZ string containing the netname of
+ the share to delete.
+
+ reserved --Reserved, must be zero.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+
+ if (!(netname && *netname) || reserved) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrShareDelSticky (
+ servername,
+ netname,
+ reserved);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareDelSticky",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareDelSticky
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareEnum (
+ IN LPTSTR servername,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareEnum
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information required. 0, 1 and 2 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by
+ totalentries.
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing share search. The handle should be zero on the first
+ call and left unchanged for subsequent calls. If resumehandle
+ is NULL, then no resume handle is stored..
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+
+ //
+ // check the caller's parameters
+ //
+
+ *totalentries = *entriesread = 0;
+ *bufptr = NULL;
+
+ if ( (level > 2) && (level != 502) ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrShareEnum (
+ servername,
+ (LPSHARE_ENUM_STRUCT) &infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel server.
+ //
+
+ if ( level != 502 ) {
+ apiStatus = RxNetShareEnum(servername, level, bufptr,
+ prefmaxlen, entriesread, totalentries, resume_handle);
+ } else {
+ apiStatus = ERROR_NOT_SUPPORTED;
+ }
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareEnum
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareEnumSticky (
+ IN LPTSTR servername,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareEnumSticky
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information required. 0, 1 and 2 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by
+ totalentries.
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing share search. The handle should be zero on the first
+ call and left unchanged for subsequent calls. If resumehandle
+ is NULL, then no resume handle is stored..
+
+Return Value:
+
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+
+ //
+ // check the caller's parameters
+ //
+
+ *totalentries = *entriesread = 0;
+ *bufptr = NULL;
+
+ if ( (level > 2) && (level != 502) ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrShareEnumSticky (
+ servername,
+ (LPSHARE_ENUM_STRUCT) &infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel support
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareEnumSticky
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareGetInfo (
+ IN LPTSTR servername,
+ IN LPTSTR netname,
+ IN DWORD level,
+ OUT LPBYTE *bufptr
+ )
+/*++
+
+Routine Description:
+
+ NetShareGetInfo
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ netname --A pointer to an ASCIIZ string containing the netname of
+ the share to return information on.
+
+ level --Level of information required. 0, 1 and 2 are valid.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ *bufptr = NULL; // Must be NULL so RPC knows to till it in.
+
+ if ( (level > 2) && (level != 502) && (level != 1005)) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ if (!(netname && *netname)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrShareGetInfo (
+ servername,
+ netname,
+ level,
+ (LPSHARE_INFO) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareGetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel server.
+ //
+
+ if ( level != 502 && level != 1005 ) {
+ apiStatus = RxNetShareGetInfo(servername, netname, level, bufptr);
+ } else {
+ apiStatus = ERROR_NOT_SUPPORTED;
+ }
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetShareSetInfo (
+ IN LPTSTR servername,
+ IN LPTSTR netname,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetShareSetInfo
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ netname --A pointer to an ASCIIZ string containing the netname of
+ the share to set information on.
+
+ level --Level of information to set.
+
+ buf --A pointer to a buffer containing the share information. If
+ parmnum is non zero then the buffer contains only the
+ appropriate data for the specific element.
+
+ parm_err --Optional pointer to a DWORD to return the index of the
+ first parameter in error when ERROR_INVALID_PARAMETER is
+ returned. If NULL the parameter is not returned on error.
+
+Return Value:
+
+--*/
+
+{
+
+ NET_API_STATUS apiStatus;
+ NTSTATUS status;
+ ULONG sdLength = 0;
+ ULONG oldSdLength;
+ PSECURITY_DESCRIPTOR securityDescriptor = NULL;
+ PSECURITY_DESCRIPTOR oldSecurityDescriptor = NULL;
+ LPSHARE_INFO_1501 shi1501 = NULL;
+
+ NET_REMOTE_TRY_RPC
+
+ //
+ // If the info level can change the security descriptor, get
+ // the necessary information.
+ //
+ // *** Note that this code expects the layout of the reserved
+ // and security_descriptor fields in the 502 struct to
+ // match the 1501 struct.
+ //
+
+ if ( level == 502 ) {
+
+ shi1501 =
+ (LPSHARE_INFO_1501)&((LPSHARE_INFO_502)buf)->shi502_reserved;
+
+ } else if ( level == SHARE_FILE_SD_INFOLEVEL ) {
+
+ shi1501 = (LPSHARE_INFO_1501)buf;
+
+ }
+
+ if ( shi1501 != NULL ) {
+
+ oldSdLength = shi1501->shi1501_reserved;
+ oldSecurityDescriptor = shi1501->shi1501_security_descriptor;
+
+ if ( oldSecurityDescriptor != NULL ) {
+
+ //
+ // Make a self relative security descriptor for use in the
+ // RPC call.
+ //
+
+ if ( !RtlValidSecurityDescriptor( oldSecurityDescriptor) ) {
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ status = RtlMakeSelfRelativeSD(
+ oldSecurityDescriptor,
+ NULL,
+ &sdLength
+ );
+
+ if ( status != STATUS_BUFFER_TOO_SMALL ) {
+
+ return ERROR_INVALID_PARAMETER;
+
+ } else {
+
+ securityDescriptor = MIDL_user_allocate( sdLength );
+
+ if ( securityDescriptor == NULL) {
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ } else {
+
+ //
+ // Make an appropriate self-relative security
+ // descriptor.
+ //
+
+ status = RtlMakeSelfRelativeSD(
+ oldSecurityDescriptor,
+ securityDescriptor,
+ &sdLength
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ MIDL_user_free( securityDescriptor );
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ shi1501->shi1501_reserved = sdLength;
+ shi1501->shi1501_security_descriptor =
+ securityDescriptor;
+
+ }
+
+ }
+
+ } else {
+
+ shi1501->shi1501_reserved = 0;
+
+ }
+ }
+
+ apiStatus = NetrShareSetInfo(
+ servername,
+ netname,
+ level,
+ (LPSHARE_INFO) &buf,
+ parm_err);
+
+ if ( shi1501 != NULL ) {
+
+ //
+ // restore old values
+ //
+
+ shi1501->shi1501_reserved = oldSdLength;
+ shi1501->shi1501_security_descriptor = oldSecurityDescriptor;
+
+ MIDL_user_free( securityDescriptor );
+
+ }
+
+
+ NET_REMOTE_RPC_FAILED(
+ "NetShareSetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel server.
+ //
+
+ if ( (level != 502) && (level != SHARE_FILE_SD_INFOLEVEL) && (level != 1005 ) ) {
+
+ apiStatus = RxNetShareSetInfo(
+ servername,
+ netname,
+ level,
+ buf,
+ parm_err);
+ } else {
+ apiStatus = ERROR_NOT_SUPPORTED;
+ }
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetShareSetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerDiskEnum (
+ IN LPTSTR servername,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerDiskEnum.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information required. 0 is the only valid level.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+ prefmaxlen --Prefered maximum length of returned data (in 8-bit
+ bytes). 0xffffffff specifies no limit.
+
+ entriesread --On return the actual enumerated element count is
+ located in the DWORD pointed to by entriesread.
+
+ totalentries --On return the total entries available to be
+ enumerated is located in the DWORD pointed to by totalentries
+
+ resumehandle --On return, a resume handle is stored in the DWORD
+ pointed to by resumehandle, and is used to continue an
+ existing server disk search. The handle should be zero on the
+ first call and left unchanged for subsequent calls. If
+ resumehandle is NULL, then no resume handle is stored..
+
+Return Value:
+
+--*/
+{
+ NET_API_STATUS apiStatus;
+ DISK_ENUM_CONTAINER diskEnumContainer;
+
+
+ diskEnumContainer.Buffer = NULL;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerDiskEnum (
+ servername,
+ level,
+ &diskEnumContainer,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (diskEnumContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)diskEnumContainer.Buffer;
+ } else {
+ *bufptr = NULL;
+ }
+
+ if (diskEnumContainer.EntriesRead > 0) {
+
+ //
+ // We must subtract out the extra count that we added so
+ // that RPC would buffer the extra NUL at the end of the list.
+ //
+
+ *entriesread = diskEnumContainer.EntriesRead - 1;
+
+ } else {
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerDiskEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel version of the API.
+ //
+
+ apiStatus = RxNetServerDiskEnum(
+ servername,
+ level,
+ bufptr,
+ prefmaxlen,
+ entriesread,
+ totalentries,
+ resume_handle);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerDiskEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerGetInfo (
+ IN LPTSTR servername,
+ IN DWORD level,
+ OUT LPBYTE *bufptr
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerGetInfo
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information required. 100, 101 and 102 are valid
+ for all platforms. 302, 402, 403, 502 are valid for the
+ appropriate platform.
+
+ bufptr --On return a pointer to the return information structure
+ is returned in the address pointed to by bufptr.
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ *bufptr = NULL; // Must be NULL so RPC knows to fill it in.
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerGetInfo (
+ servername,
+ level,
+ (LPSERVER_INFO) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerGetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel version of the API.
+ //
+ apiStatus = RxNetServerGetInfo (
+ servername,
+ level,
+ bufptr);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerSetInfo (
+ IN LPTSTR servername,
+ IN DWORD level,
+ IN LPBYTE buf,
+ OUT LPDWORD parm_err
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerSetInfo.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ level --Level of information to set.
+
+ buf --A pointer to a buffer containing the server information. If
+ parmnum is non zero then the buffer contains only the
+ appropriate data for the specific element.
+
+ parm_err --Optional pointer to a DWORD to return the index of the
+ first parameter in error when ERROR_INVALID_PARAMETER is
+ returned. If NULL the parameter is not returned on error.
+
+Return Value:
+
+--*/
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerSetInfo (
+ servername,
+ level,
+ (LPSERVER_INFO ) &buf,
+ parm_err);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerSetInfo",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // Call downlevel server.
+ //
+
+ apiStatus = RxNetServerSetInfo(
+ servername,
+ level,
+ buf,
+ parm_err);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerSetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerStatisticsGet (
+ IN LPTSTR servername,
+ IN DWORD level,
+ IN DWORD options,
+ OUT LPBYTE *bufptr
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetStatisticsGet.
+
+Arguments:
+
+ servername --Points to an ASCIIZ string that contains the name of the
+ server on which to execute NetStatisticsGet. A NULL pointer or
+ NULL string specifies the local computer.
+
+ level --Specifies the level of detail requested; must be 0.
+
+ options --Specifies the options flags.
+
+ Bit(s) Meaning
+ 0 Clear statistics.
+ 1-31 Reserved; must be 0.
+
+ bufptr --On return a pointer to the returned information is
+ returned in the address pointed to by bufptr.
+
+Return Value:
+
+--*/
+{
+ NET_API_STATUS apiStatus;
+
+ *bufptr = NULL; // Must be NULL so RPC knows to fill it in.
+
+ NET_REMOTE_TRY_RPC
+
+ //
+ // BUGBUG - at some point, remove this redundant service name parameter
+ // - this will change MIDL interface
+ //
+
+ apiStatus = NetrServerStatisticsGet (
+ servername,
+ SERVICE_SERVER,
+ level,
+ options,
+ (LPSTAT_SERVER_0 *) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerStatisticsGet",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetStatisticsGet(
+ servername,
+ SERVICE_SERVER,
+ level,
+ options,
+ bufptr
+ );
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerStatisticsGet
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerTransportAdd (
+ IN LPTSTR servername,
+ IN DWORD level,
+ IN LPBYTE bufptr
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerTransportAdd
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerTransportAdd (
+ servername,
+ level,
+ (LPSERVER_TRANSPORT_INFO_0) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerTransportAdd",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerTransportAdd
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerTransportDel (
+ IN LPTSTR servername,
+ IN DWORD level,
+ IN LPBYTE bufptr
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerTransportAdd
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerTransportDel (
+ servername,
+ level,
+ (LPSERVER_TRANSPORT_INFO_0) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerTransportDel",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerTransportDel
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerTransportEnum (
+ IN LPTSTR servername,
+ IN DWORD level,
+ OUT LPBYTE *bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD entriesread,
+ OUT LPDWORD totalentries,
+ IN OUT LPDWORD resume_handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerTransportEnum
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ GENERIC_INFO_CONTAINER genericInfoContainer;
+ GENERIC_ENUM_STRUCT infoStruct;
+
+ genericInfoContainer.Buffer = NULL;
+ genericInfoContainer.EntriesRead = 0;
+
+ infoStruct.Container = &genericInfoContainer;
+ infoStruct.Level = level;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerTransportEnum (
+ servername,
+ (LPSERVER_XPORT_ENUM_STRUCT) &infoStruct,
+ prefmaxlen,
+ totalentries,
+ resume_handle);
+
+ if (genericInfoContainer.Buffer != NULL) {
+ *bufptr = (LPBYTE)genericInfoContainer.Buffer;
+ *entriesread = genericInfoContainer.EntriesRead;
+ } else {
+ *bufptr = NULL;
+ *entriesread = 0;
+ }
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerTransportEnum",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // NetServerTransportEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetRemoteTOD (
+ IN LPCWSTR servername,
+ OUT LPBYTE *bufptr
+ )
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetRemoteTOD
+
+Arguments:
+
+ servername - name of the server on which the API so to be executed.
+ bufptr - the location where the address of the buffer allocated
+ for the time-of-day information is placed.
+
+Return Value:
+
+ NERR_SUCCESS if there was no error. Otherwise, the error code is
+ returned.
+
+
+--*/
+{
+ NET_API_STATUS apiStatus;
+
+ //
+ // Call API
+ //
+ *bufptr = NULL; // Must be NULL so RPC knows to fill it in.
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrRemoteTOD (
+ (LPWSTR)servername,
+ (TIME_OF_DAY_INFO **) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetRemoteTOD",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_TIMESOURCE )
+
+ apiStatus = RxNetRemoteTOD (
+ (LPWSTR)servername,
+ (LPBYTE *) bufptr);
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+}
+
+
+NET_API_STATUS
+I_NetServerSetServiceBitsEx (
+ IN LPWSTR ServerName,
+ IN LPWSTR EmulatedServerName OPTIONAL,
+ IN LPTSTR TransportName OPTIONAL,
+ IN DWORD ServiceBitsOfInterest,
+ IN DWORD ServiceBits,
+ IN DWORD UpdateImmediately
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for I_NetServerSetServiceBitsEx. This
+ routine sets the value of the Server Type as sent in server
+ announcement messages. It is an internal API used only by the
+ service controller.
+
+Arguments:
+
+ ServerName - Used by RPC to direct the call. This API may only be
+ issued locally. This is enforced by the client stub.
+
+ EmulatedServerName - the name server using for accepting connections
+ on the network and for announcements. If null, use the priamary
+ server name.
+
+ TransportName - the name of one of the transports the server is bound
+ on. If null, set the bits for all the transports.
+
+ ServiceBitsOfInterest - a mask indicating which bits are significant
+ in 'ServiceBits'
+
+ ServiceBits - Bits (preassigned to various components by Microsoft)
+ indicating which services are active. This field is not
+ interpreted by the server service.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or ERROR_NOT_SUPPORTED.
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ DWORD localOrRemote;
+
+ //
+ // Don't let this API go remote.
+ //
+
+ if ((ServerName != NULL) && (*ServerName != '\0')) {
+ apiStatus = NetpIsRemote(ServerName, &localOrRemote, NULL, 0);
+ if (apiStatus != NERR_Success) {
+ return apiStatus;
+ }
+ if (localOrRemote == ISREMOTE) {
+ return ERROR_NOT_SUPPORTED;
+ }
+ }
+
+ //
+ // Do the call.
+ //
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = I_NetrServerSetServiceBitsEx (
+ ServerName,
+ EmulatedServerName,
+ TransportName,
+ ServiceBitsOfInterest,
+ ServiceBits,
+ UpdateImmediately);
+
+ NET_REMOTE_RPC_FAILED(
+ "I_NetServerSetServiceBitsEx",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // I_NetServerSetServiceBitsEx
+
+NET_API_STATUS
+I_NetServerSetServiceBits (
+ IN LPTSTR servername,
+ IN LPTSTR transportname,
+ IN DWORD servicebits,
+ IN DWORD updateimmediately
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for I_NetServerSetServiceBits. This
+ routine sets the value of the Server Type as sent in server
+ announcement messages. It is an internal API used only by the
+ service controller.
+
+Arguments:
+
+ ServerName - Used by RPC to direct the call. This API may only be
+ issued locally. This is enforced by the client stub.
+
+ ServiceBits - Bits (preassigned to various components by Microsoft)
+ indicating which services are active. This field is not
+ interpreted by the server service.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or ERROR_NOT_SUPPORTED.
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+ DWORD localOrRemote;
+
+ //
+ // Don't let this API go remote.
+ //
+
+ if ((servername != NULL) && (*servername != '\0')) {
+ apiStatus = NetpIsRemote(servername, &localOrRemote, NULL, 0);
+ if (apiStatus != NERR_Success) {
+ return apiStatus;
+ }
+ if (localOrRemote == ISREMOTE) {
+ return ERROR_NOT_SUPPORTED;
+ }
+ }
+
+ //
+ // Do the call.
+ //
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = I_NetrServerSetServiceBits (
+ servername,
+ transportname,
+ servicebits,
+ updateimmediately);
+
+ NET_REMOTE_RPC_FAILED(
+ "I_NetServerSetServiceBits",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ return(apiStatus);
+
+} // I_NetServerSetServiceBits
+//
+// Netps canonicalization functions. These are essentially private functions
+// and are called from the API stubs in canonapi.c. The canonicalization
+// functions have to be usable locally without going via the server service
+// hence they live in NETAPI.DLL, but call local functions in NETLIB if the
+// ServerName parameter is NULL (or designates the local machine). If the
+// ServerName parameter is not NULL and designates a remote computer then the
+// RPC function (here) will be called, hence the remote server must be
+// running in order to make remote canonicalization requests
+//
+
+NET_API_STATUS
+NET_API_FUNCTION
+NetpsNameCanonicalize(
+ IN LPTSTR ServerName,
+ IN LPTSTR Name,
+ OUT LPTSTR Outbuf,
+ IN DWORD OutbufLen,
+ IN DWORD NameType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Canonicalizes a name
+
+Arguments:
+
+ ServerName - where to run this API
+ Name - name to canonicalize
+ Outbuf - where to put canonicalized name
+ OutbufLen - length of Outbuf
+ NameType - type of name to canonicalize
+ Flags - control flags
+
+Return Value:
+
+ NET_API_STATUS
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetprNameCanonicalize(ServerName,
+ Name,
+ Outbuf,
+ OutbufLen,
+ NameType,
+ Flags
+ );
+
+ NET_REMOTE_RPC_FAILED("NetpsNameCanonicalize",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetpNameCanonicalize(ServerName,
+ Name,
+ Outbuf,
+ OutbufLen,
+ NameType,
+ Flags
+ );
+
+ NET_REMOTE_END
+
+ return apiStatus;
+}
+
+LONG
+NET_API_FUNCTION
+NetpsNameCompare(
+ IN LPTSTR ServerName,
+ IN LPTSTR Name1,
+ IN LPTSTR Name2,
+ IN DWORD NameType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Compares two names. Must be of same type
+
+Arguments:
+
+ ServerName - where to run this API
+ Name1 - 1st name to compare
+ Name2 - 2nd
+ NameType - type of names
+ Flags - control flags
+
+Return Value:
+
+ LONG
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetprNameCompare(ServerName, Name1, Name2, NameType, Flags);
+
+ NET_REMOTE_RPC_FAILED("NetpsNameCompare",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetpNameCompare(ServerName, Name1, Name2, NameType, Flags);
+
+ NET_REMOTE_END
+
+ return apiStatus;
+}
+
+NET_API_STATUS
+NET_API_FUNCTION
+NetpsNameValidate(
+ IN LPTSTR ServerName,
+ IN LPTSTR Name,
+ IN DWORD NameType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a name - checks whether a name of a certain type conforms to
+ canonicalization rules for that name type. Canonicalization rules mean
+ character set, name syntax and length
+
+Arguments:
+
+ ServerName - where to perform this function
+ Name - name to validate
+ NameType - what type of name it is
+ Flags - MBZ
+
+Return Value:
+
+ NET_API_STATUS
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetprNameValidate(ServerName, Name, NameType, Flags);
+
+ NET_REMOTE_RPC_FAILED("NetpsNameValidate",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetpNameValidate(ServerName, Name, NameType, Flags);
+
+ NET_REMOTE_END
+
+ return apiStatus;
+}
+
+NET_API_STATUS
+NET_API_FUNCTION
+NetpsPathCanonicalize(
+ IN LPTSTR ServerName,
+ IN LPTSTR PathName,
+ OUT LPTSTR Outbuf,
+ IN DWORD OutbufLen,
+ IN LPTSTR Prefix OPTIONAL,
+ IN OUT LPDWORD PathType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Canonicalizes a directory path or a device name
+
+Arguments:
+
+ ServerName - where to run this API
+ PathName - path to canonicalize
+ Outbuf - where to write the canonicalized version
+ OutbufLen - length of Outbuf in bytes
+ Prefix - optional prefix which will be prepended to Path
+ PathType - the type of path to canonicalize. May be different at output
+ Flags - control flags
+
+Return Value:
+
+ NET_API_STATUS
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetprPathCanonicalize(ServerName,
+ PathName,
+ (LPBYTE)Outbuf,
+ OutbufLen,
+ Prefix,
+ PathType,
+ Flags
+ );
+
+ NET_REMOTE_RPC_FAILED("NetpsPathCanonicalize",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetpPathCanonicalize(ServerName,
+ PathName,
+ Outbuf,
+ OutbufLen,
+ Prefix,
+ PathType,
+ Flags
+ );
+
+ NET_REMOTE_END
+
+ return apiStatus;
+}
+
+LONG
+NET_API_FUNCTION
+NetpsPathCompare(
+ IN LPTSTR ServerName,
+ IN LPTSTR PathName1,
+ IN LPTSTR PathName2,
+ IN DWORD PathType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Compares two paths. The paths are assumed to be of the same type
+
+Arguments:
+
+ ServerName - where to run this API
+ PathName1 - 1st path to compare
+ PathName2 - 2nd
+ PathType - types of paths
+ Flags - control flags
+
+Return Value:
+
+ LONG
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetprPathCompare(ServerName,
+ PathName1,
+ PathName2,
+ PathType,
+ Flags
+ );
+
+ NET_REMOTE_RPC_FAILED("NetpsPathCompare",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetpPathCompare(ServerName,
+ PathName1,
+ PathName2,
+ PathType,
+ Flags
+ );
+
+ NET_REMOTE_END
+
+ return apiStatus;
+}
+
+NET_API_STATUS
+NET_API_FUNCTION
+NetpsPathType(
+ IN LPTSTR ServerName,
+ IN LPTSTR PathName,
+ OUT LPDWORD PathType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Determines the type of a path
+
+Arguments:
+
+ ServerName - where to run this API
+ PathName - to find type of
+ PathType - returned path type
+ Flags - control flags
+
+Return Value:
+
+ NET_API_STATUS
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetprPathType(ServerName, PathName, PathType, Flags);
+
+ NET_REMOTE_RPC_FAILED("NetpsPathType",
+ ServerName,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // RPC call didn't work - try down-level routine
+ //
+
+ apiStatus = RxNetpPathType(ServerName, PathName, PathType, Flags);
+
+ NET_REMOTE_END
+
+ return apiStatus;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerTransportAddEx (
+ IN LPTSTR servername,
+ IN DWORD level,
+ IN LPBYTE bufptr
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerTransportAddEx. It functions
+ just like NetServerTransportAdd, but it supports level 1 as well as 0
+
+--*/
+
+{
+ NET_API_STATUS apiStatus;
+
+ NET_REMOTE_TRY_RPC
+
+ apiStatus = NetrServerTransportAddEx (
+ servername,
+ level,
+ (LPTRANSPORT_INFO) bufptr);
+
+ NET_REMOTE_RPC_FAILED(
+ "NetServerTransportAddEx",
+ servername,
+ apiStatus,
+ NET_REMOTE_FLAG_NORMAL,
+ SERVICE_SERVER)
+
+ //
+ // No downlevel call.
+ //
+
+ apiStatus = ERROR_NOT_SUPPORTED;
+
+ NET_REMOTE_END
+
+ if( apiStatus == RPC_NT_PROCNUM_OUT_OF_RANGE ) {
+ apiStatus = NERR_InvalidAPI;
+ }
+
+ return(apiStatus);
+
+} // NetServerTransportAddEx
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerComputerNameAdd(
+ IN LPWSTR ServerName OPTIONAL,
+ IN LPWSTR EmulatedDomainName OPTIONAL,
+ IN LPWSTR EmulatedServerName
+)
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerComputerNameAdd. This api
+ causes 'ServerName' to respond to requests for 'EmulatedServerName'.
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ EmulatedServerName --A pointer to the ASCIIZ string containing the
+ name which the server should stop supporting
+
+ EmulatedDomainName --A pointer to the ASCIIZ string containing the
+ domain name the server should use when announcing the presence of
+ 'EmulatedServerName'
+
+Return Value:
+
+ NERR_Success, or reason for failure
+
+--*/
+{
+ DWORD resumehandle = 0;
+ NET_API_STATUS retval;
+ DWORD entriesread, totalentries;
+ DWORD i, j;
+ BOOLEAN AddedOne = FALSE;
+ UCHAR NetBiosName[ MAX_PATH ];
+ OEM_STRING NetBiosNameString;
+ UNICODE_STRING UniName;
+
+ //
+ // Ensure a valid EmulatedServerName was passed in
+ //
+ if( EmulatedServerName == NULL ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the EmulatedServerName to an OEM string
+ //
+ RtlInitUnicodeString( &UniName, EmulatedServerName );
+ NetBiosNameString.Buffer = (PCHAR)NetBiosName;
+ NetBiosNameString.MaximumLength = sizeof( NetBiosName );
+ (VOID) RtlUpcaseUnicodeStringToOemString(
+ &NetBiosNameString,
+ &UniName,
+ FALSE
+ );
+
+ if( ARGUMENT_PRESENT( EmulatedDomainName ) ) {
+
+ //
+ // The caller wants to set a new computer name and domain name to the
+ // server. This requires level 1, which is new in 4.0
+ //
+ PSERVER_TRANSPORT_INFO_1 psti1;
+
+ //
+ // Enumerate all the transports so we can add the name and domain
+ // to each one.
+ //
+ retval = NetServerTransportEnum ( ServerName,
+ 1,
+ (LPBYTE *)&psti1,
+ (DWORD)-1,
+ &entriesread,
+ &totalentries,
+ &resumehandle );
+ if( retval == NERR_Success ) {
+ //
+ // Add the new name and domain to all of the transports
+ //
+ for( i=0; i < entriesread; i++ ) {
+
+ //
+ // Make sure we haven't already added to this transport
+ //
+ for( j = 0; j < i; j++ ) {
+ if( wcscmp( psti1[j].svti1_transportname, psti1[i].svti1_transportname ) == 0 )
+ break;
+ }
+
+ if( i != j )
+ continue;
+
+ psti1[i].svti1_transportaddress = NetBiosName;
+ psti1[i].svti1_transportaddresslength = strlen( NetBiosName );
+ psti1[i].svti1_domain = EmulatedDomainName;
+
+ retval = NetServerTransportAddEx( ServerName, 1, (LPBYTE)&psti1[ i ] );
+
+ if( retval == NERR_Success ) {
+ AddedOne = TRUE;
+ }
+ }
+
+ MIDL_user_free( psti1 );
+ }
+
+
+ } else {
+
+ //
+ // The caller just wants to set an alternate server name. Use level 0,
+ // since 3.51 servers support level 0
+ //
+ PSERVER_TRANSPORT_INFO_0 psti0;
+
+ //
+ // Enumerate all the transports so we can add the name and domain
+ // to each one.
+ //
+ retval = NetServerTransportEnum ( ServerName,
+ 0,
+ (LPBYTE *)&psti0,
+ (DWORD)-1,
+ &entriesread,
+ &totalentries,
+ &resumehandle );
+ if( retval == NERR_Success ) {
+ //
+ // Add the new name to all of the transports
+ //
+ for( i=0; i < entriesread; i++ ) {
+
+ //
+ // Make sure we haven't already added to this transport
+ //
+ for( j = 0; j < i; j++ ) {
+ if( wcscmp( psti0[j].svti0_transportname, psti0[i].svti0_transportname ) == 0 )
+ break;
+ }
+
+ if( i != j )
+ continue;
+
+ psti0[i].svti0_transportaddress = NetBiosName;
+ psti0[i].svti0_transportaddresslength = strlen( NetBiosName );
+
+ retval = NetServerTransportAdd( ServerName, 0, (LPBYTE)&psti0[ i ] );
+
+ if( retval == NERR_Success ) {
+ AddedOne = TRUE;
+ }
+ }
+
+ MIDL_user_free( psti0 );
+ }
+ }
+
+ return AddedOne ? NERR_Success : retval;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetServerComputerNameDel (
+ IN LPWSTR ServerName OPTIONAL,
+ IN LPWSTR EmulatedServerName
+)
+/*++
+
+Routine Description:
+
+ This is the DLL entrypoint for NetServerComputerNameDel. This api
+ causes 'ServerName' to cease responding to requests for 'EmulatedServerName'
+
+Arguments:
+
+ servername --A pointer to an ASCIIZ string containing the name of
+ the remote server on which the function is to execute. A NULL
+ pointer or string specifies the local machine.
+
+ EmulatedServerName --A pointer to the ASCIIZ string containing the
+ name which the server should stop supporting
+
+Return Value:
+
+ NERR_Success, or reason for failure
+
+--*/
+{
+ DWORD resumehandle = 0;
+ NET_API_STATUS retval, tmpretval;
+ DWORD entriesread, totalentries;
+ DWORD i;
+ UCHAR NetBiosName[MAX_PATH];
+ OEM_STRING NetBiosNameString;
+ UNICODE_STRING UniName;
+ PSERVER_TRANSPORT_INFO_0 psti0;
+ BOOLEAN nameFound = FALSE;
+
+ //
+ // Ensure a valid EmulatedServerName was passed in
+ //
+ if( EmulatedServerName == NULL ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the EmulatedServerName to an OEM string
+ //
+ RtlInitUnicodeString( &UniName, EmulatedServerName );
+ NetBiosNameString.Buffer = (PCHAR)NetBiosName;
+ NetBiosNameString.MaximumLength = sizeof( NetBiosName );
+ (VOID) RtlUpcaseUnicodeStringToOemString(
+ &NetBiosNameString,
+ &UniName,
+ FALSE
+ );
+
+ //
+ // Enumerate all the transports so we can delete the name from each one
+ //
+ retval = NetServerTransportEnum ( ServerName,
+ 0,
+ (LPBYTE *)&psti0,
+ (DWORD)-1,
+ &entriesread,
+ &totalentries,
+ &resumehandle );
+ if( retval != NERR_Success ) {
+ return retval;
+ }
+
+ if( entriesread == 0 ) {
+ return ERROR_BAD_NET_NAME;
+ }
+
+ //
+ // Delete the name from all of the transports
+ //
+ for( i=0; i < entriesread; i++ ) {
+
+ if( psti0[i].svti0_transportaddresslength != NetBiosNameString.Length ) {
+ continue;
+ }
+
+ if( RtlCompareMemory( psti0[i].svti0_transportaddress,
+ NetBiosName,
+ NetBiosNameString.Length) != NetBiosNameString.Length ) {
+ continue;
+ }
+
+ nameFound = TRUE;
+
+ tmpretval = NetServerTransportDel( ServerName, 0, (LPBYTE)&psti0[ i ] );
+
+ if( tmpretval != NERR_Success && retval == NERR_Success ) {
+ retval = tmpretval;
+ }
+ }
+
+ MIDL_user_free( psti0 );
+
+ return nameFound == TRUE ? retval : ERROR_BAD_NET_NAME;
+}
diff --git a/private/net/svcdlls/srvsvc/client/tsrvsvc.c b/private/net/svcdlls/srvsvc/client/tsrvsvc.c
new file mode 100644
index 000000000..0eb7715aa
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/client/tsrvsvc.c
@@ -0,0 +1,90 @@
+#include <windows.h>
+#include <lmcons.h>
+#include <lmerr.h>
+#include <lmshare.h>
+#include <lmserver.h>
+
+int
+main (
+ int argc,
+ char *argv[]
+ )
+{
+ LPBYTE buffer;
+ DWORD entries;
+ DWORD totalEntries;
+ NET_API_STATUS status;
+
+#if 0
+ status = I_NetServerSetServiceBits( NULL, 0x5555AAAA );
+
+ if ( status != NERR_Success ) {
+
+ printf( "I_NetServerSetServiceBits failed: %ld\n", status );
+
+ }
+#endif
+
+#if 0
+ status = NetServerDiskEnum(
+ NULL,
+ 0,
+ &buffer,
+ -1,
+ &entries,
+ &totalEntries,
+ NULL
+ );
+
+ if ( status != NERR_Success ) {
+
+ printf( "NetServerDiskEnum failed: %ld\n", status );
+
+ } else {
+
+ PSZ p = buffer;
+ DWORD i = 0;
+
+ while ( *p != 0 ) {
+ printf( "Disk %ld is %s\n", i, p );
+ while ( *(++p) != 0 ) ;
+ p++;
+ i++;
+ }
+
+ if ( i != entries ) {
+ printf( "Incorrect entry count returned: %ld\n", entries );
+ }
+
+ }
+
+ return status;
+#endif
+
+#if 1
+ status = NetShareEnum(
+ "",
+ 0,
+ &buffer,
+ 8192,
+ &entries,
+ &totalEntries,
+ NULL
+ );
+
+ if ( status != NERR_Success ) {
+
+ printf( "NetShareEnum failed: %ld\n", status );
+
+ } else {
+
+ printf( "NetShareEnum worked.\n" );
+ printf( " entries = %ld, totalEntries = %ld\n",
+ entries, totalEntries );
+
+ }
+
+ return status;
+#endif
+
+} // main
diff --git a/private/net/svcdlls/srvsvc/dirs b/private/net/svcdlls/srvsvc/dirs
new file mode 100644
index 000000000..87ef360df
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/dirs
@@ -0,0 +1,30 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+
+DIRS=lib \
+ server \
+ client
+
+
+#OPTIONAL_DIRS=dir8 \
+# dir9
diff --git a/private/net/svcdlls/srvsvc/import.h b/private/net/svcdlls/srvsvc/import.h
new file mode 100644
index 000000000..1610997c6
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/import.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ import.h
+
+Abstract:
+
+ This file allows us to include standard system header files in the
+ .idl file. The main .idl file imports a file called import.idl.
+ This allows the .idl file to use the types defined in these header
+ files. It also causes the following line to be added in the
+ MIDL generated header file:
+
+ #include "import.h"
+
+ Thus these types are available to the RPC stub routines as well.
+
+Author:
+
+ Dan Lafferty (danl) 07-May-1991
+
+Revision History:
+
+
+--*/
+
+//#include <windef.h>
+#include <nt.h>
+#include <ntrtl.h>
+
+// #include <rpc.h>
+#include <windef.h>
+#include <winerror.h>
+
+#include <lmcons.h>
+
+#ifdef MIDL_PASS
+#ifdef UNICODE
+#define LPTSTR [string] wchar_t*
+#else
+#define LPTSTR [string] LPTSTR
+#endif
+#define LPSTR [string] LPSTR
+#define BOOL DWORD
+#endif
+
+#include <lmchdev.h>
+#include <lmremutl.h>
+#include <lmserver.h>
+#include <lmshare.h>
+#include <lmstats.h>
+#include <dfspriv.h>
diff --git a/private/net/svcdlls/srvsvc/import.idl b/private/net/svcdlls/srvsvc/import.idl
new file mode 100644
index 000000000..c032eb6fe
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/import.idl
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ import.idl
+
+Abstract:
+
+ This file is useful for creating RPC interfaces that require the use
+ of windef types. The .idl file for the RPC product should contain a
+ line in the interface body that imports this file. For example:
+
+ import "import.h";
+
+ Doing this causes the MIDL generated header file to contain the
+ following line:
+
+ #include "import.h"
+
+ If this technique is not used, and instead the .idl file for the RPC
+ product simply contains #include <import.h>, then the contents of
+ import.h will be expanded in the MIDL generated header file. This
+ can lead to duplicate definition problems later when the RPC client
+ or RPC server code needs to include both the MIDL generated header file
+ and a file that is included in import.h.
+
+Author:
+
+ Dan Lafferty (danl) 20-Mar-1991
+
+Environment:
+
+ User Mode - Win32 - for use with the MIDL compiler
+
+
+Revision History:
+
+ 03-Apr-1991 danl
+ created
+
+--*/
+
+[
+ uuid(12345678-1234-ABCD-EF00-9948756789AB),
+#ifdef __midl
+ ms_union,
+#endif // __midl
+ version(1.0)
+]
+interface imports
+
+{
+#define MIDL_PASS
+#include "import.h"
+
+}
diff --git a/private/net/svcdlls/srvsvc/lib/adtcomn.c b/private/net/svcdlls/srvsvc/lib/adtcomn.c
new file mode 100644
index 000000000..730c55b10
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/lib/adtcomn.c
@@ -0,0 +1,216 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ adtcomn.c
+
+Abstract:
+
+ AdminTools common Routines.
+
+ This file contains the calls to GetFileSecurity and
+ SetFileSecurity that is used on both the client and server
+ sides of this RPC server.
+
+Author:
+
+ Dan Lafferty (danl) 23-Mar-1993
+
+Environment:
+
+ User Mode - Win32
+
+
+Revision History:
+
+ 23-Mar-1993 danl
+ Created
+
+--*/
+
+//
+// Includes
+//
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <lmcons.h>
+#include <lmerr.h>
+
+#include <rpc.h>
+#include <srvsvc.h>
+#include <netlibnt.h> // NetpNtStatusToApiStatus
+
+#include "adtcomn.h"
+
+//
+// LOCAL FUNCTIONS
+//
+
+
+DWORD
+PrivateGetFileSecurity (
+ LPWSTR FileName,
+ SECURITY_INFORMATION RequestedInfo,
+ PSECURITY_DESCRIPTOR *pSDBuffer,
+ LPDWORD pBufSize
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns to the caller a copy of the security descriptor
+ protecting a file or directory. It calls GetFileSecurity. The
+ Security Descriptor is always returned in the self-relative format.
+
+ NOTE: This function allocates storage for the pSDBuffer. Therefore,
+ this pointer must be free'd by the caller.
+
+Arguments:
+
+ FileName - A pointer to the name fo the file or directory whose
+ security is being retrieved.
+
+ RequestedInfo - The type of security information being requested.
+
+ pSDBuffer - A pointer to a location where a pointer for the
+ security descriptor and a length field for the security descriptor.
+
+ pBufSize - A pointer to the location where the size, in bytes, of
+ the returned security descriptor is to be placed.
+
+
+Return Value:
+
+ NERR_Success - The operation was successful.
+
+ ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the security
+ descriptor.
+
+ This function can also return any error that GetFileSecurity can
+ return.
+
+
+--*/
+{
+
+ NET_API_STATUS status;
+ DWORD sizeNeeded;
+
+ *pSDBuffer = NULL;
+ //
+ // Determine the buffer size for the Descriptor
+ //
+ if (GetFileSecurityW(
+ FileName, // File whose security is being retrieved
+ RequestedInfo, // security info being requested
+ *pSDBuffer, // buffer to receive security descriptor
+ 0, // size of the buffer
+ &sizeNeeded)) { // size of buffer required
+
+ //
+ // We should have a failed due to a buffer size being too small.
+ //
+ status = ERROR_INVALID_PARAMETER;
+ goto CleanExit;
+ }
+
+ status = GetLastError();
+
+ if ((status == ERROR_INSUFFICIENT_BUFFER) && (sizeNeeded > 0)) {
+
+ *pSDBuffer = MIDL_user_allocate(sizeNeeded);
+
+ if (pSDBuffer == NULL) {
+ status = GetLastError();
+ ADT_LOG1(ERROR,"NetrpGetFileSecurity:MIDL_user_alloc1 failed %d\n",status);
+ goto CleanExit;
+ }
+ *pBufSize = sizeNeeded;
+
+ if (!GetFileSecurityW(
+ FileName, // File whose security is being retrieved
+ RequestedInfo, // security info being requested
+ *pSDBuffer, // buffer to receive security descriptor
+ sizeNeeded, // size of the buffer
+ &sizeNeeded)) { // size of buffer required
+
+ //
+ // The call with the proper buffer size failed.
+ //
+ status = GetLastError();
+ ADT_LOG1(ERROR, "GetFileSecurity Failed %d\n", status);
+ MIDL_user_free(*pSDBuffer);
+ goto CleanExit;
+ }
+
+ ADT_LOG0(TRACE,"NetrpGetFileSecurity:GetFileSecurity Success\n");
+
+ if (!IsValidSecurityDescriptor(*pSDBuffer)) {
+ ADT_LOG0(TRACE,"FAILURE: SECURITY DESCRIPTOR IS INVALID\n");
+ }
+ else {
+ ADT_LOG0(TRACE,"SUCCESS: SECURITY DESCRIPTOR IS GOOD\n");
+ }
+ status = NO_ERROR;
+ }
+
+CleanExit:
+ return(status);
+}
+
+
+DWORD
+PrivateSetFileSecurity (
+ LPWSTR FileName,
+ SECURITY_INFORMATION SecurityInfo,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This function can be used to set the security of a file or directory.
+ It calls SetFileSecurity().
+
+Arguments:
+
+ FileName - A pointer to the name of the file or directory whose
+ security is being changed.
+
+ SecurityInfo - Information describing the contents
+ of the Security Descriptor.
+
+ pSecurityDescriptor - A pointer to a structure that contains a
+ self-relative security descriptor and a length.
+
+Return Value:
+
+ NERR_Success - The operation was successful.
+
+ This function can also return any error that GetFileSecurity can
+ return.
+
+--*/
+{
+ DWORD status=NO_ERROR;
+
+ //
+ // Call SetFileSecurity
+ //
+ if (!SetFileSecurityW (
+ FileName,
+ SecurityInfo,
+ pSecurityDescriptor)) {
+
+ status = GetLastError();
+ return(status);
+ }
+ return(NO_ERROR);
+}
+
diff --git a/private/net/svcdlls/srvsvc/lib/makefile b/private/net/svcdlls/srvsvc/lib/makefile
new file mode 100644
index 000000000..f0db8e4a7
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/lib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS LINE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/net/svcdlls/srvsvc/lib/sources b/private/net/svcdlls/srvsvc/lib/sources
new file mode 100644
index 000000000..d894e1513
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/lib/sources
@@ -0,0 +1,38 @@
+!IF 0
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Dan Lafferty (danl) 13-Jan-1992
+
+
+Revision History:
+
+!ENDIF
+
+MAJORCOMP = srvsvc
+MINORCOMP = srvcomn
+
+
+NTPROFILEINPUT=YES
+
+TARGETNAME=srvcomn
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..;..\..\..\inc;..\..\..\..\inc;
+
+SOURCES= adtcomn.c
diff --git a/private/net/svcdlls/srvsvc/makefil0 b/private/net/svcdlls/srvsvc/makefil0
new file mode 100644
index 000000000..a5182db48
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/makefil0
@@ -0,0 +1,60 @@
+#
+# this is the midl compile phase of the build process.
+#
+# The following is where you put the name of your .idl file without
+# the .idl extension:
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.plt
+
+IDL_NAME = srvsvc
+
+!IFNDEF DISABLE_NET_UNICODE
+UNICODE=1
+NET_C_DEFINES=-DUNICODE
+!ENDIF
+
+SDKINC = $(BASEDIR)\public\sdk\inc
+SDKCRTINC = $(BASEDIR)\public\sdk\inc\crt
+INCS = -I$(SDKINC) -I$(SDKCRTINC) -I..\..\inc -I$(BASEDIR)\private\inc
+
+CPP = -cpp_cmd "$(MIDL_CPP)" $(MIDL_FLAGS) $(C_DEFINES) $(NET_C_DEFINES)
+
+CLIENT_TARGETS = client\$(IDL_NAME)_c.c \
+ .\$(IDL_NAME).h
+
+SERVER_TARGETS = server\$(IDL_NAME)_s.c
+
+EXTRN_DEPENDS = $(SDKINC)\lmcons.h \
+ $(SDKINC)\windef.h \
+ $(SDKINC)\lmchdev.h \
+ $(SDKINC)\lmshare.h \
+ $(SDKINC)\lmserver.h \
+ $(SDKINC)\lmstats.h \
+ $(IDL_NAME).acf
+
+#
+# Define Products and Dependencies
+#
+
+all: $(CLIENT_TARGETS) $(SERVER_TARGETS) $(EXTRN_DEPENDS)
+!IF "$(BUILDMSG)" != ""
+ @ech ; $(BUILDMSG) ;
+!ENDIF
+
+clean: delete_source all
+
+delete_source:
+ erase $(CLIENT_TARGETS) $(SERVER_TARGETS)
+
+#
+# MIDL COMPILE
+#
+
+$(CLIENT_TARGETS) : $(IDL_NAME).idl $(EXTRN_DEPENDS)
+ midl -Oi -server none -oldnames -error allocation -error ref -ms_ext -c_ext $(CPP) $(IDL_NAME).idl $(INCS)
+ IF EXIST $(IDL_NAME)_c.c copy $(IDL_NAME)_c.c .\client & del $(IDL_NAME)_c.c
+
+$(SERVER_TARGETS) : $(IDL_NAME).idl $(EXTRN_DEPENDS)
+ midl -client none -oldnames -error stub_data -error allocation -error ref -ms_ext -c_ext $(CPP) $(IDL_NAME).idl $(INCS)
+ IF EXIST $(IDL_NAME)_s.c copy $(IDL_NAME)_s.c .\server & del $(IDL_NAME)_s.c
diff --git a/private/net/svcdlls/srvsvc/server/adtsrv.c b/private/net/svcdlls/srvsvc/server/adtsrv.c
new file mode 100644
index 000000000..e15205abd
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/adtsrv.c
@@ -0,0 +1,450 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ adtsrv.c
+
+Abstract:
+
+ AdminTools Server functions.
+
+ This file contains the remote interface for NetpGetFileSecurity and
+ NetpSetFileSecurity API.
+
+Author:
+
+ Dan Lafferty (danl) 25-Mar-1993
+
+Environment:
+
+ User Mode - Win32
+
+
+Revision History:
+
+ 27-Oct-1994 IsaacHe
+ Make sure the share permissions allow these operations.
+ 05-Sep-1994 Danl
+ Free memory and NULL the pointer to the SecurityDescriptor if
+ a failure occurs. Also free the buffer returned from
+ NetShareGetInfo.
+ 25-Mar-1993 danl
+ Created
+
+--*/
+
+//
+// Includes
+//
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+
+#include <lmerr.h>
+#include <adtcomn.h>
+#include <tstr.h>
+
+//
+// GLOBALS
+//
+ DWORD AdtsvcDebugLevel = DEBUG_ERROR;
+
+//
+// LOCAL FUNCTIONS
+//
+
+NET_API_STATUS
+AdtCheckShareAccessAndGetFullPath(
+ LPWSTR pShare,
+ LPWSTR pFileName,
+ LPWSTR *pPath,
+ ACCESS_MASK DesiredAccess
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrpGetFileSecurity (
+ IN LPWSTR ServerName,
+ IN LPWSTR ShareName,
+ IN LPWSTR FileName,
+ IN SECURITY_INFORMATION RequestedInfo,
+ OUT PADT_SECURITY_DESCRIPTOR *pSecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns to the caller a copy of the security descriptor
+ protecting a file or directory. It calls GetFileSecurity. The
+ Security Descriptor is always returned in the self-relative format.
+
+ This function is called only when accessing remote files. In this case,
+ the filename is broken into ServerName, ShareName, and FileName components.
+ The ServerName gets the request to this routine. The ShareName must be
+ expanded to find the local path associated with it. This is combined
+ with the FileName to create a fully qualified pathname that is local
+ to this machine.
+
+Arguments:
+
+ ServerName - A pointer to a string containing the name of the remote
+ server on which the function is to execute. A NULL pointer or
+ string specifies the local machine.
+
+ ShareName - A pointer to a string that identifies the share name
+ on which the file is found.
+
+ FileName - A pointer to the name fo the file or directory whose
+ security is being retrieved.
+
+ RequestedInfo - The type of security information being requested.
+
+ pSecurityDescriptor - A pointer to a pointer to a structure which
+ contains the buffer pointer for the security descriptor and
+ a length field for the security descriptor.
+
+Return Value:
+
+ NERR_Success - The operation was successful.
+
+ ERROR_NOT_ENOUGH_MEMORY - Unable to allocate memory for the security
+ descriptor.
+
+ Other - This function can also return any error that
+ GetFileSecurity,
+ RpcImpersonateClient, or
+ ShareEnumCommon
+ can return.
+
+
+--*/
+{
+ NET_API_STATUS status;
+ PSECURITY_DESCRIPTOR pNewSecurityDescriptor;
+ DWORD bufSize;
+ LPWSTR FullPath=NULL;
+ ACCESS_MASK DesiredAccess = 0;
+
+ *pSecurityDescriptor = MIDL_user_allocate(sizeof(ADT_SECURITY_DESCRIPTOR));
+
+ if (*pSecurityDescriptor == NULL) {
+ ADT_LOG0( ERROR, "NetrpGetFileSecurity:MIDL_user_alloc failed\n" );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Figure out accesses needed to perform the indicated operation(s).
+ // This code is taken from ntos\se\semethod.c
+ //
+ if ((RequestedInfo & OWNER_SECURITY_INFORMATION) ||
+ (RequestedInfo & GROUP_SECURITY_INFORMATION) ||
+ (RequestedInfo & DACL_SECURITY_INFORMATION)) {
+ DesiredAccess |= READ_CONTROL;
+ }
+
+ if ((RequestedInfo & SACL_SECURITY_INFORMATION)) {
+ DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+ }
+
+ //
+ // Check share perms and create a full path string by getting
+ // the path for the share name, and adding the FileName string to it.
+ //
+ status = AdtCheckShareAccessAndGetFullPath(
+ ShareName,
+ FileName,
+ &FullPath,
+ DesiredAccess
+ );
+
+ if( status == NO_ERROR ) {
+ if( (status = RpcImpersonateClient(NULL)) == NO_ERROR ) {
+ //
+ // Get the File Security information
+ //
+ status = PrivateGetFileSecurity(
+ FullPath,
+ RequestedInfo,
+ &pNewSecurityDescriptor,
+ &bufSize);
+
+ if ( status == NO_ERROR ) {
+ (*pSecurityDescriptor)->Length = bufSize;
+ (*pSecurityDescriptor)->Buffer = pNewSecurityDescriptor;
+ }
+
+ (VOID)RpcRevertToSelf();
+ }
+ MIDL_user_free( FullPath );
+ }
+
+ if ( status != NO_ERROR ) {
+ MIDL_user_free(*pSecurityDescriptor);
+ *pSecurityDescriptor = NULL;
+ }
+
+ return status;
+}
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrpSetFileSecurity (
+ IN LPWSTR ServerName OPTIONAL,
+ IN LPWSTR ShareName,
+ IN LPWSTR FileName,
+ IN SECURITY_INFORMATION SecurityInfo,
+ IN PADT_SECURITY_DESCRIPTOR pSecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This function can be used to set the security of a file or directory.
+ It calls SetFileSecurity().
+
+Arguments:
+
+ ServerName - A pointer to a string containing the name of the remote
+ server on which the function is to execute. A NULL pointer or
+ string specifies the local machine.
+
+ ShareName - A pointer to a string that identifies the share name
+ on which the file or directory is found.
+
+ FileName - A pointer to the name of the file or directory whose
+ security is being changed.
+
+ SecurityInfo - Information describing the contents
+ of the Security Descriptor.
+
+ pSecurityDescriptor - A pointer to a structure that contains a
+ self-relative security descriptor and a length.
+
+Return Value:
+
+ NERR_Success - The operation was successful.
+
+ Other - This function can also return any error that
+ SetFileSecurity,
+ RpcImpersonateClient, or
+ ShareEnumCommon
+ can return.
+
+--*/
+{
+ NET_API_STATUS status;
+ LPWSTR FullPath=NULL;
+ ACCESS_MASK DesiredAccess = 0;
+
+ UNREFERENCED_PARAMETER(ServerName);
+
+ //
+ // Figure out accesses needed to perform the indicated operation(s).
+ // This code is taken from ntos\se\semethod.c
+ //
+ if ((SecurityInfo & OWNER_SECURITY_INFORMATION) ||
+ (SecurityInfo & GROUP_SECURITY_INFORMATION) ) {
+ DesiredAccess |= WRITE_OWNER;
+ }
+
+ if (SecurityInfo & DACL_SECURITY_INFORMATION) {
+ DesiredAccess |= WRITE_DAC;
+ }
+
+ if (SecurityInfo & SACL_SECURITY_INFORMATION) {
+ DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+ }
+
+ //
+ // Check perms and create a full path string by getting the path
+ // for the share name, and adding the FileName string to it.
+ //
+ status = AdtCheckShareAccessAndGetFullPath(
+ ShareName,
+ FileName,
+ &FullPath,
+ DesiredAccess
+ );
+
+ if ( status == NO_ERROR ) {
+ if( (status = RpcImpersonateClient(NULL)) == NO_ERROR ) {
+ //
+ // Call SetFileSecurity
+ //
+ status = PrivateSetFileSecurity(
+ FullPath,
+ SecurityInfo,
+ pSecurityDescriptor->Buffer);
+
+ (VOID)RpcRevertToSelf();
+ }
+ MIDL_user_free(FullPath);
+ }
+
+ return(status);
+}
+
+NET_API_STATUS
+AdtCheckShareAccessAndGetFullPath(
+ LPWSTR pShare,
+ LPWSTR pFileName,
+ LPWSTR *pPath,
+ ACCESS_MASK DesiredAccess
+ )
+
+/*++
+
+Routine Description:
+
+ This function ensures the DesiredAccess is allowed and finds the
+ path associated with the share name, combines this with the
+ file name, and creates a fully qualified path name.
+
+ NOTE: This function allocates storage for the pPath string.
+
+Arguments:
+
+ pShare - This is a pointer to the share name string.
+
+ pFileName - This is a pointer to the file name (or path) string.
+
+ pPath - This is a pointer to a location where the pointer to the
+ complete file path string can be stored. This pointer needs to
+ be free'd with MIDL_user_free when the caller is finished with it.
+
+ DesiredAccess - what we'd like to do through the share
+
+Return Value:
+
+ NO_ERROR - if The operation was completely successful.
+
+ Other - Errors returned from ShareEnumCommon, and MIDL_user_allocate may be
+ returned from this routine.
+
+Comments:
+ The share access checking is complicated by the fact that the share ACL has
+ had the owner and group SIDs stripped out. We need to put them back
+ in, or the SsCheckAccess() call will fail.
+
+--*/
+{
+ NET_API_STATUS status;
+ PSHARE_INFO_502 pshi502 = NULL;
+ DWORD bufSize;
+ DWORD fileNameSize;
+ LPWSTR pLastChar;
+ DWORD entriesRead;
+ DWORD totalEntries;
+ PSECURITY_DESCRIPTOR NewDescriptor = NULL;
+ SECURITY_DESCRIPTOR ModificationDescriptor;
+ GENERIC_MAPPING Mapping;
+ SRVSVC_SECURITY_OBJECT SecurityObject;
+ HANDLE token;
+
+ status = ShareEnumCommon(
+ 502,
+ (LPBYTE *)&pshi502,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ pShare
+ );
+
+ if( status != NO_ERROR )
+ return status;
+
+ if( entriesRead == 0 || pshi502 == NULL ) {
+ status = NERR_NetNameNotFound;
+
+ } else if( pshi502->shi502_path == NULL ) {
+ status = ERROR_BAD_DEV_TYPE;
+
+ } else if( pshi502->shi502_security_descriptor != NULL ) {
+
+ status = RtlCopySecurityDescriptor( pshi502->shi502_security_descriptor, &NewDescriptor );
+ if( status != STATUS_SUCCESS )
+ goto getout;
+
+ RtlCreateSecurityDescriptor( &ModificationDescriptor, SECURITY_DESCRIPTOR_REVISION );
+
+ RtlSetOwnerSecurityDescriptor( &ModificationDescriptor, SsLmsvcsGlobalData->LocalSystemSid, FALSE );
+
+ RtlSetGroupSecurityDescriptor( &ModificationDescriptor, SsLmsvcsGlobalData->LocalSystemSid, FALSE );
+
+ Mapping.GenericRead = FILE_GENERIC_READ;
+ Mapping.GenericWrite = FILE_GENERIC_WRITE;
+ Mapping.GenericExecute = FILE_GENERIC_EXECUTE;
+ Mapping.GenericAll = FILE_ALL_ACCESS;
+
+ if( ImpersonateSelf( SecurityImpersonation ) == FALSE ) {
+ status = GetLastError();
+ goto getout;
+ }
+
+ status = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, TRUE, &token );
+
+ RevertToSelf();
+
+ if( status != STATUS_SUCCESS )
+ goto getout;
+
+ status = RtlSetSecurityObject (
+ GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
+ &ModificationDescriptor,
+ &NewDescriptor,
+ &Mapping,
+ token
+ );
+
+ NtClose( token );
+
+ if( status == STATUS_SUCCESS ) {
+
+ SecurityObject.ObjectName = pShare;
+ SecurityObject.Mapping = &Mapping;
+ SecurityObject.SecurityDescriptor = NewDescriptor;
+
+ //
+ // SsCheckAccess does an RpcImpersonateClient()...
+ //
+ status = SsCheckAccess( &SecurityObject, DesiredAccess );
+ }
+ }
+
+ if( status == STATUS_SUCCESS ) {
+
+ //
+ // If the last character is a '\', then we must remove it.
+ //
+ pLastChar = pshi502->shi502_path + wcslen(pshi502->shi502_path);
+ pLastChar--;
+ if (*pLastChar == L'\\') {
+ *pLastChar = L'\0';
+ }
+
+ bufSize = STRSIZE(pshi502->shi502_path);
+ fileNameSize = STRSIZE(pFileName);
+
+ *pPath = MIDL_user_allocate( bufSize + fileNameSize );
+
+ if (*pPath != NULL) {
+ wcscpy (*pPath, pshi502->shi502_path);
+ wcscat (*pPath, pFileName);
+ } else {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+getout:
+ if( NewDescriptor != NULL )
+ RtlDeleteSecurityObject( &NewDescriptor );
+
+ if( pshi502 != NULL )
+ MIDL_user_free( pshi502 );
+
+ return status;
+}
diff --git a/private/net/svcdlls/srvsvc/server/canon.c b/private/net/svcdlls/srvsvc/server/canon.c
new file mode 100644
index 000000000..b3dd64e8a
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/canon.c
@@ -0,0 +1,259 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ canon.c
+
+Abstract:
+
+ Stubs for server side of internal canonicalization RPC. These routines
+ just call the local versions of the routines which live in NetLib.LIB
+
+ Moved from cansvc
+
+Author:
+
+ Richard Firth (rfirth) 20-May-1991
+
+Revision History:
+
+
+--*/
+
+#include <windows.h>
+#include <lmcons.h>
+#include <netcan.h>
+
+NET_API_STATUS
+NetprPathType(
+ IN LPTSTR ServerName,
+ IN LPTSTR PathName,
+ IN LPDWORD PathType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Stub function for NetpPathType - calls local version
+
+Arguments:
+
+ ServerName - identifies this server
+ PathName - path name to check
+ PathType - assumed type of PathName
+ Flags - controlling flags for NetpPathType
+
+Return Value:
+
+ NET_API_STATUS
+ Success = 0
+ Failure = (return code from NetpPathType)
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(ServerName);
+
+ return NetpwPathType(PathName, PathType, Flags);
+}
+
+NET_API_STATUS
+NetprPathCanonicalize(
+ IN LPTSTR ServerName,
+ IN LPTSTR PathName,
+ OUT LPTSTR Outbuf,
+ IN DWORD OutbufLen,
+ IN LPTSTR Prefix,
+ OUT LPDWORD PathType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Stub function for NetpPathCanonicalize - calls local version
+
+Arguments:
+
+ ServerName - identifies this server
+ PathName - path name to canonicalize
+ Outbuf - where to place canonicalized path
+ OutbufLen - size of Outbuf
+ Prefix - (historical) prefix for path
+ PathType - type of PathName
+ Flags - controlling flags for NetpPathCanonicalize
+
+Return Value:
+
+ NET_API_STATUS
+ Success = 0
+ Failure = (return code from NetpPathCanonicalize)
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(ServerName);
+
+ return NetpwPathCanonicalize(PathName,
+ Outbuf,
+ OutbufLen,
+ Prefix,
+ PathType,
+ Flags
+ );
+}
+
+LONG
+NetprPathCompare(
+ IN LPTSTR ServerName,
+ IN LPTSTR PathName1,
+ IN LPTSTR PathName2,
+ IN DWORD PathType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Stub function for NetpPathCompare - calls local version
+
+Arguments:
+
+ ServerName - identifies this server
+ PathName1 - path name to compare
+ PathName2 - path name to compare
+ PathType - type of PathName1, PathName2
+ Flags - controlling flags for NetpPathCompare
+
+Return Value:
+
+ LONG
+ -1 - Name1 < Name2
+ 0 - Name1 = Name2
+ +1 - Name1 > Name2
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(ServerName);
+
+ return NetpwPathCompare(PathName1, PathName2, PathType, Flags);
+}
+
+NET_API_STATUS
+NetprNameValidate(
+ IN LPTSTR ServerName,
+ IN LPTSTR Name,
+ IN DWORD NameType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Stub function for NetpNameValidate - calls local version
+
+Arguments:
+
+ ServerName - identifies this server
+ Name - to validate
+ NameType - type of Name
+ Flags - controlling flags for NetpNameValidate
+
+Return Value:
+
+ NET_API_STATUS
+ Success = 0
+ Failure = (return code from NetpNameValidate)
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(ServerName);
+
+ return NetpwNameValidate(Name, NameType, Flags);
+}
+
+NET_API_STATUS
+NetprNameCanonicalize(
+ IN LPTSTR ServerName,
+ IN LPTSTR Name,
+ OUT LPTSTR Outbuf,
+ IN DWORD OutbufLen,
+ IN DWORD NameType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Stub function for NetpNameCanonicalize - calls local version
+
+Arguments:
+
+ ServerName - identifies this server
+ Name - to canonicalize
+ Outbuf - where to place canonicalized name
+ OutbufLen - size of Outbuf
+ NameType - type of Name
+ Flags - controlling flags for NetpNameCanonicalize
+
+Return Value:
+
+ NET_API_STATUS
+ Success = 0
+ Failure = (return code from NetpNameCanonicalize)
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(ServerName);
+
+ return NetpwNameCanonicalize(Name, Outbuf, OutbufLen, NameType, Flags);
+}
+
+LONG
+NetprNameCompare(
+ IN LPTSTR ServerName,
+ IN LPTSTR Name1,
+ IN LPTSTR Name2,
+ IN DWORD NameType,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Stub function for NetpNameCompare - calls local version
+
+Arguments:
+
+ ServerName - identifies this server
+ Name1 - name to compare
+ Name2 - "
+ NameType - type of names
+ Flags - controlling flags for NetpNameCompare
+
+Return Value:
+
+ LONG
+ -1 - Name1 < Name2
+ 0 - Name1 = Name2
+ +1 - Name1 > Name2
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(ServerName);
+
+ return NetpwNameCompare(Name1, Name2, NameType, Flags);
+}
diff --git a/private/net/svcdlls/srvsvc/server/cdev.c b/private/net/svcdlls/srvsvc/server/cdev.c
new file mode 100644
index 000000000..adacfb2c1
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/cdev.c
@@ -0,0 +1,341 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ CDev.c
+
+Abstract:
+
+ This module contains support for the Character Device catagory of
+ APIs for the NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 20-Dec-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrCharDevControl (
+ IN LPTSTR ServerName,
+ IN LPTSTR DeviceName,
+ IN DWORD OpCode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSP to implement the
+ NetCharDevControl function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+#ifdef SRV_COMM_DEVICES
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsCharDevSecurityObject,
+ SRVSVC_CHARDEV_INFO_SET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Make sure that the opcode is legitimate. Only CHARDEV_CLOSE, used
+ // to close the current open of the device, is possible.
+ //
+
+ if ( OpCode != CHARDEV_CLOSE ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Set up the request packet.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+#ifdef UNICODE
+ RtlInitUnicodeString( &srp->Name1, DeviceName );
+#else
+ {
+ OEM_STRING ansiString;
+ NTSTATUS status;
+ NetpInitOemString( &ansiString, DeviceName );
+ status = RtlOemStringToUnicodeString( &srp->Name1, &ansiString, TRUE );
+ SS_ASSERT( NT_SUCCESS(status) );
+ }
+#endif
+
+ //
+ // Simply send the request on to the server.
+ //
+
+ error = SsServerFsControl( NULL, FSCTL_SRV_NET_CHARDEV_CONTROL, srp, NULL, 0 );
+
+#ifndef UNICODE
+ RtlFreeUnicodeString( &srp->Name1 );
+#endif
+
+ SsFreeSrp( srp );
+
+ return error;
+#else
+ ServerName, DeviceName, OpCode;
+ return ERROR_NOT_SUPPORTED;
+#endif
+
+} // NetrCharDevControl
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrCharDevEnum (
+ SRVSVC_HANDLE ServerName,
+ LPCHARDEV_ENUM_STRUCT InfoStruct,
+ DWORD PreferedMaximumLength,
+ LPDWORD TotalEntries,
+ LPDWORD ResumeHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetCharDevEnum function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+#ifdef SRV_COMM_DEVICES
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsCharDevSecurityObject,
+ SRVSVC_CHARDEV_ADMIN_INFO_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( InfoStruct->Level != 0 && InfoStruct->Level != 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = InfoStruct->Level;
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_CHARDEV_ENUM,
+ srp,
+ (PVOID *)&InfoStruct->CharDevInfo.Level1->Buffer,
+ PreferedMaximumLength
+ );
+
+ //
+ // Set up return information.
+ //
+
+ InfoStruct->CharDevInfo.Level1->EntriesRead =
+ srp->Parameters.Get.EntriesRead;
+
+ if ( ARGUMENT_PRESENT( TotalEntries ) ) {
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+ }
+
+ if ( srp->Parameters.Get.EntriesRead > 0 &&
+ ARGUMENT_PRESENT( ResumeHandle ) ) {
+
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+ SsFreeSrp( srp );
+
+ return error;
+#else
+ ServerName, InfoStruct, PreferedMaximumLength, TotalEntries, ResumeHandle;
+ return ERROR_NOT_SUPPORTED;
+#endif
+
+} // NetrCharDevEnum
+
+
+NET_API_STATUS
+NetrCharDevGetInfo (
+ IN LPTSTR ServerName,
+ IN LPTSTR DeviceName,
+ IN DWORD Level,
+ OUT LPCHARDEV_INFO CharDevInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetCharDevGetInfo function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+#ifdef SRV_COMM_DEVICES
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsCharDevSecurityObject,
+ SRVSVC_CHARDEV_ADMIN_INFO_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( Level != 0 && Level != 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = Level;
+ srp->Flags = SRP_RETURN_SINGLE_ENTRY;
+ srp->Parameters.Get.ResumeHandle = 0;
+
+#ifdef UNICODE
+ RtlInitUnicodeString( &srp->Name1, DeviceName );
+#else
+ {
+ NTSTATUS status;
+ OEM_STRING ansiString;
+ RtlInitString( &ansiString, DeviceName );
+ status = RtlOemStringToUnicodeString( &srp->Name1, &ansiString, TRUE );
+ SS_ASSERT( NT_SUCCESS(status) );
+ }
+#endif
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_CHARDEV_ENUM,
+ srp,
+ (PVOID *)CharDevInfo,
+ -1
+ );
+
+ //
+ // Free resources and return.
+ //
+
+#ifndef UNICODE
+ RtlFreeUnicodeString( &srp->Name1 );
+#endif
+
+ SsFreeSrp( srp );
+
+ return error;
+#else
+ ServerName, DeviceName, Level, CharDevInfo;
+ return ERROR_NOT_SUPPORTED;
+#endif
+
+} // NetrCharDevGetInfo
+
diff --git a/private/net/svcdlls/srvsvc/server/cdevq.c b/private/net/svcdlls/srvsvc/server/cdevq.c
new file mode 100644
index 000000000..0c40d2d18
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/cdevq.c
@@ -0,0 +1,215 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ CDevQ.c
+
+Abstract:
+
+ This module contains support for the Character Device Queue catagory
+ of APIs for the NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 31-Dec-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrCharDevQEnum (
+ IN LPTSTR ServerName,
+ IN LPTSTR UserName,
+ IN OUT LPCHARDEVQ_ENUM_STRUCT InfoStruct,
+ IN DWORD PreferedMaximumLength,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetCharDevEnum function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+#ifdef SRV_COMM_DEVICES
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName, UserName;
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsCharDevSecurityObject,
+ SRVSVC_CHARDEV_ADMIN_INFO_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( InfoStruct->Level != 0 && InfoStruct->Level != 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = InfoStruct->Level;
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_CHARDEVQ_ENUM,
+ srp,
+ (PVOID *)&InfoStruct->CharDevQInfo.Level1->Buffer,
+ PreferedMaximumLength
+ );
+
+ //
+ // Set up return information.
+ //
+
+ InfoStruct->CharDevQInfo.Level1->EntriesRead =
+ srp->Parameters.Get.EntriesRead;
+
+ if ( ARGUMENT_PRESENT( TotalEntries ) ) {
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+ }
+
+ if ( srp->Parameters.Get.EntriesRead > 0 &&
+ ARGUMENT_PRESENT( ResumeHandle ) ) {
+
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+ SsFreeSrp( srp );
+
+ return error;
+#else
+ ServerName;
+ UserName;
+ InfoStruct;
+ PreferedMaximumLength;
+ TotalEntries;
+ ResumeHandle;
+
+ return ERROR_NOT_SUPPORTED;
+#endif
+
+} // NetrCharDevQEnum
+
+
+/****************************************************************************/
+NET_API_STATUS
+NetrCharDevQGetInfo (
+ IN LPTSTR ServerName,
+ IN LPTSTR QueueName,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ OUT LPCHARDEVQ_INFO CharDevQInfo
+ )
+
+{
+ ServerName;
+ QueueName;
+ UserName;
+ Level;
+ CharDevQInfo;
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+/****************************************************************************/
+NET_API_STATUS
+NetrCharDevQSetInfo (
+ IN LPTSTR ServerName,
+ IN LPTSTR QueueName,
+ IN DWORD Level,
+ IN LPCHARDEVQ_INFO CharDevQInfo,
+ OUT LPDWORD ParmErr
+ )
+{
+ ServerName;
+ QueueName;
+ Level;
+ CharDevQInfo;
+ ParmErr;
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+/****************************************************************************/
+NET_API_STATUS
+NetrCharDevQPurge (
+ IN LPTSTR ServerName,
+ IN LPTSTR QueueName
+ )
+
+{
+ ServerName;
+ QueueName;
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+
+
+/****************************************************************************/
+NET_API_STATUS
+NetrCharDevQPurgeSelf (
+ IN LPTSTR ServerName,
+ IN LPTSTR QueueName,
+ IN LPTSTR ComputerName
+ )
+{
+ ServerName;
+ QueueName;
+ ComputerName;
+
+ return ERROR_NOT_SUPPORTED;
+}
+
diff --git a/private/net/svcdlls/srvsvc/server/cmdline.c b/private/net/svcdlls/srvsvc/server/cmdline.c
new file mode 100644
index 000000000..891a67292
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/cmdline.c
@@ -0,0 +1,335 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ CmdLine.c
+
+Abstract:
+
+ This module contains support routines for processing server service
+ command-line arguments.
+
+Author:
+
+ David Treadwell (davidtr) 10-Mar-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+
+#include <netlibnt.h>
+#include <tstr.h>
+
+
+//
+// Forward declarations.
+//
+
+PFIELD_DESCRIPTOR
+FindSwitchMatch (
+ IN LPWCH Argument,
+ IN BOOLEAN Starting
+ );
+
+NET_API_STATUS
+SetField (
+ IN PFIELD_DESCRIPTOR SwitchDesc,
+ IN LPWCH Argument
+ );
+
+
+NET_API_STATUS
+SsParseCommandLine (
+ IN DWORD argc,
+ IN LPWSTR argv[],
+ IN BOOLEAN Starting
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets server parameters using a command line. It parses
+ the command line, changing one parameter at a time as it comes up.
+
+Arguments:
+
+ argc - the number of command-line arguments.
+
+ argv - an arrray of pointers to the arguments.
+
+ Starting - TRUE if the command line is from server startup, i.e.
+ net start server. This is needed because some fields may only
+ be set at startup.
+
+Return Value:
+
+ NET_API_STATUS - 0 or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ DWORD i;
+ PFIELD_DESCRIPTOR switchDesc;
+ PSERVER_SERVICE_DATA saveSsData;
+
+ //
+ // Save the service data in case there is an invalid param and we have
+ // to back out.
+ //
+
+ saveSsData = MIDL_user_allocate( sizeof(SERVER_SERVICE_DATA) );
+ if ( saveSsData == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlCopyMemory( saveSsData, &SsData, sizeof(SERVER_SERVICE_DATA) );
+
+ //
+ // Loop through the command-line arguments, setting as we go.
+ //
+
+ for ( i = 0; i < argc; i++ ) {
+
+ LPWCH arg;
+
+ arg = argv[i];
+
+ //
+ // A hack to aid debugging.
+ //
+
+ if ( _wcsnicmp( L"/debug", arg, 6 ) == 0 ) {
+ continue;
+ }
+
+ //
+ // Try to match the switch against the legal switches.
+ //
+
+ switchDesc = FindSwitchMatch( arg, Starting );
+ if ( switchDesc == NULL ) {
+ error = ERROR_INVALID_PARAMETER;
+ goto err_exit;
+ }
+
+ //
+ // Set the value in the field.
+ //
+
+ error = SetField( switchDesc, arg );
+ if ( error != NO_ERROR ) {
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SsParseCommandLine: SetField failed for switch "
+ "\"%ws\": %ld\n", arg, error ));
+ }
+ goto err_exit;
+ }
+ }
+
+ error = NO_ERROR;
+ goto normal_exit;
+
+err_exit:
+
+ //
+ // Restore the original server settings.
+ //
+
+ RtlCopyMemory( &SsData, saveSsData, sizeof(SERVER_SERVICE_DATA) );
+
+normal_exit:
+
+ MIDL_user_free( saveSsData );
+
+ return error;
+
+} // SsParseCommandLine
+
+
+PFIELD_DESCRIPTOR
+FindSwitchMatch (
+ IN LPWCH Argument,
+ IN BOOLEAN Starting
+ )
+
+/*++
+
+Routine Description:
+
+ This routine tries to match a given switch against the possible
+ switch values.
+
+Arguments:
+
+ Argument - a pointer to the text argument.
+
+ Starting - TRUE if the command line is from server startup, i.e.
+ net start server. This is needed because some fields may only
+ be set at startup.
+
+Return Value:
+
+ A pointer to a FIELD_DESCRIPTOR field from SsServerInfoFields[], or NULL if
+ no valid match could be found.
+
+--*/
+
+{
+ SHORT i;
+ PFIELD_DESCRIPTOR foundSwitch = NULL;
+ ULONG switchLength;
+ LPWCH s;
+
+ //
+ // Ignore the leading /.
+ //
+
+ if ( *Argument != '/' ) {
+ SS_PRINT(( "Invalid switch: %ws\n", Argument ));
+ return NULL;
+ }
+
+ Argument++;
+
+ //
+ // Find out how long the passed-in switch is.
+ //
+
+ for ( s = Argument, switchLength = 0;
+ *s != ':' && *s != '\0';
+ s++, switchLength++ );
+
+ //
+ // Compare at most that many bytes. We allow a minimal matching--
+ // as long as the specified switch uniquely identifies a switch, then
+ // is is usable.
+ //
+
+ for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
+
+ if ( _wcsnicmp( Argument, SsServerInfoFields[i].FieldName, switchLength ) == 0 ) {
+
+ if ( SsServerInfoFields[i].Settable == NOT_SETTABLE ||
+ ( !Starting && SsServerInfoFields[i].Settable == SET_ON_STARTUP ) ) {
+
+ SS_PRINT(( "Cannot set field %ws at this time.\n",
+ SsServerInfoFields[i].FieldName ));
+
+ return NULL;
+ }
+
+ if ( foundSwitch != NULL ) {
+ SS_PRINT(( "Ambiguous switch name: %ws (matches %ws and %ws)\n",
+ Argument-1, foundSwitch->FieldName,
+ SsServerInfoFields[i].FieldName ));
+ return NULL;
+ }
+
+ foundSwitch = &SsServerInfoFields[i];
+ }
+ }
+
+ if ( foundSwitch == NULL ) {
+ SS_PRINT(( "Unknown argument: %ws\n", Argument-1 ));
+ }
+
+ return foundSwitch;
+
+} // FindSwitchMatch
+
+
+NET_API_STATUS
+SetField (
+ IN PFIELD_DESCRIPTOR Field,
+ IN LPWCH Argument
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the value of a server info parameter.
+
+Arguments:
+
+ Field - a pointer to the appropriate FIELD_DESCRIPTOR field
+ from SsServerInfoFields[].
+
+ Argument - a pointer to the text argument. It should be of the form
+ "/switch:value".
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ LPWCH valueStart;
+ DWORD value;
+
+ //
+ // Find out where the ':' is in the argument.
+ //
+
+ valueStart = wcschr( Argument, L':' );
+
+ if ( valueStart == NULL && Field->FieldType != BOOLEAN_FIELD ) {
+ SS_PRINT(( "Invalid argument: %s\n", Argument ));
+ }
+
+ switch ( Field->FieldType ) {
+
+ case BOOLEAN_FIELD:
+
+ //
+ // If the first character of the value is Y or there is no
+ // value specified, set the field to TRUE, otherwise set it
+ // to FALSE.
+ //
+
+ if ( valueStart == NULL || *(valueStart+1) == L'y' ||
+ *(valueStart+1) == L'Y' ) {
+ value = TRUE;
+ } else if ( *(valueStart+1) == L'n' || *(valueStart+1) == L'N' ) {
+ value = FALSE;
+ } else {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ break;
+
+ case DWORD_FIELD:
+ {
+ NTSTATUS status;
+ UNICODE_STRING unicodeString;
+
+ RtlInitUnicodeString( &unicodeString, valueStart + 1 );
+ status = RtlUnicodeStringToInteger( &unicodeString, 0, &value );
+ if ( !NT_SUCCESS(status) ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+ case LPSTR_FIELD:
+
+ value = (DWORD)( valueStart + 1 );
+ break;
+ }
+
+ //
+ // Call SsSetField to actually set the field.
+ //
+
+ return SsSetField( Field, &value, TRUE, NULL );
+
+} // SetField
+
diff --git a/private/net/svcdlls/srvsvc/server/conn.c b/private/net/svcdlls/srvsvc/server/conn.c
new file mode 100644
index 000000000..de1e68110
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/conn.c
@@ -0,0 +1,152 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ Conn.c
+
+Abstract:
+
+ This module contains support for the Connection catagory of APIs for
+ the NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 23-Feb-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrConnectionEnum (
+ IN LPTSTR ServerName,
+ IN LPTSTR Qualifier,
+ IN LPCONNECT_ENUM_STRUCT InfoStruct,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetConnectionEnum function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the level is valid. Since it is an unsigned
+ // value, it can never be less than 0.
+ //
+
+ if ( InfoStruct->Level > 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // The qualifier cannot be null or can it be a null string
+ //
+
+ if ( Qualifier == NULL || *Qualifier == L'\0' ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that the caller is allowed to get connection
+ // information in the server.
+ //
+
+ error = SsCheckAccess(
+ &SsConnectionSecurityObject,
+ SRVSVC_CONNECTION_INFO_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = InfoStruct->Level;
+
+#ifdef UNICODE
+ RtlInitUnicodeString( &srp->Name1, Qualifier );
+#else
+ {
+ OEM_STRING ansiString;
+ NTSTATUS status;
+ NetpInitOemString( &ansiString, Qualifier );
+ status = RtlOemStringToUnicodeString( &srp->Name1, &ansiString, TRUE );
+ SS_ASSERT( NT_SUCCESS(status) );
+ }
+#endif
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_CONNECTION_ENUM,
+ srp,
+ (PVOID *)&InfoStruct->ConnectInfo.Level1->Buffer,
+ PreferredMaximumLength
+ );
+
+ //
+ // Set up return information.
+ //
+
+ InfoStruct->ConnectInfo.Level1->EntriesRead =
+ srp->Parameters.Get.EntriesRead;
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+
+ if ( srp->Parameters.Get.EntriesRead > 0 &&
+ ARGUMENT_PRESENT( ResumeHandle ) ) {
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+#ifndef UNICODE
+ RtlFreeUnicodeString( &srp->Name1 );
+#endif
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // NetrConnectionEnum
+
diff --git a/private/net/svcdlls/srvsvc/server/daytona/makefile b/private/net/svcdlls/srvsvc/server/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/daytona/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/net/svcdlls/srvsvc/server/daytona/sources b/private/net/svcdlls/srvsvc/server/daytona/sources
new file mode 100644
index 000000000..97a22b441
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/daytona/sources
@@ -0,0 +1,89 @@
+!IF 0
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+MAJORCOMP=net
+MINORCOMP=srvsvcsrv
+
+TARGETNAME=srvsvc
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DYNLINK
+
+DLLDEF=obj\*\srvsvc.def
+
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntlsapi.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \
+ $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+ $(BASEDIR)\public\sdk\lib\*\winspool.lib \
+ $(BASEDIR)\public\sdk\lib\*\xactsrv.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ ..\..\lib\obj\*\srvcomn.lib
+
+INCLUDES=.;..;..\..;..\..\..\..\inc;$(BASEDIR)\private\inc;..\..\..\..\xactsrv;..\..\..\..\..\ntos\inc
+
+USE_CRTDLL=1
+
+!IFNDEF DISABLE_NET_UNICODE
+UNICODE=1
+NET_C_DEFINES=-DUNICODE
+!ENDIF
+
+SOURCES= \
+ ..\adtsrv.c \
+ ..\canon.c \
+ ..\cdev.c \
+ ..\cdevq.c \
+ ..\cmdline.c \
+ ..\conn.c \
+ ..\dfs.c \
+ ..\disk.c \
+ ..\file.c \
+ ..\internal.c \
+ ..\registry.c \
+ ..\scavengr.c \
+ ..\security.c \
+ ..\sess.c \
+ ..\share.c \
+ ..\srvinfo.c \
+ ..\srvmain.c \
+ ..\srvsvc.rc \
+ ..\srvsvc_s.c \
+ ..\ssdata.c \
+ ..\ssinit.c \
+ ..\sssubs.c \
+ ..\stats.c \
+ ..\tod.c \
+ ..\xport.c \
+ ..\xsdata.c \
+ ..\xsinit.c \
+ ..\xsproc.c
+
+C_DEFINES=-DRPC_NO_WINDOWS_H
+
+C_DEFINES=$(C_DEFINES) -D_PNP_POWER=1
diff --git a/private/net/svcdlls/srvsvc/server/dfs.c b/private/net/svcdlls/srvsvc/server/dfs.c
new file mode 100644
index 000000000..0b668b8e8
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/dfs.c
@@ -0,0 +1,835 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ Share.c
+
+Abstract:
+
+ This module contains support for the DFS catagory of APIs for the
+ NT server service.
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "lmerr.h"
+#include <dfsfsctl.h>
+
+#define CAPTURE_STRING( Name ) \
+ if( Name != NULL ) { \
+ ULONG _size = SIZE_WSTR( Name ); \
+ capture->Name = (LPWSTR)variableData; \
+ RtlCopyMemory( capture->Name, Name, _size ); \
+ variableData += _size; \
+ POINTER_TO_OFFSET( capture->Name, capture ); \
+ }
+
+#define RELATION_INFO_SIZE( RelInfo ) \
+ (sizeof( NET_DFS_ENTRY_ID_CONTAINER ) + \
+ (RelInfo->Count * sizeof(NET_DFS_ENTRY_ID)))
+
+NET_API_STATUS
+DfsFsctl(
+ IN ULONG FsControlCode,
+ IN PVOID InputBuffer,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer,
+ IN ULONG OutputBufferLength
+)
+{
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES objectAttributes;
+ IO_STATUS_BLOCK ioStatus;
+ HANDLE dfsHandle;
+ UNICODE_STRING deviceName;
+
+ deviceName.Buffer = DFS_SERVER_NAME;
+ deviceName.MaximumLength = sizeof( DFS_SERVER_NAME );
+ deviceName.Length = deviceName.MaximumLength - sizeof(UNICODE_NULL);
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &deviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ if( SsInitialized ) {
+ (VOID)RpcImpersonateClient( NULL );
+ }
+
+ status = NtCreateFile(
+ &dfsHandle,
+ SYNCHRONIZE,
+ &objectAttributes,
+ &ioStatus,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN_IF,
+ FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0);
+
+ if ( SsInitialized ) {
+ (VOID)RpcRevertToSelf( );
+ }
+
+ if ( NT_SUCCESS(status) ) {
+ status = ioStatus.Status;
+ }
+
+ if( !NT_SUCCESS( status ) ) {
+ return (NET_API_STATUS)status;
+ }
+
+ status = NtFsControlFile(
+ dfsHandle,
+ NULL, // Event,
+ NULL, // ApcRoutine,
+ NULL, // ApcContext,
+ &ioStatus,
+ FsControlCode,
+ InputBuffer,
+ InputBufferLength,
+ OutputBuffer,
+ OutputBufferLength
+ );
+
+ if(NT_SUCCESS(status)) {
+ status = ioStatus.Status;
+ }
+
+ NtClose( dfsHandle );
+
+ return (NET_API_STATUS)status;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsGetVersion(
+ IN SRVSVC_HANDLE ServerName,
+ OUT LPDWORD Version)
+{
+ DFS_GET_VERSION_ARG arg;
+ NET_API_STATUS error;
+
+ RtlZeroMemory( &arg, sizeof(arg) );
+
+ error = DfsFsctl( FSCTL_DFS_GET_VERSION, &arg, sizeof( arg ), NULL, 0 );
+
+ if (error == NERR_Success) {
+
+ *Version = arg.Version;
+
+ } else {
+
+ error = ERROR_FILE_NOT_FOUND;
+
+ }
+
+ return( error );
+
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsCreateLocalPartition (
+ IN SRVSVC_HANDLE ServerName, // Name of server for this API
+ IN LPWSTR ShareName, // Name of share to add to the DFS
+ IN LPGUID EntryUid, // unique id for this partition
+ IN LPWSTR EntryPrefix, // DFS entry path for this volume
+ IN LPWSTR ShortName, // 8.3 format of EntryPrefix
+ IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
+ IN BOOL Force // Force knowledge into consistent state?
+ )
+{
+ NET_API_STATUS error;
+ PDFS_CREATE_LOCAL_PARTITION_ARG capture;
+ ULONG size = sizeof( *capture );
+ ULONG i;
+ PCHAR variableData;
+ PSERVER_REQUEST_PACKET srp;
+ LPSHARE_INFO_2 shareInfo2 = NULL;
+ UNICODE_STRING ntSharePath;
+
+ if( ShareName == NULL || EntryUid == NULL ||
+ EntryPrefix == NULL || RelationInfo == NULL ) {
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make a call to the SMB server to find the pathname for the share.
+ //
+ srp = SsAllocateSrp();
+ if( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ };
+ srp->Level = 2;
+ srp->Flags = SRP_RETURN_SINGLE_ENTRY;
+ srp->Parameters.Get.ResumeHandle = 0;
+ RtlInitUnicodeString( &srp->Name1, ShareName );
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_SHARE_ENUM,
+ srp,
+ &shareInfo2,
+ 10000
+ );
+ if( error != NO_ERROR ) {
+ SsFreeSrp( srp );
+ return error;
+ }
+
+ if( srp->Parameters.Get.EntriesRead == 0 ||
+ shareInfo2 == NULL ||
+ shareInfo2->shi2_path == NULL ) {
+
+ SsFreeSrp( srp );
+ if( shareInfo2 != NULL ) {
+ MIDL_user_free( shareInfo2 );
+ }
+ return ERROR_BAD_NET_NAME;
+ }
+
+ if( (shareInfo2->shi2_type & ~STYPE_SPECIAL) != STYPE_DISKTREE ) {
+ SsFreeSrp( srp );
+ MIDL_user_free( shareInfo2 );
+ return ERROR_BAD_DEV_TYPE;
+ }
+
+ //
+ // Now we need to convert the share's Win32 style pathname to an
+ // NT pathname
+ //
+ ntSharePath.Buffer = NULL;
+
+ if( !RtlDosPathNameToNtPathName_U(
+ shareInfo2->shi2_path,
+ &ntSharePath,
+ NULL,
+ NULL ) ) {
+
+ SsFreeSrp( srp );
+ MIDL_user_free( shareInfo2 );
+ return ERROR_INVALID_PARAMETER;
+ }
+ MIDL_user_free( shareInfo2 );
+
+ //
+ // Pack the data into an fsctl that can be sent to the local Dfs driver:
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( ShareName );
+ size += ntSharePath.Length + sizeof( WCHAR );
+ size += SIZE_WSTR( EntryPrefix );
+ size += SIZE_WSTR( ShortName );
+
+ if( ARGUMENT_PRESENT( RelationInfo ) ) {
+ size += RELATION_INFO_SIZE(RelationInfo);
+ for( i = 0; i < RelationInfo->Count; i++ ) {
+ size += SIZE_WSTR( RelationInfo->Buffer[i].Prefix );
+ }
+ }
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ SsFreeSrp( srp );
+ RtlFreeUnicodeString( &ntSharePath );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters in the capture buffer
+ //
+ capture->EntryUid = *EntryUid;
+ capture->Force = Force;
+
+ //
+ // Put the variable data in the capture buffer.
+ //
+
+ variableData = (PCHAR)(capture + 1);
+
+ if( ARGUMENT_PRESENT( RelationInfo ) ) {
+ capture->RelationInfo = (LPNET_DFS_ENTRY_ID_CONTAINER)variableData;
+ capture->RelationInfo->Buffer = (LPNET_DFS_ENTRY_ID)
+ (capture->RelationInfo + 1);
+ variableData += RELATION_INFO_SIZE( RelationInfo );
+ for( i=0; i < RelationInfo->Count; i++ ) {
+ CAPTURE_STRING( RelationInfo->Buffer[i].Prefix );
+ capture->RelationInfo->Buffer[i].Uid = RelationInfo->Buffer[i].Uid;
+ }
+
+ POINTER_TO_OFFSET( capture->RelationInfo->Buffer, capture );
+ POINTER_TO_OFFSET( capture->RelationInfo, capture );
+
+ }
+
+ CAPTURE_STRING( ShareName );
+ CAPTURE_STRING( EntryPrefix );
+ CAPTURE_STRING( ShortName );
+
+ //
+ // Capture the nt version of the share path
+ //
+ capture->SharePath = (LPWSTR)variableData;
+ RtlCopyMemory( capture->SharePath, ntSharePath.Buffer, ntSharePath.Length );
+ variableData += ntSharePath.Length;
+ POINTER_TO_OFFSET( capture->SharePath, capture );
+
+ (WCHAR *)variableData = 0; // Null terminate the name
+ variableData += sizeof( WCHAR );
+
+ RtlFreeUnicodeString( &ntSharePath );
+
+ //
+ // First, tell the server to mark this share as being in Dfs. Note that
+ // the share name is already in srp->Name1. If we later run into an
+ // error, we'll undo the state change.
+ //
+
+ srp->Flags = SRP_SET_SHARE_IN_DFS;
+ error = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_SHARE_STATE_CHANGE,
+ srp,
+ NULL,
+ 0
+ );
+ if( error != NO_ERROR ) {
+ SsFreeSrp( srp );
+ MIDL_user_free( capture );
+ return error;
+ }
+
+ //
+ // Tell the Dfs driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_CREATE_LOCAL_PARTITION,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ if (error != NO_ERROR) {
+
+ //
+ // An error occured changing the Dfs state. So, try to undo the
+ // server share state change.
+ //
+
+ NET_API_STATUS error2;
+
+ srp->Flags = SRP_CLEAR_SHARE_IN_DFS;
+ error2 = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_SHARE_STATE_CHANGE,
+ srp,
+ NULL,
+ 0);
+
+ }
+
+ SsFreeSrp( srp );
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsDeleteLocalPartition (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix
+ )
+{
+ NET_API_STATUS error;
+ PDFS_DELETE_LOCAL_PARTITION_ARG capture;
+ ULONG size = sizeof( *capture );
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to
+ // the dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( Prefix );
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters into the capture buffer
+ //
+ capture->Uid = *Uid;
+
+ //
+ // Put the variable data in the capture buffer
+ //
+ variableData = (PCHAR)(capture + 1 );
+
+ CAPTURE_STRING( Prefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_DELETE_LOCAL_PARTITION,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ //
+ // If there was no error, tell the server that this share
+ // is no longer in the Dfs
+ //
+
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsSetLocalVolumeState (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix,
+ IN ULONG State
+ )
+{
+ NET_API_STATUS error;
+ PDFS_SET_LOCAL_VOLUME_STATE_ARG capture;
+ ULONG size = sizeof( *capture );
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to
+ // the dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( Prefix );
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters into the capture buffer
+ //
+ capture->Uid = *Uid;
+ capture->State = State;
+
+ //
+ // Put the variable data in the capture buffer
+ //
+ variableData = (PCHAR)(capture + 1 );
+
+ CAPTURE_STRING( Prefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_SET_LOCAL_VOLUME_STATE,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsSetServerInfo (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix
+ )
+{
+ NET_API_STATUS error;
+ PDFS_SET_SERVER_INFO_ARG capture;
+ ULONG size = sizeof( *capture );
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to
+ // the dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( Prefix );
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters into the capture buffer
+ //
+ capture->Uid = *Uid;
+
+ //
+ // Put the variable data in the capture buffer
+ //
+ variableData = (PCHAR)(capture + 1 );
+
+ CAPTURE_STRING( Prefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_SET_SERVER_INFO,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsCreateExitPoint (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix,
+ IN ULONG Type,
+ IN ULONG ShortPrefixLen,
+ OUT LPWSTR ShortPrefix
+ )
+{
+ NET_API_STATUS error;
+ PDFS_CREATE_EXIT_POINT_ARG capture;
+ ULONG size = sizeof( *capture );
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to
+ // the dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( Prefix );
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters into the capture buffer
+ //
+ capture->Uid = *Uid;
+ capture->Type = Type;
+
+ //
+ // Put the variable data in the capture buffer
+ //
+ variableData = (PCHAR)(capture + 1 );
+
+ CAPTURE_STRING( Prefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_CREATE_EXIT_POINT,
+ capture,
+ size,
+ ShortPrefix,
+ ShortPrefixLen * sizeof(WCHAR)
+ );
+
+ MIDL_user_free( capture );
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsDeleteExitPoint (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix,
+ IN ULONG Type
+ )
+{
+ NET_API_STATUS error;
+ PDFS_DELETE_EXIT_POINT_ARG capture;
+ ULONG size = sizeof( *capture );
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to
+ // the dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( Prefix );
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters into the capture buffer
+ //
+ capture->Uid = *Uid;
+ capture->Type = Type;
+
+ //
+ // Put the variable data in the capture buffer
+ //
+ variableData = (PCHAR)(capture + 1 );
+
+ CAPTURE_STRING( Prefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_DELETE_EXIT_POINT,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsModifyPrefix (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPGUID Uid,
+ IN LPWSTR Prefix
+ )
+{
+ NET_API_STATUS error;
+ PDFS_DELETE_LOCAL_PARTITION_ARG capture;
+ ULONG size = sizeof( *capture );
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to
+ // the dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( Prefix );
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters into the capture buffer
+ //
+ capture->Uid = *Uid;
+
+ //
+ // Put the variable data in the capture buffer
+ //
+ variableData = (PCHAR)(capture + 1 );
+
+ CAPTURE_STRING( Prefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_MODIFY_PREFIX,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ return error;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsFixLocalVolume (
+ IN SRVSVC_HANDLE ServerName,
+ IN LPWSTR VolumeName,
+ IN ULONG EntryType,
+ IN ULONG ServiceType,
+ IN LPWSTR StgId,
+ IN LPGUID EntryUid, // unique id for this partition
+ IN LPWSTR EntryPrefix, // path prefix for this partition
+ IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
+ IN ULONG CreateDisposition
+ )
+{
+ NET_API_STATUS error;
+ PDFS_FIX_LOCAL_VOLUME_ARG capture;
+ ULONG size = sizeof( *capture );
+ ULONG i;
+ PCHAR variableData;
+
+ //
+ // Pack the args into a single buffer that can be sent to the
+ // dfs driver:
+ //
+
+ //
+ // First find the size...
+ //
+ size += SIZE_WSTR( VolumeName );
+ size += SIZE_WSTR( StgId );
+ size += SIZE_WSTR( EntryPrefix );
+
+ if( ARGUMENT_PRESENT( RelationInfo ) ) {
+ size += RELATION_INFO_SIZE( RelationInfo );
+ for( i = 0; i < RelationInfo->Count; i++ ) {
+ size += SIZE_WSTR( RelationInfo->Buffer[i].Prefix );
+ }
+ }
+
+ //
+ // Now allocate the memory
+ //
+ capture = MIDL_user_allocate( size );
+ if( capture == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( capture, size );
+
+ //
+ // Put the fixed parameters in the capture buffer
+ //
+ capture->EntryType = EntryType;
+ capture->ServiceType = ServiceType;
+ capture->EntryUid = *EntryUid;
+ capture->CreateDisposition = CreateDisposition;
+
+ //
+ // Put the variable data in the capture buffer.
+ //
+
+ variableData = (PCHAR)(capture + 1);
+
+ if( ARGUMENT_PRESENT( RelationInfo ) ) {
+ capture->RelationInfo = (LPNET_DFS_ENTRY_ID_CONTAINER)variableData;
+ capture->RelationInfo->Buffer = (LPNET_DFS_ENTRY_ID)
+ (capture->RelationInfo + 1);
+ variableData += RELATION_INFO_SIZE( RelationInfo );
+ for( i=0; i < RelationInfo->Count; i++ ) {
+ CAPTURE_STRING( RelationInfo->Buffer[i].Prefix );
+ capture->RelationInfo->Buffer[i].Uid = RelationInfo->Buffer[i].Uid;
+ }
+
+ POINTER_TO_OFFSET( capture->RelationInfo->Buffer, capture );
+ POINTER_TO_OFFSET( capture->RelationInfo, capture );
+ }
+
+ CAPTURE_STRING( VolumeName );
+ CAPTURE_STRING( StgId );
+ CAPTURE_STRING( EntryPrefix );
+
+ //
+ // Tell the driver!
+ //
+ error = DfsFsctl(
+ FSCTL_DFS_FIX_LOCAL_VOLUME,
+ capture,
+ size,
+ NULL,
+ 0
+ );
+
+ MIDL_user_free( capture );
+
+ return error;
+}
+
+
+//
+// This routine returns TRUE if this machine is the root of a DFS, FALSE otherwise
+//
+VOID
+SsSetDfsRoot()
+{
+ NET_API_STATUS error;
+
+ error = DfsFsctl( FSCTL_DFS_IS_ROOT, NULL, 0, NULL, 0 );
+
+ SsData.IsDfsRoot = (error == NO_ERROR);
+}
diff --git a/private/net/svcdlls/srvsvc/server/dirs b/private/net/svcdlls/srvsvc/server/dirs
new file mode 100644
index 000000000..bf1044c7a
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/dirs
@@ -0,0 +1,3 @@
+DIRS=daytona
+
+OPTIONAL_DIRS=
diff --git a/private/net/svcdlls/srvsvc/server/disk.c b/private/net/svcdlls/srvsvc/server/disk.c
new file mode 100644
index 000000000..1342b050c
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/disk.c
@@ -0,0 +1,173 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ disk.c
+
+Abstract:
+
+ This module contains support for the NetServerDiskEnum API for the NT
+ OS/2 server service.
+
+Author:
+
+ Johnson Apacible (johnsona) 19-March-1992
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+
+#include "nturtl.h"
+
+#include "winbase.h"
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerDiskEnum(
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN OUT DISK_ENUM_CONTAINER *DiskInfoStruct,
+ IN DWORD PrefMaxLen,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ server half of the NetServerDiskEnum function.
+
+Arguments:
+
+ ServerName - optional name of server.
+ Level - must be 0
+ DiskInfoStruct - the output buffer.
+ PrefMaxLen - the preferred maximum length of the output buffer.
+ TotalEntries - total number of drive entries in the output buffer.
+ ResumeHandle - ignored.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ TCHAR diskName[4];
+ UINT i;
+ UINT driveType;
+ UINT totalBytes = 0;
+ LPTSTR tempBuffer;
+ LPTSTR currentDiskInfo;
+
+ ServerName, PrefMaxLen, ResumeHandle;
+
+ //
+ // The only valid level is 0.
+ //
+
+ if ( Level != 0 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Make sure that the caller is allowed to get disk information from
+ // the server.
+ //
+
+ error = SsCheckAccess(
+ &SsDiskSecurityObject,
+ SRVSVC_DISK_ENUM
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Go through all the driver letters, get those that does not return
+ // an error.
+ //
+
+ tempBuffer = MIDL_user_allocate(
+ (SRVSVC_MAX_NUMBER_OF_DISKS * (3 * sizeof(TCHAR))) +
+ sizeof(TCHAR)
+ );
+
+ if ( tempBuffer == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ currentDiskInfo = tempBuffer;
+
+ diskName[0] = 'A';
+ diskName[1] = ':';
+ diskName[2] = '\\';
+ diskName[3] = '\0';
+
+ *TotalEntries = 0;
+
+ for ( i = 0; i < SRVSVC_MAX_NUMBER_OF_DISKS; i++ ) {
+
+ driveType = SsGetDriveType( diskName );
+
+ if ( driveType == DRIVE_FIXED ||
+ driveType == DRIVE_CDROM ||
+ driveType == DRIVE_REMOVABLE ||
+ driveType == DRIVE_RAMDISK ) {
+
+ //
+ // This is a valid disk
+ //
+
+ (*TotalEntries)++;
+ *(currentDiskInfo++) = diskName[0];
+ *(currentDiskInfo++) = ':';
+ *(currentDiskInfo++) = '\0';
+
+ }
+
+ diskName[0]++;
+
+ }
+
+#ifdef UNICODE
+ *currentDiskInfo = UNICODE_NULL;
+#else
+ *currentDiskInfo = '\0';
+#endif
+
+ //
+ // EntriesRead must be one greater than TotalEntries so RPC can
+ // marshal the output strings back to the client correctly.
+ //
+
+ totalBytes = ((*TotalEntries) * (3 * sizeof(TCHAR))) + sizeof(TCHAR);
+
+ DiskInfoStruct->EntriesRead = (*TotalEntries) + 1;
+ DiskInfoStruct->Buffer = MIDL_user_allocate( totalBytes );
+
+ if ( DiskInfoStruct->Buffer != NULL ) {
+ RtlCopyMemory(
+ DiskInfoStruct->Buffer,
+ tempBuffer,
+ totalBytes
+ );
+ } else {
+ MIDL_user_free(tempBuffer);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ MIDL_user_free( tempBuffer );
+
+ return NO_ERROR;
+
+} // NetrServerDiskEnum
+
diff --git a/private/net/svcdlls/srvsvc/server/file.c b/private/net/svcdlls/srvsvc/server/file.c
new file mode 100644
index 000000000..fdfb0c9ae
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/file.c
@@ -0,0 +1,329 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ File.c
+
+Abstract:
+
+ This module contains support for the File catagory of APIs for the
+ NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 13-Feb-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+
+//
+// Forward declarations.
+//
+
+NET_API_STATUS
+FileEnumCommon (
+ IN LPTSTR BasePath,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL,
+ IN BOOLEAN IsGetInfo
+ );
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrFileClose (
+ IN LPTSTR ServerName,
+ IN DWORD FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD and FSP to implement the
+ NetFileClose function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the caller is allowed to close files in the server.
+ //
+
+ error = SsCheckAccess( &SsFileSecurityObject, SRVSVC_FILE_CLOSE );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Set up the request packet. We use the name buffer pointer to
+ // hold the file ID of the file to close.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Parameters.Get.ResumeHandle = FileId;
+
+ //
+ // Simply send the request on to the server.
+ //
+
+ error = SsServerFsControl( NULL, FSCTL_SRV_NET_FILE_CLOSE, srp, NULL, 0 );
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // NetrFileClose
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrFileEnum (
+ IN LPTSTR ServerName,
+ IN LPTSTR BasePath,
+ IN LPTSTR UserName,
+ OUT PFILE_ENUM_STRUCT InfoStruct,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetFileEnum function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+
+ ServerName;
+
+ //
+ // Make sure that the caller is allowed to set share information in the
+ // server.
+ //
+
+ error = SsCheckAccess(
+ &SsFileSecurityObject,
+ SRVSVC_FILE_INFO_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ return FileEnumCommon(
+ BasePath,
+ UserName,
+ InfoStruct->Level,
+ (LPBYTE *)&InfoStruct->FileInfo.Level3->Buffer,
+ PreferredMaximumLength,
+ &InfoStruct->FileInfo.Level3->EntriesRead,
+ TotalEntries,
+ ResumeHandle,
+ FALSE
+ );
+
+} // NetrFileEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrFileGetInfo (
+ IN LPTSTR ServerName,
+ IN DWORD FileId,
+ IN DWORD Level,
+ OUT LPFILE_INFO InfoStruct
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetFileGetInfo function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ ULONG entriesRead;
+ ULONG totalEntries;
+ ULONG resumeHandle = FileId;
+
+ ServerName;
+
+ //
+ // Make sure that the caller is allowed to get file information in the
+ // server.
+ //
+
+ error = SsCheckAccess(
+ &SsFileSecurityObject,
+ SRVSVC_FILE_INFO_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ error = FileEnumCommon(
+ NULL,
+ NULL,
+ Level,
+ (LPBYTE *)InfoStruct,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ &resumeHandle,
+ TRUE
+ );
+
+ if ( entriesRead == 0 ) {
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+ SS_ASSERT( error != NO_ERROR || entriesRead == 1 );
+
+ return error;
+
+} // NetrFileGetInfo
+
+
+NET_API_STATUS
+FileEnumCommon (
+ IN LPTSTR BasePath,
+ IN LPTSTR UserName,
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL,
+ IN BOOLEAN IsGetInfo
+ )
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( Level != 2 && Level != 3 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+#ifdef UNICODE
+ RtlInitUnicodeString( &srp->Name1, BasePath );
+ RtlInitUnicodeString( &srp->Name2, UserName );
+#else
+ {
+ NTSTATUS status;
+ OEM_STRING ansiString;
+ RtlInitString( &ansiString, BasePath );
+ status = RtlOemStringToUnicodeString( &srp->Name1, &ansiString, TRUE );
+ RtlInitString( &ansiString, UserName );
+ status = RtlOemStringToUnicodeString( &srp->Name2, &ansiString, TRUE );
+ }
+#endif
+
+ srp->Level = Level;
+ if ( IsGetInfo ) {
+ srp->Flags = SRP_RETURN_SINGLE_ENTRY;
+ }
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_FILE_ENUM,
+ srp,
+ (PVOID *)Buffer,
+ PreferredMaximumLength
+ );
+
+ //
+ // Set up return information. Only change the resume handle if at
+ // least one entry was returned.
+ //
+
+ *EntriesRead = srp->Parameters.Get.EntriesRead;
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+ if ( *EntriesRead > 0 && ARGUMENT_PRESENT( ResumeHandle ) ) {
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+#ifndef UNICODE
+ RtlFreeUnicodeString( &srp->Name1 );
+ RtlFreeUnicodeString( &srp->Name2 );
+#endif
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // FileEnumCommon
diff --git a/private/net/svcdlls/srvsvc/server/internal.c b/private/net/svcdlls/srvsvc/server/internal.c
new file mode 100644
index 000000000..d038cfa85
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/internal.c
@@ -0,0 +1,214 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Internal.c
+
+Abstract:
+
+ This module contains "internal" APIs exported by the server service.
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+
+#include <debugfmt.h>
+#include <tstr.h>
+#include <lmerr.h>
+
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetrServerSetServiceBitsEx (
+ IN LPTSTR ServerName,
+ IN LPTSTR EmulatedServerName OPTIONAL,
+ IN LPTSTR TransportName OPTIONAL,
+ IN DWORD ServiceBitsOfInterest,
+ IN DWORD ServiceBits,
+ IN DWORD UpdateImmediately
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the value of the Server Type as sent in server
+ announcement messages. It is an internal API used only by the
+ service controller.
+
+Arguments:
+
+ ServerName - Used by RPC to direct the call. This API may only be
+ issued locally. This is enforced by the client stub.
+
+ EmulatedServerName - server name being emulated on this computer
+
+ TransportName - parameter optionally giving specific transport for which
+ to set the bits
+
+ ServiceBitsOfInterest - bit mask indicating significant 'ServiceBits'
+
+ ServiceBits - Bits (preassigned to various components by Microsoft)
+ indicating which services are active. This field is not
+ interpreted by the server service.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or ERROR_NOT_SUPPORTED.
+
+--*/
+
+{
+ BOOL changed = FALSE;
+ PNAME_LIST_ENTRY Service;
+ PTRANSPORT_LIST_ENTRY transport;
+ DWORD newBits;
+ NET_API_STATUS error;
+ CHAR serverNameBuf[ MAX_PATH ];
+ PCHAR emulatedName;
+ ULONG namelen;
+
+ ServerName; // avoid compiler warnings
+
+ if( ARGUMENT_PRESENT( EmulatedServerName ) ) {
+ UNICODE_STRING name;
+
+ RtlInitUnicodeString( &name, EmulatedServerName );
+
+ error = ConvertStringToTransportAddress( &name, serverNameBuf, &namelen );
+ if( error != NERR_Success ) {
+ return error;
+ }
+
+ emulatedName = serverNameBuf;
+
+ } else {
+
+ emulatedName = SsServerTransportAddress;
+ namelen = SsServerTransportAddressLength;
+ }
+
+ //
+ // Don't let bits that are controlled by the server be set.
+ //
+
+ ServiceBitsOfInterest &= ~SERVER_TYPE_INTERNAL_BITS;
+ ServiceBits &= ServiceBitsOfInterest;
+
+ //
+ // Make the modifications under control of the service resource.
+ //
+
+ (VOID)RtlAcquireResourceExclusive( &SsServerInfoResource, TRUE );
+
+#ifdef SRV_PNP_POWER
+ if( SsServerNameList == NULL && !ARGUMENT_PRESENT( TransportName ) ) {
+
+ //
+ // We have not bound to any transports yet.
+ // Remember the setting which is being asked for so we can use it later
+ //
+
+ SsData.ServiceBits &= ~ServiceBitsOfInterest;
+ SsData.ServiceBits |= ServiceBits;
+ RtlReleaseResource( &SsServerInfoResource );
+ return NO_ERROR;
+ }
+#endif
+
+ //
+ // Find the entry for the server name of interest
+ //
+ for( Service = SsServerNameList; Service != NULL; Service = Service->Next ) {
+
+ if( Service->TransportAddressLength != namelen ) {
+ continue;
+ }
+
+ if( RtlEqualMemory( emulatedName, Service->TransportAddress, namelen ) ) {
+ break;
+ }
+ }
+
+ if( Service == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return NERR_NetNameNotFound;
+ }
+
+#ifdef SRV_PNP_POWER
+
+ if( SsData.ServiceBits != 0 && Service->PrimaryName ) {
+ Service->ServiceBits = SsData.ServiceBits;
+ SsData.ServiceBits = 0;
+ }
+
+#endif
+
+ if( ARGUMENT_PRESENT( TransportName ) ) {
+ //
+ // Transport name specified. Set the bits for that transport only.
+ //
+
+ for( transport = Service->Transports; transport != NULL; transport = transport->Next ) {
+ if( !STRCMPI( TransportName, transport->TransportName ) ) {
+ //
+ // This is the transport of interest!
+ //
+ if( (transport->ServiceBits & ServiceBitsOfInterest) != ServiceBits ) {
+ transport->ServiceBits &= ~ServiceBitsOfInterest;
+ transport->ServiceBits |= ServiceBits;
+ changed = TRUE;
+ }
+ break;
+ }
+ }
+ if( transport == NULL ) {
+ //
+ // The requested transport was not found.
+ //
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_PATH_NOT_FOUND;
+ }
+
+ } else {
+ //
+ // No transport name specified. Change the bits for the whole server
+ //
+
+ if( ( Service->ServiceBits & ServiceBitsOfInterest ) != ServiceBits ) {
+ Service->ServiceBits &= ~ServiceBitsOfInterest;
+ Service->ServiceBits |= ServiceBits;
+ changed = TRUE;
+
+ }
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+
+ if ( changed ) {
+ SsSetExportedServerType( NULL, TRUE, (BOOL)UpdateImmediately );
+ }
+
+ return NO_ERROR;
+
+} // I_NetrServerSetServiceBits
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetrServerSetServiceBits (
+ IN LPTSTR ServerName,
+ IN LPTSTR TransportName OPTIONAL,
+ IN DWORD ServiceBits,
+ IN DWORD UpdateImmediately
+ )
+{
+ return I_NetrServerSetServiceBitsEx (
+ ServerName,
+ NULL,
+ TransportName,
+ 0xFFFFFFFF, // All bits are of interest (just overlay the old bits)
+ ServiceBits,
+ UpdateImmediately
+ );
+}
diff --git a/private/net/svcdlls/srvsvc/server/registry.c b/private/net/svcdlls/srvsvc/server/registry.c
new file mode 100644
index 000000000..92ce6ad6e
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/registry.c
@@ -0,0 +1,2799 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ registry.c
+
+Abstract:
+
+ This module contains registry _access routines for the NT server
+ service.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 19-Mar-1992
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "ssreg.h"
+#include "srvconfg.h"
+
+#include <tstr.h>
+
+#include <netevent.h>
+
+//
+// Simple MIN and MAX macros. Watch out for side effects!
+//
+
+#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
+#define MAX(a,b) ( ((a) < (b)) ? (b) : (a) )
+
+#define MAX_INTEGER_STRING 32
+
+#define MB * 1024 * 1024
+#define INF 0xffffffff
+
+//
+// ( u, n )
+// u is units to allocate for every n megabytes on a medium server.
+//
+
+#define CONFIG_TUPLE_SIZE 2
+typedef struct {
+ DWORD initworkitems[CONFIG_TUPLE_SIZE];
+ DWORD maxworkitems[CONFIG_TUPLE_SIZE];
+ DWORD rawworkitems[CONFIG_TUPLE_SIZE];
+ DWORD maxrawworkitems[CONFIG_TUPLE_SIZE];
+ DWORD maxpagedmemoryusage[CONFIG_TUPLE_SIZE];
+ DWORD maxnonpagedmemoryusage[CONFIG_TUPLE_SIZE];
+} CONFIG_SERVER_TABLE;
+
+CONFIG_SERVER_TABLE MedSrvCfgTbl = {
+
+//
+// ** NOTE ** : If the second column is greater than 4, then
+// you will need to add a check to make sure the statistic
+// did not drop to zero.
+//
+// Units / MB
+// Parameter
+// ---------
+//
+/* initworkitems */ { 1 , 4 },
+/* maxworkitems */ { 4 , 1 },
+/* rawworkitems */ { 1 , 4 },
+/* maxrawworkitems */ { 4 , 1 },
+/* maxpagedmemoryusage */ { 1 , 1 },
+/* maxnonpagedmemoryusage */ { 1 , 8 },
+
+};
+
+//
+// Minimum configuration system size is 8MB. Anything lower treated
+// as if 8 MB.
+//
+
+#define MIN_SYSTEM_SIZE 8
+
+//
+// A medium server reaches its max at 32M. A small server at 16M.
+//
+
+#define MAX_SMALL_SIZE 16
+#define MAX_MEDIUM_SIZE 32
+
+//
+// Note that the user limit is always -1 (unlimited). Autodisconnect
+// always defaults to 15 minutes.
+//
+
+//
+// Forward declarations
+//
+
+NTSTATUS
+EnumerateStickyShare (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NET_API_STATUS
+FillStickyShareInfo(
+ IN PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo,
+ IN PSHARE_INFO_502 Shi502
+ );
+
+NTSTATUS
+GetSdFromRegistry(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+BOOLEAN
+GetStickyShareInfo (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN PUNICODE_STRING RemarkString,
+ IN PUNICODE_STRING PathString,
+ OUT PSHARE_INFO_502 shi502
+ );
+
+LONG
+LoadParameters (
+ PWCH Path
+ );
+
+LONG
+LoadSizeParameter (
+ VOID
+ );
+
+NTSTATUS
+RecreateStickyShare (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+SaveSdToRegistry(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PWSTR ShareName
+ );
+
+NTSTATUS
+SetSizeParameters (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+SetStickyParameter (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+
+ULONG
+SsRtlQueryEnvironmentLength (
+ IN PVOID Environment
+ )
+{
+ PWCH p;
+ ULONG length;
+
+ p = Environment;
+ ASSERT( p != NULL );
+
+ //
+ // The environment variable block consists of zero or more null
+ // terminated ASCII strings. Each string is of the form:
+ //
+ // name=value
+ //
+ // where the null termination is after the value.
+ //
+
+ while ( *p ) {
+ while ( *p ) {
+ p++;
+ }
+ p++;
+ }
+ p++;
+ length = (PCHAR)p - (PCHAR)Environment;
+
+ //
+ // Return accumulated length.
+ //
+
+ return length;
+}
+
+
+VOID
+SsAddParameterToRegistry (
+ PFIELD_DESCRIPTOR Field,
+ PVOID Value
+ )
+{
+ NTSTATUS status;
+ PWCH valueName;
+ DWORD valueType;
+ LPBYTE valuePtr;
+ DWORD valueDataLength;
+
+ //
+ // The value name is the parameter name and the value data is the
+ // parameter value.
+ //
+
+ valueName = Field->FieldName;
+
+ switch ( Field->FieldType ) {
+
+ case BOOLEAN_FIELD:
+ case DWORD_FIELD:
+ valueType = REG_DWORD;
+ valuePtr = Value;
+ valueDataLength = sizeof(DWORD);
+ break;
+
+ case LPSTR_FIELD:
+ valueType = REG_SZ;
+ valuePtr = *(LPBYTE *)Value;
+ if ( valuePtr != NULL ) {
+ valueDataLength = SIZE_WSTR( (PWCH)valuePtr );
+ } else {
+ valueDataLength = 0;
+ }
+ break;
+
+ }
+
+ //
+ // Set the value into the Parameters key.
+ //
+
+ status = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PARAMETERS_REGISTRY_PATH,
+ valueName,
+ valueType,
+ valuePtr,
+ valueDataLength
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddParameterToRegistry: SetValue failed: %lx; "
+ "parameter %ws won't stick\n", status, valueName ));
+ }
+ }
+
+ return;
+
+} // SsAddParameterToRegistry
+
+
+VOID
+SsAddShareToRegistry (
+ IN PSHARE_INFO_2 ShareInfo2,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL
+ )
+{
+ NTSTATUS status;
+ PWCH valueName;
+ PVOID environment;
+ UNICODE_STRING nameString;
+ UNICODE_STRING valueString;
+ WCHAR integerString[MAX_INTEGER_STRING + 1];
+ ULONG environmentLength;
+
+ //
+ // Build the value name and data strings. The value name is the
+ // share name (netname), while the value data is share information
+ // in REG_MULTI_SZ format. To build the value data, we use the
+ // RTL environment routines.
+ //
+
+ valueName = ShareInfo2->shi2_netname;
+
+ status = RtlCreateEnvironment( FALSE, &environment );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: CreateEnvironment failed: %lx; "
+ "share %ws won't stick\n", status, valueName ));
+ }
+ goto exit1;
+ }
+
+ RtlInitUnicodeString( &nameString, PATH_VARIABLE_NAME );
+ RtlInitUnicodeString( &valueString, ShareInfo2->shi2_path );
+
+ status = RtlSetEnvironmentVariable(
+ &environment,
+ &nameString,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
+ "share %s won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+
+ if ( ShareInfo2->shi2_remark != NULL ) {
+
+ RtlInitUnicodeString( &nameString, REMARK_VARIABLE_NAME );
+ RtlInitUnicodeString( &valueString, ShareInfo2->shi2_remark );
+
+ status = RtlSetEnvironmentVariable(
+ &environment,
+ &nameString,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
+ "share %s won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+
+ }
+
+ RtlInitUnicodeString( &nameString, TYPE_VARIABLE_NAME );
+ valueString.Buffer = integerString;
+ valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
+ status = RtlIntegerToUnicodeString(
+ ShareInfo2->shi2_type,
+ 10,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
+ "share %ws won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+ status = RtlSetEnvironmentVariable(
+ &environment,
+ &nameString,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
+ "share %s won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+
+ RtlInitUnicodeString( &nameString, PERMISSIONS_VARIABLE_NAME );
+ valueString.Buffer = integerString;
+ valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
+ status = RtlIntegerToUnicodeString(
+ ShareInfo2->shi2_permissions,
+ 10,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
+ "share %ws won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+ status = RtlSetEnvironmentVariable(
+ &environment,
+ &nameString,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
+ "share %s won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+
+ RtlInitUnicodeString( &nameString, MAXUSES_VARIABLE_NAME );
+ valueString.Buffer = integerString;
+ valueString.MaximumLength = (MAX_INTEGER_STRING + 1) * sizeof(WCHAR);
+ status = RtlIntegerToUnicodeString(
+ ShareInfo2->shi2_max_uses,
+ 10,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: IntegerToUnicode failed: %lx; "
+ "share %ws won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+ status = RtlSetEnvironmentVariable(
+ &environment,
+ &nameString,
+ &valueString
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SetEnvironment failed: %lx; "
+ "share %s won't stick\n", status, valueName ));
+ }
+ goto exit2;
+ }
+
+ //
+ // Set the value into the Shares key.
+ //
+
+ environmentLength = SsRtlQueryEnvironmentLength( environment );
+ status = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ SHARES_REGISTRY_PATH,
+ valueName,
+ REG_MULTI_SZ,
+ (LPBYTE)environment,
+ environmentLength
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SetValue failed: %lx; share %ws "
+ "won't stick\n", status, valueName ));
+ }
+ }
+
+ //
+ // Save the file security descriptor
+ //
+
+ if ( ARGUMENT_PRESENT( SecurityDescriptor ) ) {
+
+ status = SaveSdToRegistry(
+ SecurityDescriptor,
+ valueName
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsAddShareToRegistry: SaveSd failed: %lx; share %ws\n"
+ , status, valueName ));
+ }
+ }
+ }
+
+exit2:
+ RtlDestroyEnvironment( environment );
+
+exit1:
+
+ return;
+
+} // SsAddShareToRegistry
+
+
+NET_API_STATUS
+SsBindToTransports (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the registry to bind to specified transports.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - success/failure of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG numberOfBindings = 0;
+ RTL_QUERY_REGISTRY_TABLE queryTable[2];
+
+ //
+ // Ask the RTL to call us back for each subvalue in the MULTI_SZ
+ // value \LanmanServer\Linkage\Bind.
+ //
+
+ queryTable[0].QueryRoutine = BindToTransport;
+ queryTable[0].Flags = 0;
+ queryTable[0].Name = 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;
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ LINKAGE_REGISTRY_PATH,
+ queryTable,
+ &numberOfBindings,
+ NULL
+ );
+
+ //
+ // If the above failed to bind to any transports, fail to start the
+ // server.
+ //
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsBindToTransports: RtlQueryRegistryValues failed: "
+ "%lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+ }
+
+ if ( numberOfBindings == 0 ) {
+
+ SsLogEvent(
+ EVENT_SRV_NO_TRANSPORTS_BOUND,
+ 0,
+ NULL,
+ NO_ERROR
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsBindToTransports: no bindings created\n" ));
+ }
+ return ERROR_INVALID_PARAMETER; // !!! Need better error
+ }
+
+ //
+ // See if there any optional bindings we should perform
+ //
+ queryTable[0].QueryRoutine = BindOptionalNames;
+ queryTable[0].Flags = 0;
+ queryTable[0].Name = 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;
+
+ (void)RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ LINKAGE_REGISTRY_PATH,
+ queryTable,
+ NULL,
+ NULL
+ );
+
+ return NO_ERROR;
+}
+
+NET_API_STATUS
+SsCheckRegistry (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function verifies that the keys used by the server exist.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - success/failure of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ LPWSTR subStrings[1];
+
+ //
+ // Verify the existence of the main server service key. If this
+ // fails, the server service fails to start.
+ //
+
+ status = RtlCheckRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ SERVER_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = SERVER_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_KEY_NOT_FOUND,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsCheckRegistry: main key doesn't exist\n" ));
+ }
+ return ERROR_INVALID_PARAMETER; // !!! Need better error
+
+ }
+
+ //
+ // Verify the existence of the Linkage subkey. If this fails, the
+ // server service fails to start.
+ //
+
+ status = RtlCheckRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ LINKAGE_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = LINKAGE_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_KEY_NOT_FOUND,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsCheckRegistry: Linkage subkey doesn't exist\n" ));
+ }
+ return ERROR_INVALID_PARAMETER; // !!! Need better error
+
+ }
+
+ //
+ // If the Parameters subkey doesn't exist, create it. If it can't
+ // be created, fail to start the server.
+ //
+
+ status = RtlCheckRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ PARAMETERS_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ status = RtlCreateRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ PARAMETERS_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = PARAMETERS_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_KEY_NOT_CREATED,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsCheckRegistry: Can't create Parameters subkey: "
+ "%lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+
+ }
+
+ }
+
+ //
+ // If the AutotunedParameters subkey doesn't exist, create it. If
+ // it can't be created, fail to start the server.
+ //
+
+ status = RtlCheckRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ AUTOTUNED_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ status = RtlCreateRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ AUTOTUNED_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = AUTOTUNED_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_KEY_NOT_CREATED,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsCheckRegistry: Can't create AutotunedParameters "
+ "subkey: %lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+
+ }
+
+ }
+
+ //
+ // If the Shares subkey doesn't exist, create it. If it can't be
+ // created, fail to start the server.
+ //
+
+ status = RtlCheckRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ SHARES_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ status = RtlCreateRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ SHARES_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_KEY_NOT_CREATED,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsCheckRegistry: Can't create Shares subkey: "
+ "%lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+
+ }
+
+ }
+
+ //
+ // If the Shares Security subkey doesn't exist, create it. If it
+ // can't be created, fail to start the server.
+ //
+
+ status = RtlCheckRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ SHARES_SECURITY_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ status = RtlCreateRegistryKey(
+ RTL_REGISTRY_SERVICES,
+ SHARES_SECURITY_REGISTRY_PATH
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = SHARES_SECURITY_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_KEY_NOT_CREATED,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsCheckRegistry: Can't create Shares Security subkey: "
+ "%lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+
+ }
+
+ }
+
+ //
+ // All keys successfully checked.
+ //
+
+ return NO_ERROR;
+
+} // SsCheckRegistry
+
+
+NET_API_STATUS
+SsEnumerateStickyShares (
+ IN OUT PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the registry to find and return sticky shares.
+
+Arguments:
+
+ ShareEnumInfo - points to a structure that contains the parameters
+ to the NetShareEnumSticky call.
+
+Return Value:
+
+ NET_API_STATUS - success/failure of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PRTL_QUERY_REGISTRY_TABLE queryTable;
+
+ ShareEnumInfo->TotalBytesNeeded = 0;
+ ShareEnumInfo->TotalEntries = 0;
+ ShareEnumInfo->EntriesRead = 0;
+
+ //
+ // Initialize the reserve fields. This tells the callback routine,
+ // how many times it has been called.
+ //
+
+ ShareEnumInfo->ShareEnumIndex = 0;
+ ShareEnumInfo->StartOfFixedData = (PCHAR)ShareEnumInfo->OutputBuffer;
+ ShareEnumInfo->EndOfVariableData = (PCHAR)ShareEnumInfo->OutputBuffer +
+ ShareEnumInfo->OutputBufferLength;
+
+ //
+ // We need to align it since we deal with unicode strings.
+ //
+
+ ShareEnumInfo->EndOfVariableData =
+ (PCHAR)((ULONG)ShareEnumInfo->EndOfVariableData & ~1);
+
+ //
+ // Ask the RTL to call us back for each value in the Shares key.
+ //
+
+ queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
+
+ if ( queryTable != NULL ) {
+
+ queryTable[0].QueryRoutine = EnumerateStickyShare;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ queryTable[0].Name = NULL;
+ 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;
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ SHARES_REGISTRY_PATH,
+ queryTable,
+ ShareEnumInfo,
+ NULL
+ );
+
+ MIDL_user_free( queryTable );
+
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsEnumerateStickyShares: RtlQueryRegistryValues "
+ "failed: %lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+ }
+
+ return NO_ERROR;
+
+} // SsEnumerateStickyShares
+
+
+NET_API_STATUS
+SsLoadConfigurationParameters (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the registry to get server configuration parameters. These
+ server parameters must be set before the server FSP has been
+ started.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - success/failure of the operation.
+
+--*/
+
+{
+ LONG error;
+
+ //
+ // Get the basic Size parameter, then load autotuned parameters,
+ // then load manually set parameters. This ordering allows manual
+ // settings to override autotuning.
+ //
+
+ error = LoadSizeParameter( );
+
+ if ( error == NO_ERROR ) {
+
+ error = LoadParameters( AUTOTUNED_REGISTRY_PATH );
+
+ if ( error == NO_ERROR ) {
+
+ error = LoadParameters( PARAMETERS_REGISTRY_PATH );
+
+ }
+
+ }
+
+ //
+ // The copy read to MDL read switchover must occur at or below the
+ // SMB buffer size.
+ //
+
+ SsData.ServerInfo598.sv598_mdlreadswitchover =
+ MIN(
+ SsData.ServerInfo598.sv598_mdlreadswitchover,
+ SsData.ServerInfo599.sv599_sizreqbuf);
+
+ //
+ // Override parameters that cannot be set on WinNT (vs. NTAS).
+ //
+ // The server itself also performs most of these overrides, in case
+ // somebody figures out the FSCTL that changes parameters. We also
+ // override in the service in order to keep the service's view
+ // consistent with the server's. If you make any changes here, also
+ // make them in srv\svcsrv.c.
+ //
+ if ( SsData.ServerInfo598.sv598_producttype == NtProductWinNt ) {
+
+ //
+ // On WinNT, the maximum value of certain parameters is fixed at
+ // build time. These include: concurrent users, SMB buffers,
+ // and threads.
+ //
+
+#define MINIMIZE(_param,_max) _param = MIN( _param, _max );
+
+ MINIMIZE( SsData.ServerInfo102.sv102_users, MAX_USERS_WKSTA );
+ MINIMIZE( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS_WKSTA );
+ MINIMIZE( SsData.ServerInfo598.sv598_maxthreadsperqueue, MAX_THREADS_WKSTA );
+
+ //
+ // On WinNT, we do not cache closed RFCBs.
+ //
+
+ SsData.ServerInfo598.sv598_cachedopenlimit = 0;
+
+ //
+ // Sharing of redirected drives is not allowed on WinNT.
+ //
+
+ SsData.ServerInfo599.sv599_enablesharednetdrives = FALSE;
+
+ }
+
+ return error;
+
+} // SsLoadConfigurationParameters
+
+
+NET_API_STATUS
+SsRecreateStickyShares (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the registry to find and create sticky shares.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - success/failure of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PRTL_QUERY_REGISTRY_TABLE queryTable;
+ ULONG IterationCount = 0;
+
+ //
+ // Ask the RTL to call us back for each value in the Shares key.
+ //
+
+ queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
+
+ if ( queryTable != NULL ) {
+
+ queryTable[0].QueryRoutine = RecreateStickyShare;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ queryTable[0].Name = NULL;
+ 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;
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ SHARES_REGISTRY_PATH,
+ queryTable,
+ &IterationCount,
+ NULL
+ );
+
+ MIDL_user_free( queryTable );
+
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsRecreateStickyShares: RtlQueryRegistryValues "
+ "failed: %lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+ }
+
+ return NO_ERROR;
+
+} // SsRecreateStickyShares
+
+
+NET_API_STATUS
+SsRemoveShareFromRegistry (
+ LPWSTR NetName
+ )
+{
+ NET_API_STATUS error = NO_ERROR;
+ NTSTATUS status;
+ PWCH valueName;
+
+ //
+ // The value name is the share name. Remove that value from the
+ // Shares key.
+ //
+
+ valueName = NetName;
+
+ //
+ // Delete the share security
+ //
+
+ status = RtlDeleteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ SHARES_SECURITY_REGISTRY_PATH,
+ valueName
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsRemoveShareFromRegistry: Delete Security value failed: %lx; "
+ "share %ws will return\n", status, valueName ));
+ }
+ }
+
+ //
+ // Delete the share
+ //
+
+ status = RtlDeleteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ SHARES_REGISTRY_PATH,
+ valueName
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SsRemoveShareFromRegistry: DeleteValue failed: %lx; "
+ "share %ws will return\n", status, valueName ));
+ }
+
+ error = RtlNtStatusToDosError( status );
+ }
+
+ return error;
+
+} // SsRemoveShareFromRegistry
+
+
+NTSTATUS
+BindToTransport (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ NTSTATUS status;
+ NET_API_STATUS error;
+ PULONG numberOfBindings = Context;
+ SERVER_TRANSPORT_INFO_0 svti0;
+ LPWSTR subStrings[2];
+
+ ValueName, ValueLength, EntryContext;
+
+ //
+ // The value type must be REG_SZ (translated from REG_MULTI_SZ by
+ // the RTL).
+ //
+
+ if ( ValueType != REG_SZ ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = LINKAGE_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "BindToTransports: skipping invalid value %ws\n",
+ ValueName ));
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // The value data is the name of the transport device object.
+ //
+
+ RtlZeroMemory( &svti0, sizeof( svti0 ) );
+ svti0.svti0_transportname = ValueData;
+ svti0.svti0_transportaddress = SsServerTransportAddress;
+ svti0.svti0_transportaddresslength =
+ ComputeTransportAddressClippedLength(
+ SsServerTransportAddress,
+ SsServerTransportAddressLength );
+
+ //
+ // Bind to the transport.
+ //
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SsBindToTransports: binding to transport %ws\n",
+ ValueData ));
+ }
+
+ AnnounceServiceStatus( 1 );
+
+ error = I_NetrServerTransportAddEx( 0, (LPTRANSPORT_INFO)&svti0 );
+
+ if ( error != NO_ERROR ) {
+
+ DWORD eventId;
+
+ //
+ // In general, we do not fail server startup just because we
+ // failed to bind to a single transport. Instead, we keep a
+ // count of the number of bindings we have, and in
+ // SsBindToTransports, after attempting all transports listed in
+ // the registry, only if no bindings were made do we fail server
+ // startup.
+ //
+ // The exception to the rule is that we do not start the server
+ // service if we get a duplicate name error for any transport.
+ // This is considered to be a "user error".
+ //
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SsBindToTransports: failed to bind to %ws: "
+ "%ld\n", ValueData, error ));
+ }
+
+ eventId = EVENT_SRV_CANT_BIND_TO_TRANSPORT;
+ status = STATUS_SUCCESS; // assume not duplicate name
+
+ if ( error == ERROR_DUP_NAME ) {
+ eventId = EVENT_SRV_CANT_BIND_DUP_NAME;
+ status = STATUS_DUPLICATE_NAME;
+ *numberOfBindings = 0;
+ }
+
+ subStrings[0] = ValueData;
+ SsLogEvent(
+ eventId,
+ 1,
+ subStrings,
+ error
+ );
+
+ return status;
+
+ }
+
+ (*numberOfBindings)++;
+ return STATUS_SUCCESS;
+
+} // BindToTransport
+
+NTSTATUS
+BindNameToTransport (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ SERVER_TRANSPORT_INFO_0 sti;
+ UCHAR serverName[ MAX_PATH ];
+ UNICODE_STRING UnicodeName;
+ NET_API_STATUS error;
+ LPWSTR subStrings[2];
+ ULONG namelen;
+
+ subStrings[0] = (LPWSTR)ValueData;
+ subStrings[1] = OPTIONAL_NAMES_VALUE_NAME;
+
+ if( ValueType != REG_SZ ) {
+
+ //
+ // Not a string!
+ //
+
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ return STATUS_SUCCESS;
+ }
+
+ UnicodeName.Length = wcslen( (LPWSTR)ValueData ) * sizeof( WCHAR );
+ UnicodeName.MaximumLength = UnicodeName.Length + sizeof( WCHAR );
+ UnicodeName.Buffer = (LPWSTR)ValueData;
+
+ error = ConvertStringToTransportAddress( &UnicodeName, serverName, &namelen );
+
+ if( error != NO_ERROR ) {
+
+ //
+ // Invalid server name!
+ //
+
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ error
+ );
+
+ return STATUS_SUCCESS;
+ }
+
+ RtlZeroMemory( &sti, sizeof(sti) );
+ sti.svti0_transportname = (LPWSTR)Context;
+ sti.svti0_transportaddress = serverName;
+ sti.svti0_transportaddresslength = namelen;
+
+ //
+ // Adding the transport make take some time. Better announce our status
+ //
+ AnnounceServiceStatus( 1 );
+
+ error = I_NetrServerTransportAddEx( 0, (LPTRANSPORT_INFO)&sti );
+
+ if ( error != NO_ERROR ) {
+
+ //
+ // Could not register the name!
+ //
+
+ subStrings[0] = (LPWSTR)ValueData;
+ subStrings[1] = OPTIONAL_NAMES_VALUE_NAME;
+
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ error
+ );
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BindOptionalNames (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ RTL_QUERY_REGISTRY_TABLE queryTable[2];
+ NTSTATUS status;
+
+ ValueName, ValueLength, EntryContext;
+
+ //
+ // The value type must be REG_SZ (translated from REG_MULTI_SZ by
+ // the RTL).
+ //
+ if ( ValueType != REG_SZ ) {
+ //
+ // This error was already logged in BindToTransport
+ //
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // The value data is the name of the transport device object. Now
+ // we need to iterate over the optional names and bind them to this
+ // transport.
+ //
+
+ //
+ // Now see if there any optional bindings we should perform
+ //
+ queryTable[0].QueryRoutine = BindNameToTransport;
+ queryTable[0].Flags = 0;
+ queryTable[0].Name = OPTIONAL_NAMES_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;
+
+
+ (void)RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ PARAMETERS_REGISTRY_PATH,
+ queryTable,
+ ValueData, // pass the transport name on down
+ NULL
+ );
+
+ return STATUS_SUCCESS;
+
+} // BindToTransport
+
+NTSTATUS
+EnumerateStickyShare (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ Callback routine for SsEnumerateStickyShare. Routine will get information
+ on share and fill in the output buffer.
+
+Arguments:
+
+ ValueName - Name of the share
+ ValueType - Value type of the share name.
+ ValueData - Data associated with the ValueName.
+ Context - Pointer to our enum information structure.
+
+Return Value:
+
+ NET_API_STATUS - success/failure of the operation.
+
+--*/
+{
+
+ NET_API_STATUS error;
+ SHARE_INFO_502 shi502;
+ UNICODE_STRING pathString;
+ UNICODE_STRING remarkString;
+ PSRVSVC_SHARE_ENUM_INFO enumInfo = (PSRVSVC_SHARE_ENUM_INFO) Context;
+
+ ValueLength, EntryContext;
+
+ remarkString.Buffer = NULL;
+ pathString.Buffer = NULL;
+
+ if ( GetStickyShareInfo(
+ ValueName,
+ ValueType,
+ ValueData,
+ &remarkString,
+ &pathString,
+ &shi502
+ ) ) {
+
+ //
+ // Do the actual add of the share.
+ //
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "EnumerateStickyShares: adding share %ws\n", ValueName ));
+ }
+
+ shi502.shi502_remark = remarkString.Buffer;
+ shi502.shi502_path = pathString.Buffer;
+
+ //
+ // Skip until we have the right share to resume from
+ //
+
+ if ( (enumInfo->TotalEntries == 0) &&
+ (enumInfo->ShareEnumIndex < enumInfo->ResumeHandle) ) {
+
+ enumInfo->ShareEnumIndex++;
+
+ } else {
+
+ enumInfo->TotalEntries++;
+ error = FillStickyShareInfo( enumInfo, &shi502 );
+
+ if ( error != NO_ERROR ) {
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "EnumerateStickyShares: failed to add share "
+ "%ws = %wZ: %ld\n", ValueName, &pathString, error ));
+ }
+ } else {
+ enumInfo->EntriesRead++;
+ enumInfo->ResumeHandle++;
+ }
+ }
+
+ //
+ // free buffers allocated by GetStickyShareInfo
+ //
+
+ if ( remarkString.Buffer != NULL ) {
+ RtlFreeUnicodeString( &remarkString );
+ }
+
+ if ( pathString.Buffer != NULL ) {
+ RtlFreeUnicodeString( &pathString );
+ }
+
+ if ( shi502.shi502_security_descriptor != NULL ) {
+ MIDL_user_free( shi502.shi502_security_descriptor );
+ }
+
+ }
+
+ return STATUS_SUCCESS;
+
+} // EnumerateStickyShare
+
+
+NTSTATUS
+GetSdFromRegistry(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PSECURITY_DESCRIPTOR fileSD = NULL;
+ PSHARE_INFO_502 shi502 = (PSHARE_INFO_502) Context;
+ LPWSTR subStrings[1];
+
+ EntryContext, ValueName, ValueType;
+
+ if ( ValueLength > 0 ) {
+
+ fileSD = MIDL_user_allocate( ValueLength );
+
+ if ( fileSD == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+
+ RtlCopyMemory(
+ fileSD,
+ ValueData,
+ ValueLength
+ );
+
+ if ( !RtlValidSecurityDescriptor( fileSD ) ) {
+
+ subStrings[0] = ValueName;
+ SsLogEvent(
+ EVENT_SRV_INVALID_SD,
+ 1,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ MIDL_user_free( fileSD );
+ status = STATUS_INVALID_SECURITY_DESCR;
+ }
+ }
+ }
+
+ shi502->shi502_security_descriptor = fileSD;
+ return(status);
+
+} // GetSdFromRegistry
+
+
+BOOLEAN
+GetStickyShareInfo (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ OUT PUNICODE_STRING RemarkString,
+ OUT PUNICODE_STRING PathString,
+ OUT PSHARE_INFO_502 shi502
+ )
+
+/*++
+
+Routine Description:
+
+ Gets share information from the registry.
+
+Arguments:
+
+ ValueName - Name of the share
+ ValueType - Value type of the share name.
+ ValueData - Data associated with the ValueName.
+ RemarkString - Upon return, points to a unicode string containing the
+ user remark for this share.
+ PathString - Upon return, points to a unicode string containing the
+ path for this share.
+ shi502 - Upon return, points to a unicode string containing a
+ SHARE_INFO_502 structure.
+
+Return Value:
+
+ TRUE, if share information successfully retrieved.
+ FALSE, otherwise.
+
+--*/
+
+{
+
+ NTSTATUS status;
+ UNICODE_STRING variableNameString;
+ WCHAR integerStringBuffer[35];
+ UNICODE_STRING unicodeString;
+ LPWSTR subStrings[2];
+
+ PathString->Buffer = NULL;
+ RemarkString->Buffer = NULL;
+
+ shi502->shi502_security_descriptor = NULL;
+ shi502->shi502_path = NULL;
+ shi502->shi502_remark = NULL;
+ shi502->shi502_reserved = 0;
+
+ //
+ // Because the NT server doesn't support share-level security, the
+ // password is always NULL.
+ //
+
+ shi502->shi502_passwd = NULL;
+
+ //
+ // The value type must be REG_MULTI_SZ, and the value name must not
+ // be null.
+ //
+
+ if ( (ValueType != REG_MULTI_SZ) ||
+ (wcslen(ValueName) == 0) ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: skipping invalid value %ws\n",
+ ValueName ));
+ }
+ goto errorexit;
+
+ }
+
+ //
+ // The share name is the value name. The value data describes the
+ // rest of the information about the share.
+ //
+
+ shi502->shi502_netname = ValueName;
+
+ //
+ // The REG_MULTI_SZ format is the same as that used for storing
+ // environment variables. Find known share parameters in the data.
+ //
+ // Get the share path. It must be present.
+ //
+
+ RtlInitUnicodeString( &variableNameString, PATH_VARIABLE_NAME );
+
+ PathString->MaximumLength = 0;
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ PathString
+ );
+ if ( status != STATUS_BUFFER_TOO_SMALL ) {
+
+ //
+ // The path is not specified. Ignore this share.
+ //
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: No path; ignoring share.\n" ));
+ }
+ goto errorexit;
+
+ }
+
+ PathString->MaximumLength = (USHORT)(PathString->Length + sizeof(WCHAR));
+ PathString->Buffer = MIDL_user_allocate( PathString->MaximumLength );
+
+ if ( PathString->Buffer == NULL ) {
+
+ //
+ // No space for path. Ignore this share.
+ //
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ ERROR_NOT_ENOUGH_MEMORY
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: MIDL_user_allocate failed; ignoring "
+ "share.\n" ));
+ }
+ goto errorexit;
+
+ }
+
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ PathString
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ //
+ // Huh? The second attempt failed. Ignore this share.
+ //
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: Second query failed! Ignoring "
+ "share.\n" ));
+ }
+ goto errorexit;
+
+ }
+
+ //
+ // Get the remark. It may be omitted.
+ //
+
+ RtlInitUnicodeString( &variableNameString, REMARK_VARIABLE_NAME );
+
+ RemarkString->MaximumLength = 0;
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ RemarkString
+ );
+ if ( status == STATUS_BUFFER_TOO_SMALL ) {
+
+ RemarkString->MaximumLength =
+ (USHORT)(RemarkString->Length + sizeof(WCHAR));
+ RemarkString->Buffer =
+ MIDL_user_allocate( RemarkString->MaximumLength );
+ if ( RemarkString->Buffer == NULL ) {
+
+ //
+ // No space for remark. Ignore this share.
+ //
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ ERROR_NOT_ENOUGH_MEMORY
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: MIDL_user_allocate failed; ignoring "
+ "share.\n" ));
+ }
+ goto errorexit;
+
+ }
+
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ RemarkString
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ //
+ // Huh? The second attempt failed. Ignore this share.
+ //
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: Second query failed! "
+ "Ignoring share.\n" ));
+ }
+ goto errorexit;
+
+ }
+
+ }
+
+ //
+ // Get the share type. It may be omitted.
+ //
+
+ RtlInitUnicodeString( &variableNameString, TYPE_VARIABLE_NAME );
+
+ unicodeString.Buffer = integerStringBuffer;
+ unicodeString.MaximumLength = 35;
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ &unicodeString
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ shi502->shi502_type = STYPE_DISKTREE;
+
+ } else {
+
+ status = RtlUnicodeStringToInteger(
+ &unicodeString,
+ 0,
+ &shi502->shi502_type
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: UnicodeToInteger failed: "
+ "%lx\n", status ));
+ }
+ goto errorexit;
+
+ }
+
+ }
+
+ //
+ // Get the share permissions. It may be omitted.
+ //
+
+ RtlInitUnicodeString( &variableNameString, PERMISSIONS_VARIABLE_NAME );
+
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ &unicodeString
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ shi502->shi502_permissions = 0;
+
+ } else {
+
+ status = RtlUnicodeStringToInteger(
+ &unicodeString,
+ 0,
+ &shi502->shi502_permissions
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: UnicodeToInteger failed: "
+ "%lx\n", status ));
+ }
+ goto errorexit;
+
+ }
+
+ }
+
+ //
+ // Get the maximum number of uses allowed. It may be omitted.
+ //
+
+ RtlInitUnicodeString( &variableNameString, MAXUSES_VARIABLE_NAME );
+
+ status = RtlQueryEnvironmentVariable_U(
+ ValueData,
+ &variableNameString,
+ &unicodeString
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ shi502->shi502_max_uses = (DWORD)SHI_USES_UNLIMITED;
+
+ } else {
+
+ status = RtlUnicodeStringToInteger(
+ &unicodeString,
+ 0,
+ &shi502->shi502_max_uses
+ );
+ if ( !NT_SUCCESS(status) ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = SHARES_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ RtlNtStatusToDosError( status )
+ );
+
+ goto errorexit;
+
+ }
+
+ }
+
+ {
+ //
+ // Get the Share file security descriptor
+ //
+
+ RTL_QUERY_REGISTRY_TABLE shareQueryTable[2];
+
+ //
+ // Fill up the query table
+ //
+
+ shareQueryTable[0].QueryRoutine = GetSdFromRegistry;
+ shareQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ shareQueryTable[0].Name = shi502->shi502_netname;
+ shareQueryTable[0].EntryContext = NULL;
+ shareQueryTable[0].DefaultType = REG_NONE;
+
+ shareQueryTable[1].QueryRoutine = NULL;
+ shareQueryTable[1].Flags = 0;
+ shareQueryTable[1].Name = NULL;
+
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ SHARES_SECURITY_REGISTRY_PATH,
+ shareQueryTable,
+ shi502,
+ NULL
+ );
+
+ if ( !NT_SUCCESS( status) &&
+ ( status != STATUS_OBJECT_NAME_NOT_FOUND ) ) {
+ ASSERT(0);
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "GetStickyShareInfo: Get file SD: "
+ "%lx\n", status ));
+ }
+ goto errorexit;
+ }
+ }
+
+ return TRUE;
+
+errorexit:
+
+ if ( RemarkString->Buffer != NULL ) {
+ RtlFreeUnicodeString( RemarkString );
+ }
+
+ if ( PathString->Buffer != NULL ) {
+ RtlFreeUnicodeString( PathString );
+ }
+
+ if ( shi502->shi502_security_descriptor != NULL ) {
+ MIDL_user_free( shi502->shi502_security_descriptor );
+ }
+
+ return FALSE;
+
+} // GetStickyShareInfo
+
+
+LONG
+LoadParameters (
+ PWCH Path
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the registry to get server parameters.
+
+Arguments:
+
+ Path - PARAMETERS_REGISTRY_PATH or AUTOTUNED_REGISTRY_PATH
+
+Return Value:
+
+ LONG - success/failure of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PRTL_QUERY_REGISTRY_TABLE queryTable;
+ ULONG numberOfBindings = 0;
+
+ //
+ // Ask the RTL to call us back for each value in the appropriate
+ // key.
+ //
+
+ queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
+
+ if ( queryTable != NULL ) {
+
+ queryTable[0].QueryRoutine = SetStickyParameter;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ queryTable[0].Name = NULL;
+ 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;
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ Path,
+ queryTable,
+ Path, // Context for SetStickyParameter
+ NULL
+ );
+
+ MIDL_user_free( queryTable );
+
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "LoadParameters: RtlQueryRegistryValues failed: "
+ "%lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+ }
+
+ return NO_ERROR;
+
+} // LoadParameters
+
+
+LONG
+LoadSizeParameter (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the registry to get the basic server Size parameter.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ LONG - success/failure of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PRTL_QUERY_REGISTRY_TABLE queryTable;
+ ULONG numberOfBindings = 0;
+
+ //
+ // Ask the RTL to call us back if the Size parameter exists.
+ //
+
+ queryTable = MIDL_user_allocate( sizeof(RTL_QUERY_REGISTRY_TABLE) * 2 );
+
+ if ( queryTable != NULL ) {
+
+ queryTable[0].QueryRoutine = SetSizeParameters;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ queryTable[0].Name = SIZE_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;
+
+ status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
+ PARAMETERS_REGISTRY_PATH,
+ queryTable,
+ NULL,
+ NULL
+ );
+
+ MIDL_user_free( queryTable );
+
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "LoadSizeParameter: RtlQueryRegistryValues failed: "
+ "%lx\n", status ));
+ }
+ return RtlNtStatusToDosError( status );
+ }
+
+ return NO_ERROR;
+
+} // LoadSizeParameter
+
+VOID
+PrintShareAnnounce (
+ DWORD event
+ )
+{
+ ULONG i;
+
+ //
+ // Announce ourselves and then wait for awhile.
+ // If the event gets signaled, terminate the loop and this thread.
+ // But don't do this forever, since the print subsystem may actually
+ // get stuck
+ //
+
+ //
+ // Do it for 15 minutes
+ //
+ for( i=0; i < 60; i++ ) {
+
+ AnnounceServiceStatus( 1 );
+
+ if( WaitForSingleObject( (HANDLE)event, 15*1000 ) != WAIT_TIMEOUT ) {
+ break;
+ }
+ }
+}
+
+
+NTSTATUS
+RecreateStickyShare (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PULONG IterationCount,
+ IN PVOID EntryContext
+ )
+{
+
+ NET_API_STATUS error;
+ SHARE_INFO_502 shi502;
+ SHARE_INFO shareInfo;
+ UNICODE_STRING pathString;
+ UNICODE_STRING remarkString;
+ HANDLE threadHandle = NULL;
+ HANDLE event = NULL;
+
+ ValueLength, EntryContext;
+
+ remarkString.Buffer = NULL;
+ pathString.Buffer = NULL;
+
+
+ if ( GetStickyShareInfo(
+ ValueName,
+ ValueType,
+ ValueData,
+ &remarkString,
+ &pathString,
+ &shi502
+ ) ) {
+
+ //
+ // Do the actual add of the share.
+ //
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "RecreateStickyShares: adding share %ws\n", ValueName ));
+ }
+
+ shi502.shi502_remark = remarkString.Buffer;
+ shi502.shi502_path = pathString.Buffer;
+
+ shareInfo.ShareInfo502 = (LPSHARE_INFO_502_I)&shi502;
+
+ if( shi502.shi502_type == STYPE_PRINTQ ) {
+ //
+ // A really big problem is that FAX printers can take aribitrarily long to
+ // complete the eventual OpenPrinter() call which the server will make back
+ // up to srvsvc. And if we don't announce ourselves in the interval, the
+ // service controller will presume that we got stuck on startup. Since
+ // NetrShareAdd() is synchronous, we need to get a different thread to
+ // announce our service status until NetrShareAdd returns. So, start it
+ // now. This is most unfortunate.
+
+ event = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ if( event != NULL ) {
+ DWORD threadId;
+
+ threadHandle = CreateThread(
+ NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)PrintShareAnnounce,
+ (LPVOID)event,
+ 0,
+ &threadId
+ );
+ if( threadHandle == NULL ) {
+ CloseHandle( event );
+ }
+ }
+ }
+
+ //
+ // RecreateStickyShare is called during server initialization. The service
+ // controller will presume that we're stuck if we don't update our status
+ // with it often enough. So every 64 recreated shares we call back to it.
+ // There's nothing magic about the 64 -- easy to check for, and not too often.
+ //
+ if( (shi502.shi502_type == STYPE_PRINTQ && threadHandle == NULL) ||
+ (++(*IterationCount) & 63 ) == 0 ) {
+
+ AnnounceServiceStatus( 1 );
+ }
+
+ error = NetrShareAdd( NULL, 502, &shareInfo, NULL );
+
+ if( event != NULL ) {
+ //
+ // We created an announcement thread, set the event telling it to terminate
+ //
+ SetEvent( event );
+
+ //
+ // Wait for the thread to terminate
+ //
+ if( WaitForSingleObject( threadHandle, INFINITE ) == WAIT_FAILED ) {
+ error = GetLastError();
+ }
+
+ //
+ // Close the handles
+ //
+ CloseHandle( event );
+ CloseHandle( threadHandle );
+ }
+
+ if ( error != NO_ERROR ) {
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "RecreateStickyShares: failed to add share "
+ "%ws = %wZ: %ld\n", ValueName, &pathString, error ));
+ }
+ }
+
+ //
+ // free buffers allocated by GetStickyShareInfo
+ //
+
+ if ( remarkString.Buffer != NULL ) {
+ RtlFreeUnicodeString( &remarkString );
+ }
+
+ if ( pathString.Buffer != NULL ) {
+ RtlFreeUnicodeString( &pathString );
+ }
+
+ if ( shi502.shi502_security_descriptor != NULL ) {
+ MIDL_user_free( shi502.shi502_security_descriptor );
+ }
+
+ }
+
+ return NO_ERROR;
+
+} // RecreateStickyShare
+
+
+NTSTATUS
+SaveSdToRegistry(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PWSTR ShareName
+ )
+/*++
+
+Routine Description:
+
+ Stores the share file security descriptor in the registry.
+
+Arguments:
+
+ SecurityDescriptor - Points to a self-relative security descriptor
+ describing the access rights for files under this share.
+
+ ShareName - Points to a string containing the share name under
+ which the SD is to be stored.
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+
+ //
+ // Store the security descriptor
+ //
+
+ ULONG fileSDLength;
+
+ if ( !RtlValidSecurityDescriptor( SecurityDescriptor ) ) {
+
+ status = STATUS_INVALID_SECURITY_DESCR;
+
+ } else {
+
+ fileSDLength = RtlLengthSecurityDescriptor( SecurityDescriptor );
+
+ status = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ SHARES_SECURITY_REGISTRY_PATH,
+ ShareName,
+ REG_BINARY,
+ (LPBYTE)SecurityDescriptor,
+ fileSDLength
+ );
+
+ }
+
+ return status;
+
+} // SaveSdToRegistry
+
+
+NTSTATUS
+SetSizeParameters (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ NT_PRODUCT_TYPE productType;
+ DWORD size;
+
+ LPWSTR subStrings[2];
+
+ ValueLength, Context, EntryContext;
+
+ //
+ // Get the product type.
+ //
+
+ if ( !RtlGetNtProductType( &productType ) ) {
+ productType = NtProductWinNt;
+ }
+
+ SsData.ServerInfo598.sv598_producttype = productType;
+
+ //
+ // Make sure that we got called for the right value.
+ //
+
+ ASSERT( _wcsicmp( ValueName, SIZE_VALUE_NAME ) == 0 );
+
+ //
+ // The Size value must be a DWORD, and must be in the following
+ // range:
+ //
+ // 0 -> use defaults
+ // 1 -> small server (minimize memory usage)
+ // 2 -> medium server (balance)
+ // 3 -> large server (maximize connections)
+ //
+
+ if ( ValueType == REG_DWORD ) {
+ ASSERT( ValueLength == sizeof(DWORD) );
+ size = *(LPDWORD)ValueData;
+ }
+
+ if ( (ValueType != REG_DWORD) || (size > 3) ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = PARAMETERS_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SetSizeParameters: skipping invalid value "
+ "%ws\n", ValueName ));
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ SsData.ServerInfo598.sv598_serversize = size;
+
+ //
+ // Set appropriate fields based on the product type (Windows NT or
+ // Advanced Server) and the selected Size. Note that a Size of 0
+ // doesn't change any of the defaults.
+ //
+ // Note that the user limit is always -1 (unlimited). Autodisconnect
+ // always defaults to 15 minutes.
+ //
+
+ if ( size != 0 ) {
+
+ SYSTEM_BASIC_INFORMATION basicInfo;
+ NTSTATUS status;
+ ULONG noOfMb;
+ ULONG factor;
+ ULONG asFactor;
+
+ //
+ // Get system memory size.
+ //
+
+ status = NtQuerySystemInformation(
+ SystemBasicInformation,
+ &basicInfo,
+ sizeof( SYSTEM_BASIC_INFORMATION ),
+ NULL
+ );
+
+
+ if ( status != STATUS_SUCCESS ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = PARAMETERS_REGISTRY_PATH;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SetSizeParameters: NtQuerySystemInfo failed %x\n",
+ status ));
+ }
+ return STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Note that we first divide the page size by 512 in order to
+ // allow for physical memory sizes above 2^32-1. With this
+ // calculation, we can handle up to two terabytes of physical
+ // memory. The calculation assumes that the page size is at
+ // least 512, and is not very accurate if the page size is not
+ // a power of 2 (very unlikely).
+ //
+
+ ASSERT( basicInfo.PageSize >= 512 );
+
+ noOfMb = (((basicInfo.PageSize / 512) *
+ basicInfo.NumberOfPhysicalPages) +
+ (1 MB / 512 - 1)) / (1 MB / 512);
+
+ //
+ // Minimum is 8 MB
+ //
+
+ noOfMb = MAX( MIN_SYSTEM_SIZE, noOfMb );
+
+ //
+ // Set the maximum for the different sizes
+ //
+
+ if ( size == 1 ) {
+ noOfMb = MIN( noOfMb, MAX_SMALL_SIZE );
+ } else if ( size == 2 ) {
+ noOfMb = MIN( noOfMb, MAX_MEDIUM_SIZE );
+ }
+ }
+
+ //
+ // If small, assume the system size is half of the real one.
+ // This should give us half the paramater values of a medium server.
+ // If large, double it. Also set the free connection count.
+ //
+
+ if ( size == 1 ) {
+
+ //
+ // Small
+ //
+
+ factor = (noOfMb + 1) / 2;
+
+ SsData.ServerInfo599.sv599_minfreeconnections = 2;
+ SsData.ServerInfo599.sv599_maxfreeconnections = 2;
+
+ } else if ( size == 2 ) {
+
+ //
+ // Balanced
+ //
+
+ factor = noOfMb;
+
+ SsData.ServerInfo599.sv599_minfreeconnections = 2;
+ SsData.ServerInfo599.sv599_maxfreeconnections = 4;
+
+ } else {
+
+ //
+ // Large
+ //
+
+ factor = noOfMb * 2;
+
+ SsData.ServerInfo599.sv599_minfreeconnections = 4;
+ SsData.ServerInfo599.sv599_maxfreeconnections = 8;
+ }
+
+ //
+ // If this is an Advanced Server with at least 24M, some
+ // parameter will need to be even bigger.
+ //
+
+ asFactor = 1;
+ if ( (productType != NtProductWinNt) && (noOfMb >= 24) ) asFactor = 2;
+
+ //
+ // Now set the values for a medium server with this much memory.
+ //
+
+ SsData.ServerInfo599.sv599_maxworkitems =
+ MedSrvCfgTbl.maxworkitems[0] * factor * asFactor /
+ MedSrvCfgTbl.maxworkitems[1];
+
+ SsData.ServerInfo599.sv599_initworkitems =
+ MedSrvCfgTbl.initworkitems[0] * factor * asFactor /
+ MedSrvCfgTbl.initworkitems[1];
+
+ SsData.ServerInfo599.sv599_rawworkitems =
+ MedSrvCfgTbl.rawworkitems[0] * factor /
+ MedSrvCfgTbl.rawworkitems[1];
+
+ SsData.ServerInfo598.sv598_maxrawworkitems =
+ MedSrvCfgTbl.maxrawworkitems[0] * factor * asFactor /
+ MedSrvCfgTbl.maxrawworkitems[1];
+
+ SsData.ServerInfo599.sv599_maxworkitems =
+ MIN( SsData.ServerInfo599.sv599_maxworkitems, MAX_MAXWORKITEMS );
+ SsData.ServerInfo599.sv599_initworkitems =
+ MIN( SsData.ServerInfo599.sv599_initworkitems, MAX_INITWORKITEMS/4 );
+ SsData.ServerInfo599.sv599_rawworkitems =
+ MIN( SsData.ServerInfo599.sv599_rawworkitems, MAX_RAWWORKITEMS/4 );
+ SsData.ServerInfo598.sv598_maxrawworkitems =
+ MIN( SsData.ServerInfo598.sv598_maxrawworkitems, MAX_MAXRAWWORKITEMS );
+
+ if ( (productType != NtProductWinNt) || (size == 3) ) {
+ SsData.ServerInfo599.sv599_maxpagedmemoryusage = INF;
+ SsData.ServerInfo599.sv599_maxnonpagedmemoryusage = INF;
+ } else {
+ SsData.ServerInfo599.sv599_maxpagedmemoryusage =
+ MedSrvCfgTbl.maxpagedmemoryusage[0] * factor /
+ MedSrvCfgTbl.maxpagedmemoryusage[1] MB;
+
+ SsData.ServerInfo599.sv599_maxpagedmemoryusage =
+ MAX( SsData.ServerInfo599.sv599_maxpagedmemoryusage,
+ MIN_MAXPAGEDMEMORYUSAGE);
+
+ SsData.ServerInfo599.sv599_maxnonpagedmemoryusage =
+ MedSrvCfgTbl.maxnonpagedmemoryusage[0] * factor /
+ MedSrvCfgTbl.maxnonpagedmemoryusage[1] MB;
+
+ SsData.ServerInfo599.sv599_maxnonpagedmemoryusage =
+ MAX( SsData.ServerInfo599.sv599_maxnonpagedmemoryusage,
+ MIN_MAXNONPAGEDMEMORYUSAGE);
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+} // SetSizeParameters
+
+
+NTSTATUS
+SetStickyParameter (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+{
+ NET_API_STATUS error;
+ DWORD i;
+ PFIELD_DESCRIPTOR foundField = NULL;
+ LPWSTR subStrings[2];
+
+ ValueLength, EntryContext;
+
+ //
+ // Ignore several parameters, since they are handled elsewhere
+ //
+ if( (_wcsicmp( ValueName, SIZE_VALUE_NAME ) == 0) ||
+ (_wcsicmp( ValueName, NULL_SESSION_SHARES_VALUE_NAME ) == 0) ||
+ (_wcsicmp( ValueName, NULL_SESSION_PIPES_VALUE_NAME ) == 0) ||
+ (_wcsicmp( ValueName, PIPES_NEED_LICENSE_VALUE_NAME ) == 0) ||
+ (_wcsicmp( ValueName, ERROR_LOG_IGNORE_VALUE_NAME ) == 0) ||
+ (_wcsicmp( ValueName, OPTIONAL_NAMES_VALUE_NAME ) == 0 ) ) {
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Determine which field we need to set, based on the value
+ // name.
+ //
+ // NOTE: For Daytona, disc and comment are now invalid registry names.
+ // We use their more famous aliases autodisconnect and srvcomment
+ // instead. If we get more of these cases, we should consider adding
+ // a field to the FIELD_DESCRIPTOR structure that indicates whether
+ // the names are should appear on the registry or not. Any change
+ // here should also be made to SsSetField().
+ //
+
+ if ( (_wcsicmp( ValueName, DISC_VALUE_NAME ) != 0) &&
+ (_wcsicmp( ValueName, COMMENT_VALUE_NAME ) != 0) ) {
+
+ for ( i = 0;
+ SsServerInfoFields[i].FieldName != NULL;
+ i++ ) {
+
+ if ( _wcsicmp( ValueName, SsServerInfoFields[i].FieldName ) == 0 ) {
+ foundField = &SsServerInfoFields[i];
+ break;
+ }
+ }
+ }
+
+ if ( foundField == NULL || foundField->Settable == NOT_SETTABLE ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = Context;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SetStickyParameter: ignoring %s \"%ws\"\n",
+ (foundField == NULL ? "unknown value name" :
+ "unsettable value"), ValueName ));
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ switch ( foundField->FieldType ) {
+
+ case BOOLEAN_FIELD:
+ case DWORD_FIELD:
+
+ if ( ValueType != REG_DWORD ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = Context;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SetStickyParameter: skipping invalid value "
+ "%ws\n", ValueName ));
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ i = *(LPDWORD)ValueData;
+ break;
+
+ case LPSTR_FIELD:
+
+ if ( ValueType != REG_SZ ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = Context;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SetStickyParameter: skipping invalid value "
+ "%ws\n", ValueName ));
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ i = (DWORD)ValueData;
+ break;
+
+ }
+
+ //
+ // Set the field.
+ //
+
+ error = SsSetField( foundField, &i, FALSE, NULL );
+
+ if ( error != NO_ERROR ) {
+
+ subStrings[0] = ValueName;
+ subStrings[1] = Context;
+ SsLogEvent(
+ EVENT_SRV_INVALID_REGISTRY_VALUE,
+ 2,
+ subStrings,
+ error
+ );
+
+ IF_DEBUG(REGISTRY) {
+ SS_PRINT(( "SetStickyParameter: error %ld ignored in setting "
+ "parameter \"%ws\"n", error, ValueName ));
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+} // SetStickyParameter
+
diff --git a/private/net/svcdlls/srvsvc/server/scavengr.c b/private/net/svcdlls/srvsvc/server/scavengr.c
new file mode 100644
index 000000000..87bb309d6
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/scavengr.c
@@ -0,0 +1,1319 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ Scavengr.c
+
+Abstract:
+
+ This module contains the code for the server service scavenger
+ thread. This thread handles announcements and configuration
+ changes. (Although originally written to run in a separate thread,
+ this code now runs in the initial thread of the server service.
+
+Author:
+
+ David Treadwell (davidtr) 17-Apr-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "ssreg.h"
+
+#include <netlibnt.h>
+#include <tstr.h>
+
+#define INCLUDE_SMB_TRANSACTION
+#undef NT_PIPE_PREFIX
+#include <smbtypes.h>
+#include <smb.h>
+#include <smbtrans.h>
+#include <smbgtpt.h>
+
+#include <hostannc.h>
+#include <ntddbrow.h>
+#include <lmerr.h>
+
+#define TERMINATION_SIGNALED 0
+#define ANNOUNCE_SIGNALED 1
+#define STATUS_CHANGED 2
+#define REGISTRY_CHANGED 3 // Must be the last one!
+
+#define NUMBER_OF_EVENTS 4
+
+
+//
+// Bias request announcements by SERVER_REQUEST_ANNOUNCE_DELTA SECONDS
+//
+
+#define SERVER_REQUEST_ANNOUNCE_DELTA 30
+
+//
+// Forward declarations.
+//
+
+VOID
+Announce (
+ IN BOOL DoNtAnnouncement,
+ IN DWORD NtInterval,
+ IN BOOL DoLmAnnouncement,
+ IN BOOL TerminationAnnouncement
+ );
+
+NET_API_STATUS
+SendSecondClassMailslot (
+ IN LPTSTR Transport OPTIONAL,
+ IN PVOID Message,
+ IN DWORD MessageLength,
+ IN LPTSTR Domain,
+ IN LPSTR MailslotNameText,
+ IN UCHAR SignatureByte
+ );
+
+NET_API_STATUS
+SsBrowserIoControl (
+ IN DWORD IoControlCode,
+ IN PVOID Buffer,
+ IN DWORD BufferLength,
+ IN PLMDR_REQUEST_PACKET Packet,
+ IN DWORD PacketLength
+ );
+
+
+DWORD
+ComputeAnnounceTime (
+ IN DWORD LastAnnouncementTime,
+ IN DWORD Interval
+ )
+
+/*++
+
+Routine Description:
+
+ Compute the time to wait (in milliseconds) until the next announcement should
+ be made.
+
+Arguments:
+
+ LastAnnouncementTime - Time (in milliseconds since reboot) when the last
+ announcement was made.
+
+ Interval - Interval (in seconds) between announcements
+
+Return Value:
+
+ Timeout period (in milliseconds)
+
+--*/
+
+{
+ DWORD AnnounceDelta;
+ DWORD Timeout;
+ DWORD CurrentTime;
+
+ //
+ // Get the current time.
+ //
+
+ CurrentTime = GetTickCount();
+
+ //
+ // If the clock has gone backward,
+ // send an announcement now.
+ //
+
+ if ( LastAnnouncementTime > CurrentTime ) {
+ return 0;
+ }
+
+ //
+ // Convert the announcement period from seconds to milliseconds.
+ //
+
+ Timeout = Interval * 1000;
+
+ //
+ // Add in the random announce delta which helps prevent lots of
+ // servers from announcing at the same time.
+ //
+
+ AnnounceDelta = SsData.ServerInfo102.sv102_anndelta;
+
+ Timeout += ((rand( ) * AnnounceDelta * 2) / RAND_MAX) -
+ AnnounceDelta;
+
+ //
+ // If our time has expired,
+ // send an announcement now.
+ //
+
+ if ( (CurrentTime - LastAnnouncementTime) >= Timeout ) {
+ return 0;
+ }
+
+ //
+ // Adjust our timeout period for time already elapsed.
+ //
+
+ return Timeout - (CurrentTime - LastAnnouncementTime);
+
+}
+
+
+DWORD
+SsScavengerThread (
+ IN LPVOID lpThreadParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the server service scavenger thread.
+
+Arguments:
+
+ lpThreadParameter - ignored.
+
+Return Value:
+
+ NET_API_STATUS - thread termination result.
+
+--*/
+
+{
+ HANDLE events[ NUMBER_OF_EVENTS ];
+ ULONG numEvents = NUMBER_OF_EVENTS-1;
+ UNICODE_STRING unicodeEventName;
+ OBJECT_ATTRIBUTES obja;
+ DWORD waitStatus;
+ DWORD timeout;
+
+ DWORD LmTimeout;
+ BOOL DoLmAnnouncement;
+ DWORD LmLastAnnouncementTime;
+
+ DWORD NtTimeout;
+ BOOL DoNtAnnouncement;
+ DWORD NtLastAnnouncementTime;
+ DWORD NtInterval;
+
+ NTSTATUS status;
+ BOOL hidden = TRUE;
+ HKEY hParameters = INVALID_HANDLE_VALUE;
+
+ lpThreadParameter;
+
+ //
+ // Use the scavenger termination event to know when we're supposed
+ // to wake up and kill ourselves.
+ //
+
+ events[TERMINATION_SIGNALED] = SsTerminationEvent;
+
+ //
+ // Initialize the NT announcement interval to the LM announcement interval
+ //
+
+ NtInterval = SsData.ServerInfo102.sv102_announce;
+ DoLmAnnouncement = TRUE;
+ DoNtAnnouncement = TRUE;
+
+ //
+ // Create the announce event. When this gets signaled, we wake up
+ // and do an announcement. We use a synchronization event rather
+ // than a notification event so that we don't have to worry about
+ // resetting the event after we wake up.
+ //
+
+ //
+ // Please note that we create this event with OBJ_OPENIF. We do this
+ // to allow the browser to signal the server to force an announcement.
+ //
+ // The bowser will create this event as a part of the bowser
+ // initialization, and will set it to the signalled state when it needs
+ // to have the server announce.
+ //
+
+
+ RtlInitUnicodeString( &unicodeEventName, SERVER_ANNOUNCE_EVENT_W );
+ InitializeObjectAttributes( &obja, &unicodeEventName, OBJ_OPENIF, NULL, NULL );
+
+ status = NtCreateEvent(
+ &SsAnnouncementEvent,
+ SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
+ &obja,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ SS_PRINT(( "SsScavengerThread: NtCreateEvent failed: %X\n",
+ status ));
+ return NetpNtStatusToApiStatus( status );
+ }
+
+ events[ANNOUNCE_SIGNALED] = SsAnnouncementEvent;
+
+ //
+ // Create an unnamed event to be set to the signalled state when the
+ // service status changes (or a local application requests an
+ // announcement)
+ //
+
+ InitializeObjectAttributes( &obja, NULL, OBJ_OPENIF, NULL, NULL );
+
+ status = NtCreateEvent(
+ &SsStatusChangedEvent,
+ SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
+ &obja,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ SS_PRINT(( "SsScavengerThread: NtCreateEvent failed: %X\n",
+ status ));
+
+ NtClose( SsAnnouncementEvent );
+ SsAnnouncementEvent = NULL;
+
+ return NetpNtStatusToApiStatus( status );
+ }
+
+ events[STATUS_CHANGED] = SsStatusChangedEvent;
+
+ //
+ // Put a watch on the registry for any changes that happen in the
+ // null session share or pipe list. Don't bail out if this fails,
+ // because we've done this as a convenience in adding new null
+ // session-reliant servers. It doesn't really affect the normal
+ // operation of the server if this doesn't work.
+ //
+ events[ REGISTRY_CHANGED ] = INVALID_HANDLE_VALUE;
+ status = NtCreateEvent(
+ &events[ REGISTRY_CHANGED ],
+ SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ if ( NT_SUCCESS(status) ) {
+ status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ FULL_PARAMETERS_REGISTRY_PATH,
+ 0,
+ KEY_NOTIFY,
+ &hParameters
+ );
+
+ if( status == ERROR_SUCCESS ) {
+ (void)RegNotifyChangeKeyValue( hParameters,
+ TRUE,
+ REG_NOTIFY_CHANGE_LAST_SET,
+ events[ REGISTRY_CHANGED ],
+ TRUE
+ );
+ //
+ // Add this event to the list of events we're waiting for
+ //
+ ++numEvents;
+ }
+ }
+
+ //
+ // Seed the random number generator. We use it to generate random
+ // announce deltas.
+ //
+
+ srand( (int)SsAnnouncementEvent );
+
+ //
+ // Do an announcement immediately for startup, then loop announcing
+ // based on the announce interval.
+ //
+
+ waitStatus = WAIT_TIMEOUT;
+
+ do {
+
+
+
+ //
+ // Act according to whether the termination event, the announce
+ // event, or the timeout caused us to wake up.
+ //
+ // !!! Or the configuration event indicating a configuration
+ // change notification.
+
+ if ( waitStatus == WAIT_OBJECT_0 + TERMINATION_SIGNALED ) {
+
+ SS_PRINT(( "Scavenger: termination event signaled\n" ));
+
+ //
+ // The scavenger termination event was signaled, so we have
+ // to gracefully kill this thread. If this is not a hidden
+ // server, announce the fact that we're going down.
+ //
+
+ if ( !hidden ) {
+ Announce( TRUE, NtInterval, TRUE, TRUE );
+ }
+
+ //
+ // Close the announcement event.
+ //
+
+ NtClose( SsAnnouncementEvent );
+
+ SsAnnouncementEvent = NULL;
+
+ //
+ // Close the Registry watch event.
+ //
+ if( events[ REGISTRY_CHANGED ] != INVALID_HANDLE_VALUE )
+ NtClose( events[ REGISTRY_CHANGED ] );
+
+ //
+ // Close the Registry handle
+ //
+ if( hParameters != INVALID_HANDLE_VALUE )
+ RegCloseKey( hParameters );
+
+ //
+ // Return to caller.
+ //
+
+ return NO_ERROR;
+
+ } else if( waitStatus == WAIT_OBJECT_0 + REGISTRY_CHANGED ) {
+ //
+ // Somebody changed some server parameters. Tell the driver
+ //
+ SS_PRINT(( "SsScavengerThread: Server parameters changed\n" ));
+
+ //
+ // Tell the server FSD to look for a change in the registry
+ //
+ (void)SsServerFsControl( NULL, FSCTL_SRV_REGISTRY_CHANGE, NULL, NULL, 0 );
+
+ //
+ // Turn it back on so we get future changes, too
+ //
+ (void)RegNotifyChangeKeyValue( hParameters,
+ TRUE,
+ REG_NOTIFY_CHANGE_LAST_SET,
+ events[ REGISTRY_CHANGED ],
+ TRUE
+ );
+
+ } else {
+
+ SS_ASSERT( waitStatus == WAIT_TIMEOUT ||
+ waitStatus == WAIT_OBJECT_0 + ANNOUNCE_SIGNALED ||
+ waitStatus == WAIT_OBJECT_0 + STATUS_CHANGED );
+
+ //
+ // If we've timed out,
+ // we've already set the flags indicating whether to announce
+ // on to lanman to NT browsers
+ //
+
+ if ( waitStatus != WAIT_TIMEOUT ) {
+ DoLmAnnouncement = TRUE;
+ DoNtAnnouncement = TRUE;
+ }
+
+ //
+ // If we're not a hidden server, announce ourselves.
+ //
+
+ // Hold the database resource while we do the announcement so
+ // that we get a consistent view of the database.
+ //
+
+ (VOID)RtlAcquireResourceShared( &SsServerInfoResource, TRUE );
+
+ if ( !SsData.ServerInfo102.sv102_hidden ) {
+
+ hidden = FALSE;
+
+ Announce( DoNtAnnouncement, NtInterval, DoLmAnnouncement, FALSE );
+
+
+
+ //
+ // If we were not hidden last time through the loop but
+ // we're hidden now, we've changed to hidden, so announce
+ // that we're going down. This causes clients in the domain
+ // to take us out of their server enumerations.
+ //
+
+ } else if ( !hidden ) {
+
+ hidden = TRUE;
+ Announce( TRUE, NtInterval, TRUE, TRUE );
+
+ }
+
+ //
+ // If the server is hidden, the wait timeout is infinite. We'll
+ // be woken up by the announce event if the server becomes
+ // unhidden.
+ //
+
+ if ( SsData.ServerInfo102.sv102_hidden ) {
+
+ timeout = 0xffffffff;
+
+ } else {
+
+ //
+ // Remember when the last announcement was.
+ //
+
+ if ( DoNtAnnouncement ) {
+ NtLastAnnouncementTime = GetTickCount();
+ }
+
+ if ( DoLmAnnouncement ) {
+ LmLastAnnouncementTime = GetTickCount();
+ }
+
+ //
+ // Compute the time delta to the next announcement
+ //
+ // For NtInterval,
+ // use a local copy of the interval since we compute the correct
+ // value.
+ //
+ // For the Lanman interval,
+ // use the global copy to allow the interval to be changed.
+ //
+
+ NtTimeout = ComputeAnnounceTime(
+ NtLastAnnouncementTime,
+ NtInterval );
+
+ if (SsData.ServerInfo599.sv599_lmannounce) {
+ LmTimeout = ComputeAnnounceTime(
+ LmLastAnnouncementTime,
+ SsData.ServerInfo102.sv102_announce );
+ } else {
+ // Don't awaken this thread to do nothing.
+ LmTimeout = 0xffffffff;
+ }
+
+
+ //
+ // If our NT announcement frequency is less than 12 minutes,
+ // increase our announcement frequency by 4 minutes.
+ //
+
+ if ( NtInterval < 12 * 60 ) {
+
+ NtInterval += 4 * 60;
+
+ if ( NtInterval > 12 * 60) {
+ NtInterval = 12 * 60;
+ }
+ }
+
+ //
+ // Determine which timeout we're actually going to use.
+ //
+
+ if ( NtTimeout == LmTimeout ) {
+ timeout = NtTimeout;
+ DoLmAnnouncement = TRUE;
+ DoNtAnnouncement = TRUE;
+ } else if ( NtTimeout < LmTimeout ) {
+ timeout = NtTimeout;
+ DoLmAnnouncement = FALSE;
+ DoNtAnnouncement = TRUE;
+ } else {
+ timeout = LmTimeout;
+ DoLmAnnouncement = TRUE;
+ DoNtAnnouncement = FALSE;
+ }
+
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+ }
+
+
+ //
+ // Wait for one of the events to be signaled or for the timeout
+ // to elapse.
+ //
+
+ waitStatus = WaitForMultipleObjects( numEvents , events, FALSE, timeout );
+
+ if ( waitStatus == WAIT_OBJECT_0 + ANNOUNCE_SIGNALED ) {
+
+ //
+ // We were awakened because an announce was signalled.
+ // Unless we are a master browser on at least one transport,
+ // delay for a random delta to stagger announcements a bit
+ // to prevent lots of servers from announcing
+ // simultaneously.
+ //
+
+ BOOL isMasterBrowser = FALSE;
+ PNAME_LIST_ENTRY service = SsServerNameList;
+ PTRANSPORT_LIST_ENTRY transport;
+
+ for( service = SsServerNameList;
+ isMasterBrowser == FALSE && service != NULL;
+ service = service->Next ) {
+
+ if( service->ServiceBits & SV_TYPE_MASTER_BROWSER ) {
+ isMasterBrowser = TRUE;
+ break;
+ }
+
+ for( transport=service->Transports; transport != NULL; transport=transport->Next ) {
+ if( transport->ServiceBits & SV_TYPE_MASTER_BROWSER ) {
+ isMasterBrowser = TRUE;
+ break;
+ }
+ }
+ }
+
+ if ( !isMasterBrowser ) {
+ Sleep( ((rand( ) * (SERVER_REQUEST_ANNOUNCE_DELTA * 1000)) / RAND_MAX) );
+ }
+
+ }
+
+ } while ( TRUE );
+
+ return NO_ERROR;
+
+} // SsScavengerThread
+
+
+VOID
+SsAnnounce (
+ IN POEM_STRING OemAnnounceName,
+ IN LPWSTR EmulatedDomainName,
+ IN BOOL DoNtAnnouncement,
+ IN DWORD NtInterval,
+ IN BOOL DoLmAnnouncement,
+ IN BOOL TerminationAnnouncement,
+ IN LPTSTR Transport,
+ IN DWORD serviceType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a broadcast datagram as a second-class mailslot
+ that announces the presence of this server on the network.
+
+Arguments:
+
+ OemAnnounceName - The name we're announcing to the network
+
+ EmulatedDomainName - The name of the domain this announcement is happening for.
+
+ DoNtAnnouncement - Do an Nt-style announcement.
+
+ NtInterval - NT announcement interval (in seconds)
+
+ DoLmAnnouncement - Do an Lm-style announcement.
+
+ TerminationAnnouncement - if TRUE, send the announcement that
+ indicates that this server is going away. Otherwise, send
+ the normal message that tells clients that we're here.
+
+ Transport - Ssupplies the transport to issue the announcement
+ on.
+
+ serviceType - Service bits being announced
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD messageSize;
+ PHOST_ANNOUNCE_PACKET packet;
+ PBROWSE_ANNOUNCE_PACKET browsePacket;
+
+ LPSTR serverName;
+ DWORD oemServerNameLength; // includes the null terminator
+
+ LPSTR serverComment;
+ DWORD serverCommentLength; // includes the null terminator
+ OEM_STRING oemCommentString;
+
+ UNICODE_STRING unicodeCommentString;
+
+ NET_API_STATUS status;
+
+ //
+ // Fill in the necessary information.
+ //
+
+ if( TerminationAnnouncement ) {
+ serviceType &= ~SV_TYPE_SERVER; // since the server is going away!
+ }
+
+ SS_PRINT(( "SsScavengerThread: Announcing for transport %s, Bits: %lx\n",
+ Transport, serviceType ));
+
+ //
+ // Get the length of the oem equivalent of the server name
+ //
+
+ oemServerNameLength = OemAnnounceName->Length + 1;
+
+ //
+ // Convert server comment to a unicode string
+ //
+
+ if ( *SsData.ServerCommentBuffer == '\0' ) {
+ serverCommentLength = 1;
+ } else {
+ unicodeCommentString.Length =
+ (USHORT)(STRLEN( SsData.ServerCommentBuffer ) * sizeof(WCHAR));
+ unicodeCommentString.MaximumLength =
+ (USHORT)(unicodeCommentString.Length + sizeof(WCHAR));
+ unicodeCommentString.Buffer = SsData.ServerCommentBuffer;
+ serverCommentLength =
+ RtlUnicodeStringToOemSize( &unicodeCommentString );
+ }
+
+ oemCommentString.MaximumLength = (USHORT)serverCommentLength;
+
+ messageSize = max(sizeof(HOST_ANNOUNCE_PACKET) + oemServerNameLength +
+ serverCommentLength,
+ sizeof(BROWSE_ANNOUNCE_PACKET) + serverCommentLength);
+
+ //
+ // Get memory to hold the message. If we can't allocate enough
+ // memory, don't send an announcement.
+ //
+
+ packet = MIDL_user_allocate( messageSize );
+ if ( packet == NULL ) {
+ return;
+ }
+
+ //
+ // If we are announcing as a Lan Manager server, broadcast the
+ // announcement.
+ //
+
+ if (SsData.ServerInfo599.sv599_lmannounce && DoLmAnnouncement ) {
+
+ packet->AnnounceType = HostAnnouncement ;
+
+ SmbPutUlong( &packet->HostAnnouncement.Type, serviceType );
+
+ packet->HostAnnouncement.CompatibilityPad = 0;
+
+ packet->HostAnnouncement.VersionMajor =
+ (BYTE)SsData.ServerInfo102.sv102_version_major;
+ packet->HostAnnouncement.VersionMinor =
+ (BYTE)SsData.ServerInfo102.sv102_version_minor;
+
+ SmbPutUshort(
+ &packet->HostAnnouncement.Periodicity,
+ (WORD)SsData.ServerInfo102.sv102_announce
+ );
+
+ //
+ // Convert the server name from unicode to oem
+ //
+
+ serverName = (LPSTR)( &packet->HostAnnouncement.NameComment );
+
+ RtlCopyMemory( serverName, OemAnnounceName->Buffer, OemAnnounceName->Length );
+ serverName[OemAnnounceName->Length] = '\0';
+
+ serverComment = serverName + oemServerNameLength;
+
+ if ( serverCommentLength == 1 ) {
+ *serverComment = '\0';
+ } else {
+
+ oemCommentString.Buffer = serverComment;
+ (VOID) RtlUnicodeStringToOemString(
+ &oemCommentString,
+ &unicodeCommentString,
+ FALSE
+ );
+ }
+
+ SendSecondClassMailslot(
+ Transport,
+ packet,
+ FIELD_OFFSET(HOST_ANNOUNCE_PACKET, HostAnnouncement.NameComment) +
+ oemServerNameLength + serverCommentLength,
+ EmulatedDomainName,
+ "\\MAILSLOT\\LANMAN",
+ 0x00
+ );
+ }
+
+ //
+ // Now announce the server as a Winball server.
+ //
+
+ if ( DoNtAnnouncement ) {
+ browsePacket = (PBROWSE_ANNOUNCE_PACKET)packet;
+
+ browsePacket->BrowseType = ( serviceType & SV_TYPE_MASTER_BROWSER ?
+ LocalMasterAnnouncement :
+ HostAnnouncement );
+
+ browsePacket->BrowseAnnouncement.UpdateCount = 0;
+
+ SmbPutUlong( &browsePacket->BrowseAnnouncement.CommentPointer, (ULONG)((0xaa55 << 16) + (BROWSER_VERSION_MAJOR << 8) + BROWSER_VERSION_MINOR));
+
+ SmbPutUlong( &browsePacket->BrowseAnnouncement.Periodicity, NtInterval * 1000 );
+
+ SmbPutUlong( &browsePacket->BrowseAnnouncement.Type, serviceType );
+
+ browsePacket->BrowseAnnouncement.VersionMajor =
+ (BYTE)SsData.ServerInfo102.sv102_version_major;
+ browsePacket->BrowseAnnouncement.VersionMinor =
+ (BYTE)SsData.ServerInfo102.sv102_version_minor;
+
+ RtlCopyMemory( &browsePacket->BrowseAnnouncement.ServerName,
+ OemAnnounceName->Buffer,
+ OemAnnounceName->Length );
+ browsePacket->BrowseAnnouncement.ServerName[OemAnnounceName->Length] = '\0';
+
+ serverComment = (LPSTR)&browsePacket->BrowseAnnouncement.Comment;
+
+ if ( serverCommentLength == 1 ) {
+ *serverComment = '\0';
+ } else {
+
+ oemCommentString.Buffer = serverComment;
+ (VOID) RtlUnicodeStringToOemString(
+ &oemCommentString,
+ &unicodeCommentString,
+ FALSE
+ );
+ }
+
+#ifdef KLUDGE_NOT_NEEDED // BUGBUG: SendSecondClassMailslot always sends "from" primary computername
+ status = SendSecondClassMailslot(
+ Transport,
+ packet,
+ FIELD_OFFSET(BROWSE_ANNOUNCE_PACKET, BrowseAnnouncement.Comment) +
+ serverCommentLength,
+ EmulatedDomainName,
+ "\\MAILSLOT\\BROWSE",
+ (UCHAR)(serviceType & SV_TYPE_MASTER_BROWSER ?
+ BROWSER_ELECTION_SIGNATURE :
+ MASTER_BROWSER_SIGNATURE)
+ );
+#else
+ status = ERROR_NOT_SUPPORTED;
+#endif // KLUDGE_NOT_NEEDED
+
+ if ( status != NERR_Success ) {
+ UCHAR packetBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAX_PATH)*sizeof(WCHAR)];
+ PLMDR_REQUEST_PACKET requestPacket = (PLMDR_REQUEST_PACKET)packetBuffer;
+ UNICODE_STRING TransportString;
+
+ RtlInitUnicodeString(&TransportString, Transport);
+
+ requestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
+
+ requestPacket->TransportName = TransportString;
+#ifdef _CAIRO_
+ RtlInitUnicodeString( &requestPacket->EmulatedDomainName, EmulatedDomainName );
+#endif // _CAIRO_
+
+ requestPacket->Type = Datagram;
+
+ requestPacket->Parameters.SendDatagram.DestinationNameType = (serviceType & SV_TYPE_MASTER_BROWSER ? BrowserElection : MasterBrowser);
+
+ requestPacket->Parameters.SendDatagram.MailslotNameLength = 0;
+
+ //
+ // The domain announcement name is special, so we don't have to specify
+ // a destination name for it.
+ //
+
+ requestPacket->Parameters.SendDatagram.NameLength = STRLEN(EmulatedDomainName)*sizeof(TCHAR);
+
+ STRCPY(requestPacket->Parameters.SendDatagram.Name, EmulatedDomainName);
+
+ //
+ // This is a simple IoControl - It just sends the datagram.
+ //
+
+ status = SsBrowserIoControl(IOCTL_LMDR_WRITE_MAILSLOT,
+ packet,
+ FIELD_OFFSET(BROWSE_ANNOUNCE_PACKET, BrowseAnnouncement.Comment) +
+ serverCommentLength,
+ requestPacket,
+ FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.SendDatagram.Name)+
+ requestPacket->Parameters.SendDatagram.NameLength);
+ }
+ }
+
+ MIDL_user_free( packet );
+
+} // SsAnnounce
+
+
+ULONG
+ComputeTransportAddressClippedLength(
+ IN PCHAR TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the length of the transport address with the trailing
+ blanks removed.
+
+Arguments:
+
+ TransportAddress - Transport address with potentially trailing blanks
+
+ TransportAddressLength - Length of the Transport Address including trailing
+ blanks
+
+Return Value:
+
+ Length of the Transport Address excluding trailing blanks.
+
+--*/
+
+{
+ PCHAR p;
+
+ //
+ // Cut off any trailing spaces
+ //
+ p = &TransportAddress[ TransportAddressLength ];
+ for( ; p > TransportAddress && *(p-1) == ' '; p-- )
+ ;
+
+ return p - TransportAddress;
+}
+
+
+
+VOID
+Announce (
+ IN BOOL DoNtAnnouncement,
+ IN DWORD NtInterval,
+ IN BOOL DoLmAnnouncement,
+ IN BOOL TerminationAnnouncement
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a broadcast datagram as a second-class mailslot
+ that announces the presence of this server using all
+ of the configured server names and all networks.
+
+Arguments:
+
+ DoNtAnnouncement - Do an Nt-style announcement.
+
+ NtInterval - NT announcement interval (in seconds)
+
+ DoLmAnnouncement - Do an Lm-style announcement.
+
+ TerminationAnnouncement - if TRUE, send the announcement that
+ indicates that this server is going away. Otherwise, send
+ the normal message that tells clients that we're here.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNAME_LIST_ENTRY Service;
+ PTRANSPORT_LIST_ENTRY Transport;
+ NTSTATUS status;
+ OEM_STRING OemAnnounceName;
+
+ (VOID)RtlAcquireResourceShared( &SsServerInfoResource, TRUE );
+
+ //
+ // Loop through each emulated server name announcing on each.
+ //
+
+ for( Service = SsServerNameList; Service != NULL; Service = Service->Next ) {
+
+ //
+ // Save the AnnounceName without trailing blanks.
+ //
+
+ OemAnnounceName.Length = (USHORT) ComputeTransportAddressClippedLength(
+ Service->TransportAddress,
+ Service->TransportAddressLength );
+
+ OemAnnounceName.MaximumLength = OemAnnounceName.Length;
+ OemAnnounceName.Buffer = Service->TransportAddress;
+
+ if( OemAnnounceName.Length == 0 ) {
+ //
+ // A blank name???
+ //
+ continue;
+ }
+
+
+ //
+ // Loop through each transport announcing on each.
+ //
+
+ for( Transport = Service->Transports; Transport != NULL; Transport = Transport->Next ) {
+
+
+ //
+ // Do the actual announcement
+ //
+
+ SsAnnounce( &OemAnnounceName,
+ Service->DomainName,
+ DoNtAnnouncement,
+ NtInterval,
+ DoLmAnnouncement,
+ TerminationAnnouncement,
+ Transport->TransportName,
+ Service->ServiceBits | Transport->ServiceBits );
+
+ }
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+}
+
+
+
+NET_API_STATUS
+SendSecondClassMailslot (
+ IN LPTSTR Transport OPTIONAL,
+ IN PVOID Message,
+ IN DWORD MessageLength,
+ IN LPTSTR Domain,
+ IN LPSTR MailslotNameText,
+ IN UCHAR SignatureByte
+ )
+{
+ NET_API_STATUS status;
+ DWORD dataSize;
+ DWORD smbSize;
+ PSMB_HEADER header;
+ PSMB_TRANSACT_MAILSLOT parameters;
+ LPSTR mailslotName;
+ DWORD mailslotNameLength;
+ PVOID message;
+ DWORD domainLength;
+ CHAR domainName[NETBIOS_NAME_LEN];
+ PCHAR domainNamePointer;
+ PSERVER_REQUEST_PACKET srp;
+
+ UNICODE_STRING domainString;
+ OEM_STRING oemDomainString;
+
+ srp = SsAllocateSrp();
+
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlInitUnicodeString(&domainString, Domain);
+
+ oemDomainString.Buffer = domainName;
+ oemDomainString.MaximumLength = sizeof(domainName);
+
+ status = RtlUpcaseUnicodeStringToOemString(
+ &oemDomainString,
+ &domainString,
+ FALSE
+ );
+
+ if (!NT_SUCCESS(status)) {
+ return RtlNtStatusToDosError(status);
+ }
+
+ domainLength = oemDomainString.Length;
+
+ domainNamePointer = &domainName[domainLength];
+
+ for ( ; domainLength < NETBIOS_NAME_LEN - 1 ; domainLength++ ) {
+ *domainNamePointer++ = ' ';
+ }
+
+ //
+ // Append the signature byte to the end of the name.
+ //
+
+ *domainNamePointer = SignatureByte;
+
+ domainLength += 1;
+
+ srp->Name1.Buffer = (PWSTR)domainName;
+ srp->Name1.Length = (USHORT)domainLength;
+ srp->Name1.MaximumLength = (USHORT)domainLength;
+
+ if ( ARGUMENT_PRESENT ( Transport ) ) {
+ RtlInitUnicodeString( &srp->Name2, Transport );
+
+ } else {
+
+ srp->Name2.Buffer = NULL;
+ srp->Name2.Length = 0;
+ srp->Name2.MaximumLength = 0;
+ }
+
+ //
+ // Determine the sizes of various fields that will go in the SMB
+ // and the total size of the SMB.
+ //
+
+ mailslotNameLength = strlen( MailslotNameText );
+
+ dataSize = mailslotNameLength + 1 + MessageLength;
+ smbSize = sizeof(SMB_HEADER) + sizeof(SMB_TRANSACT_MAILSLOT) - 1 + dataSize;
+
+ //
+ // Allocate enough memory to hold the SMB. If we can't allocate the
+ // memory, don't do an announcement.
+ //
+
+ header = MIDL_user_allocate( smbSize );
+ if ( header == NULL ) {
+
+ SsFreeSrp( srp );
+
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Fill in the header. Most of the fields don't matter and are
+ // zeroed.
+ //
+
+ RtlZeroMemory( header, smbSize );
+
+ header->Protocol[0] = 0xFF;
+ header->Protocol[1] = 'S';
+ header->Protocol[2] = 'M';
+ header->Protocol[3] = 'B';
+ header->Command = SMB_COM_TRANSACTION;
+
+ //
+ // Get the pointer to the params and fill them in.
+ //
+
+ parameters = (PSMB_TRANSACT_MAILSLOT)( header + 1 );
+ mailslotName = (LPSTR)( parameters + 1 ) - 1;
+ message = mailslotName + mailslotNameLength + 1;
+
+ parameters->WordCount = 0x11;
+ SmbPutUshort( &parameters->TotalDataCount, (WORD)MessageLength );
+ SmbPutUlong( &parameters->Timeout, 0x3E8 ); // !!! fix
+ SmbPutUshort( &parameters->DataCount, (WORD)MessageLength );
+ SmbPutUshort(
+ &parameters->DataOffset,
+ (WORD)( (DWORD)message - (DWORD)header )
+ );
+ parameters->SetupWordCount = 3;
+ SmbPutUshort( &parameters->Opcode, MS_WRITE_OPCODE );
+ SmbPutUshort( &parameters->Class, 2 );
+ SmbPutUshort( &parameters->ByteCount, (WORD)dataSize );
+
+ RtlCopyMemory( mailslotName, MailslotNameText, mailslotNameLength + 1 );
+
+ RtlCopyMemory( message, Message, MessageLength );
+
+ status = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_SEND_DATAGRAM,
+ srp,
+ header,
+ smbSize
+ );
+
+ if ( status != NERR_Success ) {
+ SS_PRINT(( "SendSecondClassMailslot: NtFsControlFile failed: %X\n",
+ status ));
+ }
+
+ MIDL_user_free( header );
+
+ SsFreeSrp( srp );
+
+ return status;
+
+} // SendSecondClassMailslot
+
+ NTSTATUS
+OpenBrowser(
+ OUT PHANDLE BrowserHandle
+ )
+/*++
+
+Routine Description:
+
+ This function opens a handle to the bowser device driver.
+
+Arguments:
+
+ OUT PHANDLE BrowserHandle - Returns the handle to the browser.
+
+Return Value:
+
+ NET_API_STATUS - NERR_Success or reason for failure.
+
+--*/
+{
+ NTSTATUS ntstatus;
+
+ UNICODE_STRING deviceName;
+
+ IO_STATUS_BLOCK ioStatusBlock;
+ OBJECT_ATTRIBUTES objectAttributes;
+
+
+ //
+ // Open the redirector device.
+ //
+ RtlInitUnicodeString(&deviceName, DD_BROWSER_DEVICE_NAME_U);
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &deviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ ntstatus = NtOpenFile(
+ BrowserHandle,
+ SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
+ &objectAttributes,
+ &ioStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if (NT_SUCCESS(ntstatus)) {
+ ntstatus = ioStatusBlock.Status;
+ }
+
+ return ntstatus;
+
+}
+
+ NET_API_STATUS
+SsBrowserIoControl (
+ IN DWORD IoControlCode,
+ IN PVOID Buffer,
+ IN DWORD BufferLength,
+ IN PLMDR_REQUEST_PACKET Packet,
+ IN DWORD PacketLength
+ )
+{
+ HANDLE browserHandle;
+ NTSTATUS status;
+ PLMDR_REQUEST_PACKET realPacket;
+ DWORD RealPacketSize;
+ DWORD bytesReturned;
+ LPBYTE Where;
+
+ //
+ // Open the browser device driver.
+ //
+
+ if ( !NT_SUCCESS(status = OpenBrowser(&browserHandle)) ) {
+ return RtlNtStatusToDosError(status);
+ }
+
+ //
+ // Now copy the request packet to a new buffer to allow us to pack the
+ // transport name to the end of the buffer we pass to the driver.
+ //
+
+ RealPacketSize = PacketLength+Packet->TransportName.MaximumLength;
+#ifdef _CAIRO_
+ RealPacketSize += Packet->EmulatedDomainName.MaximumLength;
+#endif // _CAIRO_
+ realPacket = MIDL_user_allocate( RealPacketSize );
+ if (realPacket == NULL) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlCopyMemory(realPacket, Packet, PacketLength);
+ Where = ((LPBYTE)realPacket)+PacketLength;
+
+ if (Packet->TransportName.Length != 0) {
+
+ realPacket->TransportName.Buffer = (LPWSTR) Where;
+
+ realPacket->TransportName.MaximumLength = Packet->TransportName.MaximumLength;
+
+ RtlCopyUnicodeString(&realPacket->TransportName, &Packet->TransportName);
+
+ Where += Packet->TransportName.MaximumLength;
+ }
+
+#ifdef _CAIRO_
+ if (Packet->EmulatedDomainName.Length != 0) {
+
+ realPacket->EmulatedDomainName.Buffer = (LPWSTR) Where;
+
+ realPacket->EmulatedDomainName.MaximumLength = Packet->EmulatedDomainName.MaximumLength;
+
+ RtlCopyUnicodeString(&realPacket->EmulatedDomainName, &Packet->EmulatedDomainName);
+
+ Where += Packet->EmulatedDomainName.MaximumLength;
+ }
+#endif // _CAIRO_
+
+ //
+ // Send the request to the Datagram Receiver DD.
+ //
+
+ if (!DeviceIoControl(
+ browserHandle,
+ IoControlCode,
+ realPacket,
+ RealPacketSize,
+ Buffer,
+ BufferLength,
+ &bytesReturned,
+ NULL
+ )) {
+ status = GetLastError();
+ }
+
+ MIDL_user_free(realPacket);
+
+ CloseHandle(browserHandle);
+
+ return status;
+
+}
diff --git a/private/net/svcdlls/srvsvc/server/security.c b/private/net/svcdlls/srvsvc/server/security.c
new file mode 100644
index 000000000..970eaacac
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/security.c
@@ -0,0 +1,902 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ security.c
+
+Abstract:
+
+ Data and routines for managing API security in the server service.
+
+Author:
+
+ David Treadwell (davidtr) 28-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+
+#include <lmsname.h>
+#include <netlibnt.h>
+
+#include <debugfmt.h>
+
+//
+// Global security objects.
+//
+// CharDev - NetCharDev APIs
+// ConfigInfo - NetServerGetInfo, NetServerSetInfo
+// Connection - NetConnectionEnum
+// Disk - NetServerDiskEnum
+// File - NetFile APIs
+// Session - NetSession APIs
+// Share - NetShare APIs (file, print, and admin types)
+// Statistics - NetStatisticsGet, NetStatisticsClear
+//
+
+SRVSVC_SECURITY_OBJECT SsCharDevSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsConfigInfoSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsConnectionSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsDiskSecurityObject;
+SRVSVC_SECURITY_OBJECT SsFileSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsSessionSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsShareFileSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsSharePrintSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsShareAdminSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsShareConnectSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsShareAdmConnectSecurityObject = {0};
+SRVSVC_SECURITY_OBJECT SsStatisticsSecurityObject = {0};
+
+#ifdef SRV_COMM_DEVICES
+GENERIC_MAPPING SsCharDevMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_CHARDEV_USER_INFO_GET |
+ SRVSVC_CHARDEV_ADMIN_INFO_GET,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ SRVSVC_CHARDEV_INFO_SET,
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_CHARDEV_ALL_ACCESS // Generic all
+ };
+#endif // def SRV_COMM_DEVICES
+
+GENERIC_MAPPING SsConfigInfoMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_CONFIG_USER_INFO_GET |
+ SRVSVC_CONFIG_ADMIN_INFO_GET,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ SRVSVC_CONFIG_INFO_SET,
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_CONFIG_ALL_ACCESS // Generic all
+ };
+
+GENERIC_MAPPING SsConnectionMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_CONNECTION_INFO_GET,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ 0,
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_CONNECTION_ALL_ACCESS // Generic all
+ };
+
+GENERIC_MAPPING SsDiskMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_DISK_ENUM,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ 0,
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_DISK_ALL_ACCESS // Generic all
+ };
+
+GENERIC_MAPPING SsFileMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_FILE_INFO_GET,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ SRVSVC_FILE_CLOSE,
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_FILE_ALL_ACCESS // Generic all
+ };
+
+GENERIC_MAPPING SsSessionMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_SESSION_USER_INFO_GET |
+ SRVSVC_SESSION_ADMIN_INFO_GET,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ SRVSVC_SESSION_DELETE,
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_SESSION_ALL_ACCESS // Generic all
+ };
+
+GENERIC_MAPPING SsShareMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_SHARE_USER_INFO_GET |
+ SRVSVC_SHARE_ADMIN_INFO_GET,
+ STANDARD_RIGHTS_WRITE | // Generic write
+ SRVSVC_SHARE_INFO_SET,
+ STANDARD_RIGHTS_EXECUTE | // Generic execute
+ SRVSVC_SHARE_CONNECT,
+ SRVSVC_SHARE_ALL_ACCESS // Generic all
+ };
+
+GENERIC_MAPPING SsShareConnectMapping = GENERIC_SHARE_CONNECT_MAPPING;
+
+GENERIC_MAPPING SsStatisticsMapping = {
+ STANDARD_RIGHTS_READ | // Generic read
+ SRVSVC_STATISTICS_GET,
+ STANDARD_RIGHTS_WRITE, // Generic write
+ STANDARD_RIGHTS_EXECUTE, // Generic execute
+ SRVSVC_STATISTICS_ALL_ACCESS // Generic all
+ };
+
+//
+// Forward declarations.
+//
+
+NET_API_STATUS
+CreateSecurityObject (
+ PSRVSVC_SECURITY_OBJECT SecurityObject,
+ LPTSTR ObjectName,
+ PGENERIC_MAPPING Mapping,
+ PACE_DATA AceData,
+ ULONG AceDataLength
+ );
+
+#ifdef SRV_COMM_DEVICES
+NET_API_STATUS
+CreateCharDevSecurityObject (
+ VOID
+ );
+#endif
+
+NET_API_STATUS
+CreateConfigInfoSecurityObject (
+ VOID
+ );
+
+NET_API_STATUS
+CreateConnectionSecurityObject (
+ VOID
+ );
+
+NET_API_STATUS
+CreateDiskSecurityObject (
+ VOID
+ );
+
+NET_API_STATUS
+CreateFileSecurityObject (
+ VOID
+ );
+
+NET_API_STATUS
+CreateSessionSecurityObject (
+ VOID
+ );
+
+NET_API_STATUS
+CreateShareSecurityObjects (
+ VOID
+ );
+
+NET_API_STATUS
+CreateStatisticsSecurityObject (
+ VOID
+ );
+
+VOID
+DeleteSecurityObject (
+ PSRVSVC_SECURITY_OBJECT SecurityObject
+ );
+
+
+NET_API_STATUS
+SsCreateSecurityObjects (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the objects that will be used for security in the server
+ service APIs.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS status;
+
+#ifdef SRV_COMM_DEVICES
+ //
+ // Create CharDev security object.
+ //
+
+ status = CreateCharDevSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+#endif
+
+ //
+ // Create ConfigInfo security object.
+ //
+
+ status = CreateConfigInfoSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ //
+ // Create Connection security object.
+ //
+
+ status = CreateConnectionSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ //
+ // Create Disk security object.
+ //
+
+ status = CreateDiskSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ //
+ // Create File security object.
+ //
+
+ status = CreateFileSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ //
+ // Create Session security object.
+ //
+
+ status = CreateSessionSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ //
+ // Create Share security object.
+ //
+
+ status = CreateShareSecurityObjects( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ //
+ // Create Statistics security object.
+ //
+
+ status = CreateStatisticsSecurityObject( );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ return NO_ERROR;
+
+} // SsCreateSecurityObjects
+
+
+VOID
+SsDeleteSecurityObjects (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes server service security objects.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef SRV_COMM_DEVICES
+ //
+ // Delete CharDev security object.
+ //
+
+ DeleteSecurityObject( &SsCharDevSecurityObject );
+#endif
+
+ //
+ // Delete ConfigInfo security object.
+ //
+
+ DeleteSecurityObject( &SsConfigInfoSecurityObject );
+
+ //
+ // Delete Connection security object.
+ //
+
+ DeleteSecurityObject( &SsConnectionSecurityObject );
+
+ //
+ // Delete File security object.
+ //
+
+ DeleteSecurityObject( &SsFileSecurityObject );
+
+ //
+ // Delete Session security object.
+ //
+
+ DeleteSecurityObject( &SsSessionSecurityObject );
+
+ //
+ // Delete Share security objects.
+ //
+
+ DeleteSecurityObject( &SsShareFileSecurityObject );
+ DeleteSecurityObject( &SsSharePrintSecurityObject );
+ DeleteSecurityObject( &SsShareAdminSecurityObject );
+ DeleteSecurityObject( &SsShareConnectSecurityObject );
+ DeleteSecurityObject( &SsShareAdmConnectSecurityObject );
+
+ //
+ // Delete Statistics security object.
+ //
+
+ DeleteSecurityObject( &SsStatisticsSecurityObject );
+
+ return;
+
+} // SsDeleteSecurityObjects
+
+
+NET_API_STATUS
+SsCheckAccess (
+ IN PSRVSVC_SECURITY_OBJECT SecurityObject,
+ IN ACCESS_MASK DesiredAccess
+ )
+
+/*++
+
+Routine Description:
+
+ Calls NetpAccessCheckAndAudit to verify that the caller of an API
+ has the necessary access to perform the requested operation.
+
+Arguments:
+
+ SecurityObject - a pointer to the server service security object
+ that describes the security on the relevant object.
+
+ DesiredAccess - the access needed to perform the requested operation.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+
+ IF_DEBUG(SECURITY) {
+ SS_PRINT(( "SsCheckAccess: validating object " FORMAT_LPTSTR ", "
+ "access %lx\n",
+ SecurityObject->ObjectName, DesiredAccess ));
+ }
+
+ error = NetpAccessCheckAndAudit(
+ SERVER_DISPLAY_NAME,
+ SecurityObject->ObjectName,
+ SecurityObject->SecurityDescriptor,
+ DesiredAccess,
+ SecurityObject->Mapping
+ );
+
+ if ( error != NO_ERROR ) {
+ IF_DEBUG(ACCESS_DENIED) {
+ SS_PRINT(( "SsCheckAccess: NetpAccessCheckAndAudit failed for "
+ "object " FORMAT_LPTSTR ", access %lx: %ld\n",
+ SecurityObject->ObjectName, DesiredAccess, error ));
+ }
+ } else {
+ IF_DEBUG(SECURITY) {
+ SS_PRINT(( "SsCheckAccess: allowed access for " FORMAT_LPTSTR ", "
+ "access %lx\n",
+ SecurityObject->ObjectName, DesiredAccess ));
+ }
+ }
+
+ return error;
+
+} // SsCheckAccess
+
+
+NET_API_STATUS
+CreateSecurityObject (
+ PSRVSVC_SECURITY_OBJECT SecurityObject,
+ LPTSTR ObjectName,
+ PGENERIC_MAPPING Mapping,
+ PACE_DATA AceData,
+ ULONG AceDataLength
+ )
+{
+ NTSTATUS status;
+
+ //
+ // Set up security object.
+ //
+
+ SecurityObject->ObjectName = ObjectName;
+ SecurityObject->Mapping = Mapping;
+
+ //
+ // Create security descriptor.
+ //
+
+ status = NetpCreateSecurityObject(
+ AceData,
+ AceDataLength,
+ SsLmsvcsGlobalData->LocalSystemSid,
+ SsLmsvcsGlobalData->LocalSystemSid,
+ Mapping,
+ &SecurityObject->SecurityDescriptor
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "CreateSecurityObject: failed to create " FORMAT_LPTSTR
+ " object: %lx\n", ObjectName, status ));
+ }
+
+ return NetpNtStatusToApiStatus( status );
+ }
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "CreateSecurityObject: created " FORMAT_LPTSTR " object.\n",
+ ObjectName ));
+ }
+
+ return NO_ERROR;
+
+} // CreateSecurityObject
+
+
+#ifdef SRV_COMM_DEVICES
+NET_API_STATUS
+CreateCharDevSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for getting and setting character device information.
+ //
+
+ ACE_DATA CharDevAceData[] = {
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasCommOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_CHARDEV_USER_INFO_GET, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ //
+ // Create CharDev security object.
+ //
+
+ return CreateSecurityObject(
+ &SsCharDevSecurityObject,
+ SRVSVC_CHARDEV_OBJECT,
+ &SsCharDevMapping,
+ &CharDevAceData,
+ sizeof(CharDevAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateCharDevSecurityObject
+#endif
+
+
+NET_API_STATUS
+CreateConfigInfoSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for getting and setting server information.
+ //
+
+ ACE_DATA ConfigInfoAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_CONFIG_USER_INFO_GET | SRVSVC_CONFIG_POWER_INFO_GET,
+ &SsLmsvcsGlobalData->AliasPowerUsersSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_CONFIG_USER_INFO_GET, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ //
+ // Create ConfigInfo security object.
+ //
+
+ return CreateSecurityObject(
+ &SsConfigInfoSecurityObject,
+ SRVSVC_CONFIG_INFO_OBJECT,
+ &SsConfigInfoMapping,
+ ConfigInfoAceData,
+ sizeof(ConfigInfoAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateConfigInfoSecurityObject
+
+
+NET_API_STATUS
+CreateConnectionSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for getting and setting Connection information.
+ //
+
+ ACE_DATA ConnectionAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_CONNECTION_INFO_GET, &SsLmsvcsGlobalData->AliasPrintOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_CONNECTION_INFO_GET, &SsLmsvcsGlobalData->AliasPowerUsersSid}
+ };
+
+ //
+ // Create Connection security object.
+ //
+
+ return CreateSecurityObject(
+ &SsConnectionSecurityObject,
+ SRVSVC_CONNECTION_OBJECT,
+ &SsConnectionMapping,
+ ConnectionAceData,
+ sizeof(ConnectionAceData) / sizeof(ACE_DATA)
+ );
+
+ return NO_ERROR;
+
+} // CreateConnectionSecurityObject
+
+
+NET_API_STATUS
+CreateDiskSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for doing Disk enums
+ //
+
+ ACE_DATA DiskAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid}
+ };
+
+ //
+ // Create Disk security object.
+ //
+
+ return CreateSecurityObject(
+ &SsDiskSecurityObject,
+ SRVSVC_DISK_OBJECT,
+ &SsDiskMapping,
+ DiskAceData,
+ sizeof(DiskAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateDiskSecurityObject
+
+
+NET_API_STATUS
+CreateFileSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for getting and setting File information.
+ //
+
+ ACE_DATA FileAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasPowerUsersSid}
+ };
+
+ //
+ // Create File security object.
+ //
+
+ return CreateSecurityObject(
+ &SsFileSecurityObject,
+ SRVSVC_FILE_OBJECT,
+ &SsFileMapping,
+ FileAceData,
+ sizeof(FileAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateFileSecurityObject
+
+
+NET_API_STATUS
+CreateSessionSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for getting and setting session information.
+ //
+
+ ACE_DATA SessionAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasPowerUsersSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SESSION_USER_INFO_GET, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ //
+ // Create Session security object.
+ //
+
+ return CreateSecurityObject(
+ &SsSessionSecurityObject,
+ SRVSVC_SESSION_OBJECT,
+ &SsSessionMapping,
+ SessionAceData,
+ sizeof(SessionAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateSessionSecurityObject
+
+
+NET_API_STATUS
+CreateShareSecurityObjects (
+ VOID
+ )
+{
+ NET_API_STATUS status;
+
+ //
+ // Required access for getting and setting share information.
+ //
+
+ ACE_DATA ShareFileAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasPowerUsersSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SHARE_USER_INFO_GET, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ ACE_DATA SharePrintAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasPrintOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasPowerUsersSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SHARE_USER_INFO_GET, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ ACE_DATA ShareAdminAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SHARE_ADMIN_INFO_GET,
+ &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SHARE_ADMIN_INFO_GET,
+ &SsLmsvcsGlobalData->AliasPowerUsersSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SHARE_USER_INFO_GET, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ ACE_DATA ShareConnectAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasBackupOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_SHARE_CONNECT, &SsLmsvcsGlobalData->WorldSid}
+ };
+
+ ACE_DATA ShareAdmConnectAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasBackupOpsSid}
+ };
+
+ //
+ // Create Share security objects.
+ //
+
+ status = CreateSecurityObject(
+ &SsShareFileSecurityObject,
+ SRVSVC_SHARE_FILE_OBJECT,
+ &SsShareMapping,
+ ShareFileAceData,
+ sizeof(ShareFileAceData) / sizeof(ACE_DATA)
+ );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ status = CreateSecurityObject(
+ &SsSharePrintSecurityObject,
+ SRVSVC_SHARE_PRINT_OBJECT,
+ &SsShareMapping,
+ SharePrintAceData,
+ sizeof(SharePrintAceData) / sizeof(ACE_DATA)
+ );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ status = CreateSecurityObject(
+ &SsShareAdminSecurityObject,
+ SRVSVC_SHARE_ADMIN_OBJECT,
+ &SsShareMapping,
+ ShareAdminAceData,
+ sizeof(ShareAdminAceData) / sizeof(ACE_DATA)
+ );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ status = CreateSecurityObject(
+ &SsShareConnectSecurityObject,
+ SRVSVC_SHARE_CONNECT_OBJECT,
+ &SsShareConnectMapping,
+ ShareConnectAceData,
+ sizeof(ShareConnectAceData) / sizeof(ACE_DATA)
+ );
+ if ( status != NO_ERROR ) {
+ return status;
+ }
+
+ return CreateSecurityObject(
+ &SsShareAdmConnectSecurityObject,
+ SRVSVC_SHARE_ADM_CONNECT_OBJECT,
+ &SsShareConnectMapping,
+ ShareAdmConnectAceData,
+ sizeof(ShareAdmConnectAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateShareSecurityObjects
+
+
+NET_API_STATUS
+CreateStatisticsSecurityObject (
+ VOID
+ )
+{
+ //
+ // Required access for getting and setting Statistics information.
+ //
+
+ ACE_DATA StatisticsAceData[] = {
+
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasAdminsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ GENERIC_ALL, &SsLmsvcsGlobalData->AliasSystemOpsSid},
+ {ACCESS_ALLOWED_ACE_TYPE, 0, 0,
+ SRVSVC_STATISTICS_GET, &SsLmsvcsGlobalData->LocalSid}
+ };
+
+ //
+ // Create Statistics security object.
+ //
+
+ return CreateSecurityObject(
+ &SsStatisticsSecurityObject,
+ SRVSVC_STATISTICS_OBJECT,
+ &SsStatisticsMapping,
+ StatisticsAceData,
+ sizeof(StatisticsAceData) / sizeof(ACE_DATA)
+ );
+
+} // CreateStatisticsSecurityObject
+
+
+VOID
+DeleteSecurityObject (
+ PSRVSVC_SECURITY_OBJECT SecurityObject
+ )
+{
+ NTSTATUS status;
+
+ if ( SecurityObject->SecurityDescriptor != NULL ) {
+
+ status = NetpDeleteSecurityObject(
+ &SecurityObject->SecurityDescriptor
+ );
+ SecurityObject->SecurityDescriptor = NULL;
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(TERMINATION_ERRORS) {
+ SS_PRINT(( "DeleteSecurityObject: failed to delete "
+ FORMAT_LPTSTR " object: %X\n",
+ SecurityObject->ObjectName,
+ status ));
+ }
+ } else {
+ IF_DEBUG(TERMINATION) {
+ SS_PRINT(( "DeleteSecurityObject: deleted " FORMAT_LPTSTR
+ " object.\n",
+ SecurityObject->ObjectName ));
+ }
+ }
+
+ }
+
+ return;
+
+} // DeleteSecurityObject
+
diff --git a/private/net/svcdlls/srvsvc/server/sess.c b/private/net/svcdlls/srvsvc/server/sess.c
new file mode 100644
index 000000000..f3b7aaba0
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/sess.c
@@ -0,0 +1,293 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ Sess.c
+
+Abstract:
+
+ This module contains support for the Session catagory of APIs for the
+ NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 30-Jan-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include <lmerr.h>
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrSessionDel (
+ IN LPTSTR ServerName,
+ IN LPTSTR ClientName OPTIONAL,
+ IN LPTSTR UserName OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetSessionDel function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsSessionSecurityObject,
+ SRVSVC_SESSION_DELETE
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Translate zero-length strings to NULL pointers.
+ //
+
+ if ( (ClientName != NULL) && (*ClientName == L'\0') ) {
+ ClientName = NULL;
+ }
+
+ if ( (UserName != NULL) && (*UserName == L'\0') ) {
+ UserName = NULL;
+ }
+
+ //
+ // Either the client name or the user name must be specified. It
+ // is not legal to leave both NULL, as this would imply "log out all
+ // users." If that's what you want, stop the server.
+ //
+
+ if ( ClientName == NULL && UserName == NULL ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Set up the request packet.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlInitUnicodeString( &srp->Name1, ClientName );
+ RtlInitUnicodeString( &srp->Name2, UserName );
+
+ //
+ // Simply send the request on to the server.
+ //
+
+ error = SsServerFsControl( NULL, FSCTL_SRV_NET_SESSION_DEL, srp, NULL, 0 );
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // NetrSessionDel
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrSessionEnum (
+ IN LPTSTR ServerName,
+ IN LPTSTR ClientName OPTIONAL,
+ IN LPTSTR UserName OPTIONAL,
+ OUT PSESSION_ENUM_STRUCT InfoStruct,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetSessionEnum function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+ ACCESS_MASK desiredAccess;
+
+ ServerName;
+
+ //
+ // Make sure we have basic sanity on our input parameters
+ //
+ if( !ARGUMENT_PRESENT( InfoStruct ) ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that the level is valid and determine the access
+ // necessary for the level.
+ //
+
+ switch ( InfoStruct->Level ) {
+
+ case 0:
+ case 10:
+ desiredAccess = SRVSVC_SESSION_USER_INFO_GET;
+ break;
+
+ case 1:
+ case 2:
+ case 502:
+ desiredAccess = SRVSVC_SESSION_ADMIN_INFO_GET;
+ break;
+
+ default:
+
+ return ERROR_INVALID_LEVEL;
+ }
+
+ if( InfoStruct->SessionInfo.Level2 == NULL ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsSessionSecurityObject,
+ desiredAccess
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Translate zero-length strings to NULL pointers.
+ //
+
+ if ( (ClientName != NULL) && (*ClientName == L'\0') ) {
+ ClientName = NULL;
+ }
+
+ if ( (UserName != NULL) && (*UserName == L'\0') ) {
+ UserName = NULL;
+ }
+
+ //
+ // Is a client name was specified, make sure client name starts with "\\"
+ //
+
+ if ( ARGUMENT_PRESENT( ClientName ) &&
+ (ClientName[0] != L'\\' || ClientName[1] != L'\\' ) ) {
+
+ return(NERR_InvalidComputer);
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = InfoStruct->Level;
+
+ RtlInitUnicodeString( &srp->Name1, ClientName );
+ RtlInitUnicodeString( &srp->Name2, UserName );
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_SESSION_ENUM,
+ srp,
+ (PVOID *)&InfoStruct->SessionInfo.Level2->Buffer,
+ PreferredMaximumLength
+ );
+
+ //
+ // Set up return information.
+ //
+
+ InfoStruct->SessionInfo.Level2->EntriesRead =
+ srp->Parameters.Get.EntriesRead;
+
+ if ( ARGUMENT_PRESENT( TotalEntries ) ) {
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+ }
+
+ if ( srp->Parameters.Get.EntriesRead > 0 ) {
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+ } else if ( *TotalEntries == 0 ) {
+
+ //
+ // Entries read and total entries is 0. If a client name or
+ // username was specified, return the appropriate error.
+ //
+
+ if ( ARGUMENT_PRESENT( UserName ) ) {
+
+ error = NERR_UserNotFound;
+
+ } else if ( ARGUMENT_PRESENT( ClientName ) ) {
+
+ error = NERR_ClientNameNotFound;
+ }
+ }
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // NetrSessionEnum
+
diff --git a/private/net/svcdlls/srvsvc/server/share.c b/private/net/svcdlls/srvsvc/server/share.c
new file mode 100644
index 000000000..3422c1ca3
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/share.c
@@ -0,0 +1,2897 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ Share.c
+
+Abstract:
+
+ This module contains support for the Share catagory of APIs for the
+ NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 10-Jan-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "ssreg.h"
+
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <ntddnfs.h>
+#include <tstr.h>
+#include <netevent.h>
+#include <icanon.h>
+
+#define SET_ERROR_PARAMETER(a) \
+ if ( ARGUMENT_PRESENT( ErrorParameter ) ) { *ErrorParameter = a; }
+
+//
+// Use the same directory separator as the object system uses.
+//
+
+#define IS_SLASH_SLASH_NAME( _x ) \
+ ( IS_PATH_SEPARATOR( _x[0] ) && \
+ IS_PATH_SEPARATOR( _x[1] ) && \
+ _x[2] == L'.' && \
+ IS_PATH_SEPARATOR( _x[3] ) )
+
+
+GENERIC_MAPPING SrvShareFileGenericMapping = GENERIC_SHARE_FILE_ACCESS_MAPPING;
+
+//
+// Local types.
+//
+
+typedef struct _SHARE_DEL_CONTEXT {
+ SERVER_REQUEST_PACKET Srp;
+ BOOL IsPrintShare;
+ BOOL IsSpecial;
+ //WCHAR NetName[];
+} SHARE_DEL_CONTEXT, *PSHARE_DEL_CONTEXT;
+
+//
+// Forward declarations.
+//
+
+PVOID
+CaptureShareInfo (
+ IN DWORD Level,
+ IN PSHARE_INFO_2 Shi2,
+ IN DWORD ShareType,
+ IN LPWSTR Path,
+ IN LPWSTR Remark,
+ IN PSECURITY_DESCRIPTOR ConnectSecurityDescriptor,
+ IN PSECURITY_DESCRIPTOR FileSecurityDescriptor OPTIONAL,
+ OUT PULONG CapturedBufferLength
+ );
+
+NET_API_STATUS
+DisallowSharedLanmanNetDrives(
+ IN PUNICODE_STRING NtSharePath
+ );
+
+NET_API_STATUS
+ShareAssignSecurityDescriptor(
+ IN PSECURITY_DESCRIPTOR PassedSecurityDescriptor,
+ OUT PSECURITY_DESCRIPTOR *NewSecurityDescriptor
+ );
+
+NET_API_STATUS
+ShareEnumCommon (
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL,
+ IN LPWSTR NetName OPTIONAL
+ );
+
+NET_API_STATUS
+ShareEnumSticky (
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ );
+
+ULONG
+SizeShares (
+ IN ULONG Level,
+ IN PSHARE_INFO_502 Shi502
+ );
+
+BOOLEAN
+ValidSharePath(
+ IN LPWSTR SharePath
+ );
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareAdd (
+ IN LPWSTR ServerName,
+ IN DWORD Level,
+ IN LPSHARE_INFO Buffer,
+ OUT LPDWORD ErrorParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetShareAdd function. Only levels 2 and 502 are valid.
+
+Arguments:
+
+ ServerName - name of the server.
+ Level - Request level.
+ Buffer - Contains the information about the share. If this is a level
+ 502 request, will also contain a valid security descriptor in
+ self-relative form.
+ ErrorParameter - status of the FsControl call.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ NTSTATUS status;
+ PSERVER_REQUEST_PACKET srp;
+ PVOID capturedBuffer;
+ LPWSTR path;
+ LPWSTR netName;
+ LPWSTR remark;
+ ULONG bufferLength;
+ UNICODE_STRING dosSharePath;
+ UNICODE_STRING ntSharePath;
+
+ PSRVSVC_SECURITY_OBJECT securityObject;
+ PSECURITY_DESCRIPTOR connectSecurityDescriptor;
+ PSECURITY_DESCRIPTOR fileSecurityDescriptor = NULL;
+ PSECURITY_DESCRIPTOR newFileSecurityDescriptor = NULL;
+
+ UINT driveType = DRIVE_FIXED;
+ DWORD shareType;
+
+ BOOL isIpc;
+ BOOL isAdmin;
+ BOOL isDiskAdmin;
+ BOOL isPrintShare;
+ BOOL isSpecial;
+
+ PSHARE_INFO_2 shi2;
+ PSHARE_INFO_502 shi502;
+
+ ServerName;
+
+ //
+ // Check that user input buffer is not NULL
+ //
+ if (Buffer->ShareInfo2 == NULL) {
+ SET_ERROR_PARAMETER(PARM_ERROR_UNKNOWN);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Set up for error cleanup.
+ //
+
+
+ srp = NULL;
+ dosSharePath.Buffer = NULL;
+ ntSharePath.Buffer = NULL;
+ capturedBuffer = NULL;
+
+ //
+ // Extract Internal buffer information.
+ //
+
+ shi2 = Buffer->ShareInfo2;
+
+ //
+ // 502 may contain a security descriptor.
+ //
+
+ if ( Level == 502 ) {
+
+ shi502 = (LPSHARE_INFO_502) Buffer->ShareInfo502;
+ fileSecurityDescriptor = shi502->shi502_security_descriptor;
+
+ //
+ // check the reserved field. If it is zero, this was called from
+ // inside the srvsvc. If not, it was through rpc.
+ //
+
+ if ( fileSecurityDescriptor != NULL ) {
+
+ if ( shi502->shi502_reserved != 0 ) {
+
+ error = ShareAssignSecurityDescriptor(
+ fileSecurityDescriptor,
+ &newFileSecurityDescriptor
+ );
+
+ if ( error != NO_ERROR ) {
+
+ SS_PRINT(( "NetrShareAdd: ShareAssignSecurityDescriptor "
+ "error: %d\n", error ));
+
+ SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ } else {
+ newFileSecurityDescriptor = fileSecurityDescriptor;
+ }
+ }
+
+ } else if ( Level != 2 ) {
+
+ //
+ // The only valid levels are 2 and 502. 2 is a subset of 502.
+ //
+
+ error = ERROR_INVALID_LEVEL;
+ goto exit;
+ }
+
+ //
+ // A share name must be specified.
+ //
+
+ netName = shi2->shi2_netname;
+
+ if ( (netName == NULL) || (*netName == '\0') ) {
+ SET_ERROR_PARAMETER( SHARE_NETNAME_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Limit it to NNLEN
+ //
+
+ if ( wcslen(netName) > NNLEN ) {
+ SET_ERROR_PARAMETER( SHARE_NETNAME_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // If this is the IPC$ share, or the ADMIN$ share, no path
+ // may be specified. No path is needed for the IPC$ share, while a path
+ // is supplied internally for the ADMIN$ share.
+ //
+
+ path = shi2->shi2_path;
+ remark = shi2->shi2_remark;
+ shareType = shi2->shi2_type;
+
+ //
+ // Figure out which kind of share this is.
+ //
+
+ isIpc = (BOOL)(STRICMP( netName, IPC_SHARE_NAME ) == 0);
+ isAdmin = (BOOL)(STRICMP( netName, ADMIN_SHARE_NAME ) == 0);
+
+ //
+ // We have an administrative disk share if the share name is a drive letter
+ // followed by $, and if the path name is the root of that same drive.
+ //
+ if( wcslen( netName ) == 2 && netName[1] == L'$' &&
+ TOUPPER( netName[0] ) >= L'A' && TOUPPER( netName[0]) <= L'Z' &&
+ path != NULL && wcslen( path ) == 3 &&
+ TOUPPER( path[0] ) == TOUPPER( netName[0] ) &&
+ path[1] == L':' && path[2] == L'\\' ) {
+ //
+ // The share name and path look to be an administrative disk share.
+ // If the path refers to a fixed drive, then it really is one.
+ //
+ isDiskAdmin = (SsGetDriveType( path ) == DRIVE_FIXED);
+ } else {
+ isDiskAdmin = FALSE;
+ }
+
+ isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
+
+ isSpecial = isIpc || isAdmin || isDiskAdmin;
+
+ if ( isIpc ) {
+
+ if ( path != NULL ) {
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+ path = NULL;
+
+ //
+ // Let the caller specify a remark if they want. If they don't,
+ // supply a default remark.
+ //
+
+ if ( remark == NULL ) {
+ remark = SsIPCShareRemark;
+ }
+
+ shareType = STYPE_IPC;
+
+ } else if ( isAdmin ) {
+
+ if ( path != NULL ) {
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Let the caller specify a remark if they want. If they don't,
+ // supply a default remark.
+ //
+
+ if ( remark == NULL ) {
+ remark = SsAdminShareRemark;
+ }
+
+ shareType = STYPE_DISKTREE;
+
+ //
+ // For the ADMIN$ share, we set the path to the system root
+ // directory. We get this from from the kernel via the
+ // read-only shared page (USER_SHARED_DATA)
+ //
+
+ path = USER_SHARED_DATA->NtSystemRoot;
+
+ } else {
+
+ //
+ // For all shares other than IPC$ and ADMIN$, a path must be
+ // specified and must not have .. and . as directory names.
+ //
+
+ if ( (path == NULL) || (*path == '\0') || !ValidSharePath( path ) ) {
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ error = ERROR_INVALID_NAME;
+ goto exit;
+ }
+
+ //
+ // If we've got a disk admin share and they didn't supply a
+ // comment, use the built in one
+ //
+ if( isDiskAdmin && remark == NULL ) {
+ remark = SsDiskAdminShareRemark;
+ }
+ }
+
+ //
+ // The remark must be no longer than MAXCOMMENTSZ.
+ //
+
+ if ( (remark != NULL) && (STRLEN(remark) > MAXCOMMENTSZ) ) {
+ SET_ERROR_PARAMETER( SHARE_REMARK_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // If the server service is fully started, make sure that the caller
+ // is allowed to set share information in the server. We only do
+ // this if the service is started--the default share and configured
+ // share creations done during initialization do not need any
+ // special access.
+ //
+
+ if ( SsInitialized ) {
+
+ if ( isSpecial ) {
+ securityObject = &SsShareAdminSecurityObject;
+ } else if ( isPrintShare ) {
+ securityObject = &SsSharePrintSecurityObject;
+ } else {
+ securityObject = &SsShareFileSecurityObject;
+ }
+
+ error = SsCheckAccess( securityObject, SRVSVC_SHARE_INFO_SET );
+
+ if ( error != NO_ERROR ) {
+ SET_ERROR_PARAMETER( 0 );
+ goto exit;
+ }
+
+ }
+
+ //
+ // If this is a disk share, make sure that the drive is a type that
+ // can be shared.
+ //
+
+ if ( (shareType == STYPE_DISKTREE) && !isAdmin ) {
+
+ DWORD pathType;
+
+ //
+ // Check the path type. It should be an absolute directory path.
+ //
+
+ error = NetpPathType(
+ NULL,
+ path,
+ &pathType,
+ 0
+ );
+
+ if ( (error != NO_ERROR) || (pathType != ITYPE_PATH_ABSD) ) {
+ error = ERROR_INVALID_NAME;
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ goto exit;
+ }
+
+ driveType = SsGetDriveType( path );
+
+ if ( driveType == DRIVE_REMOVABLE ) {
+
+ shareType = STYPE_REMOVABLE;
+
+ } else if ( driveType == DRIVE_CDROM ) {
+
+ shareType = STYPE_CDROM;
+
+ } else if ( !(driveType == DRIVE_REMOTE &&
+ SsData.ServerInfo599.sv599_enablesharednetdrives) &&
+ driveType != DRIVE_FIXED &&
+ driveType != DRIVE_RAMDISK ) {
+
+ if ( driveType == DRIVE_REMOTE ) {
+ error = NERR_RedirectedPath;
+ } else {
+ error = NERR_UnknownDevDir;
+ }
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ goto exit;
+ }
+ }
+
+ //
+ // Set up the request packet.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+ srp->Level = Level;
+
+ //
+ // Get the path name in NT format and put it in the SRP.
+ //
+
+ if ( path != NULL ) {
+
+ RtlInitUnicodeString( &dosSharePath, path );
+
+ if ( !RtlDosPathNameToNtPathName_U(
+ dosSharePath.Buffer,
+ &ntSharePath,
+ NULL,
+ NULL ) ) {
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // If this is a redirected drive, make sure the redir is not
+ // LanMan.
+ //
+
+ if ( driveType == DRIVE_REMOTE ) {
+
+ error = DisallowSharedLanmanNetDrives( &ntSharePath );
+
+ if ( error != NERR_Success ) {
+ SET_ERROR_PARAMETER( SHARE_PATH_PARMNUM );
+ goto exit;
+ }
+
+ } // if remote drive
+
+ srp->Name1 = ntSharePath;
+ }
+
+ //
+ // Determine whether this is an admin share and use the appropriate
+ // security descriptor.
+ //
+
+ if ( isAdmin || isDiskAdmin ) {
+ connectSecurityDescriptor = SsShareAdmConnectSecurityObject.SecurityDescriptor;
+ } else {
+ connectSecurityDescriptor = SsShareConnectSecurityObject.SecurityDescriptor;
+ }
+
+ //
+ // If this is a disk share, verify that the directory to be shared
+ // exists and that the caller has access. (Don't do the access
+ // check during server startup.) Don't check the admin$ share -- we
+ // know it exists. Skip removable type disks.
+ //
+
+ if ( !isAdmin &&
+ (shareType == STYPE_DISKTREE) &&
+ (shi2->shi2_path != NULL) ) {
+
+ OBJECT_ATTRIBUTES objectAttributes;
+ IO_STATUS_BLOCK iosb;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ NTSTATUS status;
+
+ if ( SsInitialized ) {
+ (VOID)RpcImpersonateClient( NULL );
+ }
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &ntSharePath,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ NULL
+ );
+
+ status = NtOpenFile(
+ &handle,
+ FILE_LIST_DIRECTORY,
+ &objectAttributes,
+ &iosb,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE
+ );
+
+ if ( SsInitialized ) {
+ (VOID)RpcRevertToSelf( );
+ }
+
+ if ( !NT_SUCCESS(status) ) {
+
+ if ( SsInitialized || (status != STATUS_ACCESS_DENIED) ) {
+
+ //
+ // During startup, if the directory does not
+ // exist (renamed/deleted), log an event.
+ //
+
+ if ( !SsInitialized &&
+ ((status == STATUS_OBJECT_NAME_NOT_FOUND) ||
+ (status == STATUS_OBJECT_PATH_NOT_FOUND)) ) {
+
+ LPWSTR subStrings[2];
+ subStrings[0] = netName;
+ subStrings[1] = shi2->shi2_path;
+
+ SsLogEvent(
+ EVENT_SRV_CANT_RECREATE_SHARE,
+ 2,
+ subStrings,
+ NO_ERROR
+ );
+
+ }
+
+ SET_ERROR_PARAMETER( 0 );
+ error = RtlNtStatusToDosError( status );
+ goto exit;
+ }
+
+ } else if( !IS_SLASH_SLASH_NAME( path ) ) {
+
+ if ( SsInitialized ) {
+
+ PFILE_NAME_INFORMATION fileNameInformation;
+ ULONG fileInfoSize;
+ ULONG fileNameLength;
+
+ fileInfoSize = sizeof(FILE_NAME_INFORMATION) + SIZE_WSTR( path );
+
+ fileNameInformation = MIDL_user_allocate( fileInfoSize );
+
+ if ( fileNameInformation == NULL ) {
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ NtClose( handle );
+ goto exit;
+ }
+
+ //
+ // Query the name from the file system. This is because some
+ // fs like fat uses only upper case oem names. This can cause
+ // a problem because some oem characters do not have upper case
+ // equivalents and thus get mapped to something funny.
+ //
+
+ status = NtQueryInformationFile(
+ handle,
+ &iosb,
+ fileNameInformation,
+ fileInfoSize,
+ FileNameInformation
+ );
+
+
+ if ( status == STATUS_SUCCESS ) {
+
+ //
+ // The file name returned is expected to be
+ // 3 characters shorter than the share path length.
+ // These 3 characters are "X", ":", "\0".
+ //
+
+ fileNameLength = fileNameInformation->FileNameLength;
+
+ if ((fileNameLength+3*sizeof(WCHAR)) <= SIZE_WSTR(path)) {
+
+ //
+ // Copy the path name
+ //
+
+ RtlCopyMemory(
+ (LPBYTE) path + 2*sizeof(WCHAR),
+ fileNameInformation->FileName,
+ fileNameLength
+ );
+
+ path[fileNameLength/sizeof(WCHAR)+2] = L'\0';
+ }
+ }
+
+ MIDL_user_free( fileNameInformation );
+
+ }
+
+ NtClose( handle );
+
+ } else {
+
+ NtClose( handle );
+ }
+ }
+
+ //
+ // Capture the share data structure passed in.
+ //
+
+ if ( isSpecial ) {
+ shareType |= STYPE_SPECIAL;
+ }
+
+ capturedBuffer = CaptureShareInfo(
+ Level,
+ shi2,
+ shareType,
+ path,
+ remark,
+ connectSecurityDescriptor,
+ newFileSecurityDescriptor,
+ &bufferLength
+ );
+
+ if ( capturedBuffer == NULL ) {
+ SET_ERROR_PARAMETER( 0 );
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+
+ //
+ // Send the request on to the server.
+ //
+
+ error = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_NET_SHARE_ADD,
+ srp,
+ capturedBuffer,
+ bufferLength
+ );
+
+ SET_ERROR_PARAMETER( srp->Parameters.Set.ErrorParameter );
+
+ //
+ // If the request succeeded, add a value to the Shares key, thus
+ // effecting a sticky share. We only do this if the server is fully
+ // started -- the default share and configured share creations done
+ // during initialization should not be added to the registry.
+ //
+ // Don't do this if this is an admin share being [re]created.
+ //
+
+ if ( SsInitialized &&
+ (error == NO_ERROR) &&
+ !isSpecial ) {
+ SsAddShareToRegistry( shi2, newFileSecurityDescriptor );
+ }
+
+ //
+ // If a print share was successfully added, increment the number
+ // of print shares and update the exported (announced) server type.
+ //
+
+ if ( isPrintShare ) {
+ InterlockedIncrement( &SsData.NumberOfPrintShares );
+ SsSetExportedServerType( NULL, FALSE, TRUE );
+ }
+
+exit:
+
+ //
+ // Clean up. Free the share data structure that was allocated by
+ // CaptureShareInfo2. Free the server request packet. If there was
+ // an NT path name allocated by RtlDosPathNameToNtPathName, free it.
+ // If we created ADMIN$, free the system path string and the system
+ // path information buffer.
+ //
+
+ if ( (newFileSecurityDescriptor != NULL) &&
+ (shi502->shi502_reserved != 0) ) {
+
+ (VOID) RtlDeleteSecurityObject ( &newFileSecurityDescriptor );
+ }
+
+ if ( capturedBuffer != NULL ) {
+ MIDL_user_free( capturedBuffer );
+ }
+
+ if ( srp != NULL ) {
+ SsFreeSrp( srp );
+ }
+
+ if ( ntSharePath.Buffer != NULL ) {
+ RtlFreeUnicodeString( &ntSharePath );
+ }
+ return error;
+
+} // NetrShareAdd
+
+
+NET_API_STATUS
+NetrShareCheck (
+ IN LPWSTR ServerName,
+ IN LPWSTR Device,
+ OUT LPDWORD Type
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements NetShareCheck by calling NetrShareEnum.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ DWORD totalEntries;
+ DWORD entriesRead;
+ ULONG i;
+ PSHARE_INFO_2 shi2;
+ NET_API_STATUS error;
+ LPBYTE buffer;
+
+ ServerName;
+
+ //
+ // Call ShareEnumCommon to actually get the information about what
+ // the shares are on the server. We use this routine rather than
+ // calling NetrShareEnum because NetShareCheck requires no privilege
+ // to execute, and we don't want the security checks in
+ // NetrShareEnum.
+ //
+
+ error = ShareEnumCommon(
+ 2,
+ &buffer,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ NULL
+ );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ SS_ASSERT( totalEntries == entriesRead );
+
+ //
+ // Attempt to find the drive letter in a share's path name.
+ //
+
+ for ( shi2 = (PSHARE_INFO_2)buffer, i = 0; i < totalEntries; shi2++, i++ ) {
+
+ if ( shi2->shi2_path != NULL && *Device == *shi2->shi2_path ) {
+
+ //
+ // Something on the specified disk is shared--free the buffer
+ // and return the type of share.
+ //
+
+ *Type = shi2->shi2_type & ~STYPE_SPECIAL;
+ MIDL_user_free( buffer );
+
+ return NO_ERROR;
+ }
+ }
+
+ //
+ // Nothing on the specified disk is shared. Return an error.
+ //
+
+ MIDL_user_free( buffer );
+ return NERR_DeviceNotShared;
+
+} // NetrShareCheck
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareDel (
+ IN LPWSTR ServerName,
+ IN LPWSTR NetName,
+ IN DWORD Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetShareDel function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ SHARE_DEL_HANDLE handle;
+
+ error = NetrShareDelStart( ServerName, NetName, Reserved, &handle );
+
+ if ( error == NO_ERROR ) {
+ error = NetrShareDelCommit( &handle );
+ }
+
+ return error;
+
+} // NetrShareDel
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareDelStart (
+ IN LPWSTR ServerName,
+ IN LPWSTR NetName,
+ IN DWORD Reserved,
+ IN PSHARE_DEL_HANDLE ContextHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the first phase of the share deletion
+ function, which simply remembers that the specified share is to be
+ deleted. The NetrShareDelCommit function actually deletes the
+ share. This two-phase deletion is used to delete IPC$, which is
+ the share used for named pipes, so that RPC can be used to delete
+ the IPC$ share without receiving RPC errors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSHARE_INFO_2 shareInfo;
+ DWORD entriesRead;
+ DWORD totalEntries;
+ DWORD shareType;
+ BOOL isPrintShare;
+ BOOL isSpecial;
+ PSRVSVC_SECURITY_OBJECT securityObject;
+ PSHARE_DEL_CONTEXT context;
+
+ ServerName, Reserved;
+
+ //
+ // A share name must be specified.
+ //
+
+ if ( (NetName == NULL) || (*NetName == '\0') ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // First determine what kind of share is being deleted.
+ //
+
+ error = ShareEnumCommon(
+ 2,
+ (LPBYTE *)&shareInfo,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ NetName
+ );
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+ if ( entriesRead == 0 ) {
+ return NERR_NetNameNotFound;
+ }
+
+ shareType = shareInfo->shi2_type & ~STYPE_SPECIAL;
+ isSpecial = (BOOL)((shareInfo->shi2_type & STYPE_SPECIAL) != 0);
+
+ isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
+
+ MIDL_user_free( shareInfo );
+
+ //
+ // Make sure that the caller is allowed to delete this share.
+ //
+
+ if ( isSpecial ) {
+ securityObject = &SsShareAdminSecurityObject;
+ } else if ( isPrintShare ) {
+ securityObject = &SsSharePrintSecurityObject;
+ } else {
+ securityObject = &SsShareFileSecurityObject;
+ }
+
+ error = SsCheckAccess( securityObject, SRVSVC_SHARE_INFO_SET );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ //
+ // Set up context for the commit phase.
+ //
+
+ context = MIDL_user_allocate(
+ sizeof(SHARE_DEL_CONTEXT) +
+ wcslen(NetName)*sizeof(WCHAR) + sizeof(WCHAR)
+ );
+
+ if ( context == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory(
+ context,
+ sizeof(SHARE_DEL_CONTEXT) +
+ wcslen(NetName)*sizeof(WCHAR) + sizeof(WCHAR)
+ );
+
+ context->IsPrintShare = isPrintShare;
+ context->IsSpecial = isSpecial;
+
+ wcscpy( (LPWSTR)(context + 1), NetName );
+
+ RtlInitUnicodeString( &context->Srp.Name1, (LPWSTR)(context + 1) );
+
+ //
+ // Return the context pointer as an RPC context handle.
+ //
+
+ *ContextHandle = context;
+
+ return NO_ERROR;
+
+} // NetrShareDelStart
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareDelCommit (
+ IN PSHARE_DEL_HANDLE ContextHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the second phase of the share deletion
+ function, which actually deletes the share. The first phase,
+ NetrShareDelStart simply remembers that the share is to be deleted.
+ This two-phase deletion is used to delete IPC$, which is the share
+ used for named pipes, so that RPC can be used to delete the IPC$
+ share without receiving RPC errors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSHARE_DEL_CONTEXT context;
+
+ //
+ // The context handle is a pointer to allocated storage containing
+ // the name of the share being deleted and other useful information.
+ // Copy the pointer, then clear the context handle.
+ //
+
+ context = *ContextHandle;
+ *ContextHandle = NULL;
+
+ //
+ // Send the request on to the server.
+ //
+
+ error = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_NET_SHARE_DEL,
+ &context->Srp,
+ NULL,
+ 0
+ );
+
+ //
+ // If the request succeeded, remove the value corresponding to the
+ // share from the Shares key, thus effecting a sticky share
+ // deletion.
+ //
+ // We don't do this if this is an admin share being deleted. No
+ // registry information is kept for these shares.
+ //
+
+ if ( (error == NO_ERROR) && !context->IsSpecial ) {
+ SsRemoveShareFromRegistry( (LPWSTR)(context + 1) );
+ }
+
+ //
+ // If a print share was successfully deleted, decrement the number
+ // of print shares and update the exported (announced) server type.
+ //
+
+ if ( context->IsPrintShare ) {
+ InterlockedDecrement( &SsData.NumberOfPrintShares );
+ SsSetExportedServerType( NULL, FALSE, TRUE );
+ }
+
+ //
+ // Free the context.
+ //
+
+ MIDL_user_free( context );
+
+ return error;
+
+} // NetrShareDelCommit
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareDelSticky (
+ IN LPWSTR ServerName,
+ IN LPWSTR NetName,
+ IN DWORD Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the NetShareDelSticky function. It removes
+ the named share from the sticky share list in the registry. The
+ primary use of this function is to delete a sticky share whose
+ root directory has been deleted, thus preventing actual recreation
+ of the share, but whose entry still exists in the registry. It can
+ also be used to remove the persistence of a share without deleting
+ the current incarnation of the share.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSHARE_INFO_2 shareInfo, shi2;
+ DWORD entriesRead;
+ DWORD totalEntries;
+ DWORD shareType;
+ ULONG i;
+ BOOL isPrintShare;
+ PSRVSVC_SECURITY_OBJECT securityObject;
+
+ ServerName, Reserved;
+
+
+ //
+ // A share name must be specified.
+ //
+
+ if ( (NetName == NULL) || (*NetName == '\0') ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // First determine what kind of share is being deleted.
+ //
+
+ error = ShareEnumSticky(
+ 2,
+ (LPBYTE *)&shareInfo,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL
+ );
+
+ if ( error != NO_ERROR ) {
+
+ return error;
+
+ } else if ( entriesRead == 0 ) {
+
+ return NERR_NetNameNotFound;
+ }
+
+ for ( shi2 = shareInfo, i = 0 ; i < entriesRead; i++, shi2++ ) {
+
+ if ( _wcsicmp( shi2->shi2_netname, NetName ) == 0 ) {
+ break;
+ }
+ }
+
+ //
+ // Does it exist?
+ //
+
+ if ( i == entriesRead ) {
+ MIDL_user_free( shareInfo );
+ return NERR_NetNameNotFound;
+ }
+
+ //
+ // Use appropriate security object based on whether it is a print
+ // share or not. Admin shares are not sticky.
+ //
+
+ shareType = shi2->shi2_type & ~STYPE_SPECIAL;
+ isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
+
+ MIDL_user_free( shareInfo );
+
+ //
+ // Make sure that the caller is allowed to delete this share.
+ //
+
+ if ( isPrintShare ) {
+ securityObject = &SsSharePrintSecurityObject;
+ } else {
+ securityObject = &SsShareFileSecurityObject;
+ }
+
+ error = SsCheckAccess(
+ securityObject,
+ SRVSVC_SHARE_INFO_SET
+ );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ //
+ // Remove the value corresponding to the share from the Shares key,
+ // thus effecting a sticky share deletion.
+ //
+
+ error = SsRemoveShareFromRegistry( NetName );
+
+ if ( error == ERROR_FILE_NOT_FOUND ) {
+ error = NERR_NetNameNotFound;
+ }
+
+ return error;
+
+} // NetrShareDelSticky
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareEnum (
+ SRVSVC_HANDLE ServerName,
+ LPSHARE_ENUM_STRUCT InfoStruct,
+ DWORD PreferredMaximumLength,
+ LPDWORD TotalEntries,
+ LPDWORD ResumeHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetShareEnum function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ ACCESS_MASK desiredAccess;
+
+ ServerName;
+
+ //
+ // Determine the desired access.
+ //
+
+ switch ( InfoStruct->Level ) {
+
+ case 0:
+ case 1:
+ desiredAccess = SRVSVC_SHARE_USER_INFO_GET;
+ break;
+
+ case 2:
+ case 502:
+ desiredAccess = SRVSVC_SHARE_ADMIN_INFO_GET;
+ break;
+
+ default:
+
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsSharePrintSecurityObject,
+ desiredAccess
+ );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ //
+ // Use the common routine to get the information.
+ //
+
+ return ShareEnumCommon(
+ InfoStruct->Level,
+ (LPBYTE *)&InfoStruct->ShareInfo.Level2->Buffer,
+ PreferredMaximumLength,
+ &InfoStruct->ShareInfo.Level2->EntriesRead,
+ TotalEntries,
+ ResumeHandle,
+ NULL
+ );
+
+} // NetrShareEnum
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareEnumSticky (
+ SRVSVC_HANDLE ServerName,
+ LPSHARE_ENUM_STRUCT InfoStruct,
+ DWORD PreferredMaximumLength,
+ LPDWORD TotalEntries,
+ LPDWORD ResumeHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetShareEnumSticky function.
+
+Arguments:
+
+ ServerName - the name of the server whose shares we want to enumerate.
+ InfoStruct - pointer to a PSHARE_ENUM_STRUCT that will contain the
+ output buffer upon completion.
+ PreferredMaximumLength - an advisory value that specifies the maximum
+ number of bytes the client is expecting to be returned. If -1, the
+ client expects the whole list to be returned.
+ TotalEntries - Upon return, will contain the number of entries that
+ were available.
+ ResumeHandle - is not NULL, will contain the resume handle that can be
+ used to continue a search.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ ACCESS_MASK desiredAccess;
+
+ ServerName;
+
+ //
+ // Determine the desired access.
+ //
+
+ switch ( InfoStruct->Level ) {
+
+ case 0:
+ case 1:
+ desiredAccess = SRVSVC_SHARE_USER_INFO_GET;
+ break;
+
+ case 2:
+ case 502:
+ desiredAccess = SRVSVC_SHARE_ADMIN_INFO_GET;
+ break;
+
+ default:
+
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsSharePrintSecurityObject,
+ desiredAccess
+ );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ //
+ // Use the common routine to get the information.
+ //
+
+ return ShareEnumSticky(
+ InfoStruct->Level,
+ (LPBYTE *)&InfoStruct->ShareInfo.Level2->Buffer,
+ PreferredMaximumLength,
+ &InfoStruct->ShareInfo.Level2->EntriesRead,
+ TotalEntries,
+ ResumeHandle
+ );
+
+} // NetrShareEnumSticky
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareGetInfo (
+ IN LPWSTR ServerName,
+ IN LPWSTR NetName,
+ IN DWORD Level,
+ OUT LPSHARE_INFO Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetShareGetInfo function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSHARE_INFO_2 shareInfo;
+ ULONG entriesRead;
+ ULONG totalEntries;
+ ACCESS_MASK desiredAccess;
+
+ ServerName;
+
+ //
+ // A share name must be specified.
+ //
+
+ if ( (NetName == NULL) || (*NetName == '\0') ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Determine the desired access.
+ //
+
+ switch ( Level ) {
+
+ case 0:
+ case 1:
+ case 1005:
+ desiredAccess = SRVSVC_SHARE_USER_INFO_GET;
+ break;
+
+ case 2:
+ case 502:
+ desiredAccess = SRVSVC_SHARE_ADMIN_INFO_GET;
+ break;
+
+ default:
+
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsSharePrintSecurityObject,
+ desiredAccess
+ );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ //
+ // Use the common routine to get the information.
+ //
+
+ error = ShareEnumCommon(
+ Level,
+ (LPBYTE *)&shareInfo,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ NetName
+ );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+ if ( entriesRead == 0 ) {
+ return NERR_NetNameNotFound;
+ }
+ SS_ASSERT( entriesRead == 1 );
+
+ //
+ // Make sure that the caller is allowed to get share information on
+ // this share.
+ //
+
+ if ( Level == 502 ) {
+ Buffer->ShareInfo502 = (LPSHARE_INFO_502_I)shareInfo;
+ } else {
+ Buffer->ShareInfo2 = (LPSHARE_INFO_2)shareInfo;
+ }
+ return NO_ERROR;
+
+} // NetrShareGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrShareSetInfo (
+ IN LPWSTR ServerName,
+ IN LPWSTR NetName,
+ IN DWORD Level,
+ IN LPSHARE_INFO Buffer,
+ OUT LPDWORD ErrorParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ NetShareSetInfo function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+ DWORD entriesRead;
+ DWORD totalEntries;
+ DWORD shareType;
+ BOOL isPrintShare;
+ BOOL isSpecial;
+ PSRVSVC_SECURITY_OBJECT securityObject;
+ PVOID capturedBuffer;
+ ULONG bufferLength;
+
+ LPWSTR remark = NULL;
+ ULONG maxUses = 0;
+ PSECURITY_DESCRIPTOR fileSd = NULL;
+ PSECURITY_DESCRIPTOR newFileSd = NULL;
+
+ BOOL setRemark;
+ BOOL setFileSd;
+ BOOL set1005Info = FALSE;
+
+ DWORD set1005Value = 0;
+
+ PSHARE_INFO_2 shi2;
+ SHARE_INFO_2 localShi2;
+
+ ServerName;
+
+ //
+ // Check that user input buffer is not NULL
+ //
+ if (Buffer->ShareInfo2 == NULL) {
+ SET_ERROR_PARAMETER(PARM_ERROR_UNKNOWN);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Determine what the caller is trying to set.
+ //
+
+ switch ( Level ) {
+
+ case 502:
+
+ fileSd = Buffer->ShareInfo502->shi502_security_descriptor;
+
+ // *** lack of break is intentional!
+
+ case 2:
+
+ maxUses = Buffer->ShareInfo2->shi2_max_uses;
+
+ // *** lack of break is intentional!
+
+ case 1:
+
+ remark = Buffer->ShareInfo2->shi2_remark;
+
+ break;
+
+ case SHARE_REMARK_INFOLEVEL:
+
+ remark = Buffer->ShareInfo1004->shi1004_remark;
+
+ break;
+
+ case SHARE_MAX_USES_INFOLEVEL:
+
+ maxUses = Buffer->ShareInfo1006->shi1006_max_uses;
+
+ break;
+
+ case SHARE_FILE_SD_INFOLEVEL:
+
+ fileSd = Buffer->ShareInfo1501->shi1501_security_descriptor;
+
+ break;
+
+#if 0
+ case 1005:
+ set1005Info = TRUE;
+ set1005Value = Buffer->ShareInfo1005->shi1005_flags;
+ break;
+#endif
+
+ default:
+
+ SS_PRINT(( "NetrShareSetInfo: invalid level: %ld\n", Level ));
+ SET_ERROR_PARAMETER( 0 );
+ return ERROR_INVALID_LEVEL;
+ }
+
+ setRemark = (BOOLEAN)( remark != NULL );
+ setFileSd = (BOOLEAN)( fileSd != NULL );
+
+ //
+ // A share name must be specified.
+ //
+
+ if ( (NetName == NULL) || (*NetName == '\0') ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Determine what kind of share is being modified.
+ //
+
+ error = ShareEnumCommon(
+ 2,
+ (LPBYTE *)&shi2,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ NetName
+ );
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+ if ( entriesRead == 0 ) {
+ return NERR_NetNameNotFound;
+ }
+
+ shareType = shi2->shi2_type & ~STYPE_SPECIAL;
+ isSpecial = (BOOL)((shi2->shi2_type & STYPE_SPECIAL) != 0);
+
+ MIDL_user_free( shi2 );
+
+ //
+ // The share ACL cannot be changed on admin shares.
+ //
+ if ( isSpecial && setFileSd ) {
+ SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Figure out which kind of share this is.
+ //
+
+ isPrintShare = (BOOL)(shareType == STYPE_PRINTQ);
+
+ //
+ // Only disk shares can be put into the Dfs
+ //
+ if( set1005Info && shareType != STYPE_DISKTREE ) {
+ error = ERROR_BAD_DEV_TYPE;
+ goto exit;
+ }
+
+ //
+ // Make sure that the caller is allowed to set share information on
+ // this share.
+ //
+
+ if ( isSpecial || set1005Info ) {
+ securityObject = &SsShareAdminSecurityObject;
+ } else if ( isPrintShare ) {
+ securityObject = &SsSharePrintSecurityObject;
+ } else {
+ securityObject = &SsShareFileSecurityObject;
+ }
+
+ error = SsCheckAccess( securityObject, SRVSVC_SHARE_INFO_SET );
+
+ if ( error != NO_ERROR ) {
+ return error;
+ }
+
+ //
+ // Just return success if not trying to set anything.
+ //
+
+ if ( !setRemark && (maxUses == 0) && !setFileSd && !set1005Info ) {
+ return NO_ERROR;
+ }
+
+ //
+ // The remark must be no longer than MAXCOMMENTSZ.
+ //
+
+ if ( setRemark ) {
+ if ( STRLEN(remark) > MAXCOMMENTSZ ) {
+ SET_ERROR_PARAMETER( SHARE_REMARK_PARMNUM );
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Mapped the security descriptor to remove the generic permissions
+ //
+
+ if ( setFileSd ) {
+
+ error = ShareAssignSecurityDescriptor(
+ fileSd,
+ &newFileSd
+ );
+
+ if ( error != NO_ERROR ) {
+ SS_PRINT(( "NetrShareSetInfo: ShareAssignSecurityDescriptor "
+ "error: %d\n", error ));
+ SET_ERROR_PARAMETER( SHARE_FILE_SD_PARMNUM );
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Allocate a request packet.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+
+ srp->Level = Level;
+
+ //
+ // Set up the share name.
+ //
+
+ RtlInitUnicodeString( &srp->Name1, NetName );
+
+ //
+ // Set up the MaxUses field. If equal to 0, then it won't be changed
+ // by the server.
+ //
+
+ srp->Parameters.Set.Api.ShareInfo.MaxUses = maxUses;
+
+ //
+ // Capture the share data structure passed in.
+ //
+
+ localShi2.shi2_netname = NetName;
+
+ if( set1005Info == TRUE ) {
+ srp->Flags = set1005Value;
+ capturedBuffer = NULL;
+ bufferLength = 0;
+
+ } else {
+ capturedBuffer = CaptureShareInfo(
+ Level,
+ &localShi2,
+ 0, // ShareType, unused for SHARE_SET_INFO
+ NULL,
+ remark,
+ NULL,
+ newFileSd,
+ &bufferLength
+ );
+
+ if ( capturedBuffer == NULL ) {
+ SET_ERROR_PARAMETER( 0 );
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+ }
+
+ //
+ // Send the request to the server.
+ //
+
+ error = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_NET_SHARE_SET_INFO,
+ srp,
+ capturedBuffer,
+ bufferLength
+ );
+
+ //
+ // If the request succeeded, modify the share's value in the Shares
+ // key, thus effecting a sticky change.
+ //
+ // We don't do this if this is an admin share being modified. No
+ // registry information is kept for these shares.
+ //
+
+ if ( (error == NO_ERROR) && !isSpecial && !set1005Info ) {
+
+ DWORD entriesRead;
+ DWORD totalEntries;
+ NET_API_STATUS error2;
+
+ error2 = ShareEnumCommon(
+ 2,
+ (LPBYTE *)&shi2,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ NetName
+ );
+ if ( error2 == NO_ERROR ) {
+ SsAddShareToRegistry( shi2, newFileSd );
+ MIDL_user_free( shi2 );
+ }
+
+ }
+
+ //
+ // Set up the error parameter if requested and return.
+ //
+
+ SET_ERROR_PARAMETER( srp->Parameters.Set.ErrorParameter );
+
+ SsFreeSrp( srp );
+
+exit:
+
+ if ( newFileSd != NULL ) {
+ (VOID)RtlDeleteSecurityObject( &newFileSd );
+ }
+
+ if( capturedBuffer != NULL ) {
+ MIDL_user_free( capturedBuffer );
+ }
+
+ return error;
+
+} // NetrShareSetInfo
+
+
+PVOID
+CaptureShareInfo (
+ IN DWORD Level,
+ IN PSHARE_INFO_2 Shi2,
+ IN DWORD ShareType OPTIONAL,
+ IN LPWSTR Path OPTIONAL,
+ IN LPWSTR Remark OPTIONAL,
+ IN PSECURITY_DESCRIPTOR ConnectSecurityDescriptor OPTIONAL,
+ IN PSECURITY_DESCRIPTOR FileSecurityDescriptor OPTIONAL,
+ OUT PULONG CapturedBufferLength
+ )
+
+{
+ PSHARE_INFO_502 capturedShi502;
+ ULONG capturedBufferLength;
+ PCHAR variableData;
+ ULONG pathNameLength;
+ ULONG shareNameLength;
+ ULONG remarkLength;
+ ULONG connectSDLength = 0;
+ ULONG fileSdLength = 0;
+
+ //
+ // Determine the lengths of the strings in the buffer and the total
+ // length of the buffer.
+ //
+
+ if ( Shi2->shi2_netname == NULL ) {
+ shareNameLength = 0;
+ } else {
+ shareNameLength = SIZE_WSTR( Shi2->shi2_netname );
+ }
+
+ if ( Path == NULL ) {
+ pathNameLength = 0;
+ } else {
+ pathNameLength = SIZE_WSTR( Path );
+ }
+
+ if ( Remark == NULL ) {
+ remarkLength = 0;
+ } else {
+ remarkLength = SIZE_WSTR( Remark );
+ }
+
+ if ( ARGUMENT_PRESENT( ConnectSecurityDescriptor ) ) {
+
+ //
+ // Allocate extra space for the security descriptor since it needs
+ // to be longword-aligned and there may be padding in front of it.
+ //
+
+ connectSDLength =
+ RtlLengthSecurityDescriptor( ConnectSecurityDescriptor ) +
+ sizeof(ULONG);
+ }
+
+ if ( ARGUMENT_PRESENT( FileSecurityDescriptor ) ) {
+ //
+ // ULONG added for alignment.
+ //
+
+ fileSdLength = RtlLengthSecurityDescriptor( FileSecurityDescriptor ) +
+ sizeof(ULONG);
+ }
+
+ //
+ // Allocate a buffer in which to capture the share information.
+ //
+
+ capturedBufferLength = sizeof(SHARE_INFO_502) +
+ shareNameLength +
+ remarkLength +
+ pathNameLength +
+ connectSDLength +
+ fileSdLength;
+
+ //
+ // Allocate a buffer to hold the input information.
+ //
+
+ capturedShi502 = MIDL_user_allocate( capturedBufferLength );
+
+ if ( capturedShi502 == NULL ) {
+ *CapturedBufferLength = 0;
+ return NULL;
+ }
+
+ //
+ // Copy over the share info structure.
+ //
+
+ *((PSHARE_INFO_2) capturedShi502) = *Shi2;
+
+ //
+ // Optionally override the share type.
+ //
+
+ if ( ShareType != 0 ) {
+ capturedShi502->shi502_type = ShareType;
+ }
+
+ //
+ // Capture the share name.
+ //
+
+ variableData = (PCHAR)( capturedShi502 + 1 );
+
+ if ( shareNameLength != 0 ) {
+ capturedShi502->shi502_netname = (LPWSTR)variableData;
+ RtlCopyMemory( variableData, Shi2->shi2_netname, shareNameLength );
+ variableData += shareNameLength;
+ } else {
+ capturedShi502->shi502_netname = NULL;
+ }
+
+ //
+ // Capture the remark.
+ //
+
+ if ( remarkLength != 0 ) {
+ capturedShi502->shi502_remark = (LPWSTR)variableData;
+ RtlCopyMemory( variableData, Remark, remarkLength );
+ variableData += remarkLength;
+ } else {
+ capturedShi502->shi502_remark = NULL;
+ }
+
+ //
+ // Capture the path.
+ //
+
+ if ( pathNameLength > 0 ) {
+ capturedShi502->shi502_path = (LPWSTR)variableData;
+ RtlCopyMemory( variableData, Path, pathNameLength );
+ variableData += pathNameLength;
+ } else {
+ capturedShi502->shi502_path = NULL;
+ }
+
+ //
+ // Capture the security descriptor. Use the shi502_permissions field
+ // to contain the offset to the security descriptor in the buffer.
+ //
+
+ if ( ARGUMENT_PRESENT( ConnectSecurityDescriptor ) ) {
+
+ variableData = (PCHAR)( ((ULONG)variableData + 3) & ~3 );
+ capturedShi502->shi502_permissions = (ULONG)variableData;
+ variableData += (connectSDLength - sizeof(ULONG));
+
+ RtlCopyMemory(
+ (PVOID)capturedShi502->shi502_permissions,
+ ConnectSecurityDescriptor,
+ connectSDLength - sizeof(ULONG)
+ );
+ } else {
+ capturedShi502->shi502_permissions = 0;
+ }
+
+ //
+ // Capture the self relative form of the file security descriptor.
+ //
+
+ if ( ARGUMENT_PRESENT( FileSecurityDescriptor ) ) {
+
+ variableData = (PCHAR)( ((ULONG)variableData + 3) & ~3 );
+ capturedShi502->shi502_security_descriptor = (LPBYTE) variableData;
+ variableData += ( fileSdLength - sizeof(ULONG)) ;
+
+ RtlCopyMemory(
+ (PVOID)capturedShi502->shi502_security_descriptor,
+ FileSecurityDescriptor,
+ fileSdLength - sizeof(ULONG)
+ );
+
+ } else {
+ capturedShi502->shi502_security_descriptor = (LPBYTE) NULL;
+ }
+
+
+ //
+ // Convert all the pointers in the structure to offsets from the
+ // beginning of the structure.
+ //
+
+ POINTER_TO_OFFSET( capturedShi502->shi502_netname, capturedShi502 );
+ POINTER_TO_OFFSET( capturedShi502->shi502_remark, capturedShi502 );
+ POINTER_TO_OFFSET( capturedShi502->shi502_path, capturedShi502 );
+ POINTER_TO_OFFSET( (PCHAR)capturedShi502->shi502_permissions, capturedShi502 );
+ POINTER_TO_OFFSET( (PCHAR)capturedShi502->shi502_security_descriptor, capturedShi502 );
+
+ //
+ // Set up the length of the captured buffer to return to the caller
+ // and return the captures structure.
+ //
+
+ *CapturedBufferLength = capturedBufferLength;
+
+ return capturedShi502;
+
+} // CaptureShareInfo
+
+NET_API_STATUS
+DisallowSharedLanmanNetDrives(
+ IN PUNICODE_STRING NtSharePath
+ )
+{
+ NET_API_STATUS error = NERR_Success;
+ NTSTATUS status;
+ HANDLE linkHandle;
+ OBJECT_ATTRIBUTES objAttr;
+ UNICODE_STRING linkTarget;
+ ULONG returnedLength = 0;
+ UNICODE_STRING tempNtPath;
+
+ linkTarget.Buffer = NULL;
+ linkTarget.MaximumLength = 0;
+ linkTarget.Length = 0;
+ tempNtPath = *NtSharePath;
+
+ //
+ // Remove the trailing '\\'
+ //
+
+ tempNtPath.Length -= 2;
+
+ InitializeObjectAttributes(
+ &objAttr,
+ &tempNtPath,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ NULL
+ );
+
+ status = NtOpenSymbolicLinkObject(
+ &linkHandle,
+ SYMBOLIC_LINK_QUERY,
+ &objAttr
+ );
+
+
+ if ( !NT_SUCCESS(status) ) {
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Get the size of the buffer needed.
+ //
+
+ status = NtQuerySymbolicLinkObject(
+ linkHandle,
+ &linkTarget,
+ &returnedLength
+ );
+
+
+ if ( !NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL ) {
+ NtClose( linkHandle );
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Allocate our buffer
+ //
+
+ linkTarget.Length = (USHORT)returnedLength;
+ linkTarget.MaximumLength = (USHORT)(returnedLength + sizeof(WCHAR));
+ linkTarget.Buffer = MIDL_user_allocate( linkTarget.MaximumLength );
+
+ if ( linkTarget.Buffer == NULL ) {
+ NtClose( linkHandle );
+ error = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+
+ status = NtQuerySymbolicLinkObject(
+ linkHandle,
+ &linkTarget,
+ &returnedLength
+ );
+
+ NtClose( linkHandle );
+ if ( !NT_SUCCESS(status) ) {
+ error = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // See if this is a lanman drive
+ //
+
+ if (_wcsnicmp(
+ linkTarget.Buffer,
+ DD_NFS_DEVICE_NAME_U,
+ wcslen(DD_NFS_DEVICE_NAME_U)) == 0) {
+
+ error = NERR_RedirectedPath;
+ goto exit;
+ }
+
+exit:
+
+ if ( linkTarget.Buffer != NULL ) {
+ MIDL_user_free( linkTarget.Buffer );
+ }
+
+ return(error);
+
+} // DisallowSharedLanmanNetDrives
+
+NET_API_STATUS
+FillStickyShareInfo(
+ IN PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo,
+ IN PSHARE_INFO_502 Shi502
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in the output buffer with data from the shi502
+ structure.
+
+Arguments:
+
+ ShareEnumInfo - contains the parameters passed in through the
+ NetShareEnumSticky api.
+ Shi502 - pointer to a shi502 structure
+
+Return Value:
+
+ status of operation.
+
+--*/
+
+{
+
+ PSHARE_INFO_502 newShi502;
+ PCHAR endOfVariableData;
+
+ ShareEnumInfo->TotalBytesNeeded += SizeShares(
+ ShareEnumInfo->Level,
+ Shi502
+ );
+
+
+ //
+ // If we have more data but ran out of space, return ERROR_MORE_DATA
+ //
+
+ if ( ShareEnumInfo->TotalBytesNeeded >
+ ShareEnumInfo->OutputBufferLength ) {
+ return(ERROR_MORE_DATA);
+ }
+
+ //
+ // Transfer data from the share info 502 structure to the output
+ // buffer.
+ //
+
+ newShi502 = (PSHARE_INFO_502)ShareEnumInfo->StartOfFixedData;
+ ShareEnumInfo->StartOfFixedData += FIXED_SIZE_OF_SHARE(ShareEnumInfo->Level);
+
+ endOfVariableData = ShareEnumInfo->EndOfVariableData;
+
+ //
+ // Case on the level to fill in the fixed structure appropriately.
+ // We fill in actual pointers in the output structure. This is
+ // possible because we are in the server FSD, hence the server
+ // service's process and address space.
+ //
+ // *** This routine assumes that the fixed structure will fit in the
+ // buffer!
+ //
+ // *** Using the switch statement in this fashion relies on the fact
+ // that the first fields on the different share structures are
+ // identical.
+ //
+
+ switch( ShareEnumInfo->Level ) {
+
+ case 502:
+
+ if ( Shi502->shi502_security_descriptor != NULL ) {
+
+ ULONG fileSDLength;
+ fileSDLength = RtlLengthSecurityDescriptor(
+ Shi502->shi502_security_descriptor
+ );
+
+ //
+ // DWord Align
+ //
+
+ endOfVariableData = (PCHAR) ( (ULONG) ( endOfVariableData -
+ fileSDLength ) & ~3 );
+
+ newShi502->shi502_security_descriptor = endOfVariableData;
+ newShi502->shi502_reserved = fileSDLength;
+
+ RtlMoveMemory(
+ newShi502->shi502_security_descriptor,
+ Shi502->shi502_security_descriptor,
+ fileSDLength
+ );
+
+ } else {
+ newShi502->shi502_security_descriptor = NULL;
+ newShi502->shi502_reserved = 0;
+ }
+
+ case 2:
+
+ //
+ // Set level 2 specific fields in the buffer. Since this server
+ // can only have user-level security, share permissions are
+ // meaningless.
+ //
+
+ newShi502->shi502_permissions = 0;
+ newShi502->shi502_max_uses = Shi502->shi502_max_uses;
+
+ //
+ // To get the current uses, we need to query the server for this
+ //
+
+ {
+ PSHARE_INFO_2 shareInfo;
+ NET_API_STATUS error;
+ DWORD entriesRead;
+ DWORD totalEntries;
+
+ error = ShareEnumCommon(
+ 2,
+ (LPBYTE *)&shareInfo,
+ (DWORD)-1,
+ &entriesRead,
+ &totalEntries,
+ NULL,
+ Shi502->shi502_netname
+ );
+
+ if ( error != NO_ERROR || entriesRead == 0 ) {
+ newShi502->shi502_current_uses = 0;
+ } else {
+ newShi502->shi502_current_uses = shareInfo->shi2_current_uses;
+ MIDL_user_free( shareInfo );
+ }
+ }
+
+ //
+ // Copy the DOS path name to the buffer.
+ //
+
+ if ( Shi502->shi502_path != NULL ) {
+ endOfVariableData -= SIZE_WSTR( Shi502->shi502_path );
+ newShi502->shi502_path = (LPTSTR) endOfVariableData;
+ wcscpy( newShi502->shi502_path, Shi502->shi502_path );
+ } else {
+ newShi502->shi502_path = NULL;
+ }
+
+ //
+ // We don't have per-share passwords (share-level security)
+ // so set the password pointer to NULL.
+ //
+
+ newShi502->shi502_passwd = NULL;
+
+ // *** Lack of break is intentional!
+
+ case 1:
+
+ newShi502->shi502_type = Shi502->shi502_type;
+
+ //
+ // Copy the remark to the buffer. The routine will handle the
+ // case where there is no remark on the share and put a pointer
+ // to a zero terminator in the buffer.
+ //
+
+ if ( Shi502->shi502_remark != NULL ) {
+ endOfVariableData -= SIZE_WSTR( Shi502->shi502_remark );
+ newShi502->shi502_remark = (LPTSTR) endOfVariableData;
+ wcscpy( newShi502->shi502_remark, Shi502->shi502_remark );
+ } else {
+ newShi502->shi502_remark = NULL;
+ }
+
+ // *** Lack of break is intentional!
+
+ case 0:
+
+ //
+ // Copy the share name to the buffer.
+ //
+
+ if ( Shi502->shi502_netname != NULL ) {
+ endOfVariableData -= SIZE_WSTR( Shi502->shi502_netname );
+ newShi502->shi502_netname = (LPTSTR) endOfVariableData;
+ wcscpy( newShi502->shi502_netname, Shi502->shi502_netname );
+ } else {
+ newShi502->shi502_remark = NULL;
+ }
+ break;
+ }
+
+ ShareEnumInfo->EndOfVariableData = endOfVariableData;
+
+ return NO_ERROR;
+
+} // FillStickyShareInfo
+
+
+NET_API_STATUS
+ShareAssignSecurityDescriptor(
+ IN PSECURITY_DESCRIPTOR PassedSecurityDescriptor,
+ OUT PSECURITY_DESCRIPTOR *NewSecurityDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts a the generic mappings in an sd to
+ standards and specifics.
+
+Arguments:
+
+ PassedSecurityDescriptor - Security descriptor passed from the client.
+ NewSecurityDescriptor - Pointer to a buffer to receive the new sd.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+
+ NTSTATUS status;
+ HANDLE token;
+ PISECURITY_DESCRIPTOR tempSD;
+
+ //
+ // Since we don't trust the client, check if sd is valid.
+ //
+
+ if ( !RtlValidSecurityDescriptor( PassedSecurityDescriptor) ) {
+ return(ERROR_INVALID_PARAMETER);
+ }
+
+ //
+ // NULL out the owner, group, and sacl
+ //
+
+ tempSD = PassedSecurityDescriptor;
+ tempSD->Owner = NULL;
+ tempSD->Group = NULL;
+ tempSD->Sacl = NULL;
+ tempSD->Control &=
+ (SE_DACL_DEFAULTED | SE_DACL_PRESENT | SE_SELF_RELATIVE);
+
+
+ //
+ // Impersonate client
+ //
+
+ (VOID)RpcImpersonateClient( NULL );
+
+ status = NtOpenThreadToken(
+ NtCurrentThread(),
+ TOKEN_QUERY,
+ TRUE,
+ &token
+ );
+
+ (VOID)RpcRevertToSelf( );
+
+ if ( !NT_SUCCESS(status) ) {
+ return RtlNtStatusToDosError( status );
+ }
+
+ //
+ // Get a new sd which has the generics mapped to specifics.
+ // the returned sd is in self-relative form.
+ //
+
+ status = RtlNewSecurityObject(
+ NULL,
+ PassedSecurityDescriptor,
+ NewSecurityDescriptor,
+ FALSE,
+ token,
+ &SrvShareFileGenericMapping
+ );
+
+ ASSERT( RtlValidSecurityDescriptor( *NewSecurityDescriptor ) );
+
+ NtClose( token );
+ return RtlNtStatusToDosError( status );
+
+} // ShareAssignSecurityDescriptor
+
+
+void
+SHARE_DEL_HANDLE_rundown (
+ SHARE_DEL_HANDLE ContextHandle
+ )
+{
+ (VOID)NetrShareDelCommit( &ContextHandle );
+
+ return;
+
+} // SHARE_DEL_HANDLE_rundown
+
+
+NET_API_STATUS
+ShareEnumCommon (
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL,
+ IN LPWSTR NetName OPTIONAL
+ )
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ //
+ // Make sure that the level is valid. Since it is an unsigned
+ // value, it can never be less than 0.
+ //
+
+ if ( (Level > 2) && (Level != 502) && (Level != 1005)) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = Level;
+ if ( ARGUMENT_PRESENT( NetName ) ) {
+ srp->Flags = SRP_RETURN_SINGLE_ENTRY;
+ }
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ RtlInitUnicodeString( &srp->Name1, NetName );
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_SHARE_ENUM,
+ srp,
+ (PVOID *)Buffer,
+ PreferredMaximumLength
+ );
+
+ //
+ // Set up return information.
+ //
+
+ *EntriesRead = srp->Parameters.Get.EntriesRead;
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+ if ( *EntriesRead > 0 && ARGUMENT_PRESENT( ResumeHandle ) ) {
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+ SsFreeSrp( srp );
+
+ //
+ // We need to null out the owner, group, and sacl.
+ //
+
+ if ( Level == 502 ) {
+
+ PSHARE_INFO_502 shi502 = (PSHARE_INFO_502) *Buffer;
+ PSECURITY_DESCRIPTOR fileSD;
+ ULONG i;
+
+ for ( i = 0 ; i < *EntriesRead; i++, shi502++ ) {
+
+ fileSD = shi502->shi502_security_descriptor;
+ if ( fileSD != NULL ) {
+
+ PISECURITY_DESCRIPTOR SD = fileSD;
+
+ SD->Owner = NULL;
+ SD->Group = NULL;
+ SD->Sacl = NULL;
+ SD->Control &=
+ (SE_DACL_DEFAULTED | SE_DACL_PRESENT | SE_SELF_RELATIVE);
+ ASSERT( RtlValidSecurityDescriptor( fileSD ) );
+ }
+
+ } // for
+ }
+
+ return error;
+
+} // ShareEnumCommon
+
+
+NET_API_STATUS
+ShareEnumSticky (
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enumerates all the shares kept in the registry.
+
+Arguments:
+
+ Same as NetShareEnumSticky api.
+
+Return Value:
+
+ status of request.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ BOOLEAN getEverything;
+ ULONG oldResumeHandle;
+ SRVSVC_SHARE_ENUM_INFO enumInfo;
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ enumInfo.Level = Level;
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ enumInfo.ResumeHandle = *ResumeHandle;
+ } else {
+ enumInfo.ResumeHandle = 0;
+ }
+
+ oldResumeHandle = enumInfo.ResumeHandle;
+
+ //
+ // If the length of the second buffer is specified as -1, then we
+ // are supposed to get all the information, regardless of size.
+ // Allocate space for the output buffer and try to use it. If this
+ // fails, the SsEnumerateStickyShares will tell us just how much we
+ // really need to allocate.
+ //
+
+ if ( PreferredMaximumLength == 0xFFFFFFFF ) {
+
+ enumInfo.OutputBufferLength = INITIAL_BUFFER_SIZE;
+ getEverything = TRUE;
+
+ } else {
+
+ enumInfo.OutputBufferLength = PreferredMaximumLength;
+ getEverything = FALSE;
+ }
+
+ enumInfo.OutputBuffer = MIDL_user_allocate( enumInfo.OutputBufferLength );
+
+ if ( enumInfo.OutputBuffer == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Make the request
+ //
+
+ error = SsEnumerateStickyShares( &enumInfo );
+
+ //
+ // If the call was successful, or there was an error other than
+ // ERROR_MORE_DATA (which indicates that the buffer wasn't large
+ // enough), or the passed in buffer size was all we're allowed to
+ // allocate, return to the caller.
+ //
+
+ if ( (error != ERROR_MORE_DATA && error != NERR_BufTooSmall) ||
+ !getEverything ) {
+
+ //
+ // If no entries were found, free the buffer and set the pointer
+ // to NULL.
+ //
+
+ if ( enumInfo.EntriesRead == 0 ) {
+ MIDL_user_free( enumInfo.OutputBuffer );
+ enumInfo.OutputBuffer = NULL;
+ }
+
+ goto exit;
+ }
+
+ //
+ // The initial buffer wasn't large enough, and we're allowed to
+ // allocate more. Free the first buffer.
+ //
+
+ MIDL_user_free( enumInfo.OutputBuffer );
+
+ //
+ // Allocate a buffer large enough to hold all the information, plus
+ // a fudge factor in case the amount of information has increased.
+ // If the amount of information increased more than the fudge factor,
+ // then we give up. This should almost never happen.
+ //
+
+ enumInfo.OutputBufferLength = enumInfo.TotalBytesNeeded + EXTRA_ALLOCATION;
+
+ enumInfo.OutputBuffer = MIDL_user_allocate( enumInfo.OutputBufferLength );
+
+ if ( enumInfo.OutputBuffer == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Reset the resume handle in the SRP. It was altered by the first
+ // Enum attempt.
+ //
+
+ enumInfo.ResumeHandle = oldResumeHandle;
+
+ //
+ // Try again to get the information from the server, this time with the
+ // larger buffer.
+ //
+
+ error = SsEnumerateStickyShares( &enumInfo );
+
+exit:
+ //
+ // Set up return information.
+ //
+
+ *Buffer = enumInfo.OutputBuffer;
+ *EntriesRead = enumInfo.EntriesRead;
+ *TotalEntries = enumInfo.TotalEntries;
+ if ( *EntriesRead > 0 && ARGUMENT_PRESENT( ResumeHandle ) ) {
+ *ResumeHandle = enumInfo.ResumeHandle;
+ }
+
+ return error;
+
+} // ShareEnumSticky
+
+
+ULONG
+SizeShares (
+ IN ULONG Level,
+ IN PSHARE_INFO_502 Shi502
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the size the passed-in share would take up in
+ an API output buffer.
+
+Arguments:
+
+ Level - level of request
+ Shi502 - pointer to a shi502 structure
+
+Return Value:
+
+ ULONG - The number of bytes the share would take up in the
+ output buffer.
+
+--*/
+
+{
+ ULONG shareSize = 0;
+
+ switch ( Level ) {
+ case 502:
+ if ( Shi502->shi502_security_descriptor != NULL ) {
+
+ //
+ // add 4 bytes for possible padding
+ //
+
+ shareSize = sizeof( ULONG ) +
+ RtlLengthSecurityDescriptor( Shi502->shi502_security_descriptor );
+ }
+
+ case 2:
+ shareSize += SIZE_WSTR( Shi502->shi502_path );
+
+ case 1:
+ shareSize += SIZE_WSTR( Shi502->shi502_remark );
+
+ case 0:
+ shareSize += SIZE_WSTR( Shi502->shi502_netname );
+
+ }
+
+ return ( shareSize + FIXED_SIZE_OF_SHARE( Level ) );
+
+} // SizeShares
+
+
+BOOLEAN
+ValidSharePath(
+ IN LPWSTR SharePath
+ )
+/*++
+
+Routine Description:
+
+ This routine checks to see if .. and . exists on the path. If they do,
+ then we reject this path name.
+
+Arguments:
+
+ SharePath - The share path to be checked.
+
+Return Value:
+
+ TRUE, if path is ok.
+
+--*/
+
+{
+
+ LPWCH source = SharePath;
+
+ //
+ // Walk through the pathname until we reach the zero terminator. At
+ // the start of this loop, source points to the first charaecter
+ // after a directory separator or the first character of the
+ // pathname.
+ //
+
+ //
+ // Allow the NT naming convention of slash slash . slash through here
+ //
+ if( IS_SLASH_SLASH_NAME( source ) ) {
+
+ //
+ // We have a path which starts with slash slash
+ // Set the buffer ptr so we start checking the pathname after
+ // the slash slash dot
+
+ source += 3;
+ }
+
+ while ( *source != L'\0' ) {
+
+ if ( *source == L'.') {
+ source++;
+ if ( ( IS_PATH_SEPARATOR(*source) ) ||
+ ( (*source++ == L'.') &&
+ IS_PATH_SEPARATOR(*source) ) ) {
+
+ //
+ // '.' and '..' appear as a directory names. Reject.
+ //
+
+ return(FALSE);
+ }
+ }
+
+ //
+ // source does not point to a dot, so continue until we see
+ // another directory separator
+ //
+
+ while ( *source != L'\0' ) {
+ if ( *source++ == L'\\' ) {
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+} // ValidSharePath
diff --git a/private/net/svcdlls/srvsvc/server/srvconfg.h b/private/net/svcdlls/srvsvc/server/srvconfg.h
new file mode 100644
index 000000000..d9b3ee22a
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/srvconfg.h
@@ -0,0 +1,648 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SrvConfg.h
+
+Abstract:
+
+ This file contains default server settings for startup.
+
+Author:
+
+ David Treadwell (davidtr) 1-Mar-1991
+
+Revision History:
+
+--*/
+
+#ifndef _SRVCONFG_
+#define _SRVCONFG_
+
+//
+// The platform ID for NT servers. This indicates the info level that
+// should be called for platform-specific information.
+//
+
+#define DEF_PLATFORM_ID SV_PLATFORM_ID_NT
+#define MIN_PLATFORM_ID SV_PLATFORM_ID_NT
+#define MAX_PLATFORM_ID SV_PLATFORM_ID_NT
+
+//
+// The default name is used for the server set and get info APIs as well
+// as the transport name if no overriding transport name is specified.
+//
+
+#define DEF_NAME L"NTSERVER"
+
+//
+// Version definitions--these indicate LM 3.0.
+//
+
+#define DEF_VERSION_MAJOR 3
+#define MIN_VERSION_MAJOR 3
+#define MAX_VERSION_MAJOR 3
+
+#define DEF_VERSION_MINOR 10
+#define MIN_VERSION_MINOR 10
+#define MAX_VERSION_MINOR 10
+
+//
+// The server type.
+//
+
+#define DEF_TYPE 0
+#define MIN_TYPE 0
+#define MAX_TYPE 0xFFFFFFFF
+
+//
+// The server comment is used only for the server get and set info APIs.
+//
+
+#define DEF_COMMENT L""
+
+//
+// The maximum number of users that may be logged on to the server
+// simultaneously.
+//
+
+#define DEF_USERS 0xFFFFFFFF
+#define MIN_USERS 1
+#define MAX_USERS 0xFFFFFFFF
+
+//
+// The autodisconnect time: when a client is idle for this many minutes,
+// the server closes the connection, but only if the client has no open
+// files/pipes.
+//
+
+#define DEF_DISC 15
+#define MIN_DISC 0 // zero minutes -- disconnect ASAP
+#define MAX_DISC 0xFFFFFFFF
+
+//
+// The IPX autodisconnect time: when a client doesn't send any SMBs
+// for this many minutes, the server closes the 'connection', even if
+// the client has open files/pipes.
+//
+
+#define DEF_CONNECTIONLESSAUTODISC 15
+#define MIN_CONNECTIONLESSAUTODISC 15
+#define MAX_CONNECTIONLESSAUTODISC 0xFFFFFFFF
+
+//
+// Parameters dealing with server announcements: whether the server is
+// hidden (no announcements), the announce interval, the randomization
+// factor for the accounce interval, and whether the server announces
+// itself as a time source.
+//
+
+#define DEF_HIDDEN FALSE
+
+#define DEF_ANNOUNCE 4 * 60
+#define MIN_ANNOUNCE 1
+#define MAX_ANNOUNCE 65535
+
+#define DEF_ANNDELTA 3000
+#define MIN_ANNDELTA 0
+#define MAX_ANNDELTA 65535
+
+#define DEF_TIMESOURCE FALSE
+#define DEF_ACCEPTDOWNLEVELAPIS TRUE
+#define DEF_LMANNOUNCE FALSE
+
+//
+// A fully qualified path to the user directories.
+//
+
+#define DEF_USERPATH L"c:\\"
+
+//
+// The domain name to which to send server announcements.
+//
+
+#define DEF_DOMAIN L"DOMAIN"
+
+//
+// Server "heuristics", enabling various capabilities.
+//
+
+#define DEF_ENABLEOPLOCKS TRUE
+#define DEF_ENABLEFCBOPENS TRUE
+#define DEF_ENABLESOFTCOMPAT TRUE
+#define DEF_ENABLERAW TRUE
+#define DEF_ENABLESHAREDNETDRIVES FALSE
+#define DEF_ENABLEFORCEDLOGOFF TRUE
+#define DEF_ENABLEOPLOCKFORCECLOSE FALSE
+#define DEF_REMOVEDUPLICATESEARCHES TRUE
+#define DEF_RESTRICTNULLSESSACCESS TRUE
+#define DEF_ENABLEWFW311DIRECTIPX TRUE
+
+//
+// Receive buffer size, receive work item count, and receive IRP stack
+// size.
+//
+
+#define DEF_SIZREQBUF 4356
+#define MIN_SIZREQBUF 512
+#define MAX_SIZREQBUF 65535
+
+#define DEF_INITWORKITEMS 4
+#define MIN_INITWORKITEMS 1
+#define MAX_INITWORKITEMS 512
+
+#define DEF_MAXWORKITEMS 128
+#define MIN_MAXWORKITEMS 1
+#define MAX_MAXWORKITEMS 65535 // arbitrary
+
+#define DEF_RAWWORKITEMS 4
+#define MIN_RAWWORKITEMS 1
+#define MAX_RAWWORKITEMS 512
+
+#define DEF_MAXRAWWORKITEMS 16
+#define MIN_MAXRAWWORKITEMS 1
+#define MAX_MAXRAWWORKITEMS 512
+
+#define DEF_IRPSTACKSIZE 5
+#define MIN_IRPSTACKSIZE 1
+#define MAX_IRPSTACKSIZE 12
+
+//
+// Maximum raw mode buffer size. (This isn't actually configurable --
+// the server must always be prepared to receive raw requests for up to
+// 65535 bytes.)
+//
+
+#define DEF_MAXRAWBUFLEN 65535
+#define MIN_MAXRAWBUFLEN 65535
+#define MAX_MAXRAWBUFLEN 65535
+
+//
+// Cache-related parameters.
+//
+
+#define DEF_MAXCOPYREADLEN 8192
+#define MIN_MAXCOPYREADLEN 0
+#define MAX_MAXCOPYREADLEN 0xFFFFFFFF
+
+#define DEF_MAXCOPYWRITELEN 0
+#define MIN_MAXCOPYWRITELEN 0
+#define MAX_MAXCOPYWRITELEN 0xFFFFFFFF
+
+//
+// Free connection count.
+//
+
+#define DEF_MAXFREECONNECTIONS 2
+#define MIN_MAXFREECONNECTIONS 2
+#define MAX_MAXFREECONNECTIONS 100 // arbitrary
+
+#define DEF_MINFREECONNECTIONS 2
+#define MIN_MINFREECONNECTIONS 2
+#define MAX_MINFREECONNECTIONS 32 // arbitrary
+
+//
+// Initial and maximum table sizes.
+//
+
+#define DEF_INITSESSTABLE 4
+#define MIN_INITSESSTABLE 1
+#define MAX_INITSESSTABLE 64
+
+#define DEF_SESSUSERS 2048
+#define MIN_SESSUSERS 1
+#define MAX_SESSUSERS 2048
+#define ABSOLUTE_MAX_SESSION_TABLE_SIZE 2048 // Limited by index bits
+
+#define DEF_INITCONNTABLE 8
+#define MIN_INITCONNTABLE 1
+#define MAX_INITCONNTABLE 128
+
+#define DEF_SESSCONNS 2048
+#define MIN_SESSCONNS 1
+#define MAX_SESSCONNS 2048
+#define ABSOLUTE_MAX_TREE_TABLE_SIZE 2048 // Limited by index bits
+
+#define DEF_INITFILETABLE 16
+#define MIN_INITFILETABLE 1
+#define MAX_INITFILETABLE 256
+
+#define DEF_SESSOPENS 2048
+#define MIN_SESSOPENS 1
+#define MAX_SESSOPENS 2048
+#define ABSOLUTE_MAX_FILE_TABLE_SIZE 2048 // Limited by index bits
+
+#define DEF_INITSEARCHTABLE 8
+#define MIN_INITSEARCHTABLE 1
+#define MAX_INITSEARCHTABLE 2048
+
+#define DEF_OPENSEARCH 2048
+#define MIN_OPENSEARCH 1
+#define MAX_OPENSEARCH 2048
+#define ABSOLUTE_MAX_SEARCH_TABLE_SIZE 2048 // Limited by index bits
+
+#define DEF_MAXGLOBALOPENSEARCH 4096
+#define MIN_MAXGLOBALOPENSEARCH 1
+#define MAX_MAXGLOBALOPENSEARCH 0xFFFFFFFF
+
+#define DEF_INITCOMMTABLE 4
+#define MIN_INITCOMMTABLE 1
+#define MAX_INITCOMMTABLE 32
+
+#define DEF_CHDEVS 32
+#define MIN_CHDEVS 1
+#define MAX_CHDEVS 32
+#define ABSOLUTE_MAX_COMM_DEVICE_TABLE_SIZE 32
+
+//
+// Core search timeouts. The first is for active core searches, the second
+// is for core searches where we have returned STATUS_NO_MORE_FILES. The
+// second should be shorter, as these are presumably complete. All values
+// are specified in seconds.
+//
+
+#define DEF_MAXKEEPSEARCH (60 * 60)
+#define MIN_MAXKEEPSEARCH 10
+#define MAX_MAXKEEPSEARCH 10000
+
+//
+// *** These 3 parameters are no longer used.
+//
+
+#define DEF_MINKEEPSEARCH (60 * 8)
+#define MIN_MINKEEPSEARCH 5
+#define MAX_MINKEEPSEARCH 5000
+
+#define DEF_MAXKEEPCOMPLSEARCH (60 * 10)
+#define MIN_MAXKEEPCOMPLSEARCH 2
+#define MAX_MAXKEEPCOMPLSEARCH 10000
+
+#define DEF_MINKEEPCOMPLSEARCH (60 * 4)
+#define MIN_MINKEEPCOMPLSEARCH 1
+#define MAX_MINKEEPCOMPLSEARCH 1000
+
+//
+// SrvWorkerThreadCountAdd is added to the system CPU count to determine
+// how many worker threads the server will have.
+//
+// *** THIS PARAMETER IS NO LONGER USED!
+//
+
+#define DEF_THREADCOUNTADD 2
+#define MIN_THREADCOUNTADD 0
+#define MAX_THREADCOUNTADD 10
+
+//
+// SrvBlockingThreadCount is the number of blocking threads that get
+// started at server initialization.
+//
+// *** THIS PARAMETER IS NO LONGER USED!
+//
+
+#define DEF_NUMBLOCKTHREADS 2
+#define MIN_NUMBLOCKTHREADS 1
+#define MAX_NUMBLOCKTHREADS 10
+
+//
+// This is the maximum number of threads for each server queue per processor
+//
+#define DEF_MAXTHREADSPERQUEUE 10
+#define MIN_MAXTHREADSPERQUEUE 1
+#define MAX_MAXTHREADSPERQUEUE 65535
+
+//
+// Scavenger thread idle wait time.
+//
+
+#define DEF_SCAVTIMEOUT 30
+#define MIN_SCAVTIMEOUT 1
+#define MAX_SCAVTIMEOUT 300
+
+//
+// The server periodically recomputes the average work queue depth.
+// This is how often the recomputation is done (in secs)
+//
+#define DEF_QUEUESAMPLESECS 5
+#define MIN_QUEUESAMPLESECS 1
+#define MAX_QUEUESAMPLESECS 65535
+
+//
+// For multiprocessor systems, the server tries to dynamically
+// balance the workload over the processors in the system. The
+// processor handling the client's dpc's is known as the preferred
+// processor for this client. The server looks at the average work
+// queue depth for each of the processors in the system. If the
+// client is currently on the preferred processor, but some other
+// processor's average work queue length + current queue length is
+// OTHERQUEUEAFFINITY shorter, then the client is reassigned to
+// that processor
+//
+#define DEF_OTHERQUEUEAFFINITY 3
+#define MIN_OTHERQUEUEAFFINITY 1
+#define MAX_OTHERQUEUEAFFINITY 65535
+
+//
+// If the client is not currently its preferred processor, but the
+// preferred processor's average work queue length + current queue
+// length is no more than PREFERREDAFFINITY items longer, then this
+// client is reassigned to its preferred processor
+//
+#define DEF_PREFERREDAFFINITY 1
+#define MIN_PREFERREDAFFINITY 0
+#define MAX_PREFERREDAFFINITY 65535
+
+//
+// Each client looks at the other processor queues every BALANCECOUNT
+// operations to see if it would be better served by a different
+// processor
+//
+#define DEF_BALANCECOUNT 1500
+#define MIN_BALANCECOUNT 10
+#define MAX_BALANCECOUNT 65535
+
+//
+// If a client is not currently assigned to its preferred processor, we've
+// found that cpu utilization can drop if server responses are sent from the
+// client's preferred processor (most certainly because transport data is not
+// sloshed between cpus). Unfortunately this can adversely affect throughput
+// by a couple of percentage points on some platforms. This setting affects
+// whether these responses are requeued to the preferred processor.
+//
+// OBSOLETE!
+//
+#define DEF_SENDSFROMPREFERREDPROCESSOR TRUE
+
+//
+// Does the server support the bulk transfer SMBs?
+//
+#define DEF_ENABLEBULKTRANSFER FALSE
+
+//
+// Does the server support compressed bulk transfers?
+//
+#define DEF_ENABLECOMPRESSION FALSE
+
+//
+// If an NTAS, should the server automatically create the drive$ shares?
+//
+#define DEF_AUTOSHARESERVER TRUE
+
+//
+// If a workstation, should the server automaticaly create the drive$ shares?
+//
+#define DEF_AUTOSHAREWKS TRUE
+
+//
+// Various information variables for the server.
+//
+
+#define DEF_MAXMPXCT 50
+#define MIN_MAXMPXCT 1
+#define MAX_MAXMPXCT 65535 // limited by SMB word field
+
+//
+// Time server waits for an an oplock to break before failing an open
+// request
+//
+
+#define DEF_OPLOCKBREAKWAIT 35
+#define MIN_OPLOCKBREAKWAIT 10
+#define MAX_OPLOCKBREAKWAIT 180
+
+//
+// Time server waits for an oplock break response.
+//
+
+#define DEF_OPLOCKBREAKRESPONSEWAIT 35
+#define MIN_OPLOCKBREAKRESPONSEWAIT 10
+#define MAX_OPLOCKBREAKRESPONSEWAIT 180
+
+//
+// This is supposed to indicate how many virtual connections are allowed
+// between this server and client machines. It should always be set to
+// one, though more VCs can be established. This duplicates the LM 2.0
+// server's behavior.
+//
+
+#define DEF_SESSVCS 1
+#define MIN_SESSVCS 1
+#define MAX_SESSVCS 1
+
+//
+// Receive work item thresholds
+//
+
+//
+// The minimum desirable number of free receive workitems
+//
+
+#define DEF_MINRCVQUEUE 2
+#define MIN_MINRCVQUEUE 0
+#define MAX_MINRCVQUEUE 10
+
+//
+// The minimum number of free receive work items available before
+// the server will start processing a potentially blocking SMB.
+//
+
+#define DEF_MINFREEWORKITEMS 2
+#define MIN_MINFREEWORKITEMS 0
+#define MAX_MINFREEWORKITEMS 10
+
+//
+// The maximum amount of time an "extra" work item can be idle before it
+// is freed back to the system.
+//
+
+#define DEF_MAXWORKITEMIDLETIME 30 // seconds
+#define MIN_MAXWORKITEMIDLETIME 10
+#define MAX_MAXWORKITEMIDLETIME 1800
+
+//
+// Size of the shared memory section used for communication between the
+// server and XACTSRV.
+//
+
+#define DEF_XACTMEMSIZE 0x100000 // 1 MB
+#define MIN_XACTMEMSIZE 0x10000 // 64k
+#define MAX_XACTMEMSIZE 0x1000000 // 16 MB
+
+//
+// Priority of server FSP threads. Specified relative to the base
+// priority of the process. Valid values are between -2 and 2, or 15.
+//
+
+#define DEF_THREADPRIORITY 1
+#define MIN_THREADPRIORITY 0
+#define MAX_THREADPRIORITY THREAD_BASE_PRIORITY_LOWRT
+
+//
+// Limits on server memory usage.
+//
+
+#define DEF_MAXPAGEDMEMORYUSAGE 0xFFFFFFFF
+#define MIN_MAXPAGEDMEMORYUSAGE 0x100000 // 1MB
+#define MAX_MAXPAGEDMEMORYUSAGE 0xFFFFFFFF
+
+#define DEF_MAXNONPAGEDMEMORYUSAGE 0xFFFFFFFF
+#define MIN_MAXNONPAGEDMEMORYUSAGE 0x100000 // 1MB
+#define MAX_MAXNONPAGEDMEMORYUSAGE 0xFFFFFFFF
+
+//
+// The server keeps a small list of free RFCB structures to avoid hitting
+// the heap. This is the number in that list, per processor
+//
+#define DEF_MAXFREERFCBS 20
+#define MIN_MAXFREERFCBS 0
+#define MAX_MAXFREERFCBS 65535
+
+//
+// The server keeps a small list of free MFCB structures to avoid hitting
+// the heap. This is the number in that list, per processor
+//
+#define DEF_MAXFREEMFCBS 20
+#define MIN_MAXFREEMFCBS 0
+#define MAX_MAXFREEMFCBS 65535
+
+//
+// The server keeps a small list of free LFCB structures to avoid hitting
+// the heap. This is the number in that list, per processor
+//
+#define DEF_MAXFREELFCBS 20
+#define MIN_MAXFREELFCBS 0
+#define MAX_MAXFREELFCBS 65535
+
+//
+// The server keeps a small list of freed pool memory chunks to avoid hitting
+// the heap. This is the number in that list, per processor
+//
+#define DEF_MAXFREEPAGEDPOOLCHUNKS 50
+#define MIN_MAXFREEPAGEDPOOLCHUNKS 0
+#define MAX_MAXFREEPAGEDPOOLCHUNKS 65535
+
+//
+// The chunks that are kept in the free pool list must be at least this size:
+//
+#define DEF_MINPAGEDPOOLCHUNKSIZE 128
+#define MIN_MINPAGEDPOOLCHUNKSIZE 0
+#define MAX_MINPAGEDPOOLCHUNKSIZE 65535
+
+//
+// The chunks must be no larger than this
+//
+#define DEF_MAXPAGEDPOOLCHUNKSIZE 512
+#define MIN_MAXPAGEDPOOLCHUNKSIZE 0
+#define MAX_MAXPAGEDPOOLCHUNKSIZE 65535
+
+//
+// Alert information
+//
+
+#define DEF_ALERTSCHEDULE 5 // 5 minutes
+#define MIN_ALERTSCHEDULE 1
+#define MAX_ALERTSCHEDULE 65535
+
+#define DEF_ERRORTHRESHOLD 10 // 10 errors
+#define MIN_ERRORTHRESHOLD 1
+#define MAX_ERRORTHRESHOLD 65535
+
+#define DEF_NETWORKERRORTHRESHOLD 5 // 5% errors
+#define MIN_NETWORKERRORTHRESHOLD 1
+#define MAX_NETWORKERRORTHRESHOLD 100
+
+#define DEF_DISKSPACETHRESHOLD 10 // 10% free disk space
+#define MIN_DISKSPACETHRESHOLD 0
+#define MAX_DISKSPACETHRESHOLD 99
+
+//
+// Link speed parameters
+//
+
+#define DEF_MAXLINKDELAY 60 // seconds
+#define MIN_MAXLINKDELAY 0
+#define MAX_MAXLINKDELAY 0x100000
+
+#define DEF_MINLINKTHROUGHPUT 0 // bytes per second
+#define MIN_MINLINKTHROUGHPUT 0
+#define MAX_MINLINKTHROUGHPUT 0xFFFFFFFF
+
+#define DEF_LINKINFOVALIDTIME 60 // seconds
+#define MIN_LINKINFOVALIDTIME 0
+#define MAX_LINKINFOVALIDTIME 0x100000
+
+#define DEF_SCAVQOSINFOUPDATETIME 300 // seconds
+#define MIN_SCAVQOSINFOUPDATETIME 0
+#define MAX_SCAVQOSINFOUPDATETIME 0x100000
+
+//
+// Sharing violation retry delays/count
+//
+
+#define DEF_SHARINGVIOLATIONRETRIES 5 // number of retries
+#define MIN_SHARINGVIOLATIONRETRIES 0
+#define MAX_SHARINGVIOLATIONRETRIES 1000
+
+#define DEF_SHARINGVIOLATIONDELAY 200 // milliseconds
+#define MIN_SHARINGVIOLATIONDELAY 0
+#define MAX_SHARINGVIOLATIONDELAY 1000
+
+//
+// Lock violation delay
+//
+
+#define DEF_LOCKVIOLATIONDELAY 250 // milliseconds
+#define MIN_LOCKVIOLATIONDELAY 0
+#define MAX_LOCKVIOLATIONDELAY 1000
+
+#define DEF_LOCKVIOLATIONOFFSET 0xEF000000
+#define MIN_LOCKVIOLATIONOFFSET 0
+#define MAX_LOCKVIOLATIONOFFSET 0xFFFFFFFF
+
+//
+// length to switchover to mdl reads
+//
+
+#define DEF_MDLREADSWITCHOVER 1024
+#define MIN_MDLREADSWITCHOVER 512
+#define MAX_MDLREADSWITCHOVER 65535
+
+//
+// Number of closed RFCBs that can be cached
+//
+
+#define DEF_CACHEDOPENLIMIT 5
+#define MIN_CACHEDOPENLIMIT 0
+#define MAX_CACHEDOPENLIMIT 65535
+
+//
+// Number of directory names to cache for quick checkpath calls
+//
+
+#define DEF_CACHEDDIRECTORYLIMIT 5
+#define MIN_CACHEDDIRECTORYLIMIT 0
+#define MAX_CACHEDDIRECTORYLIMIT 65535
+
+
+//
+// Max length for a copy buffer operation, as opposed to taking the
+// NDIS buffer in total.
+//
+
+#define DEF_MAXCOPYLENGTH 512
+#define MIN_MAXCOPYLENGTH 40
+#define MAX_MAXCOPYLENGTH 65535
+
+//
+// *** Change the following defines to limit WinNT (vs. NTAS) parameters.
+//
+// *** If you make a change here, you need to make the same change in
+// srv\srvconfg.h!
+
+#define MAX_USERS_WKSTA 10
+#define MAX_MAXWORKITEMS_WKSTA 64
+#define MAX_THREADS_WKSTA 5
+
+#endif // ifndef _SRVCONFG_
+
diff --git a/private/net/svcdlls/srvsvc/server/srvinfo.c b/private/net/svcdlls/srvsvc/server/srvinfo.c
new file mode 100644
index 000000000..c0fd5032b
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/srvinfo.c
@@ -0,0 +1,677 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ SrvInfo.c
+
+Abstract:
+
+ This module contains support for the server get and set info APIs
+ in the server service.
+
+Author:
+
+ David Treadwell (davidtr) 7-Mar-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "ssreg.h"
+
+#include <netlibnt.h>
+
+#include <tstr.h>
+#include <lmerr.h>
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerGetInfo (
+ IN LPWSTR ServerName,
+ IN DWORD Level,
+ OUT LPSERVER_INFO InfoStruct
+ )
+
+/*++
+
+Routine Description:
+
+ This routine uses the server parameters stored in the server service
+ to return the server information.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ ULONG outputBufferLength;
+ NET_API_STATUS error;
+ ACCESS_MASK desiredAccess;
+ LPWSTR DomainName;
+ PNAME_LIST_ENTRY service;
+ PTRANSPORT_LIST_ENTRY transport;
+ UCHAR serverNameBuf[ MAX_PATH ];
+ UNICODE_STRING ServerNameUnicode;
+ NTSTATUS status;
+ ULONG namelen;
+
+ //
+ // Determine the access required for the requested level of
+ // information.
+ //
+
+ switch ( Level ) {
+
+ case 100:
+ case 101:
+
+ desiredAccess = SRVSVC_CONFIG_USER_INFO_GET;
+ break;
+
+ case 102:
+ case 502:
+
+ desiredAccess = SRVSVC_CONFIG_POWER_INFO_GET;
+ break;
+
+ case 503:
+
+ desiredAccess = SRVSVC_CONFIG_ADMIN_INFO_GET;
+ break;
+
+ default:
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Make sure that the caller has that level of access.
+ //
+
+ error = SsCheckAccess(
+ &SsConfigInfoSecurityObject,
+ desiredAccess
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Acquire the resource that protects server information. Since
+ // we'll only read the information, get shared access to the
+ // resource.
+ //
+
+ (VOID)RtlAcquireResourceShared( &SsServerInfoResource, TRUE );
+
+ if( ServerName == NULL ) {
+ ServerName = SsData.ServerNameBuffer;
+ }
+
+ //
+ // Convert the server name
+ //
+
+ if( ServerName[0] == L'\\' && ServerName[1] == L'\\' ) {
+ ServerName += 2;
+ }
+
+ RtlInitUnicodeString( &ServerNameUnicode, ServerName );
+ error = ConvertStringToTransportAddress( &ServerNameUnicode, serverNameBuf, &namelen );
+ if( error != NERR_Success ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return error;
+ }
+
+ //
+ // Look for the NAME_LIST_ENTRY entry that represents the name of the server
+ // the client referred to.
+ //
+
+ DomainName = SsData.DomainNameBuffer;
+
+ for( service = SsServerNameList; service != NULL; service = service->Next ) {
+
+ if( service->TransportAddressLength != namelen ) {
+ continue;
+ }
+
+
+ if( RtlEqualMemory( serverNameBuf, service->TransportAddress, namelen ) ) {
+ DomainName = service->DomainName;
+ break;
+ }
+ }
+
+ //
+ // If we didn't find an entry, find and use the primary entry
+ //
+ if( service == NULL ) {
+ for( service = SsServerNameList; service != NULL; service = service->Next ) {
+ if( service->PrimaryName ) {
+ DomainName = service->DomainName;
+ break;
+ }
+ }
+ }
+
+ //
+ // Use the level parameter to determine how much space to allocate
+ // and how to fill it in.
+ //
+
+ switch ( Level ) {
+
+ case 100: {
+
+ PSERVER_INFO_100 sv100;
+
+ //
+ // All we copy is the server name.
+ //
+
+ outputBufferLength = sizeof(SERVER_INFO_100) +
+ STRSIZE( ServerName);
+
+ sv100 = MIDL_user_allocate( outputBufferLength );
+ if ( sv100 == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy over the fixed portion of the buffer.
+ //
+
+ RtlCopyMemory( sv100, &SsData.ServerInfo102, sizeof(SERVER_INFO_100) );
+
+ //
+ // Set up the name string.
+ //
+
+ sv100->sv100_name = (LPWSTR)( sv100 + 1 );
+ STRCPY( sv100->sv100_name, ServerName );
+
+ //
+ // Set up the output buffer pointer.
+ //
+
+ InfoStruct->ServerInfo100 = sv100;
+
+ break;
+ }
+
+ case 101: {
+
+ PSERVER_INFO_101 sv101;
+
+ //
+ // All we copy is the server name.
+ //
+
+ outputBufferLength = sizeof(SERVER_INFO_101) +
+ STRSIZE( ServerName ) +
+ STRSIZE( SsData.ServerCommentBuffer ) ;
+
+ sv101 = MIDL_user_allocate( outputBufferLength );
+ if ( sv101 == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy over the fixed portion of the buffer.
+ //
+
+ RtlCopyMemory( sv101, &SsData.ServerInfo102, sizeof(SERVER_INFO_101) );
+
+ if( service != NULL ) {
+ sv101->sv101_type = service->ServiceBits;
+ for( transport = service->Transports; transport; transport = transport->Next ) {
+ sv101->sv101_type |= transport->ServiceBits;
+ }
+ } else {
+ //
+ // If there are no transports,
+ // return the global information.
+ //
+
+ sv101->sv101_type = SsGetServerType() | SsData.ServiceBits;
+ }
+
+
+ //
+ // Set up the variable portion of the buffer.
+ //
+
+ sv101->sv101_name = (LPWSTR)( sv101 + 1 );
+ STRCPY( sv101->sv101_name, ServerName );
+
+ sv101->sv101_comment = (LPWSTR)( (PCHAR)sv101->sv101_name +
+ STRSIZE( ServerName ));
+ STRCPY( sv101->sv101_comment, SsData.ServerCommentBuffer );
+
+ //
+ // Set up the output buffer pointer.
+ //
+
+ InfoStruct->ServerInfo101 = sv101;
+
+ break;
+ }
+
+ case 102: {
+
+ PSERVER_INFO_102 sv102;
+
+ //
+ // We copy the server name, server comment, and user path
+ // buffer.
+ //
+
+ outputBufferLength = sizeof(SERVER_INFO_102) +
+ STRSIZE( ServerName ) +
+ STRSIZE( SsData.ServerCommentBuffer ) +
+ STRSIZE( SsData.UserPathBuffer ) ;
+
+ sv102 = MIDL_user_allocate( outputBufferLength );
+ if ( sv102 == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy over the fixed portion of the buffer.
+ //
+
+ RtlCopyMemory( sv102, &SsData.ServerInfo102, sizeof(SERVER_INFO_102) );
+
+ if( service != NULL ) {
+ sv102->sv102_type = service->ServiceBits;
+ for( transport = service->Transports; transport; transport = transport->Next ) {
+ sv102->sv102_type |= transport->ServiceBits;
+ }
+ } else {
+ //
+ // If there are no transports,
+ // return the global information.
+ //
+
+ sv102->sv102_type = SsGetServerType() | SsData.ServiceBits;
+ }
+
+ //
+ // Set up the server name.
+ //
+
+ sv102->sv102_name = (LPWSTR)( sv102 + 1 );
+ STRCPY( sv102->sv102_name, ServerName );
+
+ //
+ // Set up the server comment.
+ //
+
+ sv102->sv102_comment = (LPWSTR)( (PCHAR)sv102->sv102_name + STRSIZE( ServerName ));
+ STRCPY( sv102->sv102_comment, SsData.ServerCommentBuffer );
+
+ //
+ // Set up the user path.
+ //
+
+ sv102->sv102_userpath = (LPWSTR)( (PCHAR)sv102->sv102_comment +
+ STRSIZE( sv102->sv102_comment ) );
+ STRCPY( sv102->sv102_userpath, SsData.UserPathBuffer );
+
+ //
+ // Set up the output buffer pointer.
+ //
+
+ InfoStruct->ServerInfo102 = sv102;
+
+ break;
+ }
+
+ case 502:
+
+ //
+ // Allocate enough space to hold the fixed structure. This level has
+ // no variable structure.
+ //
+
+ InfoStruct->ServerInfo502 = MIDL_user_allocate( sizeof(SERVER_INFO_502) );
+ if ( InfoStruct->ServerInfo502 == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the data from the server service buffer to the user buffer.
+ //
+
+ RtlCopyMemory(
+ InfoStruct->ServerInfo502,
+ &SsData.ServerInfo599,
+ sizeof(SERVER_INFO_502)
+ );
+
+ break;
+
+ case 503: {
+
+ PSERVER_INFO_503 sv503;
+
+ outputBufferLength = sizeof( *sv503 ) + STRSIZE( DomainName );
+
+ sv503 = MIDL_user_allocate( outputBufferLength );
+
+ if ( sv503 == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy the data from the server service buffer to the user buffer.
+ //
+
+ RtlCopyMemory( sv503, &SsData.ServerInfo599, sizeof( *sv503 ) );
+
+ //
+ // Copy the domain name
+ //
+ sv503->sv503_domain = (LPWSTR)( sv503 + 1 );
+ STRCPY( sv503->sv503_domain, DomainName );
+
+ InfoStruct->ServerInfo503 = sv503;
+
+ break;
+ }
+
+ default:
+
+ RtlReleaseResource( &SsServerInfoResource );
+ return ERROR_INVALID_LEVEL;
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+
+ return NO_ERROR;
+
+} // NetrServerGetInfo
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerSetInfo (
+ IN LPWSTR ServerName,
+ IN DWORD Level,
+ IN LPSERVER_INFO InfoStruct,
+ OUT LPDWORD ErrorParameter OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information in the server service and server.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ ULONG i;
+ LONG parmnum;
+ BOOLEAN validLevel = FALSE;
+ PSERVER_REQUEST_PACKET srp;
+ LPBYTE buffer = (LPBYTE)InfoStruct->ServerInfo100;
+ BOOLEAN announcementInformationChanged = FALSE;
+
+ ServerName;
+
+ //
+ // Check that user input buffer is not NULL
+ //
+ if (buffer == NULL) {
+ if ( ARGUMENT_PRESENT( ErrorParameter ) ) {
+ *ErrorParameter = PARM_ERROR_UNKNOWN;
+ }
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ parmnum = (LONG)(Level - PARMNUM_BASE_INFOLEVEL);
+
+ if ( ARGUMENT_PRESENT( ErrorParameter ) ) {
+ *ErrorParameter = parmnum;
+ }
+
+ //
+ // Make sure that the caller is allowed to set information in the
+ // server.
+ //
+
+ error = SsCheckAccess(
+ &SsConfigInfoSecurityObject,
+ SRVSVC_CONFIG_INFO_SET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Acquire the resource that protects server information. Since
+ // we're going to be writing to the information, we need exclusive
+ // access to the reqource.
+ //
+
+
+ //
+ // If a parameter number was specified, set that one field.
+ //
+
+ if ( parmnum >= 0 ) {
+
+ //
+ // Walk through the field descriptors looking for an
+ // equivalent parameter number.
+ //
+
+ for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
+
+ if ( (ULONG)parmnum == SsServerInfoFields[i].ParameterNumber ) {
+
+ //
+ // Verify that the field is settable.
+ //
+ // !!! We should also reject levels above 502?
+ //
+
+ if ( SsServerInfoFields[i].Settable != ALWAYS_SETTABLE ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ (VOID)RtlAcquireResourceExclusive( &SsServerInfoResource, TRUE );
+
+ //
+ // Set the field.
+ //
+
+ error = SsSetField(
+ &SsServerInfoFields[i],
+ buffer,
+ TRUE,
+ &announcementInformationChanged
+ );
+
+ RtlReleaseResource( &SsServerInfoResource );
+
+ //
+ // If a relevant parameter changed, call
+ // SsSetExportedServerType. This will cause an
+ // announcement to be sent.
+ //
+
+ if ( announcementInformationChanged ) {
+ SsSetExportedServerType( NULL, TRUE, TRUE );
+ }
+
+ return error;
+ }
+ }
+
+ //
+ // If a match had been found we would have returned by now.
+ // Indicate that the parameter number was illegal.
+ //
+
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // A full input structure was specified. Walk through all the
+ // server data field descriptors, looking for fields that should be
+ // set.
+ //
+
+ for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
+
+ ULONG fieldLevel;
+
+ //
+ // We need to set this field if:
+ //
+ // o the level specified on input is the same order as the
+ // level of the field. They have the same order if
+ // they are in the same century (e.g. 101 and 102 are
+ // in the same order); AND
+ //
+ // o the specified level is greater than or equal to the
+ // level of the field. For example, if the input
+ // level is 101 and the field level is 102, don't set
+ // the field. If the input level is 102 and the field
+ // level is 101, set it; AND
+ //
+ // o the field is settable. If the field is not settable
+ // by NetServerSetInfo, just ignore the value in the
+ // input structure.
+ //
+ // Note that level 598 doesn't follow the first rule above. It
+ // is NOT a superset of 50x, and it is NOT a subset of 599.
+ //
+
+ fieldLevel = SsServerInfoFields[i].Level;
+
+ if ( Level / 100 == fieldLevel / 100 &&
+ ((fieldLevel != 598) && (Level >= fieldLevel) ||
+ (fieldLevel == 598) && (Level == 598)) &&
+ SsServerInfoFields[i].Settable == ALWAYS_SETTABLE ) {
+
+ //
+ // We found a match, so the specified level number must have
+ // been valid.
+ //
+ // !!! Reject levels above 502?
+
+ validLevel = TRUE;
+
+ //
+ // Set this field.
+ //
+
+ (VOID)RtlAcquireResourceExclusive( &SsServerInfoResource, TRUE );
+
+ error = SsSetField(
+ &SsServerInfoFields[i],
+ buffer + SsServerInfoFields[i].FieldOffset,
+ TRUE,
+ &announcementInformationChanged
+ );
+
+ RtlReleaseResource( &SsServerInfoResource );
+
+ if ( error != NO_ERROR ) {
+
+ //
+ // Set the parameter in error if we need to.
+ //
+
+ if ( ARGUMENT_PRESENT(ErrorParameter) ) {
+ *ErrorParameter = SsServerInfoFields[i].ParameterNumber;
+ }
+
+ return error;
+ }
+
+ }
+
+ }
+
+ //
+ // If no match was ever found, then an invalid level was passed in.
+ //
+
+ if ( !validLevel ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Get an SRP and set it up with the appropriate level.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = 0xFFFFFFFF;
+
+ (VOID)RtlAcquireResourceShared( &SsServerInfoResource, TRUE );
+
+ //
+ // Send the request on to the server.
+ //
+
+ error = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_NET_SERVER_SET_INFO,
+ srp,
+ &SsData.ServerInfo102,
+ sizeof(SERVER_INFO_102) + sizeof(SERVER_INFO_599) +
+ sizeof(SERVER_INFO_598)
+ );
+
+ //
+ // Release the resource and free the SRP.
+ //
+
+ RtlReleaseResource( &SsServerInfoResource );
+
+ SsFreeSrp( srp );
+
+ //
+ // If a relevant parameter changed, call SsSetExportedServerType.
+ // This will cause an announcement to be sent.
+ //
+
+ if ( announcementInformationChanged ) {
+ SsSetExportedServerType( NULL, TRUE, TRUE );
+ }
+
+ return error;
+
+} // NetrServerSetInfo
diff --git a/private/net/svcdlls/srvsvc/server/srvmain.c b/private/net/svcdlls/srvsvc/server/srvmain.c
new file mode 100644
index 000000000..5101001db
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/srvmain.c
@@ -0,0 +1,680 @@
+/*++
+
+Copyright (c) 1990-91 Microsoft Corporation
+
+Module Name:
+
+ srvmain.c
+
+Abstract:
+
+ This is the main routine for the NT LAN Manager Server Service.
+
+ !!! Does service controller guarantee no controls will be issued
+ while we are initializing? Also, does it serialize controls?
+ If not, we need some synchronization in here.
+
+Author:
+
+ David Treadwell (davidtr) 05-10-1991
+
+Revision History:
+
+ 19-Jan-1993 Danl
+ Removed the old long endpoint name "LanmanServer".
+
+ 07-Jan-1993 Danl
+ Added an RPC endpoint name using "srvsvc", since "LanmanServer" is
+ too long for DOS machines to _access.
+ For a short time we will support both names.
+
+ 18-Feb-1992 ritaw
+ Convert to Win32 service control APIs.
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+
+#include <lmerr.h>
+#include <lmsname.h>
+#include <tstr.h>
+#include <wincon.h>
+#include <winsvc.h>
+
+#include <netlib.h>
+#include <netlibnt.h> // NetpNtStatusToApiStatus
+#include <netdebug.h> // NetpKdPrint
+#include <rpcutil.h>
+#include <services.h>
+#include <srvann.h>
+#include <srvnames.h> // SERVER_INTERFACE_NAME
+
+
+SERVICE_STATUS SsServiceStatus;
+SERVICE_STATUS_HANDLE SsServiceStatusHandle;
+
+VOID
+ControlResponse(
+ DWORD opCode
+ );
+
+
+VOID
+LMSVCS_ENTRY_POINT ( // (SRVSVC_main)
+ IN DWORD argc,
+ IN LPWSTR argv[],
+ IN PLMSVCS_GLOBAL_DATA pGlobalData,
+ IN HANDLE SvcRefHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This is the "main" routine for the server service. The containing
+ process will call this routine when we're supposed to start up.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ RPC_STATUS rpcStatus;
+ NET_API_STATUS error;
+ NET_API_STATUS terminationError;
+ BOOLEAN rpcServerStarted = FALSE;
+
+ NTSTATUS Status;
+ HANDLE EventHandle;
+ OBJECT_ATTRIBUTES EventAttributes;
+ UNICODE_STRING EventNameString;
+ LARGE_INTEGER LocalTimeout;
+
+ UNREFERENCED_PARAMETER(SvcRefHandle);
+
+ //
+ // Save the LMSVCS global data for future use.
+ //
+
+ SsLmsvcsGlobalData = pGlobalData;
+
+ //
+ // Skip the Service Name in the argument list.
+ //
+ if (argc > 0) {
+ argc--;
+ if (argc > 0) {
+ argv = &(argv[1]);
+ }
+ }
+
+
+#if DBG
+ //
+ // Set up for debugging--the first command line argument may be
+ // "/debug:X" where SsDebug gets set to X.
+ //
+
+ if ( argc > 0 && STRNICMP( TEXT("/debug:"), (LPWSTR)argv[0], 7 ) == 0 ) {
+#ifdef UNICODE
+ UNICODE_STRING ustr;
+ RtlInitUnicodeString( &ustr, (PWSTR)argv[0] + 7 );
+ RtlUnicodeStringToInteger( &ustr, 16, &SsDebug );
+#else
+ SsDebug = 0;
+ RtlCharToInteger( argv[0] + 7, 16, &SsDebug );
+#endif
+ }
+
+
+#ifndef USE_DEBUGGER
+ //SsDebug = 0xffff;
+ if ( SsDebug != 0 ) {
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ COORD coord;
+ (VOID)AllocConsole( );
+ (VOID)GetConsoleScreenBufferInfo(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ &csbi
+ );
+ coord.X = (SHORT)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
+ coord.Y = (SHORT)((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) * 20);
+ (VOID)SetConsoleScreenBufferSize(
+ GetStdHandle(STD_OUTPUT_HANDLE),
+ coord
+ );
+ }
+#endif
+#endif
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SRVSVC_main: server service starting.\n" ));
+ }
+
+ IF_DEBUG(INITIALIZATION_BREAKPOINT) {
+ DbgUserBreakPoint( );
+ }
+
+
+ //
+ // Initialize all the status fields so that subsequent calls to
+ // SetServiceStatus need to only update fields that changed.
+ //
+
+ SsServiceStatus.dwServiceType = SERVICE_WIN32;
+ SsServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+ SsServiceStatus.dwControlsAccepted = 0;
+ SsServiceStatus.dwCheckPoint = 1;
+ SsServiceStatus.dwWaitHint = 30000; // 30 seconds
+
+ SET_SERVICE_EXITCODE(
+ NO_ERROR,
+ SsServiceStatus.dwWin32ExitCode,
+ SsServiceStatus.dwServiceSpecificExitCode
+ );
+
+ //
+ // Initialize server to receive service requests by registering the
+ // control handler.
+ //
+
+ SsServiceStatusHandle = RegisterServiceCtrlHandler(
+ SERVICE_SERVER,
+ ControlResponse
+ );
+
+ if ( SsServiceStatusHandle == 0 ) {
+
+ error = GetLastError();
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SRVSVC_main: RegisterServiceCtrlHandler failed: "
+ "%ld\n", error ));
+ }
+ goto exit;
+
+ }
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SRVSVC_main: Control handler registered.\n" ));
+ }
+
+
+ //
+ // Wait for the Sam service to start.
+ //
+ // Later, when we initialize the server driver, it is going to create a
+ // "NULL Session" token by calling LsaLogonUser. That call waits until
+ // SAM is initialized. However, we don't have an opportunity to give
+ // wait hints to the service controller, so we'll wait here.
+ //
+ // Create the event to wait on.
+ //
+
+ RtlInitUnicodeString( &EventNameString, L"\\SAM_SERVICE_STARTED" );
+ InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
+
+ Status = NtCreateEvent(
+ &EventHandle,
+ SYNCHRONIZE,
+ &EventAttributes,
+ NotificationEvent,
+ (BOOLEAN) FALSE // The event is initially not signaled
+ );
+
+ if ( !NT_SUCCESS(Status)) {
+
+ //
+ // If the event already exists, SAM beat us to creating it.
+ // Just open it.
+ //
+
+ if( Status == STATUS_OBJECT_NAME_EXISTS ||
+ Status == STATUS_OBJECT_NAME_COLLISION ) {
+
+ Status = NtOpenEvent( &EventHandle,
+ SYNCHRONIZE,
+ &EventAttributes );
+
+ }
+ if ( !NT_SUCCESS(Status)) {
+ error = NetpNtStatusToApiStatus(Status);
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SRVSVC_main: Can't open SAM_SERVICE_STARTED event: %lx\n",
+ Status ));
+ }
+
+ goto exit;
+ }
+ }
+
+ //
+ // Wait for SAM to finish initializing.
+ //
+
+ LocalTimeout = RtlEnlargedIntegerMultiply( SsServiceStatus.dwWaitHint/2, -10000 );
+
+ do {
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SRVSVC_main: Wait for SAM to init.\n" ));
+ }
+ AnnounceServiceStatus( 1 );
+ Status = NtWaitForSingleObject( EventHandle,
+ (BOOLEAN)FALSE,
+ &LocalTimeout);
+ } while ( Status == STATUS_TIMEOUT );
+
+ (VOID) NtClose( EventHandle );
+
+ if ( !NT_SUCCESS(Status) ) {
+ error = NetpNtStatusToApiStatus(Status);
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SRVSVC_main: Wait for SAM_SERVICE_STARTED event failed: %lx\n",
+ Status ));
+ }
+
+ goto exit;
+ }
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SRVSVC_main: Done waiting for SAM to init.\n" ));
+ }
+
+ AnnounceServiceStatus( 1 );
+
+ //
+ // Initialize server service data and the Lanman server FSP in kernel
+ // mode.
+ //
+
+ error = SsInitialize( argc, argv );
+
+ if ( error != NO_ERROR ) {
+ goto exit;
+ }
+
+ //
+ // Set the variable that indicates that the server is fully
+ // initialized.
+ //
+
+ SS_ASSERT( !SsInitialized );
+ SsInitialized = TRUE;
+
+ //
+ // Start the RPC server. Because other services may reside in this
+ // process, the actual RPC server may already have been started;
+ // this routine will track this for us.
+ //
+ // NOTE: Now all RPC servers in services.exe share the same pipe name.
+ // However, in order to support communication with version 1.0 of WinNt,
+ // it is necessary for the Client Pipe name to remain the same as
+ // it was in version 1.0. Mapping to the new name is performed in
+ // the Named Pipe File System code.
+ //
+
+ rpcStatus = SsLmsvcsGlobalData->StartRpcServer(
+ SsLmsvcsGlobalData->SvcsRpcPipeName,
+ srvsvc_ServerIfHandle
+ );
+
+ if ( rpcStatus != 0 ) {
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SRVSVC_main: NetpStartRpcServer failed: %ld\n",
+ rpcStatus ));
+ }
+ goto exit;
+ }
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SRVSVC_main: RPC server started.\n" ));
+ }
+
+ rpcServerStarted = TRUE;
+
+#ifdef SRV_PNP_POWER
+ //
+ // Start getting PNP transport notifications from the server
+ //
+ error = StartPnpNotifications();
+ if( error != NO_ERROR ) {
+ goto exit;
+ }
+
+#endif
+
+ //
+ // Announce that we have successfully started.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_RUNNING;
+ SsServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_PAUSE_CONTINUE;
+ SsServiceStatus.dwCheckPoint = 0;
+ SsServiceStatus.dwWaitHint = 0;
+
+ AnnounceServiceStatus( 0 );
+
+ IF_DEBUG(INITIALIZATION) {
+ SS_PRINT(( "SRVSVC_main: initialization successfully completed.\n" ));
+ }
+
+ if (!I_ScSetServiceBits(SsServiceStatusHandle, SV_TYPE_SERVER, TRUE, TRUE, FALSE)) {
+ error = GetLastError();
+
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SRVSVC_main: I_ScSetServiceBits failed: %ld\n",
+ error ));
+ }
+ goto exit;
+
+ }
+
+ //
+ // Use this thread as the scavenger thread to send server
+ // announcements and watch the registry for configuration changes.
+ //
+
+ SS_ASSERT( SsInitialized );
+ (VOID)SsScavengerThread( NULL );
+ SS_ASSERT( SsInitialized );
+
+exit:
+
+ IF_DEBUG(TERMINATION) {
+ SS_PRINT(( "SRVSVC_main: terminating.\n" ));
+ }
+
+ IF_DEBUG(TERMINATION_BREAKPOINT) {
+ DbgUserBreakPoint( );
+ }
+
+ //
+ // Set the initialization variable to indicate that the server
+ // service is not started.
+ //
+
+ SsInitialized = FALSE;
+
+ //
+ // Announce that we're going down.
+ //
+
+ terminationError = error;
+
+ SsServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ SsServiceStatus.dwCheckPoint = 1;
+ SsServiceStatus.dwWaitHint = 20000; // 20 seconds
+
+ SET_SERVICE_EXITCODE(
+ terminationError,
+ SsServiceStatus.dwWin32ExitCode,
+ SsServiceStatus.dwServiceSpecificExitCode
+ );
+
+ AnnounceServiceStatus( 0 );
+
+ //
+ // Shut down our connection to the RPC server, if the RPC server
+ // was started successfully.
+ //
+
+ if ( rpcServerStarted ) {
+ rpcStatus = SsLmsvcsGlobalData->StopRpcServer (
+ srvsvc_ServerIfHandle
+ );
+ if ( rpcStatus != NO_ERROR ) {
+ IF_DEBUG(TERMINATION_ERRORS) {
+ SS_PRINT(( "SRVSVC_main: unable to terminate RPC server: %X\n",
+ rpcStatus ));
+ }
+ } else {
+ IF_DEBUG(TERMINATION) {
+ SS_PRINT(( "SRVSVC_main: RPC server successfully shut down.\n" ));
+ }
+ }
+ }
+
+ //
+ // Clean up previously initialized state.
+ //
+
+ IF_DEBUG(TERMINATION) {
+ SS_PRINT(( "SRVSVC_main: cleaning up.\n" ));
+ }
+
+ error = SsTerminate( );
+ if ( terminationError == NO_ERROR ) {
+ terminationError = error;
+ }
+
+ //
+ // Announce that we're down.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_STOPPED;
+ SsServiceStatus.dwControlsAccepted = 0;
+ SsServiceStatus.dwCheckPoint = 0;
+ SsServiceStatus.dwWaitHint = 0;
+
+ SET_SERVICE_EXITCODE(
+ terminationError,
+ SsServiceStatus.dwWin32ExitCode,
+ SsServiceStatus.dwServiceSpecificExitCode
+ );
+
+ AnnounceServiceStatus( 0 );
+
+ IF_DEBUG(TERMINATION) {
+ SS_PRINT(( "SRVSVC_main: the server service is terminated.\n" ));
+ }
+
+ return;
+
+} // LMSVCS_ENTRY_POINT (SRVSVC_main)
+
+
+VOID
+AnnounceServiceStatus (
+ DWORD increment
+ )
+
+/*++
+
+Routine Description:
+
+ Announces the service's status to the service controller.
+ Add 'increment' to the checkpoint value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Service status handle is NULL if RegisterServiceCtrlHandler failed.
+ //
+
+ if ( SsServiceStatusHandle == 0 ) {
+ SS_PRINT(( "AnnounceServiceStatus: Cannot call SetServiceStatus, "
+ "no status handle.\n" ));
+
+ return;
+ }
+
+ if( SsServiceStatus.dwCurrentState == SERVICE_RUNNING && increment ) {
+ //
+ // No need to tell the service controller about another checkpoint
+ // since it already knows we're running
+ //
+ return;
+ }
+
+ SsServiceStatus.dwCheckPoint += increment;
+
+ IF_DEBUG(ANNOUNCE) {
+ SS_PRINT(( "AnnounceServiceStatus: CurrentState %lx\n"
+ " ControlsAccepted %lx\n"
+ " Win32ExitCode %lu\n"
+ " ServiceSpecificExitCode %lu\n"
+ " CheckPoint %lu\n"
+ " WaitHint %lu\n",
+ SsServiceStatus.dwCurrentState,
+ SsServiceStatus.dwControlsAccepted,
+ SsServiceStatus.dwWin32ExitCode,
+ SsServiceStatus.dwServiceSpecificExitCode,
+ SsServiceStatus.dwCheckPoint,
+ SsServiceStatus.dwWaitHint ));
+ }
+
+ //
+ // Call SetServiceStatus, ignoring any errors.
+ //
+
+ SetServiceStatus(SsServiceStatusHandle, &SsServiceStatus);
+
+} // AnnounceServiceStatus
+
+
+VOID
+ControlResponse(
+ DWORD opCode
+ )
+
+{
+ NET_API_STATUS error;
+ BOOL announce = TRUE;
+
+ //
+ // Determine the type of service control message and modify the
+ // service status, if necessary.
+ //
+
+ switch( opCode ) {
+
+ case SERVICE_CONTROL_STOP:
+
+ IF_DEBUG(CONTROL_MESSAGES) {
+ SS_PRINT(( "ControlResponse: STOP control received.\n" ));
+ }
+
+ //
+ // Announce that we are in the process of stopping.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
+ AnnounceServiceStatus( 0 );
+
+ //
+ // Set the event that will wake up the scavenger thread.
+ // That thread will wake up and kill the server.
+ //
+
+ if ( !SetEvent( SsTerminationEvent ) ) {
+ IF_DEBUG(TERMINATION_ERRORS) {
+ SS_PRINT(( "ControlResponse: SetEvent failed: %ld\n",
+ GetLastError( ) ));
+ }
+ }
+
+ //
+ // Let the main thread announce when the stop is done.
+ //
+
+ announce = FALSE;
+
+ break;
+
+ case SERVICE_CONTROL_PAUSE:
+
+ IF_DEBUG(CONTROL_MESSAGES) {
+ SS_PRINT(( "ControlResponse: PAUSE control received.\n" ));
+ }
+
+ //
+ // Announce that we are in the process of pausing.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
+ AnnounceServiceStatus( 0 );
+
+ //
+ // Send the request on to the server.
+ //
+
+ error = SsServerFsControl( NULL, FSCTL_SRV_PAUSE, NULL, NULL, 0L );
+ SS_ASSERT( error == NO_ERROR );
+
+ //
+ // Announce that we're now paused.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_PAUSED;
+
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+
+ IF_DEBUG(CONTROL_MESSAGES) {
+ SS_PRINT(( "ControlResponse: CONTINUE control received.\n" ));
+ }
+
+ //
+ // Announce that continue is pending.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
+ AnnounceServiceStatus( 0 );
+
+ //
+ // Send the request on to the server.
+ //
+
+ error = SsServerFsControl( NULL, FSCTL_SRV_CONTINUE, NULL, NULL, 0L );
+ SS_ASSERT( error == NO_ERROR );
+
+ //
+ // Announce that we're active now.
+ //
+
+ SsServiceStatus.dwCurrentState = SERVICE_RUNNING;
+
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+
+ IF_DEBUG(CONTROL_MESSAGES) {
+ SS_PRINT(( "ControlResponse: INTERROGATE control received.\n" ));
+ }
+
+
+ break;
+
+ default:
+
+ IF_DEBUG(CONTROL_MESSAGES) {
+ SS_PRINT(( "ControlResponse: unknown code received.\n" ));
+ }
+
+ break;
+ }
+
+ if ( announce ) {
+ AnnounceServiceStatus( 0 );
+ }
+
+} // ControlResponse
+
diff --git a/private/net/svcdlls/srvsvc/server/srvsvc.def b/private/net/svcdlls/srvsvc/server/srvsvc.def
new file mode 100644
index 000000000..9f7b307f3
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/srvsvc.def
@@ -0,0 +1,6 @@
+NAME srvsvc.dll
+
+DESCRIPTION 'NT LAN Manager Server Service'
+
+EXPORTS
+ ServiceEntry
diff --git a/private/net/svcdlls/srvsvc/server/srvsvc.rc b/private/net/svcdlls/srvsvc/server/srvsvc.rc
new file mode 100644
index 000000000..d68f43a40
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/srvsvc.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Server Service DLL"
+#define VER_INTERNALNAME_STR "SRVSVC.DLL"
+#define VER_ORIGINALFILENAME_STR "SRVSVC.DLL"
+
+#include "common.ver"
+
diff --git a/private/net/svcdlls/srvsvc/server/srvsvcp.h b/private/net/svcdlls/srvsvc/server/srvsvcp.h
new file mode 100644
index 000000000..c8324657e
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/srvsvcp.h
@@ -0,0 +1,406 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ SrvSvcP.h
+
+Abstract:
+
+ This is the header file for the NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 10-Jan-1991
+
+Revision History:
+
+--*/
+
+#ifndef _SRVSVCP_
+#define _SRVSVCP_
+
+#if _PNP_POWER
+#define SRV_PNP_POWER 1
+#endif
+
+#include <nt.h>
+#include <ntrtl.h>
+
+#include <rpc.h>
+#include <windef.h>
+#include <winerror.h>
+
+#include <lmcons.h>
+#include <secobj.h>
+
+#include <srvfsctl.h>
+
+#include <srvsvc.h>
+
+#include "ssdebug.h"
+#include "sssec.h"
+
+//
+// String constants.
+//
+
+#define IPC_SHARE_NAME TEXT("IPC$")
+#define ADMIN_SHARE_NAME TEXT("ADMIN$")
+
+#define SRVSVC_MAX_NUMBER_OF_DISKS 26
+
+//
+// Internationalizable strings
+//
+extern LPWSTR SsAdminShareRemark ;
+extern LPWSTR SsIPCShareRemark ;
+extern LPWSTR SsDiskAdminShareRemark ;
+
+//
+// Bits of server type (in announcement messages) that can only be set
+// by the server itself -- not by services via the internal API
+// I_NetServerSetServiceBits.
+//
+
+#define SERVER_TYPE_INTERNAL_BITS (SV_TYPE_SERVER | \
+ SV_TYPE_TIME_SOURCE | \
+ SV_TYPE_PRINTQ_SERVER | \
+ SV_TYPE_NT | \
+ SV_TYPE_DFS)
+
+//
+// INITIAL_BUFFER_SIZE is the buffer size that GetInfo and Enum requests
+// first try to fill. If this buffer isn't large enough, they allocate
+// a buffer large enough to hold all the information plus a fudge factor,
+// EXTRA_ALLOCATION.
+//
+
+#define INITIAL_BUFFER_SIZE (ULONG)8192
+#define EXTRA_ALLOCATION 1024
+
+//
+// ServerProductName in SERVER_SERVICE_DATA is the name passed to the
+// Licensing DLL as the name of this service. MAXPRODNAME is the max
+// number of characters in the service name.
+
+#define SERVER_PRODUCT_NAME L"SMBServer"
+
+// szVersionNumber in SERVER_SERVICE_DATA is the version string passed
+// to the Licensing DLL as the vesion of this service. MAXVERSIONSZ
+// is the max number of characters for the version string
+
+#define MAXVERSIONSZ 10
+
+//
+// Structure for server service global data.
+//
+
+typedef struct _SERVER_SERVICE_DATA {
+ SERVER_INFO_102 ServerInfo102;
+ SERVER_INFO_599 ServerInfo599;
+ SERVER_INFO_598 ServerInfo598;
+
+#if SRV_PNP_POWER
+ //
+ // If we are asked to set some service bits before we've bound to
+ // any transports, we need to save those bits here and use them later
+ // when we finally do bind to transports.
+ //
+ DWORD ServiceBits;
+#endif
+
+ BOOLEAN IsDfsRoot; // TRUE if we are the root of a DFS tree
+ UNICODE_STRING ServerAnnounceName;
+ LONG NumberOfPrintShares;
+ WCHAR ServerNameBuffer[MAX_PATH];
+ WCHAR AnnounceNameBuffer[MAX_PATH];
+ WCHAR ServerCommentBuffer[MAXCOMMENTSZ+1];
+ WCHAR UserPathBuffer[MAX_PATH+1];
+ WCHAR DomainNameBuffer[MAX_PATH];
+ WCHAR LongDomainNameBuffer[MAX_PATH];
+ WCHAR ServerProductName[ sizeof( SERVER_PRODUCT_NAME ) ];
+ WCHAR szVersionNumber[ MAXVERSIONSZ+1 ];
+} SERVER_SERVICE_DATA, *PSERVER_SERVICE_DATA;
+
+//
+// Structures used to hold transport specific server type bits
+//
+typedef struct _TRANSPORT_LIST_ENTRY {
+ struct _TRANSPORT_LIST_ENTRY *Next;
+ LPWSTR TransportName; // device name for xport
+ DWORD ServiceBits; // SV... announce bits
+} TRANSPORT_LIST_ENTRY, *PTRANSPORT_LIST_ENTRY;
+
+typedef struct _NAME_LIST_ENTRY {
+ struct _NAME_LIST_ENTRY *Next;
+ CHAR TransportAddress[ MAX_PATH ]; // address of this server
+ ULONG TransportAddressLength;
+ LPWSTR DomainName; // name of the domain
+ DWORD ServiceBits; // SV... announce bits
+ struct {
+ ULONG PrimaryName: 1; // Is this the server's primary name?
+ };
+ PTRANSPORT_LIST_ENTRY Transports;
+} NAME_LIST_ENTRY, *PNAME_LIST_ENTRY;
+
+
+//
+// Structure type used for generalized switch matching.
+//
+
+typedef struct _FIELD_DESCRIPTOR {
+ LPWCH FieldName;
+ ULONG FieldType;
+ ULONG FieldOffset;
+ ULONG Level;
+ DWORD ParameterNumber;
+ ULONG Settable;
+ DWORD DefaultValue;
+ DWORD MinimumValue;
+ DWORD MaximumValue;
+} FIELD_DESCRIPTOR, *PFIELD_DESCRIPTOR;
+
+//
+// Used by NetrShareEnumSticky to get share information from the registry.
+//
+
+typedef struct _SRVSVC_SHARE_ENUM_INFO {
+ ULONG Level;
+ ULONG ResumeHandle;
+ ULONG EntriesRead;
+ ULONG TotalEntries;
+ ULONG TotalBytesNeeded;
+ PVOID OutputBuffer;
+ ULONG OutputBufferLength;
+
+ //
+ // Scratch fields used by SsEnumerateStickyShares
+ //
+
+ ULONG ShareEnumIndex;
+ PCHAR StartOfFixedData;
+ PCHAR EndOfVariableData;
+} SRVSVC_SHARE_ENUM_INFO, *PSRVSVC_SHARE_ENUM_INFO;
+
+//#include "ssdata.h"
+
+//
+// Macros.
+//
+
+#define POINTER_TO_OFFSET(val,start) \
+ (val) = (val) == NULL ? NULL : (PVOID)( (PCHAR)(val) - (ULONG)(start) )
+
+#define OFFSET_TO_POINTER(val,start) \
+ (val) = (val) == NULL ? NULL : (PVOID)( (PCHAR)(val) + (ULONG)(start) )
+
+#define FIXED_SIZE_OF_SHARE(level) \
+ ( (level) == 0 ? sizeof(SHARE_INFO_0) : \
+ (level) == 1 ? sizeof(SHARE_INFO_1) : \
+ (level) == 2 ? sizeof(SHARE_INFO_2) : \
+ sizeof(SHARE_INFO_502) )
+
+#define SIZE_WSTR( Str ) \
+ ( ( Str ) == NULL ? 0 : ((wcslen( Str ) + 1) * sizeof(WCHAR)) )
+
+//
+// Internal routine prototypes.
+//
+
+PSERVER_REQUEST_PACKET
+SsAllocateSrp (
+ VOID
+ );
+
+NET_API_STATUS
+SsCheckAccess (
+ IN PSRVSVC_SECURITY_OBJECT SecurityObject,
+ IN ACCESS_MASK DesiredAccess
+ );
+
+VOID
+SsCloseServer (
+ VOID
+ );
+
+VOID
+SsControlCHandler (
+ IN ULONG CtrlType
+ );
+
+NET_API_STATUS
+SsCreateSecurityObjects (
+ VOID
+ );
+
+VOID
+SsDeleteSecurityObjects (
+ VOID
+ );
+
+VOID
+SsFreeSrp (
+ IN PSERVER_REQUEST_PACKET Srp
+ );
+
+NET_API_STATUS
+SsInitialize (
+ IN DWORD argc,
+ IN LPTSTR argv[]
+ );
+
+VOID
+SsLogEvent(
+ IN DWORD MessageId,
+ IN DWORD NumberOfSubStrings,
+ IN LPWSTR *SubStrings,
+ IN DWORD ErrorCode
+ );
+
+NET_API_STATUS
+SsOpenServer (
+ PHANDLE handle OPTIONAL
+ );
+
+NET_API_STATUS
+SsParseCommandLine (
+ IN DWORD argc,
+ IN LPTSTR argv[],
+ IN BOOLEAN Starting
+ );
+
+DWORD
+SsScavengerThread (
+ IN LPVOID lpThreadParameter
+ );
+
+NET_API_STATUS
+SsServerFsControlGetInfo (
+ IN ULONG ServerControlCode,
+ IN PSERVER_REQUEST_PACKET Srp,
+ IN OUT PVOID *OutputBuffer,
+ IN OUT ULONG OutputBufferLength
+ );
+
+NET_API_STATUS
+SsServerFsControl (
+ IN HANDLE SrvHandle OPTIONAL,
+ IN ULONG ServerControlCode,
+ IN PSERVER_REQUEST_PACKET Srp,
+ IN PVOID Buffer OPTIONAL,
+ IN ULONG BufferLength
+ );
+
+DWORD
+SsGetServerType (
+ VOID
+ );
+
+VOID
+SsSetExportedServerType (
+ IN PNAME_LIST_ENTRY Service OPTIONAL,
+ IN BOOL ExternalBitsAlreadyChanged,
+ IN BOOL UpdateImmediately
+ );
+
+NET_API_STATUS
+SsSetField (
+ IN PFIELD_DESCRIPTOR Field,
+ IN PVOID Value,
+ IN BOOLEAN WriteToRegistry,
+ OUT BOOLEAN *AnnouncementInformationChanged OPTIONAL
+ );
+
+UINT
+SsGetDriveType (
+ IN LPWSTR path
+ );
+
+NET_API_STATUS
+SsTerminate (
+ VOID
+ );
+
+DWORD
+SsAtol (
+ IN LPTSTR Input
+ );
+
+VOID
+AnnounceServiceStatus (
+ DWORD increment
+ );
+
+NTSTATUS
+BindToTransport (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+BindOptionalNames (
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetrServerTransportAddEx (
+ IN DWORD Level,
+ IN LPTRANSPORT_INFO Buffer
+ );
+
+#if SRV_PNP_POWER
+
+NET_API_STATUS
+StartPnpNotifications (
+ VOID
+ );
+
+#endif
+
+//
+// XACTSRV functions.
+//
+
+DWORD
+XsStartXactsrv (
+ VOID
+ );
+
+VOID
+XsStopXactsrv (
+ VOID
+ );
+
+NET_API_STATUS
+ShareEnumCommon (
+ IN DWORD Level,
+ OUT LPBYTE *Buffer,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL,
+ IN LPWSTR NetName OPTIONAL
+ );
+
+NET_API_STATUS
+ConvertStringToTransportAddress (
+ IN PUNICODE_STRING InputName,
+ OUT CHAR TransportAddress[MAX_PATH],
+ OUT PULONG TransportAddressLength
+ );
+
+VOID
+SsSetDfsRoot();
+
+#endif // ndef _SRVSVCP_
diff --git a/private/net/svcdlls/srvsvc/server/ssdata.c b/private/net/svcdlls/srvsvc/server/ssdata.c
new file mode 100644
index 000000000..326eaf58e
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/ssdata.c
@@ -0,0 +1,229 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SsData.c
+
+Abstract:
+
+ This module contains declarations for global data used by the server
+ service.
+
+Author:
+
+ David Treadwell (davidtr) 7-Mar-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "srvconfg.h"
+#include "ssdata.h"
+
+//
+// Handle for accessing the server.
+//
+
+HANDLE SsServerDeviceHandle = NULL;
+
+//
+// Global server service data.
+//
+
+SERVER_SERVICE_DATA SsData;
+
+//
+// Pointer to global data made available by LMSVCS main image.
+//
+
+PLMSVCS_GLOBAL_DATA SsLmsvcsGlobalData;
+
+//
+// Macros for simplifying field generation.
+//
+
+#define MAKE_BOOL_FIELD(_name_,_lower_,_upper_,_level_,_set_) \
+ L#_name_, BOOLEAN_FIELD, FIELD_OFFSET( SERVER_INFO_ ## _level_, \
+ sv ## _level_ ## _ ## _lower_ ), _level_, SV_ ## _upper_ ## _PARMNUM, \
+ _set_, DEF_ ## _upper_, FALSE, TRUE
+#define MAKE_DWORD_FIELD(_name_,_lower_,_upper_,_level_,_set_) \
+ L#_name_, DWORD_FIELD, FIELD_OFFSET( SERVER_INFO_ ## _level_, \
+ sv ## _level_ ## _ ## _lower_ ), _level_, SV_ ## _upper_ ## _PARMNUM, \
+ _set_, DEF_ ## _upper_, MIN_ ## _upper_, MAX_ ## _upper_
+#define MAKE_LPSTR_FIELD(_name_,_lower_,_upper_,_level_,_set_) \
+ L#_name_, LPSTR_FIELD, FIELD_OFFSET( SERVER_INFO_ ## _level_, \
+ sv ## _level_ ## _ ## _lower_ ), _level_, SV_ ## _upper_ ## _PARMNUM, \
+ _set_, (DWORD)DEF_ ## _upper_, 0, 0
+
+//
+// Data for all server info fields.
+//
+
+FIELD_DESCRIPTOR SsServerInfoFields[] = {
+ MAKE_DWORD_FIELD( platform_id, platform_id, PLATFORM_ID, 100, NOT_SETTABLE ),
+ MAKE_LPSTR_FIELD( name, name, NAME, 100, NOT_SETTABLE ),
+ MAKE_DWORD_FIELD( version_major, version_major, VERSION_MAJOR, 101, NOT_SETTABLE ),
+ MAKE_DWORD_FIELD( version_minor, version_minor, VERSION_MINOR, 101, NOT_SETTABLE ),
+ MAKE_DWORD_FIELD( type, type, TYPE, 101, NOT_SETTABLE ),
+ MAKE_LPSTR_FIELD( comment, comment, COMMENT, 101, ALWAYS_SETTABLE ),
+ MAKE_LPSTR_FIELD( srvcomment, comment, COMMENT, 101, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( users, users, USERS, 102, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( disc, disc, DISC, 102, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( autodisconnect, disc, DISC, 102, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( hidden, hidden, HIDDEN, 102, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( announce, announce, ANNOUNCE, 102, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( anndelta, anndelta, ANNDELTA, 102, ALWAYS_SETTABLE ),
+ MAKE_LPSTR_FIELD( userpath, userpath, USERPATH, 102, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sessopens, sessopens, SESSOPENS, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sessvcs, sessvcs, SESSVCS, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( opensearch, opensearch, OPENSEARCH, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sizreqbuf, sizreqbuf, SIZREQBUF, 502, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( initworkitems, initworkitems, INITWORKITEMS, 502, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxworkitems, maxworkitems, MAXWORKITEMS, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( rawworkitems, rawworkitems, RAWWORKITEMS, 502, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( irpstacksize, irpstacksize, IRPSTACKSIZE, 502, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxrawbuflen, maxrawbuflen, MAXRAWBUFLEN, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sessusers, sessusers, SESSUSERS, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sessconns, sessconns, SESSCONNS, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxpagedmemoryusage, maxpagedmemoryusage, MAXPAGEDMEMORYUSAGE, 502, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxnonpagedmemoryusage, maxnonpagedmemoryusage, MAXNONPAGEDMEMORYUSAGE, 502, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enablesoftcompat, enablesoftcompat, ENABLESOFTCOMPAT, 502, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enableforcedlogoff, enableforcedlogoff, ENABLEFORCEDLOGOFF, 502, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( timesource, timesource, TIMESOURCE, 502, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( acceptdownlevelapis, acceptdownlevelapis, ACCEPTDOWNLEVELAPIS, 502, SET_ON_STARTUP ),
+ MAKE_BOOL_FIELD( lmannounce, lmannounce, LMANNOUNCE, 502, ALWAYS_SETTABLE ),
+ MAKE_LPSTR_FIELD( domain, domain, DOMAIN, 503, NOT_SETTABLE ),
+ MAKE_DWORD_FIELD( maxcopyreadlen, maxcopyreadlen, MAXCOPYREADLEN, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxcopywritelen, maxcopywritelen, MAXCOPYWRITELEN, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( minkeepsearch, minkeepsearch, MINKEEPSEARCH, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxkeepsearch, maxkeepsearch, MAXKEEPSEARCH, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( minkeepcomplsearch, minkeepcomplsearch, MINKEEPCOMPLSEARCH, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxkeepcomplsearch, maxkeepcomplsearch, MAXKEEPCOMPLSEARCH, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( threadcountadd, threadcountadd, THREADCOUNTADD, 503, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( numblockthreads, numblockthreads, NUMBLOCKTHREADS, 503, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( scavtimeout, scavtimeout, SCAVTIMEOUT, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( minrcvqueue, minrcvqueue, MINRCVQUEUE, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( minfreeworkitems, minfreeworkitems, MINFREEWORKITEMS, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( xactmemsize, xactmemsize, XACTMEMSIZE, 503, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( threadpriority, threadpriority, THREADPRIORITY, 503, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxmpxct, maxmpxct, MAXMPXCT, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( oplockbreakwait, oplockbreakwait, OPLOCKBREAKWAIT, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( oplockbreakresponsewait, oplockbreakresponsewait, OPLOCKBREAKRESPONSEWAIT, 503, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enableoplocks, enableoplocks, ENABLEOPLOCKS, 503, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enableoplockforceclose, enableoplockforceclose, ENABLEOPLOCKFORCECLOSE, 503, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enablefcbopens, enablefcbopens, ENABLEFCBOPENS, 503, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enableraw, enableraw, ENABLERAW, 503, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enablesharednetdrives, enablesharednetdrives, ENABLESHAREDNETDRIVES, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( minfreeconnections, minfreeconnections, MINFREECONNECTIONS, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxfreeconnections, maxfreeconnections, MAXFREECONNECTIONS, 503, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( initsesstable, initsesstable, INITSESSTABLE, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( initconntable, initconntable, INITCONNTABLE, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( initfiletable, initfiletable, INITFILETABLE, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( initsearchtable, initsearchtable, INITSEARCHTABLE, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( alertschedule, alertschedule, ALERTSCHEDULE, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( errorthreshold, errorthreshold, ERRORTHRESHOLD, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( networkerrorthreshold, networkerrorthreshold, NETWORKERRORTHRESHOLD, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( diskspacethreshold, diskspacethreshold, DISKSPACETHRESHOLD, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxlinkdelay, maxlinkdelay, MAXLINKDELAY, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( minlinkthroughput, minlinkthroughput, MINLINKTHROUGHPUT, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( linkinfovalidtime, linkinfovalidtime, LINKINFOVALIDTIME, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( scavqosinfoupdatetime, scavqosinfoupdatetime, SCAVQOSINFOUPDATETIME, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxworkitemidletime, maxworkitemidletime, MAXWORKITEMIDLETIME, 599, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxrawworkitems, maxrawworkitems, MAXRAWWORKITEMS, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxthreadsperqueue, maxthreadsperqueue, MAXTHREADSPERQUEUE, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( connectionlessautodisc, connectionlessautodisc, CONNECTIONLESSAUTODISC, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sharingviolationretries, sharingviolationretries, SHARINGVIOLATIONRETRIES, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( sharingviolationdelay, sharingviolationdelay, SHARINGVIOLATIONDELAY, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( maxglobalopensearch, maxglobalopensearch, MAXGLOBALOPENSEARCH, 598, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( removeduplicatesearches, removeduplicatesearches, REMOVEDUPLICATESEARCHES, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( lockviolationoffset, lockviolationoffset, LOCKVIOLATIONOFFSET, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( lockviolationdelay, lockviolationdelay, LOCKVIOLATIONDELAY, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( mdlreadswitchover, mdlreadswitchover, MDLREADSWITCHOVER, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( cachedopenlimit, cachedopenlimit, CACHEDOPENLIMIT, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( cacheddirectorylimit, cacheddirectorylimit, CACHEDDIRECTORYLIMIT, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxcopylength, maxcopylength, MAXCOPYLENGTH, 598, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( restrictnullsessaccess, restrictnullsessaccess, RESTRICTNULLSESSACCESS, 598, ALWAYS_SETTABLE ),
+ MAKE_BOOL_FIELD( enablewfw311directipx, enablewfw311directipx, ENABLEWFW311DIRECTIPX, 598, ALWAYS_SETTABLE ),
+ MAKE_DWORD_FIELD( otherqueueaffinity, otherqueueaffinity, OTHERQUEUEAFFINITY, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( queuesamplesecs, queuesamplesecs, QUEUESAMPLESECS, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( balancecount, balancecount, BALANCECOUNT, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( preferredaffinity, preferredaffinity, PREFERREDAFFINITY, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxfreerfcbs, maxfreerfcbs, MAXFREERFCBS, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxfreemfcbs, maxfreemfcbs, MAXFREEMFCBS, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxfreelfcbs, maxfreelfcbs, MAXFREELFCBS, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxfreepagedpoolchunks, maxfreepagedpoolchunks, MAXFREEPAGEDPOOLCHUNKS, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( minpagedpoolchunksize, minpagedpoolchunksize, MINPAGEDPOOLCHUNKSIZE, 598, SET_ON_STARTUP ),
+ MAKE_DWORD_FIELD( maxpagedpoolchunksize, maxpagedpoolchunksize, MAXPAGEDPOOLCHUNKSIZE, 598, SET_ON_STARTUP ),
+ MAKE_BOOL_FIELD( sendsfrompreferredprocessor, sendsfrompreferredprocessor, SENDSFROMPREFERREDPROCESSOR, 598, SET_ON_STARTUP ),
+ MAKE_BOOL_FIELD( enablebulktransfer, enablebulktransfer, ENABLEBULKTRANSFER, 598, SET_ON_STARTUP ),
+ MAKE_BOOL_FIELD( enablecompression, enablecompression, ENABLECOMPRESSION, 598, SET_ON_STARTUP ),
+ MAKE_BOOL_FIELD( autosharewks, autosharewks, AUTOSHAREWKS, 598, SET_ON_STARTUP ),
+ MAKE_BOOL_FIELD( autoshareserver, autoshareserver, AUTOSHARESERVER, 598, SET_ON_STARTUP ),
+
+ NULL, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+//
+// Resource for synchronizing access to server info.
+//
+
+RTL_RESOURCE SsServerInfoResource;
+
+BOOL SsServerInfoResourceInitialized = FALSE;
+
+//
+// Boolean indicating whether the server service is initialized.
+//
+
+BOOL SsInitialized = FALSE;
+
+//
+// Boolean indicating whether the kernel-mode server FSP has been
+// started.
+//
+
+BOOL SsServerFspStarted = FALSE;
+
+//
+// Event used for synchronizing server service termination.
+//
+
+HANDLE SsTerminationEvent = NULL;
+
+//
+// Event used for forcing the server to announce itself on the network from
+// remote machines
+//
+
+HANDLE SsAnnouncementEvent = NULL;
+
+//
+// Event used for forcing the server service to announce itself on the network.
+//
+
+HANDLE SsStatusChangedEvent = NULL;
+
+//
+// Name of this computer in OEM format
+//
+
+CHAR SsServerTransportAddress[ MAX_PATH ];
+ULONG SsServerTransportAddressLength;
+
+//
+// List containing transport specific service type bits and server names
+//
+
+PNAME_LIST_ENTRY SsServerNameList = NULL;
+
+//
+// Variable to control DbgPrints for debugging.
+//
+
+#if DBG
+DWORD SsDebug = SSDEBUG_DEFAULT;
+#endif
+
diff --git a/private/net/svcdlls/srvsvc/server/ssdata.h b/private/net/svcdlls/srvsvc/server/ssdata.h
new file mode 100644
index 000000000..6434f1732
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/ssdata.h
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SsData.h
+
+Abstract:
+
+ This module contains declarations for global data used by the server
+ service.
+
+Author:
+
+ David Treadwell (davidtr) 7-Mar-1991
+
+Revision History:
+
+--*/
+
+#ifndef _SSDATA_
+#define _SSDATA_
+
+#include <services.h>
+
+#include <nturtl.h>
+#include <winbase.h>
+#include <winreg.h>
+
+//
+// Handle for accessing the server.
+//
+
+extern HANDLE SsServerDeviceHandle;
+
+//
+// Global server service data.
+//
+
+extern SERVER_SERVICE_DATA SsData;
+
+//
+// Pointer to global data made available by LMSVCS main image.
+//
+
+extern PLMSVCS_GLOBAL_DATA SsLmsvcsGlobalData;
+
+//
+// Manifests that determine field type.
+//
+
+#define BOOLEAN_FIELD 0
+#define DWORD_FIELD 1
+#define LPSTR_FIELD 2
+
+//
+// Manifests that determine when a field may be set.
+//
+
+#define NOT_SETTABLE 0
+#define SET_ON_STARTUP 1
+#define ALWAYS_SETTABLE 2
+
+//
+// Data for all server info fields.
+//
+
+extern FIELD_DESCRIPTOR SsServerInfoFields[];
+
+//
+// Resource for synchronizing access to server info.
+//
+
+extern RTL_RESOURCE SsServerInfoResource;
+
+extern BOOL SsServerInfoResourceInitialized;
+
+//
+// Boolean indicating whether the server service is initialized.
+//
+
+extern BOOL SsInitialized;
+
+//
+// Boolean indicating whether the kernel-mode server FSP has been
+// started.
+//
+
+extern BOOL SsServerFspStarted;
+
+//
+// Event used for synchronizing server service termination.
+//
+
+extern HANDLE SsTerminationEvent;
+
+//
+// Event used for forcing the server to announce itself on the network from
+// remote clients.
+//
+
+extern HANDLE SsAnnouncementEvent;
+
+//
+// Event used for forcing the server to announce itself on the network from
+// inside the server service.
+//
+
+extern HANDLE SsStatusChangedEvent;
+
+//
+// Name of this computer in OEM format.
+//
+
+extern CHAR SsServerTransportAddress[ MAX_PATH ];
+extern ULONG SsServerTransportAddressLength;
+
+//
+// List containing transport specific service names and bits
+//
+
+extern PNAME_LIST_ENTRY SsServerNameList;
+
+#endif // ndef _SSDATA_
diff --git a/private/net/svcdlls/srvsvc/server/ssdebug.h b/private/net/svcdlls/srvsvc/server/ssdebug.h
new file mode 100644
index 000000000..a13bba86e
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/ssdebug.h
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SsDebug.h
+
+Abstract:
+
+ Header file for various server service debugging aids.
+
+Author:
+
+ David Treadwell (davidtr) 10-Jan-1991
+
+Revision History:
+
+--*/
+
+#ifndef _SSDEBUG_
+#define _SSDEBUG_
+
+#if DBG
+
+#ifndef SSDEBUG_DEFAULT
+#define SSDEBUG_DEFAULT 0
+#endif
+
+#define DEBUG_INITIALIZATION 0x00000001
+#define DEBUG_INITIALIZATION_ERRORS 0x00000002
+#define DEBUG_TERMINATION 0x00000004
+#define DEBUG_TERMINATION_ERRORS 0x00000008
+
+#define DEBUG_API_ERRORS 0x00000010
+#define DEBUG_FS_CONTROL 0x00000020
+#define DEBUG_REGISTRY 0x00000040
+#define DEBUG_8 0x00000080
+
+#define DEBUG_ANNOUNCE 0x00000100
+#define DEBUG_CONTROL_MESSAGES 0x00000200
+#define DEBUG_11 0x00000400
+#define DEBUG_12 0x00000800
+
+#define DEBUG_SECURITY 0x00001000
+#define DEBUG_ACCESS_DENIED 0x00002000
+#define DEBUG_INITIALIZATION_BREAKPOINT 0x00004000
+#define DEBUG_TERMINATION_BREAKPOINT 0x00008000
+
+extern ULONG SsDebug;
+
+#define DEBUG if ( TRUE )
+#define IF_DEBUG(flag) if (SsDebug & (DEBUG_ ## flag))
+
+VOID
+SsPrintf (
+ char *Format,
+ ...
+ );
+
+#ifdef USE_DEBUGGER
+#define SS_PRINT(args) DbgPrint args
+#else
+#define SS_PRINT(args) SsPrintf args
+#endif
+
+#ifdef USE_DEBUGGER
+#define SS_ASSERT(exp) ASSERT(exp)
+#else
+VOID
+SsAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber
+ );
+#define SS_ASSERT(exp) if (!(exp)) SsAssert( #exp, __FILE__, __LINE__ )
+#endif
+
+#else
+
+#define DEBUG if ( FALSE )
+#define IF_DEBUG(flag) if (FALSE)
+
+#define SS_PRINT(args)
+
+#define SS_ASSERT(exp)
+
+#endif
+
+#endif // ndef _SSDEBUG_
diff --git a/private/net/svcdlls/srvsvc/server/ssinit.c b/private/net/svcdlls/srvsvc/server/ssinit.c
new file mode 100644
index 000000000..6b753391d
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/ssinit.c
@@ -0,0 +1,1524 @@
+/*++
+
+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( &registryPath, registryPathBuffer );
+
+ status = NtLoadDriver( &registryPath );
+
+ 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( &registryPath, registryPathBuffer );
+
+ status = NtUnloadDriver( &registryPath );
+
+ 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 ;
+}
diff --git a/private/net/svcdlls/srvsvc/server/ssreg.h b/private/net/svcdlls/srvsvc/server/ssreg.h
new file mode 100644
index 000000000..d225b760f
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/ssreg.h
@@ -0,0 +1,116 @@
+
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ ssreg.h
+
+Abstract:
+
+ Manifests for Registry usage in the server service.
+
+Author:
+
+ Chuck Lenzmeier (chuckl) 21-Mar-1992
+
+Revision History:
+
+--*/
+
+#ifndef _SSREG_
+#define _SSREG_
+
+//
+// Names of server service keys.
+//
+
+#define SERVER_REGISTRY_PATH L"LanmanServer"
+
+#define PARAMETERS_REGISTRY_PATH L"LanmanServer\\Parameters"
+#define AUTOTUNED_REGISTRY_PATH L"LanmanServer\\AutotunedParameters"
+#define SHARES_REGISTRY_PATH L"LanmanServer\\Shares"
+#define SHARES_SECURITY_REGISTRY_PATH L"LanmanServer\\Shares\\Security"
+#define LINKAGE_REGISTRY_PATH L"LanmanServer\\Linkage"
+
+#define BIND_VALUE_NAME L"Bind"
+#define SIZE_VALUE_NAME L"Size"
+#define DISC_VALUE_NAME L"Disc"
+#define COMMENT_VALUE_NAME L"Comment"
+#define NULL_SESSION_PIPES_VALUE_NAME L"NullSessionPipes"
+#define NULL_SESSION_SHARES_VALUE_NAME L"NullSessionShares"
+#define PIPES_NEED_LICENSE_VALUE_NAME L"PipesNeedLicense"
+#define ERROR_LOG_IGNORE_VALUE_NAME L"ErrorLogIgnore"
+#define OPTIONAL_NAMES_VALUE_NAME L"OptionalNames"
+
+#define FULL_PARAMETERS_REGISTRY_PATH L"SYSTEM\\CurrentControlSet\\Services\\" PARAMETERS_REGISTRY_PATH
+
+//
+// Names of share "environment variables".
+//
+
+#define MAXUSES_VARIABLE_NAME L"MaxUses"
+#define PATH_VARIABLE_NAME L"Path"
+#define PERMISSIONS_VARIABLE_NAME L"Permissions"
+#define REMARK_VARIABLE_NAME L"Remark"
+#define TYPE_VARIABLE_NAME L"Type"
+
+//
+// Functions exported by registry.c.
+//
+
+VOID
+SsAddParameterToRegistry (
+ PFIELD_DESCRIPTOR Field,
+ PVOID Value
+ );
+
+VOID
+SsAddShareToRegistry (
+ IN PSHARE_INFO_2 ShareInfo2,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL
+ );
+
+NET_API_STATUS
+SsBindToTransports (
+ VOID
+ );
+
+NET_API_STATUS
+SsCheckRegistry (
+ VOID
+ );
+
+NET_API_STATUS
+SsEnumerateStickyShares (
+ IN OUT PSRVSVC_SHARE_ENUM_INFO ShareEnumInfo
+ );
+
+NET_API_STATUS
+SsLoadConfigurationParameters (
+ VOID
+ );
+
+NET_API_STATUS
+SsRecreateStickyShares (
+ VOID
+ );
+
+NET_API_STATUS
+SsRemoveShareFromRegistry (
+ LPTSTR NetName
+ );
+
+//
+// Functions used by registry.c that are elsewhere but there is no convenient
+// place to put the prototype
+//
+
+DWORD
+ComputeTransportAddressClippedLength(
+ IN PCHAR TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+#endif // ndef _SSREG_
diff --git a/private/net/svcdlls/srvsvc/server/sssec.h b/private/net/svcdlls/srvsvc/server/sssec.h
new file mode 100644
index 000000000..10e4266b8
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/sssec.h
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SsSec.h
+
+Abstract:
+
+ Manifests for API security in the server service.
+
+Author:
+
+ David Treadwell (davidtr) 28-Aug-1991
+
+Revision History:
+
+--*/
+
+#ifndef _SSSEC_
+#define _SSSEC_
+
+//
+// Structure that holds all security information for a single server
+// service security object.
+//
+
+typedef struct _SRVSVC_SECURITY_OBJECT {
+ LPTSTR ObjectName;
+ PGENERIC_MAPPING Mapping;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+} SRVSVC_SECURITY_OBJECT, *PSRVSVC_SECURITY_OBJECT;
+
+//
+// Security objects used by the server service.
+//
+
+#ifdef SRV_COMM_DEVICES
+extern SRVSVC_SECURITY_OBJECT SsCharDevSecurityObject;
+#endif
+extern SRVSVC_SECURITY_OBJECT SsConfigInfoSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsConnectionSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsDiskSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsFileSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsSessionSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsShareFileSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsSharePrintSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsShareAdminSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsShareConnectSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsShareAdmConnectSecurityObject;
+extern SRVSVC_SECURITY_OBJECT SsStatisticsSecurityObject;
+
+//
+// Object type names for audit alarm tracking.
+//
+
+#ifdef SRV_COMM_DEVICES
+#define SRVSVC_CHARDEV_OBJECT TEXT( "SrvsvcCharDev" )
+#endif
+#define SRVSVC_CONFIG_INFO_OBJECT TEXT( "SrvsvcConfigInfo" )
+#define SRVSVC_CONNECTION_OBJECT TEXT( "SrvsvcConnection" )
+#define SRVSVC_DISK_OBJECT TEXT( "SrvsvcServerDiskEnum" )
+#define SRVSVC_FILE_OBJECT TEXT( "SrvsvcFile" )
+#define SRVSVC_SESSION_OBJECT TEXT( "SrvsvcSessionInfo" )
+#define SRVSVC_SHARE_FILE_OBJECT TEXT( "SrvsvcShareFileInfo" )
+#define SRVSVC_SHARE_PRINT_OBJECT TEXT( "SrvsvcSharePrintInfo" )
+#define SRVSVC_SHARE_ADMIN_OBJECT TEXT( "SrvsvcShareAdminInfo" )
+#define SRVSVC_SHARE_CONNECT_OBJECT TEXT( "SrvsvcShareConnect" )
+#define SRVSVC_SHARE_ADM_CONNECT_OBJECT TEXT( "SrvsvcShareAdminConnect" )
+#define SRVSVC_STATISTICS_OBJECT TEXT( "SrvsvcStatisticsInfo" )
+
+#ifdef SRV_COMM_DEVICES
+//
+// Access masks for character device APIs.
+//
+
+#define SRVSVC_CHARDEV_USER_INFO_GET 0x0001
+#define SRVSVC_CHARDEV_ADMIN_INFO_GET 0x0002
+#define SRVSVC_CHARDEV_INFO_SET 0x0010
+
+#define SRVSVC_CHARDEV_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_CHARDEV_USER_INFO_GET | \
+ SRVSVC_CHARDEV_ADMIN_INFO_GET | \
+ SRVSVC_CHARDEV_INFO_SET )
+#endif // def SRV_COMM_DEVICES
+
+//
+// Access masks for configuration information (NetServer{Get,Set}Info).
+//
+
+#define SRVSVC_CONFIG_USER_INFO_GET 0x0001
+#define SRVSVC_CONFIG_POWER_INFO_GET 0x0002
+#define SRVSVC_CONFIG_ADMIN_INFO_GET 0x0004
+#define SRVSVC_CONFIG_INFO_SET 0x0010
+
+#define SRVSVC_CONFIG_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_CONFIG_USER_INFO_GET | \
+ SRVSVC_CONFIG_POWER_INFO_GET | \
+ SRVSVC_CONFIG_ADMIN_INFO_GET | \
+ SRVSVC_CONFIG_INFO_SET )
+
+//
+// Access masks for connection information (NetConnectionEnum).
+//
+
+#define SRVSVC_CONNECTION_INFO_GET 0x0001
+
+#define SRVSVC_CONNECTION_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_CONNECTION_INFO_GET )
+
+//
+// Access masks for disk information (NetServerDiskEnum).
+//
+
+#define SRVSVC_DISK_ENUM 0x0001
+
+#define SRVSVC_DISK_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_DISK_ENUM )
+
+//
+// Access masks for file information (NetFileEnum, NetFileGetInfo,
+// NetFileClose).
+//
+
+#define SRVSVC_FILE_INFO_GET 0x0001
+#define SRVSVC_FILE_CLOSE 0x0010
+
+#define SRVSVC_FILE_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_FILE_INFO_GET | \
+ SRVSVC_FILE_CLOSE )
+
+//
+// Access masks for session information (NetSessionEnum,
+// NetSessionGetInfo, NetSessionDel).
+//
+
+#define SRVSVC_SESSION_USER_INFO_GET 0x0001
+#define SRVSVC_SESSION_ADMIN_INFO_GET 0x0002
+#define SRVSVC_SESSION_DELETE 0x0010
+
+#define SRVSVC_SESSION_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_SESSION_USER_INFO_GET | \
+ SRVSVC_SESSION_ADMIN_INFO_GET | \
+ SRVSVC_SESSION_DELETE )
+
+//
+// Access masks for share information (NetShareAdd, NetShareDel,
+// NetShareEnum, NetShareGetInfo, NetShareCheck, NetShareSetInfo).
+//
+// Access masks for connecting to shares are defined in srvfsctl.h,
+// since they must be shared between the server and server service.
+//
+
+#define SRVSVC_SHARE_USER_INFO_GET 0x0001
+#define SRVSVC_SHARE_ADMIN_INFO_GET 0x0002
+#define SRVSVC_SHARE_INFO_SET 0x0010
+
+#define SRVSVC_SHARE_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_SHARE_USER_INFO_GET | \
+ SRVSVC_SHARE_ADMIN_INFO_GET | \
+ SRVSVC_SHARE_INFO_SET )
+
+//
+// Access masks for statistics information (NetStatisticsGet,
+// NetStatisticsClear).
+//
+
+#define SRVSVC_STATISTICS_GET 0x0001
+
+#define SRVSVC_STATISTICS_ALL_ACCESS ( STANDARD_RIGHTS_REQUIRED | \
+ SRVSVC_STATISTICS_GET )
+
+#endif // _SSSEC_
diff --git a/private/net/svcdlls/srvsvc/server/sssubs.c b/private/net/svcdlls/srvsvc/server/sssubs.c
new file mode 100644
index 000000000..71e82f239
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/sssubs.c
@@ -0,0 +1,1064 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ SsSubs.c
+
+Abstract:
+
+ This module contains support routines for the NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 10-Jan-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "ssreg.h"
+
+#include <lmerr.h>
+#include <lmsname.h>
+#include <netlibnt.h>
+#include <tstr.h>
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+
+PSERVER_REQUEST_PACKET
+SsAllocateSrp (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a serer request packet so that an API can
+ communicate with the kernel-mode server. Any general initialization
+ in performed here.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PSERVER_REQUEST_PACKET - a pointer to the allocated SRP.
+
+--*/
+
+{
+ PSERVER_REQUEST_PACKET srp;
+
+ srp = MIDL_user_allocate( sizeof(SERVER_REQUEST_PACKET) );
+ if ( srp != NULL ) {
+ RtlZeroMemory( srp, sizeof(SERVER_REQUEST_PACKET) );
+ }
+
+ return srp;
+
+} // SsAllocateSrp
+
+#if DBG
+
+VOID
+SsAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber
+ )
+{
+ BOOL ok;
+ CHAR choice[16];
+ DWORD bytes;
+ DWORD error;
+
+ SsPrintf( "\nAssertion failed: %s\n at line %ld of %s\n",
+ FailedAssertion, LineNumber, FileName );
+ do {
+ SsPrintf( "Break or Ignore [bi]? " );
+ bytes = sizeof(choice);
+ ok = ReadFile(
+ GetStdHandle(STD_INPUT_HANDLE),
+ &choice,
+ bytes,
+ &bytes,
+ NULL
+ );
+ if ( ok ) {
+ if ( toupper(choice[0]) == 'I' ) {
+ break;
+ }
+ if ( toupper(choice[0]) == 'B' ) {
+ DbgUserBreakPoint( );
+ }
+ } else {
+ error = GetLastError( );
+ }
+ } while ( TRUE );
+
+ return;
+
+} // SsAssert
+#endif
+
+
+VOID
+SsCloseServer (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes the server file system device, if it has been
+ opened.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Close the server device, if it has been opened.
+ //
+
+ if ( SsServerDeviceHandle != NULL ) {
+ NtClose( SsServerDeviceHandle );
+ SsServerDeviceHandle = NULL;
+ }
+
+} // SsCloseServer
+
+
+VOID
+SsControlCHandler (
+ IN ULONG CtrlType
+ )
+
+/*++
+
+Routine Description:
+
+ Captures and ignores a kill signal. Without this, any ^C pressed in
+ the window that started the server service will result in this
+ process being killed, and then the server can't function properly.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CtrlType;
+
+ return;
+
+} // SsControlCHandler
+
+
+VOID
+SsFreeSrp (
+ IN PSERVER_REQUEST_PACKET Srp
+ )
+
+/*++
+
+Routine Description:
+
+ Frees an SRP allocated by SsAllocateSrp.
+
+Arguments:
+
+ Srp - a pointer to the SRP to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ MIDL_user_free( Srp );
+
+} // SsFreeSrp
+
+
+VOID
+SsLogEvent(
+ IN DWORD MessageId,
+ IN DWORD NumberOfSubStrings,
+ IN LPWSTR *SubStrings,
+ IN DWORD ErrorCode
+ )
+{
+ HANDLE logHandle;
+ DWORD dataSize = 0;
+ LPVOID rawData = NULL;
+
+ logHandle = RegisterEventSource(
+ NULL,
+ SERVER_DISPLAY_NAME
+ );
+
+ if ( logHandle == NULL ) {
+ SS_PRINT(( "SRVSVC: RegisterEventSource failed: %lu\n",
+ GetLastError() ));
+ return;
+ }
+
+ if ( ErrorCode != NERR_Success ) {
+
+ //
+ // An error code was specified.
+ //
+
+ dataSize = sizeof(ErrorCode);
+ rawData = (LPVOID)&ErrorCode;
+
+ }
+
+ //
+ // Log the error.
+ //
+
+ if ( !ReportEventW(
+ logHandle,
+ EVENTLOG_ERROR_TYPE,
+ 0, // event category
+ MessageId,
+ NULL, // user SID
+ (WORD)NumberOfSubStrings,
+ dataSize,
+ SubStrings,
+ rawData
+ ) ) {
+ SS_PRINT(( "SRVSVC: ReportEvent failed: %lu\n",
+ GetLastError() ));
+ }
+
+ if ( !DeregisterEventSource( logHandle ) ) {
+ SS_PRINT(( "SRVSVC: DeregisterEventSource failed: %lu\n",
+ GetLastError() ));
+ }
+
+ return;
+
+} // SsLogEvent
+
+
+NET_API_STATUS
+SsOpenServer (
+ PHANDLE pHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the server file system device, allowing the
+ server service to send FS controls to it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - results of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING unicodeServerName;
+ OBJECT_ATTRIBUTES objectAttributes;
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ if( !ARGUMENT_PRESENT( pHandle ) ) {
+ SS_ASSERT( SsServerDeviceHandle == NULL );
+ pHandle = &SsServerDeviceHandle;
+ }
+
+
+ //
+ // Open the server device.
+ //
+
+ RtlInitUnicodeString( &unicodeServerName, SERVER_DEVICE_NAME );
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &unicodeServerName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ //
+ // Opening the server with desired access = SYNCHRONIZE and open
+ // options = FILE_SYNCHRONOUS_IO_NONALERT means that we don't have
+ // to worry about waiting for the NtFsControlFile to complete--this
+ // makes all IO system calls that use this handle synchronous.
+ //
+
+ status = NtOpenFile(
+ pHandle,
+ SYNCHRONIZE,
+ &objectAttributes,
+ &ioStatusBlock,
+ 0,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+
+ if ( NT_SUCCESS(status) ) {
+ status = ioStatusBlock.Status;
+ }
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(INITIALIZATION_ERRORS) {
+ SS_PRINT(( "SsOpenServer: NtOpenFile (server device object) "
+ "failed: %X\n", status ));
+ }
+ return NetpNtStatusToApiStatus( status );
+ }
+
+ //
+ // We're now ready to talk to the server.
+ //
+
+ return NO_ERROR;
+
+} // SsOpenServer
+
+#if DBG
+
+VOID
+SsPrintf (
+ char *Format,
+ ...
+ )
+
+{
+ va_list arglist;
+ char OutputBuffer[1024];
+ ULONG length;
+
+ va_start( arglist, Format );
+
+ vsprintf( OutputBuffer, Format, arglist );
+
+ va_end( arglist );
+
+ length = strlen( OutputBuffer );
+
+ WriteFile( GetStdHandle(STD_OUTPUT_HANDLE), (LPVOID )OutputBuffer, length, &length, NULL );
+
+} // SsPrintf
+#endif
+
+
+NET_API_STATUS
+SsServerFsControlGetInfo (
+ IN ULONG ServerControlCode,
+ IN PSERVER_REQUEST_PACKET Srp,
+ IN OUT PVOID *OutputBuffer,
+ IN ULONG PreferredMaximumLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends an SRP to the server for an API that retrieves
+ information from the server and takes a PreferredMaximumLength
+ parameter.
+
+Arguments:
+
+ ServerControlCode - the FSCTL code for the operation.
+
+ Srp - a pointer to the SRP for the operation.
+
+ OutputBuffer - a pointer to receive a pointer to the buffer
+ allocated by this routine to hold the output information.
+
+ PreferredMaximumLength - the PreferredMaximumLength parameter.
+
+Return Value:
+
+ NET_API_STATUS - results of operation.
+
+--*/
+
+{
+ NET_API_STATUS status = STATUS_SUCCESS;
+ ULONG resumeHandle = Srp->Parameters.Get.ResumeHandle;
+ ULONG BufLen = min( INITIAL_BUFFER_SIZE, PreferredMaximumLength );
+ ULONG i;
+
+ *OutputBuffer = NULL;
+
+ //
+ // Normally, we should only go through this loop at most 2 times. But
+ // if the amount of data the server needs to return is growing, then
+ // we might be forced to run through it a couple of more times. '5'
+ // is an arbitrary number just to ensure we don't get stuck.
+ //
+
+ for( i=0; i < 5; i++ ) {
+
+ if( *OutputBuffer ) {
+ MIDL_user_free( *OutputBuffer );
+ }
+
+ *OutputBuffer = MIDL_user_allocate( BufLen );
+
+ if( *OutputBuffer == NULL ) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ //
+ // Make the request of the server.
+ //
+
+ Srp->Parameters.Get.ResumeHandle = resumeHandle;
+
+ status = SsServerFsControl(
+ NULL,
+ ServerControlCode,
+ Srp,
+ *OutputBuffer,
+ BufLen
+ );
+
+ //
+ // If we were successful, or we got an error other than our buffer
+ // being too small, break out.
+ //
+ if ( status != ERROR_MORE_DATA && status != NERR_BufTooSmall ) {
+ break;
+ }
+
+ //
+ // We've been told that our buffer isn't big enough. But if we've hit
+ // the caller's PreferredMaximumLength, break out.
+ //
+ if( BufLen >= PreferredMaximumLength ) {
+ break;
+ }
+
+ //
+ // Let's try again. EXTRA_ALLOCATION is here to cover the case where the
+ // amount of space required grows between the previous FsControl call and
+ // the next one.
+ //
+ BufLen = min( Srp->Parameters.Get.TotalBytesNeeded + EXTRA_ALLOCATION,
+ PreferredMaximumLength );
+
+ }
+
+ if ( *OutputBuffer && Srp->Parameters.Get.EntriesRead == 0 ) {
+ MIDL_user_free( *OutputBuffer );
+ *OutputBuffer = NULL;
+ }
+
+ return status;
+
+} // SsServerFsControlGetInfo
+
+
+NET_API_STATUS
+SsServerFsControl (
+ IN HANDLE Handle OPTIONAL,
+ IN ULONG ServerControlCode,
+ IN PSERVER_REQUEST_PACKET Srp OPTIONAL,
+ IN PVOID Buffer,
+ IN ULONG BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends an FSCTL to the server. It first opens the server
+ device object, sends the FSCTL, then closes the server handle.
+
+Arguments:
+
+ ServerControlCode - the FSCTL code to send to the server.
+
+ Srp - a pointer to the SRP for the operation.
+
+ Buffer - a pointer to the buffer to pass to the server as the
+ "OutputBuffer" parameter of NtFsControlFile.
+
+ BufferLength - the size of this buffer.
+
+Return Value:
+
+ NET_API_STATUS - results of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ NET_API_STATUS error;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PSERVER_REQUEST_PACKET sendSrp;
+ ULONG sendSrpLength;
+ PWCH name1Buffer, name2Buffer;
+
+ if( !ARGUMENT_PRESENT( Handle ) ) {
+ SS_ASSERT( SsServerDeviceHandle != NULL );
+ Handle = SsServerDeviceHandle;
+ }
+
+
+ //
+ // If a name was specified, we must capture the SRP along with the
+ // name in order to avoid sending embedded input pointers.
+ //
+
+ if ( Srp != NULL ) {
+
+ name1Buffer = Srp->Name1.Buffer;
+ name2Buffer = Srp->Name2.Buffer;
+
+ if ( Srp->Name1.Buffer != NULL || Srp->Name2.Buffer != NULL ) {
+
+ PCHAR nextStringLocation;
+
+ //
+ // Allocate enough space to hold the SRP + name.
+ //
+
+ sendSrpLength = sizeof(SERVER_REQUEST_PACKET);
+
+ if ( Srp->Name1.Buffer != NULL ) {
+ sendSrpLength += Srp->Name1.MaximumLength;
+ }
+
+ if ( Srp->Name2.Buffer != NULL ) {
+ sendSrpLength += Srp->Name2.MaximumLength;
+ }
+
+ sendSrp = MIDL_user_allocate( sendSrpLength );
+
+ if ( sendSrp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Copy over the SRP.
+ //
+
+ RtlCopyMemory( sendSrp, Srp, sizeof(SERVER_REQUEST_PACKET) );
+
+ //
+ // Set up the names in the new SRP.
+ //
+
+ nextStringLocation = (PCHAR)( sendSrp + 1 );
+
+ if ( Srp->Name1.Buffer != NULL ) {
+
+ sendSrp->Name1.Length = Srp->Name1.Length;
+ sendSrp->Name1.MaximumLength = Srp->Name1.MaximumLength;
+ sendSrp->Name1.Buffer = (PWCH)nextStringLocation;
+
+ RtlCopyMemory(
+ sendSrp->Name1.Buffer,
+ Srp->Name1.Buffer,
+ Srp->Name1.MaximumLength
+ );
+
+ nextStringLocation += Srp->Name1.MaximumLength;
+
+ POINTER_TO_OFFSET( sendSrp->Name1.Buffer, sendSrp );
+ }
+
+ if ( Srp->Name2.Buffer != NULL ) {
+
+ sendSrp->Name2.Length = Srp->Name2.Length;
+ sendSrp->Name2.MaximumLength = Srp->Name2.MaximumLength;
+ sendSrp->Name2.Buffer = (PWCH)nextStringLocation;
+
+ RtlCopyMemory(
+ sendSrp->Name2.Buffer,
+ Srp->Name2.Buffer,
+ Srp->Name2.MaximumLength
+ );
+
+ POINTER_TO_OFFSET( sendSrp->Name2.Buffer, sendSrp );
+ }
+
+ } else {
+
+ //
+ // There was no name in the SRP, so just send the SRP that was
+ // passed in.
+ //
+
+ sendSrp = Srp;
+ sendSrpLength = sizeof(SERVER_REQUEST_PACKET);
+ }
+
+ } else {
+
+ //
+ // This request has no SRP.
+ //
+
+ sendSrp = NULL;
+ sendSrpLength = 0;
+
+ }
+
+ //
+ // Send the request to the server FSD.
+ //
+
+ status = NtFsControlFile(
+ Handle,
+ NULL,
+ NULL,
+ NULL,
+ &ioStatusBlock,
+ ServerControlCode,
+ sendSrp,
+ sendSrpLength,
+ Buffer,
+ BufferLength
+ );
+
+ //
+ // If an error code was set in the SRP, use it. Otherwise, if
+ // an error was returned or set in the IO status block, use that.
+ //
+
+ if ( (sendSrp != NULL) && (sendSrp->ErrorCode != NO_ERROR) ) {
+ error = sendSrp->ErrorCode;
+ IF_DEBUG(API_ERRORS) {
+ SS_PRINT(( "SsServerFsControl: (1) API call %lx to srv failed, "
+ "err = %ld\n", ServerControlCode, error ));
+ }
+ } else {
+ if ( NT_SUCCESS(status) ) {
+ status = ioStatusBlock.Status;
+ }
+ if ( status == STATUS_SERVER_HAS_OPEN_HANDLES ) {
+ error = ERROR_SERVER_HAS_OPEN_HANDLES;
+ } else {
+ error = NetpNtStatusToApiStatus( status );
+ }
+ if ( error != NO_ERROR ) {
+ IF_DEBUG(API_ERRORS) {
+ SS_PRINT(( "SsServerFsControl: (2) API call %lx to srv "
+ "failed, err = %ld, status = %X\n",
+ ServerControlCode, error, status ));
+ }
+ }
+ }
+
+ //
+ // If a separate buffer was allocated to capture the name, copy
+ // over the new SRP and free it.
+ //
+
+ if ( sendSrp != Srp ) {
+ RtlCopyMemory( Srp, sendSrp, sizeof(SERVER_REQUEST_PACKET) );
+ Srp->Name1.Buffer = name1Buffer;
+ Srp->Name2.Buffer = name2Buffer;
+ MIDL_user_free( sendSrp );
+ }
+
+ return error;
+
+} // SsServerFsControl
+
+
+DWORD
+SsGetServerType (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Return the ServiceBits of all the services implemented by this service.
+
+ Enter with SsServerInfoResource locked.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ SV_TYPE service bits.
+
+--*/
+{
+ DWORD serviceBits;
+
+ serviceBits = SV_TYPE_SERVER | SV_TYPE_NT;
+
+ if( SsData.IsDfsRoot ) {
+ serviceBits |= SV_TYPE_DFS;
+ }
+
+ if ( SsData.ServerInfo599.sv599_timesource ) {
+ serviceBits |= SV_TYPE_TIME_SOURCE;
+ }
+
+ if ( SsData.ServerInfo598.sv598_producttype == NtProductServer ) {
+ serviceBits |= SV_TYPE_SERVER_NT;
+ }
+
+ if ( SsData.NumberOfPrintShares != 0 ) {
+ serviceBits |= SV_TYPE_PRINTQ_SERVER;
+ }
+
+ return serviceBits;
+
+}
+
+
+VOID
+SsSetExportedServerType (
+ IN PNAME_LIST_ENTRY service OPTIONAL,
+ IN BOOL ExternalBitsAlreadyChanged,
+ IN BOOL UpdateImmediately
+ )
+{
+ DWORD serviceBits;
+ DWORD newServiceBits;
+ BOOL changed = ExternalBitsAlreadyChanged;
+
+ //
+ // The value returned in the sv102_type field is an amalgam of the
+ // following:
+ //
+ // 1) The internal server type bits SV_TYPE_SERVER (always set),
+ // SV_TYPE_NT (always set), SV_TYPE_TIME_SOURCE (set if the
+ // parameter TimeSource is TRUE), and SV_TYPE_PRINTQ_SERVER (set
+ // if there are any print shares).
+ //
+ // 2) SV_TYPE_DFS if this machine is the root of a DFS tree
+ //
+ // 3) The bits set by the service controller calling I_NetServerSetServiceBits.
+ //
+ // 4) The logical OR of all per-transport server type bits set by
+ // the Browser calling I_NetServerSetServiceBits.
+ //
+
+ (VOID)RtlAcquireResourceExclusive( &SsServerInfoResource, TRUE );
+
+ serviceBits = SsGetServerType();
+
+ if( ARGUMENT_PRESENT( service ) ) {
+ //
+ // Change the bits for the passed-in NAME_LIST_ENTRY only
+ //
+
+ newServiceBits = service->ServiceBits;
+ newServiceBits &= ~(SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_NT | SV_TYPE_PRINTQ_SERVER | SV_TYPE_DFS);
+ newServiceBits |= serviceBits;
+
+ if( service->ServiceBits != newServiceBits ) {
+ service->ServiceBits |= newServiceBits;
+ changed = TRUE;
+ }
+
+ } else {
+ //
+ // Change the bits for each NAME_LIST_ENTRY
+ //
+ for ( service = SsServerNameList; service != NULL; service = service->Next ) {
+
+ newServiceBits = service->ServiceBits;
+ newServiceBits &= ~(SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_NT | SV_TYPE_PRINTQ_SERVER | SV_TYPE_DFS );
+ newServiceBits |= serviceBits;
+
+ if( service->ServiceBits != newServiceBits ) {
+ service->ServiceBits |= newServiceBits;
+ changed = TRUE;
+ }
+ }
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+
+ if ( changed && UpdateImmediately ) {
+ if ( !SetEvent( SsStatusChangedEvent ) ) {
+ SS_PRINT(( "SsSetExportedServerType: SetEvent failed: %ld\n",
+ GetLastError( ) ));
+ }
+ }
+
+ return;
+
+} // SsSetExportedServerType
+
+
+NET_API_STATUS
+SsSetField (
+ IN PFIELD_DESCRIPTOR Field,
+ IN PVOID Value,
+ IN BOOLEAN WriteToRegistry,
+ OUT BOOLEAN *AnnouncementInformationChanged OPTIONAL
+ )
+{
+ PCHAR structure;
+
+ //
+ // *** We do not initialize *AnnouncementInformationChanged to
+ // FALSE! We leave it alone, unless interesting information is
+ // changed, in which case we set it to TRUE. This is to allow a
+ // caller to initialize it itself, then call this function
+ // multiple times, with the resulting value in the parameter
+ // being TRUE if at least one of the calls changed an
+ // interesting parameter.
+ //
+
+ //
+ // Determine the structure that will be set.
+ //
+
+ if ( Field->Level / 100 == 5 ) {
+ if ( Field->Level != 598 ) {
+ structure = (PCHAR)&SsData.ServerInfo599;
+ } else {
+ structure = (PCHAR)&SsData.ServerInfo598;
+ }
+ } else {
+ structure = (PCHAR)&SsData.ServerInfo102;
+ }
+
+ //
+ // Set the value in the field based on the field type.
+ //
+
+ switch ( Field->FieldType ) {
+
+ case BOOLEAN_FIELD: {
+
+ BOOLEAN value = *(PBOOLEAN)Value;
+ PBOOLEAN valueLocation;
+
+ //
+ // BOOLEANs may only be TRUE (1) or FALSE (0).
+ //
+
+ if ( value != TRUE && value != FALSE ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ valueLocation = (PBOOLEAN)( structure + Field->FieldOffset );
+
+ //
+ // If we're turning off Hidden (i.e., making the server public),
+ // indicate that an announcment-related parameter has changed.
+ // This will cause an announcement to be sent immediately.
+ //
+
+ if ( (Field->FieldOffset ==
+ FIELD_OFFSET( SERVER_INFO_102, sv102_hidden )) &&
+ (value && !(*valueLocation)) &&
+ (ARGUMENT_PRESENT(AnnouncementInformationChanged)) ) {
+ *AnnouncementInformationChanged = TRUE;
+ }
+
+ *valueLocation = value;
+
+ break;
+ }
+
+ case DWORD_FIELD: {
+
+ DWORD value = *(PDWORD)Value;
+ PDWORD valueLocation;
+
+ //
+ // Make sure that the specified value is in the range of
+ // legal values for the Field.
+ //
+
+ if ( value > Field->MaximumValue || value < Field->MinimumValue ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ valueLocation = (PDWORD)( structure + Field->FieldOffset );
+ *valueLocation = value;
+
+ break;
+ }
+
+ case LPSTR_FIELD: {
+
+ LPWCH value = *(LPWCH *)Value;
+ LPWSTR valueLocation;
+ ULONG maxLength;
+
+ //
+ // We are setting the name, comment, or userpath for the server.
+ // Use the field offset to determine which.
+ //
+
+ if ( Field->FieldOffset ==
+ FIELD_OFFSET( SERVER_INFO_102, sv102_name ) ) {
+ valueLocation = SsData.ServerNameBuffer;
+ maxLength = sizeof( SsServerTransportAddress );
+ } else if ( Field->FieldOffset ==
+ FIELD_OFFSET( SERVER_INFO_102, sv102_comment ) ) {
+ valueLocation = SsData.ServerCommentBuffer;
+ maxLength = MAXCOMMENTSZ;
+ } else if ( Field->FieldOffset ==
+ FIELD_OFFSET( SERVER_INFO_102, sv102_userpath ) ) {
+ valueLocation = SsData.UserPathBuffer;
+ maxLength = MAX_PATH;
+ } else if ( Field->FieldOffset ==
+ FIELD_OFFSET( SERVER_INFO_599, sv599_domain ) ) {
+ valueLocation = SsData.DomainNameBuffer;
+ maxLength = DNLEN;
+ } else {
+ SS_ASSERT( FALSE );
+ }
+
+ //
+ // If the string is too long, return an error.
+ //
+
+ if ( (value != NULL) && (STRLEN(value) > maxLength) ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // If we're changing the server comment, indicate that an
+ // announcment-related parameter has changed. This will cause
+ // an announcement to be sent immediately.
+ //
+
+ if ( (Field->FieldOffset ==
+ FIELD_OFFSET( SERVER_INFO_102, sv102_comment )) &&
+ ( ((value == NULL) && (*valueLocation != '\0')) ||
+ ((value != NULL) && (wcscmp(value,valueLocation) != 0)) ) &&
+ (ARGUMENT_PRESENT(AnnouncementInformationChanged)) ) {
+ *AnnouncementInformationChanged = TRUE;
+ }
+
+ //
+ // If the input is NULL, make the string zero length.
+ //
+
+ if ( value == NULL ) {
+
+ *valueLocation = '\0';
+ *(valueLocation+1) = '\0';
+
+ } else {
+
+ wcscpy( valueLocation, value );
+
+ }
+
+ break;
+ }
+
+ } // end switch
+
+ //
+ // The change worked. If requested, add the parameter to the
+ // registry, thus effecting a sticky change. Don't write it
+ // to the registry if this is xxx_comment or xxx_disc since
+ // we already write out their more well known aliases
+ // srvcomment and autodisconnect. Changes here should also be
+ // made to SetStickyParameters().
+ //
+
+ if ( WriteToRegistry &&
+ (_wcsicmp( Field->FieldName, DISC_VALUE_NAME ) != 0) &&
+ (_wcsicmp( Field->FieldName, COMMENT_VALUE_NAME ) != 0) ) {
+
+ SsAddParameterToRegistry( Field, Value );
+ }
+
+ return NO_ERROR;
+
+} // SsSetField
+
+UINT
+SsGetDriveType (
+ IN LPWSTR path
+)
+/*++
+
+Routine Description:
+
+ This routine calls GetDriveType, attempting to eliminate
+ the DRIVE_NO_ROOT_DIR type
+
+Arguments:
+
+ A path
+
+Return Value:
+
+ The drive type
+
+--*/
+{
+ UINT driveType = GetDriveType( path );
+
+ if( driveType == DRIVE_NO_ROOT_DIR ) {
+
+ if( path[0] != UNICODE_NULL && path[1] == L':' ) {
+
+ WCHAR shortPath[ 4 ];
+
+ shortPath[0] = path[0];
+ shortPath[1] = L':';
+ shortPath[2] = L'\\';
+ shortPath[3] = L'\0';
+
+ driveType = GetDriveType( shortPath );
+
+ } else {
+
+ ULONG len = wcslen( path );
+ LPWSTR pathWithSlash = MIDL_user_allocate( (len + 2) * sizeof( *path ) );
+
+ if( pathWithSlash != NULL ) {
+ RtlCopyMemory( pathWithSlash, path, len * sizeof( *path ) );
+ pathWithSlash[ len ] = L'\\';
+ pathWithSlash[ len+1 ] = L'\0';
+ driveType = GetDriveType( pathWithSlash );
+ MIDL_user_free( pathWithSlash );
+ }
+ }
+ }
+
+ return driveType;
+}
diff --git a/private/net/svcdlls/srvsvc/server/stats.c b/private/net/svcdlls/srvsvc/server/stats.c
new file mode 100644
index 000000000..06a9d5211
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/stats.c
@@ -0,0 +1,113 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ stats.c
+
+Abstract:
+
+ This module contains support for the NetStatisticsGet API for the NT
+ OS/2 server service.
+
+Author:
+
+ David Treadwell (davidtr) 12-Apr-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerStatisticsGet (
+ IN LPTSTR ServerName,
+ IN LPTSTR Service,
+ IN DWORD Level,
+ IN DWORD Options,
+ OUT LPSTAT_SERVER_0 *InfoStruct
+ )
+
+/*++
+
+Routine Description:
+
+ This routine communicates with the server FSD to implement the
+ server half of the NetStatisticsGet function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NET_API_STATUS - NO_ERROR or reason for failure.
+
+--*/
+
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName, Service;
+
+ //
+ // The only valid level is 0.
+ //
+
+ if ( Level != 0 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // No options supported.
+ //
+
+ if ( Options != 0 ) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that the caller has the access necessary for this
+ // operation.
+ //
+
+ error = SsCheckAccess(
+ &SsStatisticsSecurityObject,
+ SRVSVC_STATISTICS_GET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ //
+ // Set up the request packet.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Send the request to the server.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_STATISTICS_GET,
+ srp,
+ (PVOID *)InfoStruct,
+ (ULONG)-1
+ );
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // NetrServerStatisticsGet
+
+
diff --git a/private/net/svcdlls/srvsvc/server/tod.c b/private/net/svcdlls/srvsvc/server/tod.c
new file mode 100644
index 000000000..769ca36e5
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/tod.c
@@ -0,0 +1,204 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ tod.c
+
+Abstract:
+
+ This module contains the server end of the NetRemoteTOD API.
+
+
+Author:
+
+ Rajen Shah (rajens) 02-Apr-1991
+
+[Environment:]
+
+ User Mode - Mixed NT and Win32
+
+Revision History:
+
+ 02-Apr-1991 RajenS
+ Created
+ 02-Mar-1992 JohnRo
+ Disable DbgPrints for normal APIs (caused loss of elapsed time!)
+ 08-Apr-1992 ChuckL
+ Moved into server service
+ 10-Jun-1993 JohnRo
+ RAID 13081: NetRemoteTOD should return timezone info.
+ 16-Jun-1993 JohnRo
+ RAID 13080: Fix GP fault if MIDL_user_allocate returns NULL ptr or
+ caller passes us NULL ptr.
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#include <windows.h>
+#include <lmcons.h>
+#include <netlibnt.h>
+#include <lmremutl.h>
+#include <rpcutil.h>
+#include <ssdebug.h> // SS_PRINT() macro.
+#include <timelib.h>
+
+//
+// Some defines that are used as defaults.
+// BUGBUG These should go into a common file, e.g. lmcons.h
+//
+#define TOD_DEFAULT_INTERVAL 310 // 310-milisecond interval
+
+
+
+NTSTATUS
+timesvc_RemoteTimeOfDay(
+ OUT LPTIME_OF_DAY_INFO *lpTimeOfDayInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the Win32 and NT base timer APIs to get the
+ relevant time/date information. It also calls the Rtl routine to
+ convert the time elapsed since 1-1-1970.
+
+ The routine allocates a buffer to contain the time of day information
+ and returns a pointer to that buffer to the caller.
+
+Arguments:
+
+ lpTimeOfDayInfo - Location of where to place pointer to buffer.
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or reason for failure.
+
+--*/
+
+{
+ SYSTEMTIME SystemTime;
+ LARGE_INTEGER Time;
+ DWORD TickCount;
+ LPTIME_OF_DAY_INFO lpTimeOfDay;
+ LONG LocalTimeZoneOffsetSecs; // offset (+ for West of GMT, etc).
+
+ if (lpTimeOfDayInfo == NULL) {
+ return (STATUS_INVALID_PARAMETER);
+ }
+
+ //
+ // Call the appropriate routines to collect the time information
+ //
+
+ GetSystemTime(&SystemTime);
+
+ //
+ // Get number of seconds from UTC. Positive values for west of Greenwich,
+ // negative values for east of Greenwich.
+ //
+ LocalTimeZoneOffsetSecs = NetpLocalTimeZoneOffset();
+
+ //
+ // Allocate a TimeOfDay_INFO structure that is to be returned to the
+ // caller and fill it with the relevant data.
+ //
+
+ *lpTimeOfDayInfo = (TIME_OF_DAY_INFO *) MIDL_user_allocate(
+ sizeof (struct _TIME_OF_DAY_INFO)
+ );
+
+ if (*lpTimeOfDayInfo == NULL) {
+ SS_PRINT((
+ "SRVSVC: timesvc_RemoteTimeOfDay"
+ "got NULL from MIDL_user_allocate!\n" ));
+ return(STATUS_NO_MEMORY);
+ }
+
+ lpTimeOfDay = (LPTIME_OF_DAY_INFO)(*lpTimeOfDayInfo);
+
+ lpTimeOfDay->tod_hours = SystemTime.wHour;
+ lpTimeOfDay->tod_mins = SystemTime.wMinute;
+ lpTimeOfDay->tod_secs = SystemTime.wSecond;
+ lpTimeOfDay->tod_hunds = SystemTime.wMilliseconds/10;
+ lpTimeOfDay->tod_tinterval = TOD_DEFAULT_INTERVAL;
+ lpTimeOfDay->tod_day = SystemTime.wDay;
+ lpTimeOfDay->tod_month = SystemTime.wMonth;
+ lpTimeOfDay->tod_year = SystemTime.wYear;
+ lpTimeOfDay->tod_weekday = SystemTime.wDayOfWeek;
+
+ // tod_timezone is + for west of GMT, - for east of it.
+ // tod_timezone is in minutes.
+ lpTimeOfDay->tod_timezone = LocalTimeZoneOffsetSecs / 60;
+
+ // Get the 64-bit system time.
+ // Convert the system time to the number of miliseconds
+ // since 1-1-1970.
+ //
+
+ NtQuerySystemTime(&Time);
+ RtlTimeToSecondsSince1970(&Time,
+ &(lpTimeOfDay->tod_elapsedt)
+ );
+
+ // Get the free running counter value
+ //
+ TickCount = GetTickCount();
+ lpTimeOfDay->tod_msecs = TickCount;
+
+ return(STATUS_SUCCESS);
+
+} // timesvc_RemoteTimeOfDay
+
+
+NET_API_STATUS
+NetrRemoteTOD (
+ IN LPSTR ServerName,
+ OUT LPTIME_OF_DAY_INFO *lpTimeOfDayInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This is the RPC server entry point for the NetRemoteTOD API.
+
+Arguments:
+
+ ServerName - Name of server on which this API is to be executed.
+ It should match this server's name - no checking is
+ done since it is assumed that RPC did the right thing.
+
+ lpTimeOfDayInfo - On return takes a pointer to a TIME_OF_DAY_INFO
+ structure - the memory is allocated here.
+
+
+Return Value:
+
+ Returns a NET_API_STATUS code.
+ Also returns a pointer to the TIME_OF_DAY_INFO data buffer that was
+ allocated, if there is no error.
+
+
+--*/
+{
+ NTSTATUS status;
+
+ //
+ // Call the worker routine to collect all the time/date information
+ //
+ status = timesvc_RemoteTimeOfDay(lpTimeOfDayInfo);
+
+ //
+ // Translate the NTSTATUS to a NET_API_STATUS error, and return it.
+ //
+
+ return(NetpNtStatusToApiStatus(status));
+
+ UNREFERENCED_PARAMETER( ServerName );
+}
diff --git a/private/net/svcdlls/srvsvc/server/xport.c b/private/net/svcdlls/srvsvc/server/xport.c
new file mode 100644
index 000000000..f72415fd0
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/xport.c
@@ -0,0 +1,689 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ Xport.c
+
+Abstract:
+
+ This module contains support for the ServerTransport catagory of
+ APIs for the NT server service.
+
+Author:
+
+ David Treadwell (davidtr) 10-Mar-1991
+
+Revision History:
+
+--*/
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "ssreg.h"
+
+#include <tstr.h>
+
+//
+// Forward declarations.
+//
+
+LPSERVER_TRANSPORT_INFO_1
+CaptureSvti1 (
+ IN DWORD Level,
+ IN LPTRANSPORT_INFO Svti,
+ OUT PULONG CapturedSvtiLength
+ );
+
+
+
+NET_API_STATUS NET_API_FUNCTION
+I_NetrServerTransportAddEx (
+ IN DWORD Level,
+ IN LPTRANSPORT_INFO Buffer
+ )
+{
+ NET_API_STATUS error;
+ LPSERVER_TRANSPORT_INFO_1 capturedSvti1;
+ LPSTR TransportAddress; // Pointer to transport address within capturedSvti1
+ ULONG capturedSvtiLength;
+ PSERVER_REQUEST_PACKET srp;
+ PNAME_LIST_ENTRY service;
+ PTRANSPORT_LIST_ENTRY transport;
+ BOOLEAN serviceAllocated = FALSE;
+ LPTSTR DomainName = SsData.DomainNameBuffer;
+ HANDLE h;
+
+ if( Level == 1 && Buffer->Transport1.svti1_domain != NULL ) {
+ DomainName = Buffer->Transport1.svti1_domain;
+ }
+
+ //
+ // Capture the transport request buffer and form the full transport
+ // address.
+ //
+
+ capturedSvti1 = CaptureSvti1( Level, Buffer, &capturedSvtiLength );
+
+ if ( capturedSvti1 == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ TransportAddress = capturedSvti1->svti1_transportaddress;
+ OFFSET_TO_POINTER( TransportAddress, capturedSvti1 );
+
+
+ //
+ // Make sure this name isn't already bound for the transport
+ //
+ (VOID)RtlAcquireResourceExclusive( &SsServerInfoResource, TRUE );
+
+ for( service = SsServerNameList; service != NULL; service = service->Next ) {
+
+ if( service->TransportAddressLength != capturedSvti1->svti1_transportaddresslength ) {
+ continue;
+ }
+
+ if( !RtlEqualMemory( service->TransportAddress,
+ TransportAddress,
+ capturedSvti1->svti1_transportaddresslength
+ ) ) {
+ continue;
+ }
+
+ for( transport=service->Transports; transport != NULL; transport=transport->Next ) {
+
+ if( !STRCMPI( transport->TransportName, Buffer->Transport0.svti0_transportname ) ) {
+ //
+ // Error... this transport is already bound to the address
+ //
+ RtlReleaseResource( &SsServerInfoResource );
+ MIDL_user_free( capturedSvti1 );
+ return ERROR_DUP_NAME;
+ }
+ }
+
+ break;
+ }
+
+ //
+ // Counting on success, ensure we can allocate space for the new entry
+ //
+ if( service == NULL ) {
+
+ service = MIDL_user_allocate( sizeof( *service ) + (STRLEN( DomainName ) + 1) * sizeof( TCHAR ) );
+
+ if( service == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ MIDL_user_free( capturedSvti1 );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( service, sizeof( *service ) );
+
+ service->DomainName = (LPTSTR)( service + 1 );
+
+ serviceAllocated = TRUE;
+ }
+
+ transport = MIDL_user_allocate( sizeof( *transport ) +
+ (STRLEN( Buffer->Transport0.svti0_transportname ) + sizeof(CHAR)) * sizeof( TCHAR ) );
+
+ if( transport == NULL ) {
+
+ RtlReleaseResource( &SsServerInfoResource );
+ if( serviceAllocated ) {
+ MIDL_user_free( service );
+ }
+ MIDL_user_free( capturedSvti1 );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ RtlZeroMemory( transport, sizeof( *transport ) );
+
+ //
+ // Get a SRP in which to send the request.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ if( serviceAllocated ) {
+ MIDL_user_free( service );
+ }
+ MIDL_user_free( capturedSvti1 );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ //
+ // Check if this is the primary machine name
+ //
+
+ if((capturedSvti1->svti1_transportaddresslength ==
+ SsServerTransportAddressLength)
+ &&
+ RtlEqualMemory(SsServerTransportAddress,
+ TransportAddress,
+ SsServerTransportAddressLength) )
+ {
+ srp->Flags |= SRP_XADD_PRIMARY_MACHINE;
+ }
+
+ //
+ // Send the request on to the server.
+ //
+ if( (error = SsOpenServer( &h )) == NO_ERROR ) {
+ error = SsServerFsControl(
+ h,
+ FSCTL_SRV_NET_SERVER_XPORT_ADD,
+ srp,
+ capturedSvti1,
+ capturedSvtiLength
+ );
+
+ NtClose( h );
+ }
+
+ //
+ // Free the SRP
+ //
+
+ SsFreeSrp( srp );
+
+ if( error != NO_ERROR ) {
+ RtlReleaseResource( &SsServerInfoResource );
+ if( serviceAllocated ) {
+ MIDL_user_free( service );
+ }
+ MIDL_user_free( transport );
+ MIDL_user_free( capturedSvti1 );
+ return error;
+ }
+
+ //
+ // Everything worked. Add it to the NAME_LIST
+ //
+ transport->TransportName = (LPTSTR)(transport + 1 );
+ STRCPY( transport->TransportName, Buffer->Transport0.svti0_transportname );
+ transport->Next = service->Transports;
+ service->Transports = transport;
+
+ if( serviceAllocated ) {
+
+ RtlCopyMemory( service->TransportAddress,
+ TransportAddress,
+ capturedSvti1->svti1_transportaddresslength );
+
+ service->TransportAddress[ capturedSvti1->svti1_transportaddresslength ] = '\0';
+ service->TransportAddressLength = capturedSvti1->svti1_transportaddresslength;
+
+ STRCPY( service->DomainName, DomainName );
+
+ service->Next = SsServerNameList;
+
+ //
+ // If this is the first transport and name added to the server, it must be the primary
+ // name
+ //
+ if( SsServerNameList == NULL ) {
+ service->PrimaryName = 1;
+ }
+
+ SsServerNameList = service;
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+ MIDL_user_free( capturedSvti1 );
+ SsSetExportedServerType( service, FALSE, FALSE );
+
+ return NO_ERROR;
+}
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerTransportAddEx (
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN LPTRANSPORT_INFO Buffer
+ )
+{
+ NET_API_STATUS error;
+ LPTSTR DomainName = SsData.DomainNameBuffer;
+ PNAME_LIST_ENTRY service;
+
+ ServerName;
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( Level != 0 && Level != 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ if( Buffer->Transport0.svti0_transportname == NULL ||
+ Buffer->Transport0.svti0_transportaddress == NULL ||
+ Buffer->Transport0.svti0_transportaddresslength == 0 ||
+ Buffer->Transport0.svti0_transportaddresslength >= sizeof(service->TransportAddress) ) {
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if( Level == 1 && Buffer->Transport1.svti1_domain != NULL ) {
+
+ DomainName = Buffer->Transport1.svti1_domain;
+
+ if( STRLEN( DomainName ) > DNLEN ) {
+ return ERROR_INVALID_DOMAINNAME;
+ }
+ }
+
+ //
+ // Make sure that the caller is allowed to set information in the
+ // server.
+ //
+
+ if( SsInitialized ) {
+ error = SsCheckAccess(
+ &SsConfigInfoSecurityObject,
+ SRVSVC_CONFIG_INFO_SET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ return I_NetrServerTransportAddEx ( Level, Buffer );
+
+} // NetrServerTransportAddEx
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerTransportAdd (
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN LPSERVER_TRANSPORT_INFO_0 Buffer
+)
+{
+ if( Level != 0 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ return NetrServerTransportAddEx( ServerName, 0, (LPTRANSPORT_INFO)Buffer );
+}
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerTransportDelEx (
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN LPTRANSPORT_INFO Buffer
+ )
+
+{
+ NET_API_STATUS error;
+ LPSERVER_TRANSPORT_INFO_1 capturedSvti1;
+ LPSTR TransportAddress; // Pointer to transport address within capturedSvti1
+ ULONG capturedSvtiLength;
+ PSERVER_REQUEST_PACKET srp;
+ PNAME_LIST_ENTRY service;
+ PNAME_LIST_ENTRY sbackp = NULL;
+ PTRANSPORT_LIST_ENTRY transport;
+ PTRANSPORT_LIST_ENTRY tbackp = NULL;
+
+ ServerName;
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( Level != 0 && Level != 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ if( Buffer->Transport0.svti0_transportname == NULL ||
+ Buffer->Transport0.svti0_transportaddress == NULL ||
+ Buffer->Transport0.svti0_transportaddresslength == 0 ||
+ Buffer->Transport0.svti0_transportaddresslength >= sizeof(service->TransportAddress) ) {
+
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that the caller is allowed to set information in the
+ // server.
+ //
+
+ if( SsInitialized ) {
+ error = SsCheckAccess(
+ &SsConfigInfoSecurityObject,
+ SRVSVC_CONFIG_INFO_SET
+ );
+
+ if ( error != NO_ERROR ) {
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ //
+ // Capture the transport request buffer and form the full transport
+ // address.
+ //
+
+ capturedSvti1 = CaptureSvti1( Level, Buffer, &capturedSvtiLength );
+
+ if ( capturedSvti1 == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ TransportAddress = capturedSvti1->svti1_transportaddress;
+ OFFSET_TO_POINTER( TransportAddress, capturedSvti1 );
+
+ //
+ // Get an SRP in which to send the request.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ MIDL_user_free( capturedSvti1 );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+
+ //
+ // Send the request on to the server.
+ //
+ error = SsServerFsControl(
+ NULL,
+ FSCTL_SRV_NET_SERVER_XPORT_DEL,
+ srp,
+ capturedSvti1,
+ capturedSvtiLength
+ );
+
+ //
+ // Free the SRP and svti
+ //
+
+ SsFreeSrp( srp );
+
+ if( error != NO_ERROR ) {
+ MIDL_user_free( capturedSvti1 );
+ return error;
+ }
+
+ (VOID)RtlAcquireResourceExclusive( &SsServerInfoResource, TRUE );
+
+
+ //
+ // Remove the entry from the SsServerNameList. If it's the last transport for
+ // the NAME_LIST_ENTRY, delete the NAME_LIST_ENTRY as well.
+ //
+ for( service = SsServerNameList; service != NULL; sbackp = service, service = service->Next ) {
+
+ //
+ // Walk the list until we find the NAME_LIST_ENTRY having the transportaddress
+ // of interest
+ //
+ if( service->TransportAddressLength != capturedSvti1->svti1_transportaddresslength ) {
+ continue;
+ }
+
+ if( !RtlEqualMemory( service->TransportAddress,
+ TransportAddress,
+ capturedSvti1->svti1_transportaddresslength ) ) {
+ continue;
+ }
+
+ //
+ // This is the correct NAME_LIST_ENTRY, now find the TRANSPORT_LIST_ENTRY of interest
+ //
+ for( transport=service->Transports; transport != NULL; tbackp=transport, transport=transport->Next ) {
+
+ if( STRCMPI( transport->TransportName, Buffer->Transport0.svti0_transportname ) ) {
+ continue;
+ }
+
+ //
+ // This is the one...remove it from the list
+ //
+
+ if( tbackp == NULL ) {
+ service->Transports = transport->Next;
+ } else {
+ tbackp->Next = transport->Next;
+ }
+
+ MIDL_user_free( transport );
+
+ break;
+ }
+
+ //
+ // If this NAME_LIST_ENTRY no longer has any transports, delete it
+ //
+ if( service->Transports == NULL ) {
+ if( sbackp == NULL ) {
+ SsServerNameList = service->Next;
+ } else {
+ sbackp->Next = service->Next;
+ }
+ MIDL_user_free( service );
+ }
+
+ break;
+ }
+
+ RtlReleaseResource( &SsServerInfoResource );
+ MIDL_user_free( capturedSvti1 );
+
+ return NO_ERROR;
+
+} // NetrServerTransportDelEx
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerTransportDel (
+ IN LPTSTR ServerName,
+ IN DWORD Level,
+ IN LPSERVER_TRANSPORT_INFO_0 Buffer
+)
+{
+ return NetrServerTransportDelEx( ServerName, Level, (LPTRANSPORT_INFO)Buffer );
+}
+
+
+NET_API_STATUS NET_API_FUNCTION
+NetrServerTransportEnum (
+ IN LPTSTR ServerName,
+ IN LPSERVER_XPORT_ENUM_STRUCT InfoStruct,
+ IN DWORD PreferredMaximumLength,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle OPTIONAL
+ )
+{
+ NET_API_STATUS error;
+ PSERVER_REQUEST_PACKET srp;
+
+ ServerName;
+
+ //
+ // Make sure that the level is valid.
+ //
+
+ if ( InfoStruct->Level != 0 && InfoStruct->Level != 1 ) {
+ return ERROR_INVALID_LEVEL;
+ }
+
+ //
+ // Set up the input parameters in the request buffer.
+ //
+
+ srp = SsAllocateSrp( );
+ if ( srp == NULL ) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ srp->Level = InfoStruct->Level;
+
+ if ( ARGUMENT_PRESENT( ResumeHandle ) ) {
+ srp->Parameters.Get.ResumeHandle = *ResumeHandle;
+ } else {
+ srp->Parameters.Get.ResumeHandle = 0;
+ }
+
+ //
+ // Get the data from the server. This routine will allocate the
+ // return buffer and handle the case where PreferredMaximumLength ==
+ // -1.
+ //
+
+ error = SsServerFsControlGetInfo(
+ FSCTL_SRV_NET_SERVER_XPORT_ENUM,
+ srp,
+ (PVOID *)&InfoStruct->XportInfo.Level0->Buffer,
+ PreferredMaximumLength
+ );
+
+ //
+ // Set up return information.
+ //
+
+ InfoStruct->XportInfo.Level0->EntriesRead = srp->Parameters.Get.EntriesRead;
+ *TotalEntries = srp->Parameters.Get.TotalEntries;
+ if ( srp->Parameters.Get.EntriesRead > 0 && ARGUMENT_PRESENT( ResumeHandle ) ) {
+ *ResumeHandle = srp->Parameters.Get.ResumeHandle;
+ }
+
+ SsFreeSrp( srp );
+
+ return error;
+
+} // NetrServerTransportEnum
+
+
+LPSERVER_TRANSPORT_INFO_1
+CaptureSvti1 (
+ IN DWORD Level,
+ IN LPTRANSPORT_INFO Svti,
+ OUT PULONG CapturedSvtiLength
+ )
+{
+ LPSERVER_TRANSPORT_INFO_1 capturedSvti;
+ PCHAR variableData;
+ ULONG transportNameLength;
+ CHAR TransportAddressBuffer[MAX_PATH];
+ LPBYTE TransportAddress;
+ DWORD TransportAddressLength;
+ LPTSTR DomainName;
+ DWORD domainLength;
+
+ //
+ // If a server transport name is specified, use it, otherwise
+ // use the default server name on the transport.
+ //
+ // Either way, the return transport address is normalized into a netbios address
+ //
+
+ if ( Svti->Transport0.svti0_transportaddress == NULL ) {
+ TransportAddress = SsServerTransportAddress;
+ TransportAddressLength = SsServerTransportAddressLength;
+ Svti->Transport0.svti0_transportaddresslength = TransportAddressLength;
+ } else {
+
+
+ //
+ // Normalize the transport address.
+ //
+
+ TransportAddress = TransportAddressBuffer;
+ TransportAddressLength = min( Svti->Transport0.svti0_transportaddresslength,
+ sizeof( TransportAddressBuffer ));
+
+ RtlCopyMemory( TransportAddress,
+ Svti->Transport0.svti0_transportaddress,
+ TransportAddressLength );
+
+ if ( TransportAddressLength < NETBIOS_NAME_LEN ) {
+
+ RtlCopyMemory( TransportAddress + TransportAddressLength,
+ " ",
+ NETBIOS_NAME_LEN - TransportAddressLength );
+
+ TransportAddressLength = NETBIOS_NAME_LEN;
+
+ } else {
+
+ TransportAddressLength = NETBIOS_NAME_LEN;
+
+ }
+
+ }
+
+ transportNameLength = SIZE_WSTR( Svti->Transport0.svti0_transportname );
+
+ if( Level == 0 || Svti->Transport1.svti1_domain == NULL ) {
+ DomainName = SsData.DomainNameBuffer;
+ } else {
+ DomainName = Svti->Transport1.svti1_domain;
+ }
+
+ domainLength = SIZE_WSTR( DomainName );
+
+ //
+ // Allocate enough space to hold the captured buffer, including the
+ // full transport name/address and domain name
+ //
+
+ *CapturedSvtiLength = sizeof(*capturedSvti) +
+ transportNameLength + TransportAddressLength + domainLength;
+
+ capturedSvti = MIDL_user_allocate( *CapturedSvtiLength );
+
+ if ( capturedSvti == NULL ) {
+ return NULL;
+ }
+
+ //
+ // This field is not used...
+ //
+ capturedSvti->svti1_numberofvcs = 0;
+
+ //
+ // Copy in the domain name
+ //
+ variableData = (PCHAR)( capturedSvti + 1 );
+ capturedSvti->svti1_domain = (PWCH)variableData;
+ RtlCopyMemory( variableData,
+ DomainName,
+ domainLength
+ );
+ variableData += domainLength;
+ POINTER_TO_OFFSET( capturedSvti->svti1_domain, capturedSvti );
+
+ //
+ // Copy the transport name
+ //
+ capturedSvti->svti1_transportname = (PWCH)variableData;
+ RtlCopyMemory(
+ variableData,
+ Svti->Transport1.svti1_transportname,
+ transportNameLength
+ );
+ variableData += transportNameLength;
+ POINTER_TO_OFFSET( capturedSvti->svti1_transportname, capturedSvti );
+
+ //
+ // Copy the transport address
+ //
+ capturedSvti->svti1_transportaddress = variableData;
+ capturedSvti->svti1_transportaddresslength = TransportAddressLength;
+ RtlCopyMemory(
+ variableData,
+ TransportAddress,
+ TransportAddressLength
+ );
+ variableData += TransportAddressLength;
+ POINTER_TO_OFFSET( capturedSvti->svti1_transportaddress, capturedSvti );
+
+ return capturedSvti;
+
+} // CaptureSvti
diff --git a/private/net/svcdlls/srvsvc/server/xsdata.c b/private/net/svcdlls/srvsvc/server/xsdata.c
new file mode 100644
index 000000000..3517109e7
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/xsdata.c
@@ -0,0 +1,301 @@
+/*+
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ xsdata.c
+
+Abstract:
+
+ Global data declarations for XACTSRV.
+
+Author:
+
+ David Treadwell (davidtr) 05-Jan-1991
+ Shanku Niyogi (w-shanku)
+
+Revision History:
+
+ Chuck Lenzmeier (chuckl) 17-Jun-1992
+ Moved from xssvc to srvsvc\server
+
+--*/
+
+//
+// Includes.
+//
+
+#include "srvsvcp.h"
+#include "xsdata.h"
+
+#include <remdef.h> // from net\inc
+#include <xsprocs.h>
+
+#include <xsconst.h> // from xactsrv
+#include <xsprocsp.h>
+
+#undef DEBUG
+#undef DEBUG_API_ERRORS
+#include <xsdebug.h>
+
+//
+// Debugging flags.
+//
+
+DWORD XsDebug = 0;
+
+//
+// Number of XACTSRV worker threads.
+//
+
+LONG XsThreads = 0;
+
+//
+// Event signalled when the last XACTSRV worker thread terminates.
+//
+
+HANDLE XsAllThreadsTerminatedEvent = NULL;
+
+//
+// Boolean indicating whether XACTSRV is active or terminating.
+//
+
+BOOL XsTerminating = FALSE;
+
+//
+// Handle for the LPC port used for communication between the file server
+// and XACTSRV.
+//
+
+HANDLE XsConnectionPortHandle = NULL;
+HANDLE XsCommunicationPortHandle = NULL;
+
+//
+// Table of information necessary for dispatching API requests.
+//
+// ImpersonateClient specifies whether XACTSRV should impersonate the caller
+// before invoking the API handler.
+//
+// Handler specifies the function XACTSRV should call to handle the API.
+//
+
+XS_API_TABLE_ENTRY XsApiTable[XS_SIZE_OF_API_TABLE] = {
+ TRUE, &XsNetShareEnum, REMSmb_NetShareEnum_P, // 0
+ TRUE, &XsNetShareGetInfo, REMSmb_NetShareGetInfo_P,
+ TRUE, &XsNetShareSetInfo, REMSmb_NetShareSetInfo_P,
+ TRUE, &XsNetShareAdd, REMSmb_NetShareAdd_P,
+ TRUE, &XsNetShareDel, REMSmb_NetShareDel_P,
+ TRUE, &XsNetShareCheck, REMSmb_NetShareCheck_P,
+ TRUE, &XsNetSessionEnum, REMSmb_NetSessionEnum_P,
+ TRUE, &XsNetSessionGetInfo, REMSmb_NetSessionGetInfo_P,
+ TRUE, &XsNetSessionDel, REMSmb_NetSessionDel_P,
+ TRUE, &XsNetConnectionEnum, REMSmb_NetConnectionEnum_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 10
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetServerGetInfo, REMSmb_NetServerGetInfo_P,
+ TRUE, &XsNetServerSetInfo, REMSmb_NetServerSetInfo_P,
+ TRUE, &XsNetServerDiskEnum, REMSmb_NetServerDiskEnum_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 20
+ TRUE, &XsNetCharDevEnum, REMSmb_NetCharDevEnum_P,
+ TRUE, &XsNetCharDevGetInfo, REMSmb_NetCharDevGetInfo_P,
+ TRUE, &XsNetCharDevControl, REMSmb_NetCharDevControl_P,
+ TRUE, &XsNetCharDevQEnum, REMSmb_NetCharDevQEnum_P,
+ TRUE, &XsNetCharDevQGetInfo, REMSmb_NetCharDevQGetInfo_P,
+ TRUE, &XsNetCharDevQSetInfo, REMSmb_NetCharDevQSetInfo_P,
+ TRUE, &XsNetCharDevQPurge, REMSmb_NetCharDevQPurge_P,
+ TRUE, &XsNetCharDevQPurgeSelf, REMSmb_NetCharDevQPurgeSelf_P,
+ TRUE, &XsNetMessageNameEnum, REMSmb_NetMessageNameEnum_P,
+ TRUE, &XsNetMessageNameGetInfo, REMSmb_NetMessageNameGetInfo_P, // 30
+ TRUE, &XsNetMessageNameAdd, REMSmb_NetMessageNameAdd_P,
+ TRUE, &XsNetMessageNameDel, REMSmb_NetMessageNameDel_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetMessageBufferSend, REMSmb_NetMessageBufferSend_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetServiceEnum, REMSmb_NetServiceEnum_P,
+ TRUE, &XsNetServiceInstall, REMSmb_NetServiceInstall_P, // 40
+ TRUE, &XsNetServiceControl, REMSmb_NetServiceControl_P,
+ TRUE, &XsNetAccessEnum, REMSmb_NetAccessEnum_P,
+ TRUE, &XsNetAccessGetInfo, REMSmb_NetAccessGetInfo_P,
+ TRUE, &XsNetAccessSetInfo, REMSmb_NetAccessSetInfo_P,
+ TRUE, &XsNetAccessAdd, REMSmb_NetAccessAdd_P,
+ TRUE, &XsNetAccessDel, REMSmb_NetAccessDel_P,
+ TRUE, &XsNetGroupEnum, REMSmb_NetGroupEnum_P,
+ TRUE, &XsNetGroupAdd, REMSmb_NetGroupAdd_P,
+ TRUE, &XsNetGroupDel, REMSmb_NetGroupDel_P,
+ TRUE, &XsNetGroupAddUser, REMSmb_NetGroupAddUser_P, // 50
+ TRUE, &XsNetGroupDelUser, REMSmb_NetGroupDelUser_P,
+ TRUE, &XsNetGroupGetUsers, REMSmb_NetGroupGetUsers_P,
+ TRUE, &XsNetUserEnum, REMSmb_NetUserEnum_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUserDel, REMSmb_NetUserDel_P,
+ TRUE, &XsNetUserGetInfo, REMSmb_NetUserGetInfo_P,
+ TRUE, &XsNetUserSetInfo, REMSmb_NetUserSetInfo_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUserGetGroups, REMSmb_NetUserGetGroups_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 60
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetWkstaGetInfo, REMSmb_NetWkstaGetInfo_P,
+ TRUE, &XsNetWkstaSetInfo, REMSmb_NetWkstaSetInfo_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ FALSE, &XsNetPrintQEnum, REMSmb_DosPrintQEnum_P,
+ FALSE, &XsNetPrintQGetInfo, REMSmb_DosPrintQGetInfo_P, // 70
+ TRUE, &XsNetPrintQSetInfo, REMSmb_DosPrintQSetInfo_P,
+ TRUE, &XsNetPrintQAdd, REMSmb_DosPrintQAdd_P,
+ TRUE, &XsNetPrintQDel, REMSmb_DosPrintQDel_P,
+ TRUE, &XsNetPrintQPause, REMSmb_DosPrintQPause_P,
+ TRUE, &XsNetPrintQContinue, REMSmb_DosPrintQContinue_P,
+ FALSE, &XsNetPrintJobEnum, REMSmb_DosPrintJobEnum_P,
+ FALSE, &XsNetPrintJobGetInfo, REMSmb_DosPrintJobGetInfo_P,
+ TRUE, &XsNetPrintJobSetInfo, REMSmb_DosPrintJobSetInfo_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 80
+ TRUE, &XsNetPrintJobDel, REMSmb_DosPrintJobDel_P,
+ TRUE, &XsNetPrintJobPause, REMSmb_DosPrintJobPause_P,
+ TRUE, &XsNetPrintJobContinue, REMSmb_DosPrintJobContinue_P,
+ TRUE, &XsNetPrintDestEnum, REMSmb_DosPrintDestEnum_P,
+ TRUE, &XsNetPrintDestGetInfo, REMSmb_DosPrintDestGetInfo_P,
+ TRUE, &XsNetPrintDestControl, REMSmb_DosPrintDestControl_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 90
+ TRUE, &XsNetRemoteTOD, REMSmb_NetRemoteTOD_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetServiceGetInfo, REMSmb_NetServiceGetInfo_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 100
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetPrintQPurge, REMSmb_DosPrintQPurge_P,
+ FALSE, &XsNetServerEnum2, REMSmb_NetServerEnum2_P,
+ TRUE, &XsNetAccessGetUserPerms, REMSmb_NetAccessGetUserPerms_P,
+ TRUE, &XsNetGroupGetInfo, REMSmb_NetGroupGetInfo_P,
+ TRUE, &XsNetGroupSetInfo, REMSmb_NetGroupSetInfo_P,
+ TRUE, &XsNetGroupSetUsers, REMSmb_NetGroupSetUsers_P,
+ TRUE, &XsNetUserSetGroups, REMSmb_NetUserSetGroups_P,
+ TRUE, &XsNetUserModalsGet, REMSmb_NetUserModalsGet_P, // 110
+ TRUE, &XsNetUserModalsSet, REMSmb_NetUserModalsSet_P,
+ TRUE, &XsNetFileEnum2, REMSmb_NetFileEnum2_P,
+ TRUE, &XsNetUserAdd2, REMSmb_NetUserAdd2_P,
+ TRUE, &XsNetUserSetInfo2, REMSmb_NetUserSetInfo2_P,
+ TRUE, &XsNetUserPasswordSet2, REMSmb_NetUserPasswordSet2_P,
+ FALSE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetGetDCName, REMSmb_NetGetDCName_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 120
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetStatisticsGet2, REMSmb_NetStatisticsGet2_P,
+ TRUE, &XsNetBuildGetInfo, REMSmb_NetBuildGetInfo_P,
+ TRUE, &XsNetFileGetInfo2, REMSmb_NetFileGetInfo2_P,
+ TRUE, &XsNetFileClose2, REMSmb_NetFileClose2_P,
+ FALSE, &XsNetServerReqChallenge, REMSmb_NetServerReqChalleng_P,
+ FALSE, &XsNetServerAuthenticate, REMSmb_NetServerAuthenticat_P,
+ FALSE, &XsNetServerPasswordSet, REMSmb_NetServerPasswordSet_P,
+ FALSE, &XsNetAccountDeltas, REMSmb_NetAccountDeltas_P,
+ FALSE, &XsNetAccountSync, REMSmb_NetAccountSync_P, // 130
+ TRUE, &XsNetUserEnum2, REMSmb_NetUserEnum2_P,
+ TRUE, &XsNetWkstaUserLogon, REMSmb_NetWkstaUserLogon_P,
+ TRUE, &XsNetWkstaUserLogoff, REMSmb_NetWkstaUserLogoff_P,
+ TRUE, &XsNetLogonEnum, REMSmb_NetLogonEnum_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsI_NetPathType, REMSmb_I_NetPathType_P,
+ TRUE, &XsI_NetPathCanonicalize, REMSmb_I_NetPathCanonicalize_P,
+ TRUE, &XsI_NetPathCompare, REMSmb_I_NetPathCompare_P,
+ TRUE, &XsI_NetNameValidate, REMSmb_I_NetNameValidate_P,
+ TRUE, &XsI_NetNameCanonicalize, REMSmb_I_NetNameCanonicalize_P, //140
+ TRUE, &XsI_NetNameCompare, REMSmb_I_NetNameCompare_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetPrintDestAdd, REMSmb_DosPrintDestAdd_P,
+ TRUE, &XsNetPrintDestSetInfo, REMSmb_DosPrintDestSetInfo_P,
+ TRUE, &XsNetPrintDestDel, REMSmb_DosPrintDestDel_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetPrintJobSetInfo, REMSmb_DosPrintJobSetInfo_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 150
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 160
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 170
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 180
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 190
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 200
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P, // 210
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsNetUnsupportedApi, REMSmb_NetUnsupportedApi_P,
+ TRUE, &XsSamOEMChangePasswordUser2_P, REM32_SamOEMChgPasswordUser2_P,
+ FALSE, &XsNetServerEnum3, REMSmb_NetServerEnum3_P
+};
+
diff --git a/private/net/svcdlls/srvsvc/server/xsdata.h b/private/net/svcdlls/srvsvc/server/xsdata.h
new file mode 100644
index 000000000..873fa22bf
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/xsdata.h
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xsdata.h
+
+Abstract:
+
+ Header file for XACTSRV global data.
+
+Author:
+
+ David Treadwell (davidtr) 05-Jan-1991
+ Shanku Niyogi (w-shanku)
+
+Revision History:
+
+--*/
+
+#ifndef _XSDATA_
+#define _XSDATA_
+
+#include <nturtl.h>
+
+#include <winbase.h>
+
+#include <rap.h>
+#include <xstypes.h>
+#include <ntmsv1_0.h>
+
+//
+// Number of XACTSRV threads
+//
+extern LONG XsThreads;
+
+//
+// Event signalled when the last XACTSRV worker thread terminates.
+//
+
+extern HANDLE XsAllThreadsTerminatedEvent;
+
+//
+// Boolean indicating whether XACTSRV is active or terminating.
+//
+
+extern BOOL XsTerminating;
+
+//
+// Handle for the LPC port used for communication between the file server
+// and XACTSRV.
+//
+
+extern HANDLE XsConnectionPortHandle;
+extern HANDLE XsCommunicationPortHandle;
+
+//
+// Table of information necessary for dispatching API requests.
+// XsProcessApis uses the API number in the request transaction find
+// the appropriate entry.
+//
+
+#define XS_SIZE_OF_API_TABLE 216
+
+extern XS_API_TABLE_ENTRY XsApiTable[XS_SIZE_OF_API_TABLE];
+
+#endif // ndef _XSDATA_
+
diff --git a/private/net/svcdlls/srvsvc/server/xsinit.c b/private/net/svcdlls/srvsvc/server/xsinit.c
new file mode 100644
index 000000000..dcb495f50
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/xsinit.c
@@ -0,0 +1,536 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ xsinit.c
+
+Abstract:
+
+ This module contains the initialization and termination code for
+ the XACTSRV component of the server service.
+
+Author:
+
+ David Treadwell (davidtr) 05-Jan-1991
+ Shanku Niyogi (w-shanku)
+
+Revision History:
+
+ Chuck Lenzmeier (chuckl) 17-Jun-1992
+ Merged xactsrv.c into xsinit.c and moved from xssvc to
+ srvsvc\server
+
+--*/
+
+//
+// Includes.
+//
+
+#include "srvsvcp.h"
+#include "ssdata.h"
+#include "xsdata.h"
+
+#include <xsprocs.h> // from net\inc
+
+#include <xactsrv2.h> // from private\inc
+#include <srvfsctl.h>
+
+#include <xsconst.h> // from xactsrv
+#include <xsprocsp.h>
+
+#undef DEBUG
+#undef DEBUG_API_ERRORS
+#include <xsdebug.h>
+
+
+DWORD
+XsStartXactsrv (
+ VOID
+ )
+{
+ NTSTATUS status;
+ DWORD error;
+ DWORD i;
+ HANDLE threadHandle;
+ DWORD threadId;
+ HANDLE eventHandle;
+ HANDLE serverHandle;
+ ANSI_STRING ansiName;
+ UNICODE_STRING unicodeName;
+ IO_STATUS_BLOCK ioStatusBlock;
+ OBJECT_ATTRIBUTES objectAttributes;
+ PORT_MESSAGE connectionRequest;
+ REMOTE_PORT_VIEW clientView;
+ BOOL waitForEvent;
+
+ //
+ // Set up variables so that we'll know how to shut down in case of
+ // an error.
+ //
+
+ serverHandle = NULL;
+ eventHandle = NULL;
+ waitForEvent = FALSE;
+
+ //
+ // Create a event that will be set by the last thread to exit.
+ //
+
+ IF_DEBUG(INIT) {
+ SS_PRINT(( "XsStartXactsrv: Creating termination event.\n" ));
+ }
+ SS_ASSERT( XsAllThreadsTerminatedEvent == NULL );
+
+ status = NtCreateEvent(
+ &XsAllThreadsTerminatedEvent,
+ EVENT_ALL_ACCESS,
+ NULL,
+ NotificationEvent,
+ FALSE
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtCreateEvent failed: %X\n",
+ status ));
+ }
+
+ XsAllThreadsTerminatedEvent = NULL;
+ goto exit;
+ }
+
+ //
+ // Open the server device. Note that we need this handle because
+ // the handle used by the main server service is synchronous. We
+ // need to to do the XACTSRV_CONNECT FSCTL asynchronously.
+ //
+
+ RtlInitUnicodeString( &unicodeName, XS_SERVER_DEVICE_NAME_W );
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &unicodeName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ status = NtOpenFile(
+ &serverHandle,
+ FILE_READ_DATA, // DesiredAccess
+ &objectAttributes,
+ &ioStatusBlock,
+ 0L, // ShareAccess
+ 0L // OpenOptions
+ );
+
+ if ( NT_SUCCESS(status) ) {
+ status = ioStatusBlock.Status;
+ }
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtOpenFile (server device object) "
+ "failed: %X\n", status ));
+ }
+ goto exit;
+ }
+
+ //
+ // Create the LPC port.
+ //
+ // !!! Right now this only tries a single port name. If, for some
+ // bizarre reason, somebody already has a port by this name,
+ // then this will fail. It might make sense to try different
+ // names if this fails.
+ //
+ // !!! We might want to make the port name somewhat random for
+ // slightly enhanced security.
+
+ RtlInitUnicodeString( &unicodeName, XS_PORT_NAME_W );
+ RtlInitAnsiString( &ansiName, XS_PORT_NAME_A );
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &unicodeName,
+ 0,
+ NULL,
+ NULL
+ );
+
+ IF_DEBUG(LPC) {
+ SS_PRINT(( "XsInitialize: creating port %Z\n", &ansiName ));
+ }
+
+ SS_ASSERT( XsConnectionPortHandle == NULL );
+
+ status = NtCreatePort(
+ &XsConnectionPortHandle,
+ &objectAttributes,
+ 0,
+ XS_PORT_MAX_MESSAGE_LENGTH,
+ XS_PORT_MAX_MESSAGE_LENGTH * 32
+ );
+
+ if ( ! NT_SUCCESS(status) ) {
+
+ IF_DEBUG(ERRORS) {
+ if ( status == STATUS_OBJECT_NAME_COLLISION ) {
+ SS_PRINT(( "XsStartXactsrv: The XACTSRV port already "
+ "exists\n"));
+
+ } else {
+ SS_PRINT(( "XsStartXactsrv: Failed to create port %Z: %X\n",
+ &ansiName, status ));
+ }
+ }
+
+ XsConnectionPortHandle = NULL;
+ goto exit;
+ }
+
+ //
+ // Set up an event so that we'll know when IO completes, then send
+ // the FSCTL to the server indicating that it should now connect to
+ // us. We'll set up the port while the IO is outstanding, then wait
+ // on the event when the port setup is complete.
+ //
+
+ status = NtCreateEvent(
+ &eventHandle,
+ EVENT_ALL_ACCESS,
+ NULL, // ObjectAttributes
+ NotificationEvent,
+ FALSE
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtCreateEvent failed: %X\n",
+ status ));
+ }
+ goto exit;
+ }
+
+ IF_DEBUG(LPC) {
+ SS_PRINT(( "XsStartXactsrv: sending FSCTL_SRV_XACTSRV_CONNECT.\n" ));
+ }
+
+ status = NtFsControlFile(
+ serverHandle,
+ eventHandle,
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock,
+ FSCTL_SRV_XACTSRV_CONNECT,
+ ansiName.Buffer,
+ ansiName.Length,
+ NULL, // OutputBuffer
+ 0L // OutputBufferLength
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtFsControlFile failed: %X\n",
+ status ));
+ }
+ goto exit;
+ }
+
+ waitForEvent = TRUE;
+
+ //
+ // Start listening for the server's connection to the port. Note
+ // that it is OK if the server happens to call NtConnectPort
+ // first--it will simply block until this call to NtListenPort
+ // occurs.
+ //
+
+ IF_DEBUG(LPC) {
+ SS_PRINT(( "XsStartXactsrv: listening to port.\n" ));
+ }
+
+ connectionRequest.u1.s1.TotalLength = sizeof(connectionRequest);
+ connectionRequest.u1.s1.DataLength = (CSHORT)0;
+ status = NtListenPort(
+ XsConnectionPortHandle,
+ &connectionRequest
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtListenPort failed: %X\n", status ));
+ }
+ goto exit;
+ }
+
+ //
+ // The server has initiated the connection. Accept the connection.
+ //
+ // !!! We probably need some security check here.
+ //
+
+ clientView.Length = sizeof(clientView);
+ clientView.ViewSize = 0;
+ clientView.ViewBase = 0;
+
+ IF_DEBUG(LPC) {
+ SS_PRINT(( "XsStartXactsrv: Accepting connection to port.\n" ));
+ }
+
+ SS_ASSERT( XsCommunicationPortHandle == NULL );
+
+ status = NtAcceptConnectPort(
+ &XsCommunicationPortHandle,
+ NULL, // PortContext
+ &connectionRequest,
+ TRUE, // AcceptConnection
+ NULL, // ServerView
+ &clientView
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtAcceptConnectPort failed: %X\n",
+ status ));
+ }
+
+ XsCommunicationPortHandle = NULL;
+ goto exit;
+ }
+
+ IF_DEBUG(LPC) {
+ SS_PRINT(( "XsStartXactsrv: client view size: %ld, base: %lx\n",
+ clientView.ViewSize, clientView.ViewBase ));
+ }
+
+ //
+ // Complete the connection to the port, thereby releasing the server
+ // thread waiting in NtConnectPort.
+ //
+
+ IF_DEBUG(LPC) {
+ SS_PRINT(( "XsStartXactsrv: Completing connection to port.\n" ));
+ }
+
+ status = NtCompleteConnectPort( XsCommunicationPortHandle );
+
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtCompleteConnectPort failed: %X\n",
+ status ));
+ }
+ goto exit;
+ }
+
+ status = STATUS_SUCCESS;
+
+exit:
+
+ //
+ // Wait for the IO to complete, then close the event handle.
+ //
+
+ if ( waitForEvent ) {
+
+ NTSTATUS waitStatus;
+
+ SS_ASSERT( eventHandle != NULL );
+
+ waitStatus = NtWaitForSingleObject( eventHandle, FALSE, NULL );
+
+ if ( !NT_SUCCESS(waitStatus) ) {
+
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: NtWaitForSingleObject failed: "
+ "%X\n", waitStatus ));
+ }
+
+ //
+ // If another error has already occurred, don't report this
+ // one.
+ //
+
+ if ( NT_SUCCESS(status) ) {
+ status = waitStatus;
+ }
+ }
+
+ //
+ // Check the status in the IO status block. If it is bad, then
+ // there was some problem on the server side of the port setup.
+ //
+
+ if ( !NT_SUCCESS(ioStatusBlock.Status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsStartXactsrv: bad status in IO status block: "
+ "%X\n", ioStatusBlock.Status ));
+ }
+
+ //
+ // If another error has already occurred, don't report this
+ // one.
+ //
+
+ if ( NT_SUCCESS(status) ) {
+ status = ioStatusBlock.Status;
+ }
+
+ }
+
+ CloseHandle( eventHandle );
+
+ }
+
+ //
+ // Close the handle to the server.
+ //
+
+ if ( serverHandle != NULL ) {
+ CloseHandle( serverHandle );
+ }
+
+ //
+ // If the above failed, return to caller now.
+ //
+
+ if ( !NT_SUCCESS(status) ) {
+ return RtlNtStatusToDosError( status );
+ }
+
+ //
+ // Start one API processing thread. It will spawn others if needed
+ //
+
+ XsThreads = 1;
+
+ threadHandle = CreateThread(
+ NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)XsProcessApisWrapper,
+ (LPVOID)XsThreads,
+ 0,
+ &threadId
+ );
+
+ if ( threadHandle != 0 ) {
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "XsStartXactsrv: Created thread %ld for "
+ "processing APIs\n", XsThreads ));
+ }
+
+ CloseHandle( threadHandle );
+
+ } else {
+
+ //
+ // Thread creation failed. Return an error to the caller.
+ // It is the responsibility of the caller to call
+ // XsStopXactsrv to clean up.
+ //
+
+ XsThreads = 0;
+
+ error = GetLastError( );
+ return error;
+
+ }
+
+
+ //
+ // Initialization succeeded.
+ //
+
+ return NO_ERROR;
+
+} // XsStartXactsrv
+
+
+/*
+ * This routine is called to stop the transaction processor once the
+ * server driver has terminated.
+ */
+VOID
+XsStopXactsrv (
+ VOID
+ )
+{
+ NTSTATUS status;
+ static XACTSRV_REQUEST_MESSAGE requestMessage;
+ LONG i;
+
+ //
+ // Stop all the xs worker threads, and release resources
+ //
+
+ if ( XsConnectionPortHandle != NULL ) {
+
+ //
+ // Indicate that XACTSRV is terminating.
+ //
+ XsTerminating = TRUE;
+
+ IF_DEBUG(TERMINATION) {
+ SS_PRINT(("XsStopXactsrv: queueing termination messages\n"));
+ }
+
+ //
+ // Queue a message to kill off the worker thereads
+ //
+ RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
+ requestMessage.PortMessage.u1.s1.DataLength =
+ (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
+ requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
+ requestMessage.MessageType = XACTSRV_MESSAGE_WAKEUP;
+
+ status = NtRequestPort(
+ XsConnectionPortHandle,
+ (PPORT_MESSAGE)&requestMessage
+ );
+
+ IF_DEBUG(ERRORS) {
+ if ( !NT_SUCCESS(status) ) {
+ SS_PRINT(( "SrvXsDisconnect: NtRequestPort failed: %X\n",
+ status ));
+ }
+ }
+
+ //
+ // The above will cause all worker threads to wake up then die.
+ //
+
+ if ( XsThreads != 0 ) {
+ BOOL ok;
+ ok = WaitForSingleObject( XsAllThreadsTerminatedEvent, (DWORD)-1 );
+ IF_DEBUG(ERRORS) {
+ if ( !ok ) {
+ SS_PRINT(( "XsStopXactsrv: WaitForSingleObject failed: "
+ "%ld\n", GetLastError() ));
+ }
+ }
+ }
+
+ SS_ASSERT( XsThreads == 0 );
+
+ CloseHandle( XsConnectionPortHandle );
+ }
+
+ if( XsCommunicationPortHandle != NULL ) {
+ CloseHandle( XsCommunicationPortHandle );
+ XsCommunicationPortHandle = NULL;
+ }
+
+ //
+ // Close the termination event.
+ //
+
+ if ( XsAllThreadsTerminatedEvent != NULL ) {
+ CloseHandle( XsAllThreadsTerminatedEvent );
+ XsAllThreadsTerminatedEvent = NULL;
+ }
+
+ return;
+
+} // XsStopXactsrv
diff --git a/private/net/svcdlls/srvsvc/server/xsproc.c b/private/net/svcdlls/srvsvc/server/xsproc.c
new file mode 100644
index 000000000..d60a75d2a
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/server/xsproc.c
@@ -0,0 +1,1092 @@
+/*++
+
+Copyright (c) 1991-1992 Microsoft Corporation
+
+Module Name:
+
+ xsproc.c
+
+Abstract:
+
+ This module contains the main processing loop for XACTSRV.
+
+Author:
+
+ David Treadwell (davidtr) 05-Jan-1991
+ Shanku Niyogi (w-shanku)
+
+Revision History:
+
+ 02-Jun-1992 JohnRo
+ RAID 9829: Avoid SERVICE_ equate conflicts.
+
+ Chuck Lenzmeier (chuckl) 17-Jun-1992
+ Moved from xssvc to srvsvc\server
+
+--*/
+
+//
+// Includes.
+//
+
+#include "srvsvcp.h"
+#include "xsdata.h"
+#include "ssdata.h"
+
+#include <netevent.h>
+
+#include <windows.h> // from sdk\inc
+#include <winspool.h>
+
+#include <xsprocs.h> // from net\inc
+#include <apinums.h> // from net\inc
+#include <netlib.h> // from net\inc (NetpGetComputerName)
+
+#include <xactsrv2.h> // from private\inc
+#include <smbgtpt.h>
+
+#include <xsconst.h> // from xactsrv
+#include <xsprocsp.h>
+
+#include <lmsname.h> // from \sdk\inc
+#include <lmerr.h> // from \sdk\inc
+#include <lmapibuf.h> // from \sdk\inc (NetApiBufferFree)
+#include <lmmsg.h> // from \sdk\inc (NetMessageBufferSend)
+#include <winsvc.h> // from \sdk\inc
+
+#include <ntlsapi.h> // from \sdk\inc (License Server APIs)
+
+#if DBG
+#include <stdio.h>
+#include <lmbrowsr.h>
+#endif
+
+#undef DEBUG
+#undef DEBUG_API_ERRORS
+#include <xsdebug.h>
+
+VOID
+ConvertApiStatusToDosStatus(
+ LPXS_PARAMETER_HEADER header
+ );
+
+VOID
+XsProcessApis (
+ DWORD ThreadNum
+ );
+
+//
+// This is the number of Xs threads blocked waiting for an LPC request.
+// When it drops to zero, all threads are active and another thread is
+// created.
+//
+LONG XsWaitingApiThreads = 0;
+
+
+VOID
+XsProcessApisWrapper (
+ DWORD ThreadNum
+ )
+
+/*++
+
+Routine Description:
+
+ This routine provides multithreaded capability for main processing
+ routine, XsProcessApis.
+
+Arguments:
+
+ ThreadNum - thread number for debugging purposes.
+
+
+--*/
+
+{
+ XACTSRV_REQUEST_MESSAGE requestMessage;
+
+ //
+ // Increase the priority of this thread to just above foreground (the
+ // same as the rest of the server).
+ //
+
+ SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
+
+ //
+ // Do the APIs
+ //
+ XsProcessApis( ThreadNum );
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "Thread %ld exiting, active count %ld\n", ThreadNum,
+ XsThreads ));
+ }
+
+ //
+ // Decrement the count of threads. If the count goes to
+ // zero, set the All Threads Terminated event.
+ //
+
+ if( InterlockedDecrement( &XsThreads ) == 0 ) {
+
+ SetEvent( XsAllThreadsTerminatedEvent );
+
+ } else if( XsTerminating ) {
+
+ //
+ // There are still threads left, and we are trying to terminate. Queue
+ // another message to the queue so the next thread will get it and
+ // notice that we're trying to quit.
+ //
+ RtlZeroMemory( &requestMessage, sizeof( requestMessage ));
+ requestMessage.PortMessage.u1.s1.DataLength =
+ (USHORT)( sizeof(requestMessage) - sizeof(PORT_MESSAGE) );
+ requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
+ requestMessage.MessageType = XACTSRV_MESSAGE_WAKEUP;
+
+ NtRequestPort(
+ XsConnectionPortHandle,
+ (PPORT_MESSAGE)&requestMessage
+ );
+ }
+
+
+ ExitThread( NO_ERROR );
+
+} // XsProcessApisWrapper
+
+
+VOID
+XsProcessApis (
+ DWORD ThreadNum
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits for messages to come through the LPC port to
+ the server. When one does, it calls the appropriate routine to
+ handle the API, then replies to the server indicating that the
+ API has completed.
+
+Arguments:
+
+ ThreadNum - thread number for debugging purposes.
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or reason for failure.
+
+--*/
+
+{
+ NTSTATUS status;
+ NET_API_STATUS error;
+ XACTSRV_REQUEST_MESSAGE request;
+ XACTSRV_REPLY_MESSAGE reply;
+ BOOL sendReply = FALSE;
+ LPTRANSACTION transaction;
+ WORD apiNumber;
+ LPXS_PARAMETER_HEADER header;
+ LPVOID parameters;
+ LPDESC structureDesc;
+ LPDESC auxStructureDesc;
+ LPDESC paramStructureDesc;
+ DWORD newThreadCount;
+#if 0
+ LARGE_INTEGER XactSrvStartTime;
+ LARGE_INTEGER XactSrvEndTime;
+ LARGE_INTEGER PerformanceFrequency;
+#endif
+
+ //
+ // Loop dispatching API requests.
+ //
+ while ( XsTerminating == FALSE ) {
+
+ //
+ // We're waiting to handle another API...
+ //
+ InterlockedIncrement( &XsWaitingApiThreads );
+
+ //
+ // Send the reply to the last message and wait for the next
+ // message. The first time through the loop, there will be
+ // no last message -- reply will be NULL.
+ //
+
+ status = NtReplyWaitReceivePort(
+ XsCommunicationPortHandle,
+ NULL, // PortContext
+ sendReply ? (PPORT_MESSAGE)&reply : NULL,
+ (PPORT_MESSAGE)&request
+ );
+
+ sendReply = TRUE;
+
+ //
+ // Set up the response message to be sent on the next call to
+ // NtReplyWaitReceivePort.
+ //
+ reply.PortMessage.u1.s1.DataLength =
+ sizeof(reply) - sizeof(PORT_MESSAGE);
+ reply.PortMessage.u1.s1.TotalLength = sizeof(reply);
+ reply.PortMessage.u2.ZeroInit = 0;
+ reply.PortMessage.ClientId = request.PortMessage.ClientId;
+ reply.PortMessage.MessageId = request.PortMessage.MessageId;
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "XsProcessApis: Thread %d: NtReplyWaitReceivePort %X, msg %X\n",
+ ThreadNum, status, &request ));
+ }
+
+ if ( status == STATUS_INVALID_PORT_HANDLE
+ || status == STATUS_PORT_DISCONNECTED
+ || status == STATUS_INVALID_HANDLE
+ || XsTerminating
+ || request.PortMessage.u2.s2.Type == LPC_PORT_CLOSED ) {
+
+ //
+ // The port is no longer valid, or XACTSRV is terminating.
+ //
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "XsProcessApis: %s. Thread %ld quitting\n",
+ XsTerminating ?
+ "XACTSRV terminating" : "Port invalid",
+ ThreadNum ));
+ }
+
+ InterlockedDecrement( &XsWaitingApiThreads );
+ return;
+
+ } else if ( !NT_SUCCESS(status) ) {
+
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsProcessApis: NtReplyWaitReceivePort "
+ "failed: %X\n", status ));
+ }
+ InterlockedDecrement( &XsWaitingApiThreads );
+ return;
+
+ }
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "XsProcessApis: Thread %ld responding to request, "
+ " MessageType %d, XsTerminating %d",
+ ThreadNum, request.MessageType, XsTerminating ));
+ }
+
+ if( InterlockedDecrement( &XsWaitingApiThreads ) == 0 ) {
+
+ HANDLE threadHandle;
+ DWORD threadId;
+
+ //
+ // Are there other threads ready to handle new requests? If not, then
+ // we should spawn a new thread. Since the server synchronously sends
+ // requests to xactsrv, we will never end up with more than
+ // the maximum number of server worker threads + 1.
+ //
+
+ InterlockedIncrement( &XsThreads );
+
+ threadHandle = CreateThread(
+ NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)XsProcessApisWrapper,
+ (LPVOID)XsThreads,
+ 0,
+ &threadId
+ );
+
+ if ( threadHandle != 0 ) {
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "XsStartXactsrv: Created thread %ld for "
+ "processing APIs\n", XsThreads ));
+ }
+
+ CloseHandle( threadHandle );
+
+ } else {
+
+ IF_DEBUG(THREADS) {
+ SS_PRINT(( "XsStartXactsrv: Unable to create thread %ld for "
+ "processing APIs\n", XsThreads ));
+ }
+
+ InterlockedDecrement( &XsThreads );
+ }
+ }
+
+ switch ( request.MessageType ) {
+
+ case XACTSRV_MESSAGE_SERVER_THREAD_EXIT:
+ //
+ // If we aren't the last thread, we can go away too.
+ //
+ if( XsThreads != 1 ) {
+ //
+ // But first we need to send a response
+ //
+ NtReplyPort(
+ XsCommunicationPortHandle,
+ (PPORT_MESSAGE)&reply );
+
+ return;
+ }
+
+ //
+ // We are the last thread. We must not go away.
+ //
+ break;
+
+ case XACTSRV_MESSAGE_DOWN_LEVEL_API:
+
+ //
+ // Get a pointer to the transaction block from the message.
+ // It is the file server's responsibility to set up this
+ // pointer correctly, and since he is a trusted entity, we
+ // do no checking on the pointer value.
+ //
+
+ transaction = request.Message.DownLevelApi.Transaction;
+ ASSERT( transaction != NULL );
+
+#if 0
+ NtQueryPerformanceCounter(&XactSrvStartTime, &PerformanceFrequency);
+
+ //
+ // Convert frequency from ticks/second to ticks/millisecond
+ //
+
+ PerformanceFrequency = LiXDiv(PerformanceFrequency, 1000);
+
+ if (LiGeq(XactSrvStartTime, transaction->XactSrvTime)) {
+ CHAR Buffer[200];
+ LARGE_INTEGER LpcTime = LiSub(XactSrvStartTime, transaction->XactSrvTime);
+
+ LpcTime = LiDiv(LpcTime, PerformanceFrequency);
+
+ sprintf(Buffer, "XactSrv: LPC Time: %ld milliseconds (%ld)\n", LpcTime.LowPart, LpcTime.HighPart);
+
+ I_BrowserDebugTrace(NULL, Buffer);
+ }
+#endif
+ //
+ // The API number is the first word in the parameters
+ // section, and it is followed by the parameter descriptor
+ // string. After that comes the data descriptor.
+ //
+
+ apiNumber = SmbGetUshort( (LPWORD)transaction->InParameters );
+ paramStructureDesc = (LPDESC)( transaction->InParameters + 2 );
+ structureDesc = paramStructureDesc
+ + strlen( paramStructureDesc ) + 1;
+
+ //
+ // Make sure the API number is in range.
+ //
+
+ if ( apiNumber >=
+ (sizeof(XsApiTable) / sizeof(XS_API_TABLE_ENTRY)) ) {
+ reply.Message.DownLevelApi.Status =
+ STATUS_INVALID_SYSTEM_SERVICE;
+ break;
+ }
+
+ //
+ // Check if the parameter descriptor is valid. If not,
+ // there is obviously something very wrong about this
+ // request.
+ //
+
+ if ( XsApiTable[apiNumber].Params != NULL &&
+ !XsCheckSmbDescriptor( paramStructureDesc,
+ XsApiTable[apiNumber].Params )) {
+ reply.Message.DownLevelApi.Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Capture the input parameters into a buffer. The API
+ // handler will treat this data as passed-in parameters.
+ //
+
+ header = XsCaptureParameters( transaction, &auxStructureDesc );
+
+ if ( header == NULL ) {
+ reply.Message.DownLevelApi.Status = STATUS_NO_MEMORY;
+ break;
+ }
+
+ //
+ // Initialize header to default values.
+ //
+
+ header->Converter = 0;
+ header->Status = NO_ERROR;
+ header->ClientMachineName =
+ request.Message.DownLevelApi.ClientMachineName;
+
+ header->ClientTransportName = request.Message.DownLevelApi.TransportName;
+
+ header->EncryptionKey = request.Message.DownLevelApi.LanmanSessionKey;
+
+ header->Flags = request.Message.DownLevelApi.Flags;
+
+ header->ServerName = request.Message.DownLevelApi.ServerName;
+
+ parameters = header + 1;
+
+ IF_DEBUG(LPC) {
+
+ SS_PRINT(( "XsProcessApis: received message from %ws at %lx, "
+ "transaction %lx, API %ld on transport %ws\n",
+ header->ClientMachineName, &request,
+ transaction, apiNumber,
+ header->ClientTransportName ));
+ }
+
+ IF_DEBUG(DESC_STRINGS) {
+
+ SS_PRINT(( "XsProcessApis: API %ld, parameters %s, data %s\n",
+ apiNumber, paramStructureDesc, structureDesc ));
+ }
+
+ //
+ // Impersonate the client before calling the API.
+ //
+
+ if ( XsApiTable[apiNumber].ImpersonateClient ) {
+
+ //
+ // BUGBUG: Fail here if request came over a null session!
+ // Otherwise, forging API requests over null sessions
+ // would be a great way for unprivileged clients
+ // to execute privileged APIs.
+ //
+
+ status = NtImpersonateClientOfPort(
+ XsCommunicationPortHandle,
+ (PPORT_MESSAGE)&request
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsProcessApis: NtImpersonateClientOfPort "
+ "failed: %X\n", status ));
+ }
+
+ reply.Message.DownLevelApi.Status = ERROR_ACCESS_DENIED;
+ break;
+ }
+ }
+
+ //
+ // Call the API processing routine to perform the actual API call.
+ // The called routine should set up parameters, make the actual API
+ // call, and return the status to us.
+ //
+
+ reply.Message.DownLevelApi.Status =
+ XsApiTable[apiNumber].Handler(
+ header,
+ parameters,
+ structureDesc,
+ auxStructureDesc
+ );
+
+ //
+ // Discontinue client impersonation.
+ //
+
+ if ( XsApiTable[apiNumber].ImpersonateClient ) {
+
+ PVOID dummy = NULL;
+
+ status = NtSetInformationThread(
+ NtCurrentThread( ),
+ ThreadImpersonationToken,
+ &dummy, // discontinue impersonation
+ sizeof(PVOID)
+ );
+
+ if ( !NT_SUCCESS(status)) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsProcessApis: NtSetInformationThread "
+ "(revert) failed: %X\n", status ));
+ }
+ // *** Ignore the error.
+ }
+ }
+
+ //
+ // Make sure we return the right error codes
+ //
+
+ if ( header->Status != NERR_Success ) {
+ ConvertApiStatusToDosStatus( header );
+ }
+
+ //
+ // Put the parameters in the transaction and free the parameter
+ // buffer.
+ //
+
+ XsSetParameters( transaction, header, parameters );
+
+ break;
+
+ case XACTSRV_MESSAGE_OPEN_PRINTER: {
+
+ UNICODE_STRING printerName;
+
+ RtlInitUnicodeString(
+ &printerName,
+ (PWCH)request.Message.OpenPrinter.PrinterName
+ );
+
+ if (!OpenPrinter( printerName.Buffer,
+ &reply.Message.OpenPrinter.hPrinter, NULL)) {
+
+ reply.Message.OpenPrinter.Error = GetLastError();
+ SS_PRINT(( "XsProcessApis: OpenPrinter failed: %ld\n",
+ reply.Message.OpenPrinter.Error ));
+ break;
+ }
+
+
+ reply.Message.OpenPrinter.Error = NO_ERROR;
+ break;
+ }
+
+ case XACTSRV_MESSAGE_ADD_JOB_PRINTER:
+ {
+ LPADDJOB_INFO_1 addJob;
+ PRINTER_DEFAULTS prtDefault;
+ DWORD bufferLength;
+ UNICODE_STRING dosName;
+ UNICODE_STRING ntName;
+ BOOL ok;
+ PVOID dummy = NULL;
+
+ //
+ // Allocate space for the add job structure. This buffer
+ // will get the JobId and the spool file path name.
+ //
+
+ bufferLength = sizeof(ADDJOB_INFO_1) +
+ (MAXIMUM_FILENAME_LENGTH * sizeof(TCHAR));
+
+ addJob = (LPADDJOB_INFO_1) LocalAlloc( LPTR, bufferLength );
+ if ( addJob == NULL ) {
+ reply.Message.AddPrintJob.Error = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ }
+
+ //
+ // Impersonate the client before calling the API.
+ //
+
+ status = NtImpersonateClientOfPort(
+ XsCommunicationPortHandle,
+ (PPORT_MESSAGE)&request
+ );
+
+ if ( !NT_SUCCESS(status) ) {
+
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsProcessApis: NtImpersonateClientOfPort "
+ "failed: %X\n", status ));
+ }
+
+ LocalFree( addJob );
+ reply.Message.DownLevelApi.Status = ERROR_ACCESS_DENIED;
+ break;
+ }
+
+ //
+ // call ResetJob so that we will pick up the new printer defaults
+ //
+
+ prtDefault.pDatatype = (LPWSTR)-1;
+ prtDefault.pDevMode = (LPDEVMODEW)-1;
+ prtDefault.DesiredAccess = 0;
+
+ ok = ResetPrinter(
+ request.Message.AddPrintJob.hPrinter,
+ &prtDefault
+ );
+
+ if ( !ok ) {
+
+ //
+ // *** Ignore the error. AddJob will use the old defaults
+ // in this case.
+ //
+
+ IF_DEBUG(ERRORS) {
+ DWORD error;
+ error = GetLastError( );
+ SS_PRINT(( "XsProcessApis: ResetPrinter "
+ "failed: %ld\n", error ));
+ }
+ }
+
+ //
+ // Call AddJob to set up the print job and get a job ID
+ // and spool file name.
+ //
+
+ ok = AddJob(
+ request.Message.AddPrintJob.hPrinter,
+ 1,
+ (LPBYTE)addJob,
+ bufferLength,
+ &bufferLength
+ );
+
+ if ( !ok ) {
+ reply.Message.AddPrintJob.Error = GetLastError( );
+ }
+
+ //
+ // Discontinue client impersonation.
+ //
+
+ status = NtSetInformationThread(
+ NtCurrentThread( ),
+ ThreadImpersonationToken,
+ &dummy, // discontinue impersonation
+ sizeof(PVOID)
+ );
+
+ if ( !NT_SUCCESS(status)) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsProcessApis: NtSetInformationThread "
+ "(revert) failed: %X\n", status ));
+ }
+ // *** Ignore the error.
+ }
+
+ if ( !ok ) {
+ SS_PRINT(( "XsProcessApis: AddJob failed, %ld\n",
+ reply.Message.AddPrintJob.Error ));
+ LocalFree( addJob );
+ break;
+ }
+
+ //
+ // Set up the information in the return buffer.
+ //
+
+ reply.Message.AddPrintJob.JobId = addJob->JobId;
+
+ RtlInitUnicodeString( &dosName, addJob->Path );
+
+ status = RtlDosPathNameToNtPathName_U(
+ dosName.Buffer,
+ &ntName,
+ NULL,
+ NULL
+ );
+ if ( !NT_SUCCESS(status) ) {
+ IF_DEBUG(ERRORS) {
+ SS_PRINT(( "XsProcessApis: Dos-to-NT path failed: %X\n",
+ status ));
+ }
+ ntName.Buffer = NULL;
+ ntName.Length = 0;
+ }
+
+ //
+ // Set up return data.
+ //
+
+ reply.Message.AddPrintJob.BufferLength = ntName.Length;
+ reply.Message.AddPrintJob.Error = NO_ERROR;
+ RtlCopyMemory(
+ request.Message.AddPrintJob.Buffer,
+ ntName.Buffer,
+ ntName.Length
+ );
+
+ //
+ // Free allocated resources.
+ //
+
+ LocalFree( addJob );
+ if ( ntName.Buffer != NULL ) {
+ RtlFreeHeap( RtlProcessHeap( ), 0, ntName.Buffer );
+ }
+
+ break;
+ }
+
+ case XACTSRV_MESSAGE_SCHD_JOB_PRINTER:
+
+ //
+ // Call ScheduleJob( ) to indicate that we're done writing to
+ // the spool file.
+ //
+
+ if ( !ScheduleJob(
+ request.Message.SchedulePrintJob.hPrinter,
+ request.Message.SchedulePrintJob.JobId ) ) {
+
+ reply.Message.SchedulePrintJob.Error = GetLastError( );
+ SS_PRINT(( "XsProcessApis: ScheduleJob failed, %ld\n",
+ reply.Message.SchedulePrintJob.Error ));
+ break;
+ }
+
+ reply.Message.SchedulePrintJob.Error = NO_ERROR;
+ break;
+
+ case XACTSRV_MESSAGE_CLOSE_PRINTER:
+
+ if ( !ClosePrinter( request.Message.ClosePrinter.hPrinter ) ) {
+ reply.Message.ClosePrinter.Error = GetLastError( );
+ SS_PRINT(( "XsProcessApis: ClosePrinter failed: %ld\n",
+ reply.Message.ClosePrinter.Error ));
+ break;
+ }
+
+ reply.Message.ClosePrinter.Error = NO_ERROR;
+ break;
+
+ case XACTSRV_MESSAGE_MESSAGE_SEND:
+ {
+ LPTSTR sender;
+
+ error = NetpGetComputerName( &sender );
+
+ if ( error != NO_ERROR ) {
+ SS_PRINT(( "XsProcessApis: NetpGetComputerName failed: %ld\n",
+ error ));
+ reply.Message.MessageBufferSend.Error = error;
+ break;
+ }
+
+ error = NetMessageBufferSend(
+ NULL,
+
+ //
+ // BUGBUG - the following LPTSTR typecast is WRONG -
+ // it must be fixed in ntos\srv\scavengr.c which
+ // should pass in a LPWSTR if built for unicode or
+ // convert the UNICODE_STRING to an OEM_STRING and
+ // pass a pointer to the buffer field, as it does
+ // now
+ //
+
+ //FIXFIX
+ (LPTSTR)request.Message.MessageBufferSend.Receipient,
+ //request.Message.MessageBufferSend.Receipient,
+ //ENDFIX
+ sender,
+ request.Message.MessageBufferSend.Buffer,
+ request.Message.MessageBufferSend.BufferLength
+ );
+
+ if ( error != NO_ERROR ) {
+ SS_PRINT(( "XsProcessApis: NetMessageBufferSend failed: %ld\n",
+ error ));
+ }
+
+ (void) NetApiBufferFree( sender );
+
+ reply.Message.MessageBufferSend.Error = error;
+ break;
+ }
+
+ case XACTSRV_MESSAGE_LSREQUEST:
+ SS_PRINT(( "LSREQUEST User: %ws\n", request.Message.LSRequest.UserName ));
+ {
+ NT_LS_DATA NtLSData;
+
+ NtLSData.DataType = NT_LS_USER_NAME;
+ NtLSData.Data = request.Message.LSRequest.UserName;
+ NtLSData.IsAdmin = request.Message.LSRequest.IsAdmin;
+
+ reply.Message.LSRequest.Status = NtLicenseRequest (
+ SsData.ServerProductName,
+ SsData.szVersionNumber,
+ (LS_HANDLE *)&reply.Message.LSRequest.hLicense,
+ &NtLSData
+ );
+
+ if( !NT_SUCCESS( reply.Message.LSRequest.Status ) ) {
+ //
+ // We need to return the 'same old' error code that clients are used to
+ // getting for when the server is full
+ //
+ SS_PRINT(("LSREQUEST returns status %X, mapping to %X\n",
+ reply.Message.LSRequest.Status, STATUS_REQUEST_NOT_ACCEPTED ));
+ reply.Message.LSRequest.Status = STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ break;
+ }
+
+ case XACTSRV_MESSAGE_LSRELEASE:
+
+ SS_PRINT(( "LSRELEASE Handle: %X\n", request.Message.LSRelease.hLicense ));
+ NtLSFreeHandle( (LS_HANDLE)request.Message.LSRelease.hLicense );
+ break;
+
+#ifdef SRV_PNP_POWER
+
+ case XACTSRV_MESSAGE_PNP:
+ {
+
+ UNICODE_STRING transportName;
+ ULONG numberOfBindings = 0;
+ PVOID dummy = NULL;
+
+ transportName.MaximumLength =
+ transportName.Length = request.Message.Pnp.TransportName.Length;
+
+ transportName.Buffer = MIDL_user_allocate( transportName.Length );
+
+ if( transportName.Buffer == NULL ) {
+ break;
+ }
+
+ RtlCopyMemory( transportName.Buffer,
+ request.Message.Pnp.TransportName.Buffer,
+ transportName.Length
+ );
+
+ status = NtImpersonateClientOfPort(
+ XsCommunicationPortHandle,
+ (PPORT_MESSAGE)&request
+ );
+
+ //
+ // Now process the PNP command
+ //
+ if( request.Message.Pnp.Bind == TRUE ) {
+
+ //
+ // Bind to the transport. First bind the primary server name, then bind all
+ // of the secondary names. These calls will log errors as necessary.
+ //
+ BindToTransport(
+ NULL, // ValueName
+ REG_SZ, // ValueType
+ transportName.Buffer, // ValueData (transport name)
+ transportName.Length, // ValueLength
+ &numberOfBindings, // Context
+ NULL // EntryContext
+ );
+
+ BindOptionalNames(
+ NULL, // ValueName
+ REG_SZ, // ValueType
+ transportName.Buffer, // ValueData (transport name)
+ transportName.Length, // ValueLength
+ &numberOfBindings, // Context
+ NULL // EntryContext
+ );
+
+ } else {
+ //
+ // Unbind from the transport
+ //
+ DbgPrint( "SRVSVC: PNP unbind from %wZ\n", &transportName );
+ }
+
+ //
+ // Discontinue client impersonation.
+ //
+ status = NtSetInformationThread(
+ NtCurrentThread( ),
+ ThreadImpersonationToken,
+ &dummy, // discontinue impersonation
+ sizeof(PVOID)
+ );
+
+ MIDL_user_free( transportName.Buffer );
+
+ break;
+ }
+#endif
+
+ default:
+
+ SS_ASSERT( FALSE );
+
+ }
+
+#if 0
+
+ if ( request.MessageType == XACTSRV_MESSAGE_DOWN_LEVEL_API ) {
+ NtQueryPerformanceCounter(&XactSrvEndTime, NULL);
+
+ if (LiGeq(XactSrvEndTime, XactSrvStartTime)) {
+ CHAR Buffer[200];
+ LARGE_INTEGER XsTime = LiSub(XactSrvEndTime, XactSrvStartTime);
+
+ XsTime = LiDiv(XsTime, PerformanceFrequency);
+
+ sprintf(Buffer, "XactSrv: Xactsrv Time: %ld milliseconds (%ld)\n", XsTime.LowPart/10000, XsTime.HighPart);
+
+ I_BrowserDebugTrace(NULL, Buffer);
+ }
+
+ transaction->XactSrvTime = XactSrvEndTime;
+ }
+
+#endif
+ }
+
+} // XsProcessApis
+
+
+
+VOID
+ConvertApiStatusToDosStatus(
+ LPXS_PARAMETER_HEADER Header
+ )
+/*++
+
+Routine Description:
+
+ This routine converts an api return status to status expected by
+ downlevel.
+
+Arguments:
+
+ Header - structure containing the status.
+
+Return Value:
+
+--*/
+{
+ WORD dosStatus;
+
+ switch ( Header->Status ) {
+ case ERROR_SPECIAL_ACCOUNT:
+ case ERROR_SPECIAL_GROUP:
+ case ERROR_SPECIAL_USER:
+ case ERROR_INVALID_LOGON_TYPE:
+ dosStatus = ERROR_INVALID_PARAMETER;
+ break;
+
+ case ERROR_DEPENDENT_SERVICES_RUNNING:
+ dosStatus = NERR_ServiceCtlNotValid;
+ break;
+
+ case ERROR_INVALID_DOMAINNAME:
+ dosStatus = NERR_NotLocalDomain;
+ break;
+
+ case ERROR_NO_SUCH_USER:
+ dosStatus = NERR_UserNotFound;
+ break;
+
+ case ERROR_ALIAS_EXISTS:
+ dosStatus = NERR_GroupExists;
+ break;
+
+ case NERR_BadServiceName:
+ dosStatus = NERR_ServiceNotInstalled;
+ break;
+
+ case ERROR_ILL_FORMED_PASSWORD:
+ case NERR_PasswordTooRecent:
+ dosStatus = ERROR_INVALID_PASSWORD;
+ break;
+
+ case ERROR_PASSWORD_RESTRICTION:
+ dosStatus = NERR_PasswordHistConflict;
+ break;
+
+ case ERROR_ACCOUNT_RESTRICTION:
+ dosStatus = NERR_PasswordTooRecent;
+ break;
+
+ case ERROR_PASSWORD_EXPIRED:
+ case ERROR_PASSWORD_MUST_CHANGE:
+ dosStatus = NERR_PasswordExpired;
+ break;
+
+ case ERROR_INVALID_PRINTER_NAME:
+ dosStatus = NERR_QNotFound;
+ break;
+
+ case ERROR_NO_BROWSER_SERVERS_FOUND:
+
+ //
+ // Down level clients don't understand how to deal with
+ // the "No browser server" error, so we turn it into success.
+ //
+ // This seems wrong to me, but it is what WfW does in the
+ // same circumstance.
+ //
+
+ if ( !(Header->Flags & XS_FLAGS_NT_CLIENT) ) {
+ dosStatus = NERR_Success;
+ } else {
+ dosStatus = Header->Status;
+ }
+ break;
+
+ default:
+
+ //
+ // make sure it's a valid lm error code
+ //
+
+ if ( (Header->Status > ERROR_VC_DISCONNECTED) &&
+ ((Header->Status < NERR_BASE) ||
+ (Header->Status > MAX_NERR)) ) {
+
+ NTSTATUS status;
+ LPWSTR substring[1];
+ WCHAR errorString[10];
+ UNICODE_STRING unicodeString;
+
+ substring[0] = errorString;
+ unicodeString.MaximumLength = 10 * sizeof(WCHAR);
+ unicodeString.Buffer = errorString;
+
+ status = RtlIntegerToUnicodeString(
+ (ULONG) Header->Status,
+ 10,
+ &unicodeString
+ );
+
+ if ( NT_SUCCESS( status ) ) {
+ SsLogEvent(
+ EVENT_SRV_CANT_MAP_ERROR,
+ 1,
+ substring,
+ NO_ERROR
+ );
+ }
+
+ dosStatus = ERROR_UNEXP_NET_ERR;
+ SS_PRINT(( "srvsvc: unmapped error %d from xactsrv.\n",
+ Header->Status )) ;
+
+ } else {
+
+ //
+ // No change
+ //
+
+ return;
+ }
+ }
+
+ Header->Status = dosStatus;
+ return;
+
+} // ConvertApiStatusToDosStatus
+
diff --git a/private/net/svcdlls/srvsvc/srvnames.h b/private/net/svcdlls/srvsvc/srvnames.h
new file mode 100644
index 000000000..61ba4fecd
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/srvnames.h
@@ -0,0 +1,21 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ srvnames.h
+
+Abstract:
+
+ Private header file which defines the Server Service names.
+
+Author:
+
+ Dan Lafferty (danl) 07-Jan-1993
+
+Revision History:
+
+--*/
+
+#define SERVER_INTERFACE_NAME TEXT("srvsvc")
diff --git a/private/net/svcdlls/srvsvc/srvsvc.acf b/private/net/svcdlls/srvsvc/srvsvc.acf
new file mode 100644
index 000000000..5027f010a
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/srvsvc.acf
@@ -0,0 +1,44 @@
+[ implicit_handle( handle_t srvsvc_bhandle ) ]
+
+interface srvsvc
+
+{
+
+typedef [allocate(all_nodes)] LPCHARDEV_INFO_0;
+typedef [allocate(all_nodes)] LPCHARDEV_INFO_1;
+
+typedef [allocate(all_nodes)] LPCHARDEVQ_INFO_0;
+typedef [allocate(all_nodes)] LPCHARDEVQ_INFO_1;
+
+typedef [allocate(all_nodes)] LPCONNECTION_INFO_0;
+typedef [allocate(all_nodes)] LPCONNECTION_INFO_1;
+
+typedef [allocate(all_nodes)] LPFILE_INFO_2;
+typedef [allocate(all_nodes)] LPFILE_INFO_3;
+
+typedef [allocate(all_nodes)] LPSESSION_INFO_0;
+typedef [allocate(all_nodes)] LPSESSION_INFO_1;
+typedef [allocate(all_nodes)] LPSESSION_INFO_2;
+typedef [allocate(all_nodes)] LPSESSION_INFO_10;
+typedef [allocate(all_nodes)] LPSESSION_INFO_502;
+
+typedef [allocate(all_nodes)] LPSHARE_INFO_0;
+typedef [allocate(all_nodes)] LPSHARE_INFO_1;
+typedef [allocate(all_nodes)] LPSHARE_INFO_2;
+typedef [allocate(all_nodes)] LPSHARE_INFO_502_I;
+
+typedef [allocate(all_nodes)] LPSERVER_INFO_100;
+typedef [allocate(all_nodes)] LPSERVER_INFO_101;
+typedef [allocate(all_nodes)] LPSERVER_INFO_102;
+typedef [allocate(all_nodes)] LPSERVER_INFO_402;
+typedef [allocate(all_nodes)] LPSERVER_INFO_403;
+typedef [allocate(all_nodes)] LPSERVER_INFO_502;
+typedef [allocate(all_nodes)] LPSERVER_INFO_503;
+typedef [allocate(all_nodes)] LPSERVER_INFO_599;
+
+typedef [allocate(all_nodes)] LPDISK_INFO;
+
+typedef [allocate(all_nodes)] LPSERVER_TRANSPORT_INFO_0;
+typedef [allocate(all_nodes)] LPSERVER_TRANSPORT_INFO_1;
+
+}
diff --git a/private/net/svcdlls/srvsvc/srvsvc.idl b/private/net/svcdlls/srvsvc/srvsvc.idl
new file mode 100644
index 000000000..49c31347e
--- /dev/null
+++ b/private/net/svcdlls/srvsvc/srvsvc.idl
@@ -0,0 +1,1078 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ SRVSVC.IDL
+
+Abstract:
+
+ Contains the Netr (Net Remote) RPC interface specification for the
+ API associated with the Server Service. This includes API from the
+ following catagories:
+
+ NetCharDev
+ NetCharDevQ
+ NetConnection
+ NetFile
+ NetRemoteTOD
+ NetServer
+ NetServerTransport
+ NetSession
+ NetShare
+ NetStatisticsGet (server half)
+
+ Also contains the RPC specific data structures for these API.
+
+Author:
+
+ Dan Lafferty (danl) 06-Feb-1991
+
+Environment:
+
+ User Mode - Win32 - MIDL
+
+Revision History:
+
+ 07-May-1991 danl
+ Updated with RPC unionSs and latest structures.
+
+ 06-Feb-1991 danl
+ created
+
+ 08-Aug-1992 johnsona
+ added share info level 502.
+
+--*/
+
+
+//
+// Interface Attributes
+//
+
+[
+ uuid(4B324FC8-1670-01D3-1278-5A47BF6EE188),
+ version(3.0),
+#ifdef __midl
+ ms_union,
+#endif // __midl
+ pointer_default(unique)
+]
+
+
+interface srvsvc
+
+
+{
+
+import "import.idl";
+#include <lmcons.h>
+
+//
+// BUGBUG - take this definition out when midl understands LPWSTR etc
+//
+
+#ifdef UNICODE
+#define LPTSTR wchar_t*
+#define TCHAR wchar_t
+#else
+#define TCHAR char
+#endif
+
+typedef [handle] LPTSTR SRVSVC_HANDLE;
+
+//
+// CharDev API
+//
+
+//
+// Structures - NetrCharDev
+//
+typedef struct _CHARDEV_INFO_0_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPCHARDEV_INFO_0 Buffer;
+} CHARDEV_INFO_0_CONTAINER, *PCHARDEV_INFO_0_CONTAINER, *LPCHARDEV_INFO_0_CONTAINER;
+
+typedef struct _CHARDEV_INFO_1_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPCHARDEV_INFO_1 Buffer;
+} CHARDEV_INFO_1_CONTAINER, *PCHARDEV_INFO_1_CONTAINER, *LPCHARDEV_INFO_1_CONTAINER;
+
+typedef struct _CHARDEV_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _CHARDEV_ENUM_UNION{
+ [case(0)]
+ CHARDEV_INFO_0_CONTAINER *Level0;
+ [case(1)]
+ CHARDEV_INFO_1_CONTAINER *Level1;
+ [default]
+ ;
+ } CharDevInfo;
+
+}CHARDEV_ENUM_STRUCT, *PCHARDEV_ENUM_STRUCT, *LPCHARDEV_ENUM_STRUCT;
+
+typedef [switch_type(unsigned long)] union _CHARDEV_INFO { // for Get & Set Info
+ [case(0)]
+ LPCHARDEV_INFO_0 CharDevInfo0;
+ [case(1)]
+ LPCHARDEV_INFO_1 CharDevInfo1;
+ [default]
+ ;
+} CHARDEV_INFO, *PCHARDEV_INFO, *LPCHARDEV_INFO;
+
+//
+// Function Prototypes - NetrCharDev
+//
+
+NET_API_STATUS
+NetrCharDevEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,out] LPCHARDEV_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+NET_API_STATUS
+NetrCharDevGetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR DevName,
+ [in] DWORD Level,
+ [out, switch_is(Level)] LPCHARDEV_INFO InfoStruct
+ );
+
+NET_API_STATUS
+NetrCharDevControl (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR DevName,
+ [in] DWORD Opcode
+ );
+
+
+//
+// CharDevQ API
+//
+
+//
+// Structures - NetrCharDevQ
+//
+
+typedef struct _CHARDEVQ_INFO_0_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPCHARDEVQ_INFO_0 Buffer;
+} CHARDEVQ_INFO_0_CONTAINER, *PCHARDEVQ_INFO_0_CONTAINER, *LPCHARDEVQ_INFO_0_CONTAINER;
+
+typedef struct _CHARDEVQ_INFO_1_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPCHARDEVQ_INFO_1 Buffer;
+} CHARDEVQ_INFO_1_CONTAINER, *PCHARDEVQ_INFO_1_CONTAINER, *LPCHARDEVQ_INFO_1_CONTAINER;
+
+typedef struct _CHARDEVQ_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _CHARDEVQ_ENUM_UNION{
+ [case(0)]
+ CHARDEVQ_INFO_0_CONTAINER *Level0;
+ [case(1)]
+ CHARDEVQ_INFO_1_CONTAINER *Level1;
+ [default]
+ ;
+ } CharDevQInfo;
+
+}CHARDEVQ_ENUM_STRUCT, *PCHARDEVQ_ENUM_STRUCT, *LPCHARDEVQ_ENUM_STRUCT;
+
+typedef [switch_type(unsigned long)] union _CHARDEVQ_INFO { // for Get & Set Info
+ [case(0)]
+ LPCHARDEVQ_INFO_0 CharDevQInfo0;
+ [case(1)]
+ LPCHARDEVQ_INFO_1 CharDevQInfo1;
+ [case(1002)]
+ LPCHARDEVQ_INFO_1002 CharDevQInfo11002;
+ [case(1003)]
+ LPCHARDEVQ_INFO_1003 CharDevQInfo1003;
+ [default]
+ ;
+} CHARDEVQ_INFO, *PCHARDEVQ_INFO, *LPCHARDEVQ_INFO;
+
+//
+// Function Prototypes - NetrCharDevQ
+//
+
+NET_API_STATUS
+NetrCharDevQEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR UserName,
+ [in,out] LPCHARDEVQ_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+NET_API_STATUS
+NetrCharDevQGetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR QueueName,
+ [in,string] LPTSTR UserName,
+ [in] DWORD Level,
+ [out, switch_is(Level)] LPCHARDEVQ_INFO InfoStruct
+ );
+
+NET_API_STATUS
+NetrCharDevQSetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR QueueName,
+ [in] DWORD Level,
+ [in, switch_is(Level)] LPCHARDEVQ_INFO CharDevQInfo,
+ [in,out,unique] LPDWORD ParmErr
+ );
+
+NET_API_STATUS
+NetrCharDevQPurge (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR QueueName
+ );
+
+NET_API_STATUS
+NetrCharDevQPurgeSelf (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR QueueName,
+ [in,string] LPTSTR ComputerName
+ );
+
+//
+// Connection API
+//
+
+//
+// Structures - NetrConnection
+//
+
+typedef struct _CONNECT_INFO_0_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPCONNECTION_INFO_0 Buffer;
+} CONNECT_INFO_0_CONTAINER, *PCONNECT_INFO_0_CONTAINER, *LPCONNECT_INFO_0_CONTAINER;
+
+typedef struct _CONNECT_INFO_1_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPCONNECTION_INFO_1 Buffer;
+} CONNECT_INFO_1_CONTAINER, *PCONNECT_INFO_1_CONTAINER, *LPCONNECT_INFO_1_CONTAINER;
+
+typedef struct _CONNECT_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _CONNECT_ENUM_UNION{
+ [case(0)]
+ CONNECT_INFO_0_CONTAINER *Level0;
+ [case(1)]
+ CONNECT_INFO_1_CONTAINER *Level1;
+ [default]
+ ;
+ } ConnectInfo;
+
+}CONNECT_ENUM_STRUCT, *PCONNECT_ENUM_STRUCT, *LPCONNECT_ENUM_STRUCT;
+
+
+//
+// Function Prototypes - NetrConnection
+//
+
+NET_API_STATUS
+NetrConnectionEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR Qualifier,
+ [in,out] LPCONNECT_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+//
+// File API
+//
+
+//
+// Structures - NetrFile
+//
+
+typedef struct _FILE_INFO_2_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPFILE_INFO_2 Buffer;
+} FILE_INFO_2_CONTAINER, *PFILE_INFO_2_CONTAINER, *LPFILE_INFO_2_CONTAINER;
+
+typedef struct _FILE_INFO_3_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPFILE_INFO_3 Buffer;
+} FILE_INFO_3_CONTAINER, *PFILE_INFO_3_CONTAINER, *LPFILE_INFO_3_CONTAINER;
+
+
+typedef struct _FILE_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _FILE_ENUM_UNION {
+ [case(2)]
+ FILE_INFO_2_CONTAINER *Level2;
+ [case(3)]
+ FILE_INFO_3_CONTAINER *Level3;
+ [default]
+ ;
+ } FileInfo;
+
+}FILE_ENUM_STRUCT, *PFILE_ENUM_STRUCT, *LPFILE_ENUM_STRUCT;
+
+typedef [switch_type(unsigned long)] union _FILE_INFO { // for Get & Set Info
+ [case(2)]
+ LPFILE_INFO_2 FileInfo2;
+ [case(3)]
+ LPFILE_INFO_3 FileInfo3;
+ [default]
+ ;
+} FILE_INFO, *PFILE_INFO, *LPFILE_INFO;
+
+//
+// Function Prototypes - NetrFile
+//
+
+NET_API_STATUS
+NetrFileEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR BasePath,
+ [in,string,unique] LPTSTR UserName,
+ [in,out] PFILE_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+NET_API_STATUS
+NetrFileGetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD FileId,
+ [in] DWORD Level,
+ [out, switch_is(Level)] LPFILE_INFO InfoStruct
+ );
+
+NET_API_STATUS
+NetrFileClose (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD FileId
+ );
+
+//
+// Session API
+//
+
+//
+// Structures - NetrSession
+//
+
+typedef struct _SESSION_INFO_0_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSESSION_INFO_0 Buffer;
+} SESSION_INFO_0_CONTAINER, *PSESSION_INFO_0_CONTAINER, *LPSESSION_INFO_0_CONTAINER;
+
+typedef struct _SESSION_INFO_1_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSESSION_INFO_1 Buffer;
+} SESSION_INFO_1_CONTAINER, *PSESSION_INFO_1_CONTAINER, *LPSESSION_INFO_1_CONTAINER;
+
+typedef struct _SESSION_INFO_2_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSESSION_INFO_2 Buffer;
+} SESSION_INFO_2_CONTAINER, *PSESSION_INFO_2_CONTAINER, *LPSESSION_INFO_2_CONTAINER;
+
+typedef struct _SESSION_INFO_10_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSESSION_INFO_10 Buffer;
+} SESSION_INFO_10_CONTAINER, *PSESSION_INFO_10_CONTAINER, *LPSESSION_INFO_10_CONTAINER;
+
+typedef struct _SESSION_INFO_502_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSESSION_INFO_502 Buffer;
+} SESSION_INFO_502_CONTAINER, *PSESSION_INFO_502_CONTAINER, *LPSESSION_INFO_502_CONTAINER;
+
+typedef struct _SESSION_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _SESSION_ENUM_UNION {
+ [case(0)]
+ SESSION_INFO_0_CONTAINER *Level0;
+ [case(1)]
+ SESSION_INFO_1_CONTAINER *Level1;
+ [case(2)]
+ SESSION_INFO_2_CONTAINER *Level2;
+ [case(10)]
+ SESSION_INFO_10_CONTAINER *Level10;
+ [case(502)]
+ SESSION_INFO_502_CONTAINER *Level502;
+ [default]
+ ;
+ } SessionInfo;
+
+}SESSION_ENUM_STRUCT, *PSESSION_ENUM_STRUCT, *LPSESSION_ENUM_STRUCT;
+
+//
+// Function Prototypes - NetrSession
+//
+
+NET_API_STATUS
+NetrSessionEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR ClientName,
+ [in,string,unique] LPTSTR UserName,
+ [in,out] PSESSION_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+
+NET_API_STATUS
+NetrSessionDel (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR ClientName,
+ [in,string,unique] LPTSTR UserName
+ );
+
+//
+// Share API
+//
+
+//
+// Structures - NetrShare
+//
+
+//
+// Internal 502 and 1501 structures used for passing and/or returning
+// self-relative security descriptors.
+//
+
+typedef struct _SHARE_INFO_502_I {
+ [string] LPTSTR shi502_netname;
+ DWORD shi502_type;
+ [string] LPTSTR shi502_remark;
+ DWORD shi502_permissions;
+ DWORD shi502_max_uses;
+ DWORD shi502_current_uses;
+ [string] LPTSTR shi502_path;
+ [string] LPTSTR shi502_passwd;
+ DWORD shi502_reserved;
+ [size_is(shi502_reserved)] PUCHAR shi502_security_descriptor;
+} SHARE_INFO_502_I, *PSHARE_INFO_502_I, *LPSHARE_INFO_502_I;
+
+typedef struct _SHARE_INFO_1501_I {
+ DWORD shi1501_reserved;
+ [size_is(shi1501_reserved)] PUCHAR shi1501_security_descriptor;
+} SHARE_INFO_1501_I, *PSHARE_INFO_1501_I, *LPSHARE_INFO_1501_I;
+
+//
+// Structures for NetShareEnum
+//
+
+typedef struct _SHARE_INFO_0_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSHARE_INFO_0 Buffer;
+} SHARE_INFO_0_CONTAINER;
+
+typedef struct _SHARE_INFO_1_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSHARE_INFO_1 Buffer;
+} SHARE_INFO_1_CONTAINER;
+
+typedef struct _SHARE_INFO_2_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSHARE_INFO_2 Buffer;
+} SHARE_INFO_2_CONTAINER, *PSHARE_INFO_2_CONTAINER, *LPSHARE_INFO_2_CONTAINER;
+
+typedef struct _SHARE_INFO_502_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSHARE_INFO_502_I Buffer;
+} SHARE_INFO_502_CONTAINER, *PSHARE_INFO_502_CONTAINER, *LPSHARE_INFO_502_CONTAINER;
+
+
+typedef struct _SHARE_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _SHARE_ENUM_UNION {
+ [case(0)]
+ SHARE_INFO_0_CONTAINER *Level0;
+ [case(1)]
+ SHARE_INFO_1_CONTAINER *Level1;
+ [case(2)]
+ SHARE_INFO_2_CONTAINER *Level2;
+ [case(502)]
+ SHARE_INFO_502_CONTAINER *Level502;
+ [default]
+ ;
+ } ShareInfo;
+
+}SHARE_ENUM_STRUCT, *PSHARE_ENUM_STRUCT, *LPSHARE_ENUM_STRUCT;
+
+typedef [switch_type(unsigned long)] union _SHARE_INFO { // for Get & Set Info
+ [case(0)]
+ LPSHARE_INFO_0 ShareInfo0;
+ [case(1)]
+ LPSHARE_INFO_1 ShareInfo1;
+ [case(2)]
+ LPSHARE_INFO_2 ShareInfo2;
+ [case(502)]
+ LPSHARE_INFO_502_I ShareInfo502;
+ [case(1004)]
+ LPSHARE_INFO_1004 ShareInfo1004;
+ [case(1006)]
+ LPSHARE_INFO_1006 ShareInfo1006;
+ [case(1501)]
+ LPSHARE_INFO_1501_I ShareInfo1501;
+ [default]
+ ;
+ [case(1005)]
+ LPSHARE_INFO_1005 ShareInfo1005;
+} SHARE_INFO, *PSHARE_INFO, *LPSHARE_INFO;
+
+//
+// Function Prototypes - NetrShare
+//
+
+NET_API_STATUS
+NetrShareAdd (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [in, switch_is(Level)] LPSHARE_INFO InfoStruct,
+ [in,out,unique] LPDWORD ParmErr
+ );
+
+NET_API_STATUS
+NetrShareEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,out] LPSHARE_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+NET_API_STATUS
+NetrShareGetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR NetName,
+ [in] DWORD Level,
+ [out, switch_is(Level)] LPSHARE_INFO InfoStruct
+ );
+
+NET_API_STATUS
+NetrShareSetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR NetName,
+ [in] DWORD Level,
+ [in, switch_is(Level)] LPSHARE_INFO ShareInfo,
+ [in,out,unique] LPDWORD ParmErr
+ );
+
+NET_API_STATUS
+NetrShareDel (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR NetName,
+ [in] DWORD Reserved
+ );
+
+NET_API_STATUS
+NetrShareDelSticky (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR NetName,
+ [in] DWORD Reserved
+ );
+
+NET_API_STATUS
+NetrShareCheck (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR Device,
+ [out] LPDWORD Type
+ );
+
+//
+// Server API
+//
+
+//
+// Structures - NetrServer
+//
+
+typedef [switch_type(unsigned long)] union _SERVER_INFO { // For Get & Set Info
+ [case(100)]
+ LPSERVER_INFO_100 ServerInfo100;
+ [case(101)]
+ LPSERVER_INFO_101 ServerInfo101;
+ [case(102)]
+ LPSERVER_INFO_102 ServerInfo102;
+ [case(402)]
+ LPSERVER_INFO_402 ServerInfo402;
+ [case(403)]
+ LPSERVER_INFO_403 ServerInfo403;
+ [case(502)]
+ LPSERVER_INFO_502 ServerInfo502;
+ [case(503)]
+ LPSERVER_INFO_503 ServerInfo503;
+ [case(599)]
+ LPSERVER_INFO_599 ServerInfo599;
+ [case(1005)]
+ LPSERVER_INFO_1005 ServerInfo1005;
+ [case(1107)]
+ LPSERVER_INFO_1107 ServerInfo1107;
+ [case(1010)]
+ LPSERVER_INFO_1010 ServerInfo1010;
+ [case(1016)]
+ LPSERVER_INFO_1016 ServerInfo1016;
+ [case(1017)]
+ LPSERVER_INFO_1017 ServerInfo1017;
+ [case(1018)]
+ LPSERVER_INFO_1018 ServerInfo1018;
+ [case(1501)]
+ LPSERVER_INFO_1501 ServerInfo1501;
+ [case(1502)]
+ LPSERVER_INFO_1502 ServerInfo1502;
+ [case(1503)]
+ LPSERVER_INFO_1503 ServerInfo1503;
+ [case(1506)]
+ LPSERVER_INFO_1506 ServerInfo1506;
+ [case(1509)]
+ LPSERVER_INFO_1509 ServerInfo1509;
+ [case(1510)]
+ LPSERVER_INFO_1510 ServerInfo1510;
+ [case(1511)]
+ LPSERVER_INFO_1511 ServerInfo1511;
+ [case(1512)]
+ LPSERVER_INFO_1512 ServerInfo1512;
+ [case(1513)]
+ LPSERVER_INFO_1513 ServerInfo1513;
+ [case(1514)]
+ LPSERVER_INFO_1514 ServerInfo1514;
+ [case(1515)]
+ LPSERVER_INFO_1515 ServerInfo1515;
+ [case(1516)]
+ LPSERVER_INFO_1516 ServerInfo1516;
+ [case(1518)]
+ LPSERVER_INFO_1518 ServerInfo1518;
+ [case(1520)]
+ LPSERVER_INFO_1520 ServerInfo1520;
+ [case(1521)]
+ LPSERVER_INFO_1521 ServerInfo1521;
+ [case(1522)]
+ LPSERVER_INFO_1522 ServerInfo1522;
+ [case(1523)]
+ LPSERVER_INFO_1523 ServerInfo1523;
+ [case(1524)]
+ LPSERVER_INFO_1524 ServerInfo1524;
+ [case(1525)]
+ LPSERVER_INFO_1525 ServerInfo1525;
+ [case(1528)]
+ LPSERVER_INFO_1528 ServerInfo1528;
+ [case(1529)]
+ LPSERVER_INFO_1529 ServerInfo1529;
+ [case(1530)]
+ LPSERVER_INFO_1530 ServerInfo1530;
+ [case(1533)]
+ LPSERVER_INFO_1533 ServerInfo1533;
+ [case(1534)]
+ LPSERVER_INFO_1534 ServerInfo1534;
+ [case(1535)]
+ LPSERVER_INFO_1535 ServerInfo1535;
+ [case(1536)]
+ LPSERVER_INFO_1536 ServerInfo1536;
+ [case(1537)]
+ LPSERVER_INFO_1537 ServerInfo1537;
+ [case(1538)]
+ LPSERVER_INFO_1538 ServerInfo1538;
+ [case(1539)]
+ LPSERVER_INFO_1539 ServerInfo1539;
+ [case(1540)]
+ LPSERVER_INFO_1540 ServerInfo1540;
+ [case(1541)]
+ LPSERVER_INFO_1541 ServerInfo1541;
+ [case(1542)]
+ LPSERVER_INFO_1542 ServerInfo1542;
+ [case(1543)]
+ LPSERVER_INFO_1543 ServerInfo1543;
+ [case(1544)]
+ LPSERVER_INFO_1544 ServerInfo1544;
+ [case(1545)]
+ LPSERVER_INFO_1545 ServerInfo1545;
+ [case(1546)]
+ LPSERVER_INFO_1546 ServerInfo1546;
+ [case(1547)]
+ LPSERVER_INFO_1547 ServerInfo1547;
+ [case(1548)]
+ LPSERVER_INFO_1548 ServerInfo1548;
+ [case(1549)]
+ LPSERVER_INFO_1549 ServerInfo1549;
+ [case(1550)]
+ LPSERVER_INFO_1550 ServerInfo1550;
+ [case(1552)]
+ LPSERVER_INFO_1552 ServerInfo1552;
+ [case(1553)]
+ LPSERVER_INFO_1553 ServerInfo1553;
+ [case(1554)]
+ LPSERVER_INFO_1554 ServerInfo1554;
+ [case(1555)]
+ LPSERVER_INFO_1555 ServerInfo1555;
+ [case(1556)]
+ LPSERVER_INFO_1556 ServerInfo1556;
+ [default]
+ ;
+} SERVER_INFO, *PSERVER_INFO, *LPSERVER_INFO;
+
+//
+// DiskEnum
+//
+// NOTE: The buffer pointer is supposed to point to an array of strings.
+// each string is fixed size with two characters followed by a NUL.
+// A:\0B:\0c:\0\0
+
+typedef struct _DISK_INFO {
+ [string] TCHAR Disk[3];
+} DISK_INFO, *PDISK_INFO, *LPDISK_INFO;
+
+typedef struct _DISK_ENUM_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead), length_is(EntriesRead)] LPDISK_INFO Buffer;
+} DISK_ENUM_CONTAINER;
+
+//
+// Function Prototypes - NetrServer
+//
+
+NET_API_STATUS
+NetrServerGetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [out, switch_is(Level)] LPSERVER_INFO InfoStruct
+ );
+
+NET_API_STATUS
+NetrServerSetInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [in, switch_is(Level)] LPSERVER_INFO ServerInfo,
+ [in,out,unique] LPDWORD ParmErr
+ );
+
+NET_API_STATUS
+NetrServerDiskEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [in,out] DISK_ENUM_CONTAINER *DiskInfoStruct,
+ [in] DWORD PreferredMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+//
+// Function Prototype - NetrServerStatisticsGet
+//
+
+NET_API_STATUS
+NetrServerStatisticsGet (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR Service,
+ [in] DWORD Level,
+ [in] DWORD Options,
+ [out] LPSTAT_SERVER_0 *InfoStruct
+ );
+
+//
+// Server Transport API
+//
+
+//
+// Structures - NetrServerTransport
+//
+
+typedef struct _SERVER_XPORT_INFO_0_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSERVER_TRANSPORT_INFO_0 Buffer;
+} SERVER_XPORT_INFO_0_CONTAINER, *PSERVER_XPORT_INFO_0_CONTAINER;
+
+typedef struct _SERVER_XPORT_INFO_1_CONTAINER {
+ DWORD EntriesRead;
+ [size_is(EntriesRead)] LPSERVER_TRANSPORT_INFO_1 Buffer;
+} SERVER_XPORT_INFO_1_CONTAINER, *PSERVER_XPORT_INFO_1_CONTAINER;
+
+typedef [switch_type(unsigned long)] union _TRANSPORT_INFO { // for Add and Del
+ [case(0)]
+ SERVER_TRANSPORT_INFO_0 Transport0;
+ [case(1)]
+ SERVER_TRANSPORT_INFO_1 Transport1;
+ [default]
+ ;
+} TRANSPORT_INFO, *PTRANSPORT_INFO, *LPTRANSPORT_INFO;
+
+typedef struct _SERVER_XPORT_ENUM_STRUCT {
+ DWORD Level;
+ [switch_is(Level)] union _SERVER_XPORT_ENUM_UNION {
+ [case(0)]
+ PSERVER_XPORT_INFO_0_CONTAINER Level0;
+ [case(1)]
+ PSERVER_XPORT_INFO_1_CONTAINER Level1;
+ [default]
+ ;
+ } XportInfo;
+
+} SERVER_XPORT_ENUM_STRUCT, *PSERVER_XPORT_ENUM_STRUCT, *LPSERVER_XPORT_ENUM_STRUCT;
+
+//
+// Function Prototypes - NetrServerTransport
+//
+NET_API_STATUS
+NetrServerTransportAdd (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [in] LPSERVER_TRANSPORT_INFO_0 Buffer
+ );
+
+
+NET_API_STATUS
+NetrServerTransportEnum (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,out] LPSERVER_XPORT_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+NET_API_STATUS
+NetrServerTransportDel (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [in] LPSERVER_TRANSPORT_INFO_0 Buffer
+ );
+
+
+//
+// Function Prototype - NetrRemoteTOD
+//
+
+NET_API_STATUS
+NetrRemoteTOD (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [out] LPTIME_OF_DAY_INFO *BufferPtr
+ );
+
+//
+// Function Prototype - I_NetrServerSetServiceBits (internal API)
+//
+
+NET_API_STATUS
+I_NetrServerSetServiceBits (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPTSTR TransportName,
+ [in] DWORD ServiceBits,
+ [in] DWORD UpdateImmediately
+ );
+
+//
+// Function Prototypes - Canonicalization functions
+//
+
+NET_API_STATUS
+NetprPathType(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR PathName,
+ [out] LPDWORD PathType,
+ [in] DWORD Flags
+ );
+
+NET_API_STATUS
+NetprPathCanonicalize(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR PathName,
+ [out,size_is(OutbufLen)] LPBYTE Outbuf,
+ [in] DWORD OutbufLen,
+ [in,string] LPTSTR Prefix,
+ [in,out] LPDWORD PathType,
+ [in] DWORD Flags
+ );
+
+LONG
+NetprPathCompare(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR PathName1,
+ [in,string] LPTSTR PathName2,
+ [in] DWORD PathType,
+ [in] DWORD Flags
+ );
+
+NET_API_STATUS
+NetprNameValidate(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR Name,
+ [in] DWORD NameType,
+ [in] DWORD Flags
+ );
+
+NET_API_STATUS
+NetprNameCanonicalize(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR Name,
+ [out,size_is(OutbufLen)] LPTSTR Outbuf,
+ [in] DWORD OutbufLen,
+ [in] DWORD NameType,
+ [in] DWORD Flags
+ );
+
+LONG
+NetprNameCompare(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR Name1,
+ [in,string] LPTSTR Name2,
+ [in] DWORD NameType,
+ [in] DWORD Flags
+ );
+
+NET_API_STATUS
+NetrShareEnumSticky (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,out] LPSHARE_ENUM_STRUCT InfoStruct,
+ [in] DWORD PreferedMaximumLength,
+ [out] LPDWORD TotalEntries,
+ [in,out,unique] LPDWORD ResumeHandle
+ );
+
+//
+// Two-phase share deletion used to delete IPC$
+//
+
+typedef [context_handle] void *SHARE_DEL_HANDLE;
+typedef SHARE_DEL_HANDLE *PSHARE_DEL_HANDLE;
+
+NET_API_STATUS
+NetrShareDelStart (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPTSTR NetName,
+ [in] DWORD Reserved,
+ [out] PSHARE_DEL_HANDLE ContextHandle
+ );
+
+NET_API_STATUS
+NetrShareDelCommit (
+ [in, out] PSHARE_DEL_HANDLE ContextHandle
+ );
+
+//
+// AdminTools types and functions
+//
+typedef struct _ADT_SECURITY_DESCRIPTOR {
+ DWORD Length;
+ [size_is(Length)] LPBYTE Buffer;
+} ADT_SECURITY_DESCRIPTOR, *PADT_SECURITY_DESCRIPTOR;
+
+DWORD
+NetrpGetFileSecurity (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPWSTR ShareName,
+ [in,string] LPWSTR lpFileName,
+ [in] SECURITY_INFORMATION RequestedInformation,
+ [out] PADT_SECURITY_DESCRIPTOR *SecurityDescriptor
+ );
+
+DWORD
+NetrpSetFileSecurity (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPWSTR ShareName,
+ [in,string] LPWSTR lpFileName,
+ [in] SECURITY_INFORMATION SecurityInformation,
+ [in] PADT_SECURITY_DESCRIPTOR SecurityDescriptor
+ );
+
+NET_API_STATUS
+NetrServerTransportAddEx (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] DWORD Level,
+ [in, switch_is(Level)] LPTRANSPORT_INFO Buffer
+ );
+
+NET_API_STATUS
+I_NetrServerSetServiceBitsEx (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string,unique] LPWSTR EmulatedServerName,
+ [in,string,unique] LPTSTR TransportName,
+ [in] DWORD ServiceBitsOfInterest,
+ [in] DWORD ServiceBits,
+ [in] DWORD UpdateImmediately
+ );
+
+
+//
+// Definitions for DFS operations
+//
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsGetVersion(
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [out] LPDWORD Version
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsCreateLocalPartition (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPWSTR ShareName,
+ [in] LPGUID EntryUid, // unique id for this partition
+ [in,string] LPWSTR EntryPrefix, // path prefix for this partition
+ [in,string] LPWSTR ShortName, // 8.3 format of EntryPrefix
+ [in] LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
+ [in] BOOL Force
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsDeleteLocalPartition (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] LPGUID Uid,
+ [in,string] LPWSTR Prefix
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsSetLocalVolumeState (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] LPGUID Uid,
+ [in,string] LPWSTR Prefix,
+ [in] ULONG State
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsSetServerInfo (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] LPGUID Uid,
+ [in,string] LPWSTR Prefix
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsCreateExitPoint (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] LPGUID Uid,
+ [in,string] LPWSTR Prefix,
+ [in] ULONG Type,
+ [in] DWORD ShortPrefixLen,
+ [out,size_is(ShortPrefixLen)] LPWSTR ShortPrefix
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsDeleteExitPoint (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] LPGUID Uid,
+ [in,string] LPWSTR Prefix,
+ [in] ULONG Type
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsModifyPrefix (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in] LPGUID Uid,
+ [in,string] LPWSTR Prefix
+ );
+
+NET_API_STATUS NET_API_FUNCTION
+NetrDfsFixLocalVolume (
+ [in,string,unique] SRVSVC_HANDLE ServerName,
+ [in,string] LPWSTR VolumeName,
+ [in] ULONG EntryType,
+ [in] ULONG ServiceType,
+ [in,string] LPWSTR StgId,
+ [in] LPGUID EntryUid, // unique id for this partition
+ [in,string] LPWSTR EntryPrefix, // path prefix for this partition
+ [in] LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
+ [in] ULONG CreateDisposition
+ );
+
+}