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;
}
jpetterAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jpetterAuthor Commented:
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
jpetterAuthor Commented:
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
jkrCommented:
>>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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.