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 * Parse the contents of the audit_class file to return struct au_class_ent 48 * entries. 49 */ 50static FILE *fp = NULL; 51static char linestr[AU_LINE_MAX]; 52static const char *classdelim = ":"; 53 54#ifdef HAVE_PTHREAD_MUTEX_LOCK 55static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 56#endif 57 58/* 59 * Parse a single line from the audit_class file passed in str to the struct 60 * au_class_ent elements; store the result in c. 61 */ 62static struct au_class_ent * 63classfromstr(char *str, struct au_class_ent *c) 64{ 65 char *classname, *classdesc, *classflag; 66 char *last; 67 68 /* Each line contains flag:name:desc. */ 69 classflag = strtok_r(str, classdelim, &last); 70 classname = strtok_r(NULL, classdelim, &last); 71 classdesc = strtok_r(NULL, classdelim, &last); 72 73 if ((classflag == NULL) || (classname == NULL) || (classdesc == NULL)) 74 return (NULL); 75 76 /* 77 * Check for very large classnames. 78 */ 79 if (strlen(classname) >= AU_CLASS_NAME_MAX) 80 return (NULL); 81 strlcpy(c->ac_name, classname, AU_CLASS_NAME_MAX); 82 83 /* 84 * Check for very large class description. 85 */ 86 if (strlen(classdesc) >= AU_CLASS_DESC_MAX) 87 return (NULL); 88 strlcpy(c->ac_desc, classdesc, AU_CLASS_DESC_MAX); 89 c->ac_class = strtoul(classflag, (char **) NULL, 0); 90 91 return (c); 92} 93 94/* 95 * Return the next au_class_ent structure from the file setauclass should be 96 * called before invoking this function for the first time. 97 * 98 * Must be called with mutex held. 99 */ 100static struct au_class_ent * 101getauclassent_r_locked(struct au_class_ent *c) 102{ 103 char *tokptr, *nl; 104 105 if ((fp == NULL) && ((fp = fopen(AUDIT_CLASS_FILE, "r")) == NULL)) 106 return (NULL); 107 108 /* 109 * Read until next non-comment line is found, or EOF. 110 */ 111 while (1) { 112 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) 113 return (NULL); 114 115 /* Skip comments. */ 116 if (linestr[0] == '#') 117 continue; 118 119 /* Remove trailing new line character. */ 120 if ((nl = strrchr(linestr, '\n')) != NULL) 121 *nl = '\0'; 122 123 /* Parse tokptr to au_class_ent components. */ 124 tokptr = linestr; 125 if (classfromstr(tokptr, c) == NULL) 126 return (NULL); 127 break; 128 } 129 130 return (c); 131} 132 133struct au_class_ent * 134getauclassent_r(struct au_class_ent *c) 135{ 136 struct au_class_ent *cp; 137 138#ifdef HAVE_PTHREAD_MUTEX_LOCK 139 pthread_mutex_lock(&mutex); 140#endif 141 cp = getauclassent_r_locked(c); 142#ifdef HAVE_PTHREAD_MUTEX_LOCK 143 pthread_mutex_unlock(&mutex); 144#endif 145 return (cp); 146} 147 148struct au_class_ent * 149getauclassent(void) 150{ 151 static char class_ent_name[AU_CLASS_NAME_MAX]; 152 static char class_ent_desc[AU_CLASS_DESC_MAX]; 153 static struct au_class_ent c, *cp; 154 155 bzero(&c, sizeof(c)); 156 bzero(class_ent_name, sizeof(class_ent_name)); 157 bzero(class_ent_desc, sizeof(class_ent_desc)); 158 c.ac_name = class_ent_name; 159 c.ac_desc = class_ent_desc; 160 161#ifdef HAVE_PTHREAD_MUTEX_LOCK 162 pthread_mutex_lock(&mutex); 163#endif 164 cp = getauclassent_r_locked(&c); 165#ifdef HAVE_PTHREAD_MUTEX_LOCK 166 pthread_mutex_unlock(&mutex); 167#endif 168 return (cp); 169} 170 171/* 172 * Rewind to the beginning of the enumeration. 173 * 174 * Must be called with mutex held. 175 */ 176static void 177setauclass_locked(void) 178{ 179 180 if (fp != NULL) 181 fseek(fp, 0, SEEK_SET); 182} 183 184void 185setauclass(void) 186{ 187 188#ifdef HAVE_PTHREAD_MUTEX_LOCK 189 pthread_mutex_lock(&mutex); 190#endif 191 setauclass_locked(); 192#ifdef HAVE_PTHREAD_MUTEX_LOCK 193 pthread_mutex_unlock(&mutex); 194#endif 195} 196 197/* 198 * Return the next au_class_entry having the given class name. 199 */ 200struct au_class_ent * 201getauclassnam_r(struct au_class_ent *c, const char *name) 202{ 203 struct au_class_ent *cp; 204 205 if (name == NULL) 206 return (NULL); 207 208#ifdef HAVE_PTHREAD_MUTEX_LOCK 209 pthread_mutex_lock(&mutex); 210#endif 211 setauclass_locked(); 212 while ((cp = getauclassent_r_locked(c)) != NULL) { 213 if (strcmp(name, cp->ac_name) == 0) { 214#ifdef HAVE_PTHREAD_MUTEX_LOCK 215 pthread_mutex_unlock(&mutex); 216#endif 217 return (cp); 218 } 219 } 220#ifdef HAVE_PTHREAD_MUTEX_LOCK 221 pthread_mutex_unlock(&mutex); 222#endif 223 return (NULL); 224} 225 226struct au_class_ent * 227getauclassnam(const char *name) 228{ 229 static char class_ent_name[AU_CLASS_NAME_MAX]; 230 static char class_ent_desc[AU_CLASS_DESC_MAX]; 231 static struct au_class_ent c; 232 233 bzero(&c, sizeof(c)); 234 bzero(class_ent_name, sizeof(class_ent_name)); 235 bzero(class_ent_desc, sizeof(class_ent_desc)); 236 c.ac_name = class_ent_name; 237 c.ac_desc = class_ent_desc; 238 239 return (getauclassnam_r(&c, name)); 240} 241 242 243/* 244 * Return the next au_class_entry having the given class number. 245 * 246 * OpenBSM extension. 247 */ 248struct au_class_ent * 249getauclassnum_r(struct au_class_ent *c, au_class_t class_number) 250{ 251 struct au_class_ent *cp; 252 253#ifdef HAVE_PTHREAD_MUTEX_LOCK 254 pthread_mutex_lock(&mutex); 255#endif 256 setauclass_locked(); 257 while ((cp = getauclassent_r_locked(c)) != NULL) { 258 if (class_number == cp->ac_class) 259 return (cp); 260 } 261#ifdef HAVE_PTHREAD_MUTEX_LOCK 262 pthread_mutex_unlock(&mutex); 263#endif 264 return (NULL); 265} 266 267struct au_class_ent * 268getauclassnum(au_class_t class_number) 269{ 270 static char class_ent_name[AU_CLASS_NAME_MAX]; 271 static char class_ent_desc[AU_CLASS_DESC_MAX]; 272 static struct au_class_ent c; 273 274 bzero(&c, sizeof(c)); 275 bzero(class_ent_name, sizeof(class_ent_name)); 276 bzero(class_ent_desc, sizeof(class_ent_desc)); 277 c.ac_name = class_ent_name; 278 c.ac_desc = class_ent_desc; 279 280 return (getauclassnum_r(&c, class_number)); 281} 282 283/* 284 * audit_class processing is complete; close any open files. 285 */ 286void 287endauclass(void) 288{ 289 290#ifdef HAVE_PTHREAD_MUTEX_LOCK 291 pthread_mutex_lock(&mutex); 292#endif 293 if (fp != NULL) { 294 fclose(fp); 295 fp = NULL; 296 } 297#ifdef HAVE_PTHREAD_MUTEX_LOCK 298 pthread_mutex_unlock(&mutex); 299#endif 300} 301