]> git.saurik.com Git - apple/security.git/blobdiff - securityd/src/ccaudit_extensions.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / securityd / src / ccaudit_extensions.cpp
diff --git a/securityd/src/ccaudit_extensions.cpp b/securityd/src/ccaudit_extensions.cpp
new file mode 100644 (file)
index 0000000..2ffcd5e
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ *  ccaudit_extensions.cpp
+ *  securityd
+ *
+ *  Created by G H on 3/24/09.
+ *  Copyright (c) 2009 Apple Inc. All Rights Reserved.
+ *
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>                  // vsnprintf()
+#include <stdarg.h>                 // va_start(), et al.
+#include <syslog.h>
+#include <string.h>                 // memcpy()
+#include <bsm/audit_uevents.h>      // AUE_ssauth*
+#include <bsm/libbsm.h>
+#include <security_utilities/errors.h>
+#include <security_utilities/ccaudit.h>
+#include "ccaudit_extensions.h"
+
+namespace Security
+{
+    
+namespace CommonCriteria
+{
+
+namespace Securityd 
+{
+
+//
+// AuditLogger
+//
+AuditLogger::AuditLogger(const audit_token_t *srcToken, short auEvent)
+    : mAuditFd(-1), mEvent(auEvent), mClientInfoSet(false)
+{
+    setClientInfo(srcToken); 
+}
+
+AuditLogger::AuditLogger(const AuditToken &srcToken, short auEvent)
+    : mAuditFd(-1), mEvent(auEvent), mClientInfoSet(false)
+{
+    setClientInfo(srcToken); 
+}
+    
+AuditLogger::~AuditLogger()
+{
+    close();
+}
+
+bool 
+AuditLogger::open()
+{
+    if (-1 != mAuditFd)
+        return true;
+    
+    // @@@  use audit_get_cond() when it's available
+    int acond = au_get_state();
+    switch (acond)
+    {
+        case AUC_NOAUDIT:
+            return false;
+        case AUC_AUDITING:
+            break;
+        default:
+            logInternalError("error checking auditing status (%d)", acond);
+            UnixError::throwMe(acond);  // assume it's a Unix error
+    }
+    if ((mAuditFd = au_open()) < 0)
+    {
+        logInternalError("au_open() failed (%s)", strerror(errno));
+        UnixError::throwMe(errno);
+    }
+    return true;
+}
+
+void 
+AuditLogger::close(bool writeLog/* = true*/)
+{
+    if (-1 != mAuditFd)
+    {
+        int keep = writeLog == true ?  AU_TO_WRITE : AU_TO_NO_WRITE;
+        int error = au_close(mAuditFd, keep, mEvent);
+        mAuditFd = -1;
+        if (writeLog == true && error < 0)
+        {
+            logInternalError("au_close() failed; record not committed");
+            UnixError::throwMe(error);
+        }
+    }
+}
+
+void 
+AuditLogger::setClientInfo(const audit_token_t *srcToken)
+{
+    assert(srcToken);
+    audit_token_to_au32(*srcToken, &mAuditId, &mEuid, &mEgid, &mRuid, &mRgid, &mPid, &mAuditSessionId, &mOldTerminalId);
+
+    mTerminalId.at_type = AU_IPv4;
+    mTerminalId.at_addr[0] = mOldTerminalId.machine;
+    mTerminalId.at_port = mOldTerminalId.port;
+    
+    mClientInfoSet = true;
+}
+
+void 
+AuditLogger::setClientInfo(const AuditToken &srcToken)
+{
+    mAuditId = srcToken.auditId();
+    mEuid = srcToken.euid();
+    mEgid = srcToken.egid();
+    mRuid = srcToken.ruid();
+    mRgid = srcToken.rgid();
+    mPid = srcToken.pid();
+    mAuditSessionId = srcToken.sessionId();
+    memcpy(&mOldTerminalId, &(srcToken.terminalId()), sizeof(mOldTerminalId));
+    
+    mTerminalId.at_type = AU_IPv4;
+    mTerminalId.at_addr[0] = mOldTerminalId.machine;
+    mTerminalId.at_port = mOldTerminalId.port;
+    
+    mClientInfoSet = true;
+}
+
+void
+AuditLogger::writeToken(token_t *token, const char *name)
+{
+    const char *tokenName = name ? name : "<unidentified>";
+    if (NULL == token)
+    {
+        logInternalError("Invalid '%s' token", tokenName);
+        close();
+        UnixError::throwMe(EPERM);      // per audit_submit()
+    }
+    if (au_write(mAuditFd, token) < 0)
+    {
+        logInternalError("Error writing '%s' token (%s)", tokenName, strerror(errno));
+        close();
+        UnixError::throwMe(errno);
+    }
+}
+
+void 
+AuditLogger::writeSubject()
+{
+    assert(mClientInfoSet);
+
+    token_t *token;
+
+    // @@@  terminal ID is not carried in the audit trailer nowadays, but 
+    // this code should be harmless: it replicates the current logic in 
+    // audit_submit()
+    if (AU_IPv4 == mTerminalId.at_type)
+        token = au_to_subject32(mAuditId, mEuid, mEgid, mRuid, mRgid, mPid, mAuditSessionId, &mOldTerminalId);
+    else 
+        token = au_to_subject_ex(mAuditId, mEuid, mEgid, mRuid, mRgid, mPid, mAuditSessionId, &mTerminalId);
+    writeToken(token, "subject");
+}
+
+void 
+AuditLogger::writeReturn(char status, int reterr)
+{
+    writeToken(au_to_return32(status, reterr), "return");
+}
+
+void 
+AuditLogger::logSuccess()
+{
+    if (false == open())
+        return;
+    writeCommon();
+    writeReturn(0, 0);
+    close();
+}
+
+void
+AuditLogger::logFailure(const char *errMsg, int errcode)
+{
+    if (false == open())
+        return;
+    writeCommon();
+    if (errMsg)
+        writeToken(au_to_text(errMsg), "evaluation error");
+    writeReturn(EPERM, errcode);
+    close();
+}
+
+// cribbed from audit_submit()
+void
+AuditLogger::logInternalError(const char *fmt, ...)
+{
+    va_list ap;
+    char text[MAX_AUDITSTRING_LEN];
+    
+    if (fmt != NULL)
+    {
+        int error = errno;
+        va_start(ap, fmt);
+        (void)vsnprintf(text, MAX_AUDITSTRING_LEN, fmt, ap);
+        va_end(ap);
+        syslog(LOG_AUTH | LOG_ERR, "%s", text);
+        errno = error;
+    }
+}
+
+//
+// KeychainAuthLogger
+//
+const char *KeychainAuthLogger::sysKCAuthStr = "System keychain authorization";
+const char *KeychainAuthLogger::unknownKCStr = "<unknown keychain>";
+const char *KeychainAuthLogger::unknownItemStr = "<unknown item>";
+
+KeychainAuthLogger::KeychainAuthLogger(const audit_token_t *srcToken, short auEvent)
+    : AuditLogger(srcToken, auEvent), mDatabase(unknownKCStr), 
+      mItem(unknownItemStr)
+{
+}
+
+KeychainAuthLogger::KeychainAuthLogger(const AuditToken &srcToken, short auEvent)
+    : AuditLogger(srcToken, auEvent), mDatabase(unknownKCStr), 
+      mItem(unknownItemStr)
+{
+}
+    
+KeychainAuthLogger::KeychainAuthLogger(const audit_token_t *srcToken, short auEvent, const char *database, const char *item)
+    : AuditLogger(srcToken, auEvent)
+{
+    setDbName(database);
+    setItemName(item);
+}
+
+KeychainAuthLogger::KeychainAuthLogger(const AuditToken &srcToken, short auEvent, const char *database, const char *item)
+    : AuditLogger(srcToken, auEvent)
+{
+    setDbName(database);
+    setItemName(item);
+}
+
+void
+KeychainAuthLogger::setDbName(const char *database)
+{
+    mDatabase = database ? database : unknownKCStr;
+}
+
+void
+KeychainAuthLogger::setItemName(const char *item)
+{
+    mItem = item ? item : unknownItemStr;
+}
+
+void 
+KeychainAuthLogger::writeCommon()
+{
+    writeSubject();
+    writeToken(au_to_text(sysKCAuthStr), sysKCAuthStr);
+    writeToken(au_to_text(mDatabase.c_str()), "keychain");
+    writeToken(au_to_text(mItem.c_str()), "keychain item");
+}
+
+
+//
+// RightLogger
+//
+const char *RightLogger::unknownRightStr = "<unknown right>";
+
+void 
+RightLogger::setRight(const string &rightName)  
+{
+    mRight.clear(); 
+    mRight = rightName;
+}
+
+void 
+RightLogger::setRight(const char *rightName)
+{
+    if (rightName)      // NULL bad for string class and au_to_text()
+    {
+        string tmpStr(rightName);   // setRight() takes a string&
+        setRight(tmpStr);
+    }
+}
+    
+
+//
+// AuthMechLogger
+//
+const char *AuthMechLogger::unknownMechStr = "<unknown mechanism>";
+const char *AuthMechLogger::mechStr = "mechanism ";
+
+AuthMechLogger::AuthMechLogger(const AuditToken &srcToken, short auEvent)
+    : AuditLogger(srcToken, auEvent), RightLogger(), 
+      mEvaluatingMechanism(false), mCurrentMechanism(unknownMechStr)
+{
+}
+
+AuthMechLogger::AuthMechLogger(const audit_token_t *srcToken, short auEvent)
+    : AuditLogger(srcToken, auEvent), RightLogger(), 
+      mEvaluatingMechanism(false), mCurrentMechanism(unknownMechStr)
+{
+}
+
+void 
+AuthMechLogger::setCurrentMechanism(const char *mech)
+{ 
+    mCurrentMechanism.clear();
+    if (NULL == mech)
+    {
+        mEvaluatingMechanism = false;
+    }
+    else 
+    {
+        mCurrentMechanism = mech; 
+        mEvaluatingMechanism = true; 
+    }
+}
+
+void 
+AuthMechLogger::writeCommon()
+{
+    writeSubject();
+    writeToken(au_to_text(mRight.c_str()), "right");
+    if (true == mEvaluatingMechanism)
+    {
+        string tmpStr = mechStr;    // mechStr includes a trailing space
+        tmpStr += mCurrentMechanism;
+        writeToken(au_to_text(tmpStr.c_str()), "mechanism");
+    }
+}
+
+void 
+AuthMechLogger::logInterrupt(const char *msg)
+{
+    if (false == open())
+        return;
+    writeCommon();
+    if (msg)
+        writeToken(au_to_text(msg), "interrupt");
+    writeReturn(0, 0);
+    close();
+}
+
+//
+// RightAuthenticationLogger
+//
+const char *RightAuthenticationLogger::unknownUserStr = "<unknown user>";
+const char *RightAuthenticationLogger::unknownClientStr = "<unknown client>";
+const char *RightAuthenticationLogger::unknownAuthCreatorStr = "<unknown creator>";
+const char *RightAuthenticationLogger::authenticatorStr = "known UID ";
+const char *RightAuthenticationLogger::clientStr = "client ";
+const char *RightAuthenticationLogger::authCreatorStr = "creator ";
+const char *RightAuthenticationLogger::authenticatedAsStr = "authenticated as ";
+const char *RightAuthenticationLogger::leastPrivStr = "least-privilege";
+
+RightAuthenticationLogger::RightAuthenticationLogger(const AuditToken &srcToken, short auEvent)
+    : AuditLogger(srcToken, auEvent), RightLogger()
+{
+}
+
+RightAuthenticationLogger::RightAuthenticationLogger(const audit_token_t *srcToken, short auEvent)
+    : AuditLogger(srcToken, auEvent), RightLogger()
+{
+}
+
+void 
+RightAuthenticationLogger::writeCommon()
+{
+    writeSubject();
+    writeToken(au_to_text(mRight.c_str()), "right");
+}
+
+void
+RightAuthenticationLogger::logSuccess(uid_t authenticator, uid_t target, const char *targetName)
+{
+    if (false == open())
+        return;
+    writeCommon();
+    
+    // au_to_arg32() is really meant for auditing syscall arguments; 
+    // we're slightly abusing it to get descriptive strings for free.  
+    writeToken(au_to_arg32(1, authenticatorStr, authenticator), "authenticator");
+    string tmpStr(authenticatedAsStr);
+    // targetName shouldn't be NULL on a successful authentication, but allow
+    // for programmer screwups
+    tmpStr += targetName ? targetName : unknownUserStr;
+    writeToken(au_to_arg32(2, tmpStr.c_str(), target), "target");
+    writeReturn(0, 0);
+    close();
+}
+
+void 
+RightAuthenticationLogger::logAuthorizationResult(const char *client, const char *authCreator, int errcode)
+{
+    if (false == open())
+        return;
+    writeCommon();
+    string tmpStr(clientStr);
+    tmpStr += client ? client : unknownClientStr;
+    writeToken(au_to_text(tmpStr.c_str()), "Authorization client");
+    tmpStr.clear();
+    tmpStr = authCreatorStr;
+    tmpStr += authCreator ? authCreator : unknownAuthCreatorStr;
+    writeToken(au_to_text(tmpStr.c_str()), "Authorization creator");
+    if (errAuthorizationSuccess == errcode)
+        writeReturn(0, 0);
+    else
+        writeReturn(EPERM, errcode);
+    close();
+}
+
+void 
+RightAuthenticationLogger::logLeastPrivilege(uid_t userId, bool isAuthorizingUser)
+{
+    if (false == open())
+        return;
+    writeCommon();
+    writeToken(au_to_text(leastPrivStr), leastPrivStr);
+    writeReturn(0, 0);
+    close();
+}
+
+void
+RightAuthenticationLogger::logFailure(uid_t authenticator, const char *targetName)
+{
+    if (false == open())
+        return;
+    writeCommon();
+    writeToken(au_to_arg32(1, authenticatorStr, authenticator), "authenticator");
+    if (NULL == targetName)
+        writeToken(au_to_text(unknownUserStr), "target username");
+    else
+        writeToken(au_to_text(targetName), "target username");
+    // @@@  EAUTH more appropriate, but !defined for _POSIX_C_SOURCE
+    writeReturn(EPERM, errAuthorizationDenied);
+    close();
+}
+
+}   // namespace Securityd
+    
+}   // namespace CommonCriteria
+
+}   // namespace Security