1/* 2 * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com> 3 * Copyright (c) 2009 Christian S.J. Peron 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <config.h> 19 20#include <sys/types.h> 21 22#include <bsm/audit.h> 23#include <bsm/libbsm.h> 24#include <bsm/audit_uevents.h> 25 26#include <stdio.h> 27#include <string.h> 28#include <stdarg.h> 29#include <pwd.h> 30#include <errno.h> 31#include <unistd.h> 32 33#include "error.h" 34#include "bsm_audit.h" 35 36/* 37 * Solaris auditon() returns EINVAL if BSM audit not configured. 38 * OpenBSM returns ENOSYS for unimplemented options. 39 */ 40#ifdef __sun 41# define AUDIT_NOT_CONFIGURED EINVAL 42#else 43# define AUDIT_NOT_CONFIGURED ENOSYS 44#endif 45 46static int 47audit_sudo_selected(int sf) 48{ 49 auditinfo_addr_t ainfo_addr; 50 struct au_mask *mask; 51 auditinfo_t ainfo; 52 int rc, sorf; 53 54 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) { 55 if (errno == ENOSYS) { 56 if (getaudit(&ainfo) < 0) 57 error(1, "getaudit: failed"); 58 mask = &ainfo.ai_mask; 59 } else 60 error(1, "getaudit: failed"); 61 } else 62 mask = &ainfo_addr.ai_mask; 63 sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE; 64 rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD); 65 return rc; 66} 67 68void 69bsm_audit_success(char **exec_args) 70{ 71 auditinfo_addr_t ainfo_addr; 72 auditinfo_t ainfo; 73 token_t *tok; 74 au_id_t auid; 75 long au_cond; 76 int aufd; 77 pid_t pid; 78 79 pid = getpid(); 80 /* 81 * If we are not auditing, don't cut an audit record; just return. 82 */ 83 if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) { 84 if (errno == AUDIT_NOT_CONFIGURED) 85 return; 86 error(1, "Could not determine audit condition"); 87 } 88 if (au_cond == AUC_NOAUDIT) 89 return; 90 /* 91 * Check to see if the preselection masks are interested in seeing 92 * this event. 93 */ 94 if (!audit_sudo_selected(0)) 95 return; 96 if (getauid(&auid) < 0) 97 error(1, "getauid failed"); 98 if ((aufd = au_open()) == -1) 99 error(1, "au_open: failed"); 100 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 101 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(), 102 getuid(), pid, pid, &ainfo_addr.ai_termid); 103 } else if (errno == ENOSYS) { 104 /* 105 * NB: We should probably watch out for ERANGE here. 106 */ 107 if (getaudit(&ainfo) < 0) 108 error(1, "getaudit: failed"); 109 tok = au_to_subject(auid, geteuid(), getegid(), getuid(), 110 getuid(), pid, pid, &ainfo.ai_termid); 111 } else 112 error(1, "getaudit: failed"); 113 if (tok == NULL) 114 error(1, "au_to_subject: failed"); 115 au_write(aufd, tok); 116 tok = au_to_exec_args(exec_args); 117 if (tok == NULL) 118 error(1, "au_to_exec_args: failed"); 119 au_write(aufd, tok); 120 tok = au_to_return32(0, 0); 121 if (tok == NULL) 122 error(1, "au_to_return32: failed"); 123 au_write(aufd, tok); 124 if (au_close(aufd, 1, AUE_sudo) == -1) 125 error(1, "unable to commit audit record"); 126} 127 128void 129bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap) 130{ 131 auditinfo_addr_t ainfo_addr; 132 auditinfo_t ainfo; 133 char text[256]; 134 token_t *tok; 135 long au_cond; 136 au_id_t auid; 137 pid_t pid; 138 int aufd; 139 140 pid = getpid(); 141 /* 142 * If we are not auditing, don't cut an audit record; just return. 143 */ 144 if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { 145 if (errno == AUDIT_NOT_CONFIGURED) 146 return; 147 error(1, "Could not determine audit condition"); 148 } 149 if (au_cond == AUC_NOAUDIT) 150 return; 151 if (!audit_sudo_selected(1)) 152 return; 153 if (getauid(&auid) < 0) 154 error(1, "getauid: failed"); 155 if ((aufd = au_open()) == -1) 156 error(1, "au_open: failed"); 157 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 158 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(), 159 getuid(), pid, pid, &ainfo_addr.ai_termid); 160 } else if (errno == ENOSYS) { 161 if (getaudit(&ainfo) < 0) 162 error(1, "getaudit: failed"); 163 tok = au_to_subject(auid, geteuid(), getegid(), getuid(), 164 getuid(), pid, pid, &ainfo.ai_termid); 165 } else 166 error(1, "getaudit: failed"); 167 if (tok == NULL) 168 error(1, "au_to_subject: failed"); 169 au_write(aufd, tok); 170 if (exec_args != NULL) { 171 tok = au_to_exec_args(exec_args); 172 if (tok == NULL) 173 log_error(0, "au_to_exec_args: failed"); 174 au_write(aufd, tok); 175 } 176 tok = au_to_exec_args(exec_args); 177 if (tok == NULL) 178 error(1, "au_to_exec_args: failed"); 179 au_write(aufd, tok); 180 (void) vsnprintf(text, sizeof(text), fmt, ap); 181 tok = au_to_text(text); 182 if (tok == NULL) 183 error(1, "au_to_text: failed"); 184 au_write(aufd, tok); 185 tok = au_to_return32(EPERM, 1); 186 if (tok == NULL) 187 error(1, "au_to_return32: failed"); 188 au_write(aufd, tok); 189 if (au_close(aufd, 1, AUE_sudo) == -1) 190 error(1, "unable to commit audit record"); 191} 192