diff options
Diffstat (limited to 'private/net/svcdlls/rpl/rplinst')
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/debug.c | 137 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/debug.h | 28 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/local.h | 77 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/makefile | 6 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/makefile.inc | 8 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/querydir.c | 136 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/rplimsg.h | 55 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/rplinst.c | 137 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/rplinst.rc | 14 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/security.c | 1567 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/security.h | 17 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/sources | 38 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/tree.c | 2 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/tree.h | 28 | ||||
-rw-r--r-- | private/net/svcdlls/rpl/rplinst/treei.h | 51 |
15 files changed, 2301 insertions, 0 deletions
diff --git a/private/net/svcdlls/rpl/rplinst/debug.c b/private/net/svcdlls/rpl/rplinst/debug.c new file mode 100644 index 000000000..468b04969 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/debug.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + debug.c + +Abstract: + + Debugging module. RpldDebugPrint() was adapted from TelnetDebugPrint() + in net\sockets\tcpcmd\telnet\debug.c. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "debug.h" + +#ifdef RPL_DEBUG + +#define RPL_PROMPT "[Rpl] " +#define DEBUG_RECORD_SIZE 0x80 +#define DEBUG_BUFFER_SIZE 0x20000 // 2*64k, must be a power of 2 +#define DEBUG_BUFFER_MASK (DEBUG_BUFFER_SIZE - 1) + +// int RG_DebugLevel = -1; // max debugging +// int RG_DebugLevel = 0; // no debugging, for public use + +int RG_DebugLevel; // needed by other modules +int RG_Assert; // needed by other modules + +PCHAR RG_DebugBuffer; +CRITICAL_SECTION RG_ProtectDebug; +DWORD RG_DebugOffset; +// +// This buffer is used even when RG_DebugBuffer is not NULL. +// +char RG_DebugPublicBuffer[ 120]; + + +VOID RplDebugDelete( VOID) +{ + if ( RG_DebugBuffer != NULL) { + (VOID)GlobalFree( RG_DebugBuffer); + } + DeleteCriticalSection( &RG_ProtectDebug); +} + +#define RPL_DEFAULT_DEBUG_LEVEL ( RPL_DEBUG_FLOW | \ + RPL_DEBUG_SERVER | \ + RPL_DEBUG_MAJOR ) + +#define RPL_MAXIMUM_DEBUG_LEVEL (-1L) + + + +VOID RplDebugInitialize( VOID) +{ + // + // Set RG_Assert to 0. Without this the very first use of + // RplDump() will lead to an assert. + // + RG_Assert = 0; + +// RG_DebugLevel = RPL_DEFAULT_DEBUG_LEVEL; + RG_DebugLevel = RPL_MAXIMUM_DEBUG_LEVEL & ~RPL_DEBUG_MEMALLOC + & ~RPL_DEBUG_FLOWINIT & ~RPL_DEBUG_FDR & ~RPL_DEBUG_SFR; +// RG_DebugLevel = RPL_MAXIMUM_DEBUG_LEVEL; + + + RG_DebugBuffer = (PCHAR)GlobalAlloc( + GMEM_FIXED, + DEBUG_BUFFER_SIZE + DEBUG_RECORD_SIZE + ); + if ( RG_DebugBuffer != NULL) { + RtlFillMemory( + RG_DebugBuffer, + DEBUG_BUFFER_SIZE + DEBUG_RECORD_SIZE, + '*' + ); + RG_DebugOffset = 0; + } + memcpy( RG_DebugPublicBuffer, RPL_PROMPT, sizeof( RPL_PROMPT) -1); + + InitializeCriticalSection( &RG_ProtectDebug); +} + + +VOID _CRTAPI1 RplDebugPrint( CONST CHAR * format, ...) +{ + va_list arglist; + + va_start( arglist, format); + + EnterCriticalSection( &RG_ProtectDebug); + + if ( RG_Assert == 0 && RG_DebugBuffer != NULL) { + RtlZeroMemory( RG_DebugBuffer + RG_DebugOffset, DEBUG_RECORD_SIZE); + vsprintf( RG_DebugBuffer + RG_DebugOffset, format, arglist); + RG_DebugOffset += DEBUG_RECORD_SIZE; + RG_DebugOffset &= DEBUG_BUFFER_MASK; + } else { + vsprintf( RG_DebugPublicBuffer + sizeof( RPL_PROMPT) - 1, format, arglist); + DbgPrint( "%s\n", RG_DebugPublicBuffer); + } + + if ( RG_Assert != 0) { + ASSERT( FALSE); // break for checked build + KdPrint(( "[RplSvc] Running checked version of service on a free build.\n")); + } + while ( RG_Assert != 0) { + KdPrint(( "[RplSvc] Debug, then reset RG_Assert to 0.\n")); + DbgUserBreakPoint(); + Sleep( RG_Assert * 30000); // sleep for 30 seconds + } + + LeaveCriticalSection( &RG_ProtectDebug); + + va_end( arglist); + +} // RplDebugPrint + + +#endif // RPL_DEBUG + + + diff --git a/private/net/svcdlls/rpl/rplinst/debug.h b/private/net/svcdlls/rpl/rplinst/debug.h new file mode 100644 index 000000000..31706c1fe --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/debug.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + debug.h + +Abstract: + + Exports from debug.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#ifdef RPL_DEBUG +VOID RplDebugInitialize( VOID); +VOID RplDebugDelete( VOID); +#endif // RPL_DEBUG diff --git a/private/net/svcdlls/rpl/rplinst/local.h b/private/net/svcdlls/rpl/rplinst/local.h new file mode 100644 index 000000000..ebdc7068b --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/local.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for RPLINST + +Author: + + Jon Newman (jonn) 12 - January - 1994 + +Revision History: + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here + +// +#include <lmapibuf.h> // NetApiBufferFree +#include <netlib.h> + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_INFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + +// +// Global types and constants (used in all RPL server files). +// + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> +#include <rpllib.h> // AddKey(), MapJetError(), FillTcpIpString() + +#include <rpldb.h> +#include <rpldebug.h> + +#include "rplmgrd.h" +#include "nlstxt.h" + +#include <lmshare.h> + +#define RPLFILES_STRING L"RPLFILES" +#define RPL_SERVICE_NAME L"RemoteBoot" +#define RPL_REMARK L"RemoteBoot service share" + +#define RPL_BUGBUG_ERROR 10999 // need to get rid of these + +WCHAR RG_Directory[ PATHLEN+1]; // path to rpl service disk data +DWORD RG_DirectoryLength; // length of the above path diff --git a/private/net/svcdlls/rpl/rplinst/makefile b/private/net/svcdlls/rpl/rplinst/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/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/rpl/rplinst/makefile.inc b/private/net/svcdlls/rpl/rplinst/makefile.inc new file mode 100644 index 000000000..f1d8b42fd --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/makefile.inc @@ -0,0 +1,8 @@ +# templated from portuas JonN 1/14/94 +nlstxt.mc: rplimsg.h + mapmsg -p RPLI RPLI_BASE rplimsg.h > nlstxt.mc + +rplinst.rc: nlstxt.rc msg00001.bin + +nlstxt.h nlstxt.rc msg00001.bin: nlstxt.mc + mc -v nlstxt.mc diff --git a/private/net/svcdlls/rpl/rplinst/querydir.c b/private/net/svcdlls/rpl/rplinst/querydir.c new file mode 100644 index 000000000..64e9596c1 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/querydir.c @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + querydir.c + +Abstract: + + Contains I_NetRpl_QueryDirectory + +Author: + + Jon Newman 13 - January - 1994 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE + + +#define RPL_REGISTRY_PARAMETERS L"System\\CurrentControlSet\\Services\\RemoteBoot\\Parameters" +#define RPL_REGISTRY_DIRECTORY L"Directory" +#define RPL_DEFAULT_DIRECTORY L"%SystemRoot%\\rpl\\" + +// BUGBUG server\rplmain.c should call this routine + + +DWORD I_NetRpl_QueryDirectory( OUT LPWSTR pchFilePath, + OUT LPDWORD pcchFilePathLength) +{ + DWORD Error; + BYTE Buffer[ (PATHLEN + 1) * sizeof(WCHAR)]; + PWCHAR Value; + HKEY Key; + DWORD Length; + DWORD Type; + DWORD Size; + + // RPL_ASSERT( pchFilePath != NULL); + + // + // First open the RPL service parameters registry tree. + // + Error = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + RPL_REGISTRY_PARAMETERS, + 0, + KEY_READ, + &Key + ); + if (Error != ERROR_SUCCESS){ + // RplDump( ++RG_Assert, ("Error = %d", Error)); + return( Error); + } + // Length = sizeof( Buffer); This is totally wrong! Has Rl Server been + // using the default value this whole time? + // Length = sizeof( Buffer); + Size = sizeof( Buffer); + Error = RegQueryValueEx( + Key, + RPL_REGISTRY_DIRECTORY, + NULL, + &Type, + Buffer, + &Size + ); + (VOID)RegCloseKey( Key); + if ( Error == NO_ERROR) { + // + // We have the data. First validate the data, then append the + // backslash if needed. + // + Value = (PWCHAR)Buffer; + if ( Type != REG_EXPAND_SZ || (Size&1) != 0 || Size < sizeof(L"c:")) { + // RplDump( ++RG_Assert, ("Type = 0x%x, Value = 0x%x, Size=%d", + // Type, Value, Size)); + return( RPL_BUGBUG_ERROR); + } + Length = Size / sizeof(WCHAR) - 1; + if ( Value[ Length] != 0 || Length != wcslen(Value)) { + // RplDump( ++RG_Assert, ("Length = %d, Value = 0x%x, Size=%d", + // Length, Value, Size)); + return( RPL_BUGBUG_ERROR); + } + if ( Value[ Length - 1] != L'\\') { + // + // Need to append the backslash. + // + if ( Length >= PATHLEN) { + // RplDump( ++RG_Assert, ("Length = %d, Value = 0x%x, Size=%d", + // Length, Value, Size)); + return( RPL_BUGBUG_ERROR); // not enough space + } + Value[ Length] = L'\\'; + Value[ ++Length] = 0; + } + } else { + Value = RPL_DEFAULT_DIRECTORY; + } + + // + // Length returned by ExpandEnvironmentalStrings includes terminating + // NULL byte. + // + // This code was wrong!! The third parameter to ExpandEnvironmentStrings + // should be a character count, not a byte count. + // + // Length = ExpandEnvironmentStrings( Value, RG_Directory, sizeof( RG_Directory)); + Length = ExpandEnvironmentStrings( Value, pchFilePath, PATHLEN+1); + if ( Length == 0) { + Error = GetLastError(); + // RplDump( ++RG_Assert, ("Error = %d", Error)); + return( Error); + } + if ( Length > PATHLEN+1) { + // RplDump( ++RG_Assert, ("Length = %d", Length)); + return( RPL_BUGBUG_ERROR); + } + if ( Length != wcslen( pchFilePath) + 1) { + // RplDump( ++RG_Assert, ("Length = %d", Length)); + return( RPL_BUGBUG_ERROR); + } + if (pcchFilePathLength != NULL) { + *pcchFilePathLength = (DWORD)(Length - 1); + } + return( NO_ERROR); +} diff --git a/private/net/svcdlls/rpl/rplinst/rplimsg.h b/private/net/svcdlls/rpl/rplinst/rplimsg.h new file mode 100644 index 000000000..f66f2c940 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/rplimsg.h @@ -0,0 +1,55 @@ +#define RPLI_BASE 11000 /* RPLI Messages start here */ +#define RPLI_MAX 11999 /* RPLI Messages end here */ + +#define RPLI_CreatingShare (RPLI_BASE + 0) + /* + *Creating RPLFILES share... + */ +#define RPLI_ErrorCreatingShare (RPLI_BASE + 1) + /* + *Error creating RPLFILES share:%n%1!ls! + */ +#define RPLI_ConfiguringService (RPLI_BASE + 2) + /* + *Making RPL service autostart... + */ +#define RPLI_ErrorConfiguringService (RPLI_BASE + 3) + /* + *Error making RPL service autostart:%n%1!ls! + */ +#define RPLI_RPLINSTcomplete (RPLI_BASE + 4) + /* + *RPLINST completed successfully! + */ +#define RPLI_ErrorReadingRPLDirectory (RPLI_BASE + 5) + /* + *The registry key RPL\\Parameters value Directory could not be read due to the following error:%n%1!ls! + */ +#define RPLI_ErrorReadingString (RPLI_BASE + 6) + /* + *Could not read string + */ +#define RPLI_SettingPermissions (RPLI_BASE + 7) + /* + *Making RPL service autostart... + */ +#define RPLI_ErrorSettingPermissions (RPLI_BASE + 8) + /* + *The file permissions on the RPL file tree could not be set due to the following error:%n%1!ls! + */ +#define RPLI_CreatingRPLUSER (RPLI_BASE + 9) + /* + *Creating the RPLUSER group... + */ +#define RPLI_ErrorCreatingRPLUSER (RPLI_BASE + 10) + /* + *The RPLUSER group could not be created due to the following error:%n%1!ls! + */ +#define RPLI_CheckingWkstaAccts (RPLI_BASE + 11) + /* + *Checking the workstation accounts... + */ +#define RPLI_ErrorCheckingWkstaAccts (RPLI_BASE + 12) + /* + *The following error occurred checking the workstation accounts:%n%1!ls! + */ diff --git a/private/net/svcdlls/rpl/rplinst/rplinst.c b/private/net/svcdlls/rpl/rplinst/rplinst.c new file mode 100644 index 000000000..38c018a30 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/rplinst.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rplinst.c + +Abstract: + + Secondary setup activity, including + + Establish RPLFILES share + + Set up permissions on RPLFILES tree + + BUGBUG Should polish and make WIN32 application out of this. + +Author: + + Jon Newman (jonn) 13 - January - 1994 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE + +#include "security.h" + +WCHAR RG_Directory[ PATHLEN+1]; +DWORD RG_DirectoryLength; + + +DWORD _CRTAPI1 main ( VOID) +{ + DWORD dwErr = NO_ERROR; + RPL_HANDLE hRpl = NULL; + WCHAR awchBase[ MAX_PATH ]; + + dwErr = I_NetRpl_QueryDirectory( RG_Directory, &RG_DirectoryLength); + if ( dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorReadingRPLDirectory, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_CreatingRPLUSER); + + dwErr = RplAddRPLUSERGroup(); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorCreatingRPLUSER, dwErr); + goto cleanup; + } + + dwErr = NetRplOpen( NULL, &hRpl ); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorCheckingWkstaAccts, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_CheckingWkstaAccts); + + dwErr = RplCheckWkstaAccounts( hRpl ); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorCheckingWkstaAccts, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_SettingPermissions); + + ASSERT( RG_DirectoryLength < MAX_PATH ); + ASSERT( RG_DirectoryLength == lstrlenW(RG_DirectoryLength) ); + ASSERT( RG_Directory[ RG_DirectoryLength-1 ] == L'\\' ); + lstrcpyW( awchBase, RG_Directory ); + awchBase[ RG_DirectoryLength-1 ] = L'\0'; + + dwErr = RplSetPermsOnTree( awchBase ); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorSettingPermissions, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_RPLINSTcomplete); + +cleanup: + + if (hRpl != NULL) { + NetRplClose( hRpl ); + } + + return( dwErr); +} + + +// +// allows us to use original security.c code +// +NET_API_STATUS NET_API_FUNCTION +MyNetrRplWkstaEnum( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ProfileName, + IN OUT LPRPL_WKSTA_ENUM WkstaEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + For more extensive comments see related code in NetrConfigEnum. +--*/ +{ + DWORD EntriesRead = 0; + LPBYTE Buffer = NULL; + DWORD Error = NO_ERROR; + // Error = NetApiBufferAllocate( 4096, &Buffer); + + Error = NetRplWkstaEnum( ServerHandle, + ProfileName, + WkstaEnum->Level, + (LPBYTE *)&(WkstaEnum->WkstaInfo.Level0->Buffer), + PrefMaxLength, + &(WkstaEnum->WkstaInfo.Level0->EntriesRead), + TotalEntries, + pResumeHandle ); + + return( Error); +} + +void __RPC_API MyMIDL_user_free( void __RPC_FAR * pv ) +{ + NetApiBufferFree( pv ); +} diff --git a/private/net/svcdlls/rpl/rplinst/rplinst.rc b/private/net/svcdlls/rpl/rplinst/rplinst.rc new file mode 100644 index 000000000..dbaf0b6f0 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/rplinst.rc @@ -0,0 +1,14 @@ +/* templated from portuas JonN 1/14/94 */ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "RPLINST Utility" +#define VER_INTERNALNAME_STR "rplinst.exe" +#define VER_ORIGINALFILENAME_STR "rplinst.exe" + +#include "common.ver" + +1 11 MSG00001.bin diff --git a/private/net/svcdlls/rpl/rplinst/security.c b/private/net/svcdlls/rpl/rplinst/security.c new file mode 100644 index 000000000..a064309f9 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/security.c @@ -0,0 +1,1567 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + security.c + +Abstract: + + Security addons to the tree-manipulation module + for the RPL service. + +Author: + + Jon Newman (jonn) 16 - February - 1994 + +Revision History: + + Jon Newman (jonn) 16 - February - 1994 + Added RplGrant*Perms primitives + + CODEWORK: Should have more sophisticated error handling + +--*/ + + +#include "local.h" +#include "tree.h" +#include "treei.h" +#include "security.h" +#include <ntseapi.h> +#include <ntrtl.h> // RtlAllocateAndInitializeSid +#include <ntlsa.h> +#include <ntsam.h> +#include <nturtl.h> // see IsNTFS + + +typedef enum _RPL_SD_BLOCK_TYPE { + + RPL_SD_BLOCK_TYPE_ADMINONLY = 0,// Only RPLADMIN gets access + + RPL_SD_BLOCK_TYPE_ALLUSERS, // RPLADMIN gets full access, RPLUSER + // gets RX access + + RPL_SD_BLOCK_TYPE_ONEUSER, // RPLADMIN gets full access, one + // wksta account gets RWXCDA access + + RPL_SD_BLOCK_TYPE_BADUSER // Skip setting permissions on this user +} RPL_SD_BLOCK_TYPE; + +/* + * This is the block of information which is retained between the recursive + * calls in a single RplDoTree run. It remembers the SECURITY_DESCRIPTOR + * which was assigned to the last file/directory, so if the next + * file/directory wants the same permissions (as is usually the case) + * we do not have to fetch everything all over again. It also contains + * some information about what kind of SECURITY_DESCRIPTOR is currently + * stored, plus items needed to get a different SECURITY_DESCRIPTOR. + */ +typedef struct _RPL_SD_BLOCK { + PSECURITY_DESCRIPTOR psd; + RPL_SD_BLOCK_TYPE nChangeableAceType; + PSID psidSystem; + PSID psidAdministrators; + PSID psidSystemOperators; + PSID psidRPLUSER; + PSID psidGrantTo; // SID of account with name pwszGrantToName + PWCHAR pwszGrantToName; + // Name of account for BLOCK_TYPE_ONEUSER + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain; + SAM_HANDLE hsamAccountDomain; +} RPL_SD_BLOCK, *PRPL_SD_BLOCK; + +// +// The DACL we assign to files has 3 or 4 ACEs. +// +#define RPL_INDEX_SYSTEM_ACE 0 +#define RPL_INDEX_ADMINS_ACE 1 +#define RPL_INDEX_RPLADMIN_ACE 2 +#define RPL_INDEX_CHANGEABLE_ACE 3 + + +// +// Forward declarations +// + +DWORD SetRplPerms( + IN PWCHAR pwszPath, + IN OUT PVOID * ppv); + +DWORD GetSdForFile( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN PWCHAR pwszFile, + OUT BOOL * pfSkipPermsOnFile + ); + +DWORD GetSd( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN RPL_SD_BLOCK_TYPE nChangeableAceType, + IN PWCHAR pwszGrantTo + ); + +DWORD AddInheritableAce( + IN OUT ACL * pacl, + IN ACCESS_MASK mask, + IN SID * psid ); + +DWORD InitSdBlock( + OUT RPL_SD_BLOCK ** ppsdblock + ); + +VOID FreeSdBlock( + IN RPL_SD_BLOCK ** ppsdblock + ); + +DWORD GetAccountDomain( + OUT SAM_HANDLE * phsamAccountDomain, + OUT POLICY_ACCOUNT_DOMAIN_INFO ** ppinfoAccountDomain, + IN ACCESS_MASK DesiredAccess + ); + +DWORD GetAccountSid( + IN SAM_HANDLE hsamAccountDomain, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN WCHAR * pwszAccountName, + OUT PSID * ppsidAccountSid, + IN BOOL fIsLocalgroup, + OUT DWORD * pulRid OPTIONAL + ); + +DWORD IsNTFS( + IN WCHAR * pszResource, + OUT BOOL * pfIsNTFS ); + +DWORD RplAddWkstaAccount( LPWSTR pszWkstaName, + SAM_HANDLE hsamAccountDomain, + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + SAM_HANDLE hsamRPLUSER ); + +VOID FillUnicodeString( PUNICODE_STRING punistr, + LPWSTR lpwsz ); + +DWORD MyBuildSid( OUT PSID * ppsidAccountSid, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN ULONG ulRid ); + +VOID MyFreeSid( IN OUT PSID * ppsid ); + + +/* + * Like RplTreeCopy, but also sets permissions on target files/directories. + * Target must be in %RplRoot% subtree. + * + * CODEWORK do something with error buffer + */ +DWORD RplTreeCopyAndSetPerms( + IN PWCHAR pwszSource, + IN PWCHAR pwszTarget ) +{ + WCHAR Buffer[ 300]; + DWORD Error = NO_ERROR; + PVOID pv = NULL; + DWORD Flags = RPL_TREE_COPY | RPL_TREE_AUXILIARY; + BOOL fIsNTFS = TRUE; + + // + // Check if volume is NTFS, if so never mind about ACLs + // + + Error = IsNTFS( pwszTarget, &fIsNTFS ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } else if (!fIsNTFS) { + Flags &= ~RPL_TREE_AUXILIARY; + } + + Buffer[ 0] = 0; + Error = RplDoTree( pwszSource, pwszTarget, + Flags, + Buffer, sizeof(Buffer), + SetRplPerms, &pv); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( pv != NULL) { + FreeSdBlock( (RPL_SD_BLOCK **)(&pv) ); + } + + return( Error); +} + + +/* + * Sets permissions on a file tree. + * Target must be in %RplRoot% subtree. + * + * CODEWORK do something with error buffer + */ +DWORD RplSetPermsOnTree( + IN PWCHAR pwszSource ) +{ + WCHAR Buffer[ 300]; + DWORD Error = NO_ERROR; + PVOID pv = NULL; + BOOL fIsNTFS = TRUE; + + // + // Check if volume is NTFS, if so do nothing + // + + Error = IsNTFS( pwszSource, &fIsNTFS ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } else if (!fIsNTFS) { + goto cleanup; + } + + Buffer[ 0] = 0; + Error = RplDoTree( pwszSource, NULL, + RPL_TREE_AUXILIARY, + Buffer, sizeof(Buffer), + SetRplPerms, &pv); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( pv != NULL) { + FreeSdBlock( (RPL_SD_BLOCK **)(&pv) ); + } + + return( Error); +} + + +/* + * This is the callback routine called by RplDoTree to set permissions + * on a specific file/directory. + */ +DWORD SetRplPerms( + IN PWCHAR pwszPath, + IN OUT PVOID * ppv) +{ + DWORD Error = NO_ERROR; + RPL_SD_BLOCK ** ppsdblock = (RPL_SD_BLOCK **)ppv; + PSECURITY_DESCRIPTOR psd = NULL; + BOOL fSkipPermsOnFile = FALSE; + + RPL_ASSERT( pwszPath != NULL ); + RPL_ASSERT( ppv != NULL ); + + Error = GetSdForFile( &psd, ppsdblock, pwszPath, &fSkipPermsOnFile ); + if (Error != NO_ERROR || fSkipPermsOnFile) { + goto cleanup; + } + + RPL_ASSERT( psd != NULL ); + + // + // Set the actual file security. Note that this call will succeed + // even if the volume is not NTFS, thus we must check for + // partition type elsewhere. + // + + if ( !SetFileSecurity( pwszPath, DACL_SECURITY_INFORMATION, psd)) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + return( Error); +} + + +/* + * Get the SECURITY_DESCRIPTOR which is appropriate for a file/directory + * at this position in %RplRoot%. First we determine what kind of + * SECURITY_DESCRIPTOR we want, then we call GetSd() to build it. + */ +DWORD GetSdForFile( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN PWCHAR pwszFile, + OUT BOOL * pfSkipPermsOnFile + ) +{ + DWORD Error = NO_ERROR; + PWCHAR pwszRelativeFile = NULL; + PWCHAR pwszWkstaNameStart = NULL; + PWCHAR pwszWkstaNameEnd = NULL; + RPL_SD_BLOCK_TYPE blocktype = RPL_SD_BLOCK_TYPE_ADMINONLY; + WCHAR awchFile[MAX_PATH]; + WCHAR wchSave, wchSave2; + DWORD cch; + + RPL_ASSERT( ppsd != NULL ); + RPL_ASSERT( ppsdblock != NULL ); + RPL_ASSERT( pwszFile != NULL ); + RPL_ASSERT( pfSkipPermsOnFile != NULL ); + RPL_ASSERT( lstrlenW(pwszFile) >= (INT)RG_DirectoryLength ); + RPL_ASSERT( lstrlenW(pwszFile) < MAX_PATH ); + RPL_ASSERT( RG_DirectoryLength > 0 && RG_DirectoryLength < MAX_PATH ); + + *pfSkipPermsOnFile = FALSE; + + // + // Make working copy of pwszFile + // + if (NULL == lstrcpy(awchFile,pwszFile)) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Ensure that awchFile starts with RG_Directory + // + // RG_Directory always ends with L'\\'. awchFile might be equal to + // RG_Directory without the L'\\', we must handle this. + // + wchSave = awchFile[RG_DirectoryLength]; + wchSave2 = awchFile[RG_DirectoryLength-1]; + if (lstrlenW(awchFile) == (int)RG_DirectoryLength-1) { + awchFile[RG_DirectoryLength-1] = L'\\'; + } + awchFile[RG_DirectoryLength] = L'\0'; + if ( 0 != lstrcmpi( awchFile, + RG_Directory )) { + RPL_ASSERT( FALSE ); + Error = ERROR_INVALID_PARAMETER; + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + awchFile[RG_DirectoryLength] = wchSave; + awchFile[RG_DirectoryLength-1] = wchSave2; + + pwszRelativeFile = awchFile + RG_DirectoryLength; + + // + // If the path is in rplfiles\binfiles or rplfiles\profiles, + // set the changeable ACE to RPLUSER + // + + cch = lstrlenW(L"RPLFILES\\BINFILES"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\BINFILES") ) { + blocktype = RPL_SD_BLOCK_TYPE_ALLUSERS; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + + cch = lstrlenW(L"RPLFILES\\PROFILES"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\PROFILES") ) { + blocktype = RPL_SD_BLOCK_TYPE_ALLUSERS; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + + // + // If the path is in rplfiles\machines\* or rplfiles\tmpfiles\*, + // set the changeable ACE to the individual workstation account + // + cch = lstrlenW(L"RPLFILES\\MACHINES\\"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\MACHINES\\") ) { + pwszRelativeFile[ cch ] = wchSave; + blocktype = RPL_SD_BLOCK_TYPE_ONEUSER; + pwszWkstaNameStart = pwszWkstaNameEnd = pwszRelativeFile + cch; + while (*pwszWkstaNameEnd != L'\\' && *pwszWkstaNameEnd != L'\0') { + pwszWkstaNameEnd++; + } + *pwszWkstaNameEnd = L'\0'; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + + cch = lstrlenW(L"RPLFILES\\TMPFILES\\"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\TMPFILES\\") ) { + pwszRelativeFile[ cch ] = wchSave; + blocktype = RPL_SD_BLOCK_TYPE_ONEUSER; + pwszWkstaNameStart = pwszWkstaNameEnd = pwszRelativeFile + cch; + while (*pwszWkstaNameEnd != L'\\' && *pwszWkstaNameEnd != L'\0') { + pwszWkstaNameEnd++; + } + *pwszWkstaNameEnd = L'\0'; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + +cleanup: + + // + // We now know what kind of SECURITY_DESCRIPTOR we want, so get it. + // + if (Error == NO_ERROR && !(*pfSkipPermsOnFile)) { + Error = GetSd( ppsd, ppsdblock, blocktype, pwszWkstaNameStart ); + } + + return( Error); +} + + +/* + * This call gets an actual security descriptor which corresponds to + * nChangeableAceType and pwszGrantTo. The security descriptor + * is only valid until next call to GetSd(). + * + * The caller has to free *ppsdblock eventually, but should not free + * *ppsd. + */ +DWORD GetSd( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN RPL_SD_BLOCK_TYPE nChangeableAceType, + IN PWCHAR pwszGrantTo + ) +{ + DWORD Error = NO_ERROR; + PACL paclDacl = NULL; + BOOL fDaclPresent = FALSE; + BOOL fDaclDefaulted = FALSE; + + RPL_ASSERT( ppsd != NULL); + RPL_ASSERT( ppsdblock != NULL); + + // + // Create the RPL_SD_BLOCK if it does not yet exist + // + if ( *ppsdblock == NULL ) + { + Error = InitSdBlock( ppsdblock ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + } + RPL_ASSERT( *ppsdblock != NULL ); + + // + // If the RPL_SD_BLOCK is already configured correctly, return success + // + if ( ( (*ppsdblock)->nChangeableAceType == nChangeableAceType ) + && ( (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_ONEUSER + || (0 == lstrcmpW((*ppsdblock)->pwszGrantToName, pwszGrantTo)) ) + && ( (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_BADUSER + || (0 == lstrcmpW((*ppsdblock)->pwszGrantToName, pwszGrantTo)) ) + ) + { + goto cleanup; + } + // + // Extract the DACL + // + if ( !GetSecurityDescriptorDacl( (*ppsdblock)->psd, + &fDaclPresent, + &paclDacl, + &fDaclDefaulted + )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( fDaclPresent && !fDaclDefaulted ); + + // + // Clear the changeable ACE if present + // + if ( (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_ADMINONLY + && (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_BADUSER ) + { + if ( !DeleteAce( paclDacl, RPL_INDEX_CHANGEABLE_ACE )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // CODEWORK do we need to decrement ACE count here? + (*ppsdblock)->nChangeableAceType = RPL_SD_BLOCK_TYPE_ADMINONLY; + } + + // + // Clear and rewrite psidGrantTo if necessary + // + if ( nChangeableAceType == RPL_SD_BLOCK_TYPE_ONEUSER + || nChangeableAceType == RPL_SD_BLOCK_TYPE_BADUSER ) + { + if ( (*ppsdblock)->psidGrantTo != NULL) { + MyFreeSid( &((*ppsdblock)->psidGrantTo) ); + TREE_FREE( (*ppsdblock)->pwszGrantToName ); + (*ppsdblock)->pwszGrantToName = NULL; + } + if (lstrlenW(pwszGrantTo) > RPL_MAX_WKSTA_NAME_LENGTH) + { + TREE_ASSERT( ( "Bad user %ws", pwszGrantTo)); + nChangeableAceType = RPL_SD_BLOCK_TYPE_BADUSER; + } + else + { + Error = GetAccountSid( (*ppsdblock)->hsamAccountDomain, + (*ppsdblock)->pinfoAccountDomain, + pwszGrantTo, + &((*ppsdblock)->psidGrantTo), + FALSE, + NULL ); + // CODEWORK trap error here? + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + } + + (*ppsdblock)->pwszGrantToName = + TREE_ALLOC( (lstrlenW(pwszGrantTo)+1) * sizeof(WCHAR) ); + if ( (*ppsdblock)->pwszGrantToName == NULL ) + { + Error = ERROR_NOT_ENOUGH_MEMORY; + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + lstrcpyW( (*ppsdblock)->pwszGrantToName, pwszGrantTo ); + } + + // + // Add changeable ACE if desired + // + RPL_ASSERT( (*ppsdblock)->nChangeableAceType = RPL_SD_BLOCK_TYPE_ADMINONLY ); + switch (nChangeableAceType) { + case RPL_SD_BLOCK_TYPE_ADMINONLY: + case RPL_SD_BLOCK_TYPE_BADUSER: + break; + case RPL_SD_BLOCK_TYPE_ALLUSERS: + Error = AddInheritableAce( paclDacl, + GENERIC_READ | GENERIC_EXECUTE, + (*ppsdblock)->psidRPLUSER ); + break; + case RPL_SD_BLOCK_TYPE_ONEUSER: + Error = AddInheritableAce( paclDacl, + GENERIC_READ + | GENERIC_WRITE + | GENERIC_EXECUTE + | DELETE, + (*ppsdblock)->psidGrantTo ); + break; + default: + ASSERT(FALSE); + break; + } + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + (*ppsdblock)->nChangeableAceType = nChangeableAceType; + + // + // Save the upgraded ACL into the security descriptor + // + // CODEWORK is this needed? + // + if ( !SetSecurityDescriptorDacl( (*ppsdblock)->psd, + TRUE, + paclDacl, + FALSE + )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if (Error == NO_ERROR) { + *ppsd = (*ppsdblock)->psd; + } + + return( Error); +} + + +SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; + +/* + * Create a new RPL_SD_BLOCK + */ +DWORD InitSdBlock( + OUT RPL_SD_BLOCK ** ppsdblock + ) +{ + DWORD Error = 0; + DWORD cbNewDacl = 0; + PACL paclDacl = NULL; + + RPL_ASSERT( ppsdblock != NULL ); + RPL_ASSERT( *ppsdblock == NULL ); + + // + // Allocate memory for the RPL_SD_BLOCK + // + *ppsdblock = TREE_ALLOC( sizeof(RPL_SD_BLOCK) ); + if ( *ppsdblock == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + ZeroMemory( (*ppsdblock), sizeof(RPL_SD_BLOCK) ); + + // + // Get System SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 1, + SECURITY_LOCAL_SYSTEM_RID, + 0, 0, 0, 0, 0, 0, 0, + &((*ppsdblock)->psidSystem) + ); + if (Error != NO_ERROR) { + goto cleanup; + } + + // + // Get Administrators SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &((*ppsdblock)->psidAdministrators) + ); + if (Error != NO_ERROR) { + goto cleanup; + } + + // + // Get System Operators SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_SYSTEM_OPS, + 0, 0, 0, 0, 0, 0, + &((*ppsdblock)->psidSystemOperators) + ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get information about account domain + // + Error = GetAccountDomain( &((*ppsdblock)->hsamAccountDomain), + &((*ppsdblock)->pinfoAccountDomain), + GENERIC_EXECUTE ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get RPLUSER SID + // + Error = GetAccountSid( (*ppsdblock)->hsamAccountDomain, + (*ppsdblock)->pinfoAccountDomain, + RPL_GROUP_RPLUSER, + &((*ppsdblock)->psidRPLUSER), + TRUE, + NULL ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Start assembling DACL + // + cbNewDacl = sizeof(ACL) + (3*sizeof(ACCESS_ALLOWED_ACE)) + + (3*GetSidLengthRequired(SID_MAX_SUB_AUTHORITIES)) + - sizeof(DWORD); + paclDacl = (PACL) TREE_ALLOC( cbNewDacl); + if ( paclDacl == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + if ( !InitializeAcl( paclDacl, cbNewDacl, ACL_REVISION )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Add System ACE + // + Error = AddInheritableAce( paclDacl, + GENERIC_ALL, + (*ppsdblock)->psidSystem ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // CODEWORK do we still want to free psidSystem? + + // + // Add Administrators ACE + // + Error = AddInheritableAce( paclDacl, + GENERIC_ALL, + (*ppsdblock)->psidAdministrators ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // CODEWORK do we still want to free psidAdministrators? + + // + // Add System Operators ACE + // + Error = AddInheritableAce( paclDacl, + GENERIC_ALL, + (*ppsdblock)->psidSystemOperators ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // BUGBUG shouldn't add this for WINNT machines! + // CODEWORK do we still want to free psidSystemOperators? + + // + // Build security descriptor + // + (*ppsdblock)->psd = TREE_ALLOC( sizeof(SECURITY_DESCRIPTOR) ); + if ( (*ppsdblock)->psd == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + if ( !InitializeSecurityDescriptor( (*ppsdblock)->psd, + SECURITY_DESCRIPTOR_REVISION )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + if ( !SetSecurityDescriptorDacl( (*ppsdblock)->psd, + TRUE, + paclDacl, + FALSE )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Set nChangeableAceType in RPL_SD_BLOCK + // + (*ppsdblock)->nChangeableAceType = RPL_SD_BLOCK_TYPE_ADMINONLY; + +cleanup: + + if (Error != NO_ERROR) + { + FreeSdBlock( ppsdblock ); + + if (paclDacl != NULL) { + TREE_FREE( paclDacl ); + paclDacl = NULL; + } + } + + return(Error); +} + +/* + * Add an ACCESS_ALLOWED_ACE to the ACL, with all inheritance flags set + */ +DWORD AddInheritableAce( + IN OUT ACL * pacl, + IN ACCESS_MASK mask, + IN SID * psid ) +{ + DWORD Error = NO_ERROR; + ACCESS_ALLOWED_ACE * pace = NULL; + + if ( !AddAccessAllowedAce( pacl, + ACL_REVISION, + mask, + psid )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // new ACE should be the last ACE + // + if ( !GetAce( pacl, (pacl->AceCount) - 1, &pace )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( EqualSid( psid, &(pace->SidStart)) ); + + (pace->Header.AceFlags) |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); + +cleanup: + + return( Error); +} + + +/* + * The RplDoTree run is over, free the RPL_SD_BLOCK + */ +VOID FreeSdBlock( + IN RPL_SD_BLOCK ** ppsdblock + ) +{ + RPL_ASSERT( ppsdblock != NULL ); + + if (*ppsdblock != NULL) + { + if ((*ppsdblock)->psd != NULL) { + TREE_FREE( (*ppsdblock)->psd ); + } + if ((*ppsdblock)->pwszGrantToName != NULL) { + TREE_FREE( (*ppsdblock)->pwszGrantToName ); + } + if ((*ppsdblock)->psidSystem != NULL) { + RtlFreeSid( (*ppsdblock)->psidSystem ); + } + if ((*ppsdblock)->psidAdministrators != NULL) { + RtlFreeSid( (*ppsdblock)->psidAdministrators ); + } + if ((*ppsdblock)->psidSystemOperators != NULL) { + RtlFreeSid( (*ppsdblock)->psidSystemOperators); + } + MyFreeSid( &((*ppsdblock)->psidRPLUSER) ); + MyFreeSid( &((*ppsdblock)->psidGrantTo) ); + if ( (*ppsdblock)->pinfoAccountDomain != NULL) { + LsaFreeMemory( (*ppsdblock)->pinfoAccountDomain); + } + if ((*ppsdblock)->hsamAccountDomain != NULL) { + SamCloseHandle( (*ppsdblock)->hsamAccountDomain); + } + } + TREE_FREE( *ppsdblock ); + *ppsdblock = NULL; +} + + +/* + * Get a SAM_HANDLE to the account domain, and other information about + * the account domain. This routine uses SAM and LSA directly. + */ +DWORD GetAccountDomain( + OUT SAM_HANDLE * phsamAccountDomain, + OUT POLICY_ACCOUNT_DOMAIN_INFO ** ppinfoAccountDomain, + IN ACCESS_MASK DesiredAccess + ) +{ + DWORD Error = NO_ERROR; + SAM_HANDLE hsamServer = NULL; + LSA_HANDLE hlsa = NULL; + OBJECT_ATTRIBUTES oa; + POLICY_ACCOUNT_DOMAIN_INFO * pacctdominfo = NULL; + SECURITY_QUALITY_OF_SERVICE sqos; + + RPL_ASSERT( phsamAccountDomain != NULL ); + RPL_ASSERT( ppinfoAccountDomain != NULL ); + + // + // Get server handle + // + + Error = SamConnect( NULL, + &hsamServer, + SAM_SERVER_LOOKUP_DOMAIN, + NULL ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Set up object attributes (borrowed from uintlsa.cxx) + // + + sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + sqos.ImpersonationLevel = SecurityImpersonation; + sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + sqos.EffectiveOnly = FALSE; + + InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL ); + oa.SecurityQualityOfService = &sqos; + + // + // Get LSA handle + // + + Error = LsaOpenPolicy( NULL, + &oa, + GENERIC_EXECUTE, + &hlsa ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get primary domain information + // + + Error = LsaQueryInformationPolicy( hlsa, + PolicyAccountDomainInformation, + ppinfoAccountDomain ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Open account domain handle + // + + Error = SamOpenDomain( hsamServer, + DesiredAccess, + (*ppinfoAccountDomain)->DomainSid, + phsamAccountDomain ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( hsamServer != NULL) { + SamCloseHandle( hsamServer); + } + + if ( hlsa != NULL) { + LsaClose( hlsa); + } + + if ( Error != NO_ERROR && (*ppinfoAccountDomain) != NULL) { + LsaFreeMemory( (*ppinfoAccountDomain)); + *ppinfoAccountDomain = NULL; + } + + if ( Error != NO_ERROR && phsamAccountDomain != NULL) { + SamCloseHandle( *phsamAccountDomain); + *phsamAccountDomain = NULL; + } + + return( Error); +} + + +/* + * Get the SID for an account in the account domain. This method + * uses SAM directly to do the lookup, this is why we need to keep + * around a SAM domain handle. + * + * Returns NERR_RplWkstaNeedsUserAcct if the account is not found and + * !fIsLocalgroup, NERR_RplNeedsRPLUSERAcct if fIsLocalgroup + * + * Use MyFreeSid to free the SID returned in **ppsidAccountSid + */ +DWORD GetAccountSid( + IN SAM_HANDLE hsamAccountDomain, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN WCHAR * pwszAccountName, + OUT PSID * ppsidAccountSid, + IN BOOL fIsLocalgroup, + OUT DWORD * pulRid OPTIONAL + ) +{ + DWORD Error = NO_ERROR; + UNICODE_STRING unistr; + PULONG RelativeIds = NULL; + PSID_NAME_USE Use = NULL; + DWORD cbNewSid = 0; + PUCHAR pcSubAuthorityCount = NULL; + PDWORD pdwLastSubAuthority = NULL; + + RPL_ASSERT( hsamAccountDomain != NULL ); + RPL_ASSERT( pinfoAccountDomain != NULL ); + RPL_ASSERT( pwszAccountName != NULL ); + RPL_ASSERT( ppsidAccountSid != NULL && *ppsidAccountSid == NULL ); + + // + // Lookup name + // + + FillUnicodeString( &unistr, pwszAccountName ); + + Error = SamLookupNamesInDomain( hsamAccountDomain, + 1, + &unistr, + &RelativeIds, + &Use ); + if (Error != NO_ERROR) { + if (Error == STATUS_NONE_MAPPED) { + Error = (fIsLocalgroup) ? NERR_RplNeedsRPLUSERAcct + : NERR_RplWkstaNeedsUserAcct; + } + // TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( RelativeIds != NULL && Use != NULL ); + + if ( Use[0] != ((fIsLocalgroup) ? SidTypeAlias : SidTypeUser) ) { + Error = (fIsLocalgroup) ? NERR_RplNeedsRPLUSERAcct + : NERR_RplWkstaNeedsUserAcct; + goto cleanup; + } + + // + // Construct account SID from RID and domain SID + // + + Error = MyBuildSid( ppsidAccountSid, pinfoAccountDomain, RelativeIds[0] ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( Error == NO_ERROR && pulRid != NULL) { + *pulRid = RelativeIds[0]; + } + + if (RelativeIds != NULL) { + SamFreeMemory( RelativeIds); + } + if (Use != NULL) { + SamFreeMemory( Use); + } + if ( Error != NO_ERROR ) { + MyFreeSid( ppsidAccountSid ); + } + + return( Error); +} + + +/******************************************************************* + + NAME: IsNTFS + + SYNOPSIS: This function checks the given file resource and attempts to + determine if it is on an NTFS partition. + + ENTRY: pwszResource - Pointer to file/directory name in the form + "X:\aaa\bbb\ccc + pfIsNTFS - Pointer to BOOL that will receive the results + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 23-Feb-1994 Copied from acledit\ntfsacl.cxx + +********************************************************************/ + +DWORD IsNTFS( + IN WCHAR * pwszResource, + OUT BOOL * pfIsNTFS ) +{ + DWORD Error = NO_ERROR ; + HANDLE hDrive = NULL ; + WCHAR awchDosDriveName[4]; + WCHAR awchNtDriveName[40]; + UNICODE_STRING unistrNtDriveName; + BYTE buffFsInfo[ sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 200 ] ; + PFILE_FS_ATTRIBUTE_INFORMATION FsInfo = + (PFILE_FS_ATTRIBUTE_INFORMATION)buffFsInfo ; + OBJECT_ATTRIBUTES oa ; + IO_STATUS_BLOCK StatusBlock ; + + RPL_ASSERT( pwszResource != NULL + && lstrlen(pwszResource) >= 3 + && pfIsNTFS != NULL ) ; + + *pfIsNTFS = FALSE ; + + // + // Determine the NT drive name + // + + awchDosDriveName[0] = pwszResource[0]; + awchDosDriveName[1] = pwszResource[1]; + awchDosDriveName[2] = pwszResource[2]; + awchDosDriveName[3] = L'\0'; + RPL_ASSERT( awchDosDriveName[1] == L':' + && awchDosDriveName[2] == L'\\' ); + + unistrNtDriveName.Buffer = awchNtDriveName; + unistrNtDriveName.Length = sizeof(awchNtDriveName); + unistrNtDriveName.MaximumLength = sizeof(awchNtDriveName); + + if (!RtlDosPathNameToNtPathName_U( awchDosDriveName, + &unistrNtDriveName, + NULL, + NULL)) + { + RPL_ASSERT( FALSE ) ; + Error = ERROR_NOT_ENOUGH_MEMORY ; + goto cleanup; + } + RPL_ASSERT( unistrNtDriveName.Length < unistrNtDriveName.MaximumLength ); + unistrNtDriveName.Buffer[unistrNtDriveName.Length/sizeof(WCHAR)] = L'\0'; + + // + // Open the NT volume and query volume information + // + + InitializeObjectAttributes( &oa, + &unistrNtDriveName, + OBJ_CASE_INSENSITIVE, + 0, + 0 ); + Error = NtOpenFile( &hDrive, + SYNCHRONIZE | FILE_READ_DATA, + &oa, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_ALERT); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + Error = NtQueryVolumeInformationFile( + hDrive, + &StatusBlock, + (PVOID) FsInfo, + sizeof(buffFsInfo), + FileFsAttributeInformation ); + if (Error != NO_ERROR) { + if (Error == ERROR_ACCESS_DENIED) { + TREE_ASSERT( ( +"IsNTFS - Unable to determine volume information (access denied) assuming the file system is NTFS" + ) ) ; + Error = NO_ERROR ; + *pfIsNTFS = TRUE ; + } else { + TREE_ASSERT( ( "Error=%d", Error)); + } + goto cleanup; + } + + if ( FsInfo->FileSystemAttributes & FILE_PERSISTENT_ACLS ) + { + *pfIsNTFS = TRUE ; + } + +cleanup: + + /* Close the volume if we ever opened it + */ + if ( hDrive != NULL ) + { + NtClose( hDrive ); + } + + return( Error) ; +} + + +/******************************************************************* + + NAME: RplCreateWkstaAccounts + + SYNOPSIS: This function checks whether a user account exists for + each RPL workstation, and creates one if not. It also + adds all of these accounts to the RPLUSER local group. + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 04-Mar-1994 Created + +********************************************************************/ + +DWORD RplCheckWkstaAccounts( RPL_RPC_HANDLE ServerHandle ) +{ + DWORD Error = 0; + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain = NULL; + SAM_HANDLE hsamAccountDomain = NULL; + PSID psidRPLUSER = NULL; + ULONG ulRidRPLUSER = 0; + SAM_HANDLE hsamRPLUSER = NULL; + DWORD ErrorEnum = NO_ERROR; + RPL_WKSTA_ENUM rplwkstaenum; + RPL_WKSTA_INFO_0_CONTAINER rplwksta0container; + DWORD cEntries = 0; + DWORD hResumeHandle = 0; + DWORD i; + + rplwkstaenum.Level = 0; + rplwkstaenum.WkstaInfo.Level0 = &rplwksta0container; + rplwkstaenum.WkstaInfo.Level0->EntriesRead = 0; + rplwkstaenum.WkstaInfo.Level0->Buffer = NULL; + + Error = GetAccountDomain( &hsamAccountDomain, + &pinfoAccountDomain, + GENERIC_EXECUTE | DOMAIN_CREATE_USER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = GetAccountSid( hsamAccountDomain, + pinfoAccountDomain, + RPL_GROUP_RPLUSER, + &psidRPLUSER, + TRUE, + &ulRidRPLUSER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = SamOpenAlias( hsamAccountDomain, + ALIAS_ADD_MEMBER, + ulRidRPLUSER, + &hsamRPLUSER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + do { + ErrorEnum = NetrRplWkstaEnum( ServerHandle, + NULL, + &rplwkstaenum, + (ULONG)-1, + &cEntries, + &hResumeHandle ); + switch (ErrorEnum) { + case STATUS_MORE_ENTRIES: + case ERROR_MORE_DATA: + case NO_ERROR: + case STATUS_NO_MORE_ENTRIES: + + if (rplwkstaenum.WkstaInfo.Level0->Buffer == NULL) { + // no workstations + break; + } + for ( i = 0; + (Error == NO_ERROR) + && (i < rplwkstaenum.WkstaInfo.Level0->EntriesRead); + i++ ) { + Error = RplAddWkstaAccount( + rplwkstaenum.WkstaInfo.Level0->Buffer[i].WkstaName, + hsamAccountDomain, + pinfoAccountDomain, + hsamRPLUSER ); + } + + MIDL_user_free( rplwkstaenum.WkstaInfo.Level0->Buffer ); + rplwkstaenum.WkstaInfo.Level0->Buffer = NULL; + break; + + default: + Error = ErrorEnum; + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + } while ( Error == STATUS_MORE_ENTRIES || Error == ERROR_MORE_DATA ); + +cleanup: + + /* + * We have no way to free the resume handle + */ + + if ( rplwkstaenum.WkstaInfo.Level0->Buffer != NULL ) { + MIDL_user_free( rplwkstaenum.WkstaInfo.Level0->Buffer ); + } + + if ( pinfoAccountDomain != NULL) { + LsaFreeMemory( pinfoAccountDomain); + } + if (hsamAccountDomain != NULL) { + SamCloseHandle( hsamAccountDomain); + } + + if (hsamRPLUSER != NULL) { + SamCloseHandle( hsamRPLUSER); + } + + if (hsamRPLUSER != NULL) { + SamCloseHandle( hsamRPLUSER); + } + + MyFreeSid( &psidRPLUSER ); + + return( Error); +} + + +/******************************************************************* + + NAME: RplAddWkstaAccount + + SYNOPSIS: This function checks whether a user account exists for + a single workstation, and creates one if not. It also + adds the account to the RPLUSER local group. + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 04-Mar-1994 Created + +********************************************************************/ + +DWORD RplAddWkstaAccount( LPWSTR pszWkstaName, + SAM_HANDLE hsamAccountDomain, + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + SAM_HANDLE hsamRPLUSER ) +{ + DWORD Error = 0; + UNICODE_STRING unistr; + PSID psidUser = NULL; + ULONG ulRidUser = 0; + SAM_HANDLE hsamUser = NULL; + + RPL_ASSERT( pszWkstaName != NULL + && hsamAccountDomain != NULL + && pinfoAccountDomain != NULL + && hsamRPLUSER != NULL ); + + /* + * Get SID of existing account. It would be more efficient to look + * up all the accounts at once. + */ + + Error = GetAccountSid( hsamAccountDomain, + pinfoAccountDomain, + pszWkstaName, + &psidUser, + FALSE, + &ulRidUser ); + if ( Error == NERR_RplWkstaNeedsUserAcct ) + { + /* + * Account doesn't exist, add it + * + * Note that this will fail unless user is administrator or + * at least account operator + */ + + FillUnicodeString( &unistr, pszWkstaName ); + + Error = SamCreateUserInDomain( hsamAccountDomain, + &unistr, + 0x0, + &hsamUser, + &ulRidUser ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = MyBuildSid( &psidUser, pinfoAccountDomain, ulRidUser ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + } + + /* + * Add account to RPLUSER alias + * + * Note that this will fail unless user is administrator or + * at least account operator + */ + + Error = SamAddMemberToAlias( hsamRPLUSER, psidUser ); + switch (Error) { + case STATUS_MEMBER_IN_ALIAS: + Error = NO_ERROR; + // fall through + case NO_ERROR: + break; + default: + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + +cleanup: + + MyFreeSid( &psidUser ); + + if (hsamUser != NULL) { + SamCloseHandle( hsamUser); + } + + return( Error); +} + + +/******************************************************************* + + NAME: RplAddRPLUSERGroup + + SYNOPSIS: This function checks whether the RPLUSER local group + exists, and creates it if it doesn't. + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 03-Mar-1994 Created + +********************************************************************/ + +DWORD RplAddRPLUSERGroup( VOID ) +{ + DWORD Error = 0; + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain = NULL; + SAM_HANDLE hsamAccountDomain = NULL; + PSID psidRPLUSER = NULL; + UNICODE_STRING unistr; + SAM_HANDLE hsamRPLUSER = NULL; + ULONG ulRidRPLUSER = 0; + + Error = GetAccountDomain( &hsamAccountDomain, + &pinfoAccountDomain, + GENERIC_EXECUTE | DOMAIN_CREATE_ALIAS ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = GetAccountSid( hsamAccountDomain, + pinfoAccountDomain, + RPL_GROUP_RPLUSER, + &psidRPLUSER, + TRUE, + NULL ); + if ( Error == NO_ERROR) { + // RPLUSER already exists + goto cleanup; + } else if (Error != NERR_RplNeedsRPLUSERAcct) + { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + FillUnicodeString( &unistr, RPL_GROUP_RPLUSER ); + + Error = SamCreateAliasInDomain( hsamAccountDomain, + &unistr, + 0x0, + &hsamRPLUSER, + &ulRidRPLUSER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( pinfoAccountDomain != NULL) { + LsaFreeMemory( pinfoAccountDomain); + } + if (hsamAccountDomain != NULL) { + SamCloseHandle( hsamAccountDomain); + } + + if (hsamRPLUSER != NULL) { + SamCloseHandle( hsamRPLUSER); + } + + MyFreeSid( &psidRPLUSER ); + + return( Error); +} + +VOID FillUnicodeString( PUNICODE_STRING punistr, + LPWSTR lpwsz ) +{ + ASSERT( punistr != NULL && lpwsz == NULL ); + punistr->Buffer = lpwsz; + punistr->Length = lstrlenW(lpwsz) * sizeof(WCHAR); + punistr->MaximumLength = punistr->Length + sizeof(WCHAR); +} + +DWORD MyBuildSid( OUT PSID * ppsidAccountSid, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN ULONG ulRid ) +{ + DWORD Error = 0; + DWORD cbNewSid = 0; + PUCHAR pcSubAuthorityCount = NULL; + PDWORD pdwLastSubAuthority = NULL; + + ASSERT( ppsidAccountSid != NULL && pinfoAccountDomain != NULL && ulRid != 0 ); + + cbNewSid = GetLengthSid(pinfoAccountDomain->DomainSid) + sizeof(DWORD); + *ppsidAccountSid = TREE_ALLOC( cbNewSid ); + if ( *ppsidAccountSid == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + if ( !CopySid( cbNewSid, *ppsidAccountSid, pinfoAccountDomain->DomainSid)) { + Error = GetLastError(); + goto cleanup; + } + + pcSubAuthorityCount = GetSidSubAuthorityCount( *ppsidAccountSid ); + RPL_ASSERT( pcSubAuthorityCount != NULL ); + (*pcSubAuthorityCount)++; + pdwLastSubAuthority = GetSidSubAuthority( + *ppsidAccountSid, (DWORD)((*pcSubAuthorityCount)-1) ); + RPL_ASSERT( pdwLastSubAuthority != NULL ); + *pdwLastSubAuthority = ulRid; + +cleanup: + + if (Error != NO_ERROR) { + MyFreeSid( ppsidAccountSid ); + } + + return( Error); +} + +VOID MyFreeSid( IN OUT PSID * ppsid ) +{ + RPL_ASSERT( ppsid != NULL ); + + if ( *ppsid != NULL) { + TREE_FREE( *ppsid ); + *ppsid = NULL; + } +} diff --git a/private/net/svcdlls/rpl/rplinst/security.h b/private/net/svcdlls/rpl/rplinst/security.h new file mode 100644 index 000000000..403aa7fd1 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/security.h @@ -0,0 +1,17 @@ +// +// #define RPL_RPC_HANDLE RPL_HANDLE +// + +#define NetrRplWkstaEnum MyNetrRplWkstaEnum +#define MIDL_user_free MyMIDL_user_free + +#include <rplsvc_s.h> // RPL_WKSTA_ENUM + +#include "..\server\security.h" + +#undef TREE_ALLOC +#undef TREE_FREE +#undef TREE_ASSERT +#define TREE_ALLOC(x) (malloc( (x) )) +#define TREE_FREE(x) (free( (x) )) +#define TREE_ASSERT( x ) ASSERT(FALSE) diff --git a/private/net/svcdlls/rpl/rplinst/sources b/private/net/svcdlls/rpl/rplinst/sources new file mode 100644 index 000000000..60cf3e52f --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/sources @@ -0,0 +1,38 @@ +MAJORCOMP=net +MINORCOMP=rplinst + +TARGETPATH=obj +TARGETNAME=rplinst +TARGETTYPE=PROGRAM +NTTARGETFILE0=nlstxt.h nlstxt.mc nlstxt.rc + +TARGETLIBS= \ + ..\lib\obj\*\rpllib.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\samlib.lib \ + $(BASEDIR)\public\sdk\lib\*\wsock32.lib \ + $(BASEDIR)\public\sdk\lib\*\jet500.lib + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\server;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + rplinst.rc \ + rplinst.c \ + security.c \ + tree.c \ + debug.c \ + querydir.c + + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 -DRPL_RPLCNV + +UMTYPE=console + diff --git a/private/net/svcdlls/rpl/rplinst/tree.c b/private/net/svcdlls/rpl/rplinst/tree.c new file mode 100644 index 000000000..08b3a942c --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/tree.c @@ -0,0 +1,2 @@ + +#include "..\server\tree.c" diff --git a/private/net/svcdlls/rpl/rplinst/tree.h b/private/net/svcdlls/rpl/rplinst/tree.h new file mode 100644 index 000000000..d68d34917 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/tree.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.h + +Abstract: + + Exports from tree.c + +Author: + + Jon Newman (jonn) 23 - November - 1993 + +Revision History: + + Vladimir Z. Vulovic (vladimv) 02 - December - 1993 + Integrated with the rest of RPL service code. + +--*/ + +DWORD RplTreeCopy( IN PWCHAR Source, IN PWCHAR Target); +DWORD RplTreeDelete( IN PWCHAR Target); +DWORD RplMakeDir( IN PWCHAR Target); + + diff --git a/private/net/svcdlls/rpl/rplinst/treei.h b/private/net/svcdlls/rpl/rplinst/treei.h new file mode 100644 index 000000000..3489cd759 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/treei.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.h + +Abstract: + + Internal definitions from tree.c + +Author: + + Jon Newman (jonn) 16 - February - 1994 + +Revision History: + + Jon Newman (jonn) 16 - February - 1994 + Added RplGrant*Perms primitives + +--*/ + +typedef DWORD (RPL_TREE_CALLBACK)( PWCHAR pszPath, PVOID * ppv); + +#define RPL_TREE_COPY_DACL 0x1 // not yet implemented +#define RPL_TREE_COPY_SACL 0x2 // not yet implemented +#define RPL_TREE_AUXILIARY 0x2000 // perform callback action +#define RPL_TREE_COPY 0x4000 +#define RPL_TREE_DELETE 0x8000 + +// +// Forward declarations +// + +DWORD RplDoTree( + PWCHAR Source, + PWCHAR Target, + DWORD Flags, + PWCHAR Buffer, + DWORD BufferSize, + RPL_TREE_CALLBACK AuxiliaryCallback, + PVOID AuxiliaryBlock + ); + +VOID LoadError( + PWCHAR FilePath, + LPVOID Buffer, + DWORD BufferSize + ); + |