1#include <asl.h> 2#include <stdio.h> 3#include <unistd.h> 4#include <sys/stat.h> 5 6#include <security/pam_appl.h> 7#include <security/pam_modules.h> 8#include <security/openpam.h> 9 10 11#include <CoreFoundation/CoreFoundation.h> 12#include <DirectoryService/DirectoryService.h> 13#include <OpenDirectory/OpenDirectory.h> 14#include <OpenDirectory/OpenDirectoryPriv.h> 15#include <ServerInformation/ServerInformation.h> 16 17#include "Common.h" 18 19#if !defined(kDSValueAuthAuthorityDisabledUser) 20#define kDSValueAuthAuthorityDisabledUser ";DisabledUser;" 21#endif 22 23#define kOSInstall_mpkg "/System/Installation/Packages/OSInstall.mpkg" 24#define kOSInstall_collection "/System/Installation/Packages/OSInstall.collection" 25 26enum { 27 kWaitSeconds = 1, 28 kMaxIterationCount = 30 29}; 30 31int 32cfboolean_get_value(CFTypeRef p) 33{ 34 int value = 0; 35 int retval = 0; 36 37 if (NULL == p) { 38 goto cleanup; 39 } 40 41 if (CFBooleanGetTypeID() == CFGetTypeID(p)) 42 retval = CFBooleanGetValue(p); 43 else if (CFNumberGetTypeID() == CFGetTypeID(p) && CFNumberGetValue(p, kCFNumberIntType, &value)) 44 retval = value; 45 else 46 retval = 0; 47 48cleanup: 49 if (PAM_SUCCESS != retval) 50 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 51 52 return retval; 53} 54 55int 56cstring_to_cfstring(const char *val, CFStringRef *buffer) 57{ 58 int retval = PAM_BUF_ERR; 59 60 if (NULL == val || NULL == buffer) { 61 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 62 retval = PAM_SERVICE_ERR; 63 goto cleanup; 64 } 65 66 *buffer = CFStringCreateWithCString(kCFAllocatorDefault, val, kCFStringEncodingUTF8); 67 if (NULL == *buffer) { 68 openpam_log(PAM_LOG_DEBUG, "CFStringCreateWithCString() failed"); 69 retval = PAM_BUF_ERR; 70 goto cleanup; 71 } 72 73 retval = PAM_SUCCESS; 74 75cleanup: 76 if (PAM_SUCCESS != retval) 77 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 78 79 return retval; 80} 81 82int 83cfstring_to_cstring(const CFStringRef val, char **buffer) 84{ 85 CFIndex maxlen = 0; 86 int retval = PAM_BUF_ERR; 87 88 if (NULL == val || NULL == buffer) { 89 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 90 retval = PAM_SERVICE_ERR; 91 goto cleanup; 92 } 93 94 maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(val), kCFStringEncodingUTF8); 95 *buffer = calloc(maxlen + 1, sizeof(char)); 96 if (NULL == *buffer) { 97 openpam_log(PAM_LOG_DEBUG, "malloc() failed"); 98 retval = PAM_BUF_ERR; 99 goto cleanup; 100 } 101 102 if (CFStringGetCString(val, *buffer, maxlen + 1, kCFStringEncodingUTF8)) { 103 retval = PAM_SUCCESS; 104 } else { 105 openpam_log(PAM_LOG_DEBUG, "CFStringGetCString failed."); 106 free(*buffer); 107 *buffer = NULL; 108 } 109 110cleanup: 111 if (PAM_SUCCESS != retval) 112 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 113 114 return retval; 115} 116 117#ifdef OPENDIRECTORY_CACHE 118static void 119cleanup_cache(pam_handle_t *pamh, void *data, int pam_end_status) 120{ 121 CFRelease((CFTypeRef)data); 122} 123#endif /* OPENDIRECTORY_CACHE */ 124 125int 126od_record_create(pam_handle_t *pamh, ODRecordRef *record, CFStringRef cfUser) 127{ 128 int retval = PAM_SERVICE_ERR; 129 const int attr_num = 5; 130 131 ODNodeRef cfNode = NULL; 132 CFErrorRef cferror = NULL; 133 CFArrayRef attrs = NULL; 134 CFTypeRef cfVals[attr_num]; 135 136 if (NULL == record || NULL == cfUser) { 137 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 138 retval = PAM_SERVICE_ERR; 139 goto cleanup; 140 } 141 142#ifdef OPENDIRECTORY_CACHE 143#define CFRECORDNAME_CACHE "CFRecordName" 144#define CFRECORDNAME_NAME CFSTR("name") 145#define CFRECORDNAME_RECORD CFSTR("record") 146 147 CFDictionaryRef cfdict; 148 CFStringRef cachedUser; 149 150 if (pam_get_data(pamh, CFRECORDNAME_CACHE, (void *)&cfdict) == PAM_SUCCESS && 151 (CFGetTypeID(cfdict) == CFDictionaryGetTypeID()) && 152 (cachedUser = CFDictionaryGetValue(cfdict, CFRECORDNAME_NAME)) != NULL && 153 CFGetTypeID(cachedUser) == CFStringGetTypeID() && 154 CFStringCompare(cfUser, cachedUser, 0) == kCFCompareEqualTo && 155 (*record = (ODRecordRef)CFDictionaryGetValue(cfdict, CFRECORDNAME_RECORD)) != NULL) 156 { 157 CFRetain(*record); 158 return PAM_SUCCESS; 159 } 160#endif /* OPENDIRECTORY_CACHE */ 161 162 int current_iterations = 0; 163 164 cfNode = ODNodeCreateWithNodeType(kCFAllocatorDefault, 165 kODSessionDefault, 166 eDSAuthenticationSearchNodeName, 167 &cferror); 168 if (NULL == cfNode || NULL != cferror) { 169 openpam_log(PAM_LOG_ERROR, "ODNodeCreateWithNodeType failed."); 170 retval = PAM_SERVICE_ERR; 171 goto cleanup; 172 } 173 174 cfVals[0] = kODAttributeTypeAuthenticationAuthority; 175 cfVals[1] = kODAttributeTypeHomeDirectory; 176 cfVals[2] = kODAttributeTypeNFSHomeDirectory; 177 cfVals[3] = kODAttributeTypeUserShell; 178 cfVals[4] = kODAttributeTypeUniqueID; 179 attrs = CFArrayCreate(kCFAllocatorDefault, cfVals, (CFIndex)attr_num, &kCFTypeArrayCallBacks); 180 if (NULL == attrs) { 181 openpam_log(PAM_LOG_DEBUG, "CFArrayCreate() failed"); 182 retval = PAM_BUF_ERR; 183 goto cleanup; 184 } 185 186 retval = PAM_SERVICE_ERR; 187 while (current_iterations <= kMaxIterationCount) { 188 CFIndex unreachable_count = 0; 189 CFArrayRef unreachable_nodes = ODNodeCopyUnreachableSubnodeNames(cfNode, NULL); 190 if (unreachable_nodes) { 191 unreachable_count = CFArrayGetCount(unreachable_nodes); 192 CFRelease(unreachable_nodes); 193 openpam_log(PAM_LOG_DEBUG, "%lu OD nodes unreachable.", unreachable_count); 194 } 195 196 *record = ODNodeCopyRecord(cfNode, kODRecordTypeUsers, cfUser, attrs, &cferror); 197 if (*record) 198 break; 199 if (0 == unreachable_count) 200 break; 201 202 openpam_log(PAM_LOG_DEBUG, "Waiting %d seconds for nodes to become reachable", kWaitSeconds); 203 sleep(kWaitSeconds); 204 ++current_iterations; 205 } 206 207 if (*record) { 208#ifdef OPENDIRECTORY_CACHE 209 const void *keys[] = { CFRECORDNAME_NAME, CFRECORDNAME_RECORD }; 210 const void *values[] = { cfUser, *record }; 211 CFDictionaryRef dict; 212 213 dict = CFDictionaryCreate(NULL, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 214 if (dict) 215 pam_set_data(pamh, CFRECORDNAME_CACHE, (void *)dict, cleanup_cache); 216#endif /* OPENDIRECTORY_CACHE */ 217 retval = PAM_SUCCESS; 218 } else { 219 retval = PAM_USER_UNKNOWN; 220 } 221 222 if (current_iterations > 0) { 223 char *wt = NULL, *found = NULL; 224 int retval2; 225 226 if (*record) 227 found = "failure"; 228 else 229 found = "success"; 230 231 retval2 = asprintf(&wt, "%d", kWaitSeconds * current_iterations); 232 if (-1 == retval2) { 233 openpam_log(PAM_LOG_DEBUG, "Failed to convert current wait time to string."); 234 retval = PAM_BUF_ERR; 235 goto cleanup; 236 } 237 238 239 aslmsg m = asl_new(ASL_TYPE_MSG); 240 asl_set(m, "com.apple.message.domain", "com.apple.pam_modules.odAvailableWaitTime" ); 241 asl_set(m, "com.apple.message.signature", "wait_time"); 242 asl_set(m, "com.apple.message.value", wt); 243 asl_set(m, "com.apple.message.result", found); 244 asl_log(NULL, m, ASL_LEVEL_NOTICE, "OD nodes online delay: %ss. User record lookup: %s.", wt, found); 245 asl_free(m); 246 free(wt); 247 } 248 249cleanup: 250 if (NULL != attrs) { 251 CFRelease(attrs); 252 } 253 254 if (NULL != cferror) { 255 CFRelease(cferror); 256 } 257 258 if (NULL != cfNode) { 259 CFRelease(cfNode); 260 } 261 262 if (PAM_SUCCESS != retval) { 263 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 264 if (NULL != *record) { 265 CFRelease(*record); 266 *record = NULL; 267 } 268 } 269 270 return retval; 271} 272 273int 274od_record_create_cstring(pam_handle_t *pamh, ODRecordRef *record, const char *user) 275{ 276 int retval = PAM_SUCCESS; 277 CFStringRef cfUser = NULL; 278 279 if (NULL == record || NULL == user) { 280 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 281 retval = PAM_SERVICE_ERR; 282 goto cleanup; 283 } 284 285 if (PAM_SUCCESS != (retval = cstring_to_cfstring(user, &cfUser)) || 286 PAM_SUCCESS != (retval = od_record_create(pamh, record, cfUser))) { 287 openpam_log(PAM_LOG_DEBUG, "od_record_create() failed"); 288 goto cleanup; 289 } 290 291cleanup: 292 if (PAM_SUCCESS != retval) { 293 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 294 if (NULL != *record) { 295 CFRelease(*record); 296 } 297 } 298 299 if (NULL != cfUser) { 300 CFRelease(cfUser); 301 } 302 303 return retval; 304} 305 306/* Can return NULL */ 307int 308od_record_attribute_create_cfarray(ODRecordRef record, CFStringRef attrib, CFArrayRef *out) 309{ 310 int retval = PAM_SUCCESS; 311 312 if (NULL == record || NULL == attrib || NULL == out) { 313 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 314 retval = PAM_SERVICE_ERR; 315 goto cleanup; 316 } 317 318 *out = ODRecordCopyValues(record, attrib, NULL); 319 320cleanup: 321 if (PAM_SUCCESS != retval) { 322 if (NULL != out) { 323 CFRelease(out); 324 } 325 } 326 return retval; 327} 328 329/* Can return NULL */ 330int 331od_record_attribute_create_cfstring(ODRecordRef record, CFStringRef attrib, CFStringRef *out) 332{ 333 int retval = PAM_SERVICE_ERR; 334 CFTypeRef cval = NULL; 335 CFArrayRef vals = NULL; 336 CFIndex i = 0, count = 0; 337 338 if (NULL == record || NULL == attrib || NULL == out) { 339 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 340 retval = PAM_SERVICE_ERR; 341 goto cleanup; 342 } 343 344 *out = NULL; 345 retval = od_record_attribute_create_cfarray(record, attrib, &vals); 346 if (PAM_SUCCESS != retval) { 347 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfarray() failed"); 348 goto cleanup; 349 } 350 if (NULL == vals) { 351 retval = PAM_SUCCESS; 352 goto cleanup; 353 } 354 355 count = CFArrayGetCount(vals); 356 if (1 != count) { 357 char *attr_cstr = NULL; 358 cfstring_to_cstring(attrib, &attr_cstr); 359 openpam_log(PAM_LOG_DEBUG, "returned %lx attributes for %s", count, attr_cstr); 360 free(attr_cstr); 361 } 362 363 for (i = 0; i < count; ++i) { 364 cval = CFArrayGetValueAtIndex(vals, i); 365 if (NULL == cval) { 366 continue; 367 } 368 if (CFGetTypeID(cval) == CFStringGetTypeID()) { 369 *out = CFStringCreateCopy(kCFAllocatorDefault, cval); 370 if (NULL == *out) { 371 openpam_log(PAM_LOG_DEBUG, "CFStringCreateCopy() failed"); 372 retval = PAM_BUF_ERR; 373 goto cleanup; 374 } 375 break; 376 } else { 377 openpam_log(PAM_LOG_DEBUG, "attribute is not a cfstring"); 378 retval = PAM_PERM_DENIED; 379 goto cleanup; 380 } 381 } 382 retval = PAM_SUCCESS; 383 384cleanup: 385 if (PAM_SUCCESS != retval) { 386 if (NULL != out) { 387 CFRelease(out); 388 } 389 } 390 if (NULL != vals) { 391 CFRelease(vals); 392 } 393 394 return retval; 395} 396 397/* Can return NULL */ 398int 399od_record_attribute_create_cstring(ODRecordRef record, CFStringRef attrib, char **out) 400{ 401 int retval = PAM_SERVICE_ERR; 402 CFStringRef val = NULL; 403 404 if (NULL == record || NULL == attrib || NULL == out) { 405 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 406 retval = PAM_SERVICE_ERR; 407 goto cleanup; 408 } 409 410 retval = od_record_attribute_create_cfstring(record, attrib, &val); 411 if (PAM_SUCCESS != retval) { 412 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); 413 goto cleanup; 414 } 415 416 if (NULL != val) { 417 retval = cfstring_to_cstring(val, out); 418 if (PAM_SUCCESS != retval) { 419 openpam_log(PAM_LOG_DEBUG, "cfstring_to_cstring() failed"); 420 goto cleanup; 421 } 422 } 423 424cleanup: 425 if (PAM_SUCCESS != retval) { 426 free(out); 427 } 428 429 if (NULL != val) { 430 CFRelease(val); 431 } 432 433 return retval; 434} 435 436int 437od_record_check_pwpolicy(ODRecordRef record) 438{ 439 CFErrorRef oderror = NULL; 440 int retval = PAM_SERVICE_ERR; 441 442 if (NULL == record) { 443 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 444 retval = PAM_SERVICE_ERR; 445 goto cleanup; 446 } 447 448 if (!ODRecordAuthenticationAllowed(record, &oderror)) { 449 switch (CFErrorGetCode(oderror)) { 450 case kODErrorCredentialsAccountNotFound: 451 retval = PAM_USER_UNKNOWN; 452 break; 453 case kODErrorCredentialsAccountDisabled: 454 case kODErrorCredentialsAccountInactive: 455 retval = PAM_PERM_DENIED; 456 break; 457 case kODErrorCredentialsPasswordExpired: 458 case kODErrorCredentialsPasswordChangeRequired: 459 retval = PAM_NEW_AUTHTOK_REQD; 460 break; 461 case kODErrorCredentialsInvalid: 462 retval = PAM_AUTH_ERR; 463 break; 464 default: 465 retval = PAM_AUTH_ERR; 466 break; 467 } 468 469 } else { 470 retval = PAM_SUCCESS; 471 } 472 473cleanup: 474 openpam_log(PAM_LOG_DEBUG, "retval: %d", retval); 475 return retval; 476} 477 478int 479od_record_check_authauthority(ODRecordRef record) 480{ 481 int retval = PAM_PERM_DENIED; 482 CFStringRef authauth = NULL; 483 484 if (NULL == record) { 485 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 486 retval = PAM_SERVICE_ERR; 487 goto cleanup; 488 } 489 490 retval = od_record_attribute_create_cfstring(record, kODAttributeTypeAuthenticationAuthority, &authauth); 491 if (PAM_SUCCESS != retval) { 492 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); 493 goto cleanup; 494 } 495 if (NULL == authauth) { 496 retval = PAM_SUCCESS; 497 goto cleanup; 498 } 499 if (!CFStringHasPrefix(authauth, CFSTR(kDSValueAuthAuthorityDisabledUser))) { 500 retval = PAM_SUCCESS; 501 } 502 503cleanup: 504 if (PAM_SUCCESS != retval) { 505 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 506 } 507 508 if (authauth) { 509 CFRelease(authauth); 510 } 511 512 return retval; 513} 514 515int 516od_record_check_homedir(ODRecordRef record) 517{ 518 int retval = PAM_SERVICE_ERR; 519 CFStringRef tmp = NULL; 520 521 if (NULL == record) { 522 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 523 retval = PAM_SERVICE_ERR; 524 goto cleanup; 525 } 526 527 retval = od_record_attribute_create_cfstring(record, kODAttributeTypeNFSHomeDirectory, &tmp); 528 if (PAM_SUCCESS != retval) { 529 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); 530 goto cleanup; 531 } 532 533 /* Allow NULL home directories */ 534 if (NULL == tmp) { 535 retval = PAM_SUCCESS; 536 goto cleanup; 537 } 538 539 /* Do not allow login with '/dev/null' home */ 540 if (kCFCompareEqualTo == CFStringCompare(tmp, CFSTR("/dev/null"), 0)) { 541 openpam_log(PAM_LOG_DEBUG, "home directory is /dev/null"); 542 retval = PAM_PERM_DENIED; 543 goto cleanup; 544 } 545 546 if (kCFCompareEqualTo == CFStringCompare(tmp, CFSTR("99"), 0)) { 547 openpam_log(PAM_LOG_DEBUG, "home directory is 99"); 548 retval = PAM_PERM_DENIED; 549 goto cleanup; 550 } 551 552 retval = PAM_SUCCESS; 553 554cleanup: 555 if (PAM_SUCCESS != retval) 556 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 557 558 if (NULL != tmp) { 559 CFRelease(tmp); 560 } 561 562 return retval; 563} 564 565int 566od_record_check_shell(ODRecordRef record) 567{ 568 int retval = PAM_PERM_DENIED; 569 CFStringRef cfstr = NULL; 570 571 if (NULL == record) { 572 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 573 retval = PAM_SERVICE_ERR; 574 goto cleanup; 575 } 576 577 retval = od_record_attribute_create_cfstring(record, kODAttributeTypeUserShell, &cfstr); 578 if (PAM_SUCCESS != retval) { 579 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); 580 goto cleanup; 581 } 582 583 if (NULL == cfstr) { 584 retval = PAM_SUCCESS; 585 goto cleanup; 586 } 587 588 if (CFStringCompare(cfstr, CFSTR("/usr/bin/false"), 0) == kCFCompareEqualTo) { 589 openpam_log(PAM_LOG_DEBUG, "user shell is /bin/false"); 590 retval = PAM_PERM_DENIED; 591 } 592 593cleanup: 594 if (PAM_SUCCESS != retval) 595 openpam_log(PAM_LOG_ERROR, "failed: %d", retval); 596 597 if (NULL != cfstr) { 598 CFRelease(cfstr); 599 } 600 601 return retval; 602} 603 604int 605od_string_from_record(ODRecordRef record, CFStringRef attrib, char **out) 606{ 607 int retval = PAM_SERVICE_ERR; 608 CFStringRef val = NULL; 609 610 if (NULL == record) { 611 openpam_log(PAM_LOG_DEBUG, "%s - NULL ODRecord passed.", __func__); 612 goto cleanup; 613 } 614 615 retval = od_record_attribute_create_cfstring(record, attrib, &val); 616 if (PAM_SUCCESS != retval) { 617 goto cleanup; 618 } 619 620 if (val) 621 retval = cfstring_to_cstring(val, out); 622 623cleanup: 624 if (val) 625 CFRelease(val); 626 627 return retval; 628} 629 630int 631extract_homemount(char *in, char **out_url, char **out_path) 632{ 633 // Directory Services people have assured me that this won't change 634 static const char URL_OPEN[] = "<url>"; 635 static const char URL_CLOSE[] = "</url>"; 636 static const char PATH_OPEN[] = "<path>"; 637 static const char PATH_CLOSE[] = "</path>"; 638 639 char *server_URL = NULL; 640 char *path = NULL; 641 char *record_start = NULL; 642 char *record_end = NULL; 643 644 int retval = PAM_SERVICE_ERR; 645 646 if (NULL == in) 647 goto fin; 648 649 record_start = in; 650 server_URL = strstr(record_start, URL_OPEN); 651 if (NULL == server_URL) 652 goto fin; 653 server_URL += sizeof(URL_OPEN)-1; 654 while ('\0' != *server_URL && isspace(*server_URL)) 655 server_URL++; 656 record_end = strstr(server_URL, URL_CLOSE); 657 if (NULL == record_end) 658 goto fin; 659 while (record_end >= server_URL && '\0' != *record_end && isspace(*(record_end-1))) 660 record_end--; 661 if (NULL == record_end) 662 goto fin; 663 *record_end = '\0'; 664 if (NULL == (*out_url = strdup(server_URL))) 665 goto fin; 666 667 record_start = record_end+1; 668 path = strstr(record_start, PATH_OPEN); 669 if (NULL == path) 670 goto ok; 671 path += sizeof(PATH_OPEN)-1; 672 while ('\0' != *path && isspace(*path)) 673 path++; 674 record_end = strstr(path, PATH_CLOSE); 675 if (NULL == record_end) 676 goto fin; 677 while (record_end >= path && '\0' != *record_end && isspace(*(record_end-1))) 678 record_end--; 679 if (NULL == record_end) 680 goto fin; 681 *record_end = '\0'; 682 if (NULL == (*out_path = strdup(path))) 683 goto fin; 684 685ok: 686 retval = PAM_SUCCESS; 687fin: 688 return retval; 689} 690 691int 692od_extract_home(pam_handle_t *pamh, const char *username, char **server_URL, char **path, char **homedir) 693{ 694 int retval = PAM_SERVICE_ERR; 695 char *tmp = NULL; 696 ODRecordRef record = NULL; 697 698 retval = od_record_create_cstring(pamh, &record, username); 699 if (PAM_SUCCESS != retval) { 700 goto cleanup; 701 } 702 703 retval = od_string_from_record(record, kODAttributeTypeHomeDirectory, &tmp); 704 if (retval) { 705 openpam_log(PAM_LOG_DEBUG, "%s - get kODAttributeTypeHomeDirectory : %d", 706 __func__, retval); 707 goto cleanup; 708 } 709 extract_homemount(tmp, server_URL, path); 710 openpam_log(PAM_LOG_DEBUG, "%s - Server URL : %s", __func__, *server_URL); 711 openpam_log(PAM_LOG_DEBUG, "%s - Path to mount: %s", __func__, *path); 712 713 retval = od_string_from_record(record, kODAttributeTypeNFSHomeDirectory, homedir); 714 openpam_log(PAM_LOG_DEBUG, "%s - Home dir : %s", __func__, *homedir); 715 if (retval) 716 goto cleanup; 717 718 retval = PAM_SUCCESS; 719 720cleanup: 721 if (tmp) 722 free(tmp); 723 if (record) 724 CFRelease(record); 725 726 return retval; 727} 728 729/* extract the principal from OpenDirectory */ 730int 731od_principal_for_user(pam_handle_t *pamh, const char *user, char **od_principal) 732{ 733 int retval = PAM_SERVICE_ERR; 734 ODRecordRef record = NULL; 735 CFStringRef principal = NULL; 736 CFArrayRef authparts = NULL, vals = NULL; 737 CFIndex i = 0, count = 0; 738 739 if (NULL == user || NULL == od_principal) { 740 openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); 741 retval = PAM_SERVICE_ERR; 742 goto cleanup; 743 } 744 745 retval = od_record_create_cstring(pamh, &record, user); 746 if (PAM_SUCCESS != retval) { 747 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); 748 goto cleanup; 749 } 750 751 retval = od_record_attribute_create_cfarray(record, kODAttributeTypeAuthenticationAuthority, &vals); 752 if (PAM_SUCCESS != retval) { 753 openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfarray() failed"); 754 goto cleanup; 755 } 756 if (NULL == vals) { 757 openpam_log(PAM_LOG_DEBUG, "no authauth availale for user."); 758 retval = PAM_PERM_DENIED; 759 goto cleanup; 760 } 761 762 count = CFArrayGetCount(vals); 763 for (i = 0; i < count; i++) 764 { 765 const void *val = CFArrayGetValueAtIndex(vals, i); 766 if (NULL == val || CFGetTypeID(val) != CFStringGetTypeID()) 767 break; 768 769 authparts = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, val, CFSTR(";")); 770 if (NULL == authparts) 771 continue; 772 773 if ((CFArrayGetCount(authparts) < 5) || 774 (CFStringCompare(CFArrayGetValueAtIndex(authparts, 1), CFSTR("Kerberosv5"), kCFCompareEqualTo)) || 775 (CFStringHasPrefix(CFArrayGetValueAtIndex(authparts, 4), CFSTR("LKDC:")))) { 776 if (NULL != authparts) { 777 CFRelease(authparts); 778 authparts = NULL; 779 } 780 continue; 781 } else { 782 break; 783 } 784 } 785 786 if (NULL == authparts) { 787 openpam_log(PAM_LOG_DEBUG, "No authentication authority returned"); 788 retval = PAM_PERM_DENIED; 789 goto cleanup; 790 } 791 792 principal = CFArrayGetValueAtIndex(authparts, 3); 793 if (NULL == principal) { 794 openpam_log(PAM_LOG_DEBUG, "no principal found in authentication authority"); 795 retval = PAM_PERM_DENIED; 796 goto cleanup; 797 } 798 799 retval = cfstring_to_cstring(principal, od_principal); 800 if (PAM_SUCCESS != retval) { 801 openpam_log(PAM_LOG_DEBUG, "cfstring_to_cstring() failed"); 802 goto cleanup; 803 } 804 805 806cleanup: 807 if (PAM_SUCCESS != retval) { 808 openpam_log(PAM_LOG_DEBUG, "failed: %d", retval); 809 } 810 811 if (NULL != record) { 812 CFRelease(record); 813 } 814 815 if (NULL != authparts) { 816 CFRelease(authparts); 817 } 818 819 if (NULL != vals) { 820 CFRelease(vals); 821 } 822 823 return retval; 824} 825 826void 827pam_cf_cleanup(__unused pam_handle_t *pamh, void *data, __unused int pam_end_status) 828{ 829 if (data) { 830 CFStringRef *cfstring = data; 831 CFRelease(*cfstring); 832 } 833} 834