bsm_control.c revision 191273
1/*- 2 * Copyright (c) 2004, 2009 Apple Inc. 3 * Copyright (c) 2006 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_control.c#33 $ 31 */ 32 33#include <config/config.h> 34 35#include <bsm/libbsm.h> 36 37#include <ctype.h> 38#include <errno.h> 39#include <string.h> 40#ifdef HAVE_PTHREAD_MUTEX_LOCK 41#include <pthread.h> 42#endif 43#include <stdio.h> 44#include <stdlib.h> 45 46#ifndef HAVE_STRLCAT 47#include <compat/strlcat.h> 48#endif 49#ifndef HAVE_STRLCPY 50#include <compat/strlcpy.h> 51#endif 52 53#include <sys/stat.h> 54 55/* 56 * Parse the contents of the audit_control file to return the audit control 57 * parameters. These static fields are protected by 'mutex'. 58 */ 59static FILE *fp = NULL; 60static char linestr[AU_LINE_MAX]; 61static char *delim = ":"; 62 63static char inacdir = 0; 64static char ptrmoved = 0; 65 66#ifdef HAVE_PTHREAD_MUTEX_LOCK 67static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 68#endif 69 70/* 71 * Audit policy string token table for au_poltostr() and au_strtopol(). 72 */ 73struct audit_polstr { 74 long ap_policy; 75 const char *ap_str; 76}; 77 78static struct audit_polstr au_polstr[] = { 79 { AUDIT_CNT, "cnt" }, 80 { AUDIT_AHLT, "ahlt" }, 81 { AUDIT_ARGV, "argv" }, 82 { AUDIT_ARGE, "arge" }, 83 { AUDIT_SEQ, "seq" }, 84 { AUDIT_WINDATA, "windata" }, 85 { AUDIT_USER, "user" }, 86 { AUDIT_GROUP, "group" }, 87 { AUDIT_TRAIL, "trail" }, 88 { AUDIT_PATH, "path" }, 89 { AUDIT_SCNT, "scnt" }, 90 { AUDIT_PUBLIC, "public" }, 91 { AUDIT_ZONENAME, "zonename" }, 92 { AUDIT_PERZONE, "perzone" }, 93 { -1, NULL } 94}; 95 96/* 97 * Returns the string value corresponding to the given label from the 98 * configuration file. 99 * 100 * Must be called with mutex held. 101 */ 102static int 103getstrfromtype_locked(char *name, char **str) 104{ 105 char *type, *nl; 106 char *tokptr; 107 char *last; 108 109 *str = NULL; 110 111 if ((fp == NULL) && ((fp = fopen(AUDIT_CONTROL_FILE, "r")) == NULL)) 112 return (-1); /* Error */ 113 114 while (1) { 115 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) { 116 if (ferror(fp)) 117 return (-1); 118 return (0); /* EOF */ 119 } 120 121 if (linestr[0] == '#') 122 continue; 123 124 /* Remove trailing new line character. */ 125 if ((nl = strrchr(linestr, '\n')) != NULL) 126 *nl = '\0'; 127 128 tokptr = linestr; 129 if ((type = strtok_r(tokptr, delim, &last)) != NULL) { 130 if (strcmp(name, type) == 0) { 131 /* Found matching name. */ 132 *str = strtok_r(NULL, delim, &last); 133 if (*str == NULL) { 134 errno = EINVAL; 135 return (-1); /* Parse error in file */ 136 } 137 return (0); /* Success */ 138 } 139 } 140 } 141} 142 143/* 144 * Convert a given time value with a multiplier (seconds, hours, days, years) to 145 * seconds. Return 0 on success. 146 */ 147static int 148au_timetosec(time_t *seconds, u_long value, char mult) 149{ 150 if (NULL == seconds) 151 return (-1); 152 153 switch(mult) { 154 case 's': 155 /* seconds */ 156 *seconds = (time_t)value; 157 break; 158 159 case 'h': 160 /* hours */ 161 *seconds = (time_t)value * 60 * 60; 162 break; 163 164 case 'd': 165 /* days */ 166 *seconds = (time_t)value * 60 * 60 * 24; 167 break; 168 169 case 'y': 170 /* years. Add a day for each 4th (leap) year. */ 171 *seconds = (time_t)value * 60 * 60 * 24 * 364 + 172 ((time_t)value / 4) * 60 * 60 * 24; 173 break; 174 175 default: 176 return (-1); 177 } 178 return (0); 179} 180 181/* 182 * Convert a given disk space value with a multiplier (bytes, kilobytes, 183 * megabytes, gigabytes) to bytes. Return 0 on success. 184 */ 185static int 186au_spacetobytes(size_t *bytes, u_long value, char mult) 187{ 188 if (NULL == bytes) 189 return (-1); 190 191 switch(mult) { 192 case 'B': 193 case ' ': 194 /* Bytes */ 195 *bytes = (size_t)value; 196 break; 197 198 case 'K': 199 /* Kilobytes */ 200 *bytes = (size_t)value * 1024; 201 break; 202 203 case 'M': 204 /* Megabytes */ 205 *bytes = (size_t)value * 1024 * 1024; 206 break; 207 208 case 'G': 209 /* Gigabytes */ 210 *bytes = (size_t)value * 1024 * 1024 * 1024; 211 break; 212 213 default: 214 return (-1); 215 } 216 return (0); 217} 218 219/* 220 * Convert a policy to a string. Return -1 on failure, or >= 0 representing 221 * the actual size of the string placed in the buffer (excluding terminating 222 * nul). 223 */ 224ssize_t 225au_poltostr(int policy, size_t maxsize, char *buf) 226{ 227 int first = 1; 228 int i = 0; 229 230 if (maxsize < 1) 231 return (-1); 232 buf[0] = '\0'; 233 234 do { 235 if (policy & au_polstr[i].ap_policy) { 236 if (!first && strlcat(buf, ",", maxsize) >= maxsize) 237 return (-1); 238 if (strlcat(buf, au_polstr[i].ap_str, maxsize) >= 239 maxsize) 240 return (-1); 241 first = 0; 242 } 243 } while (NULL != au_polstr[++i].ap_str); 244 245 return (strlen(buf)); 246} 247 248/* 249 * Convert a string to a policy. Return -1 on failure (with errno EINVAL, 250 * ENOMEM) or 0 on success. 251 */ 252int 253au_strtopol(const char *polstr, int *policy) 254{ 255 char *bufp, *string; 256 char *buffer; 257 int i, matched; 258 259 *policy = 0; 260 buffer = strdup(polstr); 261 if (buffer == NULL) 262 return (-1); 263 264 bufp = buffer; 265 while ((string = strsep(&bufp, ",")) != NULL) { 266 matched = i = 0; 267 268 do { 269 if (strcmp(string, au_polstr[i].ap_str) == 0) { 270 *policy |= au_polstr[i].ap_policy; 271 matched = 1; 272 break; 273 } 274 } while (NULL != au_polstr[++i].ap_str); 275 276 if (!matched) { 277 free(buffer); 278 errno = EINVAL; 279 return (-1); 280 } 281 } 282 free(buffer); 283 return (0); 284} 285 286/* 287 * Rewind the file pointer to beginning. 288 */ 289static void 290setac_locked(void) 291{ 292 static time_t lastctime = 0; 293 struct stat sbuf; 294 295 ptrmoved = 1; 296 if (fp != NULL) { 297 /* 298 * Check to see if the file on disk has changed. If so, 299 * force a re-read of the file by closing it. 300 */ 301 if (fstat(fileno(fp), &sbuf) < 0) 302 goto closefp; 303 if (lastctime != sbuf.st_ctime) { 304 lastctime = sbuf.st_ctime; 305closefp: 306 fclose(fp); 307 fp = NULL; 308 return; 309 } 310 311 fseek(fp, 0, SEEK_SET); 312 } 313} 314 315void 316setac(void) 317{ 318 319#ifdef HAVE_PTHREAD_MUTEX_LOCK 320 pthread_mutex_lock(&mutex); 321#endif 322 setac_locked(); 323#ifdef HAVE_PTHREAD_MUTEX_LOCK 324 pthread_mutex_unlock(&mutex); 325#endif 326} 327 328/* 329 * Close the audit_control file. 330 */ 331void 332endac(void) 333{ 334 335#ifdef HAVE_PTHREAD_MUTEX_LOCK 336 pthread_mutex_lock(&mutex); 337#endif 338 ptrmoved = 1; 339 if (fp != NULL) { 340 fclose(fp); 341 fp = NULL; 342 } 343#ifdef HAVE_PTHREAD_MUTEX_LOCK 344 pthread_mutex_unlock(&mutex); 345#endif 346} 347 348/* 349 * Return audit directory information from the audit control file. 350 */ 351int 352getacdir(char *name, int len) 353{ 354 char *dir; 355 int ret = 0; 356 357 /* 358 * Check if another function was called between successive calls to 359 * getacdir. 360 */ 361#ifdef HAVE_PTHREAD_MUTEX_LOCK 362 pthread_mutex_lock(&mutex); 363#endif 364 if (inacdir && ptrmoved) { 365 ptrmoved = 0; 366 if (fp != NULL) 367 fseek(fp, 0, SEEK_SET); 368 ret = 2; 369 } 370 if (getstrfromtype_locked(DIR_CONTROL_ENTRY, &dir) < 0) { 371#ifdef HAVE_PTHREAD_MUTEX_LOCK 372 pthread_mutex_unlock(&mutex); 373#endif 374 return (-2); 375 } 376 if (dir == NULL) { 377#ifdef HAVE_PTHREAD_MUTEX_LOCK 378 pthread_mutex_unlock(&mutex); 379#endif 380 return (-1); 381 } 382 if (strlen(dir) >= (size_t)len) { 383#ifdef HAVE_PTHREAD_MUTEX_LOCK 384 pthread_mutex_unlock(&mutex); 385#endif 386 return (-3); 387 } 388 strlcpy(name, dir, len); 389#ifdef HAVE_PTHREAD_MUTEX_LOCK 390 pthread_mutex_unlock(&mutex); 391#endif 392 return (ret); 393} 394 395/* 396 * Return the minimum free diskspace value from the audit control file. 397 */ 398int 399getacmin(int *min_val) 400{ 401 char *min; 402 403#ifdef HAVE_PTHREAD_MUTEX_LOCK 404 pthread_mutex_lock(&mutex); 405#endif 406 setac_locked(); 407 if (getstrfromtype_locked(MINFREE_CONTROL_ENTRY, &min) < 0) { 408#ifdef HAVE_PTHREAD_MUTEX_LOCK 409 pthread_mutex_unlock(&mutex); 410#endif 411 return (-2); 412 } 413 if (min == NULL) { 414#ifdef HAVE_PTHREAD_MUTEX_LOCK 415 pthread_mutex_unlock(&mutex); 416#endif 417 return (1); 418 } 419 *min_val = atoi(min); 420#ifdef HAVE_PTHREAD_MUTEX_LOCK 421 pthread_mutex_unlock(&mutex); 422#endif 423 return (0); 424} 425 426/* 427 * Return the desired trail rotation size from the audit control file. 428 */ 429int 430getacfilesz(size_t *filesz_val) 431{ 432 char *str; 433 size_t val; 434 char mult; 435 int nparsed; 436 437#ifdef HAVE_PTHREAD_MUTEX_LOCK 438 pthread_mutex_lock(&mutex); 439#endif 440 setac_locked(); 441 if (getstrfromtype_locked(FILESZ_CONTROL_ENTRY, &str) < 0) { 442#ifdef HAVE_PTHREAD_MUTEX_LOCK 443 pthread_mutex_unlock(&mutex); 444#endif 445 return (-2); 446 } 447 if (str == NULL) { 448#ifdef HAVE_PTHREAD_MUTEX_LOCK 449 pthread_mutex_unlock(&mutex); 450#endif 451 errno = EINVAL; 452 return (1); 453 } 454 455 /* Trim off any leading white space. */ 456 while (*str == ' ' || *str == '\t') 457 str++; 458 459 nparsed = sscanf(str, "%ju%c", (uintmax_t *)&val, &mult); 460 461 switch (nparsed) { 462 case 1: 463 /* If no multiplier then assume 'B' (bytes). */ 464 mult = 'B'; 465 /* fall through */ 466 case 2: 467 if (au_spacetobytes(filesz_val, val, mult) == 0) 468 break; 469 /* fall through */ 470 default: 471 errno = EINVAL; 472#ifdef HAVE_PTHREAD_MUTEX_LOCK 473 pthread_mutex_unlock(&mutex); 474#endif 475 return (-1); 476 } 477 478 /* 479 * The file size must either be 0 or >= MIN_AUDIT_FILE_SIZE. 0 480 * indicates no rotation size. 481 */ 482 if (*filesz_val < 0 || (*filesz_val > 0 && 483 *filesz_val < MIN_AUDIT_FILE_SIZE)) { 484#ifdef HAVE_PTHREAD_MUTEX_LOCK 485 pthread_mutex_unlock(&mutex); 486#endif 487 filesz_val = 0L; 488 errno = EINVAL; 489 return (-1); 490 } 491#ifdef HAVE_PTHREAD_MUTEX_LOCK 492 pthread_mutex_unlock(&mutex); 493#endif 494 return (0); 495} 496 497/* 498 * Return the system audit value from the audit contol file. 499 */ 500int 501getacflg(char *auditstr, int len) 502{ 503 char *str; 504 505#ifdef HAVE_PTHREAD_MUTEX_LOCK 506 pthread_mutex_lock(&mutex); 507#endif 508 setac_locked(); 509 if (getstrfromtype_locked(FLAGS_CONTROL_ENTRY, &str) < 0) { 510#ifdef HAVE_PTHREAD_MUTEX_LOCK 511 pthread_mutex_unlock(&mutex); 512#endif 513 return (-2); 514 } 515 if (str == NULL) { 516#ifdef HAVE_PTHREAD_MUTEX_LOCK 517 pthread_mutex_unlock(&mutex); 518#endif 519 return (1); 520 } 521 if (strlen(str) >= (size_t)len) { 522#ifdef HAVE_PTHREAD_MUTEX_LOCK 523 pthread_mutex_unlock(&mutex); 524#endif 525 return (-3); 526 } 527 strlcpy(auditstr, str, len); 528#ifdef HAVE_PTHREAD_MUTEX_LOCK 529 pthread_mutex_unlock(&mutex); 530#endif 531 return (0); 532} 533 534/* 535 * Return the non attributable flags from the audit contol file. 536 */ 537int 538getacna(char *auditstr, int len) 539{ 540 char *str; 541 542#ifdef HAVE_PTHREAD_MUTEX_LOCK 543 pthread_mutex_lock(&mutex); 544#endif 545 setac_locked(); 546 if (getstrfromtype_locked(NA_CONTROL_ENTRY, &str) < 0) { 547#ifdef HAVE_PTHREAD_MUTEX_LOCK 548 pthread_mutex_unlock(&mutex); 549#endif 550 return (-2); 551 } 552 if (str == NULL) { 553#ifdef HAVE_PTHREAD_MUTEX_LOCK 554 pthread_mutex_unlock(&mutex); 555#endif 556 return (1); 557 } 558 if (strlen(str) >= (size_t)len) { 559#ifdef HAVE_PTHREAD_MUTEX_LOCK 560 pthread_mutex_unlock(&mutex); 561#endif 562 return (-3); 563 } 564 strlcpy(auditstr, str, len); 565#ifdef HAVE_PTHREAD_MUTEX_LOCK 566 pthread_mutex_unlock(&mutex); 567#endif 568 return (0); 569} 570 571/* 572 * Return the policy field from the audit control file. 573 */ 574int 575getacpol(char *auditstr, size_t len) 576{ 577 char *str; 578 579#ifdef HAVE_PTHREAD_MUTEX_LOCK 580 pthread_mutex_lock(&mutex); 581#endif 582 setac_locked(); 583 if (getstrfromtype_locked(POLICY_CONTROL_ENTRY, &str) < 0) { 584#ifdef HAVE_PTHREAD_MUTEX_LOCK 585 pthread_mutex_unlock(&mutex); 586#endif 587 return (-2); 588 } 589 if (str == NULL) { 590#ifdef HAVE_PTHREAD_MUTEX_LOCK 591 pthread_mutex_unlock(&mutex); 592#endif 593 return (-1); 594 } 595 if (strlen(str) >= len) { 596#ifdef HAVE_PTHREAD_MUTEX_LOCK 597 pthread_mutex_unlock(&mutex); 598#endif 599 return (-3); 600 } 601 strlcpy(auditstr, str, len); 602#ifdef HAVE_PTHREAD_MUTEX_LOCK 603 pthread_mutex_unlock(&mutex); 604#endif 605 return (0); 606} 607 608int 609getachost(char *auditstr, size_t len) 610{ 611 char *str; 612 613#ifdef HAVE_PTHREAD_MUTEX_LOCK 614 pthread_mutex_lock(&mutex); 615#endif 616 setac_locked(); 617 if (getstrfromtype_locked(AUDIT_HOST_CONTROL_ENTRY, &str) < 0) { 618#ifdef HAVE_PTHREAD_MUTEX_LOCK 619 pthread_mutex_unlock(&mutex); 620#endif 621 return (-2); 622 } 623 if (str == NULL) { 624#ifdef HAVE_PTHREAD_MUTEX_LOCK 625 pthread_mutex_unlock(&mutex); 626#endif 627 return (1); 628 } 629 if (strlen(str) >= len) { 630#ifdef HAVE_PTHREAD_MUTEX_LOCK 631 pthread_mutex_unlock(&mutex); 632#endif 633 return (-3); 634 } 635 strlcpy(auditstr, str, len); 636#ifdef HAVE_PTHREAD_MUTEX_LOCK 637 pthread_mutex_unlock(&mutex); 638#endif 639 return (0); 640} 641 642/* 643 * Set expiration conditions. 644 */ 645static int 646setexpirecond(time_t *age, size_t *size, u_long value, char mult) 647{ 648 649 if (isupper(mult) || ' ' == mult) 650 return (au_spacetobytes(size, value, mult)); 651 else 652 return (au_timetosec(age, value, mult)); 653} 654 655/* 656 * Return the expire-after field from the audit control file. 657 */ 658int 659getacexpire(int *andflg, time_t *age, size_t *size) 660{ 661 char *str; 662 int nparsed; 663 u_long val1, val2; 664 char mult1, mult2; 665 char andor[AU_LINE_MAX]; 666 667 *age = 0L; 668 *size = 0LL; 669 *andflg = 0; 670 671#ifdef HAVE_PTHREAD_MUTEX_LOCK 672 pthread_mutex_lock(&mutex); 673#endif 674 setac_locked(); 675 if (getstrfromtype_locked(EXPIRE_AFTER_CONTROL_ENTRY, &str) < 0) { 676#ifdef HAVE_PTHREAD_MUTEX_LOCK 677 pthread_mutex_unlock(&mutex); 678#endif 679 return (-2); 680 } 681 if (str == NULL) { 682#ifdef HAVE_PTHREAD_MUTEX_LOCK 683 pthread_mutex_unlock(&mutex); 684#endif 685 return (1); 686 } 687 688 /* First, trim off any leading white space. */ 689 while (*str == ' ' || *str == '\t') 690 str++; 691 692 nparsed = sscanf(str, "%lu%c%[ \tadnorADNOR]%lu%c", &val1, &mult1, 693 andor, &val2, &mult2); 694 695 switch (nparsed) { 696 case 1: 697 /* If no multiplier then assume 'B' (Bytes). */ 698 mult1 = 'B'; 699 /* fall through */ 700 case 2: 701 /* One expiration condition. */ 702 if (setexpirecond(age, size, val1, mult1) != 0) { 703#ifdef HAVE_PTHREAD_MUTEX_LOCK 704 pthread_mutex_unlock(&mutex); 705#endif 706 return (-1); 707 } 708 break; 709 710 case 5: 711 /* Two expiration conditions. */ 712 if (setexpirecond(age, size, val1, mult1) != 0 || 713 setexpirecond(age, size, val2, mult2) != 0) { 714#ifdef HAVE_PTHREAD_MUTEX_LOCK 715 pthread_mutex_unlock(&mutex); 716#endif 717 return (-1); 718 } 719 if (strcasestr(andor, "and") != NULL) 720 *andflg = 1; 721 else if (strcasestr(andor, "or") != NULL) 722 *andflg = 0; 723 else { 724#ifdef HAVE_PTHREAD_MUTEX_LOCK 725 pthread_mutex_unlock(&mutex); 726#endif 727 return (-1); 728 } 729 break; 730 731 default: 732#ifdef HAVE_PTHREAD_MUTEX_LOCK 733 pthread_mutex_unlock(&mutex); 734#endif 735 return (-1); 736 } 737 738#ifdef HAVE_PTHREAD_MUTEX_LOCK 739 pthread_mutex_unlock(&mutex); 740#endif 741 return (0); 742} 743