directoryservice.cpp revision 9c0076729ec8138e89ce8a6af9a772b68f1f8dc7
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * VBox Remote Desktop Protocol:
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * External Authentication Library:
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * Mac OS X Authentication. This is based on
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * http://developer.apple.com/mac/library/samplecode/CryptNoMore/
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * Copyright (C) 2009-2010 Oracle Corporation
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * available from http://www.virtualbox.org. This file is free software;
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * General Public License (GPL) as published by the Free Software
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync/* Globals */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsynctDirStatus defaultSearchNodePath(tDirReference pDirRef, tDataListPtr *pdsNodePath)
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Create a buffer for the resulting nodes */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Try to find the default search node for local names */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsFindDirNodes(pDirRef, pTmpBuf, NULL, eDSLocalNodeNames, &cNodes, &pCtx);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Any nodes found? */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* The first path of the node list is what we looking for. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsGetDirNodeName(pDirRef, pTmpBuf, 1, pdsNodePath);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsynctDirStatus userAuthInfo(tDirReference pDirRef, tDirNodeReference pNodeRef, const char *pszUsername, tDataListPtr *ppAuthNodeListOut)
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Create a buffer for the resulting authentication info */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataBufferPtr pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Create the necessary lists for kDSNAttrMetaNodeLocation and kDSNAttrRecordName. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataListPtr pRecordType = dsBuildListFromStrings(pDirRef, kDSStdRecordTypeUsers, NULL);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataListPtr pRecordName = dsBuildListFromStrings(pDirRef, pszUsername, NULL);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataListPtr pRequestedAttributes = dsBuildListFromStrings(pDirRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Now search for the first matching record */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Process the first found record. Look at any attribute one by one. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsGetRecordEntry(pNodeRef, pTmpBuf, 1, &pRecAttrListRef, &pRecEntry);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync for (size_t i = 1; i <= pRecEntry->fRecordAttributeCount; ++i)
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Get the information for this attribute. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsGetAttributeEntry(pNodeRef, pTmpBuf, pRecAttrListRef, i,
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Has any value? */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsGetAttributeValue(pNodeRef, pTmpBuf, 1, pAttrValueListRef, &pValueEntry);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Check for kDSNAttrMetaNodeLocation */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0)
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Convert the meta location attribute to a path node list */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsDeallocAttributeValueEntry(pDirRef, pValueEntry);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Copy the results */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Copy out results. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsCleanErr = dsDataListDeallocate(pDirRef, pAuthNodeList);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsCleanErr = dsDataListDeallocate(pDirRef, pRequestedAttributes);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsCleanErr = dsDataListDeallocate(pDirRef, pRecordName);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsCleanErr = dsDataListDeallocate(pDirRef, pRecordType);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsynctDirStatus authWithNode(tDirReference pDirRef, tDataListPtr pAuthNodeList, const char *pszUsername, const char *pszPassword)
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Open the authentication node. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsOpenDirNode(pDirRef, pAuthNodeList, &pAuthNodeRef);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* How like we to authenticate! */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataNodePtr pAuthMethod = dsDataNodeAllocateString(pDirRef, kDSStdAuthNodeNativeClearTextOK);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Create the memory holding the authentication data. The data
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * structure consists of 4 byte length of the username + zero byte,
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * the username itself, a 4 byte length of the password & the
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * password itself + zero byte. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataBufferPtr pAuthOutBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync unsigned long cLen = 0;
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync tDataBufferPtr pAuthInBuf = dsDataBufferAllocate(pDirRef, sizeof(cLen) + cUserName + sizeof(cLen) + cPassword);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Move the data into the buffer. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Length of the username */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], &cLen, sizeof(cLen));
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* The username itself */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], pszUsername, cUserName);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Length of the password */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], &cLen, sizeof(cLen));
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* The password itself */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], pszPassword, cPassword);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Now authenticate */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsDoDirNodeAuth(pAuthNodeRef, pAuthMethod, true, pAuthInBuf, pAuthOutBuf, NULL);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Clean up. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsyncDECLEXPORT(VRDPAuthResult) VRDPAUTHCALL VRDPAuth(PVRDPAUTHUUID pUuid,
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync const char *pszUser,
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Validate input */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync AssertPtrReturn(pszPassword, VRDPAuthAccessDenied);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Result to a default value */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Connect to the Directory Service. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Fetch the default search node */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = defaultSearchNodePath(pDirRef, &pSearchNodeList);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Open the default search node */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = dsOpenDirNode(pDirRef, pSearchNodeList, &pSearchNodeRef);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Search for the user info, fetch the authentication node &
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * the authentication user name. This allows the client to
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * specify a long user name even if the name which is used to
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync * authenticate has the short form. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = userAuthInfo(pDirRef, pSearchNodeRef, pszUser, &pAuthNodeList);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync /* Open the authentication node and do the authentication. */
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsErr = authWithNode(pDirRef, pAuthNodeList, pszUser, pszPassword);
9c0076729ec8138e89ce8a6af9a772b68f1f8dc7vboxsync dsCleanErr = dsDataListDeallocate(pDirRef, pAuthNodeList);