• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 464
  • Last Modified:

How to programaticaly set the 'log on as a service' privilege for specific user account

I am wondering how I can set the log on as a service privledge for a user account at the time that the service is installed?

PT
0
ptrennum
Asked:
ptrennum
  • 3
  • 3
1 Solution
 
jkrCommented:
As if I already knew it :o)

The following code is an adaption of MSDN's 'lsapriv' sample, which is no longer available online. Just add

extern "C"
int SetPrivilege    (   wchar_t*    pwcAccount,
                        wchar_t*    pwcMachine,
                        wchar_t*    pwszPriv,
                        BOOL        bEnable
                    );

to your header files.

/*++

Copyright 1996 - 1997 Microsoft Corporation

Module Name:

    privs.c

Abstract:

    This module illustrates how to use the Windows NT LSA security API
    to manage account privileges on the local or a remote machine.

    When targetting a domain controller for privilege update operations,
    be sure to target the primary domain controller for the domain.
    The privilege settings are replicated by the primary domain controller
    to each backup domain controller as appropriate.  The NetGetDCName()
    Lan Manager API call can be used to get the primary domain controller
    computer name from a domain name.

    For a list of privilges, consult winnt.h, and search for
    SE_ASSIGNPRIMARYTOKEN_NAME.

    For a list of logon rights, which can also be assigned using this
    sample code, consult ntsecapi.h, and search for SE_BATCH_LOGON_NAME

    You can use domain\account as argv[1]. For instance, mydomain\scott will
    grant the privilege to the mydomain domain account scott.

    The optional target machine is specified as argv[2], otherwise, the
    account database is updated on the local machine.

    The LSA APIs used by this sample are Unicode only.

    Use LsaRemoveAccountRights() to remove account rights.

Author:

    Scott Field (sfield)    17-Apr-96
        Minor cleanup

    Scott Field (sfield)    12-Jul-95

--*/

#ifndef UNICODE
#define UNICODE
#endif // UNICODE

#include <windows.h>
#include <stdio.h>

#include "ntsecapi.h"


NTSTATUS
OpenPolicy(
    LPWSTR ServerName,          // machine to open policy on (Unicode)
    DWORD DesiredAccess,        // desired access to policy
    PLSA_HANDLE PolicyHandle    // resultant policy handle
    );

BOOL
GetAccountSid(
    LPTSTR SystemName,          // where to lookup account
    LPTSTR AccountName,         // account of interest
    PSID *Sid                   // resultant buffer containing SID
    );

NTSTATUS
SetPrivilegeOnAccount(
    LSA_HANDLE PolicyHandle,    // open policy handle
    PSID AccountSid,            // SID to grant privilege to
    LPWSTR PrivilegeName,       // privilege to grant (Unicode)
    BOOL bEnable                // enable or disable
    );

void
InitLsaString(
    PLSA_UNICODE_STRING LsaString, // destination
    LPWSTR String                  // source (Unicode)
    );

void
DisplayNtStatus(
    LPSTR szAPI,                // pointer to function name (ANSI)
    NTSTATUS Status             // NTSTATUS error value
    );

void
DisplayWinError(
    LPSTR szAPI,                // pointer to function name (ANSI)
    DWORD WinError              // DWORD WinError
    );

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

//
// If you have the ddk, include ntstatus.h.
//
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
#endif
int SetPrivilege    (   wchar_t*    pwcAccount,
                        wchar_t*    pwcMachine,
                        wchar_t*    pwszPriv,
                        BOOL        bEnable
                    )
{
    LSA_HANDLE PolicyHandle;

    PSID pSid;

    NTSTATUS Status;
    int iRetVal=RTN_ERROR;          // assume error from main

    //
    // Pick up account name on argv[1].
    // Assumes source is ANSI. Resultant string is ANSI or Unicode
    //
//    wsprintf(AccountName, TEXT("%hS"), pwcAccount);

    //
    // Open the policy on the target machine.
    //
    Status = OpenPolicy(
                pwcMachine,      // local machine
                POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
                &PolicyHandle       // resultant policy handle
                );

    if(Status != STATUS_SUCCESS) {
        DisplayNtStatus("OpenPolicy", Status);
        return RTN_ERROR;
    }

    //
    // Obtain the SID of the user/group.
    // Note that we could target a specific machine, but we don't.
    // Specifying NULL for target machine searches for the SID in the
    // following order: well-known, Built-in and local, primary domain,
    // trusted domains.
    //
    if(GetAccountSid(
            NULL,       // default lookup logic
            pwcAccount,// account to obtain SID
            &pSid       // buffer to allocate to contain resultant SID
            )) {
        //
        // We only grant the privilege if we succeeded in obtaining the
        // SID. We can actually add SIDs which cannot be looked up, but
        // looking up the SID is a good sanity check which is suitable for
        // most cases.

        //
        // Grant the SeServiceLogonRight to users represented by pSid.
        //
        Status = SetPrivilegeOnAccount(
                    PolicyHandle,           // policy handle
                    pSid,                   // SID to grant privilege
                    pwszPriv, // Unicode privilege
                    bEnable                    // enable the privilege
                    );

        if(Status == STATUS_SUCCESS)
        {
            iRetVal = RTN_OK;
#ifdef _DEBUG
            wprintf ( L"'%s' modified for '%s'\n",  pwszPriv,   pwcAccount);
#endif
        }
        else
            DisplayNtStatus("SetPrivilegeOnAccount", Status);
    }
    else {
        //
        // Error obtaining SID.
        //
        DisplayWinError("GetAccountSid", GetLastError());
    }

    //
    // Close the policy handle.
    //
    LsaClose(PolicyHandle);

    //
    // Free memory allocated for SID.
    //
    if(pSid != NULL) HeapFree(GetProcessHeap(), 0, pSid);

    return iRetVal;
}

/*++
This function attempts to obtain a SID representing the supplied
account on the supplied system.

If the function succeeds, the return value is TRUE. A buffer is
allocated which contains the SID representing the supplied account.
This buffer should be freed when it is no longer needed by calling
HeapFree(GetProcessHeap(), 0, buffer)

If the function fails, the return value is FALSE. Call GetLastError()
to obtain extended error information.

Scott Field (sfield)    12-Jul-95
--*/

BOOL
GetAccountSid(
    LPTSTR SystemName,
    LPTSTR AccountName,
    PSID *Sid
    )
{
    LPTSTR ReferencedDomain=NULL;
    DWORD cbSid=128;    // initial allocation attempt
    DWORD cchReferencedDomain=16; // initial allocation size
    SID_NAME_USE peUse;
    BOOL bSuccess=FALSE; // assume this function will fail

    __try {

    //
    // initial memory allocations
    //
    *Sid = (PSID)HeapAlloc(GetProcessHeap(), 0, cbSid);

    if(*Sid == NULL) __leave;

    ReferencedDomain = (LPTSTR)HeapAlloc(
                    GetProcessHeap(),
                    0,
                    cchReferencedDomain * sizeof(TCHAR)
                    );

    if(ReferencedDomain == NULL) __leave;

    //
    // Obtain the SID of the specified account on the specified system.
    //
    while(!LookupAccountName(
                    SystemName,         // machine to lookup account on
                    AccountName,        // account to lookup
                    *Sid,               // SID of interest
                    &cbSid,             // size of SID
                    ReferencedDomain,   // domain account was found on
                    &cchReferencedDomain,
                    &peUse
                    )) {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
            //
            // reallocate memory
            //
            *Sid = (PSID)HeapReAlloc(
                        GetProcessHeap(),
                        0,
                        *Sid,
                        cbSid
                        );
            if(*Sid == NULL) __leave;

            ReferencedDomain = (LPTSTR)HeapReAlloc(
                        GetProcessHeap(),
                        0,
                        ReferencedDomain,
                        cchReferencedDomain * sizeof(TCHAR)
                        );
            if(ReferencedDomain == NULL) __leave;
        }
        else __leave;
    }

    //
    // Indicate success.
    //
    bSuccess = TRUE;

    } // try
    __finally {

    //
    // Cleanup and indicate failure, if appropriate.
    //

    HeapFree(GetProcessHeap(), 0, ReferencedDomain);

    if(!bSuccess) {
        if(*Sid != NULL) {
            HeapFree(GetProcessHeap(), 0, *Sid);
            *Sid = NULL;
        }
    }

    } // finally

    return bSuccess;
}

NTSTATUS
SetPrivilegeOnAccount(
    LSA_HANDLE PolicyHandle,    // open policy handle
    PSID AccountSid,            // SID to grant privilege to
    LPWSTR PrivilegeName,       // privilege to grant (Unicode)
    BOOL bEnable                // enable or disable
    )
{
    LSA_UNICODE_STRING PrivilegeString;

    //
    // Create a LSA_UNICODE_STRING for the privilege name.
    //
    InitLsaString(&PrivilegeString, PrivilegeName);

    //
    // grant or revoke the privilege, accordingly
    //
    if(bEnable) {
        return LsaAddAccountRights(
                PolicyHandle,       // open policy handle
                AccountSid,         // target SID
                &PrivilegeString,   // privileges
                1                   // privilege count
                );
    }
    else {
        return LsaRemoveAccountRights(
                PolicyHandle,       // open policy handle
                AccountSid,         // target SID
                FALSE,              // do not disable all rights
                &PrivilegeString,   // privileges
                1                   // privilege count
                );
    }
}

void
InitLsaString(
    PLSA_UNICODE_STRING LsaString,
    LPWSTR String
    )
{
    DWORD StringLength;

    if(String == NULL) {
        LsaString->Buffer = NULL;
        LsaString->Length = 0;
        LsaString->MaximumLength = 0;
        return;
    }

    StringLength = lstrlenW(String);
    LsaString->Buffer = String;
    LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
    LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
}

NTSTATUS
OpenPolicy(
    LPWSTR ServerName,
    DWORD DesiredAccess,
    PLSA_HANDLE PolicyHandle
    )
{
    LSA_OBJECT_ATTRIBUTES ObjectAttributes;
    LSA_UNICODE_STRING ServerString;
    PLSA_UNICODE_STRING Server;

    //
    // Always initialize the object attributes to all zeroes.
    //
    ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));

    if (ServerName != NULL) {
        //
        // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
        //
        InitLsaString(&ServerString, ServerName);
        Server = &ServerString;
    } else {
        Server = NULL;
    }

    //
    // Attempt to open the policy.
    //
    return LsaOpenPolicy(
                Server,
                &ObjectAttributes,
                DesiredAccess,
                PolicyHandle
                );
}

void
DisplayNtStatus(
    LPSTR szAPI,
    NTSTATUS Status
    )
{
    //
    // Convert the NTSTATUS to Winerror. Then call DisplayWinError().
    //
    DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
}

void
DisplayWinError(
    LPSTR szAPI,
    DWORD WinError
    )
{
    LPSTR MessageBuffer;
    DWORD dwBufferLength;

    //
    // TODO: Get this fprintf out of here!
    //
    fprintf(stderr,"%s error %d!\n", szAPI, WinError);

    if(dwBufferLength=FormatMessageA(
                        FORMAT_MESSAGE_ALLOCATE_BUFFER |
                        FORMAT_MESSAGE_FROM_SYSTEM,
                        NULL,
                        WinError,
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                        (LPSTR) &MessageBuffer,
                        0,
                        NULL
                        ))
    {
        DWORD dwBytesWritten; // unused

        //
        // Output message string on stderr.
        //
        WriteFile(
            GetStdHandle(STD_ERROR_HANDLE),
            MessageBuffer,
            dwBufferLength,
            &dwBytesWritten,
            NULL
            );

        //
        // Free the buffer allocated by the system.
        //
        LocalFree(MessageBuffer);
    }
}
0
 
ptrennumAuthor Commented:
Sorry, theres a lot to look at here.  So should I then copy this code into my project and call set privilege() before I call createService?  And you wouldn't happen to have an example of a call to SetPrivilege() would yah??

PT
0
 
jkrCommented:
>>So should I then copy this code into my project and call set privilege() before I call createService?

That was the idea :o)

>> And you wouldn't happen to have an example of a call to SetPrivilege() would yah??

Of course - I thought that one was the easy part:

#include <lmcons.h>

void SetSeServiceLogonRightOnAccount ( wchar_t* pwszName) {

    wchar_t awcDomUsrName[LM20_DNLEN + LM20_UNLEN + 1];
    wchar_t awcWkSta[MAX_COMPUTERNAME_LENGTH + 2];
    DWORD   dwBufSiz = MAX_COMPUTERNAME_LENGTH  + 1;

    GetComputerName ( awcWkSta, &dwBufSiz);

    wsprintf ( awcDomUsrName, L"%s\\%s", awcWkSta, pwszName);  

    SetPrivilege ( awcDomUsrName, NULL, L"SeServiceLogonRight", TRUE);
}
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
ptrennumAuthor Commented:
It seems to return success yet I do not see the new client added to the privilege in the security settings??
0
 
ptrennumAuthor Commented:
Sorry it worked just needed to be refreshed.  Again JKR you're the master, Thanks!!

PT
0
 
jkrCommented:
That's the problem with the security/privilege settings -  if you alter them for your current account, you need to log out and back in for the changes to take effect...
0
 
itsmeandnobodyelseCommented:
I tried to make the code shorter. It compiles but I am currently working on a system where I have no admin rights So, I couldn't test the prog.

Regards, Alex

#ifndef UNICODE
#define UNICODE

#endif // UNICODE

#include <windows.h>
#include <stdio.h>

#include "ntsecapi.h"
#include <winerror.h>

int main()
{
    LSA_HANDLE hPol;
    WCHAR wszComputerName[256]=L"MYWORKSTATION";   // static machine name buffer
    TCHAR tszAccountName[256]=TEXT("MYACCOUNT");   // static account name buffer

    unsigned short wlen = (unsigned short)lstrlenW(wszComputerName) * sizeof(WCHAR);
    LSA_OBJECT_ATTRIBUTES objectAttributes = { 0 };
    LSA_UNICODE_STRING    lsaServer = { wlen, wlen + (unsigned short)sizeof(WCHAR), wszComputerName };

    int ret = 0;
    if ((ret = LsaOpenPolicy(&lsaServer, &objectAttributes,
                      POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, &hPol))
        != 0)  
        return LsaNtStatusToWinError(ret);

    SID             sid;
    PSID            pSid  = &sid;
    SID_NAME_USE    snUse = SidTypeUnknown;

    unsigned long   cbSid               = sizeof(SID);
    unsigned long   cbrefDomainName     = 0;
    LPTSTR          ptszRefDomainName   = NULL;

    ret = LookupAccountName(NULL, tszAccountName, pSid, &cbSid, ptszRefDomainName, &cbrefDomainName, &snUse);
    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
        return GetLastError();
    pSid                = (PSID)   new unsigned char[cbSid];  
    ptszRefDomainName   = (LPTSTR) new TCHAR[cbrefDomainName];
    if ((ret = LookupAccountName(NULL, tszAccountName, pSid, &cbSid,
         ptszRefDomainName, &cbrefDomainName, &snUse)) != 0)
        return GetLastError();

    LPWSTR wszServiceLogonRight = L"SeServiceLogonRight";
    wlen = (unsigned short)lstrlenW(wszServiceLogonRight) * sizeof(WCHAR);;
    LSA_UNICODE_STRING privString = { wlen, (unsigned short)sizeof(wszServiceLogonRight), wszServiceLogonRight };

    if ((ret = LsaAddAccountRights(hPol, pSid, &privString, 1)) != 0)
        return LsaNtStatusToWinError(ret);
   
    LsaClose(hPol);
    delete [] (unsigned char*)pSid;
    delete [] ptszRefDomainName;
    return 0;
}
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now