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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  26 /*        All Rights Reserved   */
  27 
  28 
  29 
  30 #include <errno.h>
  31 #include <fcntl.h>
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <strings.h>
  36 #include <signal.h>
  37 #include <unistd.h>
  38 #ifdef  __i386
  39 #include <libscf_priv.h>
  40 #endif /* __i386 */
  41 
  42 #include <bsm/adt.h>
  43 #include <bsm/adt_event.h>
  44 
  45 #include <sys/types.h>
  46 #include <sys/uadmin.h>
  47 #include <sys/wait.h>
  48 
  49 #define SMF_RST "/etc/svc/volatile/resetting"
  50 #define RETRY_COUNT 15  /* number of 1 sec retries for audit(1M) to complete */
  51 
  52 static const char *Usage = "Usage: %s cmd fcn [mdep]\n";
  53 
  54 static int closeout_audit(int, int);
  55 static int turnoff_auditd(void);
  56 static void wait_for_auqueue();
  57 static int change_audit_file(void);
  58 
  59 int
  60 main(int argc, char *argv[])
  61 {
  62         int cmd, fcn;
  63         uintptr_t mdep = NULL;
  64         sigset_t set;
  65         adt_session_data_t *ah;  /* audit session handle */
  66         adt_event_data_t *event = NULL; /* event to be generated */
  67         au_event_t event_id;
  68         enum adt_uadmin_fcn fcn_id;
  69 
  70         if (argc < 3 || argc > 4) {
  71                 (void) fprintf(stderr, Usage, argv[0]);
  72                 return (1);
  73         }
  74 
  75         (void) sigfillset(&set);
  76         (void) sigprocmask(SIG_BLOCK, &set, NULL);
  77 
  78         cmd = atoi(argv[1]);
  79         fcn = atoi(argv[2]);
  80         if (argc == 4) {        /* mdep argument given */
  81                 if (cmd != A_REBOOT && cmd != A_SHUTDOWN && cmd != A_DUMP &&
  82                     cmd != A_FREEZE) {
  83                         (void) fprintf(stderr, "%s: mdep argument not "
  84                             "allowed for this cmd value\n", argv[0]);
  85                         (void) fprintf(stderr, Usage, argv[0]);
  86                         return (1);
  87                 } else {
  88                         mdep = (uintptr_t)argv[3];
  89                 }
  90         }
  91 
  92         /* set up audit session and event */
  93         if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
  94                 (void) fprintf(stderr, "%s: can't start audit session\n",
  95                     argv[0]);
  96         }
  97         switch (cmd) {
  98         case A_SHUTDOWN:
  99                 event_id = ADT_uadmin_shutdown;
 100                 break;
 101         case A_REBOOT:
 102                 event_id = ADT_uadmin_reboot;
 103                 break;
 104         case A_DUMP:
 105                 event_id = ADT_uadmin_dump;
 106                 break;
 107         case A_REMOUNT:
 108                 event_id = ADT_uadmin_remount;
 109                 break;
 110         case A_FREEZE:
 111                 event_id = ADT_uadmin_freeze;
 112                 break;
 113         case A_FTRACE:
 114                 event_id = ADT_uadmin_ftrace;
 115                 break;
 116         case A_CONFIG:
 117                 event_id = ADT_uadmin_config;
 118                 break;
 119         case A_SWAPCTL:
 120                 event_id = ADT_uadmin_swapctl;
 121                 break;
 122         case A_INTRD:
 123                 event_id = ADT_uadmin_intrd;
 124                 break;
 125         default:
 126                 event_id = 0;
 127         }
 128         if ((event_id != 0) &&
 129             (event = adt_alloc_event(ah, event_id)) == NULL) {
 130                 (void) fprintf(stderr, "%s: can't allocate audit event\n",
 131                     argv[0]);
 132         }
 133         switch (fcn) {
 134         case AD_HALT:
 135                 fcn_id = ADT_UADMIN_FCN_AD_HALT;
 136                 break;
 137         case AD_POWEROFF:
 138                 fcn_id = ADT_UADMIN_FCN_AD_POWEROFF;
 139                 break;
 140         case AD_BOOT:
 141                 fcn_id = ADT_UADMIN_FCN_AD_BOOT;
 142                 break;
 143         case AD_IBOOT:
 144                 fcn_id = ADT_UADMIN_FCN_AD_IBOOT;
 145                 break;
 146         case AD_SBOOT:
 147                 fcn_id = ADT_UADMIN_FCN_AD_SBOOT;
 148                 break;
 149         case AD_SIBOOT:
 150                 fcn_id = ADT_UADMIN_FCN_AD_SIBOOT;
 151                 break;
 152         case AD_NOSYNC:
 153                 fcn_id = ADT_UADMIN_FCN_AD_NOSYNC;
 154                 break;
 155         case AD_FASTREBOOT:
 156 #ifdef __i386
 157                 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT;
 158                 mdep = NULL;    /* Ignore all arguments */
 159 #else /* __i386 */
 160                 fcn = AD_BOOT;
 161                 fcn_id = ADT_UADMIN_FCN_AD_BOOT;
 162 #endif /* __i386 */
 163                 break;
 164         case AD_FASTREBOOT_DRYRUN:
 165                 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT_DRYRUN;
 166                 mdep = NULL;    /* Ignore all arguments */
 167                 break;
 168         default:
 169                 fcn_id = 0;
 170         }
 171         if (cmd == A_FREEZE) {
 172                 switch (fcn) {
 173                 case AD_SUSPEND_TO_DISK:
 174                         fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK;
 175                         break;
 176                 case AD_CHECK_SUSPEND_TO_DISK:
 177                         fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_DISK;
 178                         break;
 179                 case AD_FORCE:
 180                         fcn_id = ADT_UADMIN_FCN_AD_FORCE;
 181                         break;
 182                 case AD_SUSPEND_TO_RAM:
 183                         fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM;
 184                         break;
 185                 case AD_CHECK_SUSPEND_TO_RAM:
 186                         fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_RAM;
 187                         break;
 188                 case AD_REUSEINIT:
 189                         fcn_id = ADT_UADMIN_FCN_AD_REUSEINIT;
 190                         break;
 191                 case AD_REUSABLE:
 192                         fcn_id = ADT_UADMIN_FCN_AD_REUSABLE;
 193                         break;
 194                 case AD_REUSEFINI:
 195                         fcn_id = ADT_UADMIN_FCN_AD_REUSEFINI;
 196                         break;
 197                 }
 198         } else if (cmd == A_FTRACE) {
 199                 switch (fcn) {
 200                 case AD_FTRACE_START:
 201                         fcn_id = ADT_UADMIN_FCN_AD_FTRACE_START;
 202                         break;
 203                 case AD_FTRACE_STOP:
 204                         fcn_id = ADT_UADMIN_FCN_AD_FTRACE_STOP;
 205                         break;
 206                 }
 207 #ifdef  __i386
 208         } else if (cmd == A_CONFIG) {
 209                 uint8_t boot_config = 0;
 210                 uint8_t boot_config_ovr = 0;
 211 
 212                 switch (fcn) {
 213                 case AD_UPDATE_BOOT_CONFIG:
 214                         fcn_id = ADT_UADMIN_FCN_AD_UPDATE_BOOT_CONFIG;
 215                         scf_get_boot_config(&boot_config);
 216                         boot_config_ovr = boot_config;
 217                         scf_get_boot_config_ovr(&boot_config_ovr);
 218                         boot_config &= boot_config_ovr;
 219                         mdep = (uintptr_t)(&boot_config);
 220                         break;
 221                 }
 222 #endif /* __i386 */
 223         }
 224 
 225         if (geteuid() == 0) {
 226                 if (event != NULL) {
 227                         switch (cmd) {
 228                         case A_SHUTDOWN:
 229                                 event->adt_uadmin_shutdown.fcn = fcn_id;
 230                                 event->adt_uadmin_shutdown.mdep = (char *)mdep;
 231                                 break;
 232                         case A_REBOOT:
 233                                 event->adt_uadmin_reboot.fcn = fcn_id;
 234                                 event->adt_uadmin_reboot.mdep = (char *)mdep;
 235                                 break;
 236                         case A_DUMP:
 237                                 event->adt_uadmin_dump.fcn = fcn_id;
 238                                 event->adt_uadmin_dump.mdep = (char *)mdep;
 239                                 break;
 240                         case A_REMOUNT:
 241                                 /* no parameters */
 242                                 break;
 243                         case A_FREEZE:
 244                                 event->adt_uadmin_freeze.fcn = fcn_id;
 245                                 event->adt_uadmin_freeze.mdep = (char *)mdep;
 246                                 break;
 247                         case A_FTRACE:
 248                                 event->adt_uadmin_ftrace.fcn = fcn_id;
 249                                 event->adt_uadmin_ftrace.mdep = (char *)mdep;
 250                                 break;
 251                         case A_CONFIG:
 252                                 event->adt_uadmin_config.fcn = fcn_id;
 253                                 event->adt_uadmin_config.mdep = (char *)mdep;
 254                                 break;
 255                         case A_SWAPCTL:
 256                                 event->adt_uadmin_swapctl.fcn = fcn_id;
 257                                 break;
 258                         case A_INTRD:
 259                                 event->adt_uadmin_intrd.fcn = fcn_id;
 260                                 break;
 261                         }
 262 
 263                         if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
 264                                 (void) fprintf(stderr,
 265                                     "%s: can't put audit event\n", argv[0]);
 266                         }
 267                         /*
 268                          * allow audit record to be processed in the kernel
 269                          * audit queue
 270                          */
 271                         wait_for_auqueue();
 272                 }
 273 
 274                 if (closeout_audit(cmd, fcn) == -1)
 275                         (void) fprintf(stderr, "%s: can't turn off auditd\n",
 276                             argv[0]);
 277 
 278                 if (cmd == A_SHUTDOWN || cmd == A_REBOOT)
 279                         (void) creat(SMF_RST, 0777);
 280         }
 281 
 282         (void) adt_free_event(event);
 283         if (uadmin(cmd, fcn, mdep) < 0) {
 284                 perror("uadmin");
 285 
 286                 (void) unlink(SMF_RST);
 287 
 288                 return (1);
 289         }
 290 
 291         /* If returning from a suspend, audit thaw */
 292         if ((cmd == A_FREEZE) &&
 293             ((fcn == AD_FORCE) ||
 294             (fcn == AD_REUSABLE) ||
 295             (fcn == AD_SUSPEND_TO_DISK) ||
 296             (fcn == AD_SUSPEND_TO_RAM))) {
 297                 if ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) == NULL) {
 298                         (void) fprintf(stderr, "%s: can't allocate thaw audit "
 299                             "event\n", argv[0]);
 300                 }
 301                 event->adt_uadmin_thaw.fcn = fcn_id;
 302                 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
 303                         (void) fprintf(stderr, "%s: can't put thaw audit "
 304                             "event\n", argv[0]);
 305                 }
 306                 (void) adt_free_event(event);
 307         }
 308         (void) adt_end_session(ah);
 309 
 310         return (0);
 311 }
 312 
 313 static int
 314 closeout_audit(int cmd, int fcn)
 315 {
 316         if (!adt_audit_state(AUC_AUDITING)) {
 317                 /* auditd not running, just return */
 318                 return (0);
 319         }
 320         switch (cmd) {
 321         case A_SHUTDOWN:
 322                 switch (fcn) {
 323                 case AD_FASTREBOOT_DRYRUN:
 324                         /* No system discontinuity, don't turn off auditd */
 325                         return (0);
 326                 default:
 327                         break;  /* For all the other shutdown functions */
 328                 }
 329                 /* FALLTHROUGH */
 330         case A_REBOOT:
 331         case A_DUMP:
 332                 /* system shutting down, turn off auditd */
 333                 return (turnoff_auditd());
 334         case A_REMOUNT:
 335         case A_SWAPCTL:
 336         case A_FTRACE:
 337         case A_CONFIG:
 338                 /* No system discontinuity, don't turn off auditd */
 339                 return (0);
 340         case A_FREEZE:
 341                 switch (fcn) {
 342                 case AD_CHECK_SUSPEND_TO_DISK:  /* AD_CHECK */
 343                 case AD_CHECK_SUSPEND_TO_RAM:
 344                 case AD_REUSEINIT:
 345                 case AD_REUSEFINI:
 346                         /* No system discontinuity, don't turn off auditd */
 347                         return (0);
 348                 case AD_REUSABLE:
 349                 case AD_SUSPEND_TO_DISK:        /* AD_COMPRESS */
 350                 case AD_SUSPEND_TO_RAM:
 351                 case AD_FORCE:
 352                         /* suspend the system, change audit files */
 353                         return (change_audit_file());
 354                 default:
 355                         return (0);     /* not an audit error */
 356                 }
 357         default:
 358                 return (0);     /* not an audit error */
 359         }
 360 }
 361 
 362 static int
 363 turnoff_auditd(void)
 364 {
 365         int     rc;
 366         int     retries = RETRY_COUNT;
 367 
 368         if ((rc = (int)fork()) == 0) {
 369                 (void) execl("/usr/sbin/audit", "audit", "-T", NULL);
 370                 (void) fprintf(stderr, "error disabling auditd: %s\n",
 371                     strerror(errno));
 372                 _exit(-1);
 373         } else if (rc == -1) {
 374                 (void) fprintf(stderr, "error disabling auditd: %s\n",
 375                     strerror(errno));
 376                 return (-1);
 377         }
 378 
 379         /*
 380          * wait for auditd to finish its work.  auditd will change the
 381          * auditstart from AUC_AUDITING (auditd up and running) to
 382          * AUC_NOAUDIT.  Other states are errors, so we're done as well.
 383          */
 384         do {
 385                 int     auditstate;
 386 
 387                 rc = -1;
 388                 if ((auditon(A_GETCOND, (caddr_t)&auditstate,
 389                     sizeof (auditstate)) == 0) &&
 390                     (auditstate == AUC_AUDITING)) {
 391                         retries--;
 392                         (void) sleep(1);
 393                 } else {
 394                         rc = 0;
 395                 }
 396         } while ((rc != 0) && (retries != 0));
 397 
 398         return (rc);
 399 }
 400 
 401 static int
 402 change_audit_file(void)
 403 {
 404         pid_t   pid;
 405 
 406         if ((pid = fork()) == 0) {
 407                 (void) execl("/usr/sbin/audit", "audit", "-n", NULL);
 408                 (void) fprintf(stderr, "error changing audit files: %s\n",
 409                     strerror(errno));
 410                 _exit(-1);
 411         } else if (pid == -1) {
 412                 (void) fprintf(stderr, "error changing audit files: %s\n",
 413                     strerror(errno));
 414                 return (-1);
 415         } else {
 416                 pid_t   rc;
 417                 int     retries = RETRY_COUNT;
 418 
 419                 /*
 420                  * Wait for audit(1M) -n process to complete
 421                  *
 422                  */
 423                 do {
 424                         if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) {
 425                                 return (0);
 426                         } else if (rc == -1) {
 427                                 return (-1);
 428                         } else {
 429                                 (void) sleep(1);
 430                                 retries--;
 431                         }
 432 
 433                 } while (retries != 0);
 434         }
 435         return (-1);
 436 }
 437 
 438 static void
 439 wait_for_auqueue()
 440 {
 441         au_stat_t       au_stat;
 442         int             retries = 10;
 443 
 444         while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) {
 445                 if (au_stat.as_enqueue == au_stat.as_written) {
 446                         break;
 447                 }
 448                 (void) sleep(1);
 449         }
 450 }