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 2008 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 71 void 72 setauevent() 73 { 74 (void) mutex_lock(&mutex_eventfile); 75 if (au_event_file) { 76 (void) fseek(au_event_file, 0L, 0); 77 } 78 (void) mutex_unlock(&mutex_eventfile); 79 } 80 81 82 void 83 endauevent() 84 { 85 (void) mutex_lock(&mutex_eventfile); 86 if (au_event_file) { 87 (void) fclose(au_event_file); 88 au_event_file = (FILE *)0; 89 } 90 (void) mutex_unlock(&mutex_eventfile); 91 } 92 93 au_event_ent_t * 94 getauevent() 95 { 96 static au_event_ent_t au_event_entry; 97 static char ename[AU_EVENT_NAME_MAX]; 98 static char edesc[AU_EVENT_DESC_MAX]; 99 100 /* initialize au_event_entry structure */ 101 au_event_entry.ae_name = ename; 102 au_event_entry.ae_desc = edesc; 103 104 return (getauevent_r(&au_event_entry)); 105 } 106 107 au_event_ent_t * 108 getauevent_r(au_event_entry) 109 au_event_ent_t *au_event_entry; 110 { 111 int i, error = 0, found = 0; 112 char *s, input[AU_EVENT_LINE_MAX]; 113 char trim_buf[AU_EVENT_NAME_MAX+1]; 114 115 /* open audit event file if it isn't already */ 116 (void) mutex_lock(&mutex_eventfile); 117 if (!au_event_file) 118 if (!(au_event_file = fopen(au_event_fname, "rF"))) { 119 (void) mutex_unlock(&mutex_eventfile); 120 return (NULL); 121 } 122 123 while (fgets(input, AU_EVENT_LINE_MAX, au_event_file)) { 124 if (input[0] != '#') { 125 s = input + strspn(input, " \t\r\n"); 126 if ((*s == '\0') || (*s == '#')) { 127 continue; 128 } 129 found = 1; 130 s = input; 131 132 /* parse number */ 133 i = strcspn(s, ":"); 134 s[i] = '\0'; 135 (void) sscanf(s, "%hu", &au_event_entry->ae_number); 136 s = &s[i+1]; 137 138 /* parse event name */ 139 i = strcspn(s, ":"); 140 s[i] = '\0'; 141 (void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s", 142 trim_buf); 143 (void) strncpy(au_event_entry->ae_name, trim_buf, 144 AU_EVENT_NAME_MAX); 145 s = &s[i+1]; 146 147 /* parse event description */ 148 i = strcspn(s, ":"); 149 s[i] = '\0'; 150 (void) strncpy(au_event_entry->ae_desc, s, 151 AU_EVENT_DESC_MAX); 152 s = &s[i+1]; 153 154 /* parse class */ 155 i = strcspn(s, "\n\0"); 156 s[i] = '\0'; 157 (void) sscanf(s, "%" VAL2STR(AU_EVENT_NAME_MAX) "s", 158 trim_buf); 159 au_event_entry->ae_class = flagstohex(trim_buf); 160 if (cacheauclass_failure == 1) { 161 error = 1; 162 cacheauclass_failure = 0; 163 } 164 165 break; 166 } 167 } 168 (void) mutex_unlock(&mutex_eventfile); 169 170 if (!error && found) { 171 return (au_event_entry); 172 } else { 173 return (NULL); 174 } 175 } 176 177 178 au_event_ent_t * 179 getauevnam(char *name) 180 { 181 static au_event_ent_t au_event_entry; 182 static char ename[AU_EVENT_NAME_MAX]; 183 static char edesc[AU_EVENT_DESC_MAX]; 184 185 /* initialize au_event_entry structure */ 186 au_event_entry.ae_name = ename; 187 au_event_entry.ae_desc = edesc; 188 189 return (getauevnam_r(&au_event_entry, name)); 190 } 191 192 au_event_ent_t * 193 getauevnam_r(au_event_ent_t *e, char *name) 194 { 195 setauevent(); 196 while (getauevent_r(e) != NULL) { 197 if (strcmp(e->ae_name, name) == 0) { 198 endauevent(); 199 return (e); 200 } 201 } 202 endauevent(); 203 return (NULL); 204 } 205 206 au_event_ent_t * 207 getauevnum_r(au_event_ent_t *e, au_event_t event_number) 208 { 209 setauevent(); 210 while (getauevent_r(e) != NULL) { 211 if (e->ae_number == event_number) { 212 endauevent(); 213 return (e); 214 } 215 } 216 endauevent(); 217 return (NULL); 218 } 219 220 au_event_ent_t * 221 getauevnum(au_event_t event_number) 222 { 223 static au_event_ent_t e; 224 static char ename[AU_EVENT_NAME_MAX]; 225 static char edesc[AU_EVENT_DESC_MAX]; 226 227 /* initialize au_event_entry structure */ 228 e.ae_name = ename; 229 e.ae_desc = edesc; 230 231 return (getauevnum_r(&e, event_number)); 232 } 233 234 au_event_t 235 getauevnonam(char *event_name) 236 { 237 au_event_ent_t e; 238 char ename[AU_EVENT_NAME_MAX]; 239 char edesc[AU_EVENT_DESC_MAX]; 240 241 /* initialize au_event_entry structure */ 242 e.ae_name = ename; 243 e.ae_desc = edesc; 244 245 if (getauevnam_r(&e, event_name) == NULL) { 246 return (0); 247 } 248 return (e.ae_number); 249 } 250 251 /* 252 * cacheauevent: 253 * Read the entire audit_event file into memory. 254 * Set a pointer to the requested entry in the cache 255 * or a pointer to an invalid entry if the event number 256 * is not known. 257 * 258 * Return < 0, if error. 259 * Return 0, if event number not in cache. 260 * Return 1, if event number is in cache. 261 */ 262 263 int 264 cacheauevent(au_event_ent_t **result, au_event_t event_number) 265 { 266 static au_event_t max; /* the highest event number in the file */ 267 static au_event_t min; /* the lowest event number in the file */ 268 static int invalid; /* 1+index of the highest event number */ 269 static au_event_ent_t **index_tbl; 270 static au_event_ent_t **p_tbl; 271 static int called_once = 0; 272 273 char line[AU_EVENT_LINE_MAX]; 274 int lines = 0; 275 FILE *fp; 276 au_event_ent_t *p_event; 277 int i, size; 278 int hit = 0; 279 char *s; 280 281 (void) mutex_lock(&mutex_eventcache); 282 if (called_once == 0) { 283 284 /* Count number of lines in the events file */ 285 if ((fp = fopen(au_event_fname, "rF")) == NULL) { 286 (void) mutex_unlock(&mutex_eventcache); 287 return (-1); 288 } 289 while (fgets(line, AU_EVENT_LINE_MAX, fp) != NULL) { 290 s = line + strspn(line, " \t\r\n"); 291 if ((*s == '\0') || (*s == '#')) { 292 continue; 293 } 294 lines++; 295 } 296 (void) fclose(fp); 297 size = lines; 298 299 /* 300 * Make an array in which each element in an entry in the 301 * events file. Make the next to last element an invalid 302 * event. Make the last element a NULL pointer. 303 */ 304 305 p_tbl = calloc(lines + 1, sizeof (au_event_ent_t)); 306 if (p_tbl == NULL) { 307 (void) mutex_unlock(&mutex_eventcache); 308 return (-2); 309 } 310 lines = 0; 311 max = 0; 312 min = 65535; 313 setauevent(); 314 while ((p_event = getauevent()) != NULL) { 315 p_tbl[lines] = (au_event_ent_t *) 316 malloc(sizeof (au_event_ent_t)); 317 if (p_tbl[lines] == NULL) { 318 (void) mutex_unlock(&mutex_eventcache); 319 return (-3); 320 } 321 p_tbl[lines]->ae_number = p_event->ae_number; 322 p_tbl[lines]->ae_name = strdup(p_event->ae_name); 323 p_tbl[lines]->ae_desc = strdup(p_event->ae_desc); 324 p_tbl[lines]->ae_class = p_event->ae_class; 325 #ifdef DEBUG2 326 printevent(p_tbl[lines]); 327 #endif 328 if (p_event->ae_number > max) { 329 max = p_event->ae_number; 330 } 331 if (p_event->ae_number < min) { 332 min = p_event->ae_number; 333 } 334 lines++; 335 } 336 endauevent(); 337 invalid = lines; 338 p_tbl[invalid] = (au_event_ent_t *) 339 malloc(sizeof (au_event_ent_t)); 340 if (p_tbl[invalid] == NULL) { 341 (void) mutex_unlock(&mutex_eventcache); 342 return (-4); 343 } 344 p_tbl[invalid]->ae_number = (au_event_t)-1; 345 p_tbl[invalid]->ae_name = "invalid event number"; 346 p_tbl[invalid]->ae_desc = p_tbl[invalid]->ae_name; 347 p_tbl[invalid]->ae_class = (au_class_t)-1; 348 349 #ifdef DEBUG2 350 for (i = 0; i < size; i++) { 351 printf("%d:%s:%s:%d\n", p_tbl[i]->ae_number, 352 p_tbl[i]->ae_name, p_tbl[i]->ae_desc, 353 p_tbl[i]->ae_class); 354 } 355 #endif 356 357 /* get space for the index_tbl */ 358 index_tbl = calloc(max+1, sizeof (au_event_ent_t *)); 359 if (index_tbl == NULL) { 360 (void) mutex_unlock(&mutex_eventcache); 361 return (-5); 362 } 363 364 /* intialize the index_tbl to the invalid event number */ 365 for (i = 0; (au_event_t)i < max; i++) { 366 index_tbl[i] = p_tbl[invalid]; 367 } 368 369 /* point each index_tbl element at the corresponding event */ 370 for (i = 0; i < size; i++) { 371 index_tbl[p_tbl[i]->ae_number] = p_tbl[i]; 372 } 373 374 called_once = 1; 375 376 } 377 378 if (event_number > max || event_number < min) { 379 *result = index_tbl[invalid]; 380 } else { 381 *result = index_tbl[event_number]; 382 hit = 1; 383 } 384 (void) mutex_unlock(&mutex_eventcache); 385 return (hit); 386 } 387 388 389 static au_class_t 390 flagstohex(char *flags) 391 { 392 au_class_ent_t *p_class; 393 au_class_t hex = 0; 394 char *comma = ","; 395 char *s; 396 char *last; 397 398 s = strtok_r(flags, comma, &last); 399 while (s != NULL) { 400 if ((cacheauclassnam(&p_class, s)) < 0) { 401 cacheauclass_failure = 1; 402 return ((au_class_t)-1); 403 } 404 hex |= p_class->ac_class; 405 s = strtok_r(NULL, comma, &last); 406 } 407 return (hex); 408 } 409 410 411 #ifdef DEBUG2 412 void 413 printevent(p_event) 414 au_event_ent_t *p_event; 415 { 416 printf("%d:%s:%s:%d\n", p_event->ae_number, p_event->ae_name, 417 p_event->ae_desc, p_event->ae_class); 418 fflush(stdout); 419 } 420 421 422 #endif 423