I have a Windows service (running in the system process) and a desktop application that need to share a configuration structure. The data originates in the app, but the user process doesn't have permission to create a global memory object so I create it when the service starts using CreateFileMapping() and a DACL based on this answer. This appears to work fine: I get a non-null handle back from CreateFileMapping() and GetLastError() is 0. The problem is that the app can't see the object -- OpenFileMapping() returns a NULL handle and ERROR_FILE_NOT_FOUND -- and I also can't see it if I manually browse the global objects with WinObj. What's keeping my object from being visible?
SECURITY_ATTRIBUTES security;
ZeroMemory(&security, sizeof(security));
security.nLength = sizeof(security);
ConvertStringSecurityDescriptorToSecurityDescriptor(
"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)",
SDDL_REVISION_1,
&security.lpSecurityDescriptor,
NULL);
HANDLE hFile = CreateFileMapping(INVALID_HANDLE_VALUE, &security, PAGE_READWRITE, 0, 1024*4, "Global\\gCONFIGXFILE");
DWORD fileMappingResult = GetLastError();
if (hFile)
{
CloseHandle(hFile);
}
LocalFree(security.lpSecurityDescriptor);
Your service is closing its handle to the file mapping immediately after creating it, thus the mapping is being destroyed before the app has a chance to open its handle to the mapping. Your service needs to leave its handle to the mapping open, at least until after the app has opened its handle to the mapping.
Since you are sharing configuration, you should probably be creating the mapping at service start and leave it open until service stop. You could use a named event via CreateEvent() to let the service tell the app when the mapping has actually been created, and maybe use another named event whenever the content of the mapping is changed by either process.
Related
I have an application that is running a chromium client browser, and at some point I need to execute WMI code to access some device information, but it fails everytime. It is working only when the application is not using TChromium object. Possible TChromium(CEF3) Initializes the COM library, and only one instance is allowed on the current thread. I read that application should use CoInitializeEx with COINIT_APARTMENTTHREADED instead of CoInitialize.
It is possible to access COM library and CoInitializeSecurity when using TChromium (CEF3) in one application? If yes, how to do it?
Below is what I want to achive:
CoUninitialize();
CoInitialize(NULL);
if(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0) == S_OK)
{
// cannot get here, CoInitializeSecurity fails
... need to execute WMI code using IWbemLocator, IWbemServices ...
}
COM can be initialized only 1 time per thread. CoInitialize/Ex() can be called multiple times per thread (with corresponding CoUninitialize() calls for every successful CoInitialize/Ex() call), but COM will only be initialized on the first call, and subsequent calls will return either S_FALSE or RPC_E_CHANGED_MODE if COM has already been initialized on the calling thread.
To solve your issue, try moving your WMI code to a separate worker thread, then you have total control over how you want to initialize COM for that thread, completely separate from how COM is initialized on the main UI thread. Have your main thread create the WMI thread when needed and wait for it to terminate, then the WMI thread can query the device info and pass it back to the main thread.
I have an application where i am using ReadDirectoryChanges to monitor changes in a directory. If any new file gets created or modified or deleted, i will get notification. Once i get the notification, i use the CreateFile api to open the file with flag OPEN_EXISTING, use the handle to call other windows apis to get file attributes. The way i call CreateFile
CreateFile(path,GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL ,
NULL );
But sometimes, i get Error 32 which is sharing violation i.e the file is being used by some other process so my application is not able to access.
I added a sleep of 100ms before calling the api and it worked fine as by this time the other process has released the file(or closed handle). But i dont want to add any explicit sleep and i am not sure about the sleep time, it could be different in different environments. This time is based on trial and error
I have also tried to continuously poll/call the CreateFile until it succeeds, but it uses up resource and is not a good solution.
Is there any way where i can wait on the CloseHandle, so that i can the CreateFile then or is there any way i can avoid the error code 32
I'm looking for a possibility to create a shared memory block on Windows platforms that is write-protected for all processes except for the process that created the shared memory block.
In detail I need the following:
Process (1) has to create a shared memory block and should be able to modify the buffer.
Process (2) should be able to open and to read the created shared memory block but must not have permission to modify the content. This is important due to security/safty reasons.
Currently I have a solution creating a shared memory block using CreateFileMapping() together with MapViewOfFile() which then has read and write permission in process (1) and (2) like:
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, highSize, lowSize, L"uniquename");
void* sharedMemory = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
// now we can modify sharedMemory...
These two lines of code can be applied in both processes as the first process creates the shared memory block and the second process simply opens the shared memory.
However, obviously the second process will have write permission due to the provided access values (PAGE_READWRITE and FILE_MAP_ALL_ACCESS) during creation of the memory block.
I would need to create the shared memory block in process (1) by using access values PAGE_READONLY and FILE_MAP_READ but obviously than I'm not allowed to initialize/set/modify the memory block in process (1) which than is a useless memory buffer.
To my best knowledge, the definition of security attributes can not solve the problem as my problem does not depend on users or groups.
I even would be happy with a solution which creates a shared memory block in process (1) relying on memory content that is known before the creation of the shared memory block (and which will not be modified in process (1) afterwards).
Do you trust process #2 to use FILE_MAP_READ? That will prevent accidental overwrites from e.g. wild pointers corrupting the shared memory.
If you're trying to protect against malicious overwrites, then you need to use the OS-provided security principals and run process #2 in a different session with lesser credentials. If process #2 runs under the same security credentials as process #1, then it can perform any operation process #1 can perform (for example, by injecting code into process #1).
(On Windows, users are security principals and processes are not. Users are not the only level of restriction, for example User Access Control in Vista and later creates tokens corresponding to an administrative user both with and without the Administrators group membership)
Since you say process #1 doesn't need continuing write access, only one time, you could create the mapping, map it for write, then adjust the ACL using SetSecurityInfo so that future accesses cannot write.
Another possibility is to instead map a disk file, and open it with FILE_SHARE_READ (but not FILE_SHARE_WRITE) access from the first process.
But neither of these prevent process #2 from coercing process #1 to make changes on its behalf. Only using separate tokens can prevent coercion.
You don't explain why you can't provide different arguments in each case, so I'm going to assume you don't know which process is the creator until you have the file open. In which case, you might want to try:
HANDLE h = OpenFileMapping(FILE_MAP_READ, /*args*/);
if (h) {
v = MapViewOfFile(h, FILE_MAP_READ, 0, 0, 0);
} else {
h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, highSize, lowSize, L"uniquename");
if (!h)
FirePhotonTorpedoes();
v = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
The CreateFileMapping function allows you to set an ACL for the file mapping object. If you create an ACL that only allows read-only access, other processes should be unable to open the file mapping object with read-write access.
Typically, when creating an object, the permissions you assign don't apply to the handle you obtain during creation. However, I haven't tested this with CreateFileMapping in particular.
This only provides weak protection. A malicious process could change the permissions on the file mapping object, or inject code into the process that created the object.
First, I'd like to note that I need to use the COM/OLE2 APIs, the low level stuff, the stuff you can put in a C Windows Console program. I can't use MFC. I can't use .NET.
My question is:
Given the following code:
CLSID clsid;
HRESULT hr;
hr = CLSIDFromProgID(L"InternetExplorer.Application", &clsid);
assert(SUCCEEDED(hr));
hr = CoCreateInstance(clsid,
NULL,
CLSCTX_LOCAL_SERVER,
IID_IDispatch,
(void **)&(iePtr_));
assert(SUCCEEDED(hr));
Is there a way to write some information to the disk so that I can reconnect to the same instance of IE later on? Basically can "iePtr_" be stringified for later reconstitution by some other process?
Thanks.
---- added later------
The broader problem I am trying to solve is that I want to start an AutoCAD application, load some data into it, and then leave it running for my client to interact with. Later he will go back to my application and I want to reconnect to the same AutoCAD session and feed it more data.
Now, I full well realize I can keep the IDispatch pointer in memory in my application and I'll be able to continue to interact with the same AutoCAD process. That's my fallback position.
However, I use a "wrapper" program to do my COM stuff. So the wrapper is transient. My main application starts the wrapper, then the wrapper communicates, and then exits. I just want subsequent wrapper processes to be able to reconnect to the same AutoCAD process.
Why use a wrapper? Here's the working reason: My main application is a 32-bit application, but I can use a 64-bit wrapper and communicate with 64-bit AutoCAD. I need to be able to communicate with 64-bit AutoCAD and can probably not port my main application easily (500K+ lines of C++) vs. my wrapper program (couple hundred lines).
If the application registered itself in the Running Object Table, you can use the GetActiveObject function to get a reference to the application object.
IUnknown *pUnknown;
hr = GetActiveObject(clsid, NULL, &pUnknown);
assert(SUCCEEDED(hr));
hr = pUnknown->QueryInterface(IID_IDispatch, (void **)&(iePtr_));
assert(SUCCEEDED(hr));
CoMarshalInterface (and related APIs) can be used to marshal an interface into another thread, process or different PC on the network. I don't know how long you are allowed to wait before completing the marshaling process, but in principal, if the object you are marshaling an interface to has not been closed the marshaling process can be completed later.
Being able to destroy an OLE object and later restore "the same object" is tied into what are called Monikers, and if you (can) understand those then your OLE/COM Juju is powerful indeed.
I'd suggest making the wrapper layer long lived rather than transient, therefore it can easily hold a single reference to the third application.
The wrapper can still appear transient to the client code.
If you make the wrapper a COM singleton then each time you cocreate it, you will get back the same instance.
To ensure the wrapper lives for the lifetime of your client hold a reference from startup to shutdown. This reference does not need to be wired through to other code. All other code simply creates the singleton every time it wants it.
Nope, that's impossible. The whole idea of COM is that the COM server is started transparently and only preserves state until you have stopped using its objects. After you've released the COM objects the COM subsystem is free to completely stop the server and there's no way to recreate the same process. The only way a similar result would be possible is to have a COM object with serialization methods that would permit saving the state into a stream and restoring it from a stream. But even then you would have to CoCreateInstance() again, obtain a new COM object interface pointer and call the restore method of that object.
The pointer you get from CoCreateInstance is only valid for the current process, if you save it on disk and restore later it will become invalid.
I'm using the ShellExecuteEx function in a C++ program to launch an Uninstall.lnk file. In my program, I'd like to wait for the uninstaller to finish. My first attempt was to set the SEE_MASK_NOCLOSEPROCESS flag in the SHELLEXECUTEINFO structure and then call WaitForSingleObject on the hProcess handle available in the SHELLEXECUTEINFO structure passed to ShellExecuteEx, but that still seemed to return way too early.
My current suspicion is that this is because the process launched by ShellExecuteEx (does it launch a new shell?) creates new child processes, but doesn't wait for them. So I'm trying to create a "wait for my child process and all the children it launches" function. To do so, I'm trying to use job objects.
I created a job object using CreateJobObject, assigned the process handle returned by ShellExecuteEx to the job and then attempted to wait for the job object. Unfortunately assigning the process to the job failed, and I think this is due to insufficient access rights.
Does anybody know how to set the PROCESS_SET_QUOTA and PROCESS_TERMINATE access rights (which are required for AssignProcessToJobObject to succeed, according to the MSDN) on a process handle, or another way to wait for the process launched by ShellExecuteEx to finish?
UPDATE: I should point out that I'm also launching other applications, not just Uninstall.lnk. One of them is e.g. a ClickOnce application, which is effectively a simple XML file with the file extension .application.
Vista uses job objects for launching links. Therefor the process you try to assign to another job object might already be assigned.
See: this question
Why not to execute target file instead of openning Uninstall.lnk? You could use IShellLink to get shortcut target. Then you'll be able to execute target file via ShellExecuteEx using SEE_MASK_NOCLOSEPROCESS flag.