Print this page
11972 resync smatch
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/auditreduce/main.c
+++ new/usr/src/cmd/auditreduce/main.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
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 + * Copyright 2019 Joyent, Inc.
29 + */
30 +
31 +/*
28 32 * The Secure SunOS audit reduction tool - auditreduce.
29 33 * Document SM0071 is the primary source of information on auditreduce.
30 34 *
31 35 * Composed of 4 source modules:
32 36 * main.c - main driver.
33 37 * option.c - command line option processing.
34 38 * process.c - record/file/process functions.
35 39 * time.c - date/time handling.
36 40 *
37 41 * Main(), write_header(), audit_stats(), and a_calloc()
38 42 * are the only functions visible outside this module.
39 43 */
40 44
41 45 #include <siginfo.h>
42 46 #include <locale.h>
43 47 #include <libintl.h>
44 48 #include "auditr.h"
45 49 #include "auditrd.h"
46 50
47 51 #if !defined(TEXT_DOMAIN)
48 52 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
49 53 #endif
50 54
51 55 extern void derive_str(time_t, char *);
52 56 extern int process_options(int, char **);
53 57 extern int mproc(audit_pcb_t *);
54 58 extern void init_tokens(void); /* shared with praudit */
55 59
56 60 static int a_pow(int, int);
57 61 static void calc_procs(void);
58 62 static void chld_handler(int);
59 63 static int close_outfile(void);
60 64 static void c_close(audit_pcb_t *, int);
61 65 static void delete_infiles(void);
62 66 static void gather_pcb(audit_pcb_t *, int, int);
63 67 static void init_options(void);
64 68 static int init_sig(void);
65 69 static void int_handler(int);
66 70 static int mfork(audit_pcb_t *, int, int, int);
67 71 static void mcount(int, int);
68 72 static int open_outfile(void);
69 73 static void p_close(audit_pcb_t *);
70 74 static int rename_outfile(void);
71 75 static void rm_mem(audit_pcb_t *);
72 76 static void rm_outfile(void);
73 77 static void trim_mem(audit_pcb_t *);
74 78 static int write_file_token(time_t);
75 79 static int write_trailer(void);
76 80
77 81 /*
78 82 * File globals.
79 83 */
80 84 static int max_sproc; /* maximum number of subprocesses per process */
81 85 static int total_procs; /* number of processes in the process tree */
82 86 static int total_layers; /* number of layers in the process tree */
83 87
84 88 /*
85 89 * .func main - main.
86 90 * .desc The beginning. Main() calls each of the initialization routines
87 91 * and then allocates the root pcb. Then it calls mfork() to get
88 92 * the work done.
89 93 * .call main(argc, argv).
90 94 * .arg argc - number of arguments.
91 95 * .arg argv - array of pointers to arguments.
92 96 * .ret 0 - via exit() - no errors detected.
93 97 * .ret 1 - via exit() - errors detected (messages printed).
94 98 */
95 99 int
96 100 main(int argc, char **argv)
97 101 {
98 102 int ret;
99 103 audit_pcb_t *pcb;
100 104
101 105 /* Internationalization */
102 106 (void) setlocale(LC_ALL, "");
103 107 (void) textdomain(TEXT_DOMAIN);
104 108
105 109 root_pid = getpid(); /* know who is root process for error */
106 110 init_options(); /* initialize options */
107 111 init_tokens(); /* initialize token processing table */
108 112 if (init_sig()) /* initialize signals */
109 113 exit(1);
110 114 if (process_options(argc, argv))
111 115 exit(1); /* process command line options */
112 116 if (open_outfile()) /* setup root process output stream */
113 117 exit(1);
114 118 calc_procs(); /* see how many subprocesses we need */
115 119 /*
116 120 * Allocate the root pcb and set it up.
117 121 */
118 122 pcb = (audit_pcb_t *)a_calloc(1, sizeof (audit_pcb_t));
119 123 pcb->pcb_procno = root_pid;
120 124 pcb->pcb_flags |= PF_ROOT;
121 125 pcb->pcb_fpw = stdout;
122 126 pcb->pcb_time = -1;
123 127 /*
124 128 * Now start the whole thing rolling.
125 129 */
126 130 if (mfork(pcb, pcbnum, 0, pcbnum - 1)) {
127 131 /*
128 132 * Error in processing somewhere. A message is already printed.
129 133 * Display usage statistics and remove the outfile.
130 134 */
131 135 if (getpid() == root_pid) {
132 136 audit_stats();
133 137 (void) close_outfile();
134 138 rm_outfile();
135 139 }
136 140 exit(1);
137 141 }
138 142 /*
139 143 * Clean up afterwards.
140 144 * Only do outfile cleanup if we are root process.
141 145 */
142 146 if (getpid() == root_pid) {
143 147 if ((ret = write_trailer()) == 0) { /* write trailer to file */
144 148
145 149 ret = close_outfile(); /* close the outfile */
146 150 }
147 151 /*
148 152 * If there was an error in cleanup then remove outfile.
149 153 */
150 154 if (ret) {
151 155 rm_outfile();
152 156 exit(1);
153 157 }
154 158 /*
155 159 * And lastly delete the infiles if the user so wishes.
156 160 */
157 161 if (f_delete)
158 162 delete_infiles();
159 163 }
160 164 return (0);
161 165 /*NOTREACHED*/
162 166 }
163 167
164 168
165 169 /*
166 170 * .func mfork - main fork routine.
167 171 * .desc Create a (sub-)tree of processses if needed, or just do the work
168 172 * if we have few enough groups to process. This is a recursive routine
169 173 * which stops recursing when the number of files to process is small
170 174 * enough. Each call to mfork() is responsible for a range of pcbs
171 175 * from audit_pcbs[]. This range is designated by the lo and hi
172 176 * arguments (inclusive). If the number of pcbs is small enough
173 177 * then we have hit a leaf of the tree and mproc() is called to
174 178 * do the processing. Otherwise we fork some processes and break
175 179 * the range of pcbs up amongst them.
176 180 * .call ret = mfork(pcb, nsp, lo, hi).
177 181 * .arg pcb - ptr to pcb that is root node of the to-be-created tree.
178 182 * .arg nsp - number of sub-processes this tree must process.
179 183 * .arg lo - lower-limit of process number range. Index into audit_pcbs.
180 184 * .arg hi - higher limit of pcb range. Index into audit_pcbs.
181 185 * .ret 0 - succesful completion.
182 186 * .ret -1 - error encountered in processing - message already printed.
183 187 */
184 188 static int
185 189 mfork(audit_pcb_t *pcb, int nsp, int lo, int hi)
186 190 {
187 191 int range, procno, i, tofork, nnsp, nrem;
188 192 int fildes[2];
189 193 audit_pcb_t *pcbn;
190 194
191 195 #if AUDIT_PROC_TRACE
192 196 (void) fprintf(stderr, "mfork: nsp %d %d->%d\n", nsp, lo, hi);
193 197 #endif
194 198
195 199 /*
196 200 * The range of pcb's to process is small enough now. Do the work.
197 201 */
198 202 if (nsp <= max_sproc) {
199 203 pcb->pcb_flags |= PF_LEAF; /* leaf in process tree */
200 204 pcb->pcb_below = audit_pcbs; /* proc pcbs from audit_pcbs */
201 205 gather_pcb(pcb, lo, hi);
202 206 trim_mem(pcb); /* trim allocated memory */
203 207 return (mproc(pcb)); /* do the work */
204 208 }
205 209 /*
206 210 * Too many pcb's for one process - must fork.
207 211 * Try to balance the tree as it grows and make it short and fat.
208 212 * The thing to minimize is the number of times a record passes
209 213 * through a pipe.
210 214 */
211 215 else {
212 216 /*
213 217 * Fork less than the maximum number of processes.
214 218 */
215 219 if (nsp <= max_sproc * (max_sproc - 1)) {
216 220 tofork = nsp / max_sproc;
217 221 if (nsp % max_sproc)
218 222 tofork++; /* how many to fork */
219 223 }
220 224 /*
221 225 * Fork the maximum number of processes.
222 226 */
223 227 else {
224 228 tofork = max_sproc; /* how many to fork */
225 229 }
226 230 /*
227 231 * Allocate the nodes below us in the process tree.
228 232 */
229 233 pcb->pcb_below = (audit_pcb_t *)
230 234 a_calloc(tofork, sizeof (*pcb));
231 235 nnsp = nsp / tofork; /* # of pcbs per forked process */
232 236 nrem = nsp % tofork; /* remainder to spread around */
233 237 /*
234 238 * Loop to fork all of the subs. Open a pipe for each.
235 239 * If there are any errors in pipes, forks, or getting streams
236 240 * for the pipes then quit altogether.
237 241 */
238 242 for (i = 0; i < tofork; i++) {
239 243 pcbn = &pcb->pcb_below[i];
↓ open down ↓ |
202 lines elided |
↑ open up ↑ |
240 244 pcbn->pcb_time = -1;
241 245 if (pipe(fildes)) {
242 246 perror(gettext(
243 247 "auditreduce: couldn't get a pipe"));
244 248 return (-1);
245 249 }
246 250 /*
247 251 * Convert descriptors to streams.
248 252 */
249 253 if ((pcbn->pcb_fpr = fdopen(fildes[0], "r")) == NULL) {
250 - perror(gettext("auditreduce: couldn't get read stream for pipe"));
254 + perror(gettext("auditreduce: couldn't get read "
255 + "stream for pipe"));
251 256 return (-1);
252 257 }
253 258 if ((pcbn->pcb_fpw = fdopen(fildes[1], "w")) == NULL) {
254 - perror(gettext("auditreduce: couldn't get write stream for pipe"));
259 + perror(gettext("auditreduce: couldn't get "
260 + "write stream for pipe"));
255 261 return (-1);
256 262 }
257 263 if ((procno = fork()) == -1) {
258 264 perror(gettext("auditreduce: fork failed"));
259 265 return (-1);
260 266 }
261 267 /*
262 268 * Calculate the range of pcbs from audit_pcbs [] this
263 269 * branch of the tree will be responsible for.
264 270 */
265 271 range = (nrem > 0) ? nnsp + 1 : nnsp;
266 272 /*
267 273 * Child route.
268 274 */
269 275 if (procno == 0) {
270 276 pcbn->pcb_procno = getpid();
271 277 c_close(pcb, i); /* close unused streams */
272 278 /*
273 279 * Continue resolving this branch.
274 280 */
275 281 return (mfork(pcbn, range, lo, lo + range - 1));
276 282 }
277 283 /* Parent route. */
278 284 else {
279 285 pcbn->pcb_procno = i;
280 286 /* allocate buffer to hold record */
281 287 pcbn->pcb_rec = (char *)a_calloc(1,
282 288 AUDITBUFSIZE);
283 289 pcbn->pcb_size = AUDITBUFSIZE;
284 290 p_close(pcbn); /* close unused streams */
285 291
286 292 nrem--;
287 293 lo += range;
288 294 }
289 295 }
290 296 /*
291 297 * Done forking all of the subs.
292 298 */
293 299 gather_pcb(pcb, 0, tofork - 1);
294 300 trim_mem(pcb); /* free unused memory */
295 301 return (mproc(pcb));
296 302 }
297 303 }
298 304
299 305
300 306 /*
301 307 * .func trim_mem - trim memory usage.
302 308 * .desc Free un-needed allocated memory.
303 309 * .call trim_mem(pcb).
304 310 * .arg pcb - ptr to pcb for current process.
305 311 * .ret void.
306 312 */
307 313 static void
308 314 trim_mem(audit_pcb_t *pcb)
309 315 {
310 316 int count;
311 317 size_t size;
312 318
313 319 /*
314 320 * For the root don't free anything. We need to save audit_pcbs[]
315 321 * in case we are deleting the infiles at the end.
316 322 */
317 323 if (pcb->pcb_flags & PF_ROOT)
318 324 return;
319 325 /*
320 326 * For a leaf save its part of audit_pcbs[] and then remove it all.
321 327 */
322 328 if (pcb->pcb_flags & PF_LEAF) {
323 329 count = pcb->pcb_count;
324 330 size = sizeof (audit_pcb_t);
325 331 /* allocate a new buffer to hold the pcbs */
326 332 pcb->pcb_below = (audit_pcb_t *)a_calloc(count, size);
327 333 /* save this pcb's portion */
328 334 (void) memcpy((void *) pcb->pcb_below,
329 335 (void *) &audit_pcbs[pcb->pcb_lo], count * size);
330 336 rm_mem(pcb);
331 337 gather_pcb(pcb, 0, count - 1);
332 338 }
333 339 /*
334 340 * If this is an intermediate node then just remove it all.
335 341 */
336 342 else {
337 343 rm_mem(pcb);
338 344 }
339 345 }
340 346
341 347
342 348 /*
343 349 * .func rm_mem - remove memory.
344 350 * .desc Remove unused memory associated with audit_pcbs[]. For each
345 351 * pcb in audit_pcbs[] free the record buffer and all of
346 352 * the fcbs. Then free audit_pcbs[].
347 353 * .call rm_mem(pcbr).
348 354 * .arg pcbr - ptr to pcb of current process.
349 355 * .ret void.
350 356 */
351 357 static void
352 358 rm_mem(audit_pcb_t *pcbr)
353 359 {
354 360 int i;
355 361 audit_pcb_t *pcb;
356 362 audit_fcb_t *fcb, *fcbn;
357 363
358 364 for (i = 0; i < pcbsize; i++) {
359 365 /*
360 366 * Don't free the record buffer and fcbs for the pcbs this
361 367 * process is using.
362 368 */
363 369 if (pcbr->pcb_flags & PF_LEAF) {
364 370 if (pcbr->pcb_lo <= i || i <= pcbr->pcb_hi)
365 371 continue;
366 372 }
367 373 pcb = &audit_pcbs[i];
368 374 free(pcb->pcb_rec);
369 375 for (fcb = pcb->pcb_first; fcb != NULL; /* */) {
370 376 fcbn = fcb->fcb_next;
371 377 free((char *)fcb);
372 378 fcb = fcbn;
373 379 }
374 380 }
375 381 free((char *)audit_pcbs);
376 382 }
377 383
378 384
379 385 /*
380 386 * .func c_close - close unused streams.
381 387 * .desc This is called for each child process just after being born.
382 388 * The child closes the read stream for the pipe to its parent.
383 389 * It also closes the read streams for the other children that
384 390 * have been born before it. If any closes fail a warning message
385 391 * is printed, but processing continues.
386 392 * .call ret = c_close(pcb, i).
387 393 * .arg pcb - ptr to the child's parent pcb.
388 394 * .arg i - iteration # of child in forking loop.
389 395 * .ret void.
390 396 */
391 397 static void
392 398 c_close(audit_pcb_t *pcb, int i)
↓ open down ↓ |
128 lines elided |
↑ open up ↑ |
393 399 {
394 400 int j;
395 401 audit_pcb_t *pcbt;
396 402
397 403 /*
398 404 * Do all pcbs in parent's group up to and including us
399 405 */
400 406 for (j = 0; j <= i; j++) {
401 407 pcbt = &pcb->pcb_below[j];
402 408 if (fclose(pcbt->pcb_fpr) == EOF) {
403 - if (!f_quiet)
404 - perror(gettext("auditreduce: initial close on pipe failed"));
409 + if (!f_quiet) {
410 + perror(gettext("auditreduce: initial close "
411 + "on pipe failed"));
412 + }
405 413 }
406 414 /*
407 415 * Free the buffer allocated to hold incoming records.
408 416 */
409 417 if (i != j) {
410 418 free(pcbt->pcb_rec);
411 419 }
412 420 }
413 421 }
414 422
415 423
416 424 /*
417 425 * .func p_close - close unused streams for parent.
418 426 * .desc Called by the parent right after forking a child.
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
419 427 * Closes the write stream on the pipe to the child since
420 428 * we will never use it.
421 429 * .call p_close(pcbn),
422 430 * .arg pcbn - ptr to pcb.
423 431 * .ret void.
424 432 */
425 433 static void
426 434 p_close(audit_pcb_t *pcbn)
427 435 {
428 436 if (fclose(pcbn->pcb_fpw) == EOF) {
429 - if (!f_quiet)
430 - perror(gettext("auditreduce: close for write pipe failed"));
437 + if (!f_quiet) {
438 + perror(gettext("auditreduce: close for write "
439 + "pipe failed"));
440 + }
431 441 }
432 442 }
433 443
434 444
435 445 /*
436 446 * .func audit_stats - print statistics.
437 447 * .desc Print usage statistics for the user if the run fails.
438 448 * Tells them how many files they had and how many groups this
439 449 * totalled. Also tell them how many layers and processes the
440 450 * process tree had.
441 451 * .call audit_stats().
442 452 * .arg none.
443 453 * .ret void.
444 454 */
445 455 void
446 456 audit_stats(void)
447 457 {
448 458 struct rlimit rl;
449 459
450 460 if (getrlimit(RLIMIT_NOFILE, &rl) != -1)
451 461 (void) fprintf(stderr,
452 462 gettext("%s The system allows %d files per process.\n"),
453 463 ar, rl.rlim_cur);
454 464 (void) fprintf(stderr, gettext(
455 465 "%s There were %d file(s) %d file group(s) %d process(es) %d layer(s).\n"),
456 466 ar, filenum, pcbnum, total_procs, total_layers);
457 467 }
458 468
459 469
460 470 /*
461 471 * .func gather_pcb - gather pcbs.
462 472 * .desc Gather together the range of the sub-processes that we are
463 473 * responsible for. For a pcb that controls processes this is all
464 474 * of the sub-processes that it forks. For a pcb that controls
465 475 * files this is the the range of pcbs from audit_pcbs[].
466 476 * .call gather_pcb(pcb, lo, hi).
467 477 * .arg pcb - ptr to pcb.
468 478 * .arg lo - lo index into pcb_below.
469 479 * .arg hi - hi index into pcb_below.
470 480 * .ret void.
471 481 */
472 482 static void
473 483 gather_pcb(audit_pcb_t *pcb, int lo, int hi)
474 484 {
475 485 pcb->pcb_lo = lo;
476 486 pcb->pcb_hi = hi;
477 487 pcb->pcb_count = hi - lo + 1;
478 488 }
479 489
480 490
481 491 /*
482 492 * .func calc_procs - calculate process parameters.
483 493 * .desc Calculate the current run's paramters regarding how many
484 494 * processes will have to be forked (maybe none).
485 495 * 5 is subtracted from maxfiles_proc to allow for stdin, stdout,
486 496 * stderr, and the pipe to a parent process. The outfile
487 497 * in the root process is assigned to stdout. The unused half of each
488 498 * pipe is closed, to allow for more connections, but we still
489 499 * have to have the 5th spot because in order to get the pipe
490 500 * we need 2 descriptors up front.
491 501 * .call calc_procs().
492 502 * .arg none.
493 503 * .ret void.
494 504 */
495 505 static void
496 506 calc_procs(void)
497 507 {
498 508 int val;
499 509 int maxfiles_proc;
500 510 struct rlimit rl;
501 511
502 512 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
503 513 perror("auditreduce: getrlimit");
504 514 exit(1);
505 515 }
506 516
507 517 maxfiles_proc = rl.rlim_cur;
508 518
509 519 max_sproc = maxfiles_proc - 5; /* max subprocesses per process */
510 520
511 521 /*
512 522 * Calculate how many layers the process tree has.
513 523 */
514 524 total_layers = 1;
515 525 for (/* */; /* */; /* */) {
516 526 val = a_pow(max_sproc, total_layers);
517 527 if (val > pcbnum)
518 528 break;
519 529 total_layers++;
520 530 }
521 531 /*
522 532 * Count how many processes are in the process tree.
523 533 */
524 534 mcount(pcbnum, 0);
525 535
526 536 #if AUDIT_PROC_TRACE
527 537 (void) fprintf(stderr,
528 538 "pcbnum %d filenum %d mfp %d msp %d ly %d tot %d\n\n",
529 539 pcbnum, filenum, maxfiles_proc, max_sproc,
530 540 total_layers, total_procs);
531 541 #endif
532 542 }
533 543
534 544
535 545 static int
536 546 a_pow(int base, int exp)
537 547 {
538 548 int i;
539 549 int answer;
540 550
541 551 if (exp == 0) {
542 552 answer = 1;
543 553 } else {
544 554 answer = base;
545 555 for (i = 0; i < (exp - 1); i++)
546 556 answer *= base;
547 557 }
548 558 return (answer);
549 559 }
550 560
551 561
552 562 /*
553 563 * .func mcount - main count.
554 564 * .desc Go through the motions of building the process tree just
555 565 * to count how many processes there are. Don't really
556 566 * build anything. Answer is in global var total_procs.
557 567 * .call mcount(nsp, lo).
558 568 * .arg nsp - number of subs for this tree branch.
559 569 * .arg lo - lo side of range of subs.
560 570 * .ret void.
561 571 */
562 572 static void
563 573 mcount(int nsp, int lo)
564 574 {
565 575 int range, i, tofork, nnsp, nrem;
566 576
567 577 total_procs++; /* count another process created */
568 578
569 579 if (nsp > max_sproc) {
570 580 if (nsp <= max_sproc * (max_sproc - 1)) {
571 581 tofork = nsp / max_sproc;
572 582 if (nsp % max_sproc)
573 583 tofork++;
574 584 } else {
575 585 tofork = max_sproc;
576 586 }
577 587 nnsp = nsp / tofork;
578 588 nrem = nsp % tofork;
579 589 for (i = 0; i < tofork; i++) {
580 590 range = (nrem > 0) ? nnsp + 1 : nnsp;
581 591 mcount(range, lo);
582 592 nrem--;
583 593 lo += range;
584 594 }
585 595 }
586 596 }
587 597
588 598
589 599 /*
590 600 * .func delete_infiles - delete the input files.
591 601 * .desc If the user asked us to (via 'D' flag) then unlink the input files.
592 602 * .call ret = delete_infiles().
593 603 * .arg none.
594 604 * .ret void.
595 605 */
596 606 static void
597 607 delete_infiles(void)
598 608 {
599 609 int i;
600 610 audit_pcb_t *pcb;
601 611 audit_fcb_t *fcb;
602 612
603 613 for (i = 0; i < pcbsize; i++) {
604 614 pcb = &audit_pcbs[i];
605 615 fcb = pcb->pcb_dfirst;
606 616 while (fcb != NULL) {
607 617 /*
608 618 * Only delete a file if it was succesfully processed.
609 619 * If there were any read errors or bad records
610 620 * then don't delete it.
611 621 * There may still be unprocessed records in it.
612 622 */
613 623 if (fcb->fcb_flags & FF_DELETE) {
614 624 if (unlink(fcb->fcb_file)) {
615 625 if (f_verbose) {
616 626 (void) sprintf(errbuf, gettext(
617 627 "%s delete on %s failed"),
618 628 ar, fcb->fcb_file);
619 629 }
620 630 perror(errbuf);
621 631 }
622 632 }
623 633 fcb = fcb->fcb_next;
624 634 }
625 635 }
626 636 }
627 637
628 638
629 639 /*
630 640 * .func rm_outfile - remove the outfile.
631 641 * .desc Remove the file we are writing the records to. We do this if
632 642 * processing failed and we are quitting before finishing.
633 643 * Update - don't actually remove the outfile, but generate
634 644 * a warning about its possible heathen nature.
635 645 * .call ret = rm_outfile().
636 646 * .arg none.
637 647 * .ret void.
638 648 */
639 649 static void
640 650 rm_outfile(void)
641 651 {
642 652 #if 0
643 653 if (f_outfile) {
644 654 if (unlink(f_outtemp) == -1) {
645 655 (void) sprintf(errbuf,
646 656 gettext("%s delete on %s failed"),
647 657 ar, f_outtemp);
648 658 perror(errbuf);
649 659 }
650 660 }
651 661 #else
652 662 (void) fprintf(stderr,
653 663 gettext("%s Warning: Incomplete audit file may have been generated - %s\n"),
654 664 ar,
655 665 (f_outfile == NULL) ? gettext("standard output") : f_outfile);
656 666 #endif
657 667 }
658 668
659 669
660 670 /*
661 671 * .func close_outfile - close the outfile.
662 672 * .desc Close the file we are writing records to.
663 673 * .call ret = close_outfile().
664 674 * .arg none.
665 675 * .ret 0 - close was succesful.
666 676 * .ret -1 - close failed.
667 677 */
668 678 static int
669 679 close_outfile(void)
670 680 {
671 681 if (fclose(stdout) == EOF) {
672 682 (void) sprintf(errbuf, gettext("%s close on %s failed"),
673 683 ar, f_outfile ? f_outfile : "standard output");
674 684 perror(errbuf);
675 685 return (-1);
676 686 }
677 687 (void) fsync(fileno(stdout));
678 688 return (rename_outfile());
679 689 }
680 690
681 691
682 692 /*
683 693 * .func write_header - write audit file header.
684 694 * .desc Write an audit file header to the output stream. The time in the
685 695 * header is the time of the first record written to the stream. This
686 696 * routine is called by the process handling the root node of the
687 697 * process tree just before it writes the first record to the output
688 698 * stream.
689 699 * .ret 0 - succesful write.
690 700 * .ret -1 - failed write - message printed.
691 701 */
692 702 int
693 703 write_header(void)
694 704 {
695 705 return (write_file_token(f_start));
696 706 }
697 707
698 708
699 709 static int
700 710 write_file_token(time_t when)
701 711 {
702 712 adr_t adr; /* adr ptr */
703 713 struct timeval tv; /* time now */
704 714 char for_adr[16]; /* plenty of room */
705 715 #ifdef _LP64
706 716 char token_id = AUT_OTHER_FILE64;
707 717 #else
708 718 char token_id = AUT_OTHER_FILE32;
709 719 #endif
710 720 short i = 1;
711 721 char c = '\0';
712 722
713 723 tv.tv_sec = when;
714 724 tv.tv_usec = 0;
715 725 adr_start(&adr, for_adr);
716 726 adr_char(&adr, &token_id, 1);
717 727 #ifdef _LP64
718 728 adr_int64(&adr, (int64_t *)&tv, 2);
719 729 #else
720 730 adr_int32(&adr, (int32_t *)&tv, 2);
721 731 #endif
722 732 adr_short(&adr, &i, 1);
723 733 adr_char(&adr, &c, 1);
724 734
725 735 if (fwrite(for_adr, sizeof (char), adr_count(&adr), stdout) !=
726 736 adr_count(&adr)) {
727 737 if (when == f_start) {
728 738 (void) sprintf(errbuf,
729 739 gettext("%s error writing header to %s. "),
730 740 ar,
731 741 f_outfile ? f_outfile :
732 742 gettext("standard output"));
733 743 } else {
734 744 (void) sprintf(errbuf,
735 745 gettext("%s error writing trailer to %s. "),
736 746 ar,
737 747 f_outfile ? f_outfile :
738 748 gettext("standard output"));
739 749 }
740 750 perror(errbuf);
741 751 return (-1);
742 752 }
743 753 return (0);
744 754 }
745 755
746 756
747 757 /*
748 758 * .func write_trailer - write audit file trailer.
749 759 * .desc Write an audit file trailer to the output stream. The finish
750 760 * time for the trailer is the time of the last record written
751 761 * to the stream.
752 762 * .ret 0 - succesful write.
753 763 * .ret -1 - failed write - message printed.
754 764 */
755 765 static int
756 766 write_trailer(void)
757 767 {
758 768 return (write_file_token(f_end));
759 769 }
760 770
761 771
762 772 /*
763 773 * .func rename_outfile - rename the outfile.
764 774 * .desc If the user used the -O flag they only gave us the suffix name
765 775 * for the outfile. We have to add the time stamps to put the filename
766 776 * in the proper audit file name format. The start time will be the time
767 777 * of the first record in the file and the end time will be the time of
768 778 * the last record in the file.
769 779 * .ret 0 - rename succesful.
770 780 * .ret -1 - rename failed - message printed.
771 781 */
772 782 static int
773 783 rename_outfile(void)
774 784 {
775 785 char f_newfile[MAXFILELEN];
776 786 char buf1[15], buf2[15];
777 787 char *f_file, *f_nfile, *f_time, *f_name;
778 788
779 789 if (f_outfile != NULL) {
780 790 /*
781 791 * Get string representations of start and end times.
782 792 */
783 793 derive_str(f_start, buf1);
784 794 derive_str(f_end, buf2);
785 795
786 796 f_nfile = f_time = f_newfile; /* working copy */
787 797 f_file = f_name = f_outfile; /* their version */
788 798 while (*f_file) {
789 799 if (*f_file == '/') { /* look for filename */
790 800 f_time = f_nfile + 1;
791 801 f_name = f_file + 1;
792 802 }
793 803 *f_nfile++ = *f_file++; /* make copy of their version */
794 804 }
795 805 *f_time = '\0';
796 806 /* start time goes first */
797 807 (void) strcat(f_newfile, buf1);
798 808 (void) strcat(f_newfile, ".");
799 809 /* then the finish time */
800 810 (void) strcat(f_newfile, buf2);
801 811 (void) strcat(f_newfile, ".");
802 812 /* and the name they gave us */
803 813 (void) strcat(f_newfile, f_name);
804 814
805 815 #if AUDIT_FILE
806 816 (void) fprintf(stderr, "rename_outfile: <%s> --> <%s>\n",
807 817 f_outfile, f_newfile);
808 818 #endif
809 819
810 820 #if AUDIT_RENAME
811 821 if (rename(f_outtemp, f_newfile) == -1) {
812 822 (void) fprintf(stderr,
813 823 "%s rename of %s to %s failed.\n",
814 824 ar, f_outtemp, f_newfile);
815 825 return (-1);
816 826 }
817 827 f_outfile = f_newfile;
818 828 #else
819 829 if (rename(f_outtemp, f_outfile) == -1) {
820 830 (void) fprintf(stderr,
821 831 gettext("%s rename of %s to %s failed.\n"),
822 832 ar, f_outtemp, f_outfile);
823 833 return (-1);
824 834 }
825 835 #endif
826 836 }
827 837 return (0);
828 838 }
829 839
830 840
831 841 /*
832 842 * .func open_outfile - open the outfile.
833 843 * .desc Open the outfile specified by the -O option. Assign it to the
834 844 * the standard output. Get a unique temporary name to use so we
835 845 * don't clobber an existing file.
836 846 * .ret 0 - no errors detected.
837 847 * .ret -1 - errors in processing (message already printed).
838 848 */
839 849 static int
840 850 open_outfile(void)
841 851 {
842 852 int tmpfd = -1;
843 853
844 854 if (f_outfile != NULL) {
845 855 f_outtemp = (char *)a_calloc(1, strlen(f_outfile) + 8);
846 856 (void) strcpy(f_outtemp, f_outfile);
847 857 (void) strcat(f_outtemp, "XXXXXX");
848 858 if ((tmpfd = mkstemp(f_outtemp)) == -1) {
849 859 (void) sprintf(errbuf,
850 860 gettext("%s couldn't create temporary file"), ar);
851 861 perror(errbuf);
852 862 return (-1);
853 863 }
854 864 (void) fflush(stdout);
855 865 if (tmpfd != fileno(stdout)) {
856 866 if ((dup2(tmpfd, fileno(stdout))) == -1) {
857 867 (void) sprintf(errbuf,
858 868 gettext("%s can't assign %s to the "
859 869 "standard output"), ar, f_outfile);
860 870 perror(errbuf);
861 871 return (-1);
862 872 }
863 873 (void) close(tmpfd);
864 874 }
865 875 }
866 876 return (0);
867 877 }
868 878
869 879
870 880 /*
871 881 * .func init_options - initialize the options.
872 882 * .desc Give initial and/or default values to some options.
873 883 * .call init_options();
874 884 * .arg none.
875 885 * .ret void.
876 886 */
877 887 static void
878 888 init_options(void)
879 889 {
880 890 struct timeval tp;
881 891 struct timezone tpz;
882 892
883 893 /*
884 894 * Get current time for general use.
885 895 */
886 896 if (gettimeofday(&tp, &tpz) == -1)
887 897 perror(gettext("auditreduce: initial getttimeofday failed"));
888 898
889 899 time_now = tp.tv_sec; /* save for general use */
890 900 f_start = 0; /* first record time default */
891 901 f_end = time_now; /* last record time default */
892 902 m_after = 0; /* Jan 1, 1970 00:00:00 */
893 903
894 904 /*
895 905 * Setup initial size of audit_pcbs[].
896 906 */
897 907 pcbsize = PCB_INITSIZE; /* initial size of file-holding pcb's */
898 908
899 909 audit_pcbs = (audit_pcb_t *)a_calloc(pcbsize, sizeof (audit_pcb_t));
900 910
901 911 /* description of 'current' error */
902 912 error_str = gettext("initial error");
903 913
904 914 }
905 915
906 916
907 917 /*
908 918 * .func a_calloc - audit calloc.
909 919 * .desc Calloc with check for failure. This is called by all of the
910 920 * places that want memory.
911 921 * .call ptr = a_calloc(nelem, size).
912 922 * .arg nelem - number of elements to allocate.
913 923 * .arg size - size of each element.
914 924 * .ret ptr - ptr to allocated and zeroed memory.
915 925 * .ret never - if calloc fails then we never return.
916 926 */
917 927 void *
918 928 a_calloc(int nelem, size_t size)
919 929 {
920 930 void *ptr;
921 931
922 932 if ((ptr = calloc((unsigned)nelem, size)) == NULL) {
923 933 perror(gettext("auditreduce: memory allocation failed"));
924 934 exit(1);
925 935 }
926 936 return (ptr);
927 937 }
928 938
929 939
930 940 /*
931 941 * .func init_sig - initial signal catching.
932 942 *
933 943 * .desc
934 944 * Setup the signal catcher to catch the SIGCHLD signal plus
935 945 * "environmental" signals -- keyboard plus other externally
936 946 * generated signals such as out of file space or cpu time. If a
937 947 * child exits with either a non-zero exit code or was killed by
938 948 * a signal to it then we will also exit with a non-zero exit
939 949 * code. In this way abnormal conditions can be passed up to the
940 950 * root process and the entire run be halted. Also catch the int
941 951 * and quit signals. Remove the output file since it is in an
942 952 * inconsistent state.
943 953 * .call ret = init_sig().
944 954 * .arg none.
945 955 * .ret 0 - no errors detected.
946 956 * .ret -1 - signal failed (message printed).
947 957 */
948 958 static int
949 959 init_sig(void)
950 960 {
951 961 if (signal(SIGCHLD, chld_handler) == SIG_ERR) {
952 962 perror(gettext("auditreduce: SIGCHLD signal failed"));
953 963 return (-1);
954 964 }
955 965
956 966 if (signal(SIGHUP, int_handler) == SIG_ERR) {
957 967 perror(gettext("auditreduce: SIGHUP signal failed"));
958 968 return (-1);
959 969 }
960 970 if (signal(SIGINT, int_handler) == SIG_ERR) {
961 971 perror(gettext("auditreduce: SIGINT signal failed"));
962 972 return (-1);
963 973 }
964 974 if (signal(SIGQUIT, int_handler) == SIG_ERR) {
965 975 perror(gettext("auditreduce: SIGQUIT signal failed"));
966 976 return (-1);
967 977 }
968 978 if (signal(SIGABRT, int_handler) == SIG_ERR) {
969 979 perror(gettext("auditreduce: SIGABRT signal failed"));
970 980 return (-1);
971 981 }
972 982 if (signal(SIGTERM, int_handler) == SIG_ERR) {
973 983 perror(gettext("auditreduce: SIGTERM signal failed"));
974 984 return (-1);
975 985 }
976 986 if (signal(SIGPWR, int_handler) == SIG_ERR) {
977 987 perror(gettext("auditreduce: SIGPWR signal failed"));
978 988 return (-1);
979 989 }
980 990 if (signal(SIGXCPU, int_handler) == SIG_ERR) {
981 991 perror(gettext("auditreduce: SIGXCPU signal failed"));
982 992 return (-1);
983 993 }
984 994 if (signal(SIGXFSZ, int_handler) == SIG_ERR) {
985 995 perror(gettext("auditreduce: SIGXFSZ signal failed"));
986 996 return (-1);
987 997 }
988 998 if (signal(SIGSEGV, int_handler) == SIG_ERR) {
989 999 perror(gettext("auditreduce: SIGSEGV signal failed"));
990 1000 return (-1);
991 1001 }
992 1002
993 1003 return (0);
994 1004 }
995 1005
996 1006
997 1007 /*
998 1008 * .func chld_handler - handle child signals.
999 1009 * .desc Catch the SIGCHLD signals. Remove the root process
1000 1010 * output file because it is in an inconsistent state.
1001 1011 * Print a message giving the signal number and/or return code
1002 1012 * of the child who caused the signal.
1003 1013 * .ret void.
1004 1014 */
1005 1015 /* ARGSUSED */
1006 1016 void
1007 1017 chld_handler(int sig)
1008 1018 {
1009 1019 int pid;
1010 1020 int status;
1011 1021
1012 1022 /*
1013 1023 * Get pid and reasons for cause of event.
1014 1024 */
1015 1025 pid = wait(&status);
1016 1026
1017 1027 if (pid > 0) {
1018 1028 /*
1019 1029 * If child received a signal or exited with a non-zero
1020 1030 * exit status then print message and exit
1021 1031 */
1022 1032 if ((WHIBYTE(status) == 0 && WLOBYTE(status) != 0) ||
1023 1033 (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)) {
1024 1034 (void) fprintf(stderr,
1025 1035 gettext("%s abnormal child termination - "), ar);
1026 1036
1027 1037 if (WHIBYTE(status) == 0 && WLOBYTE(status) != 0) {
1028 1038 psignal(WLOBYTE(status), "signal");
1029 1039 if (WCOREDUMP(status))
1030 1040 (void) fprintf(stderr,
1031 1041 gettext("core dumped\n"));
1032 1042 }
1033 1043
1034 1044 if (WHIBYTE(status) != 0 && WLOBYTE(status) == 0)
1035 1045 (void) fprintf(stderr, gettext(
1036 1046 "return code %d\n"),
1037 1047 WHIBYTE(status));
1038 1048
1039 1049 /*
1040 1050 * Get rid of outfile - it is suspect.
1041 1051 */
1042 1052 if (f_outfile != NULL) {
1043 1053 (void) close_outfile();
1044 1054 rm_outfile();
1045 1055 }
1046 1056 /*
1047 1057 * Give statistical info that may be useful.
1048 1058 */
1049 1059 audit_stats();
1050 1060
1051 1061 exit(1);
1052 1062 }
1053 1063 }
1054 1064 }
1055 1065
1056 1066
1057 1067 /*
1058 1068 * .func int_handler - handle quit/int signals.
1059 1069 * .desc Catch the keyboard and other environmental signals.
1060 1070 * Remove the root process output file because it is in
1061 1071 * an inconsistent state.
1062 1072 * .ret void.
1063 1073 */
1064 1074 /* ARGSUSED */
1065 1075 void
1066 1076 int_handler(int sig)
1067 1077 {
1068 1078 if (getpid() == root_pid) {
1069 1079 (void) close_outfile();
1070 1080 rm_outfile();
1071 1081 exit(1);
1072 1082 }
1073 1083 /*
1074 1084 * For a child process don't give an error exit or the
1075 1085 * parent process will catch it with the chld_handler and
1076 1086 * try to erase the outfile again.
1077 1087 */
1078 1088 exit(0);
1079 1089 }
↓ open down ↓ |
639 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX