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