2010-01-06 85 views
2

问题:通过LoadUserProfile API为漫游用户创建漫游用户配置文件程序在Windows 2008

登录和负荷分布不正确创建配置文件。这只发生在Windows 2008(UAC off和on)下。登录使用标准的Windows登录正常工作和相同的代码工作正常在Windows 2003上

日志:

  1. http://drop.io/6t2b3f3 通过命令创建用户配置文件服务的ETL: logman - 启动配置文件-p {eb7428f5 -ab1f-4322-a4cc-1f1a9b2c5e98} 255 3 -ets 该文件需要由有权访问源的人进行分析,并希望能够了解为什么配置文件始终以临时文件加载的原因。

环境:

  1. 的Windows 2008模式域/林
  2. 服务器fs001 - 的Windows 2008标准版SP2 x86机器
  3. 文件共享上fs001 “分享” 与每个人+系统,具有全控制共享和NTFS。

重现:

  1. 与漫游配置文件设置为\ fs001 \共享\ tuser1 \简介
  2. 运行该程序的任何域管理员和本地管理员帐户上fs001创建域用户tuser1 (如果UAC以管理员身份运行),临时用户配置文件将加载到c:\ users \ temp *而不是c:\ users \ tuser1中

ETL可能是最佳方式在这里,并将提供最快捷的诊断。用户配置文件服务svchost实例和系统级别跟踪登录的Procmon没有透露太多有关错误的信息(如果需要,我可以提供更多信息,但它是死路一条)。 Windows 2003上的userenv.log会有所帮助,但ETL只能由MSFT的人员分析。

任何想法?

谢谢, 亚历克斯

using System; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 

namespace consoleLogon { 
    class Program { 
    #region Helpers for setting privilegies functionality 
    [StructLayout(LayoutKind.Sequential, Pack = 4)] 
    public struct LUID_AND_ATTRIBUTES { 
     public long Luid; 
     public int Attributes; 
    } 

    [StructLayout(LayoutKind.Sequential, Pack = 4)] 
    public struct TOKEN_PRIVILEGES { 
     public int PrivilegeCount; 
     public LUID_AND_ATTRIBUTES Privileges; 
    } 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool AdjustTokenPrivileges(
     IntPtr TokenHandle, 
     bool DisableAllPrivileges, 
     ref TOKEN_PRIVILEGES NewState, 
     int BufferLength, 
     IntPtr PreviousState, 
     IntPtr ReturnLength 
     ); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool LookupPrivilegeValue(
     string lpSystemName, 
     string lpName, 
     ref long lpLuid 
     ); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool OpenProcessToken(
     IntPtr ProcessHandle, 
     int DesiredAccess, 
     ref IntPtr TokenHandle 
     ); 

    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; 
    public const int TOKEN_QUERY = 0x00000008; 
    public const int TOKEN_DUPLICATE = 0x00000002; 
    public const int TOKEN_IMPERSONATE = 0x00000004; 
    public const int SE_PRIVILEGE_ENABLED = 0x00000002; 
    public const string SE_RESTORE_NAME = "SeRestorePrivilege"; 
    public const string SE_BACKUP_NAME = "SeBackupPrivilege"; 

    [DllImport("advapi32.dll", SetLastError = true)] 
    static public extern bool LogonUser(String lpszUsername, String lpszDomain, 
     String lpszPassword, 
     int dwLogonType, int dwLogonProvider, ref IntPtr phToken); 

    [DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)] 
    public static extern bool LoadUserProfile(
     IntPtr hToken,    // user token 
     ref PROFILEINFO lpProfileInfo // profile 
     ); 

    [DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)] 
    public static extern bool UnloadUserProfile(
     IntPtr hToken, // user token 
     IntPtr hProfile // handle to registry key 
     ); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private extern static bool DuplicateToken(
     IntPtr ExistingTokenHandle, 
     int SECURITY_IMPERSONATION_LEVEL, 
     ref IntPtr DuplicateTokenHandle 
     ); 


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    public struct PROFILEINFO { 
     public static readonly int SizeOf = Marshal.SizeOf(typeof(PROFILEINFO)); 

     public int dwSize;     // Set to sizeof(PROFILEINFO) before calling 
     public int dwFlags;    // See PI_ flags defined in userenv.h 
     public string lpUserName;   // User name (required) 
     public string lpProfilePath;  // Roaming profile path (optional, can be NULL) 
     public string lpDefaultPath;  // Default user profile path (optional, can be NULL) 
     public string lpServerName;  // Validating domain controller name in netbios format (optional, can be NULL but group NT4 style policy won't be applied) 
     public string lpPolicyPath;  // Path to the NT4 style policy file (optional, can be NULL) 
     public IntPtr hProfile;   // Filled in by the function. Registry key handle open to the root. 
    } 
    #endregion 

    static void Main(string[] args) { 
     string domain = "dev1"; 
     string userName = "tuser1"; 
     string password = "asd!234"; 
     string profilePath = @"\\fs001\TestProfiles\tuser9\profile"; 

     bool retVal = false; 
     IntPtr primaryToken = IntPtr.Zero; 
     IntPtr dupeToken = IntPtr.Zero; 
     PROFILEINFO profileInfo = new PROFILEINFO(); 
     try { 
      // Add RESTORE AND BACUP privileges to process primary token, this is needed for LoadUserProfile function 
      IntPtr processToken = IntPtr.Zero; 

      OpenProcessToken(System.Diagnostics.Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref processToken); 

      long luidRestore = 0; 
      long luidBackup = 0; 
      retVal = LookupPrivilegeValue(null, SE_RESTORE_NAME, ref luidRestore); 
      retVal = LookupPrivilegeValue(null, SE_BACKUP_NAME, ref luidBackup); 

      TOKEN_PRIVILEGES tpRestore = new TOKEN_PRIVILEGES(); 
      TOKEN_PRIVILEGES tpBackup = new TOKEN_PRIVILEGES(); 

      tpRestore.PrivilegeCount = 1; 
      tpRestore.Privileges = new LUID_AND_ATTRIBUTES(); 
      tpRestore.Privileges.Attributes = SE_PRIVILEGE_ENABLED; 
      tpRestore.Privileges.Luid = luidRestore; 

      tpBackup.PrivilegeCount = 1; 
      tpBackup.Privileges = new LUID_AND_ATTRIBUTES(); 
      tpBackup.Privileges.Attributes = SE_PRIVILEGE_ENABLED; 
      tpBackup.Privileges.Luid = luidBackup; 

      retVal = AdjustTokenPrivileges(processToken, false, ref tpRestore, 0, IntPtr.Zero, IntPtr.Zero); 
      if (false == retVal) { 
       throw new Win32Exception(); 
      } 
      retVal = AdjustTokenPrivileges(processToken, false, ref tpBackup, 0, IntPtr.Zero, IntPtr.Zero); 
      if (false == retVal) { 
       throw new Win32Exception(); 
      } 

      // Logon as user + password in clear text for sake of simple sample (protocol transitioning is better). 
      retVal = LogonUser(userName, domain, password, 3 /* LOGON32_LOGON_NETWORK */, 0 /*LOGON32_PROVIDER_DEFAULT */, ref primaryToken); 
      if (false == retVal) { 
       throw new Win32Exception(); 
      } 

      // Duplicate primary token. 
      // LoadUserProfile needs a token with TOKEN_IMPERSONATE and TOKEN_DUPLICATE access flags. 
      retVal = DuplicateToken(primaryToken, 2 /* securityimpersonation */, ref dupeToken); 
      if (false == retVal) { 
       throw new Win32Exception(); 
      } 

      // Load user profile for roaming profile 
      profileInfo.dwSize = PROFILEINFO.SizeOf; 
      profileInfo.lpUserName = domain + @"\" + userName; 
      profileInfo.lpProfilePath = profilePath; 

      Console.WriteLine("UserName: {0}", profileInfo.lpUserName); 
      Console.WriteLine("ProfilePath: {0}", profileInfo.lpProfilePath); 

      retVal = LoadUserProfile(dupeToken, ref profileInfo); 
      if (false == retVal) { 
       throw new Win32Exception(); 
      } 

      // What should happen 
      // 1. Local new profile in c:\users\tuser1.dev1 folder with copy from default. 
      // 2. Valid user registry hive ntuser.dat 
      // 3. Loaded profile session entry in the registry entry 
      //  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\SID of tuser1\ 
      //  State bit mask should have new local profile (x004), new central profile (x008), 
      //  update the central profile (0010). 
      // 
      //  "State"=dword:0000021c 
      //  "CentralProfile"="\\fs001\Share\tuser1\profile.V2" 
      //  "ProfileImagePath"="C:\Users\tuser1" 
      // 
      //  See http://technet.microsoft.com/en-us/library/cc775560(WS.10).aspx fpr more info 
      //  Roaming Profile - New User section. 
      // 
      // What actually happens: 
      // 1. Temp profile is loaded in c:\users\temp 
      // 2. Registry entry ProfieList/SID is showing temporary profile 
      //  "State"=dword:00000a04 
      //  "CentralProfile"="\\fs001\Share\tuser1\profile.V2" 
      //  "ProfileImagePath"="C:\Users\TEMP" 

      Console.WriteLine("Profile loaded, hit enter to unload profile"); 
      Console.ReadLine(); 
     } 
     catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
      Console.ReadLine(); 
     } 
     finally { 
      // Unload profile properly. 
      if (IntPtr.Zero != dupeToken) { 
       retVal = UnloadUserProfile(dupeToken, profileInfo.hProfile); 
       if (false == retVal) { 
        throw new Win32Exception(); 
       } 
      } 
     } 
    } 
} 

}

+0

当你得到用户的令牌时,我没有看到TOKEN_IMPERSONATE和TOKEN_DUPLICATE被请求作为特权...有时他们在那里,但明确地要求他们可能引发一个失败,指出你在正确的方向。 – 2011-08-28 14:04:29

+0

另外,如果这些基于bool的函数目前失败了,它们将不会给你带来任何帮助,因为它们不会捕获Win32的最后一个错误。查看这篇博客文章,了解如何操作的快速示例: http://blogs.msdn.com/b/adam_nathan/archive/2003/04/25/56643.aspx – 2011-08-28 14:07:51

回答

1

我一直在追逐了几个月了同样的问题终于有了答案。我在互联网上的其他任何地方都没有看到这个答案。它也会从LoadUserProfile的处理中移除5到10秒。这些注释仅适用于使用漫游配置文件的情况。

PROFILEINFO中的lpUserName字段至少用于Windows 2008 R2中的活动目录用户验证。它用于构建漫游配置文件路径和本地配置文件路径。如果lpUserName包含域名(mydomain \ myusername),则使用的路径包含此。但是,如果您更改lpUserName以排除域,则LoadUserProfile调用将失败。

但是,如果您只使用lpUserName中的用户名并在lpServerName中提供NetBIOS域名,则它可以工作。 NetBIOS名称通常是域名(mydomain.parent.com,例如名称为mydomain)的最高级别,在第16个字符中填充或修剪为15个字符加上十六进制1B(C#字符串中的\ u001B)。

您可以在HKLM \ Software \ Microsoft \ Windows NT \ CurrentVersion \ ProfileList {sid}的CentralProfile字符串中自己查看问题。 CentralProfile仅在尝试将漫游配置文件使用LoadUserProfile时才存在。

相关问题