?
Solved

Programmatically Create a Window's User Profile

Posted on 2005-03-21
4
Medium Priority
?
1,560 Views
Last Modified: 2008-01-09
I have written a utility program that we are using to help migrate users from our old domain controllers over to active directory. One of the pieces of this utility creates their new profile on their machine, and then migrates all of their settings from their previous profile over to their new one. I used Microsoft's KB article 196070 along with the platform SDK as my "go-by", and it seemed to work very well. That is it did until I tested it on a Win2k SP4 machine. When testing it on that system (Win2k SP4), LogonUser returns 1314 which indicates that a required privilege is not held by the client. So, what I don't understand is: why does this work on XP (SP1 and SP2) without any error, but on 2K it throws the 1314 error?

If anyone has run across this, or has any ideas, I would greatly appreciate any and all help.

Thanks,
Jeff

btw, I've pasted my code below fwiw.
///////////////////////////////////////////////////////////////
// CreateProfile
///////////////////////////////////////////////////////////////
bool      CreateProfile (LPSTR lpUser, LPSTR lpPwd)
{
//      DWORD                  dwError;
      HRESULT                  hr = S_OK;
      HANDLE                  hToken;
      PROFILEINFO            pi;
      TCHAR                  errorMsg[256];
      DWORD                  cchPath = 1024;
      TCHAR                  szUserName[20];
      bool                  bReturn = false;

      // Set USERENV.DLL function pointers
      if ( !InitUserEnv() )
      {
            _stprintf(errorMsg, TEXT("Failed to set USERENV.DLL function pointers: %d"), GetLastError());
            MessageBox(NULL, errorMsg, TEXT("CreateProfile"), MB_OK);
            bReturn = false;;
      }

      // Set USERENV.DLL function pointers
      if ( !InitUserEnv() )
      {
            _stprintf(errorMsg, TEXT("Failed to set USERENV.DLL function pointers: %d"), GetLastError());
            MessageBox(NULL, errorMsg, TEXT("CreateProfile"), MB_OK);
            return false;
      }

      lstrcpy( szUserName, lpUser );


      if ( !LogonUser(
            szUserName,                 // user name
            "US1",                      // domain or server
            lpPwd,                                    // password
            LOGON32_LOGON_INTERACTIVE,  // type of logon operation
            LOGON32_PROVIDER_DEFAULT,   // logon provider
            &hToken ) )                              // pointer to token handle
      {
            char      szError[128];
            
            wsprintf (szError, "LogonUser falied with: %d", GetLastError());
            MessageBox (NULL, szError, "_processWkstnInfo error", MB_OK);
            bReturn = false;
      }

      else
      {
            // Set up the PROFILEINFO structure that will be used to load the
            // new user's profile
            bReturn = true;
            ZeroMemory( &pi, sizeof(pi) );
            pi.dwSize = sizeof(pi);

            pi.lpUserName = (LPTSTR)szUserName;

            pi.dwFlags = PI_NOUI;

            // Load the profile. Since it doesn't exist, it will be created
            if ( !LoadUserProfile(      hToken,            // token for the user
                        &pi ) )            // pointer to PROFILEINFO structure
            {              
                  _stprintf(errorMsg, TEXT("LoadUserProfile() failed.  Error: %d"), GetLastError());
                  MessageBox(NULL, errorMsg, TEXT("CreateProfile"), MB_OK);
                  bReturn = false;
            }

            else
            {
                  // Unload the profile when it is no longer needed
                  if ( !UnloadUserProfile(hToken,                        // token for the user
                              pi.hProfile ) )            // registry key handle
                  {    
                        _stprintf(errorMsg, TEXT("UnloadUserProfile() failed.  Error: %d"), GetLastError());
                        MessageBox(NULL, errorMsg, TEXT("CreateProfile"), MB_OK);
                        bReturn = false;
                  }

                  // Release USERENV.DLL
                  if ( g_hUserEnvLib )
                  {
                        FreeLibrary( g_hUserEnvLib );
                  }      
            }
      }

      return bReturn;
}
0
Comment
Question by:jpetter
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
  • 2
4 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 13592741
Stupid Q: Have you checked whether the account you're trying to run this under on SP4 holds the SE_TCB_NAME (aka "SeTcbPrivilege" or "Act as part of the operating system") privilege?
0
 

Author Comment

by:jpetter
ID: 13592860
Way to set me up with the "stupid Q" qualifier...as a matter of fact, I have a call into the manager of our Name Admin group to ask him just that. I know that previously when I had to perform functions like this, I wrapped them in services to get around that. Now that we're running 2K and XP for desktop OS's, I can make use of CreateProcessWithLogonW, which I did to streamline the process. (getting rid of the service and the program required for the impersonation to launch it).

So, I did an end around your question. It was a concern of mine, I was surprised that it would work on XP, but not on 2K - both of which use the same account - same code. But, I should know the particulars of the account soon.

Thanks,
Jeff
0
 

Author Comment

by:jpetter
ID: 13600096
jkr,

After exchanging a number of emails with our Name Admin group, I was able to confirm what you suspected: the account does not hold the required privilege. I think what really threw me is that even though it lacks the SE_TCB_NAME privilege, it works fine on XP (both service packs).

One more question if I may. My intent here is to create the user's profile. Do you know whether I can create a profile with CreateProcessWithLogonW if I pass the value LOGON_WITH_PROFILE for the dwLogonFlags parameter? The documentation states that while time consuming, it will load the user's profile. But it doesn't state whether it will create one if none exists. I was thinking that among my options for creating the profile, I have: (1) wait for the Name Admin team to add the privilege - could take a while due to the politics involved in breaking a corporate policy. (modifying domain level policies)  (2) Call some small innocuous program CreateProcessWithLogonW, and passing the LOGON_WITH_PROFILE - if it works. (3) using a service so I can makes the calls in the local system context.

Thanks,
Jeff
0
 
LVL 86

Expert Comment

by:jkr
ID: 13602124
>>Do you know whether I can create a profile with CreateProcessWithLogonW if I pass the value
>>LOGON_WITH_PROFILE for the dwLogonFlags parameter?

Actually, I don't know whether you can do that, never tried it. But, since the docs (http://msdn.microsoft.com/library/en-us/dllproc/base/createprocesswithlogonw.asp) state "It is your responsibility to load the user registry hive into HKEY_USERS before calling CreateProcessWithLogonW, by using LOGON_WITH_PROFILE, or by calling the LoadUserProfile function.", I doubt that you'll be able to achieve the desired result. Also, using a service might not work, since the "SeTcbPrivilege" is not granted to anyone by default...
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question