1 /* 2 * Copyright (c) 2004 Apple Computer, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_wrappers.c#18 $ 30 */ 31 32 #ifdef __APPLE__ 33 #define _SYS_AUDIT_H /* Prevent include of sys/audit.h. */ 34 #endif 35 36 #include <sys/param.h> 37 #include <sys/stat.h> 38 39 #ifdef __APPLE__ 40 #include <sys/queue.h> /* Our bsm/audit.h doesn't include queue.h. */ 41 #endif 42 43 #include <sys/sysctl.h> 44 45 #include <bsm/libbsm.h> 46 47 #include <unistd.h> 48 #include <syslog.h> 49 #include <string.h> 50 #include <errno.h> 51 52 /* These are not advertised in libbsm.h */ 53 int audit_set_terminal_port(dev_t *p); 54 int audit_set_terminal_host(uint32_t *m); 55 56 int 57 audit_set_terminal_port(dev_t *p) 58 { 59 struct stat st; 60 61 if (p == NULL) 62 return (kAUBadParamErr); 63 64 #ifdef NODEV 65 *p = NODEV; 66 #else 67 *p = -1; 68 #endif 69 70 /* for /usr/bin/login, try fstat() first */ 71 if (fstat(STDIN_FILENO, &st) != 0) { 72 if (errno != EBADF) { 73 syslog(LOG_ERR, "fstat() failed (%s)", 74 strerror(errno)); 75 return (kAUStatErr); 76 } 77 if (stat("/dev/console", &st) != 0) { 78 syslog(LOG_ERR, "stat() failed (%s)", 79 strerror(errno)); 80 return (kAUStatErr); 81 } 82 } 83 *p = st.st_rdev; 84 return (kAUNoErr); 85 } 86 87 int 88 audit_set_terminal_host(uint32_t *m) 89 { 90 91 #ifdef KERN_HOSTID 92 int name[2] = { CTL_KERN, KERN_HOSTID }; 93 size_t len; 94 95 if (m == NULL) 96 return (kAUBadParamErr); 97 *m = 0; 98 len = sizeof(*m); 99 if (sysctl(name, 2, m, &len, NULL, 0) != 0) { 100 syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno)); 101 return (kAUSysctlErr); 102 } 103 return (kAUNoErr); 104 #else 105 *m = -1; 106 return (kAUNoErr); 107 #endif 108 } 109 110 int 111 audit_set_terminal_id(au_tid_t *tid) 112 { 113 int ret; 114 115 if (tid == NULL) 116 return (kAUBadParamErr); 117 if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr) 118 return (ret); 119 return (audit_set_terminal_host(&tid->machine)); 120 } 121 122 /* 123 * This is OK for those callers who have only one token to write. If you have 124 * multiple tokens that logically form part of the same audit record, you need 125 * to use the existing au_open()/au_write()/au_close() API: 126 * 127 * aufd = au_open(); 128 * tok = au_to_random_token_1(...); 129 * au_write(aufd, tok); 130 * tok = au_to_random_token_2(...); 131 * au_write(aufd, tok); 132 * ... 133 * au_close(aufd, 1, AUE_your_event_type); 134 * 135 * Assumes, like all wrapper calls, that the caller has previously checked 136 * that auditing is enabled via the audit_get_state() call. 137 * 138 * XXX: Should be more robust against bad arguments. 139 */ 140 int 141 audit_write(short event_code, token_t *subject, token_t *misctok, char retval, 142 int errcode) 143 { 144 int aufd; 145 char *func = "audit_write()"; 146 token_t *rettok; 147 148 if ((aufd = au_open()) == -1) { 149 au_free_token(subject); 150 au_free_token(misctok); 151 syslog(LOG_ERR, "%s: au_open() failed", func); 152 return (kAUOpenErr); 153 } 154 155 /* Save subject. */ 156 if (subject && au_write(aufd, subject) == -1) { 157 au_free_token(subject); 158 au_free_token(misctok); 159 (void)au_close(aufd, 0, event_code); 160 syslog(LOG_ERR, "%s: write of subject failed", func); 161 return (kAUWriteSubjectTokErr); 162 } 163 164 /* Save the event-specific token. */ 165 if (misctok && au_write(aufd, misctok) == -1) { 166 au_free_token(misctok); 167 (void)au_close(aufd, 0, event_code); 168 syslog(LOG_ERR, "%s: write of caller token failed", func); 169 return (kAUWriteCallerTokErr); 170 } 171 172 /* Tokenize and save the return value. */ 173 if ((rettok = au_to_return32(retval, errcode)) == NULL) { 174 (void)au_close(aufd, 0, event_code); 175 syslog(LOG_ERR, "%s: au_to_return32() failed", func); 176 return (kAUMakeReturnTokErr); 177 } 178 179 if (au_write(aufd, rettok) == -1) { 180 au_free_token(rettok); 181 (void)au_close(aufd, 0, event_code); 182 syslog(LOG_ERR, "%s: write of return code failed", func); 183 return (kAUWriteReturnTokErr); 184 } 185 186 /* 187 * au_close()'s second argument is "keep": if keep == 0, the record is 188 * discarded. We assume the caller wouldn't have bothered with this 189 * function if it hadn't already decided to keep the record. 190 */ 191 if (au_close(aufd, 1, event_code) < 0) { 192 syslog(LOG_ERR, "%s: au_close() failed", func); 193 return (kAUCloseErr); 194 } 195 196 return (kAUNoErr); 197 } 198 199 /* 200 * Same caveats as audit_write(). In addition, this function explicitly 201 * assumes success; use audit_write_failure() on error. 202 */ 203 int 204 audit_write_success(short event_code, token_t *tok, au_id_t auid, uid_t euid, 205 gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 206 au_tid_t *tid) 207 { 208 char *func = "audit_write_success()"; 209 token_t *subject = NULL; 210 211 /* Tokenize and save subject. */ 212 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, 213 tid); 214 if (subject == NULL) { 215 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 216 return kAUMakeSubjectTokErr; 217 } 218 219 return (audit_write(event_code, subject, tok, 0, 0)); 220 } 221 222 /* 223 * Same caveats as audit_write(). In addition, this function explicitly 224 * assumes success; use audit_write_failure_self() on error. 225 */ 226 int 227 audit_write_success_self(short event_code, token_t *tok) 228 { 229 token_t *subject; 230 char *func = "audit_write_success_self()"; 231 232 if ((subject = au_to_me()) == NULL) { 233 syslog(LOG_ERR, "%s: au_to_me() failed", func); 234 return (kAUMakeSubjectTokErr); 235 } 236 237 return (audit_write(event_code, subject, tok, 0, 0)); 238 } 239 240 /* 241 * Same caveats as audit_write(). In addition, this function explicitly 242 * assumes failure; use audit_write_success() otherwise. 243 * 244 * XXX This should let the caller pass an error return value rather than 245 * hard-coding -1. 246 */ 247 int 248 audit_write_failure(short event_code, char *errmsg, int errcode, au_id_t auid, 249 uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 250 au_tid_t *tid) 251 { 252 char *func = "audit_write_failure()"; 253 token_t *subject, *errtok; 254 255 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid); 256 if (subject == NULL) { 257 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 258 return (kAUMakeSubjectTokErr); 259 } 260 261 /* tokenize and save the error message */ 262 if ((errtok = au_to_text(errmsg)) == NULL) { 263 au_free_token(subject); 264 syslog(LOG_ERR, "%s: au_to_text() failed", func); 265 return (kAUMakeTextTokErr); 266 } 267 268 return (audit_write(event_code, subject, errtok, -1, errcode)); 269 } 270 271 /* 272 * Same caveats as audit_write(). In addition, this function explicitly 273 * assumes failure; use audit_write_success_self() otherwise. 274 * 275 * XXX This should let the caller pass an error return value rather than 276 * hard-coding -1. 277 */ 278 int 279 audit_write_failure_self(short event_code, char *errmsg, int errret) 280 { 281 char *func = "audit_write_failure_self()"; 282 token_t *subject, *errtok; 283 284 if ((subject = au_to_me()) == NULL) { 285 syslog(LOG_ERR, "%s: au_to_me() failed", func); 286 return (kAUMakeSubjectTokErr); 287 } 288 /* tokenize and save the error message */ 289 if ((errtok = au_to_text(errmsg)) == NULL) { 290 au_free_token(subject); 291 syslog(LOG_ERR, "%s: au_to_text() failed", func); 292 return (kAUMakeTextTokErr); 293 } 294 return (audit_write(event_code, subject, errtok, -1, errret)); 295 } 296 297 /* 298 * For auditing errors during login. Such errors are implicitly 299 * non-attributable (i.e., not ascribable to any user). 300 * 301 * Assumes, like all wrapper calls, that the caller has previously checked 302 * that auditing is enabled via the audit_get_state() call. 303 */ 304 int 305 audit_write_failure_na(short event_code, char *errmsg, int errret, uid_t euid, 306 uid_t egid, pid_t pid, au_tid_t *tid) 307 { 308 309 return (audit_write_failure(event_code, errmsg, errret, -1, euid, 310 egid, -1, -1, pid, -1, tid)); 311 } 312 313 /* END OF au_write() WRAPPERS */ 314 315 #ifdef __APPLE__ 316 void 317 audit_token_to_au32(audit_token_t atoken, uid_t *auidp, uid_t *euidp, 318 gid_t *egidp, uid_t *ruidp, gid_t *rgidp, pid_t *pidp, au_asid_t *asidp, 319 au_tid_t *tidp) 320 { 321 322 if (auidp != NULL) 323 *auidp = (uid_t)atoken.val[0]; 324 if (euidp != NULL) 325 *euidp = (uid_t)atoken.val[1]; 326 if (egidp != NULL) 327 *egidp = (gid_t)atoken.val[2]; 328 if (ruidp != NULL) 329 *ruidp = (uid_t)atoken.val[3]; 330 if (rgidp != NULL) 331 *rgidp = (gid_t)atoken.val[4]; 332 if (pidp != NULL) 333 *pidp = (pid_t)atoken.val[5]; 334 if (asidp != NULL) 335 *asidp = (au_asid_t)atoken.val[6]; 336 if (tidp != NULL) { 337 audit_set_terminal_host(&tidp->machine); 338 tidp->port = (dev_t)atoken.val[7]; 339 } 340 } 341 #endif /* !__APPLE__ */ 342