CLOUDSTACK-7234: stop sending smb credentials to Hyper-v agent

This commit is contained in:
Anshul Gangwar 2014-07-30 12:21:43 +05:30 committed by Devdeep Singh
parent 97f5281cf4
commit 0ecc9f79af
4 changed files with 88 additions and 261 deletions

View File

@ -129,23 +129,23 @@ public class StoragePoolVO implements StoragePool {
}
public StoragePoolVO() {
this.status = StoragePoolStatus.Initial;
status = StoragePoolStatus.Initial;
}
public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type, long dataCenterId, Long podId, long availableBytes, long capacityBytes,
String hostAddress, int port, String hostPath) {
this.name = name;
this.id = poolId;
id = poolId;
this.uuid = uuid;
this.poolType = type;
poolType = type;
this.dataCenterId = dataCenterId;
this.usedBytes = availableBytes;
usedBytes = availableBytes;
this.capacityBytes = capacityBytes;
this.hostAddress = hostAddress;
this.port = port;
this.podId = podId;
this.setStatus(StoragePoolStatus.Initial);
this.setPath(hostPath);
setStatus(StoragePoolStatus.Initial);
setPath(hostPath);
}
public StoragePoolVO(StoragePoolVO that) {
@ -153,12 +153,12 @@ public class StoragePoolVO implements StoragePool {
}
public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) {
this.poolType = type;
poolType = type;
this.hostAddress = hostAddress;
this.port = port;
this.setStatus(StoragePoolStatus.Initial);
this.uuid = UUID.randomUUID().toString();
this.setPath(path);
setStatus(StoragePoolStatus.Initial);
uuid = UUID.randomUUID().toString();
setPath(path);
}
@Override
@ -177,7 +177,7 @@ public class StoragePoolVO implements StoragePool {
}
public void setPoolType(StoragePoolType protocol) {
this.poolType = protocol;
poolType = protocol;
}
@Override
@ -258,14 +258,17 @@ public class StoragePoolVO implements StoragePool {
}
public void setHostAddress(String host) {
this.hostAddress = host;
hostAddress = host;
}
@Override
public String getPath() {
String updatedPath = path;
if (this.poolType == StoragePoolType.SMB) {
if (poolType == StoragePoolType.SMB) {
updatedPath = UriUtils.getUpdateUri(updatedPath, false);
if (updatedPath.contains("password") && updatedPath.contains("?")) {
updatedPath = updatedPath.substring(0, updatedPath.indexOf('?'));
}
}
return updatedPath;
@ -285,7 +288,7 @@ public class StoragePoolVO implements StoragePool {
}
public void setDataCenterId(long dcId) {
this.dataCenterId = dcId;
dataCenterId = dcId;
}
public void setPodId(Long podId) {
@ -327,9 +330,10 @@ public class StoragePoolVO implements StoragePool {
}
public ScopeType getScope() {
return this.scope;
return scope;
}
@Override
public HypervisorType getHypervisor() {
return hypervisor;
}
@ -344,7 +348,7 @@ public class StoragePoolVO implements StoragePool {
return false;
}
StoragePoolVO that = (StoragePoolVO)obj;
return this.id == that.id;
return id == that.id;
}
@Override
@ -359,7 +363,7 @@ public class StoragePoolVO implements StoragePool {
@Override
public boolean isShared() {
return this.scope == ScopeType.HOST ? false : true;
return scope == ScopeType.HOST ? false : true;
}
@Override

View File

@ -1,4 +1,4 @@
// Licensed to the Apache Software Foundation (ASF) under one
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
@ -69,52 +69,6 @@ namespace HypervResource
}
}
public string User
{
get
{
string user = null;
if (uri != null)
{
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
user = System.Web.HttpUtility.UrlDecode(queryDictionary["user"]);
}
return user;
}
}
public string Password
{
get
{
string password = null;
if (uri != null)
{
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
password = System.Web.HttpUtility.UrlDecode(queryDictionary["password"]);
}
return password;
}
}
public string Domain
{
get
{
string domain = null;
if (uri != null)
{
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
if (queryDictionary["domain"] != null)
{
domain = System.Web.HttpUtility.UrlDecode(queryDictionary["domain"]);
}
else domain = uri.Host;
}
return domain;
}
}
public Boolean isLocal
{
get
@ -457,36 +411,7 @@ namespace HypervResource
return uncPath;
}
}
public string User
{
get
{
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
return System.Web.HttpUtility.UrlDecode(queryDictionary["user"]);
}
}
public string Password
{
get
{
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
return System.Web.HttpUtility.UrlDecode(queryDictionary["password"]);
}
}
public string Domain
{
get
{
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
if (queryDictionary["domain"] != null)
{
return System.Web.HttpUtility.UrlDecode(queryDictionary["domain"]);
}
else return uri.Host;
}
}
public static NFSTO ParseJson(dynamic json)
{
NFSTO result = null;

View File

@ -84,48 +84,31 @@ namespace HypervResource
/// <param name="destFile"></param>
public static void DownloadCifsFileToLocalFile(string filePathRelativeToShare, NFSTO cifsShareDetails, string destFile)
{
try
String dest = "";
if (filePathRelativeToShare.EndsWith(".iso") || filePathRelativeToShare.EndsWith(".vhd") || filePathRelativeToShare.EndsWith(".vhdx"))
{
IntPtr token = IntPtr.Zero;
LogonUser(cifsShareDetails.User, cifsShareDetails.Domain, cifsShareDetails.Password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref token);
using (WindowsImpersonationContext remoteIdentity = new WindowsIdentity(token).Impersonate())
dest = Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare);
dest = Utils.NormalizePath(dest);
}
// if the filePathRelativeToShare string don't have filename and only a dir point then find the vhd files in that folder and use
// In the clean setup, first copy command wont be having the filename it contains onlyu dir path.
// we need to scan the folder point and then copy the file to destination.
else if (!filePathRelativeToShare.EndsWith(".vhd") || !filePathRelativeToShare.EndsWith(".vhdx"))
{
// scan the folder and get the vhd filename.
String uncPath = Path.Combine(cifsShareDetails.UncPath, Path.Combine(filePathRelativeToShare.Split('/')));
//uncPath = uncPath.Replace("/", "\\");
DirectoryInfo dir = new DirectoryInfo(uncPath);
FileInfo[] vhdFiles = dir.GetFiles("*.vhd*");
if (vhdFiles.Length > 0)
{
String dest = "";
if (filePathRelativeToShare.EndsWith(".iso") || filePathRelativeToShare.EndsWith(".vhd") || filePathRelativeToShare.EndsWith(".vhdx"))
{
dest = Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare);
dest = Utils.NormalizePath(dest);
}
// if the filePathRelativeToShare string don't have filename and only a dir point then find the vhd files in that folder and use
// In the clean setup, first copy command wont be having the filename it contains onlyu dir path.
// we need to scan the folder point and then copy the file to destination.
else if (!filePathRelativeToShare.EndsWith(".vhd") || !filePathRelativeToShare.EndsWith(".vhdx"))
{
// scan the folder and get the vhd filename.
String uncPath = Path.Combine(cifsShareDetails.UncPath, Path.Combine(filePathRelativeToShare.Split('/')));
//uncPath = uncPath.Replace("/", "\\");
DirectoryInfo dir = new DirectoryInfo(uncPath);
FileInfo[] vhdFiles = dir.GetFiles("*.vhd*");
if (vhdFiles.Length > 0)
{
FileInfo file = vhdFiles[0];
dest = file.FullName;
}
}
s_logger.Info(CloudStackTypes.CopyCommand + ": copy " + Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare) + " to " + destFile);
File.Copy(dest, destFile, true);
remoteIdentity.Undo();
FileInfo file = vhdFiles[0];
dest = file.FullName;
}
}
catch (UnauthorizedAccessException ex)
{
string errMsg = "Invalid user or password for the share " + cifsShareDetails.UncPath;
s_logger.Error(errMsg);
throw new ArgumentException(errMsg, ex);
}
s_logger.Info(CloudStackTypes.CopyCommand + ": copy " + Path.Combine(cifsShareDetails.UncPath, filePathRelativeToShare) + " to " + destFile);
File.Copy(dest, destFile, true);
}
public static void GetShareDetails(string remoteUNC, out long capacity, out long available)
@ -193,142 +176,11 @@ namespace HypervResource
// from http://stackoverflow.com/a/2541569/939250
#region imports
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr existingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr duplicateTokenHandle);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpFreeBytesAvailable,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
#endregion
#region consts
// logon types
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
// logon providers
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_PROVIDER_WINNT50 = 3;
const int LOGON32_PROVIDER_WINNT40 = 2;
const int LOGON32_PROVIDER_WINNT35 = 1;
const int RESOURCE_CONNECTED = 0x00000001;
const int RESOURCE_GLOBALNET = 0x00000002;
const int RESOURCE_REMEMBERED = 0x00000003;
const int RESOURCETYPE_ANY = 0x00000000;
const int RESOURCETYPE_DISK = 0x00000001;
const int RESOURCETYPE_PRINT = 0x00000002;
const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;
const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
const int RESOURCEUSAGE_CONTAINER = 0x00000002;
const int CONNECT_INTERACTIVE = 0x00000008;
const int CONNECT_PROMPT = 0x00000010;
const int CONNECT_REDIRECT = 0x00000080;
const int CONNECT_UPDATE_PROFILE = 0x00000001;
const int CONNECT_COMMANDLINE = 0x00000800;
const int CONNECT_CMD_SAVECRED = 0x00001000;
const int CONNECT_LOCALDRIVE = 0x00000100;
#endregion
#region Errors
const int NO_ERROR = 0;
const int ERROR_ACCESS_DENIED = 5;
const int ERROR_ALREADY_ASSIGNED = 85;
const int ERROR_BAD_DEVICE = 1200;
const int ERROR_BAD_NET_NAME = 67;
const int ERROR_BAD_PROVIDER = 1204;
const int ERROR_CANCELLED = 1223;
const int ERROR_EXTENDED_ERROR = 1208;
const int ERROR_INVALID_ADDRESS = 487;
const int ERROR_INVALID_PARAMETER = 87;
const int ERROR_INVALID_PASSWORD = 1216;
const int ERROR_MORE_DATA = 234;
const int ERROR_NO_MORE_ITEMS = 259;
const int ERROR_NO_NET_OR_BAD_PATH = 1203;
const int ERROR_NO_NETWORK = 1222;
const int ERROR_BAD_PROFILE = 1206;
const int ERROR_CANNOT_OPEN_PROFILE = 1205;
const int ERROR_DEVICE_IN_USE = 2404;
const int ERROR_NOT_CONNECTED = 2250;
const int ERROR_OPEN_FILES = 2401;
private struct ErrorClass
{
public int num;
public string message;
public ErrorClass(int num, string message)
{
this.num = num;
this.message = message;
}
}
private static ErrorClass[] ERROR_LIST = new ErrorClass[] {
new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"),
new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"),
new ErrorClass(ERROR_BAD_DEVICE, "Error: Bad Device"),
new ErrorClass(ERROR_BAD_NET_NAME, "Error: Bad Net Name"),
new ErrorClass(ERROR_BAD_PROVIDER, "Error: Bad Provider"),
new ErrorClass(ERROR_CANCELLED, "Error: Cancelled"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"),
new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"),
new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"),
new ErrorClass(ERROR_MORE_DATA, "Error: More Data"),
new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"),
new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"),
new ErrorClass(ERROR_NO_NETWORK, "Error: No Network"),
new ErrorClass(ERROR_BAD_PROFILE, "Error: Bad Profile"),
new ErrorClass(ERROR_CANNOT_OPEN_PROFILE, "Error: Cannot Open Profile"),
new ErrorClass(ERROR_DEVICE_IN_USE, "Error: Device In Use"),
new ErrorClass(ERROR_EXTENDED_ERROR, "Error: Extended Error"),
new ErrorClass(ERROR_NOT_CONNECTED, "Error: Not Connected"),
new ErrorClass(ERROR_OPEN_FILES, "Error: Open Files"),
};
private static string getErrorForNumber(int errNum)
{
foreach (ErrorClass er in ERROR_LIST)
{
if (er.num == errNum) return er.message;
}
return "Error: Unknown, " + errNum;
}
#endregion
[StructLayout(LayoutKind.Sequential)]
private class NETRESOURCE
{
public int dwScope = 0;
public int dwType = 0;
public int dwDisplayType = 0;
public int dwUsage = 0;
public string lpLocalName = "";
public string lpRemoteName = "";
public string lpComment = "";
public string lpProvider = "";
}
}
}

View File

@ -65,6 +65,8 @@ import org.apache.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.cloudstack.storage.command.CopyCommand;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckRouterAnswer;
import com.cloud.agent.api.CheckRouterCommand;
@ -123,9 +125,11 @@ import com.cloud.agent.api.routing.SetStaticRouteCommand;
import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand;
import com.cloud.agent.api.routing.VmDataCommand;
import com.cloud.agent.api.routing.VpnUsersCfgCommand;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DhcpTO;
import com.cloud.agent.api.to.FirewallRuleTO;
import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.agent.api.to.StaticNatRuleTO;
@ -486,6 +490,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
answer = execute((PlugNicCommand)cmd);
} else if (clazz == UnPlugNicCommand.class) {
answer = execute((UnPlugNicCommand)cmd);
} else if (clazz == CopyCommand.class) {
answer = execute((CopyCommand)cmd);
}
else {
if (clazz == StartCommand.class) {
@ -519,6 +525,46 @@ public class HypervDirectConnectResource extends ServerResourceBase implements S
return answer;
}
private Answer execute(CopyCommand cmd) {
URI agentUri = null;
try {
String cmdName = cmd.getClass().getName();
agentUri =
new URI("https", null, _agentIp, _port,
"/api/HypervResource/" + cmdName, null, null);
} catch (URISyntaxException e) {
String errMsg = "Could not generate URI for Hyper-V agent";
s_logger.error(errMsg, e);
return null;
}
cleanPassword(cmd.getSrcTO().getDataStore());
cleanPassword(cmd.getDestTO().getDataStore());
// Send the cmd to hyperv agent.
String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri);
if (ansStr == null) {
return Answer.createUnsupportedCommandAnswer(cmd);
}
Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
String logResult = cleanPassword(StringEscapeUtils.unescapeJava(result.toString()));
s_logger.debug("executeRequest received response " + logResult);
if (result.length > 0) {
return result[0];
}
return null;
}
private void cleanPassword(DataStoreTO dataStoreTO) {
if (dataStoreTO instanceof NfsTO) {
NfsTO nfsTO = (NfsTO)dataStoreTO;
String url = nfsTO.getUrl();
if (url.contains("cifs") && url.contains("password")) {
nfsTO.setUrl(url.substring(0, url.indexOf('?')));
}
}
}
private PlugNicAnswer execute(PlugNicCommand cmd) {
if (s_logger.isInfoEnabled()) {