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