1/* Copyright (c) 2012 Apple Inc. All rights reserved. */ 2 3#include "credential.h" 4#include "authutilities.h" 5#include "debugging.h" 6#include "crc.h" 7 8#include <pwd.h> 9#include <membership.h> 10#include <membershipPriv.h> 11 12struct _credential_s { 13 __AUTH_BASE_STRUCT_HEADER__; 14 15 bool right; // is least-privileged credential 16 17 uid_t uid; 18 char * name; 19 char * realName; 20 21 CFAbsoluteTime creationTime; 22 bool valid; 23 bool shared; 24 25 CFMutableSetRef cachedGroups; 26}; 27 28static void 29_credential_finalize(CFTypeRef value) 30{ 31 credential_t cred = (credential_t)value; 32 33 free_safe(cred->name); 34 free_safe(cred->realName); 35 CFReleaseSafe(cred->cachedGroups); 36} 37 38static CFStringRef 39_credential_copy_description(CFTypeRef value) 40{ 41 credential_t cred = (credential_t)value; 42 CFStringRef str = NULL; 43 CFTimeZoneRef sys_tz = CFTimeZoneCopySystem(); 44 CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(cred->creationTime, sys_tz); 45 CFReleaseSafe(sys_tz); 46 if (cred->right) { 47 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); 48 } else { 49 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); 50 } 51 return str; 52} 53 54static CFHashCode 55_credential_hash(CFTypeRef value) 56{ 57 credential_t cred = (credential_t)value; 58 uint64_t crc = crc64_init(); 59 if (cred->right) { 60 crc = crc64_update(crc, cred->name, strlen(cred->name)); 61 } else { 62 crc = crc64_update(crc, &cred->uid, sizeof(cred->uid)); 63 } 64 crc = crc64_update(crc, &cred->shared, sizeof(cred->shared)); 65 crc = crc64_final(crc); 66 67 return crc; 68} 69 70static Boolean 71_credential_equal(CFTypeRef value1, CFTypeRef value2) 72{ 73 credential_t cred1 = (credential_t)value1; 74 credential_t cred2 = (credential_t)value2; 75 76 return _credential_hash(cred1) == _credential_hash(cred2); 77} 78 79AUTH_TYPE_INSTANCE(credential, 80 .init = NULL, 81 .copy = NULL, 82 .finalize = _credential_finalize, 83 .equal = _credential_equal, 84 .hash = _credential_hash, 85 .copyFormattingDesc = NULL, 86 .copyDebugDesc = _credential_copy_description 87 ); 88 89static CFTypeID credential_get_type_id() { 90 static CFTypeID type_id = _kCFRuntimeNotATypeID; 91 static dispatch_once_t onceToken; 92 93 dispatch_once(&onceToken, ^{ 94 type_id = _CFRuntimeRegisterClass(&_auth_type_credential); 95 }); 96 97 return type_id; 98} 99 100static credential_t 101_credential_create() 102{ 103 credential_t cred = NULL; 104 105 cred = (credential_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, credential_get_type_id(), AUTH_CLASS_SIZE(credential), NULL); 106 require(cred != NULL, done); 107 108 cred->creationTime = CFAbsoluteTimeGetCurrent(); 109 cred->cachedGroups = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);; 110 111done: 112 return cred; 113} 114 115credential_t 116credential_create(uid_t uid) 117{ 118 credential_t cred = NULL; 119 120 cred = _credential_create(); 121 require(cred != NULL, done); 122 123 struct passwd *pw = getpwuid(uid); 124 if (pw != NULL) { 125 // avoid hinting a locked account 126 if ( (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) { 127 cred->uid = pw->pw_uid; 128 cred->name = _copy_string(pw->pw_name); 129 cred->realName = _copy_string(pw->pw_gecos); 130 cred->valid = true; 131 } else { 132 cred->uid = (uid_t)-2; 133 cred->valid = false; 134 } 135 endpwent(); 136 } 137 138done: 139 return cred; 140} 141 142credential_t 143credential_create_with_credential(credential_t srcCred, bool shared) 144{ 145 credential_t cred = NULL; 146 147 cred = _credential_create(); 148 require(cred != NULL, done); 149 150 cred->uid = srcCred->uid; 151 cred->name = _copy_string(srcCred->name); 152 cred->realName = _copy_string(srcCred->realName); 153 cred->valid = srcCred->valid; 154 cred->right = srcCred->right; 155 cred->shared = shared; 156 157done: 158 return cred; 159} 160 161credential_t 162credential_create_with_right(const char * right) 163{ 164 credential_t cred = NULL; 165 166 cred = _credential_create(); 167 require(cred != NULL, done); 168 169 cred->right = true; 170 cred->name = _copy_string(right); 171 cred->uid = (uid_t)-2; 172 cred->valid = true; 173 174done: 175 return cred; 176} 177 178uid_t 179credential_get_uid(credential_t cred) 180{ 181 return cred->uid; 182} 183 184const char * 185credential_get_name(credential_t cred) 186{ 187 return cred->name; 188} 189 190const char * 191credential_get_realname(credential_t cred) 192{ 193 return cred->realName; 194} 195 196CFAbsoluteTime 197credential_get_creation_time(credential_t cred) 198{ 199 return cred->creationTime; 200} 201 202bool 203credential_get_valid(credential_t cred) 204{ 205 return cred->valid; 206} 207 208bool 209credential_get_shared(credential_t cred) 210{ 211 return cred->shared; 212} 213 214bool 215credential_is_right(credential_t cred) 216{ 217 return cred->right; 218} 219 220bool 221credential_check_membership(credential_t cred,const char* group) 222{ 223 bool result = false; 224 CFStringRef cachedGroup = NULL; 225 require(group != NULL, done); 226 require(cred->uid != 0 || cred->uid != (uid_t)-2, done); 227 require(cred->right != true, done); 228 229 cachedGroup = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8); 230 require(cachedGroup != NULL, done); 231 232 if (CFSetGetValue(cred->cachedGroups, cachedGroup) != NULL) { 233 result = true; 234 goto done; 235 } 236 237 int rc, ismember; 238 uuid_t group_uuid, user_uuid; 239 rc = mbr_group_name_to_uuid(group, group_uuid); 240 require_noerr(rc, done); 241 242 rc = mbr_uid_to_uuid(cred->uid, user_uuid); 243 require_noerr(rc, done); 244 245 rc = mbr_check_membership(user_uuid, group_uuid, &ismember); 246 require_noerr(rc, done); 247 248 result = ismember; 249 250 if (ismember) { 251 CFSetSetValue(cred->cachedGroups, cachedGroup); 252 } 253 254done: 255 CFReleaseSafe(cachedGroup); 256 return result; 257} 258 259void 260credential_invalidate(credential_t cred) 261{ 262 cred->valid = false; 263} 264