]>
Commit | Line | Data |
---|---|---|
52b7d2ce A |
1 | /* |
2 | * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
23 | ||
24 | #include <CoreFoundation/CoreFoundation.h> | |
25 | ||
26 | #include <DirectoryService/DirServices.h> | |
27 | #include <DirectoryService/DirServicesUtils.h> | |
28 | #include <DirectoryService/DirServicesConst.h> | |
29 | #include <CoreFoundation/CFString.h> | |
30 | #include <SystemConfiguration/SystemConfiguration.h> | |
31 | ||
32 | #include "vmbuf.h" | |
33 | #include "remoteconf.h" | |
34 | #include "plog.h" | |
35 | #include "misc.h" | |
36 | #include "gcmalloc.h" | |
37 | #include "open_dir.h" | |
38 | ||
39 | #define BUF_LEN 1024 | |
40 | ||
41 | ||
42 | static tDirStatus open_dir_get_search_node_ref(tDirReference dirRef, unsigned long index, | |
43 | tDirNodeReference *searchNodeRef, unsigned long *count); | |
44 | static tDirStatus open_dir_get_user_attr(tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, | |
45 | char *attr, tAttributeValueEntryPtr *attr_value); | |
46 | static tDirStatus open_dir_check_group_membership(tDirReference dirRef, tDirNodeReference searchNodeRef, | |
47 | char *group_name, char *user_name, char *userGID, int *authorized); | |
48 | ||
49 | ||
50 | //---------------------------------------------------------------------- | |
51 | // open_dir_authorize_id | |
52 | //---------------------------------------------------------------------- | |
53 | int open_dir_authorize_id(vchar_t *id, vchar_t *group) | |
54 | { | |
55 | ||
56 | tDirReference dirRef; | |
57 | tDirStatus dsResult = eDSNoErr; | |
58 | int authorized = 0; | |
59 | tDirNodeReference searchNodeRef; | |
60 | tAttributeValueEntryPtr groupID = NULL; | |
61 | tAttributeValueEntryPtr recordName = NULL; | |
62 | unsigned long searchNodeCount; | |
63 | char* user_name = NULL; | |
64 | char* group_name = NULL; | |
65 | ||
66 | if (id == 0 || id->l < 1) { | |
67 | plog(LLV_ERROR, LOCATION, NULL, "invalid user name.\n"); | |
68 | goto end; | |
69 | } | |
70 | user_name = racoon_malloc(id->l + 1); | |
71 | if (user_name == NULL) { | |
72 | plog(LLV_ERROR, LOCATION, NULL, "out of memory - unable to allocate space for user name.\n"); | |
73 | goto end; | |
74 | } | |
75 | bcopy(id->v, user_name, id->l); | |
76 | *(user_name + id->l) = 0; | |
77 | ||
78 | if (group && group->l > 0) { | |
79 | group_name = racoon_malloc(group->l + 1); | |
80 | if (group_name == NULL) { | |
81 | plog(LLV_NOTIFY, LOCATION, NULL, "out of memeory - unable to allocate space for group name.\n"); | |
82 | goto end; | |
83 | } | |
84 | bcopy(group->v, group_name, group->l); | |
85 | *(group_name + group->l) = 0; | |
86 | } | |
87 | ||
88 | if ((dsResult = dsOpenDirService(&dirRef)) == eDSNoErr) { | |
89 | // get the search node ref | |
90 | if ((dsResult = open_dir_get_search_node_ref(dirRef, 1, &searchNodeRef, &searchNodeCount)) == eDSNoErr) { | |
91 | // get the user's primary group ID | |
92 | if (dsResult = open_dir_get_user_attr(dirRef, searchNodeRef, user_name, kDSNAttrRecordName, &recordName) == eDSNoErr) { | |
93 | if (recordName != 0) { | |
94 | if (group_name != 0) { | |
95 | if ((dsResult = open_dir_get_user_attr(dirRef, searchNodeRef, user_name, kDS1AttrPrimaryGroupID, &groupID)) == eDSNoErr) { | |
96 | // check if user is member of the group | |
97 | dsResult = open_dir_check_group_membership(dirRef, searchNodeRef, group_name, | |
98 | recordName->fAttributeValueData.fBufferData, groupID->fAttributeValueData.fBufferData, &authorized); | |
99 | } | |
100 | } else | |
101 | authorized = 1; // no group required - user record found | |
102 | } | |
103 | } | |
104 | if (groupID) | |
105 | dsDeallocAttributeValueEntry(dirRef, groupID); | |
106 | if (recordName) | |
107 | dsDeallocAttributeValueEntry(dirRef, recordName); | |
108 | dsCloseDirNode(searchNodeRef); // close the search node | |
109 | } | |
110 | dsCloseDirService(dirRef); | |
111 | } | |
112 | ||
113 | end: | |
114 | if (authorized) | |
115 | plog(LLV_NOTIFY, LOCATION, NULL, "User '%s' authorized for access\n", user_name); | |
116 | else | |
117 | plog(LLV_NOTIFY, LOCATION, NULL, "User '%s' not authorized for access\n", user_name); | |
118 | if (user_name) | |
119 | free(user_name); | |
120 | if (group_name) | |
121 | free(group_name); | |
122 | return authorized; | |
123 | } | |
124 | ||
125 | ||
126 | //---------------------------------------------------------------------- | |
127 | // open_dir_get_search_node_ref | |
128 | //---------------------------------------------------------------------- | |
129 | static tDirStatus open_dir_get_search_node_ref(tDirReference dirRef, unsigned long index, | |
130 | tDirNodeReference *searchNodeRef, unsigned long *count) | |
131 | { | |
132 | tDirStatus dsResult = -1; | |
133 | tDataBufferPtr searchNodeDataBufferPtr = 0; | |
134 | tDataListPtr searchNodeNameDataListPtr = 0; | |
135 | ||
136 | unsigned long outNodeCount; | |
137 | tContextData continueData = 0; | |
138 | ||
139 | *searchNodeRef = 0; | |
140 | *count = 0; | |
141 | ||
142 | // allocate required buffers and data lists | |
143 | if ((searchNodeDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) { | |
144 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); | |
145 | goto cleanup; | |
146 | } | |
147 | if ((searchNodeNameDataListPtr = dsDataListAllocate(dirRef)) == 0) { | |
148 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
149 | goto cleanup; | |
150 | } | |
151 | ||
152 | // find authentication search node(s) | |
153 | if ((dsResult = dsFindDirNodes(dirRef, searchNodeDataBufferPtr, 0, eDSAuthenticationSearchNodeName, | |
154 | &outNodeCount, &continueData)) == eDSNoErr) { | |
155 | if (outNodeCount != 0) { | |
156 | ||
157 | // get the seach node name and open the node | |
158 | if ((dsResult = dsGetDirNodeName(dirRef, searchNodeDataBufferPtr, index, | |
159 | &searchNodeNameDataListPtr)) == eDSNoErr) { | |
160 | if ((dsResult = dsOpenDirNode(dirRef, searchNodeNameDataListPtr, searchNodeRef)) == eDSNoErr) { | |
161 | *count = outNodeCount; | |
162 | } | |
163 | } | |
164 | } | |
165 | if (continueData) | |
166 | dsReleaseContinueData(dirRef, continueData); | |
167 | } | |
168 | ||
169 | cleanup: | |
170 | if (searchNodeDataBufferPtr) | |
171 | dsDataBufferDeAllocate(dirRef, searchNodeDataBufferPtr); | |
172 | if (searchNodeNameDataListPtr) | |
173 | dsDataListDeallocate(dirRef, searchNodeNameDataListPtr); | |
174 | ||
175 | return dsResult; | |
176 | } | |
177 | ||
178 | //---------------------------------------------------------------------- | |
179 | // open_dir_get_user_attr | |
180 | //---------------------------------------------------------------------- | |
181 | static tDirStatus open_dir_get_user_attr(tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, | |
182 | char *attr, tAttributeValueEntryPtr *attr_value) | |
183 | { | |
184 | ||
185 | tDirStatus dsResult = -1; | |
186 | ||
187 | tDataBufferPtr userRcdDataBufferPtr = 0; | |
188 | tDataListPtr recordNameDataListPtr = 0; | |
189 | tDataListPtr recordTypeDataListPtr = 0; | |
190 | tDataListPtr attrTypeDataListPtr = 0; | |
191 | tContextData continueData = 0; | |
192 | ||
193 | unsigned long outRecordCount; | |
194 | int userRcdFound = 0; | |
195 | u_int32_t userRecordIndex, attrIndex; | |
196 | ||
197 | *attr_value = 0; | |
198 | ||
199 | if ((userRcdDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) { | |
200 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); | |
201 | goto cleanup; | |
202 | } | |
203 | if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, user_name, 0)) == 0) { | |
204 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
205 | goto cleanup; | |
206 | } | |
207 | if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeUsers, 0)) == 0) { | |
208 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
209 | goto cleanup; | |
210 | } | |
211 | if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSNAttrRecordName, kDS1AttrDistinguishedName, attr, 0)) == 0) { | |
212 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
213 | goto cleanup; | |
214 | } | |
215 | ||
216 | // find the user record(s), extracting the user name and requested attribute | |
217 | do { | |
218 | dsResult = dsGetRecordList(searchNodeRef, userRcdDataBufferPtr, recordNameDataListPtr, eDSExact, | |
219 | recordTypeDataListPtr, attrTypeDataListPtr, 0, &outRecordCount, &continueData); | |
220 | ||
221 | // if buffer too small - allocate a larger one | |
222 | if (dsResult == eDSBufferTooSmall) { | |
223 | u_int32_t size = userRcdDataBufferPtr->fBufferSize * 2; | |
224 | ||
225 | dsDataBufferDeAllocate(dirRef, userRcdDataBufferPtr); | |
226 | if ((userRcdDataBufferPtr = dsDataBufferAllocate(dirRef, size)) == 0) { | |
227 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); | |
228 | dsResult = -1; | |
229 | goto cleanup; | |
230 | } | |
231 | } | |
232 | } while (dsResult == eDSBufferTooSmall); | |
233 | ||
234 | if (dsResult == eDSNoErr) { | |
235 | // for each user record | |
236 | for (userRecordIndex = 1; (userRecordIndex <= outRecordCount) && (dsResult == eDSNoErr) | |
237 | && (userRcdFound == 0); userRecordIndex++) { | |
238 | ||
239 | tAttributeListRef attrListRef; | |
240 | tRecordEntryPtr userRcdEntryPtr; | |
241 | ||
242 | // get the user record entry from the data buffer | |
243 | if ((dsResult = dsGetRecordEntry(searchNodeRef, userRcdDataBufferPtr, userRecordIndex, | |
244 | &attrListRef, &userRcdEntryPtr)) == eDSNoErr) { | |
245 | // for each attribute | |
246 | for (attrIndex = 1; (attrIndex <= userRcdEntryPtr->fRecordAttributeCount) | |
247 | && (dsResult == eDSNoErr); attrIndex++) { | |
248 | ||
249 | tAttributeValueListRef attrValueListRef; | |
250 | tAttributeEntryPtr attrInfoPtr; | |
251 | tAttributeValueEntryPtr attrValuePtr; | |
252 | ||
253 | if ((dsResult = dsGetAttributeEntry(searchNodeRef, userRcdDataBufferPtr, | |
254 | attrListRef, attrIndex, &attrValueListRef, &attrInfoPtr)) == eDSNoErr) { | |
255 | if ((dsResult = dsGetAttributeValue(searchNodeRef, userRcdDataBufferPtr, 1, | |
256 | attrValueListRef, &attrValuePtr)) == eDSNoErr) { | |
257 | ||
258 | // check for user record name or attribute searching for | |
259 | if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDSNAttrRecordName)) { | |
260 | if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) | |
261 | userRcdFound = 1; | |
262 | } | |
263 | if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDS1AttrDistinguishedName)) { | |
264 | if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) | |
265 | userRcdFound = 1; | |
266 | } | |
267 | if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, attr)) { | |
268 | *attr_value = attrValuePtr; // return the attribute value | |
269 | attrValuePtr = 0; // set to zero so we don't deallocate it | |
270 | } | |
271 | if (attrValuePtr) | |
272 | dsDeallocAttributeValueEntry(dirRef, attrValuePtr); | |
273 | } | |
274 | dsCloseAttributeValueList(attrValueListRef); | |
275 | dsDeallocAttributeEntry(dirRef, attrInfoPtr); | |
276 | } | |
277 | } | |
278 | // make sure we've processed both attributes and we have a match on user name | |
279 | if(userRcdFound == 0 || *attr_value == 0) { | |
280 | userRcdFound = 0; | |
281 | if (*attr_value) | |
282 | dsDeallocAttributeValueEntry(dirRef, *attr_value); | |
283 | *attr_value = 0; | |
284 | } | |
285 | dsCloseAttributeList(attrListRef); | |
286 | dsDeallocRecordEntry(dirRef, userRcdEntryPtr); | |
287 | } | |
288 | } | |
289 | } | |
290 | ||
291 | cleanup: | |
292 | if (continueData) | |
293 | dsReleaseContinueData(searchNodeRef, continueData); | |
294 | if (userRcdDataBufferPtr) | |
295 | dsDataBufferDeAllocate(dirRef, userRcdDataBufferPtr); | |
296 | if (recordNameDataListPtr) | |
297 | dsDataListDeallocate(dirRef, recordNameDataListPtr); | |
298 | if (recordTypeDataListPtr) | |
299 | dsDataListDeallocate(dirRef, recordTypeDataListPtr); | |
300 | if (attrTypeDataListPtr) | |
301 | dsDataListDeallocate(dirRef, attrTypeDataListPtr); | |
302 | ||
303 | return dsResult; | |
304 | ||
305 | } | |
306 | ||
307 | ||
308 | //---------------------------------------------------------------------- | |
309 | // open_dir_check_group_membership | |
310 | //---------------------------------------------------------------------- | |
311 | static tDirStatus open_dir_check_group_membership(tDirReference dirRef, tDirNodeReference searchNodeRef, | |
312 | char *group_name, char *user_name, char *userGID, int *authorized) | |
313 | { | |
314 | tDirStatus dsResult = -1; | |
315 | ||
316 | tDataBufferPtr groupRcdDataBufferPtr = 0; | |
317 | tDataListPtr recordNameDataListPtr = 0; | |
318 | tDataListPtr recordTypeDataListPtr = 0; | |
319 | tDataListPtr attrTypeDataListPtr = 0; | |
320 | tContextData continueData = 0; | |
321 | ||
322 | unsigned long outRecordCount; | |
323 | u_int32_t attrIndex, valueIndex; | |
324 | ||
325 | *authorized = 0; | |
326 | ||
327 | if ((groupRcdDataBufferPtr = dsDataBufferAllocate(dirRef, BUF_LEN)) == 0) { | |
328 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); | |
329 | goto cleanup; | |
330 | } | |
331 | if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, group_name, 0)) == 0) { | |
332 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
333 | goto cleanup; | |
334 | } | |
335 | if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeGroups, 0)) == 0) { | |
336 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
337 | goto cleanup; | |
338 | } | |
339 | if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDS1AttrPrimaryGroupID, kDSNAttrGroupMembership, 0)) == 0) { | |
340 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataList\n"); | |
341 | goto cleanup; | |
342 | } | |
343 | ||
344 | // find the group record, extracting the group ID and group membership attribute | |
345 | do { | |
346 | dsResult = dsGetRecordList(searchNodeRef, groupRcdDataBufferPtr, recordNameDataListPtr, eDSExact, | |
347 | recordTypeDataListPtr, attrTypeDataListPtr, 0, &outRecordCount, &continueData); | |
348 | // if buffer too small - allocate a larger one | |
349 | if (dsResult == eDSBufferTooSmall) { | |
350 | u_int32_t size = groupRcdDataBufferPtr->fBufferSize * 2; | |
351 | ||
352 | dsDataBufferDeAllocate(dirRef, groupRcdDataBufferPtr); | |
353 | if ((groupRcdDataBufferPtr = dsDataBufferAllocate(dirRef, size)) == 0) { | |
354 | plog(LLV_ERROR, LOCATION, NULL, "Could not allocate tDataBuffer\n"); | |
355 | dsResult = -1; | |
356 | goto cleanup; | |
357 | } | |
358 | } | |
359 | } while (dsResult == eDSBufferTooSmall); | |
360 | ||
361 | if (dsResult == eDSNoErr) { | |
362 | ||
363 | tAttributeListRef attrListRef; | |
364 | tRecordEntryPtr groupRcdEntryPtr; | |
365 | ||
366 | // get the group record entry | |
367 | if ((dsResult = dsGetRecordEntry(searchNodeRef, groupRcdDataBufferPtr, 1, &attrListRef, &groupRcdEntryPtr)) == eDSNoErr) { | |
368 | ||
369 | // for each attribute | |
370 | for (attrIndex = 1; (attrIndex <= groupRcdEntryPtr->fRecordAttributeCount) && (dsResult == eDSNoErr) | |
371 | && (*authorized == 0); attrIndex++) { | |
372 | ||
373 | tAttributeValueListRef attrValueListRef; | |
374 | tAttributeEntryPtr attrInfoPtr; | |
375 | tAttributeValueEntryPtr attrValuePtr; | |
376 | ||
377 | if ((dsResult = dsGetAttributeEntry(searchNodeRef, groupRcdDataBufferPtr, attrListRef, | |
378 | attrIndex, &attrValueListRef, &attrInfoPtr)) == eDSNoErr) { | |
379 | ||
380 | // group ID attribute ? | |
381 | if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDS1AttrPrimaryGroupID)) { | |
382 | if ((dsResult = dsGetAttributeValue(searchNodeRef, groupRcdDataBufferPtr, 1, | |
383 | attrValueListRef, &attrValuePtr)) == eDSNoErr) { | |
384 | ||
385 | // check for match on primary group ID | |
386 | if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, userGID)) | |
387 | *authorized = 1; | |
388 | dsDeallocAttributeValueEntry(dirRef, attrValuePtr); | |
389 | } | |
390 | } else if (!strcmp(attrInfoPtr->fAttributeSignature.fBufferData, kDSNAttrGroupMembership)) { | |
391 | // for each value check for user's name in the group | |
392 | for (valueIndex = 1; (valueIndex <= attrInfoPtr->fAttributeValueCount) | |
393 | && (dsResult == eDSNoErr) && (*authorized == 0); valueIndex++) { | |
394 | ||
395 | if ((dsResult = dsGetAttributeValue(searchNodeRef, groupRcdDataBufferPtr, | |
396 | valueIndex, attrValueListRef, &attrValuePtr)) == eDSNoErr) { | |
397 | if (!strcmp(attrValuePtr->fAttributeValueData.fBufferData, user_name)) | |
398 | *authorized = 1; | |
399 | dsDeallocAttributeValueEntry(dirRef, attrValuePtr); | |
400 | } | |
401 | } | |
402 | } | |
403 | dsCloseAttributeValueList(attrValueListRef); | |
404 | dsDeallocAttributeEntry(dirRef, attrInfoPtr); | |
405 | } | |
406 | } | |
407 | dsCloseAttributeList(attrListRef); | |
408 | dsDeallocRecordEntry(dirRef, groupRcdEntryPtr); | |
409 | } | |
410 | } | |
411 | ||
412 | cleanup: | |
413 | if (continueData) | |
414 | dsReleaseContinueData(searchNodeRef, continueData); | |
415 | if (groupRcdDataBufferPtr) | |
416 | dsDataBufferDeAllocate(dirRef, groupRcdDataBufferPtr); | |
417 | if (recordNameDataListPtr) | |
418 | dsDataListDeallocate(dirRef, recordNameDataListPtr); | |
419 | if (recordTypeDataListPtr) | |
420 | dsDataListDeallocate(dirRef, recordTypeDataListPtr); | |
421 | if (attrTypeDataListPtr) | |
422 | dsDataListDeallocate(dirRef, attrTypeDataListPtr); | |
423 | ||
424 | return dsResult; | |
425 | } | |
426 |