1/* 2 * ccaudit_extensions.cpp 3 * securityd 4 * 5 * Created by G H on 3/24/09. 6 * Copyright (c) 2009 Apple Inc. All Rights Reserved. 7 * 8 */ 9 10#include <errno.h> 11#include <assert.h> 12#include <stdio.h> // vsnprintf() 13#include <stdarg.h> // va_start(), et al. 14#include <syslog.h> 15#include <string.h> // memcpy() 16#include <bsm/audit_uevents.h> // AUE_ssauth* 17#include <bsm/libbsm.h> 18#include <security_utilities/errors.h> 19#include <security_utilities/ccaudit.h> 20#include "ccaudit_extensions.h" 21 22namespace Security 23{ 24 25namespace CommonCriteria 26{ 27 28namespace Securityd 29{ 30 31// 32// AuditLogger 33// 34AuditLogger::AuditLogger(const audit_token_t *srcToken, short auEvent) 35 : mAuditFd(-1), mEvent(auEvent), mClientInfoSet(false) 36{ 37 setClientInfo(srcToken); 38} 39 40AuditLogger::AuditLogger(const AuditToken &srcToken, short auEvent) 41 : mAuditFd(-1), mEvent(auEvent), mClientInfoSet(false) 42{ 43 setClientInfo(srcToken); 44} 45 46AuditLogger::~AuditLogger() 47{ 48 close(); 49} 50 51bool 52AuditLogger::open() 53{ 54 if (-1 != mAuditFd) 55 return true; 56 57 // @@@ use audit_get_cond() when it's available 58 int acond = au_get_state(); 59 switch (acond) 60 { 61 case AUC_NOAUDIT: 62 return false; 63 case AUC_AUDITING: 64 break; 65 default: 66 logInternalError("error checking auditing status (%d)", acond); 67 UnixError::throwMe(acond); // assume it's a Unix error 68 } 69 if ((mAuditFd = au_open()) < 0) 70 { 71 logInternalError("au_open() failed (%s)", strerror(errno)); 72 UnixError::throwMe(errno); 73 } 74 return true; 75} 76 77void 78AuditLogger::close(bool writeLog/* = true*/) 79{ 80 if (-1 != mAuditFd) 81 { 82 int keep = writeLog == true ? AU_TO_WRITE : AU_TO_NO_WRITE; 83 int error = au_close(mAuditFd, keep, mEvent); 84 mAuditFd = -1; 85 if (writeLog == true && error < 0) 86 { 87 logInternalError("au_close() failed; record not committed"); 88 UnixError::throwMe(error); 89 } 90 } 91} 92 93void 94AuditLogger::setClientInfo(const audit_token_t *srcToken) 95{ 96 assert(srcToken); 97 audit_token_to_au32(*srcToken, &mAuditId, &mEuid, &mEgid, &mRuid, &mRgid, &mPid, &mAuditSessionId, &mOldTerminalId); 98 99 mTerminalId.at_type = AU_IPv4; 100 mTerminalId.at_addr[0] = mOldTerminalId.machine; 101 mTerminalId.at_port = mOldTerminalId.port; 102 103 mClientInfoSet = true; 104} 105 106void 107AuditLogger::setClientInfo(const AuditToken &srcToken) 108{ 109 mAuditId = srcToken.auditId(); 110 mEuid = srcToken.euid(); 111 mEgid = srcToken.egid(); 112 mRuid = srcToken.ruid(); 113 mRgid = srcToken.rgid(); 114 mPid = srcToken.pid(); 115 mAuditSessionId = srcToken.sessionId(); 116 memcpy(&mOldTerminalId, &(srcToken.terminalId()), sizeof(mOldTerminalId)); 117 118 mTerminalId.at_type = AU_IPv4; 119 mTerminalId.at_addr[0] = mOldTerminalId.machine; 120 mTerminalId.at_port = mOldTerminalId.port; 121 122 mClientInfoSet = true; 123} 124 125void 126AuditLogger::writeToken(token_t *token, const char *name) 127{ 128 const char *tokenName = name ? name : "<unidentified>"; 129 if (NULL == token) 130 { 131 logInternalError("Invalid '%s' token", tokenName); 132 close(); 133 UnixError::throwMe(EPERM); // per audit_submit() 134 } 135 if (au_write(mAuditFd, token) < 0) 136 { 137 logInternalError("Error writing '%s' token (%s)", tokenName, strerror(errno)); 138 close(); 139 UnixError::throwMe(errno); 140 } 141} 142 143void 144AuditLogger::writeSubject() 145{ 146 assert(mClientInfoSet); 147 148 token_t *token; 149 150 // @@@ terminal ID is not carried in the audit trailer nowadays, but 151 // this code should be harmless: it replicates the current logic in 152 // audit_submit() 153 if (AU_IPv4 == mTerminalId.at_type) 154 token = au_to_subject32(mAuditId, mEuid, mEgid, mRuid, mRgid, mPid, mAuditSessionId, &mOldTerminalId); 155 else 156 token = au_to_subject_ex(mAuditId, mEuid, mEgid, mRuid, mRgid, mPid, mAuditSessionId, &mTerminalId); 157 writeToken(token, "subject"); 158} 159 160void 161AuditLogger::writeReturn(char status, int reterr) 162{ 163 writeToken(au_to_return32(status, reterr), "return"); 164} 165 166void 167AuditLogger::logSuccess() 168{ 169 if (false == open()) 170 return; 171 writeCommon(); 172 writeReturn(0, 0); 173 close(); 174} 175 176void 177AuditLogger::logFailure(const char *errMsg, int errcode) 178{ 179 if (false == open()) 180 return; 181 writeCommon(); 182 if (errMsg) 183 writeToken(au_to_text(errMsg), "evaluation error"); 184 writeReturn(EPERM, errcode); 185 close(); 186} 187 188// cribbed from audit_submit() 189void 190AuditLogger::logInternalError(const char *fmt, ...) 191{ 192 va_list ap; 193 char text[MAX_AUDITSTRING_LEN]; 194 195 if (fmt != NULL) 196 { 197 int error = errno; 198 va_start(ap, fmt); 199 (void)vsnprintf(text, MAX_AUDITSTRING_LEN, fmt, ap); 200 va_end(ap); 201 syslog(LOG_AUTH | LOG_ERR, "%s", text); 202 errno = error; 203 } 204} 205 206// 207// KeychainAuthLogger 208// 209const char *KeychainAuthLogger::sysKCAuthStr = "System keychain authorization"; 210const char *KeychainAuthLogger::unknownKCStr = "<unknown keychain>"; 211const char *KeychainAuthLogger::unknownItemStr = "<unknown item>"; 212 213KeychainAuthLogger::KeychainAuthLogger(const audit_token_t *srcToken, short auEvent) 214 : AuditLogger(srcToken, auEvent), mDatabase(unknownKCStr), 215 mItem(unknownItemStr) 216{ 217} 218 219KeychainAuthLogger::KeychainAuthLogger(const AuditToken &srcToken, short auEvent) 220 : AuditLogger(srcToken, auEvent), mDatabase(unknownKCStr), 221 mItem(unknownItemStr) 222{ 223} 224 225KeychainAuthLogger::KeychainAuthLogger(const audit_token_t *srcToken, short auEvent, const char *database, const char *item) 226 : AuditLogger(srcToken, auEvent) 227{ 228 setDbName(database); 229 setItemName(item); 230} 231 232KeychainAuthLogger::KeychainAuthLogger(const AuditToken &srcToken, short auEvent, const char *database, const char *item) 233 : AuditLogger(srcToken, auEvent) 234{ 235 setDbName(database); 236 setItemName(item); 237} 238 239void 240KeychainAuthLogger::setDbName(const char *database) 241{ 242 mDatabase = database ? database : unknownKCStr; 243} 244 245void 246KeychainAuthLogger::setItemName(const char *item) 247{ 248 mItem = item ? item : unknownItemStr; 249} 250 251void 252KeychainAuthLogger::writeCommon() 253{ 254 writeSubject(); 255 writeToken(au_to_text(sysKCAuthStr), sysKCAuthStr); 256 writeToken(au_to_text(mDatabase.c_str()), "keychain"); 257 writeToken(au_to_text(mItem.c_str()), "keychain item"); 258} 259 260 261// 262// RightLogger 263// 264const char *RightLogger::unknownRightStr = "<unknown right>"; 265 266void 267RightLogger::setRight(const string &rightName) 268{ 269 mRight.clear(); 270 mRight = rightName; 271} 272 273void 274RightLogger::setRight(const char *rightName) 275{ 276 if (rightName) // NULL bad for string class and au_to_text() 277 { 278 string tmpStr(rightName); // setRight() takes a string& 279 setRight(tmpStr); 280 } 281} 282 283 284// 285// AuthMechLogger 286// 287const char *AuthMechLogger::unknownMechStr = "<unknown mechanism>"; 288const char *AuthMechLogger::mechStr = "mechanism "; 289 290AuthMechLogger::AuthMechLogger(const AuditToken &srcToken, short auEvent) 291 : AuditLogger(srcToken, auEvent), RightLogger(), 292 mEvaluatingMechanism(false), mCurrentMechanism(unknownMechStr) 293{ 294} 295 296AuthMechLogger::AuthMechLogger(const audit_token_t *srcToken, short auEvent) 297 : AuditLogger(srcToken, auEvent), RightLogger(), 298 mEvaluatingMechanism(false), mCurrentMechanism(unknownMechStr) 299{ 300} 301 302void 303AuthMechLogger::setCurrentMechanism(const char *mech) 304{ 305 mCurrentMechanism.clear(); 306 if (NULL == mech) 307 { 308 mEvaluatingMechanism = false; 309 } 310 else 311 { 312 mCurrentMechanism = mech; 313 mEvaluatingMechanism = true; 314 } 315} 316 317void 318AuthMechLogger::writeCommon() 319{ 320 writeSubject(); 321 writeToken(au_to_text(mRight.c_str()), "right"); 322 if (true == mEvaluatingMechanism) 323 { 324 string tmpStr = mechStr; // mechStr includes a trailing space 325 tmpStr += mCurrentMechanism; 326 writeToken(au_to_text(tmpStr.c_str()), "mechanism"); 327 } 328} 329 330void 331AuthMechLogger::logInterrupt(const char *msg) 332{ 333 if (false == open()) 334 return; 335 writeCommon(); 336 if (msg) 337 writeToken(au_to_text(msg), "interrupt"); 338 writeReturn(0, 0); 339 close(); 340} 341 342// 343// RightAuthenticationLogger 344// 345const char *RightAuthenticationLogger::unknownUserStr = "<unknown user>"; 346const char *RightAuthenticationLogger::unknownClientStr = "<unknown client>"; 347const char *RightAuthenticationLogger::unknownAuthCreatorStr = "<unknown creator>"; 348const char *RightAuthenticationLogger::authenticatorStr = "known UID "; 349const char *RightAuthenticationLogger::clientStr = "client "; 350const char *RightAuthenticationLogger::authCreatorStr = "creator "; 351const char *RightAuthenticationLogger::authenticatedAsStr = "authenticated as "; 352const char *RightAuthenticationLogger::leastPrivStr = "least-privilege"; 353 354RightAuthenticationLogger::RightAuthenticationLogger(const AuditToken &srcToken, short auEvent) 355 : AuditLogger(srcToken, auEvent), RightLogger() 356{ 357} 358 359RightAuthenticationLogger::RightAuthenticationLogger(const audit_token_t *srcToken, short auEvent) 360 : AuditLogger(srcToken, auEvent), RightLogger() 361{ 362} 363 364void 365RightAuthenticationLogger::writeCommon() 366{ 367 writeSubject(); 368 writeToken(au_to_text(mRight.c_str()), "right"); 369} 370 371void 372RightAuthenticationLogger::logSuccess(uid_t authenticator, uid_t target, const char *targetName) 373{ 374 if (false == open()) 375 return; 376 writeCommon(); 377 378 // au_to_arg32() is really meant for auditing syscall arguments; 379 // we're slightly abusing it to get descriptive strings for free. 380 writeToken(au_to_arg32(1, authenticatorStr, authenticator), "authenticator"); 381 string tmpStr(authenticatedAsStr); 382 // targetName shouldn't be NULL on a successful authentication, but allow 383 // for programmer screwups 384 tmpStr += targetName ? targetName : unknownUserStr; 385 writeToken(au_to_arg32(2, tmpStr.c_str(), target), "target"); 386 writeReturn(0, 0); 387 close(); 388} 389 390void 391RightAuthenticationLogger::logAuthorizationResult(const char *client, const char *authCreator, int errcode) 392{ 393 if (false == open()) 394 return; 395 writeCommon(); 396 string tmpStr(clientStr); 397 tmpStr += client ? client : unknownClientStr; 398 writeToken(au_to_text(tmpStr.c_str()), "Authorization client"); 399 tmpStr.clear(); 400 tmpStr = authCreatorStr; 401 tmpStr += authCreator ? authCreator : unknownAuthCreatorStr; 402 writeToken(au_to_text(tmpStr.c_str()), "Authorization creator"); 403 if (errAuthorizationSuccess == errcode) 404 writeReturn(0, 0); 405 else 406 writeReturn(EPERM, errcode); 407 close(); 408} 409 410void 411RightAuthenticationLogger::logLeastPrivilege(uid_t userId, bool isAuthorizingUser) 412{ 413 if (false == open()) 414 return; 415 writeCommon(); 416 writeToken(au_to_text(leastPrivStr), leastPrivStr); 417 writeReturn(0, 0); 418 close(); 419} 420 421void 422RightAuthenticationLogger::logFailure(uid_t authenticator, const char *targetName) 423{ 424 if (false == open()) 425 return; 426 writeCommon(); 427 writeToken(au_to_arg32(1, authenticatorStr, authenticator), "authenticator"); 428 if (NULL == targetName) 429 writeToken(au_to_text(unknownUserStr), "target username"); 430 else 431 writeToken(au_to_text(targetName), "target username"); 432 // @@@ EAUTH more appropriate, but !defined for _POSIX_C_SOURCE 433 writeReturn(EPERM, errAuthorizationDenied); 434 close(); 435} 436 437} // namespace Securityd 438 439} // namespace CommonCriteria 440 441} // namespace Security 442