#include <stdio.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <DirectoryService/DirServices.h>
#include <DirectoryService/DirServicesUtils.h>
#include <DirectoryService/DirServicesConst.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <Security/Security.h>
#include "../../Helpers/vpnd/RASSchemaDefinitions.h"
#include "../../Helpers/pppd/pppd.h"
#include "../../Helpers/pppd/chap-new.h"
#include "../../Helpers/pppd/chap_ms.h"
#include "../../Family/ppp_comp.h"
#include "../../Helpers/pppd/ccp.h"
#include "DSUser.h"
#define BUF_LEN 1024
char serviceName[] = "com.apple.ras";
static CFBundleRef bundle = 0;
extern u_char mppe_send_key[MPPE_MAX_KEY_LEN];
extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
extern int mppe_keys_set;
extern CFPropertyListRef systemOptions;
extern ccp_options ccp_wantoptions[];
static int dsauth_check(void);
static int dsauth_ip_allowed_address(u_int32_t addr);
static int dsauth_pap(char *user, char *passwd, char **msgp, struct wordlist **paddrs, struct wordlist **popts);
static int dsauth_chap(u_char *name, u_char *ourname, int id,
struct chap_digest_type *digest,
unsigned char *challenge, unsigned char *response,
unsigned char *message, int message_space);
static int dsauth_set_mppe_keys(tDirReference dirRef, tDirNodeReference userNode, u_char *remmd,
tAttributeValueEntryPtr authAuthorityAttr,
const unsigned char *challenge);
static void dsauth_get_admin_acct(u_int32_t *acctNameSize, char** acctName, u_int32_t *passwordSize, char **password);
static int dsauth_get_admin_password(u_int32_t acctlen, char* acctname, u_int32_t *password_len, char **password);
static int dsauth_find_user_node(tDirReference dirRef, char *user_name, tDirNodeReference *user_node,
tAttributeValueEntryPtr *recordNameAttr, tAttributeValueEntryPtr *authAuthorityAttr);
#define DSAuth_hex_print(name, str, len) \
{ int i; error("DSAuth: Chap %s", name); \
for (i=0; i<len; i++) { error(" - %c %2x", str[i], str[i]); } \
}
int start(CFBundleRef ref)
{
bundle = ref;
CFRetain(bundle);
pap_check_hook = dsauth_check;
pap_auth_hook = dsauth_pap;
chap_check_hook = dsauth_check;
chap_verify_hook = dsauth_chap;
allowed_address_hook = dsauth_ip_allowed_address;
info("Directory Services Authentication plugin initialized");
return 0;
}
static int dsauth_check(void)
{
return 1;
}
static int dsauth_ip_allowed_address(u_int32_t addr)
{
return 1;
}
static int dsauth_pap(char *user, char *passwd, char **msgp, struct wordlist **paddrs, struct wordlist **popts)
{
tDirReference dirRef;
tDirNodeReference userNode = 0;
tDataNodePtr authTypeDataNodePtr = 0;
tDataBufferPtr authDataBufPtr = 0;
tDataBufferPtr responseDataBufPtr = 0;
tAttributeValueEntryPtr recordNameAttr = 0;
tAttributeValueEntryPtr authAuthorityAttr = 0;
tDirStatus dsResult = eDSNoErr;
char *ptr;
int authResult = 0;
u_int32_t userShortNameSize;
u_int32_t passwordSize = strlen(passwd);
u_int32_t authDataSize;
if ((dsResult = dsOpenDirService(&dirRef)) == eDSNoErr) {
if ((responseDataBufPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) {
error("DSAuth plugin: Could not allocate data buffer\n");
goto cleanup;
}
if ((authTypeDataNodePtr = dsDataNodeAllocateString(dirRef, kDSStdAuthNodeNativeNoClearText)) == 0) {
error("DSAuth plugin: Could not allocate data buffer\n");
goto cleanup;
}
if (dsauth_find_user_node(dirRef, user, &userNode, &recordNameAttr, &authAuthorityAttr) == 0) {
userShortNameSize = recordNameAttr->fAttributeValueData.fBufferLength;
authDataSize = userShortNameSize + passwordSize + (2 * sizeof(u_int32_t));
if ((authDataBufPtr = dsDataBufferAllocate(dirRef, authDataSize)) != 0) {
authDataBufPtr->fBufferLength = authDataSize;
ptr = (char*)(authDataBufPtr->fBufferData);
*((u_int32_t*)ptr) = userShortNameSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, recordNameAttr->fAttributeValueData.fBufferData, userShortNameSize);
ptr += userShortNameSize;
*((u_int32_t*)ptr) = passwordSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, passwd, passwordSize);
if ((dsResult = dsDoDirNodeAuth(userNode, authTypeDataNodePtr, TRUE, authDataBufPtr,
responseDataBufPtr, 0)) == eDSNoErr) {
authResult = 1;
info("DSAuth plugin: user authentication successful\n");
}
bzero(authDataBufPtr->fBufferData, authDataSize); }
dsCloseDirNode(userNode); dsDeallocAttributeValueEntry(dirRef, recordNameAttr);
dsDeallocAttributeValueEntry(dirRef, authAuthorityAttr);
}
cleanup:
if (responseDataBufPtr)
dsDataBufferDeAllocate(dirRef, responseDataBufPtr);
if (authTypeDataNodePtr)
dsDataNodeDeAllocate(dirRef, authTypeDataNodePtr);
if (authDataBufPtr)
dsDataBufferDeAllocate(dirRef, authDataBufPtr);
dsCloseDirService(dirRef);
}
return authResult;
}
#define CHALLENGE_SIZE 16
#define NT_RESPONSE_SIZE 24
static int dsauth_chap(u_char *name, u_char *ourname, int id,
struct chap_digest_type *digest,
unsigned char *challenge, unsigned char *response,
unsigned char *message, int message_space)
{
tDirReference dirRef;
tDirNodeReference userNode = 0;
tDataNodePtr authTypeDataNodePtr = 0;
tDataBufferPtr authDataBufPtr = 0;
tDataBufferPtr responseDataBufPtr = 0;
tAttributeValueEntryPtr recordNameAttr = 0;
tAttributeValueEntryPtr authAuthorityAttr = 0;
tDirStatus dsResult = eDSNoErr;
int authResult = 0;
char *ptr;
MS_Chap2Response *resp;
u_int32_t userShortNameSize;
u_int32_t userNameSize = strlen((char*)name);
u_int32_t authDataSize;
int challenge_len, response_len;
CFMutableDictionaryRef serviceInfo = 0;
CFMutableDictionaryRef eventDetail;
CFDictionaryRef interface;
CFStringRef subtypeRef;
CFStringRef addrRef;
challenge_len = *challenge++;
response_len = *response++;
if (digest->code != CHAP_MICROSOFT_V2
|| response_len != MS_CHAP2_RESPONSE_LEN
|| challenge_len != CHALLENGE_SIZE)
return 0;
resp = (MS_Chap2Response*)response;
if ((dsResult = dsOpenDirService(&dirRef)) == eDSNoErr) {
if ((authTypeDataNodePtr = dsDataNodeAllocateString(dirRef, kDSStdAuthMSCHAP2)) == 0) {
error("DSAuth plugin: Could not allocate data buffer\n");
goto cleanup;
}
interface = CFDictionaryGetValue(systemOptions, kRASEntInterface);
if (interface && CFGetTypeID(interface) == CFDictionaryGetTypeID()) {
subtypeRef = CFDictionaryGetValue(interface, kRASPropInterfaceSubType);
if (subtypeRef && CFGetTypeID(subtypeRef) == CFStringGetTypeID()) {
serviceInfo = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (serviceInfo) {
eventDetail = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (eventDetail) {
addrRef = CFStringCreateWithCString(0, remoteaddress, kCFStringEncodingUTF8);
if (addrRef) {
CFDictionaryAddValue(eventDetail, CFSTR("ClientIP"), addrRef);
CFRelease(addrRef);
}
if (CFStringCompare(subtypeRef, kRASValInterfaceSubTypeL2TP, 0) == kCFCompareEqualTo) {
CFDictionaryAddValue(eventDetail, CFSTR("HostPort"), CFSTR("1701"));
CFDictionaryAddValue(eventDetail, CFSTR("ProtocolName"), CFSTR("L2TP"));
CFDictionaryAddValue(eventDetail, CFSTR("ProtocolVersion"), CFSTR("2"));
} else if (CFStringCompare(subtypeRef, kRASValInterfaceSubTypePPTP, 0) == kCFCompareEqualTo) {
CFDictionaryAddValue(eventDetail, CFSTR("HostPort"), CFSTR("1723"));
CFDictionaryAddValue(eventDetail, CFSTR("ProtocolName"), CFSTR("PPTP"));
CFDictionaryAddValue(eventDetail, CFSTR("ProtocolVersion"), CFSTR("1"));
} else
CFDictionaryAddValue(eventDetail, CFSTR("ProtocolName"), subtypeRef);
CFDictionaryAddValue(eventDetail, CFSTR("ServiceName"), CFSTR("VPN"));
CFDictionaryAddValue(serviceInfo, CFSTR("ServiceInformation"), eventDetail);
CFRelease(eventDetail);
if (dsServiceInformationAllocate(serviceInfo, BUF_LEN, &responseDataBufPtr) != eDSNoErr) {
error("DSAuth plugin: Unable to allocate service info buffer\n");
goto cleanup;
}
} else {
error("DSAuth plugin: Unable to allocate eventDetail dictionary\n");
goto cleanup;
}
} else {
error("DSAuth plugin: Unable to allocate serviceInfo dictionary\n");
goto cleanup;
}
} else {
error("DSAuth plugin: No Interface subtype found\n");
goto cleanup;
}
} else {
error("DSAuth plugin: No Interface dictionary found\n");
goto cleanup;
}
if (dsauth_find_user_node(dirRef, (char*)name, &userNode, &recordNameAttr, &authAuthorityAttr) == 0) {
userShortNameSize = recordNameAttr->fAttributeValueData.fBufferLength;
authDataSize = userNameSize + userShortNameSize + NT_RESPONSE_SIZE + (2 * CHALLENGE_SIZE) + (5 * sizeof(u_int32_t));
if ((authDataBufPtr = dsDataBufferAllocate(dirRef, authDataSize)) != 0) {
authDataBufPtr->fBufferLength = authDataSize;
ptr = (char*)(authDataBufPtr->fBufferData);
*((u_int32_t*)ptr) = userShortNameSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, recordNameAttr->fAttributeValueData.fBufferData, userShortNameSize);
ptr += userShortNameSize;
*((u_int32_t*)ptr) = CHALLENGE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, challenge, CHALLENGE_SIZE);
ptr += CHALLENGE_SIZE;
*((u_int32_t*)ptr) = CHALLENGE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, resp->PeerChallenge, CHALLENGE_SIZE);
ptr += CHALLENGE_SIZE;
*((u_int32_t*)ptr) = NT_RESPONSE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, resp->NTResp, NT_RESPONSE_SIZE);
ptr += NT_RESPONSE_SIZE;
*((u_int32_t*)ptr) = userNameSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, name, userNameSize);
if ((dsResult = dsDoDirNodeAuth(userNode, authTypeDataNodePtr, TRUE, authDataBufPtr,
responseDataBufPtr, 0)) == eDSNoErr) {
if ((responseDataBufPtr->fBufferLength == MS_AUTH_RESPONSE_LENGTH + 4)
&& *((u_int32_t*)(responseDataBufPtr->fBufferData)) == MS_AUTH_RESPONSE_LENGTH) {
responseDataBufPtr->fBufferData[4 + MS_AUTH_RESPONSE_LENGTH] = 0;
if (resp->Flags[0])
slprintf((char*)message, message_space, "S=%s", responseDataBufPtr->fBufferData + 4);
else
slprintf((char*)message, message_space, "S=%s M=%s",
responseDataBufPtr->fBufferData + 4, "Access granted");
authResult = 1;
if ((ccp_wantoptions[0].mppe)) {
if (!dsauth_set_mppe_keys(dirRef, userNode, response, authAuthorityAttr, challenge)) {
error("DSAuth plugin: MPPE key required, but its retrieval failed.\n");
authResult = 0;
}
}
}
}
}
dsCloseDirNode(userNode);
dsDeallocAttributeValueEntry(dirRef, recordNameAttr);
dsDeallocAttributeValueEntry(dirRef, authAuthorityAttr);
}
cleanup:
if (serviceInfo)
CFRelease(serviceInfo);
if (responseDataBufPtr)
dsDataBufferDeAllocate(dirRef, responseDataBufPtr);
if (authTypeDataNodePtr)
dsDataNodeDeAllocate(dirRef, authTypeDataNodePtr);
if (authDataBufPtr)
dsDataBufferDeAllocate(dirRef, authDataBufPtr);
dsCloseDirService(dirRef);
}
return authResult;
}
static tDataBufferPtr dsauth_agent_authbuffer(tDirReference dirRef, const char *keyaccessName, u_int32_t keyaccessNameSize,
const char *keyaccessPassword, u_int32_t keyaccessPasswordSize,
const unsigned char *challenge)
{
tDataBufferPtr authDataBufPtr;
u_int32_t authDataSize;
char *ptr;
MS_Chap2Response keyResponse;
unsigned char priv[64];
authDataSize = (2 * keyaccessNameSize) + NT_RESPONSE_SIZE + (2 * CHALLENGE_SIZE) + (5 * sizeof(u_int32_t));
if ((authDataBufPtr = dsDataBufferAllocate(dirRef, authDataSize)) != 0) {
authDataBufPtr->fBufferLength = authDataSize;
ptr = (char *)(authDataBufPtr->fBufferData);
*((u_int32_t*)ptr) = keyaccessNameSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, keyaccessName, keyaccessNameSize);
ptr += keyaccessNameSize;
*((u_int32_t*)ptr) = CHALLENGE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, challenge, CHALLENGE_SIZE);
ptr += CHALLENGE_SIZE;
bzero(priv, sizeof(priv));
bzero(&keyResponse, sizeof(keyResponse));
ChapMS2(challenge, NULL,
keyaccessName,
keyaccessPassword, keyaccessPasswordSize,
&keyResponse, priv,
MS_CHAP2_AUTHENTICATEE);
#ifdef DSAUTH_DEBUG
DSAuth_hex_print("VPN agent Name", keyaccessName, keyaccessNameSize);
DSAuth_hex_print("Pwd", keyaccessPassword, keyaccessPasswordSize);
DSAuth_hex_print("Challenge", challenge, CHALLENGE_SIZE);
DSAuth_hex_print("PeerChallenge", keyResponse.PeerChallenge, CHALLENGE_SIZE);
DSAuth_hex_print("response", keyResponse.NTResp, 24);
#endif
*((u_int32_t*)ptr) = CHALLENGE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, keyResponse.PeerChallenge, CHALLENGE_SIZE);
ptr += CHALLENGE_SIZE;
*((u_int32_t*)ptr) = NT_RESPONSE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, keyResponse.NTResp, NT_RESPONSE_SIZE);
ptr += NT_RESPONSE_SIZE;
*((u_int32_t*)ptr) = keyaccessNameSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, keyaccessName, keyaccessNameSize);
}
return authDataBufPtr;
}
static int dsauth_set_mppe_keys(tDirReference dirRef, tDirNodeReference userNode, u_char *remmd,
tAttributeValueEntryPtr authAuthorityAttr,
const unsigned char *challenge)
{
tDataNodePtr authKeysDataNodePtr = 0;
tDataBufferPtr authDataBufPtr = 0;
tDataBufferPtr responseDataBufPtr = 0;
tDataBufferPtr chapDataBufPtr = NULL;
tDirStatus dsResult = eDSNoErr;
char *ptr, *comma, *tagStart;
MS_Chap2Response *resp;
char *keyaccessPassword = 0;
char *keyaccessName = 0;
u_int32_t keyaccessNameSize = 0;
u_int32_t keyaccessPasswordSize;
int len, i;
u_int32_t slotIDSize = 0;
const char *slotID;
tContextData dir_context = 0;
int status = 0;
mppe_keys_set = 0;
tagStart = 0;
ptr = authAuthorityAttr->fAttributeValueData.fBufferData;
for (i = 0; i < authAuthorityAttr->fAttributeValueData.fBufferLength; i++) {
if (*ptr == ';') {
if (tagStart == 0)
tagStart = ptr + 1;
else
break;
}
ptr++;
}
if (*ptr != ';') {
error("DSAuth plugin: Password Server not available for MPPE key retrieval.\n");
return (status);
}
if (strncmp(tagStart, kDSTagAuthAuthorityPasswordServer, ptr - tagStart) == 0) {
dsauth_get_admin_acct(&keyaccessNameSize, &keyaccessName, &keyaccessPasswordSize, &keyaccessPassword);
if (keyaccessName == 0) {
error("DSAuth plugin: Could not retrieve key agent account information.\n");
return (status);
}
comma = strchr(ptr, ',');
if (comma == NULL) {
error("DSAuth plugin: Could not retrieve slot ID.\n");
return (status);
}
slotID = ptr + 1; slotIDSize = comma - slotID;
} else {
error("DSAuth plugin: unsupported authen authority: recved %s, want %s\n", tagStart, kDSTagAuthAuthorityPasswordServer);
return (status); }
resp = (MS_Chap2Response*)remmd;
if ((responseDataBufPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) {
error("DSAuth plugin: Could not allocate data buffer\n");
goto cleanup;
}
if ((authKeysDataNodePtr = dsDataNodeAllocateString(dirRef, kDSStdAuthMPPEMasterKeys)) == 0) {
error("DSAuth plugin: Could not allocate data buffer\n");
goto cleanup;
}
if ((authDataBufPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) {
error("DSAuth plugin: Could not allocate data buffer\n");
goto cleanup;
}
chapDataBufPtr = dsauth_agent_authbuffer(dirRef, keyaccessName, keyaccessNameSize,
keyaccessPassword, keyaccessPasswordSize,
challenge);
if (chapDataBufPtr == NULL) {
error("DSAuth plugin: Could not generate agent auth buffer\n");
goto cleanup;
}
if ((dsResult = dsDoDirNodeAuth(userNode, authKeysDataNodePtr, TRUE, chapDataBufPtr,
responseDataBufPtr, &dir_context)) != eDSNoErr) {
error("DSAuth plugin: Could not authenticate key agent for encryption key retrieval, err %d\n", dsResult);
goto cleanup;
}
ptr = (char*)(authDataBufPtr->fBufferData);
*((u_int32_t*)ptr) = slotIDSize;
ptr += sizeof(u_int32_t);
memcpy(ptr, slotID, slotIDSize);
ptr += slotIDSize;
*((u_int32_t*)ptr) = NT_RESPONSE_SIZE;
ptr += sizeof(u_int32_t);
memcpy(ptr, resp->NTResp, NT_RESPONSE_SIZE);
ptr += NT_RESPONSE_SIZE;
*((u_int32_t*)ptr) = 1;
ptr += sizeof(u_int32_t);
*ptr = MPPE_MAX_KEY_LEN;
authDataBufPtr->fBufferLength = slotIDSize + NT_RESPONSE_SIZE + 1 + (3 * sizeof(u_int32_t));
if ((dsResult = dsDoDirNodeAuth(userNode, authKeysDataNodePtr, TRUE, authDataBufPtr,
responseDataBufPtr, &dir_context)) == eDSNoErr) {
if (responseDataBufPtr->fBufferLength == (2 * sizeof(u_int32_t)) + (2 * MPPE_MAX_KEY_LEN)) {
ptr = (char*)(responseDataBufPtr->fBufferData);
len = *((u_int32_t*)ptr);
ptr += sizeof(u_int32_t);
if (len == sizeof(mppe_send_key))
memcpy(mppe_send_key, ptr, sizeof(mppe_send_key));
ptr += len;
len = *((u_int32_t*)ptr);
ptr += sizeof(u_int32_t);
if (len == sizeof(mppe_recv_key))
memcpy(mppe_recv_key, ptr, sizeof(mppe_recv_key));
mppe_keys_set = 1;
status = 1;
} else
error("DSAuth plugin: Invalid MPPE data for encryption keys retrieval\n");
} else
error("DSAuth plugin: Failed to retrieve MPPE encryption keys from the password server: errno %d, ctxt %x\n", dsResult, dir_context);
cleanup:
if (dir_context != 0) {
dsReleaseContinueData(dirRef, dir_context);
}
if (keyaccessPassword) {
bzero(keyaccessPassword, keyaccessPasswordSize); #if !TARGET_OS_EMBEDDED // This file is not built for Embedded
SecKeychainItemFreeContent(NULL, keyaccessPassword);
#endif
}
if (keyaccessName) {
free(keyaccessName);
}
if (responseDataBufPtr)
dsDataBufferDeAllocate(dirRef, responseDataBufPtr);
if (chapDataBufPtr)
dsDataNodeDeAllocate(dirRef, chapDataBufPtr);
if (authKeysDataNodePtr)
dsDataNodeDeAllocate(dirRef, authKeysDataNodePtr);
if (authDataBufPtr)
dsDataBufferDeAllocate(dirRef, authDataBufPtr);
return (status);
}
static void dsauth_get_admin_acct(u_int32_t *acctNameSize, char** acctName, u_int32_t *passwordSize, char **password)
{
SCPreferencesRef prefs;
CFPropertyListRef globals;
CFStringRef acctNameRef;
char namestr[256];
u_int32_t namelen;
*passwordSize = 0;
*password = 0;
*acctNameSize = 0;
*acctName = 0;
if ((prefs = SCPreferencesCreate(0, CFSTR("pppd"), kRASServerPrefsFileName)) != 0) {
if ((globals = SCPreferencesGetValue(prefs, kRASGlobals)) != 0) {
if ((acctNameRef = CFDictionaryGetValue(globals, KRASGlobPSKeyAccount)) != 0) {
namestr[0] = 0;
CFStringGetCString(acctNameRef, namestr, 256, kCFStringEncodingMacRoman);
if (namestr[0]) {
namelen = strlen(namestr);
if (dsauth_get_admin_password(namelen, namestr, passwordSize, password) == 0) {
*acctNameSize = namelen;
*acctName = malloc(namelen + 1);
if (acctName != 0)
memcpy(*acctName, namestr, namelen + 1);
}
} else
error("DSAuth plugin: Key access user name not valid.\n");
}
}
CFRelease(prefs);
}
}
static int dsauth_get_admin_password(u_int32_t acctlen, char* acctname, u_int32_t *password_len, char **password)
{
#if !TARGET_OS_EMBEDDED // This file is not built for Embedded
SecKeychainRef keychain = 0;
OSStatus status;
if ((status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem)) == noErr) {
if ((status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain)) == noErr) {
status = SecKeychainFindGenericPassword(keychain, strlen(serviceName), serviceName,
acctlen, acctname, (UInt32*)password_len, (void**)password, NULL);
}
}
if (keychain)
CFRelease(keychain);
if (status == noErr)
return 0;
else {
error("DSAuth plugin: Error %d while retrieving key agent password from the system keychain.\n", status);
return -1;
}
#else
error("System Keychain support not available");
return -1;
#endif
}
static int dsauth_find_user_node(tDirReference dirRef, char *user_name, tDirNodeReference *user_node,
tAttributeValueEntryPtr *recordNameAttr, tAttributeValueEntryPtr *authAuthorityAttr)
{
tDirStatus dsResult = eDSNoErr;
tDataListPtr userPathDataListPtr = 0;
UInt32 searchNodeCount;
tAttributeValueEntryPtr userNodePath = 0;
tDirNodeReference searchNodeRef = 0;
*user_node = 0; *recordNameAttr = 0;
*authAuthorityAttr = 0;
if ((dsResult = dsauth_get_search_node_ref(dirRef, 1, &searchNodeRef, &searchNodeCount)) == eDSNoErr) {
dsResult = dsauth_get_user_attr(dirRef, searchNodeRef, user_name, kDSNAttrMetaNodeLocation, &userNodePath);
if (dsResult == eDSNoErr && userNodePath != 0) {
if (userPathDataListPtr = dsBuildFromPath(dirRef, userNodePath->fAttributeValueData.fBufferData, "/")) {
dsResult = dsOpenDirNode(dirRef, userPathDataListPtr, user_node);
dsDataListDeallocate(dirRef, userPathDataListPtr);
}
if (dsResult == eDSNoErr)
dsResult = dsauth_get_user_attr(dirRef, searchNodeRef, user_name, kDSNAttrRecordName, recordNameAttr);
if (dsResult == eDSNoErr)
dsResult = dsauth_get_user_attr(dirRef, searchNodeRef, user_name, kDSNAttrAuthenticationAuthority, authAuthorityAttr);
}
if (userNodePath)
dsDeallocAttributeValueEntry(dirRef, userNodePath);
dsCloseDirNode(searchNodeRef); }
if (dsResult != eDSNoErr || *user_node == 0 || *recordNameAttr == 0 || *authAuthorityAttr == 0) {
if (*user_node)
dsCloseDirNode(*user_node);
if (*recordNameAttr)
dsDeallocAttributeValueEntry(dirRef, *recordNameAttr);
if (*authAuthorityAttr)
dsDeallocAttributeValueEntry(dirRef, *authAuthorityAttr);
return -1;
}
return 0;
}