1104349Sphk/*- 2104349Sphk * Copyright (c) 2004 Apple Inc. 3104349Sphk * Copyright (c) 2006 Robert N. M. Watson 4104349Sphk * All rights reserved. 5104349Sphk * 6104349Sphk * Redistribution and use in source and binary forms, with or without 7104349Sphk * modification, are permitted provided that the following conditions 8104349Sphk * are met: 9104349Sphk * 1. Redistributions of source code must retain the above copyright 10104349Sphk * notice, this list of conditions and the following disclaimer. 11104349Sphk * 2. Redistributions in binary form must reproduce the above copyright 12104349Sphk * notice, this list of conditions and the following disclaimer in the 13104349Sphk * documentation and/or other materials provided with the distribution. 14104349Sphk * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15104349Sphk * its contributors may be used to endorse or promote products derived 16104349Sphk * from this software without specific prior written permission. 17104349Sphk * 18104349Sphk * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 19104349Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20104349Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21104349Sphk * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 22104349Sphk * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23104349Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24104349Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25104349Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26104349Sphk * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27104349Sphk * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28104349Sphk * POSSIBILITY OF SUCH DAMAGE. 29104349Sphk */ 30104349Sphk 31104349Sphk#include <config/config.h> 32104349Sphk 33104349Sphk#include <bsm/libbsm.h> 34104349Sphk 35104349Sphk#include <string.h> 36104349Sphk#ifdef HAVE_PTHREAD_MUTEX_LOCK 37104349Sphk#include <pthread.h> 38104349Sphk#endif 39104349Sphk#include <stdio.h> 40104349Sphk#include <stdlib.h> 41104349Sphk 42247296Sdelphij#ifndef HAVE_STRLCPY 43247296Sdelphij#include <compat/strlcpy.h> 44247296Sdelphij#endif 45104349Sphk 46104349Sphk/* 47104349Sphk * Parse the contents of the audit_class file to return struct au_class_ent 48104349Sphk * entries. 49104349Sphk */ 50104349Sphkstatic FILE *fp = NULL; 51104349Sphkstatic char linestr[AU_LINE_MAX]; 52104349Sphkstatic const char *classdelim = ":"; 53104349Sphk 54247296Sdelphij#ifdef HAVE_PTHREAD_MUTEX_LOCK 55247296Sdelphijstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 56247296Sdelphij#endif 57247296Sdelphij 58104349Sphk/* 59104349Sphk * Parse a single line from the audit_class file passed in str to the struct 60104349Sphk * au_class_ent elements; store the result in c. 61104349Sphk */ 62104349Sphkstatic struct au_class_ent * 63104349Sphkclassfromstr(char *str, struct au_class_ent *c) 64104349Sphk{ 65104349Sphk char *classname, *classdesc, *classflag; 66104349Sphk char *last; 67104349Sphk 68104349Sphk /* Each line contains flag:name:desc. */ 69104349Sphk classflag = strtok_r(str, classdelim, &last); 70247296Sdelphij classname = strtok_r(NULL, classdelim, &last); 71247296Sdelphij classdesc = strtok_r(NULL, classdelim, &last); 72247296Sdelphij 73104349Sphk if ((classflag == NULL) || (classname == NULL) || (classdesc == NULL)) 74104349Sphk return (NULL); 75104349Sphk 76104349Sphk /* 77104349Sphk * Check for very large classnames. 78104349Sphk */ 79104349Sphk if (strlen(classname) >= AU_CLASS_NAME_MAX) 80104349Sphk return (NULL); 81104349Sphk strlcpy(c->ac_name, classname, AU_CLASS_NAME_MAX); 82104349Sphk 83104349Sphk /* 84104349Sphk * Check for very large class description. 85104349Sphk */ 86104349Sphk if (strlen(classdesc) >= AU_CLASS_DESC_MAX) 87104349Sphk return (NULL); 88104349Sphk strlcpy(c->ac_desc, classdesc, AU_CLASS_DESC_MAX); 89104349Sphk c->ac_class = strtoul(classflag, (char **) NULL, 0); 90104349Sphk 91104349Sphk return (c); 92178848Scokane} 93178848Scokane 94178848Scokane/* 95104349Sphk * Return the next au_class_ent structure from the file setauclass should be 96104349Sphk * called before invoking this function for the first time. 97104349Sphk * 98247296Sdelphij * Must be called with mutex held. 99104349Sphk */ 100104349Sphkstatic struct au_class_ent * 101247296Sdelphijgetauclassent_r_locked(struct au_class_ent *c) 102104349Sphk{ 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