问题:通过LoadUserProfile API为漫游用户创建漫游用户配置文件程序在Windows 2008
登录和负荷分布不正确创建配置文件。这只发生在Windows 2008(UAC off和on)下。登录使用标准的Windows登录正常工作和相同的代码工作正常在Windows 2003上
日志:
- http://drop.io/6t2b3f3 通过命令创建用户配置文件服务的ETL: logman - 启动配置文件-p {eb7428f5 -ab1f-4322-a4cc-1f1a9b2c5e98} 255 3 -ets 该文件需要由有权访问源的人进行分析,并希望能够了解为什么配置文件始终以临时文件加载的原因。
环境:
- 的Windows 2008模式域/林
- 服务器fs001 - 的Windows 2008标准版SP2 x86机器
- 文件共享上fs001 “分享” 与每个人+系统,具有全控制共享和NTFS。
重现:
- 与漫游配置文件设置为\ fs001 \共享\ tuser1 \简介
- 运行该程序的任何域管理员和本地管理员帐户上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();
}
}
}
}
}
}
当你得到用户的令牌时,我没有看到TOKEN_IMPERSONATE和TOKEN_DUPLICATE被请求作为特权...有时他们在那里,但明确地要求他们可能引发一个失败,指出你在正确的方向。 – 2011-08-28 14:04:29
另外,如果这些基于bool的函数目前失败了,它们将不会给你带来任何帮助,因为它们不会捕获Win32的最后一个错误。查看这篇博客文章,了解如何操作的快速示例: http://blogs.msdn.com/b/adam_nathan/archive/2003/04/25/56643.aspx – 2011-08-28 14:07:51