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
main(int argc,char * argv[])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
sig_auditd(int sig)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
is_audit_config_ok()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
is_valid_zone(boolean_t show_err)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
contains_valid_dirs(char * dirs_str)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
validate_path(char * dir_path)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
start_auditd()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
display_smf_error()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