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 */ 50 static FILE *fp = NULL; 51 static char linestr[AU_LINE_MAX]; 52 static const char *classdelim = ":"; 53 54 #ifdef HAVE_PTHREAD_MUTEX_LOCK 55 static 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 */ 62 static struct au_class_ent * 63 classfromstr(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 */ 100 static struct au_class_ent * 101 getauclassent_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 133 struct au_class_ent * 134 getauclassent_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 148 struct au_class_ent * 149 getauclassent(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 */ 176 static void 177 setauclass_locked(void) 178 { 179 180 if (fp != NULL) 181 fseek(fp, 0, SEEK_SET); 182 } 183 184 void 185 setauclass(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 */ 200 struct au_class_ent * 201 getauclassnam_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 226 struct au_class_ent * 227 getauclassnam(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 */ 248 struct au_class_ent * 249 getauclassnum_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 267 struct au_class_ent * 268 getauclassnum(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 */ 286 void 287 endauclass(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