Link to home
Start Free TrialLog in
Avatar of jpetter
jpetter

asked on

Programmatically Create a Window's User Profile

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;
}
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jpetter
jpetter

ASKER

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
Avatar of jpetter

ASKER

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
>>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...