/*++ 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 // IN, DWORD, etc. #include // LAN Manager common definitions #include // Needed by . // These may be included in any order: #include // RCGlobalExportList, etc. #include // REPL_KEYWORD_ equates. #include // LPREPL_INFO_0. #include // RMGlobalImportList, etc. #include // NetpAssert(). #include // NetpMemoryFree(), NetpSetParmError(). #include // ACQUIRE_LOCK(), etc. #include // PREFIX_ equates. #include // My prototype (in MIDL-generated .h file). #include // ReplConfig routines. #include // ReplIsRoleValid(), etc. #include // ReplGlobal and ReplConfig variables. #include // NetpImpersonateClient(), NetpRevertToSelf(). #include // NetpAlloc{type}From{type}, STRCPY(), TCHAR_EOS, etc. #include // 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