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