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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Copyright (c) 2018, Joyent, Inc. 28 */ 29 30 #include <fcntl.h> 31 #include <libscf.h> 32 #include <secdb.h> 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <sys/file.h> 37 #include <sys/stat.h> 38 #include <sys/types.h> 39 #include <sys/wait.h> 40 #include <signal.h> 41 #include <sys/param.h> 42 #include <unistd.h> 43 #include <bsm/audit.h> 44 #include <bsm/libbsm.h> 45 #include <locale.h> 46 #include <zone.h> 47 #include <audit_scf.h> 48 49 #if !defined(TEXT_DOMAIN) 50 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 51 #endif 52 53 #define VERIFY -1 54 55 /* GLOBALS */ 56 static char *progname = "audit"; 57 static char *usage = "audit [-n] | [-s] | [-t] | [-v]"; 58 static int silent = 0; 59 60 static void display_smf_error(); 61 62 static boolean_t is_audit_config_ok(); /* config validation */ 63 static boolean_t is_valid_zone(boolean_t); /* operation ok in this zone? */ 64 static boolean_t contains_valid_dirs(char *); /* p_dir contents validation */ 65 static boolean_t validate_path(char *); /* is it path to dir? */ 66 static void start_auditd(); /* start audit daemon */ 67 static int sig_auditd(int); /* send signal to auditd */ 68 69 /* 70 * audit() - This program serves as a general administrator's interface to 71 * the audit trail. Only one option is valid at a time. 72 * 73 * input: 74 * audit -s 75 * - signal audit daemon to read audit configuration and 76 * start auditd if needed. 77 * audit -n 78 * - signal audit daemon to use next audit_binfile directory. 79 * audit -t 80 * - signal audit daemon to disable auditing. 81 * audit -T 82 * - signal audit daemon to temporarily disable auditing reporting 83 * no errors. 84 * audit -v 85 * - validate audit configuration parameters; 86 * Print errors or "configuration ok". 87 * 88 * 89 * output: 90 * 91 * returns: 0 - command successful 92 * >0 - command failed 93 */ 94 95 int 96 main(int argc, char *argv[]) 97 { 98 int c; 99 100 /* Internationalization */ 101 (void) setlocale(LC_ALL, ""); 102 (void) textdomain(TEXT_DOMAIN); 103 104 /* second or more options not allowed; please pick one */ 105 if (argc > 2) { 106 (void) fprintf(stderr, gettext("usage: %s\n"), usage); 107 exit(1); 108 } 109 110 /* first option required */ 111 if ((c = getopt(argc, argv, "nstTv")) == -1) { 112 (void) fprintf(stderr, gettext("usage: %s\n"), usage); 113 exit(1); 114 } 115 116 switch (c) { 117 case 'n': 118 if (!is_valid_zone(1)) /* 1 == display error if any */ 119 exit(1); 120 121 if (sig_auditd(SIGUSR1) != 0) 122 exit(1); 123 break; 124 case 's': 125 if (!is_valid_zone(1)) /* 1 == display error if any */ 126 exit(1); 127 else if (!is_audit_config_ok()) 128 exit(1); 129 130 start_auditd(); 131 return (0); 132 case 't': 133 if (!is_valid_zone(0)) /* 0 == no error message display */ 134 exit(1); 135 if (smf_disable_instance(AUDITD_FMRI, 0) != 0) { 136 display_smf_error(); 137 exit(1); 138 } 139 break; 140 case 'T': 141 silent = 1; 142 if (!is_valid_zone(0)) /* 0 == no error message display */ 143 exit(1); 144 if (smf_disable_instance(AUDITD_FMRI, SMF_TEMPORARY) != 0) { 145 exit(1); 146 } 147 break; 148 case 'v': 149 if (is_audit_config_ok()) { 150 (void) fprintf(stderr, gettext("configuration ok\n")); 151 exit(0); 152 } else { 153 exit(1); 154 } 155 break; 156 default: 157 (void) fprintf(stderr, gettext("usage: %s\n"), usage); 158 exit(1); 159 } 160 161 return (0); 162 } 163 164 /* 165 * sig_auditd(sig) 166 * 167 * send a signal to auditd service 168 * 169 * returns: 0 - successful 170 * 1 - error 171 */ 172 173 static int 174 sig_auditd(int sig) 175 { 176 scf_simple_prop_t *prop = NULL; 177 uint64_t *cid = NULL; 178 179 if ((prop = scf_simple_prop_get(NULL, AUDITD_FMRI, SCF_PG_RESTARTER, 180 SCF_PROPERTY_CONTRACT)) == NULL) { 181 display_smf_error(); 182 return (1); 183 } 184 if ((scf_simple_prop_numvalues(prop) < 0) || 185 (cid = scf_simple_prop_next_count(prop)) == NULL) { 186 scf_simple_prop_free(prop); 187 display_smf_error(); 188 return (1); 189 } 190 if (sigsend(P_CTID, (ctid_t)*cid, sig) != 0) { 191 perror("audit: can't signal auditd"); 192 scf_simple_prop_free(prop); 193 return (1); 194 } 195 scf_simple_prop_free(prop); 196 return (0); 197 } 198 199 /* 200 * perform reasonableness check on audit configuration 201 */ 202 203 static boolean_t 204 is_audit_config_ok() { 205 int state = B_TRUE; /* B_TRUE/B_FALSE = ok/not_ok */ 206 char *cval_str; 207 int cval_int; 208 kva_t *kvlist; 209 scf_plugin_kva_node_t *plugin_kva_ll; 210 scf_plugin_kva_node_t *plugin_kva_ll_head; 211 boolean_t one_plugin_enabled = B_FALSE; 212 213 /* 214 * There must be at least one active plugin configured; if the 215 * configured plugin is audit_binfile(5), then the p_dir must not be 216 * empty. 217 */ 218 if (!do_getpluginconfig_scf(NULL, &plugin_kva_ll)) { 219 (void) fprintf(stderr, 220 gettext("Could not get plugin configuration.\n")); 221 exit(1); 222 } 223 224 plugin_kva_ll_head = plugin_kva_ll; 225 226 while (plugin_kva_ll != NULL) { 227 kvlist = plugin_kva_ll->plugin_kva; 228 229 if (!one_plugin_enabled) { 230 cval_str = kva_match(kvlist, "active"); 231 if (atoi(cval_str) == 1) { 232 one_plugin_enabled = B_TRUE; 233 } 234 } 235 236 if (strcmp((char *)&(*plugin_kva_ll).plugin_name, 237 "audit_binfile") == 0) { 238 cval_str = kva_match(kvlist, "p_dir"); 239 if (cval_str == NULL || cval_str[0] == '\0') { 240 (void) fprintf(stderr, 241 gettext("%s: audit_binfile(5) \"p_dir:\" " 242 "attribute empty\n"), progname); 243 state = B_FALSE; 244 } else if (!contains_valid_dirs(cval_str)) { 245 (void) fprintf(stderr, 246 gettext("%s: audit_binfile(5) \"p_dir:\" " 247 "attribute invalid\n"), progname); 248 state = B_FALSE; 249 } 250 251 cval_str = kva_match(kvlist, "p_minfree"); 252 cval_int = atoi(cval_str); 253 if (cval_int < 0 || cval_int > 100) { 254 (void) fprintf(stderr, 255 gettext("%s: audit_binfile(5) " 256 "\"p_minfree:\" attribute invalid\n"), 257 progname); 258 state = B_FALSE; 259 } 260 } 261 262 plugin_kva_ll = plugin_kva_ll->next; 263 } 264 265 plugin_kva_ll_free(plugin_kva_ll_head); 266 267 if (!one_plugin_enabled) { 268 (void) fprintf(stderr, gettext("%s: no active plugin found\n"), 269 progname); 270 state = B_FALSE; 271 } 272 273 return (state); 274 } 275 276 /* 277 * The operations that call this function are only valid in the global 278 * zone unless the perzone audit policy is set. 279 * 280 * "!silent" and "show_err" are slightly different; silent is from 281 * -T for which no error messages should be displayed and show_err 282 * applies to more options (including -T) 283 * 284 */ 285 286 static boolean_t 287 is_valid_zone(boolean_t show_err) 288 { 289 uint32_t policy; 290 291 if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) { 292 if (!silent) { 293 (void) fprintf(stderr, gettext( 294 "%s: Cannot read audit policy: %s\n"), 295 progname, strerror(errno)); 296 } 297 return (0); 298 } 299 if (policy & AUDIT_PERZONE) 300 return (1); 301 302 if (getzoneid() != GLOBAL_ZONEID) { 303 if (show_err) 304 (void) fprintf(stderr, 305 gettext("%s: Not valid in a local zone.\n"), 306 progname); 307 return (0); 308 } else { 309 return (1); 310 } 311 } 312 313 /* 314 * Verify, whether the dirs_str contains at least one currently valid path to 315 * the directory. All invalid paths are reported. In case no valid directory 316 * path is found function returns B_FALSE, otherwise B_TRUE. 317 */ 318 319 static boolean_t 320 contains_valid_dirs(char *dirs_str) 321 { 322 boolean_t rc = B_FALSE; 323 boolean_t rc_validate_path = B_TRUE; 324 char *tok_ptr; 325 char *tok_lasts; 326 327 if (dirs_str == NULL) { 328 return (rc); 329 } 330 331 if ((tok_ptr = strtok_r(dirs_str, ",", &tok_lasts)) != NULL) { 332 if (validate_path(tok_ptr)) { 333 rc = B_TRUE; 334 } else { 335 rc_validate_path = B_FALSE; 336 } 337 while ((tok_ptr = strtok_r(NULL, ",", &tok_lasts)) != NULL) { 338 if (validate_path(tok_ptr)) { 339 rc = B_TRUE; 340 } else { 341 rc_validate_path = B_FALSE; 342 } 343 } 344 } 345 346 if (rc && !rc_validate_path) { 347 (void) fprintf(stderr, gettext("%s: at least one valid " 348 "directory path found\n"), progname); 349 } 350 351 return (rc); 352 } 353 354 /* 355 * Verify, that the dir_path is path to a directory. 356 */ 357 358 static boolean_t 359 validate_path(char *dir_path) 360 { 361 boolean_t rc = B_FALSE; 362 struct stat statbuf; 363 364 if (dir_path == NULL) { 365 return (rc); 366 } 367 368 if (stat(dir_path, &statbuf) == -1) { 369 (void) fprintf(stderr, gettext("%s: %s error: %s\n"), progname, 370 dir_path, strerror(errno)); 371 } else if (statbuf.st_mode & S_IFDIR) { 372 rc = B_TRUE; 373 } else { 374 (void) fprintf(stderr, gettext("%s: %s is not a directory\n"), 375 progname, dir_path); 376 } 377 378 return (rc); 379 } 380 381 /* 382 * if auditd isn't running, start it. Otherwise refresh. 383 * First check to see if c2audit is loaded via the auditon() 384 * system call, then check SMF state. 385 */ 386 static void 387 start_auditd() 388 { 389 int audit_state; 390 char *state; 391 392 if (auditon(A_GETCOND, (caddr_t)&audit_state, 393 sizeof (audit_state)) != 0) 394 exit(1); 395 396 if ((state = smf_get_state(AUDITD_FMRI)) == NULL) { 397 display_smf_error(); 398 exit(1); 399 } 400 if (strcmp(SCF_STATE_STRING_ONLINE, state) != 0) { 401 if (smf_enable_instance(AUDITD_FMRI, 0) != 0) { 402 display_smf_error(); 403 free(state); 404 exit(1); 405 } 406 } else { 407 if (smf_refresh_instance(AUDITD_FMRI) != 0) { 408 display_smf_error(); 409 free(state); 410 exit(1); 411 } 412 } 413 free(state); 414 } 415 416 static void 417 display_smf_error() 418 { 419 scf_error_t rc = scf_error(); 420 421 switch (rc) { 422 case SCF_ERROR_NOT_FOUND: 423 (void) fprintf(stderr, 424 "SMF error: \"%s\" not found.\n", 425 AUDITD_FMRI); 426 break; 427 default: 428 (void) fprintf(stderr, "SMF error: %s\n", scf_strerror(rc)); 429 break; 430 } 431 }