Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

516 lines
16 KiB

/*++
Copyright (c) 1992-1993 Microsoft Corporation
Module Name:
ReplSet.c
Abstract:
This file contains NetrReplSetInfo().
Author:
John Rogers (JohnRo) 10-Feb-1992
Environment:
User Mode - Win32
Portable to any flat, 32-bit environment. (Uses Win32 typedefs.)
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
10-Feb-1992 JohnRo
Created.
16-Feb-1992 JohnRo
Use ReplIs{Interval,GuardTime,Pulse,Random}Valid() macros.
12-Mar-1992 JohnRo
Update registry with new values.
Added support for setinfo info levels in ReplIsApiRecordValid().
24-Mar-1992 JohnRo
Renamed many ReplGlobal vars to ReplConfig vars.
22-Jul-1992 JohnRo
RAID 2274: repl svc should impersonate caller.
06-Aug-1992 JohnRo
RAID 2252: repl should prevent export on Windows/NT.
27-Aug-1992 JohnRo
RAID 4611: Set ParmError if we get an invalid info level (e.g. on
a bad import/export list).
22-Oct-92 jimkel
Added a call to InitClientList() <- in master.c
Added a call to InitClientImpList() <- in client.c
These calls cannonicalize the import and export lists and
store their cannonicalized forms for internal replicator use.
16-Nov-1992 JohnRo
RAID 1537: repl APIs in wrong role kill service.
01-Dec-1992 JohnRo
RAID 3844: remote NetReplSetInfo uses local machine type.
16-Dec-1992 JohnRo
RAID 1513: Repl does not maintain ACLs (also fix timestamps).
06-Jan-1993 JohnRo
Repl WAN support (get rid of repl name list limits).
01-Apr-1993 JohnRo
Made changes suggested by PC-LINT 5.0
Use NetpKdPrint() where possible.
--*/
// These must be included first:
#include <windef.h> // IN, DWORD, etc.
#include <lmcons.h> // LAN Manager common definitions
#include <rpc.h> // Needed by <repl.h>.
// These may be included in any order:
#include <client.h> // RCGlobalExportList, etc.
#include <confname.h> // REPL_KEYWORD_ equates.
#include <lmrepl.h> // LPREPL_INFO_0.
#include <master.h> // RMGlobalImportList, etc.
#include <netdebug.h> // NetpAssert().
#include <netlib.h> // NetpMemoryFree(), NetpSetParmError().
#include <netlock.h> // ACQUIRE_LOCK(), etc.
#include <prefix.h> // PREFIX_ equates.
#include <repl.h> // My prototype (in MIDL-generated .h file).
#include <replconf.h> // ReplConfig routines.
#include <repldefs.h> // ReplIsRoleValid(), etc.
#include <replgbl.h> // ReplGlobal and ReplConfig variables.
#include <rpcutil.h> // NetpImpersonateClient(), NetpRevertToSelf().
#include <tstring.h> // NetpAlloc{type}From{type}, STRCPY(), TCHAR_EOS, etc.
#include <winerror.h> // ERROR_ equates, NO_ERROR.
//
// Set config data for the replicator. Only callable when
// the replicator service is started.
//
NET_API_STATUS
NetrReplSetInfo (
IN LPTSTR UncServerName OPTIONAL,
IN DWORD Level,
IN LPCONFIG_CONTAINER Buf,
OUT LPDWORD ParmError OPTIONAL
)
{
NET_API_STATUS ApiStatus;
DWORD OldRole;
BOOL Impersonated = FALSE;
BOOL Locked = FALSE;
UNREFERENCED_PARAMETER( UncServerName );
//
// Check for caller's errors.
//
NetpSetParmError( PARM_ERROR_UNKNOWN ); // Set in case we get bad level.
#define RETURN_BAD_PARM( parm_error ) \
{ \
NetpSetParmError( parm_error ); \
ApiStatus = ERROR_INVALID_PARAMETER; \
goto Cleanup; /* Don't forget to release lock... */ \
}
if (Buf == NULL) {
RETURN_BAD_PARM( PARM_ERROR_UNKNOWN )
/*NOTREACHED*/
}
if ( !ReplConfigIsLevelValid( Level, TRUE ) ) { // Yes, allow setinfo lvl
ApiStatus = ERROR_INVALID_LEVEL;
goto Cleanup;
}
//
// We need to check all fields before we set any.
//
if ( !ReplConfigIsApiRecordValid (
Level,
(LPVOID) (Buf->Info0), // BUGBUG: nonportable?
ParmError ) ) {
ApiStatus = ERROR_INVALID_PARAMETER; // ParmError already set.
goto Cleanup;
}
//
// Impersonate caller, so security check (write to registry) reflects
// the client's process, not the repl service process.
//
ApiStatus = NetpImpersonateClient();
if (ApiStatus != NO_ERROR) {
goto Cleanup;
}
Impersonated = TRUE;
//
// Get exclusive lock on config variables, so we don't get confused by
// another API thread. This also locks the matching registry data.
//
ACQUIRE_LOCK( ReplConfigLock );
Locked = TRUE;
IF_DEBUG( REPLAPI ) {
NetpKdPrint(( PREFIX_REPL
"NetrReplSetInfo(server side): got config lock OK.\n" ));
}
//
// Based on info level, do additional checking and updates.
//
switch (Level) {
case 0 :
{
LPREPL_INFO_0 Buffer = (LPVOID) (Buf->Info0);
if ( !ReplConfigIsRoleAllowed( NULL, Buffer->rp0_role ) ) {
RETURN_BAD_PARM( 1 ) // Role is first field in struct.
/*NOTREACHED*/
}
//
// Change permanent copy of registry data for the replicator.
// This acts as our security check, too.
//
ApiStatus = ReplConfigWrite(
NULL, // no server name
Buffer->rp0_role,
Buffer->rp0_exportpath,
Buffer->rp0_exportlist,
Buffer->rp0_importpath,
Buffer->rp0_importlist,
Buffer->rp0_logonusername,
Buffer->rp0_interval,
Buffer->rp0_pulse,
Buffer->rp0_guardtime,
Buffer->rp0_random );
if (ApiStatus != NO_ERROR) {
goto Cleanup; // Don't forget to release lock...
}
//
// Change in-memory copy of registry data for the replicator.
//
#define SET_LIST( globalName, fieldName ) \
{ \
LPTSTR Source = Buffer->rp0_ ## fieldName; \
if ( (Source!=NULL) && ( (*Source) != TCHAR_EOS ) ) { \
if (globalName != NULL) { \
if (STRICMP(globalName, Source) == 0) { \
/* OK as is; nothing to do. */ \
} else { \
/* Old and new are different. Free old and alloc new. */ \
NetpMemoryFree( globalName ); \
globalName = NetpAllocTStrFromTStr( Source ); \
if (globalName == NULL) { \
ApiStatus = ERROR_NOT_ENOUGH_MEMORY; \
goto Cleanup; /* Don't forget to release lock... */ \
} \
} \
} else { \
/* New name but no old name. Alloc new. */ \
globalName = NetpAllocTStrFromTStr( Source ); \
if (globalName == NULL) { \
ApiStatus = ERROR_NOT_ENOUGH_MEMORY; \
goto Cleanup; /* Don't forget to release lock... */ \
} \
} \
} else if (globalName != NULL) { \
/* Old list but no new list. Free old. */ \
NetpMemoryFree( globalName ); \
globalName = NULL; \
} \
}
#define SET_PATH( globalName, fieldName ) \
{ \
LPTSTR Source = Buffer->rp0_ ## fieldName; \
NetpAssert( globalName != NULL ); \
if ( (Source!=NULL) && ( (*Source) != TCHAR_EOS ) ) { \
(void) STRCPY( globalName, Source ); \
} else { \
globalName[0] = TCHAR_EOS; \
} \
}
// Note: because of possible shock to other code, set role last.
SET_PATH( ReplConfigExportPath, exportpath );
// The UI will update REPL$ share to reflect new export path.
// Repl svc may not be running as admin so can't do NetShareAdd?
// BUGBUG: Hey, we impersonated, so maybe we can!
SET_LIST( ReplConfigExportList, exportlist );
SET_PATH( ReplConfigImportPath, importpath );
RCGlobalFsTimeResolutionSecs =
ReplGetFsTimeResolutionSecs( ReplConfigImportPath );
SET_LIST( ReplConfigImportList, importlist );
// BUGBUG: Set logonusername!!!
ReplConfigInterval = Buffer->rp0_interval;
ReplConfigPulse = Buffer->rp0_pulse;
ReplConfigGuardTime = Buffer->rp0_guardtime;
ReplConfigRandom = Buffer->rp0_random;
//
// If the role is not changing make sure the internal
// variables are updated.
//
OldRole = ReplConfigRole;
IF_DEBUG( REPLAPI ) {
NetpKdPrint(( PREFIX_REPL
"NetrReplSetInfo(server side): initing lists.\n" ));
}
if ( ReplRoleIncludesExport(Buffer->rp0_role)
&& ReplRoleIncludesExport(OldRole) ) {
if (RMGlobalImportList != NULL) {
NetpMemoryFree( RMGlobalImportList );
RMGlobalImportList = NULL;
}
// NOTE: ReplInitAnyList() assumes caller has config data lock.
ApiStatus = ReplInitAnyList(
(LPCTSTR) ReplConfigExportList, // uncanon
& RMGlobalImportList, // canon list: alloc and set ptr
(LPCTSTR) REPL_KEYWORD_EXPLIST, // config keyword name
& RMGlobalImportCount ); // set entry count too
if ( ApiStatus != NO_ERROR )
goto Cleanup;
}
if ( ReplRoleIncludesImport(Buffer->rp0_role)
&& ReplRoleIncludesImport(OldRole) ) {
if (RCGlobalExportList != NULL) {
NetpMemoryFree( RCGlobalExportList );
RCGlobalExportList = NULL;
}
// NOTE: ReplInitAnyList() assumes caller has config data lock.
ApiStatus = ReplInitAnyList(
(LPCTSTR) ReplConfigImportList, // uncanon
& RCGlobalExportList, // canon list: alloc and set ptr
(LPCTSTR) REPL_KEYWORD_IMPLIST, // config keyword name
& RCGlobalExportCount ); // set entry count too
if ( ApiStatus != NO_ERROR )
goto Cleanup;
}
//
// Change the role, including all the side-effects (like
// starting and stopping threads). Also set ReplConfigRole.
// NOTE: ReplChangeRole assumes caller has exclusive lock on
// ReplConfigLock.
//
IF_DEBUG( REPLAPI ) {
NetpKdPrint(( PREFIX_REPL
"NetrReplSetInfo(server side): changing role.\n" ));
}
ApiStatus = ReplChangeRole( Buffer->rp0_role );
NetpAssert( ApiStatus == NO_ERROR );
IF_DEBUG( REPLAPI ) {
NetpKdPrint(( PREFIX_REPL
"NetrReplSetInfo(server side): "
"done changing role.\n" ));
}
// Don't forget to unimpersonate.
}
break;
case 1000 :
{
LPREPL_INFO_1000 Buffer = (LPVOID) (Buf->Info1000);
DWORD NewValue = Buffer->rp1000_interval;
if ( !ReplIsIntervalValid( NewValue ) ) {
RETURN_BAD_PARM( 1 ) // first field in structure.
/*NOTREACHED*/
}
//
// Change permanent copy of registry data for the replicator.
// This acts as our security check, too.
//
ApiStatus = ReplConfigWrite(
NULL, // no server name
ReplConfigRole,
ReplConfigExportPath,
ReplConfigExportList,
ReplConfigImportPath,
ReplConfigImportList,
ReplConfigLogonUserName,
NewValue, // new interval
ReplConfigPulse,
ReplConfigGuardTime,
ReplConfigRandom );
if (ApiStatus != NO_ERROR) {
goto Cleanup; // Don't forget to release lock...
}
ReplConfigInterval = NewValue;
// Don't forget to unlock and unimpersonate.
// BUGBUG: Notify anybody?
}
break;
case 1001 :
{
LPREPL_INFO_1001 Buffer = (LPVOID) (Buf->Info1001);
DWORD NewValue = Buffer->rp1001_pulse;
if ( !ReplIsPulseValid( NewValue ) ) {
RETURN_BAD_PARM( 1 ) // first field in structure.
/*NOTREACHED*/
}
//
// Change permanent copy of registry data for the replicator.
// This acts as our security check, too.
//
ApiStatus = ReplConfigWrite(
NULL, // no server name
ReplConfigRole,
ReplConfigExportPath,
ReplConfigExportList,
ReplConfigImportPath,
ReplConfigImportList,
ReplConfigLogonUserName,
ReplConfigInterval,
NewValue, // new pulse
ReplConfigGuardTime,
ReplConfigRandom );
if (ApiStatus != NO_ERROR) {
goto Cleanup; // Don't forget to release lock...
}
ReplConfigPulse = NewValue;
// Don't forget to unlock and unimpersonate.
// BUGBUG: Notify anybody?
}
break;
case 1002 :
{
LPREPL_INFO_1002 Buffer = (LPVOID) (Buf->Info1002);
DWORD NewValue = Buffer->rp1002_guardtime;
if ( !ReplIsGuardTimeValid( NewValue ) ) {
RETURN_BAD_PARM( 1 ) // first field in structure.
/*NOTREACHED*/
}
//
// Change permanent copy of registry data for the replicator.
// This acts as our security check, too.
//
ApiStatus = ReplConfigWrite(
NULL, // no server name
ReplConfigRole,
ReplConfigExportPath,
ReplConfigExportList,
ReplConfigImportPath,
ReplConfigImportList,
ReplConfigLogonUserName,
ReplConfigInterval,
ReplConfigPulse,
NewValue, // new guard time
ReplConfigRandom );
if (ApiStatus != NO_ERROR) {
goto Cleanup; // Don't forget to release lock...
}
ReplConfigGuardTime = NewValue;
// Don't forget to unlock and unimpersonate.
// BUGBUG: Notify anybody?
}
break;
case 1003 :
{
LPREPL_INFO_1003 Buffer = (LPVOID) (Buf->Info1003);
DWORD NewValue = Buffer->rp1003_random;
if ( !ReplIsRandomValid( NewValue ) ) {
RETURN_BAD_PARM( 1 ) // first field in structure.
/*NOTREACHED*/
}
//
// Change permanent copy of registry data for the replicator.
// This acts as our security check, too.
//
ApiStatus = ReplConfigWrite(
NULL, // no server name
ReplConfigRole,
ReplConfigExportPath,
ReplConfigExportList,
ReplConfigImportPath,
ReplConfigImportList,
ReplConfigLogonUserName,
ReplConfigInterval,
ReplConfigPulse,
ReplConfigGuardTime,
NewValue ); // new random time
if (ApiStatus != NO_ERROR) {
goto Cleanup; // Don't forget to release lock...
}
ReplConfigRandom = NewValue;
// Don't forget to unlock and unimpersonate.
}
break;
default :
NetpAssert( FALSE ); // Can't get here.
}
//
// All done.
//
Cleanup:
if (Impersonated) {
(VOID) NetpRevertToSelf();
}
if (Locked) {
RELEASE_LOCK( ReplConfigLock );
}
if (ApiStatus == NO_ERROR) {
NetpSetParmError( PARM_ERROR_NONE );
}
return (ApiStatus);
} // NetpReplSetInfo