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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 /* 27 * get audit control info (replaces getacinfo.c) 28 */ 29 30 #include <secdb.h> 31 #include <stdio.h> 32 #include <sys/types.h> 33 #include <bsm/audit.h> 34 #include <bsm/libbsm.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <synch.h> 38 39 #define REALLY_LONG_LINE 8192 40 41 #define FILE_AT_START 0 /* file pointer is at file start or file is closed */ 42 #define FILE_MIDDLE 1 /* file pointer is not at file start */ 43 44 #define LEN 360 /* arbitrary audit control entry length */ 45 46 #define SUCCESS 0 47 #define EOF_WARN 1 48 #define REW_WARN 2 49 #define EOF_ERR -1 50 #define ERROR -2 51 #define FORMAT_ERR -3 52 #define NO_CONTEXT -4 53 54 /* 55 * libbsm.h has opaque typedef: typedef struct au_acinfo au_acinfo_t 56 */ 57 struct au_acinfo { 58 char *file; 59 FILE *fp; 60 int file_pointer; 61 int once_read; 62 }; 63 64 static char *MINLABEL = "minfree:"; 65 static char *DIRLABEL = "dir:"; 66 static char *DEFFLGLABEL = "flags:"; 67 static char *NAFLGLABEL = "naflags:"; 68 static char *lib_label = "plugin:"; 69 70 /* 71 * get extended line, i.e., interpret trailing "\" and join to make 72 * a single line. Returns NULL on error or EOF, else returns its 73 * input pointer. A line containing only "\" and some blanks is valid. 74 * 75 * doesn't handle a comment line embedded in a series of continued lines. 76 */ 77 78 static char * 79 getlongline(char *line, int length, FILE *fp) 80 { 81 int keepgoing = 1; 82 int partcount = 0; 83 char *l, *b; 84 int end = 0; 85 86 l = line; 87 while (keepgoing) { 88 if (fgets(l, length, fp) != NULL) { 89 partcount++; 90 end = strlen(l); 91 b = l + end - 2; /* last char before \n */ 92 *(b + 1) = '\0'; /* chop the \n */ 93 keepgoing = 0; 94 while (b >= l) { 95 if (*b == '\\') { 96 keepgoing = 1; 97 l = b; 98 length -= (end - 1); 99 break; 100 } else if (*b != ' ') 101 break; 102 end--; 103 b--; 104 } 105 } else 106 keepgoing = 0; 107 } 108 if (partcount > 0) 109 return (line); 110 else 111 return (NULL); 112 } 113 114 /* 115 * input a string of the form attr: xxxxx{\n} 116 * and return xxxxx with leading, internal, and trailing blanks removed 117 */ 118 119 static int 120 getvalue(char *out_buf, char *line, char *attr_name, int out_len) 121 { 122 int attr_length, value_length; 123 char *bp, *cp; 124 int retstat = SUCCESS; 125 126 attr_length = (int)strlen(attr_name); 127 value_length = (int)strlen(line); 128 129 if (strncmp(line, attr_name, attr_length) == 0) { 130 /* 131 * allow zero or more blanks 132 * between colon and rest of line 133 */ 134 value_length -= attr_length; 135 136 bp = line + attr_length; 137 while (*bp == ' ') { 138 value_length--; 139 attr_length++; /* offset to first non-blank */ 140 bp++; 141 } 142 cp = bp; 143 while (*bp != '\0') { 144 if (*bp == ' ') { 145 bp++; 146 value_length--; 147 } else { 148 *cp++ = *bp++; 149 } 150 } 151 *cp = '\0'; 152 153 if (value_length < 1) { 154 *out_buf = '\0'; 155 return (retstat); 156 } 157 if ((retstat == SUCCESS) && 158 (strlcpy(out_buf, line + attr_length, out_len) >= 159 out_len)) 160 retstat = FORMAT_ERR; 161 } else 162 retstat = FORMAT_ERR; 163 164 return (retstat); 165 } 166 167 /* 168 * getacval.c - get audit control info 169 * 170 * _getacdir() - get audit control directories, one at a time 171 * _getacflg() - get audit control default audit flags 172 * _getacmin() - get audit control directory min. fill value 173 * _getacna() - get audit control non-attrib audit flags 174 * _getacplug() - get audit control remote host and associated data 175 * _openac() - open the audit control file 176 * _endac() - close the audit control file 177 */ 178 179 /* 180 * _getacdir() - get audit control directories, one at a time 181 * 182 * input: len - size of dir buffer 183 * 184 * output: dir - directory string 185 * 186 * returns: 0 - entry read ok 187 * -1 - end of file 188 * -2 - error - can't open audit control file for read 189 * -3 - error - directory entry format error 190 * 2 - directory search started from beginning again 191 * 192 * notes: It is the responsibility of the calling function to 193 * check the status of the directory entry. 194 */ 195 196 int 197 _getacdir(au_acinfo_t *context, char *dir, int len) 198 { 199 int retstat = SUCCESS, gotone = 0; 200 char *entry; 201 202 if (context == NULL) 203 return (NO_CONTEXT); 204 205 entry = malloc(REALLY_LONG_LINE); 206 if (entry == NULL) 207 return (ERROR); 208 209 if ((context->file_pointer != FILE_AT_START) && 210 (context->once_read == 1)) { 211 retstat = REW_WARN; 212 _rewindac(context); 213 } else { 214 context->once_read = 1; 215 context->file_pointer = FILE_AT_START; 216 } 217 if (retstat >= SUCCESS) do { 218 if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) { 219 if (*entry == 'd') { 220 retstat = getvalue(dir, entry, DIRLABEL, len); 221 if (retstat == SUCCESS) { 222 if (strlen(dir) == 0) { 223 retstat = FORMAT_ERR; 224 } else { 225 gotone = 1; 226 } 227 } 228 } 229 } else if ((feof(context->fp)) == 0) { 230 retstat = ERROR; 231 } else { 232 retstat = EOF_ERR; 233 } 234 } while (gotone == 0 && retstat >= SUCCESS); 235 236 free(entry); 237 return (retstat); 238 } 239 240 241 /* 242 * _getacmin() - get audit control directory min. fill value 243 * 244 * output: min_val - percentage of directory fill allowed 245 * 246 * returns: 0 - entry read ok 247 * 1 - end of file 248 * -2 - error; errno contains error number 249 * -3 - error - directory entry format error 250 */ 251 252 int 253 _getacmin(au_acinfo_t *context, int *min_val) 254 { 255 int retstat = SUCCESS, gotone = 0; 256 257 char entry[LEN]; 258 char value[LEN]; 259 260 if (context == NULL) 261 return (NO_CONTEXT); 262 263 _rewindac(context); 264 265 if (retstat == SUCCESS) do { 266 if (getlongline(entry, LEN, context->fp) != NULL) { 267 if (*entry == 'm') { 268 retstat = getvalue(value, entry, MINLABEL, 269 5); /* sb 2 digits, allow more */ 270 if (retstat == SUCCESS) { 271 gotone = 1; 272 *min_val = (int)strtol(value, NULL, 10); 273 if ((*min_val == 0) && (errno != 0)) 274 retstat = FORMAT_ERR; 275 } 276 } 277 } else if ((feof(context->fp)) == 0) 278 retstat = ERROR; 279 else 280 retstat = EOF_WARN; 281 282 } while (gotone == 0 && retstat == SUCCESS); 283 284 if (context->file_pointer == FILE_AT_START) 285 context->file_pointer = FILE_MIDDLE; 286 else 287 _rewindac(context); 288 289 return (retstat); 290 } 291 292 293 /* 294 * _getacflg() - get audit control flags 295 * 296 * output: auditstring - character representation of system audit flags 297 * 298 * returns: 0 - entry read ok 299 * 1 - end of file 300 * -2 - error - errno contains error number 301 * -3 - error - directory entry format error 302 */ 303 304 int 305 _getacflg(au_acinfo_t *context, char *auditstring, int len) 306 { 307 int retstat = SUCCESS, gotone = 0; 308 char *entry; 309 310 if (context == NULL) 311 return (NO_CONTEXT); 312 313 entry = malloc(REALLY_LONG_LINE); 314 if (entry == NULL) 315 return (ERROR); 316 317 _rewindac(context); 318 319 if (retstat == SUCCESS) do { 320 if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) { 321 if (*entry == 'f') { 322 retstat = getvalue(auditstring, entry, 323 DEFFLGLABEL, len); 324 if (retstat == SUCCESS) 325 gotone = 1; 326 } 327 } else if ((feof(context->fp)) == 0) { 328 retstat = ERROR; 329 } else { 330 retstat = EOF_WARN; 331 } 332 } while (gotone == 0 && retstat == SUCCESS); 333 334 if (context->file_pointer == FILE_AT_START) 335 context->file_pointer = FILE_MIDDLE; 336 else 337 _rewindac(context); 338 339 free(entry); 340 return (retstat); 341 } 342 343 344 /* 345 * _getacna() - get audit flags for non-attributable (server) events 346 * 347 * output: auditstring - character representation of system audit flags 348 * 349 * returns: 0 - entry read ok 350 * 1 - end of file 351 * -2 - error - errno contains error number 352 * -3 - error - directory entry format error 353 */ 354 355 int 356 _getacna(au_acinfo_t *context, char *auditstring, int len) 357 { 358 int retstat = SUCCESS, gotone = 0; 359 char *entry; 360 361 entry = malloc(REALLY_LONG_LINE); 362 if (entry == NULL) 363 return (ERROR); 364 365 _rewindac(context); 366 367 if (retstat == SUCCESS) do { 368 if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) { 369 if (*entry == 'n') { 370 retstat = getvalue(auditstring, entry, 371 NAFLGLABEL, len); 372 if (retstat == SUCCESS) 373 gotone = 1; 374 } 375 } else if ((feof(context->fp)) == 0) { 376 retstat = ERROR; 377 } else { 378 retstat = EOF_WARN; 379 } 380 /* end of if-do */ 381 } while (gotone == 0 && retstat == SUCCESS); 382 383 if (context->file_pointer == FILE_AT_START) 384 context->file_pointer = FILE_MIDDLE; 385 else 386 _rewindac(context); 387 388 free(entry); 389 return (retstat); 390 } 391 392 /* 393 * _getacplug() - get plugin parameter line 394 * 395 * As with _getacdir, the caller is responsible for checking the 396 * validity of what's returned. 397 * 398 * outputs: keyvalue list (call _kva_free(list_ptr) when you're done with 399 * it.) 400 * 401 * returns: SUCCESS - entry read ok 402 * EOF_WARN - end of file 403 * REW_WARN - started over at the start of file 404 * ERROR - error - errno contains error number 405 * FORMAT_ERROR - fat finger failure 406 */ 407 #define MAX_ARG 256 408 409 int 410 _getacplug(au_acinfo_t *context, kva_t **kv_list) 411 { 412 int retstat = SUCCESS, got_one = 0; 413 char entry[REALLY_LONG_LINE]; 414 char value[REALLY_LONG_LINE]; 415 416 if (context == NULL) 417 return (NO_CONTEXT); 418 419 if (context->file_pointer != FILE_AT_START && context->once_read == 1) { 420 retstat = REW_WARN; 421 _rewindac(context); 422 } else { 423 context->once_read = 1; 424 context->file_pointer = FILE_AT_START; 425 } 426 427 if (retstat == SUCCESS) do { 428 if (getlongline(entry, REALLY_LONG_LINE, context->fp) != NULL) { 429 if (*entry == 'p') { 430 retstat = getvalue(value, entry, lib_label, 431 REALLY_LONG_LINE); 432 if (retstat == SUCCESS) 433 got_one = 1; 434 } 435 } else if ((feof(context->fp)) == 0) { 436 retstat = ERROR; 437 } else { 438 retstat = EOF_WARN; 439 } 440 /* end of if-do */ 441 } while ((got_one == 0) && (retstat == SUCCESS)); 442 443 /* value contains a list of attribute/value pairs */ 444 if (got_one) { 445 *kv_list = _str2kva(value, "=", ";"); 446 if (*kv_list == NULL) 447 retstat = FORMAT_ERR; 448 } else { 449 retstat = EOF_WARN; 450 *kv_list = NULL; 451 } 452 lib_exit: 453 454 return (retstat); 455 } 456 457 /* rewind the audit control file */ 458 void 459 _rewindac(au_acinfo_t *context) 460 { 461 rewind(context->fp); 462 context->file_pointer = FILE_AT_START; 463 context->once_read = 0; 464 } 465 466 /* 467 * _openac() open either the audit_control file or an alternate. 468 * A NULL input means use the real audit_control. 469 */ 470 471 au_acinfo_t * 472 _openac(char *filepath) 473 { 474 au_acinfo_t *context; 475 476 if (filepath == NULL) 477 filepath = AUDITCONTROLFILE; 478 479 context = malloc(sizeof (au_acinfo_t)); 480 if (context == NULL) 481 return (NULL); 482 483 context->file = strdup(filepath); 484 if (filepath == NULL) { 485 free(context); 486 return (NULL); 487 } 488 context->fp = fopen(filepath, "rF"); 489 if (context->fp == NULL) { 490 free(context->file); 491 free(context); 492 return (NULL); 493 } 494 context->file_pointer = FILE_AT_START; 495 context->once_read = 0; 496 return (context); 497 } 498 499 /* close the audit control file */ 500 void 501 _endac(au_acinfo_t *context) 502 { 503 if (context == NULL) 504 return; 505 506 if (context->fp != NULL) 507 (void) fclose(context->fp); 508 509 free(context->file); 510 free(context); 511 } 512