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 42static tDirStatus open_dir_get_search_node_ref (tDirReference dirRef, unsigned long index, 43 tDirNodeReference *searchNodeRef, unsigned long *count); 44static tDirStatus open_dir_get_user_attr (tDirReference dirRef, tDirNodeReference searchNodeRef, char *user_name, 45 char *attr, tAttributeValueEntryPtr *attr_value); 46static 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//---------------------------------------------------------------------- 53int 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(ASL_LEVEL_ERR, "invalid user name.\n"); 68 goto end; 69 } 70 user_name = racoon_malloc(id->l + 1); 71 if (user_name == NULL) { 72 plog(ASL_LEVEL_ERR, "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(ASL_LEVEL_ERR, "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 113end: 114 if (authorized) 115 plog(ASL_LEVEL_NOTICE, "User '%s' authorized for access\n", user_name); 116 else 117 plog(ASL_LEVEL_NOTICE, "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//---------------------------------------------------------------------- 129static 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(ASL_LEVEL_ERR, "Could not allocate tDataBuffer\n"); 145 goto cleanup; 146 } 147 if ((searchNodeNameDataListPtr = dsDataListAllocate(dirRef)) == 0) { 148 plog(ASL_LEVEL_ERR, "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 (UInt32*)&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 169cleanup: 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//---------------------------------------------------------------------- 181static 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(ASL_LEVEL_ERR, "Could not allocate tDataBuffer\n"); 201 goto cleanup; 202 } 203 if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, user_name, 0)) == 0) { 204 plog(ASL_LEVEL_ERR, "Could not allocate tDataList\n"); 205 goto cleanup; 206 } 207 if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeUsers, 0)) == 0) { 208 plog(ASL_LEVEL_ERR, "Could not allocate tDataList\n"); 209 goto cleanup; 210 } 211 if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSNAttrRecordName, kDS1AttrDistinguishedName, attr, 0)) == 0) { 212 plog(ASL_LEVEL_ERR, "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, (UInt32*)&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(ASL_LEVEL_ERR, "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 291cleanup: 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//---------------------------------------------------------------------- 311static 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(ASL_LEVEL_ERR, "Could not allocate tDataBuffer\n"); 329 goto cleanup; 330 } 331 if ((recordNameDataListPtr = dsBuildListFromStrings(dirRef, group_name, 0)) == 0) { 332 plog(ASL_LEVEL_ERR, "Could not allocate tDataList\n"); 333 goto cleanup; 334 } 335 if ((recordTypeDataListPtr = dsBuildListFromStrings(dirRef, kDSStdRecordTypeGroups, 0)) == 0) { 336 plog(ASL_LEVEL_ERR, "Could not allocate tDataList\n"); 337 goto cleanup; 338 } 339 if ((attrTypeDataListPtr = dsBuildListFromStrings(dirRef, kDS1AttrPrimaryGroupID, kDSNAttrGroupMembership, 0)) == 0) { 340 plog(ASL_LEVEL_ERR, "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, (UInt32*)&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(ASL_LEVEL_ERR, "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 412cleanup: 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 427