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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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/types.h> 34 #include <sys/wait.h> 35 #include <signal.h> 36 #include <sys/param.h> 37 #include <unistd.h> 38 #include <bsm/audit.h> 39 #include <bsm/libbsm.h> 40 #include <locale.h> 41 #include <audit_sig_infc.h> 42 #include <zone.h> 43 44 #if !defined(TEXT_DOMAIN) 45 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 46 #endif 47 48 #define VERIFY -1 49 50 /* GLOBALS */ 51 static char *progname = "audit"; 52 static char *usage = "audit [-n] | [-s] | [-t] | [-v filepath]"; 53 54 static void display_smf_error(); 55 56 static boolean_t is_audit_control_ok(char *); /* file validation */ 57 static boolean_t is_valid_zone(boolean_t); /* operation ok in this zone? */ 58 static int start_auditd(); /* start audit daemon */ 59 static int sig_auditd(int); /* send signal to auditd */ 60 61 /* 62 * audit() - This program serves as a general administrator's interface to 63 * the audit trail. Only one option is valid at a time. 64 * 65 * input: 66 * audit -s 67 * - signal audit daemon to read audit_control file and 68 * start auditd if needed. 69 * audit -n 70 * - signal audit daemon to use next audit_control audit directory. 71 * audit -t 72 * - signal audit daemon to permanently disable auditing. 73 * audit -v filepath 74 * - validate audit_control parameters but use filepath for 75 * the name. Emit errors or "syntax ok" 76 * 77 * 78 * output: 79 * 80 * returns: 0 - command successful 81 * >0 - command failed 82 */ 83 84 int 85 main(int argc, char *argv[]) 86 { 87 char c; 88 char *first_option; 89 90 /* Internationalization */ 91 (void) setlocale(LC_ALL, ""); 92 (void) textdomain(TEXT_DOMAIN); 93 94 /* first option required */ 95 if ((c = getopt(argc, argv, "nstv:")) == -1) { 96 (void) fprintf(stderr, gettext("usage: %s\n"), usage); 97 exit(3); 98 } 99 first_option = optarg; 100 /* second or more options not allowed; please pick one */ 101 if (getopt(argc, argv, "nstv:") != -1) { 102 (void) fprintf(stderr, gettext("usage: %s\n"), usage); 103 exit(5); 104 } 105 switch (c) { 106 case 'n': 107 if (!is_valid_zone(1)) /* 1 == display error if any */ 108 exit(10); 109 110 if (sig_auditd(AU_SIG_NEXT_DIR) != 0) 111 exit(1); 112 break; 113 case 's': 114 if (!is_valid_zone(1)) /* 1 == display error if any */ 115 exit(10); 116 else if (!is_audit_control_ok(NULL)) 117 exit(7); 118 119 return (start_auditd()); 120 case 't': 121 if (!is_valid_zone(0)) /* 0 == no error message display */ 122 exit(10); 123 if (smf_disable_instance(AUDITD_FMRI, 0) != 0) { 124 display_smf_error(); 125 exit(11); 126 } 127 break; 128 case 'v': 129 if (is_audit_control_ok(first_option)) { 130 (void) fprintf(stderr, gettext("syntax ok\n")); 131 exit(0); 132 } else { 133 exit(8); 134 } 135 break; 136 default: 137 (void) fprintf(stderr, gettext("usage: %s\n"), usage); 138 exit(6); 139 } 140 141 return (0); 142 } 143 144 /* 145 * sig_auditd(sig) 146 * 147 * send a signal to auditd service 148 * 149 * returns: 0 - successful 150 * 1 - error 151 */ 152 153 static int 154 sig_auditd(int sig) 155 { 156 scf_simple_prop_t *prop = NULL; 157 uint64_t *cid = NULL; 158 159 if ((prop = scf_simple_prop_get(NULL, AUDITD_FMRI, SCF_PG_RESTARTER, 160 SCF_PROPERTY_CONTRACT)) == NULL) { 161 display_smf_error(); 162 return (1); 163 } 164 if ((scf_simple_prop_numvalues(prop) < 0) || 165 (cid = scf_simple_prop_next_count(prop)) == NULL) { 166 scf_simple_prop_free(prop); 167 display_smf_error(); 168 return (1); 169 } 170 if (sigsend(P_CTID, (ctid_t)*cid, sig) != 0) { 171 perror("audit: can't signal auditd"); 172 scf_simple_prop_free(prop); 173 return (1); 174 } 175 scf_simple_prop_free(prop); 176 return (0); 177 } 178 179 /* 180 * perform reasonableness check on audit_control or its standin; goal 181 * is that "audit -s" (1) not crash the system and (2) c2audit/auditd 182 * actually generates data. 183 * 184 * A NULL input is ok -- it is used to tell _openac() to use the 185 * real audit_control file, not a substitute. 186 */ 187 #define TRADITIONAL_MAX 1024 188 189 static boolean_t 190 is_audit_control_ok(char *filename) { 191 char buf[TRADITIONAL_MAX]; 192 int outputs = 0; 193 int state = 1; /* 1 is ok, 0 is not */ 194 int rc; 195 int min; 196 kva_t *kvlist; 197 char *plugin_name; 198 char *plugin_dir; 199 au_acinfo_t *ach; 200 201 ach = _openac(filename); /* open audit_control */ 202 if (ach == NULL) { 203 perror(progname); 204 exit(9); 205 } 206 /* 207 * There must be at least one directory or one plugin 208 * defined. 209 */ 210 if ((rc = _getacdir(ach, buf, TRADITIONAL_MAX)) == 0) { 211 outputs++; 212 } else if (rc < -1) { /* -1 is not found, others are errors */ 213 (void) fprintf(stderr, 214 gettext("%s: audit_control \"dir:\" spec invalid\n"), 215 progname); 216 state = 0; /* is_not_ok */ 217 } 218 219 /* 220 * _getacplug -- all that is of interest is the return code. 221 */ 222 _rewindac(ach); /* rewind audit_control */ 223 while ((rc = _getacplug(ach, &kvlist)) == 0) { 224 plugin_name = kva_match(kvlist, "name"); 225 if (plugin_name == NULL) { 226 (void) fprintf(stderr, gettext("%s: audit_control " 227 "\"plugin:\" missing name\n"), progname); 228 state = 0; /* is_not_ok */ 229 } else { 230 if (strcmp(plugin_name, "audit_binfile.so") == 0) { 231 plugin_dir = kva_match(kvlist, "p_dir"); 232 if ((plugin_dir == NULL) && (outputs == 0)) { 233 (void) fprintf(stderr, 234 gettext("%s: audit_control " 235 "\"plugin:\" missing p_dir\n"), 236 progname); 237 state = 0; /* is_not_ok */ 238 } else { 239 outputs++; 240 } 241 } 242 } 243 _kva_free(kvlist); 244 } 245 if (rc < -1) { 246 (void) fprintf(stderr, 247 gettext("%s: audit_control \"plugin:\" spec invalid\n"), 248 progname); 249 state = 0; /* is_not_ok */ 250 } 251 if (outputs == 0) { 252 (void) fprintf(stderr, 253 gettext("%s: audit_control must have either a " 254 "valid \"dir:\" entry or a valid \"plugin:\" " 255 "entry with \"p_dir:\" specified.\n"), 256 progname); 257 state = 0; /* is_not_ok */ 258 } 259 /* minfree is not required */ 260 _rewindac(ach); 261 if ((rc = _getacmin(ach, &min)) < -1) { 262 (void) fprintf(stderr, 263 gettext( 264 "%s: audit_control \"minfree:\" spec invalid\n"), 265 progname); 266 state = 0; /* is_not_ok */ 267 } 268 /* flags is not required */ 269 _rewindac(ach); 270 if ((rc = _getacflg(ach, buf, TRADITIONAL_MAX)) < -1) { 271 (void) fprintf(stderr, 272 gettext("%s: audit_control \"flags:\" spec invalid\n"), 273 progname); 274 state = 0; /* is_not_ok */ 275 } 276 /* naflags is not required */ 277 _rewindac(ach); 278 if ((rc = _getacna(ach, buf, TRADITIONAL_MAX)) < -1) { 279 (void) fprintf(stderr, 280 gettext( 281 "%s: audit_control \"naflags:\" spec invalid\n"), 282 progname); 283 state = 0; /* is_not_ok */ 284 } 285 _endac(ach); 286 return (state); 287 } 288 289 /* 290 * The operations that call this function are only valid in the global 291 * zone unless the perzone audit policy is set. 292 */ 293 294 static boolean_t 295 is_valid_zone(boolean_t show_err) 296 { 297 long policy; 298 299 if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) { 300 (void) fprintf(stderr, gettext( 301 "%s: Cannot read audit policy: %s\n"), 302 progname, strerror(errno)); 303 return (0); 304 } 305 if (policy & AUDIT_PERZONE) 306 return (1); 307 308 if (getzoneid() != GLOBAL_ZONEID) { 309 if (show_err) 310 (void) fprintf(stderr, 311 gettext("%s: Not valid in a local zone.\n"), 312 progname); 313 return (0); 314 } else { 315 return (1); 316 } 317 } 318 319 /* 320 * if auditd isn't running, start it. Otherwise refresh. 321 * First check to see if c2audit is loaded via the auditon() 322 * system call, then check SMF state. 323 */ 324 static int 325 start_auditd() 326 { 327 int audit_state; 328 char *state; 329 330 if (auditon(A_GETCOND, (caddr_t)&audit_state, 331 sizeof (audit_state)) != 0) 332 return (12); 333 334 if ((state = smf_get_state(AUDITD_FMRI)) == NULL) { 335 display_smf_error(); 336 return (13); 337 } 338 if (strcmp(SCF_STATE_STRING_ONLINE, state) != 0) { 339 if (smf_enable_instance(AUDITD_FMRI, 0) != 0) { 340 display_smf_error(); 341 free(state); 342 return (14); 343 } 344 } else { 345 if (smf_refresh_instance(AUDITD_FMRI) != 0) { 346 display_smf_error(); 347 free(state); 348 return (15); 349 } 350 } 351 free(state); 352 return (0); 353 } 354 355 static void 356 display_smf_error() 357 { 358 scf_error_t rc = scf_error(); 359 360 switch (rc) { 361 case SCF_ERROR_NOT_FOUND: 362 (void) fprintf(stderr, 363 "SMF error: \"%s\" not found.\n", 364 AUDITD_FMRI); 365 break; 366 default: 367 (void) fprintf(stderr, "SMF error: %s\n", scf_strerror(rc)); 368 break; 369 } 370 } 371