Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

248 lines
9.9 KiB

License Logging Service
Last Update: 11-21-94 6:30pm
by: arth
What is this licensing Stuff?
------------------------------
All back-office applications, and all the server-services will now track
useage and check for license compliance. There will be two licensing modes:
1. Per Seat - A per workstation license for the server services on a
network. This basically counts up how many unique users (based on
the username) have ever used the service and warns the admin when the
license limit has been reached.
2. Concurrent - A maximum simultaneous user limit on a server. I.E. Limit
the number of simultaneous sessions that can connect to a service.
Any server-service or back-office application can use either of these
licensing modes on any particular server as selected by the admin. Therefore
on the same server SQL could be running in Per Seat mode and RAS could be
running in Concurrent licensing mode.
File and print services (SMB Server, FPNW Server, Print Service, MAC) will use
a shared pool of licenses in Concurrent licensing mode. Therefore if
File and Print licensing limit is set to 100 and 50 people are using the SMB
server, and 50 people are using the FPNW server then no more users can access
any of the file and print services.
During installation the setup program will ask what mode of licensing the
admin is using, and if using Concurrent licensing, what session limit to
enforce (I.E. how many licenses the admin has bought). The NT setup program
will do this for file and print services. The back-office applications
(SQL, SNA, etc..) will handle this license configuration in their individual
setup programs.
What must I do?
---------------
First you will need the header and libs from NT build 856 or later to get the
latest license API and LsaLogonUser changes.
If you have your own installation/setup program then you need to put up
a dialog to check for the mode of licensing and session limit. Thomaspa's
group is working on a DLL and common dialog for this. This information is
written out to the registry.
In the service itself there are basically three different options depending
on what your needs are:
1. Let LsaLogonUser handle licensing for you.
2. Directly call the License API's and have it handle all licensing for you.
3. Handle Concurrent based licensing yourself and call the License API's
for Per Seat licensing.
1. If you call LsaLogonUser to validate connections then it is fairly easy.
First you need to call LSALogonUser with LSA_CALL_LICENSE_SERVER
(from sdk\inc\ntlsa.h) or'd into the AuthenticationParameter. This tells
LsaLogonUser to call the license service, the default is to not call the
Licensing service.
With this bit set, LsaLogonUser will call the license API for you, and the
License API will determine what mode of licensing should be used and act
appropriatly.
You must also check the return from LsaLogonUser for the new return
STATUS_LICENSE_QUOTA_EXCEEDED. This means the license limit was exceeded
and you should not let the user on.
Note: When the token received from LsaLogonUser is freed the License
service will free the session. LsaLogonUser already returns a token and
expects the code to free it, so no changes should be required in your code
for this.
2. If you call the Licensing API's directly the changes are also fairly easy.
There are two API's NtLicenseRequest and NtLicenseFree (from sdk\inc\ntlsapi.h)
Call NtLicenseRequest when a session is established and NtLicenseFree when a
session is terminated.
This method is used by the SMB server because at the time that it makes the
call to LsaLogonUser the service doesn't know if the connection is for
file i/o or pipe i/o, and pipe i/o isn't supposed to be licensed.
The Licensing API will determine what type of licensing mode should be used
and act accordingly without any special code in the service.
3. Doing it this way means you handle the Concurrent licensing yourself.
You must read from the registry the licensing mode and if in Concurrent
licensing mode you must track the session limits and reject users. You
should also have a background thread that periodically checks the registry
to see if the licensing info has changed. Only call the Licensing API's
if you are in Per Seat licensing mode.
SQL does it this way as currently SQL tracks session connection and tear
down in a way that is difficult to integrate with the licensing API, and it
is easier for them to do it themselves.
Note: If your service is one of the "file and print services" then you *MUST*
use one of the other options and let the License API handle Concurrent
Licensing. This allows the License API code to limit the file and print
services using a shared pool of licenses.
I need to call the Licensing API directly, how do I do this?
------------------------------------------------------------
First, let me (arth) know that you need to call the API directly so if there
are any changes then I can let you know about them.
The header file is in %NT_ROOT%\public\sdk\inc\ntlsapi.h
The DLL is in %NT_ROOT%\public\sdk\lib\*\ntlsapi.dll
The only two function calls you care about are:
LS_STATUS_CODE LS_API_ENTRY NtLicenseRequest(
LPSTR ProductName,
LPSTR Version,
LS_HANDLE FAR *LicenseHandle,
NT_LS_DATA *NtData);
LS_STATUS_CODE LS_API_ENTRY NtLSFreeHandle(
LS_HANDLE LicenseHandle );
There are currently only three return codes you need to worry about:
LS_SUCCESS - Everything worked
LS_INSUFFICIENT_UNITS - The license limit was exceeded (reject user)
LS_RESOURCES_UNAVAILABLE - Out of memory
The NtData field is used to pass in the username or SID and is defined as:
typedef struct {
ULONG DataType; // Type of the following data, ie. user name, sid...
VOID *Data; // Actual data. username, sid, etc...
// if call the unicode API character data
// must be in unicode as well
BOOL IsAdmin;
} NT_LS_DATA;
Set DataType to NT_LS_USER_NAME (defined in ntlsapi.h) if the Data field will
contain a username, and NT_LS_USER_SID if it will contain a SID.
Note: Please pass in a username if possible as it is quicker.
IsAdmin is a bool used to tell if the user is an Admin. This allows an admin
to still get a connection if the session limit is reached. If you don't want
or care if an admin is allowed to connect when the session limit is reached,
then just always pass in FALSE for this field.
A typical call would therefore look something like:
{
NT_LS_DATA LsData;
LS_STATUS_CODE err;
LS_HANDLE LicenseHandle;
...
LsData.DataType = NT_LS_USER_NAME;
LsData.Data = (VOID *) MyUserNameField; // wherever you keep the username
LsData.IsAdmin = FALSE; // or whatever appropriate in your case.
err = NtLicenseRequest("Microsoft SQL Server", // Your service name
"4.0", // Version of product
&LicenseHandle,
&LsData);
switch (err) {
case LS_SUCCESS:
// Go ahead and do what you want
break;
case LS_INSUFFICIENT_UNITS:
// Disallow user connection
break;
case LS_RESOURCES_UNAVAILABLE:
// License Service got an out of memory so report error as approp.
break;
}
...
NtLSFreeHandle(LicenseHandle);
...
}
ANSI and Unicode endpoints are both provided. The Data field values should
be in ANSI if calling the ANSI API's and Unicode if calling the Unicode API's.
My server is in kernel mode, how do I call these API's?
-------------------------------------------------------
All kernel mode servers should have a user-mode service (at least when I
checked before they all did). You need to thunk up to your user-mode
service and then have it make the API call.
If this causes a big problem then let me know. The License API DLL will need
to make an LPC call to the License Service so when this is coded you could
just make the LPC call directly, but sticking with using the DLL makes it
easier to change things in the future.
My server is connectionless, and using the Licensing API's isn't feasible.
--------------------------------------------------------------------------
Send me (arth) mail, these have to be handled on a case by case basis. Some
of the internet servers have this problem and the current plan is to only call
the licensing API's for authenticated connections.
I'm handling Concurrent licensing Directly, what is the registry format?
------------------------------------------------------------------------
The following is the format that server apps should use for setting and
checking the mode they operate in:
Key = \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LicenseInfo
Value= ErrorControl : REG_DWORD : 0x1
Value= Start : REG_DWORD : 0x3
Value= Type : REG_DWORD : 0x4
Subkeys :
\SNA
\SQL
\FilePrint
Value for All Subkeys=
Mode : REG_DWORD : (0x0 = Per Seat Mode, 0x1 = Concurrent/Per Server Mode)
ConcurrentLimit : REG_DWORD : (0x<limit>,
ie. 0x100 = 256 concurrent user limit)
FlipAllow : REG_DWORD : (0x0 = can change license mode, 0x1 license mode
can't be changed. Server apps are only allowed to
switch their license mode once, so after the first
switch, this value would be set to non-zero, then
the UI will warn about further changes to the
licence mode.)
Issue: Server/service apps should poll the value every hour or so in case of
change. Otherwise, if more licenses are added, or the mode changes, is it
acceptable to require the server apps to be stopped, and restarted?
What is the timeline for this stuff?
------------------------------------
These changes need to be in the servers by the PPC release.