tDirStatus userAuthInfo(tDirReference pDirRef, tDirNodeReference pNodeRef, const char *pszUsername, tDataListPtr *ppAuthNodeListOut)
{
    tDirStatus dsErr = eDSNoErr;
    tDirStatus dsCleanErr = eDSNoErr;
    /* Create a buffer for the resulting authentication info */
    tDataBufferPtr pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
    if (pTmpBuf)
    {
        /* Create the necessary lists for kDSNAttrMetaNodeLocation and kDSNAttrRecordName. */
        tDataListPtr pRecordType = dsBuildListFromStrings(pDirRef, kDSStdRecordTypeUsers, NULL);
        tDataListPtr pRecordName = dsBuildListFromStrings(pDirRef, pszUsername, NULL);
        tDataListPtr pRequestedAttributes = dsBuildListFromStrings(pDirRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);
        if (!(   pRecordType == NULL
              || pRecordName == NULL
              || pRequestedAttributes == NULL))
        {
            /* Now search for the first matching record */
            UInt32 cRecords = 1;
            tContextData pCtx = NULL;
            dsErr = dsGetRecordList(pNodeRef,
                                    pTmpBuf,
                                    pRecordName,
                                    eDSExact,
                                    pRecordType,
                                    pRequestedAttributes,
                                    false,
                                    &cRecords,
                                    &pCtx);
            if (   dsErr == eDSNoErr
                && cRecords >= 1)
            {
                /* Process the first found record. Look at any attribute one by one. */
                tAttributeListRef pRecAttrListRef = NULL;
                tRecordEntryPtr pRecEntry = NULL;
                tDataListPtr pAuthNodeList = NULL;
                dsErr = dsGetRecordEntry(pNodeRef, pTmpBuf, 1, &pRecAttrListRef, &pRecEntry);
                if (dsErr == eDSNoErr)
                {
                    for (size_t i = 1; i <= pRecEntry->fRecordAttributeCount; ++i)
                    {
                        tAttributeValueListRef pAttrValueListRef = NULL;
                        tAttributeEntryPtr pAttrEntry = NULL;
                        /* Get the information for this attribute. */
                        dsErr = dsGetAttributeEntry(pNodeRef, pTmpBuf, pRecAttrListRef, i,
                                                    &pAttrValueListRef, &pAttrEntry);
                        if (dsErr == eDSNoErr)
                        {
                            tAttributeValueEntryPtr pValueEntry = NULL;
                            /* Has any value? */
                            if (pAttrEntry->fAttributeValueCount > 0)
                            {
                                dsErr = dsGetAttributeValue(pNodeRef, pTmpBuf, 1, pAttrValueListRef, &pValueEntry);
                                if (dsErr == eDSNoErr)
                                {
                                    /* Check for kDSNAttrMetaNodeLocation */
                                    if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0)
                                    {
                                        /* Convert the meta location attribute to a path node list */
                                        pAuthNodeList = dsBuildFromPath(pDirRef,
                                                                        pValueEntry->fAttributeValueData.fBufferData,
                                                                        "/");
                                        if (pAuthNodeList == NULL)
                                            dsErr = eDSAllocationFailed;
                                    }
                                }
                            }

                            if (pValueEntry != NULL)
                                dsDeallocAttributeValueEntry(pDirRef, pValueEntry);
                            if (pAttrValueListRef)
                                dsCloseAttributeValueList(pAttrValueListRef);
                            if (pAttrEntry != NULL)
                                dsDeallocAttributeEntry(pDirRef, pAttrEntry);

                            if (dsErr != eDSNoErr)
                                break;
                        }
                    }
                }
                /* Copy the results */
                if (dsErr == eDSNoErr)
                {
                    if (pAuthNodeList != NULL)
                    {
                        /* Copy out results. */
                        *ppAuthNodeListOut = pAuthNodeList;
                        pAuthNodeList = NULL;
                    }
                    else
                        dsErr = eDSAttributeNotFound;
                }

                if (pAuthNodeList != NULL)
                {
                    dsCleanErr = dsDataListDeallocate(pDirRef, pAuthNodeList);
                    if (dsCleanErr == eDSNoErr)
                        free(pAuthNodeList);
                }
                if (pRecAttrListRef)
                    dsCloseAttributeList(pRecAttrListRef);
                if (pRecEntry != NULL)
                    dsDeallocRecordEntry(pDirRef, pRecEntry);
            }
            else
                dsErr = eDSRecordNotFound;
            if (pCtx)
                dsReleaseContinueData(pDirRef, pCtx);
        }
        else
            dsErr = eDSAllocationFailed;
        if (pRequestedAttributes != NULL)
        {
            dsCleanErr = dsDataListDeallocate(pDirRef, pRequestedAttributes);
            if (dsCleanErr == eDSNoErr)
                free(pRequestedAttributes);
        }
        if (pRecordName != NULL)
        {
            dsCleanErr = dsDataListDeallocate(pDirRef, pRecordName);
            if (dsCleanErr == eDSNoErr)
                free(pRecordName);
        }
        if (pRecordType != NULL)
        {
            dsCleanErr = dsDataListDeallocate(pDirRef, pRecordType);
            if (dsCleanErr == eDSNoErr)
                free(pRecordType);
        }
        dsDataBufferDeAllocate(pDirRef, pTmpBuf);
    }
    else
        dsErr = eDSAllocationFailed;

    return dsErr;
}
Beispiel #2
0
//----------------------------------------------------------------------
//	dsauth_set_mppe_keys
//		get the mppe keys from the password server
//		if this fails - do nothing.  there is no way to
//		know if the keys are actually going to be needed
//		at this point.
//----------------------------------------------------------------------
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;

 	// parse authAuthorityAttribute to determine if key agent needs to be used.
	// auth authority tag will be between 2 semicolons.
	tagStart = 0;
	ptr = authAuthorityAttr->fAttributeValueData.fBufferData;
	// DSAuth_hex_print("authAuth mppe", authAuthorityAttr->fAttributeValueData.fBufferData, authAuthorityAttr->fAttributeValueData.fBufferLength);
	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);
		}
		
		// PWS auths expect to receive the PWS ID in the MPPE phase
		comma = strchr(ptr, ',');
		if (comma == NULL) {
			error("DSAuth plugin: Could not retrieve slot ID.\n");
			return (status);
		}

		slotID = ptr + 1; // skip the ';' as well
		slotIDSize = comma - slotID;
	} else {
	        error("DSAuth plugin: unsupported authen authority: recved %s, want %s\n", tagStart, kDSTagAuthAuthorityPasswordServer);
		return (status);		// unsupported authentication authority - don't set the keys
	}
        
	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;
    }
	
	/*
	 * phase 1 uses an MSCHAP-style auth for the VPN agent (agent account, server challenge, peer challenge, agent NT response, agent account)
	 * phase 2 retrieves the keys (PWS ID of the user, client NT response, keysize)
	 */
	
	// Phase 1
	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;
	}

	// Phase 2
	ptr = (char*)(authDataBufPtr->fBufferData);

	// DSAuth_hex_print("PWS ID", slotID, slotIDSize);
	// DSAuth_hex_print("NTResp", resp->NTResp, NT_RESPONSE_SIZE);

	// 4 byte length & slotID
	*((u_int32_t*)ptr) = slotIDSize;
	ptr += sizeof(u_int32_t);
	memcpy(ptr, slotID, slotIDSize);
	ptr += slotIDSize;

	// 4 byte length & client digest
	*((u_int32_t*)ptr) = NT_RESPONSE_SIZE;
	ptr += sizeof(u_int32_t);
	memcpy(ptr, resp->NTResp, NT_RESPONSE_SIZE);
	ptr += NT_RESPONSE_SIZE;

	// 4 byte length and master key len - always 128
	*((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));

	// get the mppe keys
	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);	// clear the admin password from memory
#if !TARGET_OS_EMBEDDED // This file is not built for Embedded
        SecKeychainItemFreeContent(NULL, keyaccessPassword);
#endif /* TARGET_OS_EMBEDDED */
    }
    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);
}
Beispiel #3
0
tDirStatus
FindUsersAuthInfo(
    tDirReference       dirRef,
    tDirNodeReference   nodeRef,
    const char *        username,
    tDataListPtr *      pathListToAuthNodePtr
)
{
    tDirStatus          err;
    tDirStatus          junk;
    tDataBufferPtr      buf;
    tDataListPtr        recordType;
    tDataListPtr        recordName;
    tDataListPtr        requestedAttributes;
    unsigned long       recordCount;
    tAttributeListRef   foundRecAttrList;
    tContextData        context;
    tRecordEntryPtr     foundRecEntry;
    tDataListPtr        pathListToAuthNode;

    if (!( (dirRef != NULL) || (nodeRef != NULL) || (username != NULL) ||
            ( pathListToAuthNodePtr != NULL) || (*pathListToAuthNodePtr == NULL) ) )
        return(eDSBadParam);

    recordType = NULL;
    recordName = NULL;
    requestedAttributes = NULL;
    foundRecAttrList = NULL;
    context = NULL;
    foundRecEntry = NULL;
    pathListToAuthNode = NULL;

    /*
    ** Allocate a buffer for the record results.  We'll grow this
    ** buffer if it proves to be too small.
    */

    err = eDSNoErr;
    buf = dsDataBufferAllocate(dirRef, kDefaultDSBufferSize);
    if (buf == NULL)
        err = eDSAllocationFailed;

    /*
    ** Create the information needed for the search.  We're searching for
    ** a record of type kDSStdRecordTypeUsers whose name is "username".
    ** We want to get back the kDSNAttrMetaNodeLocation and kDSNAttrRecordName
    ** attributes.
    */

    if (err == eDSNoErr)
    {
        recordType = dsBuildListFromStrings(dirRef, kDSStdRecordTypeUsers, NULL);
        recordName = dsBuildListFromStrings(dirRef, username, NULL);
        requestedAttributes = dsBuildListFromStrings(dirRef,
                              kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);

        if ( (recordType == NULL) || (recordName == NULL) ||
                (requestedAttributes == NULL) )
            err = eDSAllocationFailed;
    }

    /* Search for a matching record. */

    if (err == eDSNoErr) {
        recordCount = 1;            /* we only want one match (the first) */

        err = dsGetRecordListQ(
                  dirRef,
                  nodeRef,
                  &buf,
                  recordName,
                  eDSExact,
                  recordType,
                  requestedAttributes,
                  false,
                  &recordCount,
                  &context
              );
    }

    if ( (err == eDSNoErr) && (recordCount < 1) )
        err = eDSRecordNotFound;

    /*
    ** Get the first record from the search.  Then enumerate the attributes for
    ** that record.  For each attribute, extract the first value (remember that
    ** attributes can by multi-value).  Then see if the attribute is one that
    ** we care about.  If it is, remember the value for later processing.
    */
    if (err == eDSNoErr)
        err = dsGetRecordEntry(nodeRef, buf, 1, &foundRecAttrList,
                               &foundRecEntry);

    if (err == eDSNoErr)
    {
        unsigned long attrIndex;

        /* Iterate over the attributes. */

        for (attrIndex = 1;
                attrIndex <= foundRecEntry->fRecordAttributeCount;
                attrIndex++)
        {
            tAttributeValueListRef  thisValue;
            tAttributeEntryPtr      thisAttrEntry;
            tAttributeValueEntryPtr thisValueEntry;
            const char *            thisAttrName;

            thisValue = NULL;
            thisAttrEntry = NULL;
            thisValueEntry = NULL;

            /* Get the information for this attribute. */

            err = dsGetAttributeEntry(nodeRef, buf, foundRecAttrList, attrIndex,
                                      &thisValue, &thisAttrEntry);

            if (err == eDSNoErr)
            {
                thisAttrName = thisAttrEntry->fAttributeSignature.fBufferData;

                /* We only care about attributes that have values. */

                if (thisAttrEntry->fAttributeValueCount > 0)
                {
                    /*
                    ** Get the first value for this attribute.  This is common
                    ** code for the two potential attribute values listed below,
                    ** so we do it first.
                    */

                    err = dsGetAttributeValue(nodeRef, buf, 1, thisValue,
                                              &thisValueEntry);

                    if (err == eDSNoErr)
                    {
                        const char *    thisValueDataPtr;
                        unsigned long   thisValueDataLen;

                        thisValueDataPtr = thisValueEntry->fAttributeValueData.fBufferData;
                        thisValueDataLen = thisValueEntry->fAttributeValueData.fBufferLength;

                        /*
                                    ** Handle each of the two attributes we care about;
                        ** ignore any others.
                        */

                        if ( STcompare(thisAttrName,
                                       kDSNAttrMetaNodeLocation) == 0 )
                        {

                            /*
                                        ** This is the kDSNAttrMetaNodeLocation attribute,
                            ** which contains a path to the node used for
                            ** authenticating this record; convert its value
                            ** into a path list.
                            */

                            pathListToAuthNode = dsBuildFromPath(
                                                     dirRef,
                                                     thisValueDataPtr,
                                                     "/"
                                                 );
                            if (pathListToAuthNode == NULL)
                                err = eDSAllocationFailed;

                        }
                    }
                    else
                    {
                        fprintf(stderr, "FindUsersAuthInfo: Unexpected no-value attribute '%s'.", thisAttrName);
                    }
                }

                /* Clean up. */

                if (thisValueEntry != NULL)
                    dsDeallocAttributeValueEntry(dirRef, thisValueEntry);
                if (thisValue != NULL)
                    dsCloseAttributeValueList(thisValue);
                if (thisAttrEntry != NULL)
                    dsDeallocAttributeEntry(dirRef, thisAttrEntry);

                if (err != eDSNoErr)
                    break;
            }
        } /* Check attr loop */
    }

    /* Copy results out to caller. */

    if (err == eDSNoErr)
    {
        if (pathListToAuthNode != NULL)
        {
            /* Copy out results. */

            *pathListToAuthNodePtr = pathListToAuthNode;

            /* NULL out locals so that we don't dispose them. */

            pathListToAuthNode = NULL;
        }
        else
            err = eDSAttributeNotFound;
    }

    /* Clean up. */

    if (pathListToAuthNode != NULL)
        dsDataListAndHeaderDeallocate(dirRef, pathListToAuthNode);
    if (foundRecAttrList != NULL)
        dsCloseAttributeList(foundRecAttrList);
    if (context != NULL)
        dsReleaseContinueData(dirRef, context);
    if (foundRecAttrList != NULL)
        dsDeallocRecordEntry(dirRef, foundRecEntry);
    if (requestedAttributes != NULL)
        dsDataListAndHeaderDeallocate(dirRef, requestedAttributes);
    if (recordName != NULL)
        dsDataListAndHeaderDeallocate(dirRef, recordName);
    if (recordType != NULL)
        dsDataListAndHeaderDeallocate(dirRef, recordType);
    if (buf != NULL)
        dsDataBufferDeAllocate(dirRef, buf);

    return err;
}
Beispiel #4
0
CFArrayRef find_user_records_by_name(KADirectoryNode *node, const char *username)
{  
    tDirStatus status = 0;
    long unsigned record_count = 0; // This is an input variable too
    tContextData continuation_data_ptr = NULL;
    CFMutableArrayRef results = NULL;

	tDataListPtr recordTypeDataList = dsBuildListFromStrings(node->_directoryRef, kDSStdRecordTypeUsers, NULL);
	tDataListPtr returnAttributesDataList = dsBuildListFromStrings(node->_directoryRef, kDSAttributesAll, NULL);
    tDataListPtr record_name_ptr = dsBuildListFromStrings(node->_directoryRef, username, NULL);
	
	do {
	
		for (;;)
		{
			status = dsGetRecordList(node->_nodeRef, node->_dataBufferPtr,
				record_name_ptr, eDSExact,
				recordTypeDataList,
				returnAttributesDataList,
				false,	/* attr info and data */
				&record_count,
				&continuation_data_ptr);
				
			// Of all errors we only try to recover from eDSBufferTooSmall here
			if ((status != eDSBufferTooSmall) || !(node->_dataBufferPtr = double_databuffer_or_bail(node->_directoryRef, node->_dataBufferPtr)))
			break;
		} 

        if (status)
			break;
			
        if (record_count > 0) 
        {
			long unsigned i;

			if (!results)
				results = CFArrayCreateMutable(kCFAllocatorDefault, record_count, &kCFTypeArrayCallBacks);

			for (i=1; i <= record_count; i++)
			{
				CFMutableDictionaryRef record = get_record_at_index(node, i);
				
				if (record)
				{
					CFArrayAppendValue(results, record);
					CFRelease(record);
				}
			}
        }
        
    } while (continuation_data_ptr != NULL);

	if (record_name_ptr)
		dsDataListDeallocate(node->_directoryRef, record_name_ptr);
	if (recordTypeDataList)
	    dsDataListDeallocate(node->_directoryRef, recordTypeDataList);
	if (returnAttributesDataList)
	    dsDataListDeallocate(node->_directoryRef, returnAttributesDataList);
    if (continuation_data_ptr)
		dsReleaseContinueData(node->_nodeRef, continuation_data_ptr);

	return results;
}
Beispiel #5
0
tDirStatus
getdsnodepath(tDirReference dirRef, tDataListPtr *dsnodepath)
{
    tDirStatus          err;
    tDirStatus          junk;
    tDataBufferPtr      buf;
    tDirPatternMatch    patternToFind;
    unsigned long       nodeCount;
    tContextData        context;

    if (!( (dirRef != NULL) || ( dsnodepath != NULL) || (*dsnodepath == NULL) ) )
        return( eDSBadParam );

    if (authlocalonly)
        patternToFind = eDSLocalNodeNames;
    else
        patternToFind = eDSAuthenticationSearchNodeName;

    context = NULL;

    /*
    ** Allocate a buffer for the node find results.  We'll grow
    ** this buffer if it proves to be to small.
    */

    buf = dsDataBufferAllocate(dirRef, kDefaultDSBufferSize);
    err = eDSNoErr;
    if (buf == NULL)
        err = eDSAllocationFailed;

    /*
    ** Find the node.  Note that this is a degenerate case because
    ** we're only looking for a single node, the search node, so
    ** we don't need to loop calling dsFindDirNodes, which is the
    ** standard way of using dsFindDirNodes.
    */

    if (err == eDSNoErr)
    {
        err = dsFindDirNodesQ(
                  dirRef,
                  &buf,                               /* place results here */
                  NULL,                               /* no pattern, rather... */
                  patternToFind,                      /* ... hardwired search type */
                  &nodeCount,
                  &context
              );
    }

    /* If we didn't find any nodes, that's bad. */

    if ( (err == eDSNoErr) && (nodeCount < 1) )
        err = eDSNodeNotFound;

    /*
    ** Grab the first node from the buffer.  Note that the inDirNodeIndex
    ** parameter to dsGetDirNodeName is one-based, so we pass in the constant
    ** 1.
    **
    ** Also, if we found more than one, that's unusual, but not enough to
    ** cause us to error.
    */

    if (err == eDSNoErr)
        err = dsGetDirNodeName(dirRef, buf, 1, dsnodepath);

    /* Clean up. */

    if (context != NULL)
        dsReleaseContinueData(dirRef, context);
    if (buf != NULL)
        dsDataBufferDeAllocate(dirRef, buf);

    return err;
}