ERROR_BAD_INHERITANCE_ACL from SetNamedSecurityInfo? - windows

What does ERROR_BAD_INHERITANCE_ACL returned from SetNamedSecurityInfo imply? In this case I'm adding a user to a directory's ACL. I've looked at the directory in question and its rights seem reasonable before the call. But the calls fails.
Any thoughts?
Here is the code snippet doing the work (and as I paste it here, I'm wondering about the NO_MULTIPLE_TRUSTEE value):
pAAP is a pointer to a structure with the following members:
CString objName; // name of object
SE_OBJECT_TYPE ObjectType; // type of object
CString trustee; // trustee for new ACE (explicit user name)
CString targetComputer;
bool bNeedWrite;
DWORD dwRes = 0;
PACL pOldDACL = NULL, pNewDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea = {0};
CSID trusteeSID;
bool bGotSID = false;
if(0 == wcsncmp(pAAP->trustee, L"SID:", 4)) //4 = len of SID: //GLOK
bGotSID = CSID::FromString((LPWSTR)((LPCWSTR)pAAP->trustee + 4), trusteeSID);
else
bGotSID = CSID::FromAccount(pAAP->targetComputer, pAAP->trustee, trusteeSID);
if(false == bGotSID)
{
Log(logDEBUG, L"CSID::FromAccount failed for [%s] on [%s]. GLE=%s", pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(GetLastError()));
_ASSERT(0);
goto Cleanup;
}
// Get a pointer to the existing DACL.
dwRes = GetNamedSecurityInfo(pAAP->objName.LockBuffer(), pAAP->ObjectType, DACL_SECURITY_INFORMATION,
NULL, NULL, &pOldDACL, NULL, &pSD);
pAAP->objName.UnlockBuffer();
if (ERROR_SUCCESS != dwRes)
{
Log(logDEBUG, L"GetNamedSecurityInfo failed on [%s] for [%s] on [%s]. GLE=%s", pAAP->objName, pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(dwRes));
//_ASSERT(ERROR_FILE_NOT_FOUND == dwRes);
goto Cleanup;
}
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
ea.grfAccessPermissions = pAAP->bNeedWrite ? GENERIC_ALL : GENERIC_READ;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = (LPWSTR)(PSID)trusteeSID;
ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
// Create a new ACL that merges the new ACE into the existing DACL.
dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
if (ERROR_SUCCESS != dwRes)
{
Log(logDEBUG, L"SetEntriesInAcl failed on [%s] for [%s] on [%s]. GLE=%s", pAAP->objName, pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(dwRes));
//_ASSERT(0);
goto Cleanup;
}
// Attach the new ACL as the object's DACL.
dwRes = SetNamedSecurityInfo(pAAP->objName.LockBuffer(), pAAP->ObjectType, DACL_SECURITY_INFORMATION,
NULL, NULL, pNewDACL, NULL);
if (ERROR_SUCCESS != dwRes)
{
Log(logDEBUG, L"SetNamedSecurityInfo failed on [%s] for [%s] on [%s]. GLE=%s", pAAP->objName, pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(dwRes));
//_ASSERT(dwRes == ERROR_BAD_INHERITANCE_ACL);
goto Cleanup;
}
Cleanup:
if(pSD != NULL)
LocalFree((HLOCAL) pSD);
if(pNewDACL != NULL)
LocalFree((HLOCAL) pNewDACL);

A code sample would definitely help. It's easy to get the logic to build and set the ACL subtly wrong.
I don't have the code in front of me, but the basic logic is:
acquire the process token with a sufficient access mask
GetNamedSecurityInfo
allocate a new ACL big enough for the new ACE, copy from the old to the new, and call AddAccessAllowedAceEx to add the user's SID
SetNamedSecurityInfo

Related

Using OleCreatePropertyFrame to set/inspect webcam capture pin properties

I am trying to use OleCreatePropertyFrame() to set the WebCam properties on the filter Capture pin (controls frame rate, etc). The amcap program released by Microsoft does this.
The amcap program builds a filter graph, and then uses:
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Interleaved, gcap.pVCap,
IID_IAMVideoCompression, (void **)&gcap.pVC);
To find the interface for which to extract the property pages.
I want to get it work by directly finding the capture pin on the filter.
https://learn.microsoft.com/en-us/windows/win32/api/strmif/nn-strmif-iamstreamconfig
seems to imply this should work.
In the following code, the call to OleCreatePropertyFrame() segment faults.
I can't tell why ..
Is this approach just not going to work?
//==========================================================================
// first find the cam filter
// this parts works
// I can use pSrc to look at the filter property pages using OleCreatePropertyFrame()
//==========================================================================
IBaseFilter *pSrc = NULL;
HRESULT hr = S_OK;
IMoniker* pMoniker =NULL;
ICreateDevEnum *pDevEnum =NULL;
IEnumMoniker *pClassEnum = NULL;
hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **) &pDevEnum);
my_assert(!FAILED(hr),"");
hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
my_assert(!FAILED(hr) && pClassEnum!=NULL,"");
hr = pClassEnum->Next (1, &pMoniker, NULL); // pick first device
my_assert(!FAILED(hr),"");
hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
my_assert(!FAILED(hr),"");
SAFE_RELEASE(pMoniker);
SAFE_RELEASE(pDevEnum);
SAFE_RELEASE(pClassEnum);
//=======================================================
// now find the interface on the capture pin
// no assertions trigger, I believe I find the capture pin correctly
// It seems like I find the capture pin property pages correctly as well
// However, it segfaults when I call OleCreatePropertyFrame()
//==================================================================
ISpecifyPropertyPages *pProp = NULL;
IUnknown *pFilterUnk =NULL;
IAMStreamConfig *pConfig = NULL;
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
hr = pSrc->EnumPins(&pEnum);
my_assert(!FAILED(hr),"");
while(pEnum->Next(1, &pPin, 0) == S_OK){
IKsPropertySet *pKs = NULL;
hr = pPin->QueryInterface(IID_PPV_ARGS(&pKs));
my_assert(!FAILED(hr),"");
DWORD cbReturned = 0;
GUID myPinCategory;
hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
&myPinCategory, sizeof(GUID), &cbReturned);
my_assert(!FAILED(hr),"");
SAFE_RELEASE(pKs);
if (myPinCategory!=PIN_CATEGORY_CAPTURE){
pPin->Release();
continue;
}
//IAMStreamConfig *pConfig = NULL;
hr = pPin->QueryInterface(IID_PPV_ARGS(&pConfig));
my_assert(!FAILED(hr),"could not find stream config interface");
hr = pConfig->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
my_assert(SUCCEEDED(hr),"");
pFilterUnk = (IUnknown *)pConfig;
pPin->Release();
break;
}
pEnum->Release();
if (pProp==NULL || pFilterUnk==NULL){
SAFE_RELEASE(pFilterUnk);
return("ERROR: can not find capture pin");
}
CAUUID caGUID;
hr = pProp->GetPages(&caGUID);
my_assert(SUCCEEDED(hr),"");
HWND ghApp = (HWND)pc->winId();
OleCreatePropertyFrame(
ghApp, // Parent window
0, 0, // location on the screen
filterName,
1, // Number of objects (just the filter)
&pFilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
If order to use OleCreatePropertyFrame on webcam capture pins, it seems like the webcam filter must be in graph. This ends up being pretty easy to do:
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER,IID_ICaptureGraphBuilder2, (void**)&pBuilder);
my_assert(pBuilder!=NULL && !FAILED(hr),"");
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&pFg);
my_assert(pFg!=NULL && !FAILED(hr),"");
hr = pBuilder->SetFiltergraph(pFg);
my_assert(!FAILED(hr),"");
hr = pFg->AddFilter(pSrc, L"my-cam");
my_assert(!FAILED(hr),"");
hr = pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pSrc,IID_IAMStreamConfig,
(void **)&pConfig);
my_assert(pConfig!=NULL && !FAILED(hr),"");

MFC: debug assertion failed?

When I run the program in debug mode, I receive this error.
Debug Assertion Failed!
Program: ...
File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\winhand.cpp
Line: 139
...
And it comes from the following code.
CObject* CHandleMap::FromHandle(HANDLE h)
{
ASSERT(m_pClass != NULL);
ASSERT(m_nHandles == 1 || m_nHandles == 2);
if (h == NULL)
return NULL;
CObject* pObject = LookupPermanent(h);
if (pObject != NULL)
return pObject; // return permanent one
else if ((pObject = LookupTemporary(h)) != NULL)
{
HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset);
ASSERT(ph[0] == h || ph[0] == NULL);
But I am not able to tell what error it is and how to fix.
I have the following call within "CMyDialog::OnInitDialog()" which causes the failure.
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
set_font_weight(IDC_STATIC1_LABEL, FW_BOLD | FW_BLACK);
SetDlgItemText(IDC_STATIC1, L"");
Is it a problem doing these within OnInitDialog? Most specifically, it is "set_font_weight" that causes problem (GetFont()).
void CMyDialog::set_font_weight(int nID, LONG weight)
{
CWnd *pwnd = GetDlgItem(nID);
CFont *pfont = pwnd->GetFont();
LOGFONT lf;
pfont->GetLogFont(&lf);
lf.lfWeight = weight;
pfont->CreateFontIndirect(&lf);
pwnd->SetFont(pfont);
}

OS X Application How to get allocation blocks(cluster size) of a volume

I want to get size (in bytes) of allocation blocks of a removable volume.
In my Macos application, I use FSGetVolumeInfo method to get FSVolumeInfo object.
In FSVolumeInfo object, attribute "blockSize" is the right one.
However, method FSGetVolumeInfo is deprecated after Macos10.8.
Is there any function to replace?
Below is sample code with FSVolumeInfo :
const char* path = "/Volumes/Untitled";
FSCatalogInfo volCatalogInfo;
FSVolumeRefNum realVolRefNum;
FSVolumeInfo myVolumeinfo;
if ('\0' != path[0]) {
CFStringRef pathStr = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
CFURLRef volumePath = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStr, kCFURLPOSIXPathStyle, false);
FSRef volumeRef;
if (CFURLGetFSRef(volumePath, &volumeRef)) {
OSStatus err = FSGetCatalogInfo(&volumeRef, kFSCatInfoVolume, &volCatalogInfo, NULL, NULL, NULL);
if (noErr == err) {
FSVolumeRefNum volRefNum = volCatalogInfo.volume;
err = FSGetVolumeInfo(volRefNum, 0, &realVolRefNum, kFSVolInfoGettableInfo, &myVolumeinfo, NULL, NULL);
if (noErr == err) {
printf("get volume info success!");
}
}
}
}
I would look into standard c function calls I think, statvfs() does what you want.

Assigning folder permissions to "ALL APPLICATION PACKAGES" group

It seems Win 8 has a new user group "ALL APPLICATION PACKAGES". This group seems to have Read permissions on all folders by default. However my requirement is to set some specific ACLs on a folder created by me. This group has no permissions on my folder currently and I wrote some code to add Read permissions for "ALL APPLICATION PACKAGES". I'm using VS 2010 and below is the trimmed down code snippet.
The SID for "ALL APPLICATION PACKAGES" as listed at http://msdn.microsoft.com/en-us/library/cc980032.aspx is ALL_APP_PACKAGES (S-1-15-2-1).
But no matter how or what value I pass as trustee Name the code below does not work. For example in the code below SetNamedSecurityInfo() fails with ERROR_INVALID_ACL. However if I use "Administrators" or "Everyone" account then it works.
Exact permission I need to assign are “Read & Execute”, “List Folder Contents”, and “Read”
#include "stdafx.h"
#include "windows.h"
#include "sddl.h"
#include "Aclapi.h"
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR pszObjName[MAX_PATH] = L"C:\\Program Files\\Common Files\\Test\\";
PACL pOldDACL = NULL, pNewDACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
// Get a pointer to the existing DACL (Conditionaly).
DWORD dwRes = GetNamedSecurityInfo(pszObjName, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD);
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = STANDARD_RIGHTS_READ;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
// ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
// Should I be using SID (S-1-15-2-1) (SetEntriesInAcl() fails) or "ALL_APP_PACKAGES" (SetEntriesInAcl() passes but SetNamedSecurityInfo() fails)
//If I use "Administrators" or "Everyone" as Trustee Name then it works fine but not with "ALL APPLICATION PACKAGES"
ea.Trustee.ptstrName = _T(" ALL_APP_PACKAGES");
// Create a new ACL that merges the new ACE into the existing DACL.
dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
if(ERROR_SUCCESS != dwRes)
goto Cleanup;
// Attach the new ACL as the object's DACL.
dwRes = SetNamedSecurityInfo(pszObjName, SE_FILE_OBJECT, si, NULL, NULL, pNewDACL, NULL);
if(ERROR_SUCCESS != dwRes)
goto Cleanup;
Cleanup:
if(pSD != NULL)
LocalFree((HLOCAL) pSD);
if(pNewDACL != NULL)
LocalFree((HLOCAL) pNewDACL);
return dwRes;
}
Try to set the Trustee structure this way. It works for me.
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = L"ALL APPLICATION PACKAGES";
Exact permission I need to assign are “Read & Execute”, “List Folder
Contents”, and “Read”
So you need
ea.grfAccessPermissions = GENERIC_READ | GENERIC_EXECUTE;
instead of
ea.grfAccessPermissions = STANDARD_RIGHTS_READ;
Also this is probably won't work if the group name is localized:
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = L"ALL APPLICATION PACKAGES";
This piece will:
// Allocate enough memory for the largest possible SID.
PSID TheSID = NULL;
DWORD SidSize = SECURITY_MAX_SID_SIZE;
if (!(TheSID = LocalAlloc(LMEM_FIXED, SidSize)))
goto Cleanup;
// Create a SID for the Everyone group on the local computer.
if (!CreateWellKnownSid(WinBuiltinAnyPackageSid, NULL, TheSID, &SidSize))
goto Cleanup;
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = GENERIC_READ | GENERIC_EXECUTE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = (LPWSTR)TheSID;

OSX: How to get a volume name (or bsd name) from a IOUSBDeviceInterface or location id

I'm trying to write an app that associates a particular USB string descriptor (of a USB mass storage device) with its volume or bsd name.
So the code goes through all the connected USB devices, gets the string descriptors and extracts information from one of them. I would like to get the volume name of those USB devices. I can't find the right API to do that.
I have tried to do that:
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk_ref = DADiskCreateFromIOMedia(kCFAllocatorDefault,
session,
usb_device_ref);
const char* name = DADiskGetBSDName(disk_ref);
But the DADiskCreateFromIOMedia function returned nil, I assume the usb_device_ref that I passed was not compatible with the io_service_t that the function is expecting.
So how can I get the volume name of a USB device?
Could I use the location id to do that?
Thanks for reading.
-L
FOO_Result result = FOO_SUCCESS;
mach_port_t master_port;
kern_return_t k_result;
io_iterator_t iterator = 0;
io_service_t usb_device_ref;
CFMutableDictionaryRef matching_dictionary = NULL;
// first create a master_port
if (FOO_FAILED(k_result = IOMasterPort(MACH_PORT_NULL, &master_port))) {
fprintf(stderr, "could not create master port, err = %d\n", k_result);
goto cleanup;
}
if ((matching_dictionary = IOServiceMatching(kIOUSBDeviceClassName)) == NULL)
{
fprintf(stderr, "could not create matching dictionary, err = %d\n", k_result);
goto cleanup;
}
if (FOO_FAILED(k_result = IOServiceGetMatchingServices(master_port, matching_dictionary, &iterator))) {
fprintf(stderr, "could not find any matching services, err = %d\n", k_result);
goto cleanup;
}
while (usb_device_ref = IOIteratorNext(iterator))
{
IOReturn err;
IOCFPlugInInterface **iodev; // requires <IOKit/IOCFPlugIn.h>
IOUSBDeviceInterface **dev;
SInt32 score;
err = IOCreatePlugInInterfaceForService(usb_device_ref, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score);
if (err || !iodev)
{
printf("dealWithDevice: unable to create plugin. ret = %08x, iodev = %p\n", err, iodev);
return;
}
err = (*iodev)->QueryInterface(iodev,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
(LPVOID*)&dev);
(*iodev)->Release(iodev); // done with this
FOO_String string_value;
UInt8 string_index = 0x1;
FOO_Result result = FOO_SUCCESS;
CFStringRef device_name_as_cf_string;
do {
if (FOO_SUCCEEDED(result = FOO_GetStringDescriptor(dev, string_index, 0, string_value))) {
printf("String at index %i is %s\n", string_index, string_value.GetChars());
// extract the command code if it is the FOO string
if (string_value.CompareN("FOO:", 4) == 0) {
FOO_Byte code = 0;
FOO_HexToByte(string_value.GetChars() + 4, code);
// Get other relevant information from the device
io_name_t device_name;
UInt32 location_id = 0;
// Get the USB device's name.
err = IORegistryEntryGetName(usb_device_ref, device_name);
device_name_as_cf_string = CFStringCreateWithCString(kCFAllocatorDefault, device_name,
kCFStringEncodingASCII);
err = (*dev)->GetLocationID(dev, &location_id);
// TODO: get volume or BSD name
// add the device to the list
break;
}
}
string_index++;
} while (FOO_SUCCEEDED(result));
err = (*dev)->USBDeviceClose(dev);
if (err)
{
printf("dealWithDevice: error closing device - %08x\n", err);
(*dev)->Release(dev);
return;
}
err = (*dev)->Release(dev);
if (err)
{
printf("dealWithDevice: error releasing device - %08x\n", err);
return;
}
IOObjectRelease(usb_device_ref); // no longer need this reference
}
Once you have the io_service_t, you can recurse through the IORegistry to find the BSD Name. You do not need to actually create an interface.
#import <IOKit/IOBSD.h>
CFStringRef bsdName = ( CFStringRef ) IORegistryEntrySearchCFProperty ( usbDevice,
kIOServicePlane,
CFSTR ( kIOBSDNameKey ),
kCFAllocatorDefault,
kIORegistryIterateRecursively );
See also:
usbdevs - list mounted USB devices & their volume paths on Mac OS X
https://gist.github.com/atr000/621561

Resources