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