1/*- 2 * Copyright (c) 2004 Apple Inc. 3 * Copyright (c) 2006 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <config/config.h> 32 33#include <bsm/libbsm.h> 34 35#include <string.h> 36#ifdef HAVE_PTHREAD_MUTEX_LOCK 37#include <pthread.h> 38#endif 39#include <stdio.h> 40#include <stdlib.h> 41 42#ifndef HAVE_STRLCPY 43#include <compat/strlcpy.h> 44#endif 45 46 47/* 48 * Parse the contents of the audit_event file to return 49 * au_event_ent entries 50 */ 51static FILE *fp = NULL; 52static char linestr[AU_LINE_MAX]; 53static const char *eventdelim = ":"; 54 55#ifdef HAVE_PTHREAD_MUTEX_LOCK 56static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 57#endif 58 59/* 60 * Parse one line from the audit_event file into the au_event_ent structure. 61 */ 62static struct au_event_ent * 63eventfromstr(char *str, struct au_event_ent *e) 64{ 65 char *evno, *evname, *evdesc, *evclass; 66 struct au_mask evmask; 67 char *last; 68 69 evno = strtok_r(str, eventdelim, &last); 70 evname = strtok_r(NULL, eventdelim, &last); 71 evdesc = strtok_r(NULL, eventdelim, &last); 72 evclass = strtok_r(NULL, eventdelim, &last); 73 74 if ((evno == NULL) || (evname == NULL)) 75 return (NULL); 76 77 if (strlen(evname) >= AU_EVENT_NAME_MAX) 78 return (NULL); 79 80 strlcpy(e->ae_name, evname, AU_EVENT_NAME_MAX); 81 if (evdesc != NULL) { 82 if (strlen(evdesc) >= AU_EVENT_DESC_MAX) 83 return (NULL); 84 strlcpy(e->ae_desc, evdesc, AU_EVENT_DESC_MAX); 85 } else 86 strlcpy(e->ae_desc, "", AU_EVENT_DESC_MAX); 87 88 e->ae_number = atoi(evno); 89 90 /* 91 * Find out the mask that corresponds to the given list of classes. 92 */ 93 if (evclass != NULL) { 94 if (getauditflagsbin(evclass, &evmask) != 0) 95 e->ae_class = 0; 96 else 97 e->ae_class = evmask.am_success; 98 } else 99 e->ae_class = 0; 100 101 return (e); 102} 103 104/* 105 * Rewind the audit_event file. 106 */ 107static void 108setauevent_locked(void) 109{ 110 111 if (fp != NULL) 112 fseek(fp, 0, SEEK_SET); 113} 114 115void 116setauevent(void) 117{ 118 119#ifdef HAVE_PTHREAD_MUTEX_LOCK 120 pthread_mutex_lock(&mutex); 121#endif 122 setauevent_locked(); 123#ifdef HAVE_PTHREAD_MUTEX_LOCK 124 pthread_mutex_unlock(&mutex); 125#endif 126} 127 128/* 129 * Close the open file pointers. 130 */ 131void 132endauevent(void) 133{ 134 135#ifdef HAVE_PTHREAD_MUTEX_LOCK 136 pthread_mutex_lock(&mutex); 137#endif 138 if (fp != NULL) { 139 fclose(fp); 140 fp = NULL; 141 } 142#ifdef HAVE_PTHREAD_MUTEX_LOCK 143 pthread_mutex_unlock(&mutex); 144#endif 145} 146 147/* 148 * Enumerate the au_event_ent entries. 149 */ 150static struct au_event_ent * 151getauevent_r_locked(struct au_event_ent *e) 152{ 153 char *nl; 154 155 if ((fp == NULL) && ((fp = fopen(AUDIT_EVENT_FILE, "r")) == NULL)) 156 return (NULL); 157 158 while (1) { 159 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) 160 return (NULL); 161 162 /* Remove new lines. */ 163 if ((nl = strrchr(linestr, '\n')) != NULL) 164 *nl = '\0'; 165 166 /* Skip comments. */ 167 if (linestr[0] == '#') 168 continue; 169 170 /* Get the next event structure. */ 171 if (eventfromstr(linestr, e) == NULL) 172 return (NULL); 173 break; 174 } 175 176 return (e); 177} 178 179struct au_event_ent * 180getauevent_r(struct au_event_ent *e) 181{ 182 struct au_event_ent *ep; 183 184#ifdef HAVE_PTHREAD_MUTEX_LOCK 185 pthread_mutex_lock(&mutex); 186#endif 187 ep = getauevent_r_locked(e); 188#ifdef HAVE_PTHREAD_MUTEX_LOCK 189 pthread_mutex_unlock(&mutex); 190#endif 191 return (ep); 192} 193 194struct au_event_ent * 195getauevent(void) 196{ 197 static char event_ent_name[AU_EVENT_NAME_MAX]; 198 static char event_ent_desc[AU_EVENT_DESC_MAX]; 199 static struct au_event_ent e; 200 201 bzero(&e, sizeof(e)); 202 bzero(event_ent_name, sizeof(event_ent_name)); 203 bzero(event_ent_desc, sizeof(event_ent_desc)); 204 e.ae_name = event_ent_name; 205 e.ae_desc = event_ent_desc; 206 return (getauevent_r(&e)); 207} 208 209/* 210 * Search for an audit event structure having the given event name. 211 * 212 * XXXRW: Why accept NULL name? 213 */ 214static struct au_event_ent * 215getauevnam_r_locked(struct au_event_ent *e, const char *name) 216{ 217 char *nl; 218 219 if (name == NULL) 220 return (NULL); 221 222 /* Rewind to beginning of the file. */ 223 setauevent_locked(); 224 225 if ((fp == NULL) && ((fp = fopen(AUDIT_EVENT_FILE, "r")) == NULL)) 226 return (NULL); 227 228 while (fgets(linestr, AU_LINE_MAX, fp) != NULL) { 229 /* Remove new lines. */ 230 if ((nl = strrchr(linestr, '\n')) != NULL) 231 *nl = '\0'; 232 233 if (eventfromstr(linestr, e) != NULL) { 234 if (strcmp(name, e->ae_name) == 0) 235 return (e); 236 } 237 } 238 239 return (NULL); 240} 241 242struct au_event_ent * 243getauevnam_r(struct au_event_ent *e, const char *name) 244{ 245 struct au_event_ent *ep; 246 247#ifdef HAVE_PTHREAD_MUTEX_LOCK 248 pthread_mutex_lock(&mutex); 249#endif 250 ep = getauevnam_r_locked(e, name); 251#ifdef HAVE_PTHREAD_MUTEX_LOCK 252 pthread_mutex_unlock(&mutex); 253#endif 254 return (ep); 255} 256 257struct au_event_ent * 258getauevnam(const char *name) 259{ 260 static char event_ent_name[AU_EVENT_NAME_MAX]; 261 static char event_ent_desc[AU_EVENT_DESC_MAX]; 262 static struct au_event_ent e; 263 264 bzero(&e, sizeof(e)); 265 bzero(event_ent_name, sizeof(event_ent_name)); 266 bzero(event_ent_desc, sizeof(event_ent_desc)); 267 e.ae_name = event_ent_name; 268 e.ae_desc = event_ent_desc; 269 return (getauevnam_r(&e, name)); 270} 271 272/* 273 * Search for an audit event structure having the given event number. 274 */ 275static struct au_event_ent * 276getauevnum_r_locked(struct au_event_ent *e, au_event_t event_number) 277{ 278 char *nl; 279 280 /* Rewind to beginning of the file. */ 281 setauevent_locked(); 282 283 if ((fp == NULL) && ((fp = fopen(AUDIT_EVENT_FILE, "r")) == NULL)) 284 return (NULL); 285 286 while (fgets(linestr, AU_LINE_MAX, fp) != NULL) { 287 /* Remove new lines. */ 288 if ((nl = strrchr(linestr, '\n')) != NULL) 289 *nl = '\0'; 290 291 if (eventfromstr(linestr, e) != NULL) { 292 if (event_number == e->ae_number) 293 return (e); 294 } 295 } 296 297 return (NULL); 298} 299 300struct au_event_ent * 301getauevnum_r(struct au_event_ent *e, au_event_t event_number) 302{ 303 struct au_event_ent *ep; 304 305#ifdef HAVE_PTHREAD_MUTEX_LOCK 306 pthread_mutex_lock(&mutex); 307#endif 308 ep = getauevnum_r_locked(e, event_number); 309#ifdef HAVE_PTHREAD_MUTEX_LOCK 310 pthread_mutex_unlock(&mutex); 311#endif 312 return (ep); 313} 314 315struct au_event_ent * 316getauevnum(au_event_t event_number) 317{ 318 static char event_ent_name[AU_EVENT_NAME_MAX]; 319 static char event_ent_desc[AU_EVENT_DESC_MAX]; 320 static struct au_event_ent e; 321 322 bzero(&e, sizeof(e)); 323 bzero(event_ent_name, sizeof(event_ent_name)); 324 bzero(event_ent_desc, sizeof(event_ent_desc)); 325 e.ae_name = event_ent_name; 326 e.ae_desc = event_ent_desc; 327 return (getauevnum_r(&e, event_number)); 328} 329 330/* 331 * Search for an audit_event entry with a given event_name and returns the 332 * corresponding event number. 333 */ 334au_event_t * 335getauevnonam_r(au_event_t *ev, const char *event_name) 336{ 337 static char event_ent_name[AU_EVENT_NAME_MAX]; 338 static char event_ent_desc[AU_EVENT_DESC_MAX]; 339 static struct au_event_ent e, *ep; 340 341 bzero(event_ent_name, sizeof(event_ent_name)); 342 bzero(event_ent_desc, sizeof(event_ent_desc)); 343 bzero(&e, sizeof(e)); 344 e.ae_name = event_ent_name; 345 e.ae_desc = event_ent_desc; 346 347 ep = getauevnam_r(&e, event_name); 348 if (ep == NULL) 349 return (NULL); 350 351 *ev = e.ae_number; 352 return (ev); 353} 354 355au_event_t * 356getauevnonam(const char *event_name) 357{ 358 static au_event_t event; 359 360 return (getauevnonam_r(&event, event_name)); 361} 362