/// <summary> /// Creates an instance of a COM server using the specified license key. /// </summary> public static object CreateInstance2(Guid clsid, string hostName, UserIdentity identity) { // validate the host name before proceeding (exception thrown if host is not valid). bool isLocalHost = IsLocalHost(hostName); // allocate the connection info. ServerInfo serverInfo = new ServerInfo(); COSERVERINFO coserverInfo = serverInfo.Allocate(hostName, identity); object instance = null; IClassFactory factory = null; try { // create the factory. object unknown = null; CoGetClassObject( clsid, (isLocalHost)?CLSCTX_LOCAL_SERVER:CLSCTX_REMOTE_SERVER, ref coserverInfo, IID_IUnknown, out unknown); // SetProxySecurity(unknown, coserverInfo.pAuthInfo); factory = (IClassFactory)unknown; // check for valid factory. if (factory == null) { throw ServiceResultException.Create(StatusCodes.BadCommunicationError, "Could not load IClassFactory for COM server '{0}' on host '{1}'.", clsid, hostName); } // SetProxySecurity(factory, coserverInfo.pAuthInfo); factory.CreateInstance(null, IID_IUnknown, out instance); // SetProxySecurity(instance, coserverInfo.pAuthInfo); } finally { serverInfo.Deallocate(); } return instance; }
/// <summary> /// Creates an instance of a COM server using the specified license key. /// </summary> public static object CreateInstanceWithLicenseKey(Guid clsid, string hostName, UserIdentity identity, string licenseKey) { ServerInfo serverInfo = new ServerInfo(); COSERVERINFO coserverInfo = serverInfo.Allocate(hostName, identity); object instance = null; IClassFactory2 factory = null; try { // check whether connecting locally or remotely. uint clsctx = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER; if (hostName != null && hostName.Length > 0) { clsctx = CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER; } // get the class factory. object unknown = null; CoGetClassObject( clsid, clsctx, ref coserverInfo, typeof(IClassFactory2).GUID, out unknown); // SetProxySecurity(unknown, coserverInfo.pAuthInfo); factory = (IClassFactory2)unknown; // check for valid factory. if (factory == null) { throw ServiceResultException.Create(StatusCodes.BadCommunicationError, "Could not load IClassFactory2 for COM server '{0}' on host '{1}'.", clsid, hostName); } // SetProxySecurity(factory, coserverInfo.pAuthInfo); // create instance. factory.CreateInstanceLic( null, null, IID_IUnknown, licenseKey, out instance); // SetProxySecurity(instance, coserverInfo.pAuthInfo); } finally { serverInfo.Deallocate(); ComUtils.ReleaseServer(factory); } return instance; }
// COM impersonation is a nice feature but variations between behavoirs on different // windows platforms make it virtually impossible to support. This code is left here // in case it becomes a critical requirement in the future. #if COM_IMPERSONATION_SUPPORT /// <summary> /// Returns the WindowsIdentity associated with a UserIdentity. /// </summary> public static WindowsPrincipal GetPrincipalFromUserIdentity(UserIdentity user) { if (UserIdentity.IsDefault(user)) { return null; } // validate the credentials. IntPtr token = IntPtr.Zero; bool result = LogonUser( user.Username, user.Domain, user.Password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref token); if (!result) { throw ServiceResultException.Create( StatusCodes.BadIdentityTokenRejected, "Could not logon as user '{0}'. Reason: {1}.", user.Username, GetSystemMessage(Marshal.GetLastWin32Error(), LOCALE_SYSTEM_DEFAULT)); } try { // create the windows identity. WindowsIdentity identity = new WindowsIdentity(token); // validate the identity. identity.Impersonate(); // return a principal. return new WindowsPrincipal(identity); } finally { CloseHandle(token); } }
/// <summary> /// Sets the security settings for the proxy. /// </summary> public static void SetProxySecurity(object server, UserIdentity user) { // allocate the GCHandle hUserName = GCHandle.Alloc(user.Username, GCHandleType.Pinned); GCHandle hPassword = GCHandle.Alloc(user.Password, GCHandleType.Pinned); GCHandle hDomain = GCHandle.Alloc(user.Domain, GCHandleType.Pinned); GCHandle hIdentity = new GCHandle(); // create identity structure. COAUTHIDENTITY authIdentity = new COAUTHIDENTITY(); authIdentity.User = hUserName.AddrOfPinnedObject(); authIdentity.UserLength = (uint)((user.Username != null) ? user.Username.Length : 0); authIdentity.Password = hPassword.AddrOfPinnedObject(); authIdentity.PasswordLength = (uint)((user.Password != null) ? user.Password.Length : 0); authIdentity.Domain = hDomain.AddrOfPinnedObject(); authIdentity.DomainLength = (uint)((user.Domain != null) ? user.Domain.Length : 0); authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; hIdentity = GCHandle.Alloc(authIdentity, GCHandleType.Pinned); try { SetProxySecurity(server, hIdentity.AddrOfPinnedObject()); } finally { hUserName.Free(); hPassword.Free(); hDomain.Free(); hIdentity.Free(); } }
/// <summary> /// Creates an instance of a COM server using the specified license key. /// </summary> public static object CreateInstance(Guid clsid, string hostName, UserIdentity identity) { return CreateInstance1(clsid, hostName, identity); }
/// <summary> /// Creates an instance of a COM server. /// </summary> public static object CreateInstance1(Guid clsid, string hostName, UserIdentity identity) { ServerInfo serverInfo = new ServerInfo(); COSERVERINFO coserverInfo = serverInfo.Allocate(hostName, identity); GCHandle hIID = GCHandle.Alloc(IID_IUnknown, GCHandleType.Pinned); MULTI_QI[] results = new MULTI_QI[1]; results[0].iid = hIID.AddrOfPinnedObject(); results[0].pItf = null; results[0].hr = 0; try { // check whether connecting locally or remotely. uint clsctx = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER; if (!String.IsNullOrEmpty(hostName) && hostName != "localhost") { clsctx = CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER; } // create an instance. CoCreateInstanceEx( ref clsid, null, clsctx, ref coserverInfo, 1, results); } finally { if (hIID.IsAllocated) hIID.Free(); serverInfo.Deallocate(); } if (results[0].hr != 0) { throw ServiceResultException.Create( StatusCodes.BadCommunicationError, "Could not create COM server '{0}' on host '{1}'. Reason: {2}.", clsid, hostName, GetSystemMessage((int)results[0].hr, LOCALE_SYSTEM_DEFAULT)); } return results[0].pItf; }
/// <summary> /// Allocates a COSERVERINFO structure. /// </summary> public COSERVERINFO Allocate(string hostName, UserIdentity identity) { // initialize server info structure. COSERVERINFO serverInfo = new COSERVERINFO(); serverInfo.pwszName = hostName; serverInfo.pAuthInfo = IntPtr.Zero; serverInfo.dwReserved1 = 0; serverInfo.dwReserved2 = 0; // no authentication for default identity if (UserIdentity.IsDefault(identity)) { return serverInfo; } m_hUserName = GCHandle.Alloc(identity.Username, GCHandleType.Pinned); m_hPassword = GCHandle.Alloc(identity.Password, GCHandleType.Pinned); m_hDomain = GCHandle.Alloc(identity.Domain, GCHandleType.Pinned); m_hIdentity = new GCHandle(); // create identity structure. COAUTHIDENTITY authIdentity = new COAUTHIDENTITY(); authIdentity.User = m_hUserName.AddrOfPinnedObject(); authIdentity.UserLength = (uint)((identity.Username != null)?identity.Username.Length:0); authIdentity.Password = m_hPassword.AddrOfPinnedObject(); authIdentity.PasswordLength = (uint)((identity.Password != null)?identity.Password.Length:0); authIdentity.Domain = m_hDomain.AddrOfPinnedObject(); authIdentity.DomainLength = (uint)((identity.Domain != null)?identity.Domain.Length:0); authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; m_hIdentity = GCHandle.Alloc(authIdentity, GCHandleType.Pinned); // create authorization info structure. COAUTHINFO authInfo = new COAUTHINFO(); authInfo.dwAuthnSvc = RPC_C_AUTHN_WINNT; authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE; authInfo.pwszServerPrincName = IntPtr.Zero; authInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT; authInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE; authInfo.pAuthIdentityData = m_hIdentity.AddrOfPinnedObject(); authInfo.dwCapabilities = EOAC_NONE; // EOAC_DYNAMIC_CLOAKING; m_hAuthInfo = GCHandle.Alloc(authInfo, GCHandleType.Pinned); // update server info structure. serverInfo.pAuthInfo = m_hAuthInfo.AddrOfPinnedObject(); return serverInfo; }
/// <summary> /// Whether the identity represents an the default identity. /// </summary> public static bool IsDefault(UserIdentity identity) { if (identity != null) { return String.IsNullOrEmpty(identity.m_username); } return true; }
/// <summary> /// Connects to the specified COM server server. /// </summary> public object CreateServer(Uri uri, UserIdentity identity) { // parse path to find prog id and clsid. string progID = uri.LocalPath; string clsid = null; while (progID.StartsWith("/")) { progID = progID.Substring(1); } int index = progID.IndexOf('/'); if (index >= 0) { clsid = progID.Substring(index+1); progID = progID.Substring(0, index); } // look up prog id if clsid not specified in the uri. Guid guid = Guid.Empty; if (String.IsNullOrEmpty(clsid)) { // connect to enumerator. Connect(uri.Host, identity); // use OpcEnum to lookup the prog id. guid = CLSIDFromProgID(progID); // check if prog id is actually a clsid string. if (guid == Guid.Empty) { clsid = progID; } } // convert CLSID to a GUID. if (guid == Guid.Empty) { try { guid = new Guid(clsid); } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadCommunicationError, e, "COM server URI does not contain a valid CLSID or ProgID."); } } // use normal activation. return ComUtils.CreateInstance(guid, uri.Host, identity); #if COM_IMPERSONATION_SUPPORT // set the current thread token. IPrincipal existingPrincipal = Thread.CurrentPrincipal; WindowsPrincipal principal = ComUtils.GetPrincipalFromUserIdentity(identity); try { if (principal != null) { Thread.CurrentPrincipal = principal; } // activate with a license key if one provided. if (identity != null && !String.IsNullOrEmpty(identity.LicenseKey)) { return ComUtils.CreateInstanceWithLicenseKey(guid, uri.Host, identity, identity.LicenseKey); } // use normal activation. return ComUtils.CreateInstance(guid, uri.Host, identity); } finally { Thread.CurrentPrincipal = existingPrincipal; } #endif }
/// <summary> /// Connects to OPCEnum on the specified machine. /// </summary> public void Connect(string host, UserIdentity identity) { // disconnect from current server. Disconnect(); // create in the instance. object unknown = null; try { unknown = ComUtils.CreateInstance(OPCEnumCLSID, host, identity); } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadCommunicationError, e, "Could not connect to OPCEnum server."); } m_server = unknown as IOPCServerList2; if (m_server == null) { ComUtils.ReleaseServer(unknown); StringBuilder error = new StringBuilder(); error.Append("Server does not support IOPCServerList2. "); error.Append("The OPC proxy/stubs may not be installed properly or the client or server machine. "); error.Append("The also could be a problem with DCOM security configuration."); throw ServiceResultException.Create(StatusCodes.BadCommunicationError, error.ToString()); } m_host = host; if (String.IsNullOrEmpty(m_host)) { m_host = "localhost"; } }
/// <summary> /// Connects to the specified COM server server. /// </summary> public object CreateServer(Uri uri, UserIdentity identity) { // parse path to find prog id and clsid. string progID = uri.LocalPath; string clsid = null; while (progID.StartsWith("/")) { progID = progID.Substring(1); } int index = progID.IndexOf('/'); if (index >= 0) { clsid = progID.Substring(index + 1); progID = progID.Substring(0, index); } // look up prog id if clsid not specified in the uri. Guid guid = Guid.Empty; if (String.IsNullOrEmpty(clsid)) { // connect to enumerator. Connect(uri.Host, identity); // use OpcEnum to lookup the prog id. guid = CLSIDFromProgID(progID); // check if prog id is actually a clsid string. if (guid == Guid.Empty) { clsid = progID; } } // convert CLSID to a GUID. if (guid == Guid.Empty) { try { guid = new Guid(clsid); } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadCommunicationError, e, "COM server URI does not contain a valid CLSID or ProgID."); } } // use normal activation. return(ComUtils.CreateInstance(guid, uri.Host, identity)); #if COM_IMPERSONATION_SUPPORT // set the current thread token. IPrincipal existingPrincipal = Thread.CurrentPrincipal; WindowsPrincipal principal = ComUtils.GetPrincipalFromUserIdentity(identity); try { if (principal != null) { Thread.CurrentPrincipal = principal; } // activate with a license key if one provided. if (identity != null && !String.IsNullOrEmpty(identity.LicenseKey)) { return(ComUtils.CreateInstanceWithLicenseKey(guid, uri.Host, identity, identity.LicenseKey)); } // use normal activation. return(ComUtils.CreateInstance(guid, uri.Host, identity)); } finally { Thread.CurrentPrincipal = existingPrincipal; } #endif }