WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

wNT
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Setting Service Permissions


Question:

I have a service that I am installing via a wise package and it requires that everyone be able to start and stop the service. I wanted to use wntAccessAdd() to set those permissions. There are no real examples in the help files or in the database for what those access flags should be. What I would like is an example of that one line of code. Even if it is giving Everyone Full Control, that's good enough for me. Can you help?

Answer:

Yes, it's true, there aren't any pre-defined access strings for setting the security on a service. When support for services [object types 600 & 601] were added, it was done more for completeness rather than to meet any particular end-user's requirements. As such, the base functionality is there but there really wasn't any demand for pre-defined access strings since there currently isn't a built-in security property page that allows an administrator to modify a service's security settings via a GUI interface like you can for folders, files and registry keys. If a GUI interface had existed, it would have represented a "simplified" view of the permissions settings with checkbox controls and there would have been some access strings defined to match what the GUI shows.

So, moving forward, regarding getting & setting permissions on services, here we go....

wntAccessList() will return the names [or optionally SID values] of accounts that have either explicitly assigned or inherited permissions on a securable object. In the case of a service, I seem to recall that there isn't any inheritance as there's no parent-child hierarchical relationship and thus ACL inheritance doesn't apply to services. Please note that *ONLY* the account names and/or SID values are returned, not the actual permissions themselves.

wntAccessGet() must be called for each security principal [e.g. account name or SID value] in order to obtain the specific ACE[s] that the security principal has in the ACL. The proper technique is to call wntAccessList() one time to get a list of security principals and then use ItemExtract() & wntAccessGet() in a loop to retrieve the permissions for each security principal.

If wntAccessList() returns an empty string, it means that the DACL [Discretionary Access Control List] is *MISSING*, which is not the same as being present but empty in terms of having no ACEs present in the empty DACL. The NT Platform Family usually treats a missing DACL as meaning "Everyone - Full Control". In the case of folders, file and registry keys, and even on shares, this is the case. Incidentally, in some cases, the wntAccessList()/wntAccessGet() functions are either fooled into reporting this, or they may even have been coded to lie and return these results in order to match what the GUI tools already do when the DACL is missing.

In the case of services, starting & stopping services may require explicit permissions to be assigned by an administrator in order for non-administrator accounts to start & stop a service. This is simply an exception in how the NT Platform Family is interpreting a missing DACL when dealing with services. Rather than having to apply explicit permissions by default for the administrator to manage services, the O.S. instead behaves as observed where a total lack of a DACL means that you must have administrator rights to manage services.

Regardless of these differences, you would still use wntAccessAdd() to add some explicit permissions to a service to allow non-administrator users to start & stop a service. Be very careful when doing this as some services have dependencies such that a user may require modified permissions on several services in order to properly stop, start or restart an entire set of services.

The basic docs for what you need to compose your own access records are in the help topic for wntAccessAdd(). Specifically, after the section that details the pre-defined access strings, there are additional sections of text that define the allowable values for the 3 parts of each access record.

"record-type:access-flags:access-rights"

The "record-type" field identifies the type of ACE that is being added, with a value of "0" for access-allowed ACEs and a value of "1" for access-denied ACEs. Denial of access takes precedence over allowing of access, so be sure not to apply any denial ACEs that might mask off permissions that you are intentionally wanting to grant via an access-allowed ACE.

The "access-flags" value is a bit-mask value, and for purposes of permissions ACEs in the DACL of a service, the value can be "0".

The "access-rights" portion is also a bit-mask value. There is a list of numeric values in decimal & hex, along with the names of their corresponding C-language constants are defined in the Windows Platform SDK. There are multiple constants that exist for each access-rights bit; this is so due to the fact that each access-rights bit may have a *different* meaning depending on the type of object [e.g. folder/file, registry key, windowstation, desktop, printer, file share, print share, service, etc...] to which the ACE is applied. These constants may have something liek "(Dir)" or "(File/Pipe)" or "(RegKey)" following their names as a hint/clue that indicates what sorts of objects the bit & its particular meaning are applicable to. The names of the constants themselves also typically help to identify what types of objects they apply to. In the case of services, all of the service-related access-rights bit constants have names beginning with "SERVICE_".

The service-related bits are as follows:

1   SERVICE_QUERY_CONFIG
2   SERVICE_CHANGE_CONFIG
4   SERVICE_QUERY_STATUS
8   SERVICE_ENUMERATE_DEPENDENTS
16  SERVICE_START
32  SERVICE_STOP
64  SERVICE_PAUSE_CONTINUE
128 SERVICE_INTERROGATE
256 SERVICE_USER_DEFINED_CONTROL
Then, there are the more generic access-rights bits as follows:
65536       DELETE
131072      READ_CONTROL
262144      WRITE_DAC
524288      WRITE_OWNER
1048576     SYNCHRONIZE
16777216    ACCESS_SYSTEM_SECURITY
268435456   GENERIC_ALL
536870912   GENERIC_EXECUTE
1073741824  GENERIC_WRITE
-2147483648 GENERIC_READ
The constants named "GENERIC_*", when used in an ACE, may be translated by the O.S. into specific sets of object type specific access-rights mask values. The "DELETE" bit is required to be granted if a user should be able to delete the object, while "READ_CONTROL" allows a user to read the security settings on the object. "WRITE_DAC" is required if the user should be allowed to modify the permissions [DACL]. "WRITE_OWNER" is required if the user should be allowed to change the object's ownership. The "SYNCHRONIZE" bit isn't of much interest in terms of what WinBatch does with securable objects, but if an application needs to make certain API function calls that "wait" on an object until it is in a "signaled" state, then the application needs to be running as a user that has this permission assigned in the object's DACL. Finally, "ACCESS_SYSTEM_SECURITY" grants the user permissions to both read and write the auditing ACEs that are in the SACL [System ACL] in the object.

If you want a user to start & stop a service, then you definitely need to combine the bit values for the bits that grant these permissions and use the combined value as your access-rights mask value. Given that these values are 16 and 32, performing a bit-wise OR operation to combine them yields a result of 48. You probably also need to query the status of a service, too, so combine a value of 4 with the other bit values to get an access-rights mask of 52.

The resulting access record would be "0:0:52" to grant start/stop/query-status permissions on a service for any given user or group.

If you've previously set the desired permissions via some other 3rd party tool, you can go back and use the wntAccessList()/wntAccessGet() functions to dump out the security settings in a format that can be fed directly back into wntAccessAdd() in order to re-create those settings at a later time or on another system.

User Reply:

After setting the ACL with setACL, I can now see the Access string should be 0:0:131581

Answer:

Let's dissect that access record value of "0:0:131581".

As expected, it's of type Access-Allowed [0], has no inheritance flags [0] and has an access-mask value [131581 decimal]. The hex representation of 131581 is 0x000201FD. Breaking that down, we have the following access-mask bit values that were combined in a bit-wise OR operation:

0x00020000 = READ_CONTROL
0x00000100 = SERVICE_USER_DEFINED_CONTROL
0x00000080 = SERVICE_INTERROGATE
0x00000040 = SERVICE_PAUSE_CONTINUE
0x00000020 = SERVICE_STOP
0x00000010 = SERVICE_START
0x00000008 = SERVICE_ENUMERATE_DEPENDENTS
0x00000004 = SERVICE_QUERY_STATUS
0x00000001 = SERVICE_QUERY_CONFIG
In a nutshell, the user can read the service's configuration, cannot modify the configuration, can query the service's status, can interrogate the service, can start/stop/pause/continue the service, can enumerate all of the other services that are dependent upon the specified service and the user can read the security settings on the service. This all seems to be fairly straight forward in terms of the types of permissions that are being granted based on what you want your users to be able to do with the service.
Article ID:   W17066
File Created: 2007:07:03:14:28:04
Last Updated: 2007:07:03:14:28:04