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