1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * Interfaces to audit_event(5) (/etc/security/audit_event) 30 */ 31 32 /* 33 * This routine is obsolete. I have removed its inclusion by removing 34 * the .o from the makefile. Please use cacheauevent() or any of the 35 * getauev* routines. 36 */ 37 38 #include <sys/types.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <bsm/audit.h> 44 #include <bsm/libbsm.h> 45 #include <synch.h> 46 47 /* 48 * Macros to produce a quoted string containing the value of a 49 * preprocessor macro. For example, if SIZE is defined to be 256, 50 * VAL2STR(SIZE) is "256". This is used to construct format 51 * strings for scanf-family functions below. 52 */ 53 #define QUOTE(x) #x 54 #define VAL2STR(x) QUOTE(x) 55 56 static au_class_t flagstohex(char *); 57 58 static char au_event_fname[PATH_MAX] = AUDITEVENTFILE; 59 static FILE *au_event_file = (FILE *)0; 60 static mutex_t mutex_eventfile = DEFAULTMUTEX; 61 static mutex_t mutex_eventcache = DEFAULTMUTEX; 62 /* 63 * If an error occurs during the call to cacheauclassnam() inside 64 * flagstohex() any return value could be seen as a valid class mask so 65 * the following global variable, cacheauclass_failure, is set to indicate 66 * that an error has occurred. 67 */ 68 static int cacheauclass_failure = 0; 69 70 #ifdef DEBUG2 71 void 72 printevent(au_event_ent_t *p_event) 73 { 74 (void) printf("%d:%s:%s:%d\n", p_event->ae_number, p_event->ae_name, 75 p_event->ae_desc, p_event->ae_class); 76 (void) fflush(stdout); 77 } 78 #endif 79 80 void 81 setauevent() 82 { 83 (void) mutex_lock(&mutex_eventfile); 84 if (au_event_file) { 85 (void) fseek(au_event_file, 0L, 0); 86 } 87 (void) mutex_unlock(&mutex_eventfile); 88 } 89 90 void 91 endauevent() 92 { 93 (void) mutex_lock(&mutex_eventfile); 94 if (au_event_file) { 95 (void) fclose(au_event_file); 96 au_event_file = (FILE *)0; 97 } 98 (void) mutex_unlock(&mutex_eventfile); 99 } 100 101 au_event_ent_t * 102 getauevent() 103 { 104 static au_event_ent_t au_event_entry; 105 static char ename[AU_EVENT_NAME_MAX]; 106 static char edesc[AU_EVENT_DESC_MAX]; 107 108 /* initialize au_event_entry structure */ 109 au_event_entry.ae_name = ename; 110 au_event_entry.ae_desc = edesc; 111 112 return (getauevent_r(&au_event_entry)); 113 } 114 115 au_event_ent_t * 116 getauevent_r(au_event_ent_t *au_event_entry) 117 { 118 int i, error = 0, found = 0; 119 char *s, input[AU_EVENT_LINE_MAX]; 120 char trim_buf[AU_EVENT_NAME_MAX+1]; 121 122 /* open audit event file if it isn't already */ 123 (void) mutex_lock(&mutex_eventfile); 124 if (!au_event_file) 125 if (!(au_event_file = fopen(au_event_fname, "rF"))) { 126 (void) mutex_unlock(&mutex_eventfile); 127 return (NULL); 128 } 129 130 while (fgets(input, AU_EVENT_LINE_MAX, au_event_file)) { 131 if (input[0] != '#') { 132 s = input + strspn(input, " \t\r\n"); 133 if ((*s == '\0') || (*s == '#')) { 134 continue; 135 } 136 found = 1; 137 s = input; 138 139 /* parse number */ 140 i = strcspn(s, ":"); 141 s[i] = '\0'; 142 (void) sscanf(s, "%hu", &au_event_entry->ae_number); 143 s = &s[i+1]; 144 145 /* parse event name */ 146 i = strcspn(s, ":"); 147 s[i] = '\0'; 148 (void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s", 149 trim_buf); 150 (void) strncpy(au_event_entry->ae_name, trim_buf, 151 AU_EVENT_NAME_MAX); 152 s = &s[i+1]; 153 154 /* parse event description */ 155 i = strcspn(s, ":"); 156 s[i] = '\0'; 157 (void) strncpy(au_event_entry->ae_desc, s, 158 AU_EVENT_DESC_MAX); 159 s = &s[i+1]; 160 161 /* parse class */ 162 i = strcspn(s, "\n\0"); 163 s[i] = '\0'; 164 (void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s", 165 trim_buf); 166 au_event_entry->ae_class = flagstohex(trim_buf); 167 if (cacheauclass_failure == 1) { 168 error = 1; 169 cacheauclass_failure = 0; 170 } 171 172 break; 173 } 174 } 175 (void) mutex_unlock(&mutex_eventfile); 176 177 if (!error && found) { 178 return (au_event_entry); 179 } else { 180 return (NULL); 181 } 182 } 183 184 au_event_ent_t * 185 getauevnam(char *name) 186 { 187 static au_event_ent_t au_event_entry; 188 static char ename[AU_EVENT_NAME_MAX]; 189 static char edesc[AU_EVENT_DESC_MAX]; 190 191 /* initialize au_event_entry structure */ 192 au_event_entry.ae_name = ename; 193 au_event_entry.ae_desc = edesc; 194 195 return (getauevnam_r(&au_event_entry, name)); 196 } 197 198 au_event_ent_t * 199 getauevnam_r(au_event_ent_t *e, char *name) 200 { 201 setauevent(); 202 while (getauevent_r(e) != NULL) { 203 if (strcmp(e->ae_name, name) == 0) { 204 endauevent(); 205 return (e); 206 } 207 } 208 endauevent(); 209 return (NULL); 210 } 211 212 au_event_ent_t * 213 getauevnum_r(au_event_ent_t *e, au_event_t event_number) 214 { 215 setauevent(); 216 while (getauevent_r(e) != NULL) { 217 if (e->ae_number == event_number) { 218 endauevent(); 219 return (e); 220 } 221 } 222 endauevent(); 223 return (NULL); 224 } 225 226 au_event_ent_t * 227 getauevnum(au_event_t event_number) 228 { 229 static au_event_ent_t e; 230 static char ename[AU_EVENT_NAME_MAX]; 231 static char edesc[AU_EVENT_DESC_MAX]; 232 233 /* initialize au_event_entry structure */ 234 e.ae_name = ename; 235 e.ae_desc = edesc; 236 237 return (getauevnum_r(&e, event_number)); 238 } 239 240 au_event_t 241 getauevnonam(char *event_name) 242 { 243 au_event_ent_t e; 244 char ename[AU_EVENT_NAME_MAX]; 245 char edesc[AU_EVENT_DESC_MAX]; 246 247 /* initialize au_event_entry structure */ 248 e.ae_name = ename; 249 e.ae_desc = edesc; 250 251 if (getauevnam_r(&e, event_name) == NULL) { 252 return (0); 253 } 254 return (e.ae_number); 255 } 256 257 /* 258 * cacheauevent: 259 * Read the entire audit_event file into memory. 260 * Set a pointer to the requested entry in the cache 261 * or a pointer to an invalid entry if the event number 262 * is not known. 263 * 264 * Return < 0, if error. 265 * Return 0, if event number not in cache. 266 * Return 1, if event number is in cache. 267 */ 268 int 269 cacheauevent(au_event_ent_t **result, au_event_t event_number) 270 { 271 static au_event_t max; /* the highest event number in the file */ 272 static au_event_t min; /* the lowest event number in the file */ 273 static int invalid; /* 1+index of the highest event number */ 274 static au_event_ent_t **index_tbl; 275 static au_event_ent_t **p_tbl; 276 static int called_once = 0; 277 278 char line[AU_EVENT_LINE_MAX]; 279 int lines = 0; 280 FILE *fp; 281 au_event_ent_t *p_event; 282 int i, size; 283 int hit = 0; 284 char *s; 285 286 (void) mutex_lock(&mutex_eventcache); 287 if (called_once == 0) { 288 289 /* Count number of lines in the events file */ 290 if ((fp = fopen(au_event_fname, "rF")) == NULL) { 291 (void) mutex_unlock(&mutex_eventcache); 292 return (-1); 293 } 294 while (fgets(line, AU_EVENT_LINE_MAX, fp) != NULL) { 295 s = line + strspn(line, " \t\r\n"); 296 if ((*s == '\0') || (*s == '#')) { 297 continue; 298 } 299 lines++; 300 } 301 (void) fclose(fp); 302 size = lines; 303 304 /* 305 * Make an array in which each element in an entry in the 306 * events file. Make the next to last element an invalid 307 * event. Make the last element a NULL pointer. 308 */ 309 310 p_tbl = calloc(lines + 1, sizeof (au_event_ent_t)); 311 if (p_tbl == NULL) { 312 (void) mutex_unlock(&mutex_eventcache); 313 return (-2); 314 } 315 lines = 0; 316 max = 0; 317 min = 65535; 318 setauevent(); 319 while ((p_event = getauevent()) != NULL) { 320 p_tbl[lines] = (au_event_ent_t *) 321 malloc(sizeof (au_event_ent_t)); 322 if (p_tbl[lines] == NULL) { 323 (void) mutex_unlock(&mutex_eventcache); 324 return (-3); 325 } 326 p_tbl[lines]->ae_number = p_event->ae_number; 327 p_tbl[lines]->ae_name = strdup(p_event->ae_name); 328 p_tbl[lines]->ae_desc = strdup(p_event->ae_desc); 329 p_tbl[lines]->ae_class = p_event->ae_class; 330 #ifdef DEBUG2 331 printevent(p_tbl[lines]); 332 #endif 333 if (p_event->ae_number > max) { 334 max = p_event->ae_number; 335 } 336 if (p_event->ae_number < min) { 337 min = p_event->ae_number; 338 } 339 lines++; 340 } 341 endauevent(); 342 invalid = lines; 343 p_tbl[invalid] = (au_event_ent_t *) 344 malloc(sizeof (au_event_ent_t)); 345 if (p_tbl[invalid] == NULL) { 346 (void) mutex_unlock(&mutex_eventcache); 347 return (-4); 348 } 349 p_tbl[invalid]->ae_number = (au_event_t)-1; 350 p_tbl[invalid]->ae_name = "invalid event number"; 351 p_tbl[invalid]->ae_desc = p_tbl[invalid]->ae_name; 352 p_tbl[invalid]->ae_class = (au_class_t)-1; 353 354 #ifdef DEBUG2 355 for (i = 0; i < size; i++) { 356 (void) printf("%d:%s:%s:%d\n", p_tbl[i]->ae_number, 357 p_tbl[i]->ae_name, p_tbl[i]->ae_desc, 358 p_tbl[i]->ae_class); 359 } 360 #endif 361 362 /* get space for the index_tbl */ 363 index_tbl = calloc(max+1, sizeof (au_event_ent_t *)); 364 if (index_tbl == NULL) { 365 (void) mutex_unlock(&mutex_eventcache); 366 return (-5); 367 } 368 369 /* intialize the index_tbl to the invalid event number */ 370 for (i = 0; (au_event_t)i < max; i++) { 371 index_tbl[i] = p_tbl[invalid]; 372 } 373 374 /* point each index_tbl element at the corresponding event */ 375 for (i = 0; i < size; i++) { 376 index_tbl[p_tbl[i]->ae_number] = p_tbl[i]; 377 } 378 379 called_once = 1; 380 381 } 382 383 if (event_number > max || event_number < min) { 384 *result = index_tbl[invalid]; 385 } else { 386 *result = index_tbl[event_number]; 387 hit = 1; 388 } 389 (void) mutex_unlock(&mutex_eventcache); 390 return (hit); 391 } 392 393 static au_class_t 394 flagstohex(char *flags) 395 { 396 au_class_ent_t *p_class; 397 au_class_t hex = 0; 398 char *comma = ","; 399 char *s; 400 char *last; 401 402 s = strtok_r(flags, comma, &last); 403 while (s != NULL) { 404 if ((cacheauclassnam(&p_class, s)) < 0) { 405 cacheauclass_failure = 1; 406 return ((au_class_t)-1); 407 } 408 hex |= p_class->ac_class; 409 s = strtok_r(NULL, comma, &last); 410 } 411 return (hex); 412 } 413