Creating local group on MacOS Catalina using Core Services and Objective-C - objective-c

How do I create a local group using Core Services.? Documentation for Core Services says "The Core Services Identity Reference allows developers to support user and group creation.." but there are no examples on how to do it.
Update. This is the code I have so far but It doesn't work and ErrorCode return -2, error description is null. Really struggling to find any documentation that explains how to do it. 0 information on error codes as well.
CFStringRef realName = CFStringCreateWithCString(NULL, "newGroupTest",
kCFStringEncodingMacRoman);
CFStringRef posixName = CFStringCreateWithCString(NULL, "newgrptst1",
kCFStringEncodingMacRoman);
AuthorizationRef auth;
OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&auth);
CSIdentityAuthorityRef authority = CSGetDefaultIdentityAuthority();
CSIdentityRef identity = CSIdentityCreate(NULL, kCSIdentityClassGroup, realName,
posixName, kCSIdentityFlagNone, authority);
CFErrorRef error;
BOOL success = CSIdentityCommit(Identity, auth, &error);
if(!success)
{
CFIndex index = CFErrorGetCode(error);
CFStringRef desc = CFErrorCopyDescription(error);
const char* cDesc = CFStringGetCStringPtr(desc, CFStringGetSystemEncoding());
}

Found what was the problem. I wasn't using correct identity authority. To create a local group you need to use CSGetLocaldentityAuthority() that get a local identity authority that stores the identities local to the system, instead of
CSGetDefaultIdentityAuthority() that represents the network-bound authorities.

Related

Send certificate in http request header - c++

I have a certificate that I need to send in the header of an http request. This is how I acquired the cert:
PCCERT_CONTEXT cert = nullptr;
wstring store = // store name
wstring subjectName = // subject name
HCERTSTORE hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
store.c_str());
cert = CertFindCertificateInStore(
hStoreHandle,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
subjectName.c_str(),
NULL);
I need to send it as a custom header, as the load balancer that sits in front of my service strips off the certificate header ["X-ARR-CLIENTCERT"] before forwarding the request. I believe I need to send the cert->pbCertEncoded, but on the server, I can't decode it and convert it back to an X509Certificate2.
This is what I tried on the client:
request.headers().add("client-cert", cert->pbCertEncoded);
On the server:
var headerCert = Request.Headers["client-cert"];
byte[] certdata = Convert.FromBase64String(headerCert);
X509Certificate2 cert = new X509Certificate2(certdata);
The request header on the server is non-null. But it cannot parse it back to an X509Certificate2.
I tried another thing on the client. After getting the cert, I converted it to a string
DWORD size = 0;
CryptBinaryToString(cert->pbCertEncoded, cert->cbCertEncoded, CRYPT_STRING_BASE64, NULL, &size);
LPWSTR outstring = new TCHAR[size];
CryptBinaryToString(cert->pbCertEncoded, cert->cbCertEncoded, CRYPT_STRING_BASE64, outstring, &size);
If I try to send outstring in the header, it complains:
WinHttpAddRequestHeaders: 87: The parameter is incorrect.
But when I take the contents of outstring and try to parse it on the server, it decodes back to the right certificate. This tells me that I'm not doing something right when passing cert->pbCertEncoded in the header. Maybe I need to re-encode it or transform it somehow so the server can correctly parse it? I'd appreciate any help. Thanks!
My client is in c++ and server in .NET. I'm using cpprestsdk to send the certificate in the http request.
The pbCertEncoded is the ASN.1 encoded representation of the certificate. Look for instance here.
So you must encode the bytes to base64 for instance like this:
#include <Wincrypt.h>
#pragma comment (lib, "Crypt32.lib")
int ToBase64Crypto(const BYTE* pSrc, int nLenSrc, char* pDst, int nLenDst )
{
DWORD nLenOut = nLenDst;
BOOL fRet = CryptBinaryToString(
(const BYTE*)pSrc,
nLenSrc,
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
pDst, &nLenOut
);
if (!fRet) {
nLenOut=0; // failed
}
return (nLenOut);
}

Objective C : How can we retrieve information stored in Local Items in key chain?

I have saved the username and password for a website in safari, Safari saved this information in Local Items keychain, how can I retrieve stored information using objective C ?
I am trying to retrieve website password stored in Local Items Keychain in OS X version 10.11.4 by safari.
if I access username and password stored in login keychain. then username and password can be retrieved by below code.
OSStatus status;
NSString *account = #"Safari";
const char *cService_name = "PersonalFormsAutoFillDatabase";
UInt32 service_length = strlen(cService_name);
const char *cAccount_name = [account cStringUsingEncoding:NSUTF8StringEncoding];
UInt32 account_length = strlen(cAccount_name);
void *passwordData = nil;
SecKeychainItemRef itemRef = nil;
UInt32 passwordLength = 0;
status = SecKeychainFindGenericPassword(NULL, service_length, cService_name, account_length, cAccount_name, &passwordLength, &passwordData, NULL);
NSString *pw = [[NSString alloc]initWithBytes:passwordData length:passwordLength encoding:NSUTF8StringEncoding];
When i run above code system prompt a popup and ask for permission to allow retrieve the password . if I want to change the default Login Keychain to another keychain then user need to create the reference for new keychain like below code and need to pass reference of new keychain in SecKeychainFindGenericPassword method.
SecKeychainRef keychain ;
OSStatus status1 = SecKeychainOpen("/Users/xxxx/Library/Keychains/mykeychain.keychain", &keychain);
if(status1 != errSecSuccess) {
NSLog(#"Failed to open System keychain %#", SecCopyErrorMessageString(status1, NULL));
}
status1 = SecKeychainUnlock(keychain, 0, NULL, FALSE);
My First question is what will be path for Local Items keychain like “/Users/xxxx/Library/Keychains/mykeychain.keychain” ?
As I don’t have the path then i created a new keychain From File->Add KeyChain and give the name testing.keychain. After that I copied one keychain item form Local Items keychain and Pasted into testing.keychain. and used the above code and changed the path as below.
SecKeychainRef keychain ;
OSStatus status1 = SecKeychainOpen("/Users/xxxx/Library/Keychains/testing.keychain", &keychain);
if(status1 != errSecSuccess) {
NSLog(#"Failed to open System keychain %#", SecCopyErrorMessageString(status1, NULL));
}
status1 = SecKeychainUnlock(keychain, 0, NULL, FALSE);
and passed the reference in find generic password method and also change the service name and account name to "a#gmail.com" and service name "https://accounts.google.com"
status = SecKeychainFindGenericPassword(keychain, service_length, cService_name, account_length, cAccount_name, &passwordLength, &passwordData, NULL);
this return the password data but as i think it is in encrypted mode then it return NULL. How can I decrypt this stored password.
Anyone who can help so i can retrieve the password stored in Local Items keychain.

Get the CERT_RDN information from the certificate object

I'm opening the certificate store using the "CertOpenStore" API and get the certificates using the "CertEnumCertificatesInStore" API.
The CERT_CONTEXT data returned by the API gives the issuer name in CERT_NAME_BLOB type.
How to get the CERT_RDN or CERT_NAME_INFO from the certificate.?
My requirement is to get the issuer name attributes (O, OU, etc.). I do not want to parse the string returned by the CertNameToStr API.
The above comment is correct, you do need to decode the ASN.1 encoded data in the CERT_NAME_BLOB. However, the CryptoAPI has a function to do this for you - CryptDecodeObject.
If you have a PCCERT_CONTEXT handle pCertContext, you can decode it to a CERT_NAME_INFO structure as follows:
BOOL success = CryptDecodeObject(
X509_ASN_ENCODING,
X509_NAME,
pCertContext->pCertInfo->Issuer.pbData,
pCertContext->pCertInfo->Issuer.cbData,
0,
NULL,
&dwNameInfoSize);
// (check that CryptDecodeObject succeeded)
PCERT_NAME_INFO pCertNameInfo = (PCERT_NAME_INFO) malloc(dwNameInfoSize);
// (check that malloc succeeded)
CryptDecodeObject(
X509_ASN_ENCODING,
X509_NAME,
pCertContext->pCertInfo->Issuer.pbData,
pCertContext->pCertInfo->Issuer.cbData,
0,
pCertNameInfo,
&dwNameInfoSize);
Now you can loop through the different components of the RDN like this:
for (DWORD i = 0; i < pCertNameInfo->cRDN; i++)
{
for (DWORD j = 0; j < pCertNameInfo->rgRDN[i].cRDNAttr; j++)
{
CERT_RDN_ATTR &rdnAttribute = pCertNameInfo->rgRDN[i].rgRDNAttr[j];
//
// Do stuff with the RDN attribute
//
}
}
With each iteration, rdnAttribute will be set to a different component of the issuer name like you want.
Finally, free the memory when you're done:
free(pCertNameInfo);

Sharepoint 2010 Web Services: Authentication using WCF failing

I am creating an application to list all sub sites, attributes and to upload documents. I am trying to use WCF to use sharepoint web services.
TO authenticate i have written the below mentioned code:
HRESULT hr;
ISAXXMLReader* pRdr = NULL;
hr = CoInitialize(NULL);
hr = CoCreateInstance(
__uuidof(SAXXMLReader),
NULL,
CLSCTX_ALL,
__uuidof(ISAXXMLReader),
(void **)&pRdr);
if ( SUCCEEDED(hr) )
{
pRdr->putBaseURL(L"http://bascansp01");
Authentication::CAuthentication* auth = new Authentication::CAuthentication(pRdr);
Authentication::LoginResult* res = new Authentication::LoginResult();
BSTR sUsername = L"aakanksh#abc";
BSTR sPasswd = L"abcd";
hr = auth->Login(sUsername, sPasswd, res);
but my login is failing. While debugging i found out that it failes at the line:
__atlsoap_hr = SendRequest(_T("SOAPAction: \"http://schemas.microsoft.com/sharepoint/soap/Login\"\r\n"));
any clue why it is failing.
Thanks and Regards,
Aakanksha

Implementing mutual authentication with LDAP API and SSPI

I would like to ask you a question about implementing mutual authentication with Kerberos, using SSPI and LDAP API.
I am using the guidelines described in: ldap_sasl_bind_s(GSSAPI) - What should be provided in the credentials BERVAL structure.
Here is the algorithm I am using:
//--------------------------------------------------------------------------------------------
// client side
AcquireCredentialsHandle(NULL, "Kerberos", SECPKG_CRED_BOTH, NULL, &secIdent, NULL, NULL, &kClientCredential, &kClientTimeOut);
// AcquireCredentialsHandle returns SEC_E_OK
// begin validation
unsigned long ulClientFlags = ISC_REQ_CONNECTION | ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
int iCliStatus = InitializeSecurityContext(&kClientCredential, isContextNull(kClientContext) ? NULL : &kClientContext,
pacTargetName, ulClientFlags, 0, SECURITY_NATIVE_DREP, pkServerToken,
0, &kClientContext, &kClientToken, &ulContextAttr, NULL);
// InitializeSecurityContext returns SEC_I_CONTINUE_NEEDED
//--------------------------------------------------------------------------------------------
// server side
// ldap_init returns ok
ldap_set_option(ld, LDAP_OPT_SIGN, LDAP_OPT_OFF);
ldap_set_option(ld, LDAP_OPT_ENCRYPT, LDAP_OPT_OFF);
unsigned long ulVersion = LDAP_VERSION3;
ldap_set_option(ld, LDAP_OPT_VERSION, &ulVersion);
// ldap_connect returns LDAP_SUCCESS
// build the credentials based on what InitializeSecurityContext returned
BERVAL creds;
creds.bv_len = kClientToken.pBuffers[0].cbBuffer;
creds.bv_val = reinterpret_cast(kClientToken.pBuffers[0].pvBuffer);
BERVAL* pServerCreds = NULL;
int iError = ldap_sasl_bind_s(ld, "", "GSSAPI", &creds, NULL, NULL, &pServerCreds);
// ldap_sasl_bind_s returns LDAP_SUCCESS
unsigned long ulError = 0;
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ulError);
// ulError is equal to LDAP_SASL_BIND_IN_PROGRESS
And here is the problem: both LDAP error codes are ok, but pServerCreds points to an empty BERVAL structure (not NULL, but bv_len equals to 0), and it should contain the server credential I have to pass to the next InitializeSecurityContext call. If I use that data to build the SecBufferDesc structure for the following call, it returns SEC_E_INVALID_TOKEN.
Is ldap_sasl_bind_s supposed to return an empty BERVAL or am I doing something wrong?
I have tested the authentication using full SSPI calls (AcceptSecurityContext for the server) and it works just as expected. The problem is that I need the server to be cross-platform, so I cannot use SSPI.
Thanks for taking the time to answer!
Juan
I found the problem.
According to this thread there is a bug with ldap_sasl_bind_s returning empty server credentials in Windows XP. I have tested my application under Windows 2008 Server and the credentials are properly returned.