diff options
Diffstat (limited to 'private/net/svcdlls/srvsvc')
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( ¶meters->TotalDataCount, (WORD)MessageLength ); + SmbPutUlong( ¶meters->Timeout, 0x3E8 ); // !!! fix + SmbPutUshort( ¶meters->DataCount, (WORD)MessageLength ); + SmbPutUshort( + ¶meters->DataOffset, + (WORD)( (DWORD)message - (DWORD)header ) + ); + parameters->SetupWordCount = 3; + SmbPutUshort( ¶meters->Opcode, MS_WRITE_OPCODE ); + SmbPutUshort( ¶meters->Class, 2 ); + SmbPutUshort( ¶meters->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( ®istryPath, registryPathBuffer ); + + status = NtLoadDriver( ®istryPath ); + + MIDL_user_free( registryPathBuffer ); + + NetpReleasePrivilege( ); + + if ( status == STATUS_IMAGE_ALREADY_LOADED ) { + status = STATUS_SUCCESS; + } + + if ( !NT_SUCCESS(status) ) { + + IF_DEBUG(INITIALIZATION_ERRORS) { + SS_PRINT(( "LoadServer: Unable to load driver: %lx\n", + status )); + } + + subString[0] = SERVER_DRIVER_NAME; + SsLogEvent( + EVENT_SRV_CANT_LOAD_DRIVER, + 1, + subString, + status + ); + + } + + IF_DEBUG(INITIALIZATION) { + SS_PRINT(( "LoadServer: returning\n" )); + } + return RtlNtStatusToDosError(status); + +} // LoadServer + + +NET_API_STATUS +ConvertStringToTransportAddress ( + IN PUNICODE_STRING InputName, + OUT CHAR TransportAddress[ MAX_PATH ], + OUT PULONG TransportAddressLength + ) +{ + OEM_STRING computerName; + + if( InputName == NULL || InputName->Length == 0 ) { + RtlCopyMemory( TransportAddress, + SsServerTransportAddress, + SsServerTransportAddressLength ); + + *TransportAddressLength = SsServerTransportAddressLength; + return NO_ERROR; + } + + if( InputName->Length > (MAX_PATH - 1 ) * sizeof( WCHAR ) ) { + return ERROR_INVALID_PARAMETER; + } + + // + // Write directly to the output buffer + // + + computerName.Buffer = TransportAddress; + computerName.MaximumLength = MAX_PATH; + + // + // Convert To Oem Name + // + + (VOID) RtlUpcaseUnicodeStringToOemString( + &computerName, + InputName, + FALSE + ); + + // + // Make sure it is exactly NETBIOS_NAME_LEN characters + // + if( computerName.Length < NETBIOS_NAME_LEN ) { + + RtlCopyMemory( TransportAddress + computerName.Length, + " ", + NETBIOS_NAME_LEN - computerName.Length + ); + + *TransportAddressLength = NETBIOS_NAME_LEN; + + } else { + + *TransportAddressLength = NETBIOS_NAME_LEN; + + } + + return NO_ERROR; + +} // ConvertStringToTransportAddress + + +VOID +SetDomainName ( + VOID + ) + +/*++ + +Routine Description: + + Tries to get the Cairo domain. If it can't then: + Calls NetpGetDomainName to determine the domain name the server + should use. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + NET_API_STATUS error; + LPWSTR domainName; +#ifdef _CAIRO_ + WCHAR szDomainName[MAX_PATH]; + DWORD dwSize = MAX_PATH; + + + if(SUCCEEDED(DSGetDomainName(szDomainName, &dwSize)) + && + (szDomainName[0] == L'\\')) + { + STRCPY( SsData.LongDomainNameBuffer, szDomainName ); + } +#endif + + // + // Get the domain name. + // + + error = NetpGetDomainName( &domainName ); + SS_ASSERT( error == NO_ERROR ); + + // + // Copy the name into our name buffer. + // + + STRCPY( SsData.DomainNameBuffer, domainName ); + + // + // Free the storage allocated by NetpGetComputerName. + // + + (VOID)NetApiBufferFree( domainName ); + + IF_DEBUG(INITIALIZATION) { + SS_PRINT(( "SetDomainName: domain name set to " FORMAT_LPWSTR + "(could be overridden later!)\n", + SsData.DomainNameBuffer )); + } + + return; + +} // SetDomainName + + +VOID +SetServerName ( + VOID + ) + +/*++ + +Routine Description: + + Calls NetpGetComputerName to determine the name the server should use + to register itself on the network. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + NET_API_STATUS error; + LPWSTR computerName; + + // + // Get the computer name. + // + + error = NetpGetComputerName( &computerName ); + SS_ASSERT( error == NO_ERROR ); + + // + // Copy the name into our name buffer. This name is returned to + // our apis. + // + + STRCPY( SsData.ServerNameBuffer, computerName ); + + // + // Free the storage allocated by NetpGetComputerName. + // + + (void) NetApiBufferFree( computerName ); + + // + // Uppercase the server name. This name is used for announcements. + // + + { + UNICODE_STRING serverName; + + SsData.ServerAnnounceName.Length = + serverName.Length = + (USHORT) (STRLEN( SsData.ServerNameBuffer ) * sizeof(WCHAR)); + + SsData.ServerAnnounceName.MaximumLength = + serverName.MaximumLength = + (USHORT) (serverName.Length + sizeof(WCHAR)); + + serverName.Buffer = SsData.ServerNameBuffer; + SsData.ServerAnnounceName.Buffer = SsData.AnnounceNameBuffer; + + (VOID)RtlUpcaseUnicodeString( + &SsData.ServerAnnounceName, + &serverName, + FALSE + ); + + // + // Make the server name in Netbios format. + // + + error = ConvertStringToTransportAddress( + &serverName, + SsServerTransportAddress, + &SsServerTransportAddressLength + ); + + SS_ASSERT( error == NO_ERROR ); + } + + + IF_DEBUG(INITIALIZATION) { + SS_PRINT(( "SetServerName: server name set to " FORMAT_LPWSTR + " (could be overridden later!)\n", + SsData.ServerNameBuffer )); + } + + return; + +} // SetServerName + + +NET_API_STATUS +TerminateServer ( + VOID + ) + +/*++ + +Routine Description: + + This routine sends the FSCTL_SRV_SHUTDOWN control code to the server + FSD to tell it to shutdown operations. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + NET_API_STATUS error = NO_ERROR; + + if ( SsServerFspStarted ) { + + SsServerFspStarted = FALSE; + + // + // Send the request on to the server. + // + + error = SsServerFsControl( + NULL, + FSCTL_SRV_SHUTDOWN, + NULL, + NULL, + 0 + ); + if ( (error != NO_ERROR) && + (error != ERROR_SERVER_HAS_OPEN_HANDLES) ) { + IF_DEBUG(TERMINATION_ERRORS) { + SS_PRINT(( "TerminateServer: FSCTL_SRV_SHUTDOWN failed: %ld\n", + error )); + } + } + + // + // Unload the server driver, unless there are other open handles + // to the server. We don't unload the driver in this case + // because the driver won't actually go away until the + // additional handles are closed, so the driver will not be + // fully unloaded. This would cause a subsequent server startup + // to fail. + // + + if ( error != ERROR_SERVER_HAS_OPEN_HANDLES ) { + IF_DEBUG(TERMINATION) { + SS_PRINT(( "TerminateServer: Unloading server\n" )); + } + UnloadServer( ); + } + + } + + // + // Close the handle to the server. + // + + SsCloseServer( ); + + return error; + +} // TerminateServer + + +VOID +UnloadServer ( + VOID + ) +{ + NTSTATUS status; + NET_API_STATUS error; + LPWSTR registryPathBuffer; + UNICODE_STRING registryPath; + ULONG privileges[1]; + LPWSTR subString[1]; + + registryPathBuffer = (LPWSTR)MIDL_user_allocate( + sizeof(SERVICE_REGISTRY_KEY) + + sizeof(SERVER_DRIVER_NAME) + ); + if ( registryPathBuffer == NULL ) { + IF_DEBUG(TERMINATION_ERRORS) { + SS_PRINT(( "UnloadServer: Unable to allocate memory\n" )); + } + return; + } + + privileges[0] = SE_LOAD_DRIVER_PRIVILEGE; + + error = NetpGetPrivilege( 1, privileges ); + if ( error != NO_ERROR ) { + IF_DEBUG(TERMINATION_ERRORS) { + SS_PRINT(( "UnloadServer: Unable to enable privilege: %ld\n", + error )); + } + MIDL_user_free( registryPathBuffer ); + return; + } + + wcscpy( registryPathBuffer, SERVICE_REGISTRY_KEY ); + wcscat( registryPathBuffer, SERVER_DRIVER_NAME ); + + RtlInitUnicodeString( ®istryPath, registryPathBuffer ); + + status = NtUnloadDriver( ®istryPath ); + + MIDL_user_free( registryPathBuffer ); + + NetpReleasePrivilege( ); + + if ( !NT_SUCCESS(status) ) { + + IF_DEBUG(TERMINATION_ERRORS) { + SS_PRINT(( "UnloadServer: Unable to unload driver: %lx\n", + status )); + } + + subString[0] = SERVER_DRIVER_NAME; + SsLogEvent( + EVENT_SRV_CANT_UNLOAD_DRIVER, + 1, + subString, + status + ); + + } + + return; + +} // UnloadServer + + + +VOID +InitializeStrings( + VOID + ) + +/*++ + +Routine Description: + + Retrieve internationalizable strings from NETMSG.DLL. They + are used for share comments for IPC$, ADMIN$, C$, etc. + Routine does not report any errors. If there are problems, + the strings will be empty ones. + + FreeStrings should be called to free the memory allocated + by format message and the + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + DWORD dwRet, dwFlags ; + HMODULE hModule ; + + // + // init the strings to the default empty remark. + // + SsAdminShareRemark = SsDefaultRemark ; + SsIPCShareRemark = SsDefaultRemark ; + SsDiskAdminShareRemark = SsDefaultRemark ; + + // + // load NETMSG.DLL - if we cannot, just return. + // + hModule = LoadLibrary(NETMSG_DLL) ; + if(!hModule) + return ; + + // + // hit FormatMessage 3 times for the real thing... + // + dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE ; + + dwRet = FormatMessage(dwFlags, + hModule, + APE2_SERVER_IPC_SHARE_REMARK, + 0, + (LPWSTR) &SsIPCShareRemark, + 1, + NULL) ; + if (dwRet == 0) + SsIPCShareRemark = SsDefaultRemark ; + + dwRet = FormatMessage(dwFlags, + hModule, + APE2_SERVER_ADMIN_SHARE_REMARK, + 0, + (LPWSTR) &SsAdminShareRemark, + 1, + NULL) ; + if (dwRet == 0) + SsAdminShareRemark = SsDefaultRemark ; + + dwRet = FormatMessage(dwFlags, + hModule, + APE2_SERVER_DISK_ADMIN_SHARE_REMARK, + 0, + (LPWSTR) &SsDiskAdminShareRemark, + 1, + NULL) ; + if (dwRet == 0) + SsDiskAdminShareRemark = SsDefaultRemark ; + + FreeLibrary(hModule) ; +} + + +VOID +FreeStrings( + VOID + ) + +/*++ + +Routine Description: + + Free the memory used by server comment strings (allocated by + FormatMessage). + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + // + // as long as the strings do not point to the default (static data), + // free them. + // + + if (SsAdminShareRemark && SsAdminShareRemark != SsDefaultRemark) + LocalFree(SsAdminShareRemark) ; + SsAdminShareRemark = SsDefaultRemark ; + + if (SsIPCShareRemark && SsIPCShareRemark != SsDefaultRemark) + LocalFree(SsIPCShareRemark) ; + SsIPCShareRemark = SsDefaultRemark ; + + if (SsDiskAdminShareRemark && SsDiskAdminShareRemark != SsDefaultRemark) + LocalFree(SsDiskAdminShareRemark) ; + SsDiskAdminShareRemark = SsDefaultRemark ; +} 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 + ); + +} |