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