11 Mar
Posted by: Christian Wimmer in: JEDI Windows API Headers, JEDI Windows Security Code Lib
This article is about how to retrieve the owner of a file. If you are experienced with some of the WinAPI security function this can be pretty easy. There are some problems that needs to be addressed though. The first one is the size of the security items like the SID name of the owner. Secondly, there is the possibility that a SID cannot be resolved to a human readable name at all. And thirdly, we need to check all the result values.
Many Windows Programmers still have trouble when it comes to sessions, window stations and desktops. They frequently get mixed up and we can see a lot of question on the Internet about e.g. how to spawn processes in all logged-on user desktops (rather than sessions). Hence, I have listed some articles that you can read to get a better understanding of such things like a Terminal Sessions.
In my last article “Jwscl and FreeAndNil” there were some great comments on the source design. Oliver told me to use a guarded memory page so the memory is always invalid. With his information I wrote a source code that creates a pointer which always triggers an access violation.
There is a lot of talking about the usage of FreeAndNil in destructors. I’ve never thought about it before so I used it quite often even in destructors. Although I don’t use it as a universal remedy function, it still seems to be a bad design: a thought shared by many leading Delphi experts. Thus I refactored the destructors in JWSCL to accompany them.
I had some free time that I used to put together all the features JWSCL provides currently. There are some more features that are implemented by other tool classes or functions that I left out in favor of a good overview. A complete overview of all classes, methods and more gives you the documentation at http://jwscldoc.delphi-jedi.net.
So here are the feautures (You can look up the class names on the documentation page):
I had some trouble writing these lines because usually I do not want to publish criticism. But Oliver told me that it would be a good idea and I don’t want to disagree
.
I had some trouble with this rather complicated COM structure called ACTRL_ACCESS. So I post a diagram to show its design. Otherwise it would be a pity to leave it on my private hard drive.
I’m writing this article because I want to share programming habits with you. What habit did prove to be a good one for you? Share yours then, please. Read the rest of this entry »
I just commited (revision 843) a little bugfix that existed since revision 833. In TJwWTSSession.Create LocalFree was called (after StrConnect) without LocalAlloc. Since utildll.dll handles the memory allocation is it not needed at all.
[Update]
The fix is currently only available in the developer version repository (aka trunk) of Subversion.
08 Jan
Posted by: Remko in: JEDI Windows Security Code Lib
I have just commited an updated version of my Terminal Server unit (revision 842) into SVN. I have done some tests on Windows 7 (a fix for Windows 7 was done in Jwa revision 830 btw) and all seems to work well.
Internally the Connect method of TJwTerminalServer verifies the connection to Terminal Server by reading some property. This is done because of a change in the API’s by Microsoft: opening a handle with WTSOpenServer to a nonexisting server actually returns a valid handle. I reported this as a bug to Microsoft some time ago and the “fixed it” by changing the documentation.
For those interested in the code: it is a class function called IsValidServerHandle which can be used to verify a handle returned by WTSOpenServer:
class function TJwTerminalServer.IsValidServerHandle(const hServer: THandle): Boolean;
var
dwSize: DWORD;
WinStaInfo: WINSTATIONINFORMATIONW;
begin
{ All Windows < Vista return 0 on Invalid handle }
Result := hServer <> 0;
{ No need to continue if it's already invalid... }
if not Result then
Exit;
{ For Windows >= Vista we need to make a query to be sure
A non valid connection will fail on WTSQuerySessionInformation and will
return LastError RPC_S_SERVER_UNAVAILABLE }
if (TJwWindowsVersion.IsWindowsVista(True)) or
(TJwWindowsVersion.IsWindows2008(True)) then
begin
Result := WinStationQueryInformationW(hServer, 65536, WinStationInformation,
@WinStaInfo, sizeof(WinStaInfo), dwSize) or (GetLastError() <> RPC_S_SERVER_UNAVAILABLE);
end;
end;
A more visible change is the introduction of the Session function of TJwTerminalServer, with this function you can get all details for a specific session. It is meant for those cases where you need only one specific session and is of course far more efficient than enumerating all sessions, retrieving all sessions details and then finding the particular session in the SessionList.
The signature of the function is:
function TJwTerminalServer.Session(const SessionId: TJwSessionId = WTS_CURRENT_SESSION): TJwWTSSession;
Note that the parameter is default so you can call both:
Session := TS.Session; // Retrieve the current Session
and
Session := TS.Session(1); // Retrieve the session with SessionId 1
It is important to understand the difference between Session and Sessions: where Session returns an instance of TJwWTSSession, SessionS returns a SessionList. This is especially important because Session works with a SessionId parameters and Sessions (being a TObjectList descendant) is accessed with by Index which is just the position in the ObjectList.
If a Session is not found an EJwsclWinCallFailedException will be raised so you’d better wrap the call into a try..except handler!
The last remark is that you, the caller, are responsible for freeing the object so a more complete sample would be like this:
var
TS: TJwTerminalServer;
Session: TJwWTSSession;
begin
TS := TJwTerminalServer.Create;
try
try
Session := TS.Session;
try
// Work with the session object
ShowMessageFmt('Username=%s', [Session.Username]);
Session.PostMessage('Hello from the Jedi guys!', 'Message', MB_OK);
finally
FreeAndNil(Session);
end;
except
// Handle Exception here!
end;
finally
FreeAndNil(TS);
end;
end;