2009-04-16 45 views
19

Máy trạm của chúng tôi không phải là thành viên của miền mà SQL Server của chúng tôi đang bật. (Chúng không thực sự ở trên một miền - đừng hỏi).Làm thế nào để xây dựng chức năng RUNAS/NETONLY thành một chương trình (C# /. NET/WinForms)?

Khi chúng tôi sử dụng SSMS hoặc bất kỳ thứ gì để kết nối với SQL Server, chúng tôi sử dụng RUNAS/NETONLY với DOMAIN \ user. Sau đó, chúng tôi gõ vào mật khẩu và nó khởi chạy chương trình. (RUNAS/NETONLY không cho phép bạn bao gồm mật khẩu trong tập tin thực thi). Vì vậy, tôi đã có một ứng dụng .NET WinForms cần kết nối SQL, và người dùng phải khởi chạy nó bằng cách chạy một tập tin thực thi có dòng lệnh RUNAS/NETONLY và sau đó nó khởi chạy EXE.

Nếu người dùng vô tình khởi chạy EXE trực tiếp, nó không thể kết nối với SQL Server.

Nhấp chuột phải vào ứng dụng và sử dụng tùy chọn "Chạy dưới dạng ..." không hoạt động (có thể do máy trạm không thực sự biết về miền).

Tôi đang tìm cách để ứng dụng thực hiện chức năng RUNAS/NETONLY trong nội bộ trước khi bắt đầu bất kỳ điều gì quan trọng.

Xin xem liên kết này cho một mô tả về cách runas/netonly hoạt động: http://www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982

Tôi đang nghĩ tôi sẽ phải sử dụng LOGON_NETCREDENTIALS_ONLY với CreateProcessWithLogonW

Trả lời

3

tôi thu thập được những liên kết hữu ích:

http://www.developmentnow.com/g/36_2006_3_0_0_725350/Need-help-with-impersonation-please-.htm

http://blrchen.spaces.live.com/blog/cns!572204F8C4F8A77A!251.entry

http://geekswithblogs.net/khanna/archive/2005/02/09/22430.aspx

http://msmvps.com/blogs/martinzugec/archive/2008/06/03/use-runas-from-non-domain-computer.aspx

Hóa ra tôi sẽ phải sử dụng LOGON_NETCREDENTIALS_ONLY với CreateProcessWithLogonW. Tôi sẽ xem nếu tôi có thể có chương trình phát hiện nếu nó đã được đưa ra theo cách đó và nếu không, thu thập các thông tin đăng nhập tên miền và khởi động chính nó. Bằng cách đó sẽ chỉ có một EXE tự quản lý.

+0

Tôi biết điều này thực sự là cũ, nhưng hai liên kết đầu tiên (developmentnow.com & blrchen.spaces.live.com) được deaed. – chrnola

0

Tôi cho rằng bạn không thể chỉ cần thêm một người dùng cho ứng dụng để máy chủ sql và sau đó sử dụng xác thực sql hơn là xác thực cửa sổ?

+0

Nope. Và tôi thực sự muốn người dùng truy cập bảng điều khiển này là chính họ. Nó giống như một bảng điều khiển hiển thị một số quy trình và cho phép người dùng kích hoạt chúng, xem kết quả, v.v. –

6

Tôi chỉ làm điều gì đó tương tự như thế này bằng cách sử dụng ImpersonationContext. Nó rất trực quan để sử dụng và đã làm việc hoàn hảo cho tôi.

Để chạy như một người dùng khác nhau, cú pháp là:

using (new Impersonator("myUsername", "myDomainname", "myPassword")) 
{ 
    // code that executes under the new context... 
} 

Đây là lớp:

namespace Tools 
{ 
    #region Using directives. 
    // ---------------------------------------------------------------------- 

    using System; 
    using System.Security.Principal; 
    using System.Runtime.InteropServices; 
    using System.ComponentModel; 

    // ---------------------------------------------------------------------- 
    #endregion 

    ///////////////////////////////////////////////////////////////////////// 

    /// <summary> 
    /// Impersonation of a user. Allows to execute code under another 
    /// user context. 
    /// Please note that the account that instantiates the Impersonator class 
    /// needs to have the 'Act as part of operating system' privilege set. 
    /// </summary> 
    /// <remarks> 
    /// This class is based on the information in the Microsoft knowledge base 
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158 
    /// 
    /// Encapsulate an instance into a using-directive like e.g.: 
    /// 
    ///  ... 
    ///  using (new Impersonator("myUsername", "myDomainname", "myPassword")) 
    ///  { 
    ///   ... 
    ///   [code that executes under the new context] 
    ///   ... 
    ///  } 
    ///  ... 
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected]) 
    /// for questions regarding this class. 
    /// </remarks> 
    public class Impersonator : 
     IDisposable 
    { 
     #region Public methods. 
     // ------------------------------------------------------------------ 

     /// <summary> 
     /// Constructor. Starts the impersonation with the given credentials. 
     /// Please note that the account that instantiates the Impersonator class 
     /// needs to have the 'Act as part of operating system' privilege set. 
     /// </summary> 
     /// <param name="userName">The name of the user to act as.</param> 
     /// <param name="domainName">The domain name of the user to act as.</param> 
     /// <param name="password">The password of the user to act as.</param> 
     public Impersonator(
      string userName, 
      string domainName, 
      string password) 
     { 
      ImpersonateValidUser(userName, domainName, password); 
     } 

     // ------------------------------------------------------------------ 
     #endregion 

     #region IDisposable member. 
     // ------------------------------------------------------------------ 

     public void Dispose() 
     { 
      UndoImpersonation(); 
     } 

     // ------------------------------------------------------------------ 
     #endregion 

     #region P/Invoke. 
     // ------------------------------------------------------------------ 

     [DllImport("advapi32.dll", SetLastError = true)] 
     private static extern int LogonUser(
      string lpszUserName, 
      string lpszDomain, 
      string lpszPassword, 
      int dwLogonType, 
      int dwLogonProvider, 
      ref IntPtr phToken); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern int DuplicateToken(
      IntPtr hToken, 
      int impersonationLevel, 
      ref IntPtr hNewToken); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern bool RevertToSelf(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     private static extern bool CloseHandle(
      IntPtr handle); 

     private const int LOGON32_LOGON_INTERACTIVE = 2; 
     private const int LOGON32_PROVIDER_DEFAULT = 0; 

     // ------------------------------------------------------------------ 
     #endregion 

     #region Private member. 
     // ------------------------------------------------------------------ 

     /// <summary> 
     /// Does the actual impersonation. 
     /// </summary> 
     /// <param name="userName">The name of the user to act as.</param> 
     /// <param name="domainName">The domain name of the user to act as.</param> 
     /// <param name="password">The password of the user to act as.</param> 
     private void ImpersonateValidUser(
      string userName, 
      string domain, 
      string password) 
     { 
      WindowsIdentity tempWindowsIdentity = null; 
      IntPtr token = IntPtr.Zero; 
      IntPtr tokenDuplicate = IntPtr.Zero; 

      try 
      { 
       if (RevertToSelf()) 
       { 
        if (LogonUser(
         userName, 
         domain, 
         password, 
         LOGON32_LOGON_INTERACTIVE, 
         LOGON32_PROVIDER_DEFAULT, 
         ref token) != 0) 
        { 
         if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
         { 
          tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
          impersonationContext = tempWindowsIdentity.Impersonate(); 
         } 
         else 
         { 
          throw new Win32Exception(Marshal.GetLastWin32Error()); 
         } 
        } 
        else 
        { 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
        } 
       } 
       else 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 
      } 
      finally 
      { 
       if (token != IntPtr.Zero) 
       { 
        CloseHandle(token); 
       } 
       if (tokenDuplicate != IntPtr.Zero) 
       { 
        CloseHandle(tokenDuplicate); 
       } 
      } 
     } 

     /// <summary> 
     /// Reverts the impersonation. 
     /// </summary> 
     private void UndoImpersonation() 
     { 
      if (impersonationContext != null) 
      { 
       impersonationContext.Undo(); 
      } 
     } 

     private WindowsImpersonationContext impersonationContext = null; 

     // ------------------------------------------------------------------ 
     #endregion 
    } 

    ///////////////////////////////////////////////////////////////////////// 
} 
+0

Tôi đã sử dụng mã tương tự trong trình cài đặt tùy chỉnh - tuy nhiên 'Hành động như một phần của hệ điều hành' là rất mạnh và tôi nhận được rất nhiều phản hồi từ quản trị viên hệ thống trong việc cấp điều này cho người dùng trung bình. YMMV của khóa học –

+0

Vâng mã này chỉ tốt cho đăng nhập tại địa phương - cho các thông tin truy cập từ xa (về cơ bản chỉ là kết nối SQL), bạn phải sử dụng tương đương với cờ/NETONLY, tôi đang cố gắng sửa nó ngay bây giờ. –

+1

Loại liên kết này minh họa sự khác biệt: http://www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982 - Tôi có thể cần phải tạo một quy trình mới. –

2

Mã này là một phần của một lớp runas mà chúng tôi sử dụng để khởi động một tiến trình bên ngoài với mức độ tin cậy cao. Truyền null cho tên người dùng & mật khẩu sẽ nhắc nhở với các cảnh báo UAC chuẩn. Khi chuyển một giá trị cho tên người dùng và mật khẩu, bạn thực sự có thể khởi chạy ứng dụng được nâng lên mà không có dấu nhắc UAC.

public static Process Elevated(string process, string args, string username, string password, string workingDirectory) 
{ 
    if(process == null || process.Length == 0) throw new ArgumentNullException("process"); 

    process = Path.GetFullPath(process); 
    string domain = null; 
    if(username != null) 
     username = GetUsername(username, out domain); 
    ProcessStartInfo info = new ProcessStartInfo(); 
    info.UseShellExecute = false; 
    info.Arguments = args; 
    info.WorkingDirectory = workingDirectory ?? Path.GetDirectoryName(process); 
    info.FileName = process; 
    info.Verb = "runas"; 
    info.UserName = username; 
    info.Domain = domain; 
    info.LoadUserProfile = true; 
    if(password != null) 
    { 
     SecureString ss = new SecureString(); 
     foreach(char c in password) 
      ss.AppendChar(c); 
     info.Password = ss; 
    } 

    return Process.Start(info); 
} 

private static string GetUsername(string username, out string domain) 
{ 
    SplitUserName(username, out username, out domain); 

    if(domain == null && username.IndexOf('@') < 0) 
     domain = Environment.GetEnvironmentVariable("USERDOMAIN"); 
    return username; 
} 
+0

ProcessStartInfo (và do đó phương thức Process.Start) không có bất kỳ cài đặt tương đương nào cho RUNAS/NETONLY, nơi mạng thông tin đăng nhập chỉ được sử dụng cho kết nối mạng, không được sử dụng cho các điều khoản luồng/quy trình cục bộ. –

+0

Rất tiếc ... bạn có thể phải sử dụng PInvoke và CreateProcess. –

10

Tôi biết đây là một chuỗi cũ nhưng nó rất hữu ích. Tôi có cùng một tình huống giống như Cade Roux, như tôi muốn/chức năng kiểu netonly.

Câu trả lời của John Rasch hoạt động với một sửa đổi nhỏ !!!

Thêm dòng sau liên tục (khoảng dòng 102 cho phù hợp):

private const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 

Sau đó thay đổi các cuộc gọi đến LogonUser sử dụng LOGON32_LOGON_NEW_CREDENTIALS thay vì LOGON32_LOGON_INTERACTIVE.

Đó là chỉ thay đổi mà tôi phải thực hiện để làm điều này hoạt động hoàn hảo !!! Cảm ơn John và Cade !!!

Dưới đây là mã đổi đầy đủ để dễ sao chép/dán:

namespace Tools 
{ 
    #region Using directives. 
    // ---------------------------------------------------------------------- 

    using System; 
    using System.Security.Principal; 
    using System.Runtime.InteropServices; 
    using System.ComponentModel; 

    // ---------------------------------------------------------------------- 
    #endregion 

    ///////////////////////////////////////////////////////////////////////// 

    /// <summary> 
    /// Impersonation of a user. Allows to execute code under another 
    /// user context. 
    /// Please note that the account that instantiates the Impersonator class 
    /// needs to have the 'Act as part of operating system' privilege set. 
    /// </summary> 
    /// <remarks> 
    /// This class is based on the information in the Microsoft knowledge base 
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158 
    /// 
    /// Encapsulate an instance into a using-directive like e.g.: 
    /// 
    ///  ... 
    ///  using (new Impersonator("myUsername", "myDomainname", "myPassword")) 
    ///  { 
    ///   ... 
    ///   [code that executes under the new context] 
    ///   ... 
    ///  } 
    ///  ... 
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected]) 
    /// for questions regarding this class. 
    /// </remarks> 
    public class Impersonator : 
     IDisposable 
    { 
     #region Public methods. 
     // ------------------------------------------------------------------ 

     /// <summary> 
     /// Constructor. Starts the impersonation with the given credentials. 
     /// Please note that the account that instantiates the Impersonator class 
     /// needs to have the 'Act as part of operating system' privilege set. 
     /// </summary> 
     /// <param name="userName">The name of the user to act as.</param> 
     /// <param name="domainName">The domain name of the user to act as.</param> 
     /// <param name="password">The password of the user to act as.</param> 
     public Impersonator(
      string userName, 
      string domainName, 
      string password) 
     { 
      ImpersonateValidUser(userName, domainName, password); 
     } 

     // ------------------------------------------------------------------ 
     #endregion 

     #region IDisposable member. 
     // ------------------------------------------------------------------ 

     public void Dispose() 
     { 
      UndoImpersonation(); 
     } 

     // ------------------------------------------------------------------ 
     #endregion 

     #region P/Invoke. 
     // ------------------------------------------------------------------ 

     [DllImport("advapi32.dll", SetLastError = true)] 
     private static extern int LogonUser(
      string lpszUserName, 
      string lpszDomain, 
      string lpszPassword, 
      int dwLogonType, 
      int dwLogonProvider, 
      ref IntPtr phToken); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern int DuplicateToken(
      IntPtr hToken, 
      int impersonationLevel, 
      ref IntPtr hNewToken); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern bool RevertToSelf(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     private static extern bool CloseHandle(
      IntPtr handle); 

     private const int LOGON32_LOGON_INTERACTIVE = 2; 
     private const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 
     private const int LOGON32_PROVIDER_DEFAULT = 0; 

     // ------------------------------------------------------------------ 
     #endregion 

     #region Private member. 
     // ------------------------------------------------------------------ 

     /// <summary> 
     /// Does the actual impersonation. 
     /// </summary> 
     /// <param name="userName">The name of the user to act as.</param> 
     /// <param name="domainName">The domain name of the user to act as.</param> 
     /// <param name="password">The password of the user to act as.</param> 
     private void ImpersonateValidUser(
      string userName, 
      string domain, 
      string password) 
     { 
      WindowsIdentity tempWindowsIdentity = null; 
      IntPtr token = IntPtr.Zero; 
      IntPtr tokenDuplicate = IntPtr.Zero; 

      try 
      { 
       if (RevertToSelf()) 
       { 
        if (LogonUser(
         userName, 
         domain, 
         password, 
         LOGON32_LOGON_NEW_CREDENTIALS, 
         LOGON32_PROVIDER_DEFAULT, 
         ref token) != 0) 
        { 
         if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
         { 
          tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
          impersonationContext = tempWindowsIdentity.Impersonate(); 
         } 
         else 
         { 
          throw new Win32Exception(Marshal.GetLastWin32Error()); 
         } 
        } 
        else 
        { 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
        } 
       } 
       else 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 
      } 
      finally 
      { 
       if (token != IntPtr.Zero) 
       { 
        CloseHandle(token); 
       } 
       if (tokenDuplicate != IntPtr.Zero) 
       { 
        CloseHandle(tokenDuplicate); 
       } 
      } 
     } 

     /// <summary> 
     /// Reverts the impersonation. 
     /// </summary> 
     private void UndoImpersonation() 
     { 
      if (impersonationContext != null) 
      { 
       impersonationContext.Undo(); 
      } 
     } 

     private WindowsImpersonationContext impersonationContext = null; 

     // ------------------------------------------------------------------ 
     #endregion 
    } 

    ///////////////////////////////////////////////////////////////////////// 
} 
+1

Tôi biết điều này là một vài năm sau đó, nhưng Cảm ơn bạn !!!!!!!!! Điều này đã giúp tôi một tấn. –