Unable to call SecItemAdd Successfully - c++

I'm trying to add a simple string secret to they keychain in macOS, via the C++ APIs. Unfortunately, I can't get my call to SecItemAdd to work. I know it is because my value for the kSecValueRef key is the wrong type, but so far Google/Apple docs/existing StackOverflow questions have yet to reveal to me what type I should be using, and how to create it. Here's what I have so far:
CFStringRef keys[4];
keys[0] = kSecClass;
keys[1] = kSecValueRef;
keys[2] = kSecAttrAccount;
keys[3] = kSecAttrService;
CFTypeRef values[4];
values[0] = kSecClassGenericPassword;
values[1] = CFSTR("password");
values[2] = CFSTR( "account-1" );
values[3] = CFSTR( "service-1" );
CFDictionaryRef attributes = CFDictionaryCreate
(
( CFAllocatorRef )NULL,
( const void ** )keys,
( const void ** )values,
4,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks
);
CFShow(attributes);
OSStatus status = SecItemAdd(attributes, NULL);
So what should I be putting for my kSecValueRef? I've tried making a reference to a CFStringRef, but that didn't work. I also see that in the Apple docs it says:
The corresponding value, depending on the item class requested, is of type SecKeychainItem, SecKey, SecCertificate, or SecIdentity.
But I don't have a SecKeychainItem because I haven't made added the item yet, and the other types don't seem right for just a normal string.
Thoughts?

Figured it out! For simple data, such as a string, you should use the kSecValueData key. That will let you just pass in a CFStringRef.
Example:
CFStringRef keys[4];
keys[0] = kSecClass;
keys[1] = kSecAttrAccount;
keys[2] = kSecAttrService;
keys[3] = kSecValueData;
CFTypeRef values[4];
values[0] = kSecClassGenericPassword;
values[1] = CFSTR( "account-15" );
values[2] = CFSTR( "service-126" );
values[3] = CFSTR( "password" );

Related

GSSAPI: Error 0x80090311 returned by InitializeSecurityContext

I need to set up an active directory authentication system using Kerberos. My AcquireCredentialsHandleA class looks as follows. https://learn.microsoft.com/en-us/windows/win32/secauthn/acquirecredentialshandle--kerberos
SEC_WINNT_AUTH_IDENTITY AuthData, *pAuthData = NULL;
#ifdef UNICODE
AuthData.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
AuthData.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif
unsigned char username[200] = "user";
unsigned char domain[200] = "domain.com";
unsigned char password[100] = "secret";
AuthData.User = &username[0]; //username
AuthData.Domain = &domain[0]; //domain
AuthData.Password = &password[0]; //password
AuthData.UserLength = AuthData.User ? sizeof(AuthData.User) : 0;
AuthData.DomainLength = AuthData.Domain ? sizeof(AuthData.Domain) : 0;
AuthData.PasswordLength = AuthData.Password ? sizeof(AuthData.Password) : 0;
Status = g_pSSPI->AcquireCredentialsHandleA(
NULL, // Name of principal //pN
ppPackageInfo[2].Name,//"kerberos" Name of package
SECPKG_CRED_OUTBOUND, // Flags indicating use
NULL, // Pointer to logon ID
pAuthData, //NULL, // Package specific data
NULL, // Pointer to GetKey() func
NULL, // Value to pass to GetKey()
phCreds, // (out) Cred Handle
&tsExpiry
);
This returns Success. However, when I call my InitializeSecurityContextAfunction it gives me 0x80090311 error which means SEC_E_NO_AUTHENTICATING_AUTHORITY. I have tried all sorts of possible domain name etc. When I do ksetup in the powershell it can generate ticket with same credentials. But the code always fails. Can anyone spot any problem here?
dwSSPIFlags = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_CONNECTION; // Not sure at all about them flags
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType = SECBUFFER_TOKEN; //2
//OutBuffers[0].cbBuffer = 0;
OutBuffers[0].cbBuffer = 7084;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION; //0
Status = g_pSSPI->InitializeSecurityContextA
(
phCreds,
fHaveCtxtHandle ? phContext : NULL,//phContext, can be NULL for the first call
server,
dwSSPIFlags,
0,
SECURITY_NETWORK_DREP,//SECURITY_NATIVE_DREP,
fHaveCtxtHandle ? &InBuffer : NULL,
0,
fHaveCtxtHandle ? NULL : phContext ,
&OutBuffer,
&dwSSPIOutFlags,
&tsExpiry
);
Can anyone help me with this? Thanks a lot. :)
--------------------------------------------------------------- edit ---------------------------------------------------------------
std::string fqdn = "HTTP/staging.company.com";
char * server = new char[fqdn.size() + 1];
std::copy(fqdn.begin(), fqdn.end(), server);
server[fqdn.size()] = '\0';
So this is how I set up the Service name. I have this service name registered in my active directory as well. Though the address does not offer any particular service yet. Do you think that could be the problem?
Another details: The Active directory is not in the same office, we tunnel to it via router.

What wrong I have done? The function of GetDiskFreeSpaceExA didn't work at all

I tried to use GetDiskFreeSpaceExA function, but it doesn't work:
int drvNbr = PathGetDriveNumber(db7zfolderw);
if (drvNbr == -1) // fn returns -1 on error
{
const char * errmsg = "error occured during get drive number";
strcpy_s(retmsg, strlen(errmsg) + 1, errmsg);
return -3;
}
char driverletter = (char)(65 + drvNbr);
string driverstr(1, driverletter);
driverstr = driverstr + ":";
PULARGE_INTEGER freespace = 0;
PULARGE_INTEGER totalnumbtype = 0;
PULARGE_INTEGER totalnumberfreebyte = 0;
fileSize = SzArEx_GetFileSize(&db, i);
BOOL myresult=GetDiskFreeSpaceExA(
driverstr.c_str(),
freespace,
totalnumbtype,
totalnumberfreebyte
);
The value of variable freespace is 0. I have no idea why it didn't work if the value of variable which is driverstr.c_str() was D:?
Thanks for your help.
You need to supply pointers to variables that will hold the value returned. Right now you a re supplying null pointers so nothing is retured:
::ULARGE_INTEGER freespace{};
::ULARGE_INTEGER totalnumbtype{};
::ULARGE_INTEGER totalnumberfreebyte{};
::BOOL myresult
{
::GetDiskFreeSpaceExA
(
driverstr.c_str()
, &freespace
, &totalnumbtype
, &totalnumberfreebyte
)
};
It would also be a good idea to use wide char versions of these functions.

Weird error on mysql_stmt_execute

I have a weird error when trying to execute mysql_stmt_execute.
The flow goes:
I get the list of the tables in my database I am connecting. (catalog, schema and name)
For every table I'm getting the list of foreign keys, fields and indexes.
Everything goes good until I hit the table named performance_schema.events_stages_summary_by_account_by_event_name.
I get the error: Identifier name "events_stages_summary_by_account_by_event_name" is too long. The weird thing is that the name is not an identifier - it is a parameter to the query and it is less than 64 characters which is the identifier limit.
Below is the relevant code:
std::wstring query3 = L"SELECT kcu.column_name, kcu.ordinal_position, kcu.referenced_table_schema, kcu.referenced_table_name, kcu.referenced_column_name, rc.update_rule, rc.delete_rule FROM information_schema.key_column_usage kcu, information_schema.referential_constraints rc WHERE kcu.constraint_name = rc.constraint_name AND kcu.table_catalog = ? AND kcu.table_schema = ? AND kcu.table_name = ?;";
char *catalog_name = row[0] ? row[0] : NULL;
char *schema_name = row[1] ? row[1] : NULL;
char *table_name = row[2] ? row[2] : NULL;
MYSQL_BIND params[3];
unsigned long str_length1, str_length2, str_length3;
str_length1 = strlen( catalog_name ) * 2;
str_length2 = strlen( schema_name ) * 2;
str_length3 = strlen( table_name ) * 2;
str_data1 = new char[str_length1], str_data2 = new char[str_length2], str_data3 = new char[str_length3];
memset( str_data1, '\0', str_length1 );
memset( str_data2, '\0', str_length2 );
memset( str_data3, '\0', str_length3 );
memset( params, 0, sizeof( params ) );
strncpy( str_data1, catalog_name, str_length1 );
strncpy( str_data2, schema_name, str_length2 );
strncpy( str_data3, table_name, str_length3 );
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char *) str_data1;
params[0].buffer_length = strlen( str_data1 );
params[0].is_null = 0;
params[0].length = &str_length1;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char *) str_data2;
params[1].buffer_length = strlen( str_data2 );
params[1].is_null = 0;
params[1].length = &str_length2;
params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = (char *) str_data3;
params[2].buffer_length = strlen( str_data3 );
params[2].is_null = 0;
params[2].length = &str_length3;
if( mysql_stmt_bind_param( res1, params ) )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
else
{
prepare_meta_result = mysql_stmt_result_metadata( res1 );
if( !prepare_meta_result )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
else
{
if( mysql_stmt_execute( res1 ) )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
Could someone please shed some light on the error? I can probably try to skip this table but I'd prefer not to.
[EDIT]
mysql --version
mysql ver 14.14 Distrib 5.6.35, for Linux (x86+64) using Editine wrapper
[/EDIT]
Edit:
Seems that the code is indeed OK and the strncpy is OK. I mistakenly read that the allocation was twice the length of the string but the length was still only one length of the string.
The reason why you see that error is because you are using a string which is not null terminated. This is caused by the fact that strncpy does not null-terminate the string if it exceeds the given limit and the limit you use is the actual length of the string:
memset( str_data1, '\0', str_length1 );
strncpy( str_data1, catalog_name, str_length1 );
params[0].buffer_length = strlen( str_data1 );
A better way to do this would be to use either snprintf(3) that does null terminate the string or by using the std::string constructor that takes a const char* and a length as parameters.

Setting media type ignored on output pin

I'm building a DirectShow graph.
I have video capture filter that connects its output pin to the input pin of SampleGrabber.
Before I connect two pins, I configure output pin like this:
HRESULT GraphBuilder::applyVideoFormat()
{
if( !pVideoCaptureFilter_ )
return E_FAIL;
CComPtr<IPin> pPin;
pPin.Attach( findCategoryPin( pVideoCaptureFilter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE ) );
if( !pPin )
return E_FAIL;
CComQIPtr<IAMStreamConfig> pConfig( pPin );
if( !pConfig )
return E_FAIL;
AM_MEDIA_TYPE mt = { 0 };
VIDEOINFOHEADER vih = { 0 };
if( videoStandard_ == AnalogVideo_NTSC_M )
vih.AvgTimePerFrame = 333667;
else
vih.AvgTimePerFrame = 400000;
vih.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
vih.bmiHeader.biWidth = captureResolution_.cx;
vih.bmiHeader.biHeight = captureResolution_.cy;
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biBitCount = 16;
vih.bmiHeader.biCompression = mmioFOURCC('Y','U','Y','2');
vih.bmiHeader.biSizeImage = vih.bmiHeader.biWidth * vih.bmiHeader.biHeight * 2;
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_YUY2;
mt.bFixedSizeSamples = TRUE;
mt.bTemporalCompression = FALSE;
mt.lSampleSize = vih.bmiHeader.biSizeImage;
mt.formattype = FORMAT_VideoInfo;
mt.cbFormat = sizeof( VIDEOINFOHEADER );
mt.pbFormat = (BYTE*)&vih;
mt.pUnk = NULL;
return pConfig->SetFormat( &mt ); // SUCCESS - always
}
I also configure the sample grabber, although I know it will consider only the major type and subtype. It doesn't care about the rest.
HRESULT GraphBuilder::configureVideoSampleGrabber( ISampleGrabber * const pSampleGrabber )
{
AM_MEDIA_TYPE mt = { 0 };
VIDEOINFOHEADER vih = { 0 };
if( videoStandard_ == AnalogVideo_NTSC_M )
vih.AvgTimePerFrame = 333667;
else
vih.AvgTimePerFrame = 400000;
vih.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
vih.bmiHeader.biWidth = captureResolution_.cx;
vih.bmiHeader.biHeight = captureResolution_.cy;
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biBitCount = 16;
vih.bmiHeader.biCompression = mmioFOURCC('Y','U','Y','2');
vih.bmiHeader.biSizeImage = vih.bmiHeader.biWidth * vih.bmiHeader.biHeight * 2;
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_YUY2;
mt.bFixedSizeSamples = TRUE;
mt.bTemporalCompression = FALSE;
mt.lSampleSize = vih.bmiHeader.biSizeImage;
mt.formattype = FORMAT_VideoInfo;
mt.cbFormat = sizeof( VIDEOINFOHEADER );
mt.pbFormat = (BYTE*)&vih;
mt.pUnk = NULL;
return pSampleGrabber->SetMediaType( &mt ); // SUCCESS - always
}
This code is called once the filters are in the graph, but BEFORE they are connected. All return values are 0.
In this example, the captureResolution_.cx = 352 and captureResolution_.cy = 240.
Now, the question is: WHY do I get the default 720x480 always through the SampleGrabber instead of 352x240?? I configured the capture pin to deliver 352x240.
What you are doing is about right, there are however a few things you want to change.
You definitely want to review your Sample Grabber initialization. You don't need a fully specified media type set on it. Instead you want a partial media type with only major type an subtype initialized (and the rest is NULL'ed). The rationale is the following.
Sample Grabber is just an inset which you configure to insist on specific media type. In particular, it is unable to work out a connection type on the upstream connection in any other way than straightforwardly compare attempts to its internal reference type and accept or reject depending on result of this comparison. Having said this, your Sample Grabber cannot help setting the resolution, but it can reject the connection if media type is different in some unimportant field. It is sufficient to require video, YUY2 on Sample Grabber, and the rest of the format is the responsibility of video source.
To make sure this media type is okay for the video source you can always connect it interactively without Sample Grabber and review all fields of effective connection media type.

Can't run execv

I've been trying to run command using exevp as follows:
char *args[11];
args[0] = (char*)lgulppath.c_str();
args[1] = (char*)"-i";
args[2] = (char*)sniffer_interface.c_str();
args[3] = (char*)"-r";
args[4] = (char*)pcapfileLimit.c_str();
args[5] = (char*)"-C";
args[6] = (char*)"1";
args[7] = (char*)"-f";
args[8] = (char*)serverip_filter.c_str();
args[9] = (char*)"-o";
args[10] = (char*)lpipepath.c_str();
execv("/usr/sbin/program",args);
this works. HOWEVER, when I want to have the first parameter "/usr/sbin/program" as a parameter say:
string str = "/usr/sbin/program";
//char* args is assigned as above
execv(str.c_str(),args);
this fails and returns -1. I CAN'T GET WHY THOUGH.
Thanks everybody
Null terminate the arguments you pass to execv. Something like
char *args[12];
// other args..
args[11] = (char*) 0;