X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/c38e3ce98599a410a47dc10253faa4d5830f13b2..427c49bcad63d042b29ada2ac27e3dfc4845c779:/authd/credential.c?ds=inline diff --git a/authd/credential.c b/authd/credential.c new file mode 100644 index 00000000..bbfaae1b --- /dev/null +++ b/authd/credential.c @@ -0,0 +1,263 @@ +/* Copyright (c) 2012 Apple Inc. All rights reserved. */ + +#include "credential.h" +#include "authutilities.h" +#include "debugging.h" +#include "crc.h" + +#include +#include +#include + +struct _credential_s { + __AUTH_BASE_STRUCT_HEADER__; + + bool right; // is least-privileged credential + + uid_t uid; + char * name; + char * realName; + + CFAbsoluteTime creationTime; + bool valid; + bool shared; + + CFMutableSetRef cachedGroups; +}; + +static void +_credential_finalize(CFTypeRef value) +{ + credential_t cred = (credential_t)value; + + free_safe(cred->name); + free_safe(cred->realName); + CFReleaseSafe(cred->cachedGroups); +} + +static CFStringRef +_credential_copy_description(CFTypeRef value) +{ + credential_t cred = (credential_t)value; + CFStringRef str = NULL; + CFTimeZoneRef sys_tz = CFTimeZoneCopySystem(); + CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(cred->creationTime, sys_tz); + CFReleaseSafe(sys_tz); + if (cred->right) { + str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("credential: right=%s, shared=%i, creation=%01i:%01i:%01i, valid=%i"), cred->name, cred->shared, date.hour,date.minute,(int32_t)date.second, cred->valid); + } else { + str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("credential: uid=%i, name=%s, shared=%i, creation=%01i:%01i:%01i valid=%i"), cred->uid, cred->name, cred->shared, date.hour,date.minute,(int32_t)date.second, cred->valid); + } + return str; +} + +static CFHashCode +_credential_hash(CFTypeRef value) +{ + credential_t cred = (credential_t)value; + uint64_t crc = crc64_init(); + if (cred->right) { + crc = crc64_update(crc, cred->name, strlen(cred->name)); + } else { + crc = crc64_update(crc, &cred->uid, sizeof(cred->uid)); + } + crc = crc64_update(crc, &cred->shared, sizeof(cred->shared)); + crc = crc64_final(crc); + + return crc; +} + +static Boolean +_credential_equal(CFTypeRef value1, CFTypeRef value2) +{ + credential_t cred1 = (credential_t)value1; + credential_t cred2 = (credential_t)value2; + + return _credential_hash(cred1) == _credential_hash(cred2); +} + +AUTH_TYPE_INSTANCE(credential, + .init = NULL, + .copy = NULL, + .finalize = _credential_finalize, + .equal = _credential_equal, + .hash = _credential_hash, + .copyFormattingDesc = NULL, + .copyDebugDesc = _credential_copy_description + ); + +static CFTypeID credential_get_type_id() { + static CFTypeID type_id = _kCFRuntimeNotATypeID; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + type_id = _CFRuntimeRegisterClass(&_auth_type_credential); + }); + + return type_id; +} + +static credential_t +_credential_create() +{ + credential_t cred = NULL; + + cred = (credential_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, credential_get_type_id(), AUTH_CLASS_SIZE(credential), NULL); + require(cred != NULL, done); + + cred->creationTime = CFAbsoluteTimeGetCurrent(); + cred->cachedGroups = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);; + +done: + return cred; +} + +credential_t +credential_create(uid_t uid) +{ + credential_t cred = NULL; + + cred = _credential_create(); + require(cred != NULL, done); + + struct passwd *pw = getpwuid(uid); + if (pw != NULL) { + // avoid hinting a locked account + if ( (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) { + cred->uid = pw->pw_uid; + cred->name = _copy_string(pw->pw_name); + cred->realName = _copy_string(pw->pw_gecos); + cred->valid = true; + } else { + cred->uid = (uid_t)-2; + cred->valid = false; + } + endpwent(); + } + +done: + return cred; +} + +credential_t +credential_create_with_credential(credential_t srcCred, bool shared) +{ + credential_t cred = NULL; + + cred = _credential_create(); + require(cred != NULL, done); + + cred->uid = srcCred->uid; + cred->name = _copy_string(srcCred->name); + cred->realName = _copy_string(srcCred->realName); + cred->valid = srcCred->valid; + cred->right = srcCred->right; + cred->shared = shared; + +done: + return cred; +} + +credential_t +credential_create_with_right(const char * right) +{ + credential_t cred = NULL; + + cred = _credential_create(); + require(cred != NULL, done); + + cred->right = true; + cred->name = _copy_string(right); + cred->uid = (uid_t)-2; + cred->valid = true; + +done: + return cred; +} + +uid_t +credential_get_uid(credential_t cred) +{ + return cred->uid; +} + +const char * +credential_get_name(credential_t cred) +{ + return cred->name; +} + +const char * +credential_get_realname(credential_t cred) +{ + return cred->realName; +} + +CFAbsoluteTime +credential_get_creation_time(credential_t cred) +{ + return cred->creationTime; +} + +bool +credential_get_valid(credential_t cred) +{ + return cred->valid; +} + +bool +credential_get_shared(credential_t cred) +{ + return cred->shared; +} + +bool +credential_is_right(credential_t cred) +{ + return cred->right; +} + +bool +credential_check_membership(credential_t cred,const char* group) +{ + bool result = false; + CFStringRef cachedGroup = NULL; + require(group != NULL, done); + require(cred->uid != 0 || cred->uid != (uid_t)-2, done); + require(cred->right != true, done); + + cachedGroup = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8); + require(cachedGroup != NULL, done); + + if (CFSetGetValue(cred->cachedGroups, cachedGroup) != NULL) { + result = true; + goto done; + } + + int rc, ismember; + uuid_t group_uuid, user_uuid; + rc = mbr_group_name_to_uuid(group, group_uuid); + require_noerr(rc, done); + + rc = mbr_uid_to_uuid(cred->uid, user_uuid); + require_noerr(rc, done); + + rc = mbr_check_membership(user_uuid, group_uuid, &ismember); + require_noerr(rc, done); + + result = ismember; + + if (ismember) { + CFSetSetValue(cred->cachedGroups, cachedGroup); + } + +done: + CFReleaseSafe(cachedGroup); + return result; +} + +void +credential_invalidate(credential_t cred) +{ + cred->valid = false; +}