1/*- 2 * Copyright (c) 2009 - 2011 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 - 2013 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include "mech_locl.h" 31#include <heim_threads.h> 32 33#include <Security/Security.h> 34#include "krb5.h" 35 36/** 37 * Acquire a new initial credentials using long term credentials (password, certificate). 38 * 39 * Credentials acquired should be free-ed with gss_release_cred() or 40 * destroyed with (removed from storage) gss_destroy_cred(). 41 * 42 * Some mechanism types can not directly acquire or validate 43 * credential (for example PK-U2U, SCRAM, NTLM or IAKERB), for those 44 * mechanisms its instead the gss_init_sec_context() that will either acquire or 45 * force validation of the credential. 46 * 47 * This function is blocking and should not be used on threads used for UI updates. 48 * 49 * @param desired_name name to use to acquire credential. Import the name using gss_import_name(). The type of the name has to be supported by the desired_mech used. 50 * 51 * @param desired_mech mechanism to use to acquire credential. GSS_C_NO_OID is not valid input and a mechanism must be selected. For example GSS_KRB5_MECHANISM, GSS_NTLM_MECHNISM or any other mechanisms supported by the implementation. See gss_indicate_mechs(). 52 * 53 * @param attributes CFDictionary that contains how to acquire the credential, see below for examples 54 * 55 * @param output_cred_handle the resulting credential handle, value is set to GSS_C_NO_CREDENTIAL on failure. 56 * 57 * @param error an CFErrorRef returned in case of an error, that needs to be released with CFRelease() by the caller, input can be NULL. 58 * 59 * @returns a gss_error code, see the CFErrorRef passed back in error for the failure message. 60 * 61 * attributes must contains one of the following keys 62 * * kGSSICPassword - CFStringRef password 63 * * kGSSICCertificate - SecIdentityRef to the certificate to use with PKINIT/PKU2U 64 * 65 * optional keys 66 * * kGSSCredentialUsage - one of kGSS_C_INITIATE, kGSS_C_ACCEPT, kGSS_C_BOTH, default if not given is kGSS_C_INITIATE 67 * * kGSSICVerifyCredential - validate the credential with a trusted source that there was no MITM 68 * * kGSSICLKDCHostname - CFStringRef hostname of LKDC hostname 69 * * kGSSICKerberosCacheName - CFStringRef name of cache that will be created (including type) 70 * * kGSSICAppIdentifierACL - CFArrayRef[CFStringRef] prefix of bundle ID allowed to access this credential 71 * 72 * 73 * 74 * @ingroup gssapi 75 */ 76 77OM_uint32 GSSAPI_LIB_FUNCTION 78gss_aapl_initial_cred(const gss_name_t desired_name, 79 gss_const_OID desired_mech, 80 CFDictionaryRef attributes, 81 gss_cred_id_t * output_cred_handle, 82 CFErrorRef *error) 83{ 84 OM_uint32 major_status, minor_status; 85 gss_buffer_desc credential; 86 CFStringRef usage; 87 CFTypeRef password, certificate; 88 gss_cred_usage_t cred_usage = GSS_C_INITIATE; 89 gss_const_OID cred_type; 90 void *cred_value; 91 92 credential.value = NULL; 93 credential.length = 0; 94 95 HEIM_WARN_BLOCKING("gss_aapl_initial_cred", warn_once); 96 97 if (error) 98 *error = NULL; 99 100 if (desired_mech == GSS_C_NO_OID) 101 return GSS_S_BAD_MECH; 102 if (desired_name == GSS_C_NO_NAME) 103 return GSS_S_BAD_NAME; 104 105 if (output_cred_handle == NULL) 106 return GSS_S_CALL_INACCESSIBLE_READ; 107 108 *output_cred_handle = GSS_C_NO_CREDENTIAL; 109 110 /* require password or certificate */ 111 password = CFDictionaryGetValue(attributes, kGSSICPassword); 112 certificate = CFDictionaryGetValue(attributes, kGSSICCertificate); 113 if (password == NULL && certificate == NULL) { 114 return GSS_S_CALL_INACCESSIBLE_READ; 115 } 116 117 /* check usage */ 118 usage = CFDictionaryGetValue(attributes, kGSSCredentialUsage); 119 if (usage && CFGetTypeID(usage) == CFStringGetTypeID()) { 120 if (CFStringCompare(usage, kGSS_C_INITIATE, 0) == kCFCompareEqualTo) 121 cred_usage = GSS_C_INITIATE; 122 else if (CFStringCompare(usage, kGSS_C_ACCEPT, 0) == kCFCompareEqualTo) 123 cred_usage = GSS_C_ACCEPT; 124 else if (CFStringCompare(usage, kGSS_C_BOTH, 0) == kCFCompareEqualTo) 125 cred_usage = GSS_C_BOTH; 126 else 127 return GSS_S_FAILURE; 128 } 129 130 if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM)) { 131 132 cred_value = (void *)attributes; 133 cred_type = GSS_C_CRED_HEIMBASE; 134 135 } else if (password && CFGetTypeID(password) == CFStringGetTypeID()) { 136 char *str = rk_cfstring2cstring(password); 137 if (str == NULL) 138 return GSS_S_FAILURE; 139 140 credential.value = str; 141 credential.length = strlen(str); 142 cred_value = &credential; 143 cred_type = GSS_C_CRED_PASSWORD; 144 145 } else if (password && CFGetTypeID(password) == CFDataGetTypeID()) { 146 credential.value = malloc(CFDataGetLength(password)); 147 if (credential.value == NULL) 148 return GSS_S_FAILURE; 149 150 credential.length = CFDataGetLength(password); 151 memcpy(credential.value, CFDataGetBytePtr(password), CFDataGetLength(password)); 152 153 cred_value = &credential; 154 cred_type = GSS_C_CRED_PASSWORD; 155 } else if (certificate && CFGetTypeID(certificate) == SecIdentityGetTypeID()) { 156 cred_value = rk_UNCONST(certificate); 157 cred_type = GSS_C_CRED_SecIdentity; 158 } else if (certificate && CFGetTypeID(certificate) == SecCertificateGetTypeID()) { 159 cred_value = rk_UNCONST(certificate); 160 cred_type = GSS_C_CRED_SecIdentity; 161 } else 162 return GSS_S_FAILURE; 163 164 major_status = gss_acquire_cred_ext(&minor_status, 165 desired_name, 166 cred_type, 167 cred_value, 168 GSS_C_INDEFINITE, 169 desired_mech, 170 cred_usage, 171 output_cred_handle); 172 if (credential.length) { 173 memset(credential.value, 0, credential.length); 174 free(credential.value); 175 } 176 177 if (major_status && error) { 178 *error = _gss_mg_create_cferror(major_status, minor_status, desired_mech); 179 return major_status; 180 } 181 182 /** 183 * The credential can be validated by adding kGSSICVerifyCredential to the attributes with any value. 184 */ 185 186 if (CFDictionaryGetValue(attributes, kGSSICVerifyCredential)) { 187 gss_buffer_set_t bufferset = GSS_C_NO_BUFFER_SET; 188 189 major_status = gss_inquire_cred_by_oid(&minor_status, *output_cred_handle, 190 GSS_C_CRED_VALIDATE, &bufferset); 191 if (major_status == GSS_S_COMPLETE) 192 gss_release_buffer_set(&minor_status, &bufferset); 193 else { 194 if (error) 195 *error = _gss_mg_create_cferror(major_status, minor_status, desired_mech); 196 gss_destroy_cred(&minor_status, output_cred_handle); 197 } 198 } 199 200 return major_status; 201} 202 203/** 204 * Change pasword for a gss name 205 * 206 * @param name name to change password for 207 * @param mech mechanism to use 208 * @param attributes old and new password (kGSSChangePasswordOldPassword and kGSSChangePasswordNewPassword) and other attributes. 209 * @param error if not NULL, error might be set case function doesn't 210 * return GSS_S_COMPLETE, in that case is must be released with 211 * CFRelease(). 212 * 213 * @returns returns GSS_S_COMPLETE on success, error might be set if passed in. 214 * 215 * @ingroup gssapi 216 */ 217 218OM_uint32 GSSAPI_LIB_FUNCTION 219gss_aapl_change_password(const gss_name_t name, 220 gss_const_OID mech, 221 CFDictionaryRef attributes, 222 CFErrorRef *error) 223{ 224 struct _gss_mechanism_name *mn = NULL; 225 char *oldpw = NULL, *newpw = NULL; 226 OM_uint32 maj_stat, min_stat; 227 gssapi_mech_interface m; 228 CFStringRef old, new; 229 230 _gss_load_mech(); 231 232 m = __gss_get_mechanism(mech); 233 if (m == NULL) { 234 maj_stat = GSS_S_BAD_MECH; 235 min_stat = 0; 236 goto out; 237 } 238 239 if (m->gm_aapl_change_password == NULL) { 240 maj_stat = GSS_S_UNAVAILABLE; 241 min_stat = 0; 242 goto out; 243 } 244 245 maj_stat = _gss_find_mn(&min_stat, (struct _gss_name *)name, mech, &mn); 246 if (maj_stat != GSS_S_COMPLETE) 247 goto out; 248 249 old = CFDictionaryGetValue(attributes, kGSSChangePasswordOldPassword); 250 new = CFDictionaryGetValue(attributes, kGSSChangePasswordNewPassword); 251 252 heim_assert(old != NULL, "old password missing"); 253 heim_assert(new != NULL, "new password missing"); 254 255 oldpw = rk_cfstring2cstring(old); 256 newpw = rk_cfstring2cstring(new); 257 258 if (oldpw == NULL || newpw == NULL) { 259 maj_stat = GSS_S_FAILURE; 260 min_stat = 0; 261 goto out; 262 } 263 264 maj_stat = m->gm_aapl_change_password(&min_stat, 265 mn->gmn_name, 266 oldpw, newpw); 267 if (maj_stat) 268 _gss_mg_error(m, min_stat); 269 270 out: 271 if (maj_stat && error) 272 *error = _gss_mg_create_cferror(maj_stat, min_stat, mech); 273 274 if (oldpw) { 275 memset(oldpw, 0, strlen(oldpw)); 276 free(oldpw); 277 } 278 if (newpw) { 279 memset(newpw, 0, strlen(newpw)); 280 free(newpw); 281 } 282 283 return maj_stat; 284} 285 286/** 287 * Returns a copy of the UUID of the GSS credential 288 * 289 * @param credential credential 290 * 291 * @returns CFUUIDRef that can be used to turn into a credential, 292 * normal CoreFoundaton rules for rules applies so the CFUUIDRef needs 293 * to be released. 294 * 295 * @ingroup gssapi 296 */ 297 298CFUUIDRef 299GSSCredentialCopyUUID(gss_cred_id_t credential) 300{ 301 OM_uint32 major, minor; 302 gss_buffer_set_t dataset = GSS_C_NO_BUFFER_SET; 303 krb5_error_code ret; 304 krb5_uuid uuid; 305 CFUUIDBytes cfuuid; 306 307 major = gss_inquire_cred_by_oid(&minor, credential, GSS_C_NT_UUID, &dataset); 308 if (major || dataset->count != 1) { 309 gss_release_buffer_set(&minor, &dataset); 310 return NULL; 311 } 312 313 if (dataset->elements[0].length != 36) { 314 gss_release_buffer_set(&minor, &dataset); 315 return NULL; 316 } 317 318 ret = krb5_string_to_uuid(dataset->elements[0].value, uuid); 319 gss_release_buffer_set(&minor, &dataset); 320 if (ret) 321 return NULL; 322 323 memcpy(&cfuuid, uuid, sizeof(uuid)); 324 325 return CFUUIDCreateFromUUIDBytes(NULL, cfuuid); 326} 327 328/** 329 * Returns a GSS credential for a given UUID if the credential exists. 330 * 331 * @param uuid the UUID of the credential to fetch 332 * 333 * @returns a gss_cred_id_t, normal CoreFoundaton rules for rules 334 * applies so the CFUUIDRef needs to be released with either CFRelease() or gss_release_name(). 335 * 336 * @ingroup gssapi 337 */ 338 339gss_cred_id_t GSSAPI_LIB_FUNCTION 340GSSCreateCredentialFromUUID(CFUUIDRef uuid) 341{ 342 OM_uint32 min_stat, maj_stat; 343 gss_cred_id_t cred; 344 CFStringRef name; 345 gss_name_t gname; 346 347 name = CFUUIDCreateString(NULL, uuid); 348 if (name == NULL) 349 return NULL; 350 351 gname = GSSCreateName(name, GSS_C_NT_UUID, NULL); 352 CFRelease(name); 353 if (gname == NULL) 354 return NULL; 355 356 maj_stat = gss_acquire_cred(&min_stat, gname, GSS_C_INDEFINITE, NULL, 357 GSS_C_INITIATE, &cred, NULL, NULL); 358 gss_release_name(&min_stat, &gname); 359 if (maj_stat != GSS_S_COMPLETE) 360 return NULL; 361 362 return cred; 363} 364 365static CFStringRef 366CopyFoldString(CFStringRef host) 367{ 368 CFMutableStringRef string = CFStringCreateMutableCopy(NULL, 0, host); 369 static dispatch_once_t once; 370 static CFLocaleRef locale; 371 dispatch_once(&once, ^{ 372 locale = CFLocaleCreate(NULL, CFSTR("C")); 373 }); 374 CFStringFold(string, kCFCompareCaseInsensitive, locale); 375 return string; 376} 377 378static bool 379FoldedHostName(CFStringRef stringOrURL, CFStringRef *scheme, CFStringRef *host, CFStringRef *path) 380{ 381 CFRange range; 382 383 *scheme = NULL; 384 *host = NULL; 385 *path = NULL; 386 387 range = CFStringFind(stringOrURL, CFSTR(":"), 0); 388 if (range.location != kCFNotFound) { 389 CFURLRef url; 390 391 url = CFURLCreateWithString(NULL, stringOrURL, NULL); 392 if (url) { 393 CFStringRef hn = CFURLCopyHostName(url); 394 if (hn == NULL) { 395 *host = CFSTR(""); 396 } else { 397 *host = CopyFoldString(hn); 398 CFRelease(hn); 399 if (*host == NULL) { 400 CFRelease(url); 401 return false; 402 } 403 } 404 405 *scheme = CFURLCopyScheme(url); 406 if (*scheme == NULL) 407 *scheme = CFSTR(""); 408 409 *path = CFURLCopyPath(url); 410 if (*path == NULL || CFStringCompare(*path, CFSTR(""), 0) == kCFCompareEqualTo) { 411 if (*path) 412 CFRelease(*path); 413 *path = CFSTR("/"); 414 } 415 CFRelease(url); 416 } 417 } 418 419 if (*host == NULL) { 420 *host = CopyFoldString(stringOrURL); 421 if (*scheme) 422 CFRelease(*scheme); 423 *scheme = CFSTR("any"); 424 *path = CFSTR("/"); 425 } 426 427 return true; 428} 429 430/* 431 * 432 */ 433 434void 435GSSRuleAddMatch(CFMutableDictionaryRef rules, CFStringRef host, CFStringRef value) 436{ 437 CFStringRef scheme = NULL, hostname = NULL, path = NULL; 438 CFMutableDictionaryRef match; 439 440 if (!FoldedHostName(host, &scheme, &hostname, &path)) 441 return; 442 443 match = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 444 if (match == NULL) 445 goto out; 446 447 CFDictionarySetValue(match, CFSTR("scheme"), scheme); 448 CFDictionarySetValue(match, CFSTR("path"), path); 449 CFDictionarySetValue(match, CFSTR("value"), value); 450 451 CFArrayRef array = CFDictionaryGetValue(rules, hostname); 452 CFMutableArrayRef mutable; 453 454 if (array) { 455 mutable = CFArrayCreateMutableCopy(NULL, 0, array); 456 } else { 457 mutable = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 458 } 459 if (mutable) { 460 461 CFIndex n, count = CFArrayGetCount(mutable); 462 463 for (n = 0; n < count; n++) { 464 CFDictionaryRef item = (CFDictionaryRef)CFArrayGetValueAtIndex(mutable, n); 465 CFStringRef p = CFDictionaryGetValue(item, CFSTR("path")); 466 CFStringRef s = CFDictionaryGetValue(item, CFSTR("scheme")); 467 468 if (CFStringCompare(s, scheme, kCFCompareCaseInsensitive) == kCFCompareLessThan) 469 continue; 470 471 if (CFStringHasPrefix(path, p)) { 472 CFArrayInsertValueAtIndex(mutable, n, match); 473 break; 474 } 475 } 476 if (n >= count) 477 CFArrayAppendValue(mutable, match); 478 479 CFDictionarySetValue(rules, hostname, mutable); 480 CFRelease(mutable); 481 } 482 483out: 484 CFRelease(scheme); 485 CFRelease(hostname); 486 CFRelease(path); 487 if (match) 488 CFRelease(match); 489} 490 491/* 492 * host is a URL string or hostname string 493 */ 494 495CFStringRef 496GSSRuleGetMatch(CFDictionaryRef rules, CFStringRef hostname) 497{ 498 CFStringRef scheme = NULL, hostFolded = NULL, path = NULL; 499 CFTypeRef result = NULL; 500 const char *p; 501 502 if (!FoldedHostName(hostname, &scheme, &hostFolded, &path)) 503 return NULL; 504 505 char *host = rk_cfstring2cstring(hostFolded); 506 CFRelease(hostFolded); 507 if (host == NULL) { 508 CFRelease(path); 509 return NULL; 510 } 511 512 if (host[0] == '\0') { 513 CFRelease(scheme); 514 free(host); 515 CFRelease(path); 516 return NULL; 517 } 518 519 for (p = host; p != NULL && result == NULL; p = strchr(p + 1, '.')) { 520 CFStringRef partial = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8); 521 CFArrayRef array = (CFArrayRef)CFDictionaryGetValue(rules, partial); 522 523 CFRelease(partial); 524 525 if (array) { 526 CFIndex n, count = CFArrayGetCount(array); 527 528 for (n = 0; n < count && result == NULL; n++) { 529 CFDictionaryRef item = (CFDictionaryRef)CFArrayGetValueAtIndex(array, n); 530 531 CFStringRef matchScheme = CFDictionaryGetValue(item, CFSTR("scheme")); 532 if (CFStringCompare(scheme, matchScheme, kCFCompareCaseInsensitive) != kCFCompareEqualTo && 533 CFStringCompare(CFSTR("any"), matchScheme, kCFCompareCaseInsensitive) != kCFCompareEqualTo) 534 continue; 535 536 CFStringRef matchPath = CFDictionaryGetValue(item, CFSTR("path")); 537 if (CFStringHasPrefix(path, matchPath)) 538 result = CFDictionaryGetValue(item, CFSTR("value")); 539 540 } 541 } 542 } 543 CFRelease(scheme); 544 free(host); 545 CFRelease(path); 546 return result; 547} 548 549/** 550 * Create a GSS name from a buffer and type. 551 * 552 * @param name name buffer describing a credential, can be either a CFDataRef or CFStringRef of a name. 553 * @param name_type on OID of the GSS_C_NT_* OIDs constants specifiy the name type. 554 * @param error if an error happen, this may be set to a CFErrorRef describing the failure futher. 555 * 556 * @returns returns gss_name_t or NULL on failure. Must be freed using gss_release_name() or CFRelease(). Follows CoreFoundation Create/Copy rule. 557 * 558 * @ingroup gssapi 559 */ 560 561gss_name_t 562GSSCreateName(CFTypeRef name, gss_const_OID name_type, CFErrorRef *error) 563{ 564 OM_uint32 maj_stat, min_stat; 565 gss_buffer_desc buffer; 566 int free_data = 0; 567 gss_name_t n; 568 569 if (error) 570 *error = NULL; 571 572 if (CFGetTypeID(name) == CFStringGetTypeID()) { 573 buffer.value = rk_cfstring2cstring(name); 574 if (buffer.value == NULL) 575 return GSS_S_FAILURE; 576 buffer.length = strlen((char *)buffer.value); 577 free_data = 1; 578 } else if (CFGetTypeID(name) == CFDataGetTypeID()) { 579 buffer.value = (void *)CFDataGetBytePtr(name); 580 buffer.length = (OM_uint32)CFDataGetLength(name); 581 } else { 582 return GSS_C_NO_NAME; 583 } 584 585 maj_stat = gss_import_name(&min_stat, &buffer, name_type, &n); 586 587 if (free_data) 588 free(buffer.value); 589 590 if (maj_stat) 591 return GSS_C_NO_NAME; 592 593 return n; 594} 595 596/** 597 * Copy the name describing the credential 598 * 599 * @param cred the credential to get the name from 600 * 601 * @returns returns gss_name_t or NULL on failure. Must be freed using gss_release_name() or CFRelease(). Follows CoreFoundation Create/Copy rule. 602 * 603 * @ingroup gssapi 604 */ 605 606gss_name_t 607GSSCredentialCopyName(gss_cred_id_t cred) 608{ 609 OM_uint32 major, minor; 610 gss_name_t name; 611 612 major = gss_inquire_cred(&minor, cred, &name, NULL, NULL, NULL); 613 if (major != GSS_S_COMPLETE) 614 return NULL; 615 616 return name; 617} 618 619/** 620 * Return the lifetime (in seconds) left of the credential. 621 * 622 * @param cred the credential to get the name from 623 * 624 * @returns the lifetime of the credentials. 0 on failure and 625 * GSS_C_INDEFINITE on credentials that never expire. 626 * 627 * @ingroup gssapi 628 */ 629 630OM_uint32 631GSSCredentialGetLifetime(gss_cred_id_t cred) 632{ 633 OM_uint32 maj_stat, min_stat; 634 OM_uint32 lifetime; 635 636 maj_stat = gss_inquire_cred(&min_stat, cred, NULL, &lifetime, NULL, NULL); 637 if (maj_stat != GSS_S_COMPLETE) 638 return 0; 639 640 return lifetime; 641} 642 643/** 644 * Returns a string that is suitable for displaying to user, must not 645 * be used for verify subjects on an ACLs. 646 * 647 * @param name to get a display strings from 648 * 649 * @returns a string that is printable. Follows CoreFoundation Create/Copy rule. 650 * 651 * @ingroup gssapi 652 */ 653 654CFStringRef 655GSSNameCreateDisplayString(gss_name_t name) 656{ 657 OM_uint32 maj_stat, min_stat; 658 gss_buffer_desc buffer; 659 CFStringRef str; 660 661 maj_stat = gss_display_name(&min_stat, name, &buffer, NULL); 662 if (maj_stat != GSS_S_COMPLETE) 663 return NULL; 664 665 str = CFStringCreateWithBytes(NULL, (const UInt8 *)buffer.value, buffer.length, kCFStringEncodingUTF8, false); 666 gss_release_buffer(&min_stat, &buffer); 667 668 return str; 669} 670 671/* 672 * Create a CFErrorRef from GSS-API major and minor status code. 673 * 674 * @param major_status Major status code returned by the funcation that failed 675 * @param major_status Major status code returned by the funcation that failed 676 * @param mech Mechanism passed in, if not available GSS_C_NO_OID should be used 677 * 678 * @returns a CFErrorRef in the domain org.h5l.GSS domain 679 * 680 * @ingroup gssapi 681 */ 682 683CFErrorRef 684GSSCreateError(gss_const_OID mech, 685 OM_uint32 major_status, 686 OM_uint32 minor_status) 687{ 688 return _gss_mg_create_cferror(major_status, minor_status, mech); 689} 690 691 692/* deprecated */ 693OM_uint32 694GSSCredGetLifetime(gss_cred_id_t cred) 695{ 696 return GSSCredentialGetLifetime(cred); 697} 698 699gss_name_t 700GSSCredCopyName(gss_cred_id_t cred) 701{ 702 return GSSCredentialCopyName(cred); 703} 704