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#14 $ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/stat.h> 34 #include <sys/sysctl.h> 35 36 #include <bsm/libbsm.h> 37 38 #include <unistd.h> 39 #include <syslog.h> 40 #include <string.h> 41 #include <errno.h> 42 43 /* These are not advertised in libbsm.h */ 44 int audit_set_terminal_port(dev_t *p); 45 int audit_set_terminal_host(uint32_t *m); 46 47 int 48 audit_set_terminal_port(dev_t *p) 49 { 50 struct stat st; 51 52 if (p == NULL) 53 return (kAUBadParamErr); 54 55 *p = NODEV; 56 57 /* for /usr/bin/login, try fstat() first */ 58 if (fstat(STDIN_FILENO, &st) != 0) { 59 if (errno != EBADF) { 60 syslog(LOG_ERR, "fstat() failed (%s)", 61 strerror(errno)); 62 return (kAUStatErr); 63 } 64 if (stat("/dev/console", &st) != 0) { 65 syslog(LOG_ERR, "stat() failed (%s)", 66 strerror(errno)); 67 return (kAUStatErr); 68 } 69 } 70 *p = st.st_rdev; 71 return (kAUNoErr); 72 } 73 74 int 75 audit_set_terminal_host(uint32_t *m) 76 { 77 int name[2] = { CTL_KERN, KERN_HOSTID }; 78 size_t len; 79 80 if (m == NULL) 81 return (kAUBadParamErr); 82 *m = 0; 83 len = sizeof(*m); 84 if (sysctl(name, 2, m, &len, NULL, 0) != 0) { 85 syslog(LOG_ERR, "sysctl() failed (%s)", strerror(errno)); 86 return (kAUSysctlErr); 87 } 88 return (kAUNoErr); 89 } 90 91 int 92 audit_set_terminal_id(au_tid_t *tid) 93 { 94 int ret; 95 96 if (tid == NULL) 97 return (kAUBadParamErr); 98 if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr) 99 return (ret); 100 return (audit_set_terminal_host(&tid->machine)); 101 } 102 103 /* 104 * This is OK for those callers who have only one token to write. If you have 105 * multiple tokens that logically form part of the same audit record, you need 106 * to use the existing au_open()/au_write()/au_close() API: 107 * 108 * aufd = au_open(); 109 * tok = au_to_random_token_1(...); 110 * au_write(aufd, tok); 111 * tok = au_to_random_token_2(...); 112 * au_write(aufd, tok); 113 * ... 114 * au_close(aufd, 1, AUE_your_event_type); 115 * 116 * Assumes, like all wrapper calls, that the caller has previously checked 117 * that auditing is enabled via the audit_get_state() call. 118 * 119 * XXX: Should be more robust against bad arguments. 120 */ 121 int 122 audit_write(short event_code, token_t *subject, token_t *misctok, char retval, 123 int errcode) 124 { 125 int aufd; 126 char *func = "audit_write()"; 127 token_t *rettok; 128 129 if ((aufd = au_open()) == -1) { 130 au_free_token(subject); 131 au_free_token(misctok); 132 syslog(LOG_ERR, "%s: au_open() failed", func); 133 return (kAUOpenErr); 134 } 135 136 /* Save subject. */ 137 if (subject && au_write(aufd, subject) == -1) { 138 au_free_token(subject); 139 au_free_token(misctok); 140 (void)au_close(aufd, 0, event_code); 141 syslog(LOG_ERR, "%s: write of subject failed", func); 142 return (kAUWriteSubjectTokErr); 143 } 144 145 /* Save the event-specific token. */ 146 if (misctok && au_write(aufd, misctok) == -1) { 147 au_free_token(misctok); 148 (void)au_close(aufd, 0, event_code); 149 syslog(LOG_ERR, "%s: write of caller token failed", func); 150 return (kAUWriteCallerTokErr); 151 } 152 153 /* Tokenize and save the return value. */ 154 if ((rettok = au_to_return32(retval, errcode)) == NULL) { 155 (void)au_close(aufd, 0, event_code); 156 syslog(LOG_ERR, "%s: au_to_return32() failed", func); 157 return (kAUMakeReturnTokErr); 158 } 159 160 if (au_write(aufd, rettok) == -1) { 161 au_free_token(rettok); 162 (void)au_close(aufd, 0, event_code); 163 syslog(LOG_ERR, "%s: write of return code failed", func); 164 return (kAUWriteReturnTokErr); 165 } 166 167 /* 168 * au_close()'s second argument is "keep": if keep == 0, the record is 169 * discarded. We assume the caller wouldn't have bothered with this 170 * function if it hadn't already decided to keep the record. 171 */ 172 if (au_close(aufd, 1, event_code) < 0) { 173 syslog(LOG_ERR, "%s: au_close() failed", func); 174 return (kAUCloseErr); 175 } 176 177 return (kAUNoErr); 178 } 179 180 /* 181 * Same caveats as audit_write(). In addition, this function explicitly 182 * assumes success; use audit_write_failure() on error. 183 */ 184 int 185 audit_write_success(short event_code, token_t *tok, au_id_t auid, uid_t euid, 186 gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 187 au_tid_t *tid) 188 { 189 char *func = "audit_write_success()"; 190 token_t *subject = NULL; 191 192 /* Tokenize and save subject. */ 193 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, 194 tid); 195 if (subject == NULL) { 196 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 197 return kAUMakeSubjectTokErr; 198 } 199 200 return (audit_write(event_code, subject, tok, 0, 0)); 201 } 202 203 /* 204 * Same caveats as audit_write(). In addition, this function explicitly 205 * assumes success; use audit_write_failure_self() on error. 206 */ 207 int 208 audit_write_success_self(short event_code, token_t *tok) 209 { 210 token_t *subject; 211 char *func = "audit_write_success_self()"; 212 213 if ((subject = au_to_me()) == NULL) { 214 syslog(LOG_ERR, "%s: au_to_me() failed", func); 215 return (kAUMakeSubjectTokErr); 216 } 217 218 return (audit_write(event_code, subject, tok, 0, 0)); 219 } 220 221 /* 222 * Same caveats as audit_write(). In addition, this function explicitly 223 * assumes failure; use audit_write_success() otherwise. 224 * 225 * XXX This should let the caller pass an error return value rather than 226 * hard-coding -1. 227 */ 228 int 229 audit_write_failure(short event_code, char *errmsg, int errcode, au_id_t auid, 230 uid_t euid, gid_t egid, uid_t ruid, gid_t rgid, pid_t pid, au_asid_t sid, 231 au_tid_t *tid) 232 { 233 char *func = "audit_write_failure()"; 234 token_t *subject, *errtok; 235 236 subject = au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid, tid); 237 if (subject == NULL) { 238 syslog(LOG_ERR, "%s: au_to_subject32() failed", func); 239 return (kAUMakeSubjectTokErr); 240 } 241 242 /* tokenize and save the error message */ 243 if ((errtok = au_to_text(errmsg)) == NULL) { 244 au_free_token(subject); 245 syslog(LOG_ERR, "%s: au_to_text() failed", func); 246 return (kAUMakeTextTokErr); 247 } 248 249 return (audit_write(event_code, subject, errtok, -1, errcode)); 250 } 251 252 /* 253 * Same caveats as audit_write(). In addition, this function explicitly 254 * assumes failure; use audit_write_success_self() otherwise. 255 * 256 * XXX This should let the caller pass an error return value rather than 257 * hard-coding -1. 258 */ 259 int 260 audit_write_failure_self(short event_code, char *errmsg, int errret) 261 { 262 char *func = "audit_write_failure_self()"; 263 token_t *subject, *errtok; 264 265 if ((subject = au_to_me()) == NULL) { 266 syslog(LOG_ERR, "%s: au_to_me() failed", func); 267 return (kAUMakeSubjectTokErr); 268 } 269 /* tokenize and save the error message */ 270 if ((errtok = au_to_text(errmsg)) == NULL) { 271 au_free_token(subject); 272 syslog(LOG_ERR, "%s: au_to_text() failed", func); 273 return (kAUMakeTextTokErr); 274 } 275 return (audit_write(event_code, subject, errtok, -1, errret)); 276 } 277 278 /* 279 * For auditing errors during login. Such errors are implicitly 280 * non-attributable (i.e., not ascribable to any user). 281 * 282 * Assumes, like all wrapper calls, that the caller has previously checked 283 * that auditing is enabled via the audit_get_state() call. 284 */ 285 int 286 audit_write_failure_na(short event_code, char *errmsg, int errret, uid_t euid, 287 uid_t egid, pid_t pid, au_tid_t *tid) 288 { 289 290 return (audit_write_failure(event_code, errmsg, errret, -1, euid, 291 egid, -1, -1, pid, -1, tid)); 292 } 293 294 /* END OF au_write() WRAPPERS */ 295 296 #ifdef __APPLE__ 297 void 298 audit_token_to_au32(audit_token_t atoken, uid_t *auidp, uid_t *euidp, 299 gid_t *egidp, uid_t *ruidp, gid_t *rgidp, pid_t *pidp, au_asid_t *asidp, 300 au_tid_t *tidp) 301 { 302 303 if (auidp != NULL) 304 *auidp = (uid_t)atoken.val[0]; 305 if (euidp != NULL) 306 *euidp = (uid_t)atoken.val[1]; 307 if (egidp != NULL) 308 *egidp = (gid_t)atoken.val[2]; 309 if (ruidp != NULL) 310 *ruidp = (uid_t)atoken.val[3]; 311 if (rgidp != NULL) 312 *rgidp = (gid_t)atoken.val[4]; 313 if (pidp != NULL) 314 *pidp = (pid_t)atoken.val[5]; 315 if (asidp != NULL) 316 *asidp = (au_asid_t)atoken.val[6]; 317 if (tidp != NULL) { 318 audit_set_terminal_host(&tidp->machine); 319 tidp->port = (dev_t)atoken.val[7]; 320 } 321 } 322 #endif /* !__APPLE__ */ 323