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