VirtualBox

source: vbox/trunk/src/VBox/HostServices/auth/directoryservice/directoryservice.cpp@ 78018

Last change on this file since 78018 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.7 KB
Line 
1/** @file
2 *
3 * VirtualBox External Authentication Library:
4 * Mac OS X Authentication. This is based on
5 * http://developer.apple.com/mac/library/samplecode/CryptNoMore/
6 */
7
8/*
9 * Copyright (C) 2009-2019 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <iprt/cdefs.h>
21#include <iprt/assert.h>
22
23#include <VBox/VBoxAuth.h>
24
25#include <DirectoryService/DirectoryService.h>
26
27/* Globals */
28static const size_t s_cBufferSize = 32 * 1024;
29
30tDirStatus defaultSearchNodePath(tDirReference pDirRef, tDataListPtr *pdsNodePath)
31{
32 tDirStatus dsErr = eDSNoErr;
33 /* Create a buffer for the resulting nodes */
34 tDataBufferPtr pTmpBuf = NULL;
35 pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
36 if (pTmpBuf)
37 {
38 /* Try to find the default search node for local names */
39 UInt32 cNodes;
40 tContextData hCtx = 0;
41 dsErr = dsFindDirNodes(pDirRef, pTmpBuf, NULL, eDSLocalNodeNames, &cNodes, &hCtx);
42 /* Any nodes found? */
43 if ( dsErr == eDSNoErr
44 && cNodes >= 1)
45 /* The first path of the node list is what we looking for. */
46 dsErr = dsGetDirNodeName(pDirRef, pTmpBuf, 1, pdsNodePath);
47 else
48 dsErr = eDSNodeNotFound;
49
50 if (hCtx) /* (DSoNodeConfig.m from DSTools-162 does exactly the same free if not-zero-regardless-of-return-code.) */
51 dsReleaseContinueData(pDirRef, hCtx);
52 dsDataBufferDeAllocate(pDirRef, pTmpBuf);
53 }
54 else
55 dsErr = eDSAllocationFailed;
56
57 return dsErr;
58}
59
60tDirStatus userAuthInfo(tDirReference pDirRef, tDirNodeReference pNodeRef, const char *pszUsername, tDataListPtr *ppAuthNodeListOut)
61{
62 tDirStatus dsErr = eDSNoErr;
63 tDirStatus dsCleanErr = eDSNoErr;
64 /* Create a buffer for the resulting authentication info */
65 tDataBufferPtr pTmpBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
66 if (pTmpBuf)
67 {
68 /* Create the necessary lists for kDSNAttrMetaNodeLocation and kDSNAttrRecordName. */
69 tDataListPtr pRecordType = dsBuildListFromStrings(pDirRef, kDSStdRecordTypeUsers, NULL);
70 tDataListPtr pRecordName = dsBuildListFromStrings(pDirRef, pszUsername, NULL);
71 tDataListPtr pRequestedAttributes = dsBuildListFromStrings(pDirRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, NULL);
72 if (!( pRecordType == NULL
73 || pRecordName == NULL
74 || pRequestedAttributes == NULL))
75 {
76 /* Now search for the first matching record */
77 UInt32 cRecords = 1;
78 tContextData hCtx = 0;
79 dsErr = dsGetRecordList(pNodeRef,
80 pTmpBuf,
81 pRecordName,
82 eDSExact,
83 pRecordType,
84 pRequestedAttributes,
85 false,
86 &cRecords,
87 &hCtx);
88 if ( dsErr == eDSNoErr
89 && cRecords >= 1)
90 {
91 /* Process the first found record. Look at any attribute one by one. */
92 tAttributeListRef hRecAttrListRef = 0;
93 tRecordEntryPtr pRecEntry = NULL;
94 tDataListPtr pAuthNodeList = NULL;
95 dsErr = dsGetRecordEntry(pNodeRef, pTmpBuf, 1, &hRecAttrListRef, &pRecEntry);
96 if (dsErr == eDSNoErr)
97 {
98 for (size_t i = 1; i <= pRecEntry->fRecordAttributeCount; ++i)
99 {
100 tAttributeValueListRef hAttrValueListRef = 0;
101 tAttributeEntryPtr pAttrEntry = NULL;
102 /* Get the information for this attribute. */
103 dsErr = dsGetAttributeEntry(pNodeRef, pTmpBuf, hRecAttrListRef, i,
104 &hAttrValueListRef, &pAttrEntry);
105 if (dsErr == eDSNoErr)
106 {
107 tAttributeValueEntryPtr pValueEntry = NULL;
108 /* Has any value? */
109 if (pAttrEntry->fAttributeValueCount > 0)
110 {
111 dsErr = dsGetAttributeValue(pNodeRef, pTmpBuf, 1, hAttrValueListRef, &pValueEntry);
112 if (dsErr == eDSNoErr)
113 {
114 /* Check for kDSNAttrMetaNodeLocation */
115 if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0)
116 {
117 /* Convert the meta location attribute to a path node list */
118 pAuthNodeList = dsBuildFromPath(pDirRef,
119 pValueEntry->fAttributeValueData.fBufferData,
120 "/");
121 if (pAuthNodeList == NULL)
122 dsErr = eDSAllocationFailed;
123 }
124 }
125 }
126
127 if (pValueEntry != NULL)
128 dsDeallocAttributeValueEntry(pDirRef, pValueEntry);
129 if (hAttrValueListRef)
130 dsCloseAttributeValueList(hAttrValueListRef);
131 if (pAttrEntry != NULL)
132 dsDeallocAttributeEntry(pDirRef, pAttrEntry);
133
134 if (dsErr != eDSNoErr)
135 break;
136 }
137 }
138 }
139 /* Copy the results */
140 if (dsErr == eDSNoErr)
141 {
142 if (pAuthNodeList != NULL)
143 {
144 /* Copy out results. */
145 *ppAuthNodeListOut = pAuthNodeList;
146 pAuthNodeList = NULL;
147 }
148 else
149 dsErr = eDSAttributeNotFound;
150 }
151
152 if (pAuthNodeList != NULL)
153 {
154 dsCleanErr = dsDataListDeallocate(pDirRef, pAuthNodeList);
155 if (dsCleanErr == eDSNoErr)
156 free(pAuthNodeList);
157 }
158 if (hRecAttrListRef)
159 dsCloseAttributeList(hRecAttrListRef);
160 if (pRecEntry != NULL)
161 dsDeallocRecordEntry(pDirRef, pRecEntry);
162 }
163 else
164 dsErr = eDSRecordNotFound;
165 if (hCtx)
166 dsReleaseContinueData(pDirRef, hCtx);
167 }
168 else
169 dsErr = eDSAllocationFailed;
170 if (pRequestedAttributes != NULL)
171 {
172 dsCleanErr = dsDataListDeallocate(pDirRef, pRequestedAttributes);
173 if (dsCleanErr == eDSNoErr)
174 free(pRequestedAttributes);
175 }
176 if (pRecordName != NULL)
177 {
178 dsCleanErr = dsDataListDeallocate(pDirRef, pRecordName);
179 if (dsCleanErr == eDSNoErr)
180 free(pRecordName);
181 }
182 if (pRecordType != NULL)
183 {
184 dsCleanErr = dsDataListDeallocate(pDirRef, pRecordType);
185 if (dsCleanErr == eDSNoErr)
186 free(pRecordType);
187 }
188 dsDataBufferDeAllocate(pDirRef, pTmpBuf);
189 }
190 else
191 dsErr = eDSAllocationFailed;
192
193 return dsErr;
194}
195
196tDirStatus authWithNode(tDirReference pDirRef, tDataListPtr pAuthNodeList, const char *pszUsername, const char *pszPassword)
197{
198 tDirStatus dsErr = eDSNoErr;
199 /* Open the authentication node. */
200 tDirNodeReference hAuthNodeRef = 0;
201 dsErr = dsOpenDirNode(pDirRef, pAuthNodeList, &hAuthNodeRef);
202 if (dsErr == eDSNoErr)
203 {
204 /* How like we to authenticate! */
205 tDataNodePtr pAuthMethod = dsDataNodeAllocateString(pDirRef, kDSStdAuthNodeNativeClearTextOK);
206 if (pAuthMethod)
207 {
208 /* Create the memory holding the authentication data. The data
209 * structure consists of 4 byte length of the username + zero byte,
210 * the username itself, a 4 byte length of the password & the
211 * password itself + zero byte. */
212 tDataBufferPtr pAuthOutBuf = dsDataBufferAllocate(pDirRef, s_cBufferSize);
213 if (pAuthOutBuf)
214 {
215 size_t cUserName = strlen(pszUsername) + 1;
216 size_t cPassword = strlen(pszPassword) + 1;
217 unsigned long cLen = 0;
218 tDataBufferPtr pAuthInBuf = dsDataBufferAllocate(pDirRef, sizeof(cLen) + cUserName + sizeof(cLen) + cPassword);
219 if (pAuthInBuf)
220 {
221 /* Move the data into the buffer. */
222 pAuthInBuf->fBufferLength = 0;
223 /* Length of the username */
224 cLen = cUserName;
225 memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], &cLen, sizeof(cLen));
226 pAuthInBuf->fBufferLength += sizeof(cLen);
227 /* The username itself */
228 memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], pszUsername, cUserName);
229 pAuthInBuf->fBufferLength += cUserName;
230 /* Length of the password */
231 cLen = cPassword;
232 memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], &cLen, sizeof(cLen));
233 pAuthInBuf->fBufferLength += sizeof(cLen);
234 /* The password itself */
235 memcpy(&pAuthInBuf->fBufferData[pAuthInBuf->fBufferLength], pszPassword, cPassword);
236 pAuthInBuf->fBufferLength += cPassword;
237 /* Now authenticate */
238 dsErr = dsDoDirNodeAuth(hAuthNodeRef, pAuthMethod, true, pAuthInBuf, pAuthOutBuf, NULL);
239 /* Clean up. */
240 dsDataBufferDeAllocate(pDirRef, pAuthInBuf);
241 }
242 else
243 dsErr = eDSAllocationFailed;
244 dsDataBufferDeAllocate(pDirRef, pAuthOutBuf);
245 }
246 else
247 dsErr = eDSAllocationFailed;
248 dsDataNodeDeAllocate(pDirRef, pAuthMethod);
249 }
250 else
251 dsErr = eDSAllocationFailed;
252 dsCloseDirNode(hAuthNodeRef);
253 }
254
255 return dsErr;
256}
257
258RT_C_DECLS_BEGIN
259DECLEXPORT(FNAUTHENTRY3) AuthEntry;
260RT_C_DECLS_END
261
262DECLEXPORT(AuthResult) AUTHCALL AuthEntry(const char *pszCaller,
263 PAUTHUUID pUuid,
264 AuthGuestJudgement guestJudgement,
265 const char *pszUser,
266 const char *pszPassword,
267 const char *pszDomain,
268 int fLogon,
269 unsigned clientId)
270{
271 RT_NOREF(pszCaller, pUuid, guestJudgement, pszDomain, clientId);
272
273 /* Validate input */
274 AssertPtrReturn(pszUser, AuthResultAccessDenied);
275 AssertPtrReturn(pszPassword, AuthResultAccessDenied);
276
277 /* Result to a default value */
278 AuthResult result = AuthResultAccessDenied;
279
280 /* Only process logon requests. */
281 if (!fLogon)
282 return result; /* Return value is ignored by the caller. */
283
284 tDirStatus dsErr = eDSNoErr;
285 tDirStatus dsCleanErr = eDSNoErr;
286 tDirReference hDirRef = 0;
287 /* Connect to the Directory Service. */
288 dsErr = dsOpenDirService(&hDirRef);
289 if (dsErr == eDSNoErr)
290 {
291 /* Fetch the default search node */
292 tDataListPtr pSearchNodeList = NULL;
293 dsErr = defaultSearchNodePath(hDirRef, &pSearchNodeList);
294 if (dsErr == eDSNoErr)
295 {
296 /* Open the default search node */
297 tDirNodeReference hSearchNodeRef = 0;
298 dsErr = dsOpenDirNode(hDirRef, pSearchNodeList, &hSearchNodeRef);
299 if (dsErr == eDSNoErr)
300 {
301 /* Search for the user info, fetch the authentication node &
302 * the authentication user name. This allows the client to
303 * specify a long user name even if the name which is used to
304 * authenticate has the short form. */
305 tDataListPtr pAuthNodeList = NULL;
306 dsErr = userAuthInfo(hDirRef, hSearchNodeRef, pszUser, &pAuthNodeList);
307 if (dsErr == eDSNoErr)
308 {
309 /* Open the authentication node and do the authentication. */
310 dsErr = authWithNode(hDirRef, pAuthNodeList, pszUser, pszPassword);
311 if (dsErr == eDSNoErr)
312 result = AuthResultAccessGranted;
313 dsCleanErr = dsDataListDeallocate(hDirRef, pAuthNodeList);
314 if (dsCleanErr == eDSNoErr)
315 free(pAuthNodeList);
316 }
317 dsCloseDirNode(hSearchNodeRef);
318 }
319 dsCleanErr = dsDataListDeallocate(hDirRef, pSearchNodeList);
320 if (dsCleanErr == eDSNoErr)
321 free(pSearchNodeList);
322 }
323 dsCloseDirService(hDirRef);
324 }
325
326 return result;
327}
328
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette