1/* Copyright (c) 2012 Apple Inc. All rights reserved. */ 2 3#include "ccaudit.h" 4#include "debugging.h" 5#include "process.h" 6#include "authtoken.h" 7 8#include <Security/Authorization.h> 9#include <Security/AuthorizationPlugin.h> 10#include <bsm/libbsm.h> 11 12 13struct _ccaudit_s { 14 __AUTH_BASE_STRUCT_HEADER__; 15 16 int fd; 17 int32_t event; 18 19 auth_token_t auth; 20 process_t proc; 21 audit_info_s auditInfo; 22 au_tid_t tid; 23}; 24 25static void 26_ccaudit_finalizer(CFTypeRef value) 27{ 28 ccaudit_t ccaudit = (ccaudit_t)value; 29 30 CFReleaseSafe(ccaudit->auth); 31 CFReleaseSafe(ccaudit->proc); 32} 33 34AUTH_TYPE_INSTANCE(ccaudit, 35 .init = NULL, 36 .copy = NULL, 37 .finalize = _ccaudit_finalizer, 38 .equal = NULL, 39 .hash = NULL, 40 .copyFormattingDesc = NULL, 41 .copyDebugDesc = NULL 42 ); 43 44static CFTypeID ccaudit_get_type_id() { 45 static CFTypeID type_id = _kCFRuntimeNotATypeID; 46 static dispatch_once_t onceToken; 47 48 dispatch_once(&onceToken, ^{ 49 type_id = _CFRuntimeRegisterClass(&_auth_type_ccaudit); 50 }); 51 52 return type_id; 53} 54 55ccaudit_t 56ccaudit_create(process_t proc, auth_token_t auth, int32_t event) 57{ 58 ccaudit_t ccaudit = NULL; 59 60 require(auth != NULL, done); 61 62 ccaudit = (ccaudit_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, ccaudit_get_type_id(), AUTH_CLASS_SIZE(ccaudit), NULL); 63 require(ccaudit != NULL, done); 64 65 ccaudit->auth = (auth_token_t)CFRetain(auth); 66 ccaudit->proc = (process_t)CFRetain(proc); 67 ccaudit->fd = -1; 68 ccaudit->event = event; 69 70 ccaudit->auditInfo = *auth_token_get_audit_info(auth); 71 ccaudit->tid.port = ccaudit->auditInfo.tid; 72 73done: 74 return ccaudit; 75} 76 77static bool _enabled() 78{ 79 static dispatch_once_t onceToken; 80 static bool enabled = false; 81 82 dispatch_once(&onceToken, ^{ 83 int acond = au_get_state(); 84 switch (acond) { 85 case AUC_NOAUDIT: 86 break; 87 case AUC_AUDITING: 88 enabled = true; 89 break; 90 default: 91 LOGE("ccaudit: error checking auditing status (%d)", acond); 92 } 93 }); 94 95 return enabled; 96} 97 98static bool _open(ccaudit_t ccaudit) 99{ 100 if (!_enabled()) { 101 return false; 102 } 103 104 if (-1 != ccaudit->fd) 105 return true; 106 107 if ((ccaudit->fd = au_open()) < 0) { 108 LOGE("ccaudit: au_open() failed (%s)", strerror(errno)); 109 return false; 110 } 111 112 return true; 113} 114 115static void _close(ccaudit_t ccaudit) 116{ 117 if (-1 != ccaudit->fd) { 118 int err = au_close(ccaudit->fd, AU_TO_WRITE, (short)ccaudit->event); 119 ccaudit->fd = -1; 120 if (err < 0) { 121 LOGE("ccaudit: au_close() failed; record not committed"); 122 } 123 } 124} 125 126static bool _write(ccaudit_t ccaudit, token_t * token, const char * name) 127{ 128 const char *tokenName = name ? name : "<unidentified>"; 129 if (NULL == token) 130 { 131 LOGE("ccaudit: invalid '%s' token", tokenName); 132 return false; 133 } 134 if (au_write(ccaudit->fd, token) < 0) { 135 LOGE("ccaudit: error writing '%s' token (%s)", tokenName, strerror(errno)); 136 return false; 137 } 138 return true; 139} 140 141static bool _subject(ccaudit_t ccaudit) 142{ 143 token_t * token = au_to_subject32(ccaudit->auditInfo.auid, ccaudit->auditInfo.euid, ccaudit->auditInfo.egid, 144 ccaudit->auditInfo.ruid, ccaudit->auditInfo.rgid, ccaudit->auditInfo.pid, ccaudit->auditInfo.asid, &ccaudit->tid); 145 return _write(ccaudit, token, "subject"); 146} 147 148void ccaudit_log_authorization(ccaudit_t ccaudit, const char * right, OSStatus err) 149{ 150 151 if (!_open(ccaudit)) { 152 return; 153 } 154 char buf[PATH_MAX+1]; 155 156 _subject(ccaudit); 157 _write(ccaudit, au_to_text(right), "right"); 158 snprintf(buf, sizeof(buf), "client %s", process_get_code_url(ccaudit->proc)); 159 _write(ccaudit, au_to_text(buf), "Authorization client"); 160 snprintf(buf, sizeof(buf), "creator %s", auth_token_get_code_url(ccaudit->auth)); 161 _write(ccaudit, au_to_text(buf), "Authorization creator"); 162 163 if (auth_token_least_privileged(ccaudit->auth)) { 164 _write(ccaudit, au_to_text("least-privilege"), "least-privilege"); 165 } 166 167 if (err == errAuthorizationSuccess) { 168 _write(ccaudit, au_to_return32(0, 0), "return"); 169 } else { 170 _write(ccaudit, au_to_return32(EPERM, (uint32_t)err), "return"); 171 } 172 173 _close(ccaudit); 174} 175 176void ccaudit_log_success(ccaudit_t ccaudit, credential_t cred, const char * right) 177{ 178 179 if (!_open(ccaudit)) { 180 return; 181 } 182 char buf[PATH_MAX+1]; 183 184 _subject(ccaudit); 185 _write(ccaudit, au_to_text(right), "right"); 186 _write(ccaudit, au_to_arg32(1, "known UID ", auth_token_get_uid(ccaudit->auth)), "authenticator"); 187 snprintf(buf, sizeof(buf), "authenticated as %s", credential_get_name(cred)); 188 _write(ccaudit, au_to_arg32(2, buf, credential_get_uid(cred)), "target"); 189 _write(ccaudit, au_to_return32(0, 0), "return"); 190 191 _close(ccaudit); 192} 193 194void ccaudit_log_failure(ccaudit_t ccaudit, const char * credName, const char * right) 195{ 196 197 if (!_open(ccaudit)) { 198 return; 199 } 200 _subject(ccaudit); 201 _write(ccaudit, au_to_text(right), "right"); 202 _write(ccaudit, au_to_arg32(1, "authenticated as ", auth_token_get_uid(ccaudit->auth)), "authenticator"); 203 204 if (NULL == credName) { 205 _write(ccaudit, au_to_text("<unknown user>"), "target username"); 206 } else { 207 _write(ccaudit, au_to_text(credName), "target username"); 208 } 209 _write(ccaudit, au_to_return32(EPERM, (uint32_t)errAuthorizationDenied), "return"); 210 211 _close(ccaudit); 212} 213 214void ccaudit_log_mechanism(ccaudit_t ccaudit, const char * right, const char * mech, uint32_t status, const char * interrupted) 215{ 216 217 if (!_open(ccaudit)) { 218 return; 219 } 220 char buf[PATH_MAX+1]; 221 222 _subject(ccaudit); 223 _write(ccaudit, au_to_text(right), "right"); 224 snprintf(buf, sizeof(buf), "mechanism %s", mech); 225 _write(ccaudit, au_to_text(buf), "mechanism"); 226 227 if (interrupted) { 228 _write(ccaudit, au_to_text(interrupted), "interrupt"); 229 } 230 231 if (status == kAuthorizationResultAllow) { 232 _write(ccaudit, au_to_return32(0, 0), "return"); 233 } else { 234 _write(ccaudit, au_to_return32(EPERM, (uint32_t)status), "return"); 235 } 236 237 _close(ccaudit); 238} 239 240void ccaudit_log(ccaudit_t ccaudit, const char * right, const char * msg, OSStatus err) 241{ 242 if (!_open(ccaudit)) { 243 return; 244 } 245 246 _subject(ccaudit); 247 _write(ccaudit, au_to_text(right), "right"); 248 249 if (msg) { 250 _write(ccaudit, au_to_text(msg), "evaluation error"); 251 } 252 253 if (err == errAuthorizationSuccess) { 254 _write(ccaudit, au_to_return32(0, 0), "return"); 255 } else { 256 _write(ccaudit, au_to_return32(EPERM, (uint32_t)err), "return"); 257 } 258 259 _close(ccaudit); 260} 261