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