1/* Copyright (c) 2012 Apple Inc. All Rights Reserved. */ 2 3#include "session.h" 4#include "process.h" 5#include "debugging.h" 6#include <dispatch/dispatch.h> 7#include <CoreFoundation/CoreFoundation.h> 8 9struct _session_s { 10 __AUTH_BASE_STRUCT_HEADER__; 11 12 CFMutableSetRef credentials; 13 CFMutableSetRef processes; 14 auditinfo_addr_t auditinfo; 15 16 dispatch_queue_t dispatch_queue; 17 18}; 19 20static void 21_session_finalize(CFTypeRef value) 22{ 23 session_t session = (session_t)value; 24 25 LOGV("session: %i deallocated %p", session->auditinfo.ai_asid, session); 26 27 // make sure queue is empty 28 dispatch_barrier_sync(session->dispatch_queue, ^{}); 29 30 dispatch_release(session->dispatch_queue); 31 CFReleaseSafe(session->credentials); 32 CFReleaseSafe(session->processes); 33} 34 35AUTH_TYPE_INSTANCE(session, 36 .init = NULL, 37 .copy = NULL, 38 .finalize = _session_finalize, 39 .equal = NULL, 40 .hash = NULL, 41 .copyFormattingDesc = NULL, 42 .copyDebugDesc = NULL 43 ); 44 45static CFTypeID session_get_type_id() { 46 static CFTypeID type_id = _kCFRuntimeNotATypeID; 47 static dispatch_once_t onceToken; 48 49 dispatch_once(&onceToken, ^{ 50 type_id = _CFRuntimeRegisterClass(&_auth_type_session); 51 }); 52 53 return type_id; 54} 55 56session_t 57session_create(session_id_t sid) 58{ 59 session_t session = NULL; 60 61 session = (session_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, session_get_type_id(), AUTH_CLASS_SIZE(session), NULL); 62 require(session != NULL, done); 63 64 session->auditinfo.ai_asid = sid; 65 66 if (!session_update(session)) { 67 LOGE("session: failed to get session info"); 68 } 69 70 session->dispatch_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); 71 check(session->dispatch_queue != NULL); 72 73 session->credentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks); 74 session->processes = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL); 75 76 LOGV("session: %i created (uid=%i) %p", session->auditinfo.ai_asid, session->auditinfo.ai_auid, session); 77 78done: 79 return session; 80} 81 82bool session_update(session_t session) 83{ 84 return auditon(A_GETSINFO_ADDR, &session->auditinfo, sizeof(session->auditinfo)) == 0; 85} 86 87uint64_t session_get_attributes(session_t session) 88{ 89 session_update(session); 90 91 return session->auditinfo.ai_flags; 92} 93 94static void _set_attributes(session_t session, uint64_t flags) 95{ 96 session->auditinfo.ai_flags = flags; 97 int32_t rc = setaudit_addr(&session->auditinfo, sizeof(session->auditinfo)); 98 if (rc != 0) { 99 LOGV("session: failed to update session info (%d)", rc); 100 } 101} 102 103void session_set_attributes(session_t session, uint64_t flags) 104{ 105 session_update(session); 106 _set_attributes(session,session->auditinfo.ai_flags | flags); 107} 108 109void session_clear_attributes(session_t session, uint64_t flags) 110{ 111 session_update(session); 112 _set_attributes(session,session->auditinfo.ai_flags & ~flags); 113} 114 115 116const void * 117session_get_key(session_t session) 118{ 119 return &session->auditinfo.ai_asid; 120} 121 122session_id_t 123session_get_id(session_t session) 124{ 125 return session ? session->auditinfo.ai_asid : -1; 126} 127 128uid_t 129session_get_uid(session_t session) 130{ 131 return session ? session->auditinfo.ai_auid : (uid_t)-2; 132} 133 134CFIndex 135session_add_process(session_t session, process_t proc) 136{ 137 __block CFIndex count = 0; 138 dispatch_sync(session->dispatch_queue, ^{ 139 CFSetAddValue(session->processes, proc); 140 count = CFSetGetCount(session->processes); 141 }); 142 return count; 143} 144 145CFIndex 146session_remove_process(session_t session, process_t proc) 147{ 148 __block CFIndex count = 0; 149 dispatch_sync(session->dispatch_queue, ^{ 150 CFSetRemoveValue(session->processes, proc); 151 count = CFSetGetCount(session->processes); 152 }); 153 return count; 154} 155 156CFIndex 157session_get_process_count(session_t session) 158{ 159 __block CFIndex count = 0; 160 dispatch_sync(session->dispatch_queue, ^{ 161 count = CFSetGetCount(session->processes); 162 }); 163 return count; 164} 165 166void 167session_set_credential(session_t session, credential_t cred) 168{ 169 if (!credential_get_valid(cred)) 170 return; 171 172 dispatch_sync(session->dispatch_queue, ^{ 173 CFSetSetValue(session->credentials, cred); 174 }); 175} 176 177void 178session_credentials_purge(session_t session) 179{ 180 session_credentials_iterate(session, ^bool(credential_t cred) { 181 if (!credential_get_valid(cred)) { 182 CFSetRemoveValue(session->credentials, cred); 183 } 184 return true; 185 }); 186} 187 188bool 189session_credentials_iterate(session_t session, credential_iterator_t iter) 190{ 191 __block bool result = false; 192 193 dispatch_sync(session->dispatch_queue, ^{ 194 CFIndex count = CFSetGetCount(session->credentials); 195 CFTypeRef values[count]; 196 CFSetGetValues(session->credentials, values); 197 for (CFIndex i = 0; i < count; i++) { 198 credential_t cred = (credential_t)values[i]; 199 result = iter(cred); 200 if (!result) { 201 break; 202 } 203 } 204 }); 205 206 207 return result; 208} 209