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 78 void 79 setauevent() 80 { 81 _mutex_lock(&mutex_eventfile); 82 if (au_event_file) { 83 (void) fseek(au_event_file, 0L, 0); 84 } 85 _mutex_unlock(&mutex_eventfile); 86 } 87 88 89 void 90 endauevent() 91 { 92 _mutex_lock(&mutex_eventfile); 93 if (au_event_file) { 94 (void) fclose(au_event_file); 95 au_event_file = (FILE *)0; 96 } 97 _mutex_unlock(&mutex_eventfile); 98 } 99 100 au_event_ent_t * 101 getauevent() 102 { 103 static au_event_ent_t au_event_entry; 104 static char ename[AU_EVENT_NAME_MAX]; 105 static char edesc[AU_EVENT_DESC_MAX]; 106 107 /* initialize au_event_entry structure */ 108 au_event_entry.ae_name = ename; 109 au_event_entry.ae_desc = edesc; 110 111 return (getauevent_r(&au_event_entry)); 112 } 113 114 au_event_ent_t * 115 getauevent_r(au_event_entry) 116 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 _mutex_lock(&mutex_eventfile); 124 if (!au_event_file) 125 if (!(au_event_file = fopen(au_event_fname, "rF"))) { 126 _mutex_unlock(&mutex_eventfile); 127 return ((au_event_ent_t *)0); 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, "%hd", &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 _mutex_unlock(&mutex_eventfile); 176 177 if (!error && found) { 178 return (au_event_entry); 179 } else { 180 return ((au_event_ent_t *)0); 181 } 182 } 183 184 185 au_event_ent_t * 186 #ifdef __STDC__ 187 getauevnam(char *name) 188 #else 189 getauevnam(name) 190 char *name; 191 #endif 192 { 193 static au_event_ent_t au_event_entry; 194 static char ename[AU_EVENT_NAME_MAX]; 195 static char edesc[AU_EVENT_DESC_MAX]; 196 197 /* initialize au_event_entry structure */ 198 au_event_entry.ae_name = ename; 199 au_event_entry.ae_desc = edesc; 200 201 return (getauevnam_r(&au_event_entry, name)); 202 } 203 204 au_event_ent_t * 205 #ifdef __STDC__ 206 getauevnam_r(au_event_ent_t *e, char *name) 207 #else 208 getauevnam_r(e, name) 209 au_event_ent_t &e; 210 char *name; 211 #endif 212 { 213 setauevent(); 214 while (getauevent_r(e) != NULL) { 215 if (strcmp(e->ae_name, name) == 0) { 216 endauevent(); 217 return (e); 218 } 219 } 220 endauevent(); 221 return ((au_event_ent_t *)NULL); 222 } 223 224 au_event_ent_t * 225 #ifdef __STDC__ 226 getauevnum_r(au_event_ent_t *e, au_event_t event_number) 227 #else 228 getauevnum_r(e, event_number) 229 au_event_ent_t *e; 230 au_event_t event_number; 231 #endif 232 { 233 setauevent(); 234 while (getauevent_r(e) != NULL) { 235 if (e->ae_number == event_number) { 236 endauevent(); 237 return (e); 238 } 239 } 240 endauevent(); 241 return ((au_event_ent_t *)NULL); 242 } 243 244 au_event_ent_t * 245 #ifdef __STDC__ 246 getauevnum(au_event_t event_number) 247 #else 248 getauevnum(event_number) 249 au_event_t event_number; 250 #endif 251 { 252 static au_event_ent_t e; 253 static char ename[AU_EVENT_NAME_MAX]; 254 static char edesc[AU_EVENT_DESC_MAX]; 255 256 /* initialize au_event_entry structure */ 257 e.ae_name = ename; 258 e.ae_desc = edesc; 259 260 return (getauevnum_r(&e, event_number)); 261 } 262 263 au_event_t 264 #ifdef __STDC__ 265 getauevnonam(char *event_name) 266 #else 267 getauevnonam(event_name) 268 char *event_name; 269 #endif 270 { 271 au_event_ent_t e; 272 char ename[AU_EVENT_NAME_MAX]; 273 char edesc[AU_EVENT_DESC_MAX]; 274 275 /* initialize au_event_entry structure */ 276 e.ae_name = ename; 277 e.ae_desc = edesc; 278 279 if (getauevnam_r(&e, event_name) == (au_event_ent_t *)0) { 280 return (-1); 281 } 282 return (e.ae_number); 283 } 284 285 /* 286 * cacheauevent: 287 * Read the entire audit_event file into memory. 288 * Set a pointer to the requested entry in the cache 289 * or a pointer to an invalid entry if the event number 290 * is not known. 291 * 292 * Return < 0, if error. 293 * Return 0, if event number not in cache. 294 * Return 1, if event number is in cache. 295 */ 296 297 int 298 #ifdef __STDC__ 299 cacheauevent(au_event_ent_t **result, au_event_t event_number) 300 #else 301 cacheauevent(result, event_number) 302 au_event_ent_t **result; /* set this pointer to an entry in the cache */ 303 au_event_t event_number; /* request this event number */ 304 #endif 305 { 306 static ushort_t max; /* the highest event number in the file */ 307 static ushort_t min; /* the lowest event number in the file */ 308 static int invalid; /* 1+index of the highest event number */ 309 static au_event_ent_t **index_tbl; 310 static au_event_ent_t **p_tbl; 311 static int called_once = 0; 312 313 char line[AU_EVENT_LINE_MAX]; 314 int lines = 0; 315 FILE *fp; 316 au_event_ent_t *p_event; 317 int i, size; 318 int hit = 0; 319 char *s; 320 321 _mutex_lock(&mutex_eventcache); 322 if (called_once == 0) { 323 324 /* Count number of lines in the events file */ 325 if ((fp = fopen(au_event_fname, "rF")) == NULL) { 326 _mutex_unlock(&mutex_eventcache); 327 return (-1); 328 } 329 while (fgets(line, AU_EVENT_LINE_MAX, fp) != NULL) { 330 s = line + strspn(line, " \t\r\n"); 331 if ((*s == '\0') || (*s == '#')) { 332 continue; 333 } 334 lines++; 335 } 336 (void) fclose(fp); 337 size = lines; 338 339 /* 340 * Make an array in which each element in an entry in the 341 * events file. Make the next to last element an invalid 342 * event. Make the last element a NULL pointer. 343 */ 344 345 p_tbl = calloc(lines + 1, sizeof (au_event_ent_t)); 346 if (p_tbl == NULL) { 347 _mutex_unlock(&mutex_eventcache); 348 return (-2); 349 } 350 lines = 0; 351 max = 0; 352 min = 65535; 353 setauevent(); 354 while ((p_event = getauevent()) != NULL) { 355 p_tbl[lines] = (au_event_ent_t *) 356 malloc(sizeof (au_event_ent_t)); 357 if (p_tbl[lines] == NULL) { 358 _mutex_unlock(&mutex_eventcache); 359 return (-3); 360 } 361 p_tbl[lines]->ae_number = p_event->ae_number; 362 p_tbl[lines]->ae_name = strdup(p_event->ae_name); 363 p_tbl[lines]->ae_desc = strdup(p_event->ae_desc); 364 p_tbl[lines]->ae_class = p_event->ae_class; 365 #ifdef DEBUG2 366 printevent(p_tbl[lines]); 367 #endif 368 if ((ushort_t)p_event->ae_number > max) { 369 max = p_event->ae_number; 370 } 371 if ((ushort_t)p_event->ae_number < min) { 372 min = p_event->ae_number; 373 } 374 lines++; 375 } 376 endauevent(); 377 invalid = lines; 378 p_tbl[invalid] = (au_event_ent_t *) 379 malloc(sizeof (au_event_ent_t)); 380 if (p_tbl[invalid] == NULL) { 381 _mutex_unlock(&mutex_eventcache); 382 return (-4); 383 } 384 p_tbl[invalid]->ae_number = -1; 385 p_tbl[invalid]->ae_name = "invalid event number"; 386 p_tbl[invalid]->ae_desc = p_tbl[invalid]->ae_name; 387 p_tbl[invalid]->ae_class = (au_class_t)-1; 388 389 #ifdef DEBUG2 390 for (i = 0; i < size; i++) { 391 printf("%d:%s:%s:%d\n", p_tbl[i]->ae_number, 392 p_tbl[i]->ae_name, p_tbl[i]->ae_desc, 393 p_tbl[i]->ae_class); 394 } 395 #endif 396 397 /* get space for the index_tbl */ 398 index_tbl = calloc(max+1, sizeof (au_event_ent_t *)); 399 if (index_tbl == NULL) { 400 _mutex_unlock(&mutex_eventcache); 401 return (-5); 402 } 403 404 /* intialize the index_tbl to the invalid event number */ 405 for (i = 0; (ushort_t)i < max; i++) { 406 index_tbl[i] = p_tbl[invalid]; 407 } 408 409 /* point each index_tbl element at the corresponding event */ 410 for (i = 0; i < size; i++) { 411 index_tbl[(ushort_t)p_tbl[i]->ae_number] = p_tbl[i]; 412 } 413 414 called_once = 1; 415 416 } 417 418 if ((ushort_t)event_number > max || (ushort_t)event_number < min) { 419 *result = index_tbl[invalid]; 420 } else { 421 *result = index_tbl[(ushort_t)event_number]; 422 hit = 1; 423 } 424 _mutex_unlock(&mutex_eventcache); 425 return (hit); 426 } 427 428 429 static au_class_t 430 flagstohex(char *flags) 431 { 432 au_class_ent_t *p_class; 433 au_class_t hex = 0; 434 char *comma = ","; 435 char *s; 436 char *last; 437 438 s = strtok_r(flags, comma, &last); 439 while (s != NULL) { 440 if ((cacheauclassnam(&p_class, s)) < 0) { 441 cacheauclass_failure = 1; 442 return ((au_class_t)-1); 443 } 444 hex |= p_class->ac_class; 445 s = strtok_r(NULL, comma, &last); 446 } 447 return (hex); 448 } 449 450 451 #ifdef DEBUG2 452 void 453 printevent(p_event) 454 au_event_ent_t *p_event; 455 { 456 printf("%d:%s:%s:%d\n", p_event->ae_number, p_event->ae_name, 457 p_event->ae_desc, p_event->ae_class); 458 fflush(stdout); 459 } 460 461 462 #endif 463