// 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: -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 #include #include #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] \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