#include "ccaudit.h"
#include "debugging.h"
#include "process.h"
#include "authtoken.h"
#include <Security/Authorization.h>
#include <Security/AuthorizationPlugin.h>
#include <bsm/libbsm.h>
AUTHD_DEFINE_LOG
struct _ccaudit_s {
__AUTH_BASE_STRUCT_HEADER__;
int fd;
int32_t event;
auth_token_t auth;
process_t proc;
audit_info_s auditInfo;
au_tid_t tid;
};
static void
_ccaudit_finalizer(CFTypeRef value)
{
ccaudit_t ccaudit = (ccaudit_t)value;
CFReleaseNull(ccaudit->auth);
CFReleaseNull(ccaudit->proc);
}
AUTH_TYPE_INSTANCE(ccaudit,
.init = NULL,
.copy = NULL,
.finalize = _ccaudit_finalizer,
.equal = NULL,
.hash = NULL,
.copyFormattingDesc = NULL,
.copyDebugDesc = NULL
);
static CFTypeID ccaudit_get_type_id() {
static CFTypeID type_id = _kCFRuntimeNotATypeID;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
type_id = _CFRuntimeRegisterClass(&_auth_type_ccaudit);
});
return type_id;
}
ccaudit_t
ccaudit_create(process_t proc, auth_token_t auth, int32_t event)
{
ccaudit_t ccaudit = NULL;
require(auth != NULL, done);
ccaudit = (ccaudit_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, ccaudit_get_type_id(), AUTH_CLASS_SIZE(ccaudit), NULL);
require(ccaudit != NULL, done);
ccaudit->auth = (auth_token_t)CFRetain(auth);
ccaudit->proc = (process_t)CFRetain(proc);
ccaudit->fd = -1;
ccaudit->event = event;
ccaudit->auditInfo = *auth_token_get_audit_info(auth);
ccaudit->tid.port = ccaudit->auditInfo.tid;
done:
return ccaudit;
}
static bool _enabled()
{
static dispatch_once_t onceToken;
static bool enabled = false;
dispatch_once(&onceToken, ^{
int acond = au_get_state();
switch (acond) {
case AUC_NOAUDIT:
break;
case AUC_AUDITING:
enabled = true;
break;
default:
os_log_error(AUTHD_LOG, "ccaudit: error checking auditing status (%d)", acond);
}
});
return enabled;
}
static bool _open(ccaudit_t ccaudit)
{
if (!_enabled()) {
return false;
}
if (-1 != ccaudit->fd)
return true;
if ((ccaudit->fd = au_open()) < 0) {
os_log_error(AUTHD_LOG, "ccaudit: au_open() failed (%{public}s)", strerror(errno));
return false;
}
return true;
}
static void _close(ccaudit_t ccaudit)
{
if (-1 != ccaudit->fd) {
int err = au_close(ccaudit->fd, AU_TO_WRITE, (short)ccaudit->event);
ccaudit->fd = -1;
if (err < 0) {
os_log_error(AUTHD_LOG, "ccaudit: au_close() failed; record not committed");
}
}
}
static bool _write(ccaudit_t ccaudit, token_t * token, const char * name)
{
const char *tokenName = name ? name : "<unidentified>";
if (NULL == token)
{
os_log_error(AUTHD_LOG, "ccaudit: invalid '%{public}s' token", tokenName);
return false;
}
if (au_write(ccaudit->fd, token) < 0) {
os_log_error(AUTHD_LOG, "ccaudit: error writing '%{public}s' token (%{public}s)", tokenName, strerror(errno));
return false;
}
return true;
}
static bool _subject(ccaudit_t ccaudit)
{
token_t * token = au_to_subject32(ccaudit->auditInfo.auid, ccaudit->auditInfo.euid, ccaudit->auditInfo.egid,
ccaudit->auditInfo.ruid, ccaudit->auditInfo.rgid, ccaudit->auditInfo.pid, ccaudit->auditInfo.asid, &ccaudit->tid);
return _write(ccaudit, token, "subject");
}
void ccaudit_log_authorization(ccaudit_t ccaudit, const char * right, OSStatus err)
{
if (!_open(ccaudit)) {
return;
}
char buf[PATH_MAX+1];
_subject(ccaudit);
_write(ccaudit, au_to_text(right), "right");
snprintf(buf, sizeof(buf), "client %s", process_get_code_url(ccaudit->proc));
_write(ccaudit, au_to_text(buf), "Authorization client");
snprintf(buf, sizeof(buf), "creator %s", auth_token_get_code_url(ccaudit->auth));
_write(ccaudit, au_to_text(buf), "Authorization creator");
if (auth_token_least_privileged(ccaudit->auth)) {
_write(ccaudit, au_to_text("least-privilege"), "least-privilege");
}
if (err == errAuthorizationSuccess) {
_write(ccaudit, au_to_return32(0, 0), "return");
} else {
_write(ccaudit, au_to_return32(EPERM, (uint32_t)err), "return");
}
_close(ccaudit);
}
void ccaudit_log_success(ccaudit_t ccaudit, credential_t cred, const char * right)
{
if (!_open(ccaudit)) {
return;
}
char buf[PATH_MAX+1];
_subject(ccaudit);
_write(ccaudit, au_to_text(right), "right");
_write(ccaudit, au_to_arg32(1, "known UID ", auth_token_get_uid(ccaudit->auth)), "authenticator");
snprintf(buf, sizeof(buf), "authenticated as %s", credential_get_name(cred));
_write(ccaudit, au_to_arg32(2, buf, credential_get_uid(cred)), "target");
_write(ccaudit, au_to_return32(0, 0), "return");
_close(ccaudit);
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
void ccaudit_log_failure(ccaudit_t ccaudit, const char * credName, const char * right)
{
if (!_open(ccaudit)) {
return;
}
_subject(ccaudit);
_write(ccaudit, au_to_text(right), "right");
_write(ccaudit, au_to_arg32(1, "authenticated as ", auth_token_get_uid(ccaudit->auth)), "authenticator");
_write(ccaudit, au_to_text("<unknown user>"), "target username");
_write(ccaudit, au_to_return32(EPERM, (uint32_t)errAuthorizationDenied), "return");
_close(ccaudit);
}
#pragma clang diagnostic pop
void ccaudit_log_mechanism(ccaudit_t ccaudit, const char * right, const char * mech, uint32_t status, const char * interrupted)
{
if (!_open(ccaudit)) {
return;
}
char buf[PATH_MAX+1];
_subject(ccaudit);
_write(ccaudit, au_to_text(right), "right");
snprintf(buf, sizeof(buf), "mechanism %s", mech);
_write(ccaudit, au_to_text(buf), "mechanism");
if (interrupted) {
_write(ccaudit, au_to_text(interrupted), "interrupt");
}
if (status == kAuthorizationResultAllow) {
_write(ccaudit, au_to_return32(0, 0), "return");
} else {
_write(ccaudit, au_to_return32(EPERM, (uint32_t)status), "return");
}
_close(ccaudit);
}
void ccaudit_log(ccaudit_t ccaudit, const char * right, const char * msg, OSStatus err)
{
if (!_open(ccaudit)) {
return;
}
_subject(ccaudit);
_write(ccaudit, au_to_text(right), "right");
if (msg) {
_write(ccaudit, au_to_text(msg), "evaluation error");
}
if (err == errAuthorizationSuccess) {
_write(ccaudit, au_to_return32(0, 0), "return");
} else {
_write(ccaudit, au_to_return32(EPERM, (uint32_t)err), "return");
}
_close(ccaudit);
}