352 lines
11 KiB
C++
352 lines
11 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
|
/*
|
|
|
|
|
|
File Replication Sample
|
|
File Replication Client Utility
|
|
|
|
FILE: FileRep.cpp
|
|
|
|
USAGE:
|
|
FileRep [server name] [remote file] [local file] <options...>
|
|
|
|
OPTIONS:
|
|
-n network_address
|
|
-p protocol_sequence
|
|
-e endpoint
|
|
-d print messages
|
|
|
|
PURPOSE: Client utility for the file replication application
|
|
|
|
FUNCTIONS: main() - binds to replication server and requests
|
|
file replication.
|
|
|
|
COMMENTS:
|
|
|
|
*/
|
|
|
|
#include "common.h"
|
|
|
|
#include <process.h>
|
|
#include <rpc.h>
|
|
#include <Ntdsapi.h>
|
|
|
|
#include "Service.h"
|
|
|
|
// header file generated by MIDL compiler
|
|
#include "FileRepClient.h"
|
|
|
|
/*
|
|
FUNCTION: PrintUsage()
|
|
|
|
PURPOSE: Prints help information.
|
|
|
|
PARAMETERS:
|
|
ProgName - name of the executable
|
|
|
|
RETURN VALUE:
|
|
none
|
|
|
|
COMMENTS:
|
|
*/
|
|
void PrintUsage(TCHAR *ProgName) {
|
|
_tprintf_s(TEXT("%s - File Replication Client Utility\n\n"), ProgName);
|
|
_tprintf_s(TEXT("Usage: %s [server name] [remote file] [local file] <options...> \n\n"), ProgName);
|
|
_tprintf_s(TEXT("Options:\n"));
|
|
_tprintf_s(TEXT(" -p protocol_sequence\n"));
|
|
_tprintf_s(TEXT(" -n network_address\n"));
|
|
_tprintf_s(TEXT(" -e endpoint\n"));
|
|
_tprintf_s(TEXT(" -d print messages\n"));
|
|
}
|
|
|
|
/*
|
|
FUNCTION: main()
|
|
|
|
PURPOSE: Main funciton for the utility. It binds to the local server
|
|
and requests file replication.
|
|
|
|
PARAMETERS:
|
|
dwArgc - number of command line arguments
|
|
lpszArgv - array of command line arguments
|
|
|
|
RETURN VALUE:
|
|
none
|
|
|
|
COMMENTS:
|
|
|
|
*/
|
|
INT _cdecl main(int argc, char **argv) {
|
|
|
|
INT i;
|
|
RPC_STATUS rpcstatus;
|
|
|
|
// Controlls printing out of messages.
|
|
BOOL bDebug = FALSE;
|
|
|
|
// Explicit binding handle to the client system service.
|
|
handle_t hFileRepClient = NULL;
|
|
|
|
// These are the default values for extablishing connections.
|
|
// Default connection is to a local server over local rpc.
|
|
RPC_STR pszProtocolSequence = (RPC_STR)TEXT("ncalrpc");
|
|
RPC_STR pszNetworkAddress = NULL;
|
|
|
|
// An empty endpoint string is used, since we are going to
|
|
// connect to the endpoint dynamically generated by the
|
|
// RPC run-time library. Server calls RpcServerUseProtseq to
|
|
// obtain a binding hadnle and a dynamic endpoint.
|
|
RPC_STR pszEndpoint = (RPC_STR)TEXT("");
|
|
|
|
RPC_STR pszUuid = NULL;
|
|
RPC_STR pszOptions = NULL;
|
|
RPC_STR pszStringBinding = NULL;
|
|
|
|
RPC_STR pszServerPrincipalName = NULL;
|
|
|
|
LPTSTR ServerName = NULL;
|
|
LPTSTR RemoteFileName = NULL;
|
|
LPTSTR LocalFileName = NULL;
|
|
|
|
INT nNumArgs;
|
|
|
|
#ifndef NO_SEC
|
|
// Quality of service structure to ensure authentication.
|
|
RPC_SECURITY_QOS SecurityQOS;
|
|
|
|
// Used in generating the principal name for the local system service.
|
|
TCHAR Name[128];
|
|
DWORD cbName = sizeof(Name);
|
|
|
|
TCHAR DomainName[128];
|
|
DWORD cbDomainName = sizeof(DomainName);
|
|
SID_NAME_USE Use;
|
|
|
|
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
|
|
BYTE sidBuffer[100];
|
|
PSID pSID = (PSID)&sidBuffer;
|
|
#endif
|
|
|
|
// Get a common handle on the command line arguments for both
|
|
// UNICODE and ASCII
|
|
#ifdef _UNICODE
|
|
LPWSTR *szArgList = CommandLineToArgvW(GetCommandLine(), &nNumArgs);
|
|
if (NULL == szArgList) {
|
|
_tprintf_s(TEXT("FileRep main: CommandLineToArgW failed"));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
#else
|
|
char **szArgList = argv;
|
|
nNumArgs = argc;
|
|
#endif
|
|
|
|
// Check that the correct number of arguments is given.
|
|
if(nNumArgs<4){
|
|
PrintUsage(szArgList[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// Extract the required arguments.
|
|
ServerName = szArgList[1];
|
|
RemoteFileName = szArgList[2];
|
|
LocalFileName = szArgList[3];
|
|
|
|
// Allow the user to override settings with command line switches.
|
|
for (i = 4; i < nNumArgs; i++) {
|
|
// Well-formed argument switches start with '/' or '-' and are
|
|
// two characters long.
|
|
if (((*szArgList[i] == TEXT('-')) || (*szArgList[i] == TEXT('/'))) && _tcsclen(szArgList[i]) == 2) {
|
|
|
|
switch (_totlower(*(szArgList[i]+1))) {
|
|
|
|
case TEXT('p'):
|
|
|
|
// Override protocol sequence.
|
|
|
|
// Check that the next argument exists and is not a
|
|
// switch.
|
|
if(i+1 < nNumArgs && *szArgList[i+1] != TEXT('-') && *szArgList[i+1] != TEXT('/')) {
|
|
pszProtocolSequence = (RPC_STR)szArgList[++i];
|
|
}
|
|
// Otherwise we have an empty protocol sequence.
|
|
else {
|
|
// We do not allow an empty protocol sequence.
|
|
_tprintf_s(TEXT("Protocol sequence can't be \"\".\n"));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
break;
|
|
|
|
case TEXT('n'):
|
|
|
|
// Override the network address.
|
|
if(i+1 < nNumArgs && *szArgList[i+1] != TEXT('-') && *szArgList[i+1] != TEXT('/')) {
|
|
pszNetworkAddress = (RPC_STR)szArgList[++i];
|
|
}
|
|
else {
|
|
pszNetworkAddress = (RPC_STR)TEXT("");
|
|
}
|
|
|
|
break;
|
|
|
|
case TEXT('e'):
|
|
|
|
// Override the endpoint.
|
|
if(i+1 < nNumArgs && *szArgList[i+1] != TEXT('-') && *szArgList[i+1] != TEXT('/')) {
|
|
pszEndpoint = (RPC_STR)szArgList[++i];
|
|
}
|
|
else {
|
|
pszEndpoint = (RPC_STR)TEXT("");
|
|
}
|
|
|
|
break;
|
|
|
|
case TEXT('d'):
|
|
// Turn on debugging.
|
|
bDebug = TRUE;
|
|
break;
|
|
|
|
case TEXT('h'):
|
|
case TEXT('?'):
|
|
default:
|
|
PrintUsage(szArgList[0]);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
}
|
|
else {
|
|
PrintUsage(szArgList[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
// Concatenate the elements of
|
|
// the string binding into the proper sequence.
|
|
rpcstatus = RpcStringBindingCompose(pszUuid,
|
|
pszProtocolSequence,
|
|
pszNetworkAddress,
|
|
pszEndpoint,
|
|
pszOptions,
|
|
&pszStringBinding);
|
|
if(bDebug){
|
|
_tprintf_s(TEXT("RpcStringBindingCompose returned 0x%x\n"), rpcstatus);
|
|
_tprintf_s(TEXT("pszStringBinding = %s\n"), pszStringBinding);
|
|
}
|
|
RPC_EEINFO_EXIT_IF_FAIL(rpcstatus, TEXT("RpcStringBindingCompose"));
|
|
|
|
// Set the binding handle that will be used to bind to the server.
|
|
rpcstatus = RpcBindingFromStringBinding(pszStringBinding, &hFileRepClient);
|
|
if(bDebug) _tprintf_s(TEXT("RpcBindingFromStringBinding returned 0x%x\n"), rpcstatus);
|
|
RPC_EEINFO_EXIT_IF_FAIL(rpcstatus, TEXT("RpcBindingFromStringBinding"));
|
|
|
|
// Free the binding string.
|
|
rpcstatus = RpcStringFree(&pszStringBinding);
|
|
ASSERT(rpcstatus == RPC_S_OK);
|
|
|
|
#ifndef NO_SEC
|
|
// Specify quality of service parameters.
|
|
SecurityQOS.Version = RPC_C_SECURITY_QOS_VERSION;
|
|
SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
|
|
// Dynamic identity tracking is more efficient for a single LRPC call.
|
|
SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
|
|
// The client system service needs to impersonate the security context
|
|
// of the client utility on the remote systems where it may replicate
|
|
// files from.
|
|
// We need to impersonate with level delegate, since the server system
|
|
// service will need to impersonate the user further.
|
|
SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_DELEGATE;
|
|
|
|
// Generate the principal name for the local system service.
|
|
// We can't just use the a string constant, because then
|
|
// we rely on a particular English-language representation of the
|
|
// principal.
|
|
|
|
if (AllocateAndInitializeSid(&SIDAuth, 1,
|
|
SECURITY_NETWORK_SERVICE_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pSID) == 0) {
|
|
printf_s("AllocateAndInitializeSid failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (LookupAccountSid(NULL, // name of local or remote computer
|
|
pSID, // security identifier
|
|
Name, // account name buffer
|
|
&cbName, // size of account name buffer
|
|
DomainName, // domain name
|
|
&cbDomainName, // size of domain name buffer
|
|
&Use) == 0) { // SID type
|
|
printf_s("LookupAccountSid failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if(bDebug) _tprintf_s(TEXT("Server \"magic name\" is %s\n"), Name);
|
|
|
|
pszServerPrincipalName = (RPC_STR)Name;
|
|
|
|
// Set authentication and authorisation information for
|
|
// the binding handle.
|
|
// By speciying NULL for the 5th parameter we use the security login
|
|
// context for the current address space.
|
|
// The security level is "PRIVACY" since it is the only level
|
|
// provided by LRPC.
|
|
// We are assured of talking to a local service running with
|
|
// system privileges.
|
|
rpcstatus = RpcBindingSetAuthInfoEx(hFileRepClient, pszServerPrincipalName, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_WINNT, NULL, NULL, &SecurityQOS);
|
|
RPC_EEINFO_EXIT_IF_FAIL(rpcstatus, TEXT("RpcBindingSetAuthInfo"));
|
|
|
|
#endif
|
|
|
|
// Make the RPC to request file replication.
|
|
RpcTryExcept {
|
|
if(bDebug) _tprintf_s(TEXT("Calling the remote procedure RequestFile(hFileRepClient, %s, %s, %s)\n"), ServerName, RemoteFileName, LocalFileName);
|
|
|
|
RequestFile(hFileRepClient, ServerName, RemoteFileName, LocalFileName);
|
|
|
|
if(bDebug) _tprintf_s(TEXT("RequestFile() finished\n"));
|
|
}
|
|
// Return "non-fatal" errors. Catching fatal errors
|
|
// makes it harder to debug.
|
|
RpcExcept ( ( (RpcExceptionCode() != STATUS_ACCESS_VIOLATION) &&
|
|
(RpcExceptionCode() != STATUS_DATATYPE_MISALIGNMENT) &&
|
|
(RpcExceptionCode() != STATUS_PRIVILEGED_INSTRUCTION) &&
|
|
(RpcExceptionCode() != STATUS_ILLEGAL_INSTRUCTION) &&
|
|
(RpcExceptionCode() != STATUS_BREAKPOINT))
|
|
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
|
|
|
|
PrintProcFailureEEInfo(TEXT("RequestFile"), RpcExceptionCode());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
RpcEndExcept;
|
|
|
|
// Free the binding.
|
|
rpcstatus = RpcBindingFree((VOID **)&hFileRepClient);
|
|
ASSERT(rpcstatus == RPC_S_OK);
|
|
|
|
if(bDebug) _tprintf_s(TEXT("Success!\n"));
|
|
|
|
return(EXIT_SUCCESS);
|
|
|
|
} // end main()
|
|
|
|
/*
|
|
MIDL allocate() and free()
|
|
*/
|
|
|
|
VOID __RPC_FAR * __RPC_API midl_user_allocate(size_t len) {
|
|
return(AutoHeapAlloc(len));
|
|
}
|
|
|
|
VOID __RPC_API midl_user_free(VOID __RPC_FAR * ptr) {
|
|
if(ptr != NULL) {
|
|
AutoHeapFree(ptr);
|
|
}
|
|
}
|
|
|
|
// end FileRep.cpp
|