2009-04-16 19 views
19

हमारे वर्कस्टेशन हमारे SQL सर्वर पर डोमेन के सदस्य नहीं हैं। (वे वास्तव में एक डोमेन पर नहीं हैं - पूछो मत)।एक (सी #/.NET/WinForms) प्रोग्राम में RUNAS/नेटोनली कार्यक्षमता कैसे बनाएं?

जब हम SQL सर्वर से कनेक्ट करने के लिए SSMS या कुछ भी उपयोग करते हैं, तो हम डोमेन \ उपयोगकर्ता के साथ RUNAS/NETONLY का उपयोग करते हैं। फिर हम पासवर्ड टाइप करते हैं और यह प्रोग्राम लॉन्च करता है। (RUNAS/नेटोनली आपको बैच फ़ाइल में पासवर्ड शामिल करने की अनुमति नहीं देता है)।

तो मुझे एक .NET WinForms ऐप मिला है जिसे SQL कनेक्शन की आवश्यकता है, और उपयोगकर्ताओं को बैच फ़ाइल चलाकर इसे लॉन्च करना होगा जिसमें RUNAS/NETONLY कमांड लाइन है और फिर यह EXE लॉन्च करता है।

यदि उपयोगकर्ता गलती से EXE को सीधे लॉन्च करता है, तो यह SQL सर्वर से कनेक्ट नहीं हो सकता है।

ऐप पर राइट-क्लिक करना और "रन के रूप में ..." विकल्प का उपयोग करना काम नहीं करता है (संभवतः क्योंकि वर्कस्टेशन वास्तव में डोमेन के बारे में नहीं जानता है)।

मैं कुछ भी महत्वपूर्ण शुरू करने से पहले आंतरिक रूप से RUNAS/नेटोनली कार्यक्षमता करने के लिए एप्लिकेशन के लिए एक तरीका ढूंढ रहा हूं।

कृपया RunAs/NETONLY काम करता है के वर्णन के लिए इस लिंक को देख: http://www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982

मैं मैं CreateProcessWithLogonW

उत्तर

3

मैं इन उपयोगी लिंक इकट्ठा:

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

यह पता चला मैं करने जा रहा हूँ CreateProcessWithLogonW के साथ LOGON_NETCREDENTIALS_ONLY का उपयोग करना होगा। मैं यह देखने जा रहा हूं कि क्या मुझे प्रोग्राम पता चल सकता है कि क्या यह इस तरह से लॉन्च किया गया है और यदि नहीं, तो डोमेन प्रमाण-पत्र एकत्र करें और खुद को लॉन्च करें। इस तरह केवल एक आत्म-प्रबंधन EXE होगा।

+0

मुझे पता है कि यह वास्तव में पुराना है, लेकिन पहले दो लिंक (developnow.com और blrchen.spaces.live.com) को हटा दिया गया है। – chrnola

0

साथ LOGON_NETCREDENTIALS_ONLY का उपयोग करने के लिए जा रहा हूँ सोच रहा हूँ मैं तुम्हें बस नहीं जोड़ सकते हैं लगता है ऐप के लिए एक उपयोगकर्ता एसक्यूएल सर्वर और फिर विंडोज प्रमाणीकरण के बजाय एसक्यूएल प्रमाणीकरण का उपयोग करें?

+0

नहीं:

यहाँ प्रतिलिपि करने/चिपकाने में आसानी के लिए पूर्ण रूप से संशोधित कोड है। और मैं वास्तव में उन उपयोगकर्ताओं को चाहता हूं जो इस नियंत्रण कक्ष तक पहुंचें। यह एक नियंत्रण डैशबोर्ड की तरह है जो कई प्रक्रियाओं को दिखाता है और उपयोगकर्ताओं को उन्हें ट्रिगर करने, परिणाम देखने आदि की अनुमति देता है। –

6

मैंने अभी ImpersonationContext का उपयोग करके ऐसा कुछ किया है। यह उपयोग करने के लिए बहुत सहज है और मेरे लिए पूरी तरह से काम किया है।

किसी दूसरे उपयोगकर्ता के रूप में चलाने के लिए, वाक्य रचना है:

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

मैंने कस्टम इंस्टॉलर में समान कोड का उपयोग किया है - हालांकि 'ऑपरेटिंग सिस्टम के हिस्से के रूप में कार्य' बहुत शक्तिशाली है और मैं औसत उपयोगकर्ताओं को यह प्रदान करने में सिस्टम प्रशासकों से बहुत अधिक पुशबैक मिला। निश्चित रूप से वाईएमएमवी –

+0

वैसे यह कोड स्थानीय रूप से लॉग इन करने के लिए केवल अच्छा है - रिमोट एक्सेस क्रेडेंशियल्स (मूल रूप से केवल SQL कनेक्शन के लिए) के लिए आपको/नेटोनली ध्वज के बराबर उपयोग करना होगा, मैं अभी इसे नीचे खींचने की कोशिश कर रहा हूं। –

+1

यह लिंक इस प्रकार का अंतर दिखाता है: http://www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982 - मुझे एक नई प्रक्रिया बनाने की आवश्यकता हो सकती है। –

2

इस कोड को एक RunAs वर्ग का हिस्सा है कि हम एक बाहरी प्रक्रिया शुरू करने के लिए उपयोग करते हैं:

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

यहाँ वर्ग है उन्नत निजी के साथ। उपयोगकर्ता नाम & पासवर्ड के लिए शून्य पास करना मानक यूएसी चेतावनियों के साथ संकेत देगा। उपयोगकर्ता नाम और पासवर्ड के लिए मूल्य पारित करते समय आप वास्तव में यूएसी प्रॉम्प्ट के बिना उन्नत एप्लिकेशन लॉन्च कर सकते हैं।

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 (और इसलिए Process.Start विधि) में RUNAS/NETONLY के लिए कोई समकक्ष सेटिंग्स नहीं है, जहां नेटवर्क क्रेडेंशियल्स का उपयोग केवल नेटवर्क कनेक्शन के लिए किया जाता है, स्थानीय थ्रेड/प्रक्रिया अनुमतियों के लिए नहीं। –

+0

बमर ... आपको PInvoke और CreateProcess का सहारा लेना पड़ सकता है। –

10

मुझे पता है कि यह एक पुराना धागा है, लेकिन यह बहुत उपयोगी था। मेरे पास कैड रूक्स के समान सटीक स्थिति है, क्योंकि मैं चाहता/नेटोनली शैली की कार्यक्षमता चाहता हूं।

जॉन राश का उत्तर एक छोटे से संशोधन के साथ काम करता है !!! LOGON32_LOGON_NEW_CREDENTIALSLOGON32_LOGON_INTERACTIVE के बजाय

private const int LOGON32_LOGON_NEW_CREDENTIALS = 9; 

फिर LogonUser करने के लिए कॉल को बदलने का उपयोग करें:

निम्नलिखित निरंतर (स्थिरता के लिए लाइन 102 के आसपास) जोड़ें।

यह केवल परिवर्तन मुझे इसे पूरी तरह से काम करने के लिए बनाना था !!! धन्यवाद जॉन और केड !!!

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

मुझे पता है कि यह कुछ साल बाद है, लेकिन धन्यवाद !!!!!!!!! इससे मुझे एक टन मदद मिली। –