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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Command line option processing for auditreduce.
28 * The entry point is process_options(), which is called by main().
29 * Process_options() is the only function visible outside this module.
33 #include <sys/zone.h> /* for max zonename length */
38 * Maps object strings specified on the command line to a flag
39 * used when searching by object type.
43 char *obj_str
; /* string specified on the command line */
44 int obj_flag
; /* flag used when searching */
47 typedef struct obj_ent obj_ent_t
;
50 * Supports searches by object type.
52 static obj_ent_t obj_tbl
[] = {
54 { "filegroup", OBJ_FGROUP
},
55 { "fileowner", OBJ_FOWNER
},
58 { "msgqid", OBJ_MSG
},
59 { "msgqgroup", OBJ_MSGGROUP
},
60 { "msgqowner", OBJ_MSGOWNER
},
63 { "procgroup", OBJ_PGROUP
},
64 { "procowner", OBJ_POWNER
},
66 { "semgroup", OBJ_SEMGROUP
},
67 { "semowner", OBJ_SEMOWNER
},
69 { "shmgroup", OBJ_SHMGROUP
},
70 { "shmowner", OBJ_SHMOWNER
},
72 { "user", OBJ_USER
} };
74 extern int derive_date(char *, struct tm
*);
75 extern int parse_time(char *, int);
76 extern char *re_comp2(char *);
77 extern time_t tm_to_secs(struct tm
*);
79 static int a_isnum(char *, int);
80 static int check_file(audit_fcb_t
*, int);
81 static int gather_dir(char *);
82 static audit_pcb_t
*get_next_pcb(char *);
83 static obj_ent_t
*obj_lkup(char *);
84 static int proc_class(char *);
85 static int proc_date(char *, int);
86 static int proc_file(char *, int);
87 static int process_fileopt(int, char *argv
[], int);
88 static int proc_group(char *, gid_t
*);
89 static int proc_id(char *, int);
90 static int proc_object(char *);
91 static void proc_pcb(audit_pcb_t
*, char *, int);
92 static int proc_subject(char *);
93 static int proc_sid(char *);
94 static int proc_type(char *);
95 static int proc_user(char *, uid_t
*);
96 static int proc_zonename(char *);
97 static int proc_fmri(char *);
100 * .func process_options - process command line options.
101 * .desc Process the user's command line options. These are of two types:
102 * single letter flags that are denoted by '-', and filenames. Some
103 * of the flags have arguments. Getopt() is used to get the flags.
104 * When this is done it calls process_fileopt() to handle any filenames
106 * .call ret = process_options(argc, argv).
107 * .arg argc - the original value.
108 * .arg argv - the original value.
109 * .ret 0 - no errors detected.
110 * .ret -1 - command line error detected (message already printed).
113 process_options(int argc
, char **argv
)
117 int error_combo
= FALSE
;
118 extern int optind
; /* in getopt() */
119 extern char *optarg
; /* in getopt() - holds arg to flag */
121 static char *options
= "ACD:M:NQR:S:VO:"
122 "a:b:c:d:e:g:j:m:o:r:s:t:u:z:";
124 error_str
= gettext("general error");
128 * Big switch to process the flags.
129 * Start_over: is for handling the '-' for standard input. Getopt()
130 * doesn't recognize it.
133 while ((opt
= getopt(argc
, argv
, options
)) != EOF
) {
135 case 'A': /* all records from the files */
138 case 'C': /* process only completed files */
141 case 'D': /* delete the files when done */
142 /* force 'A' 'C' 'O' to be active */
143 f_all
= f_complete
= TRUE
;
147 case 'M': /* only files from a certain machine */
150 case 'N': /* new object selection mode */
153 case 'Q': /* no file error reporting */
156 case 'R': /* from specified root */
159 case 'S': /* from specified server */
162 case 'V': /* list all files as they are opened */
165 case 'O': /* write to outfile */
168 case 'a': /* after 'date' */
169 case 'b': /* before 'date' */
170 case 'd': /* from 'day' */
171 if (proc_date(optarg
, opt
))
174 case 'j': /* subject */
175 if (proc_subject(optarg
))
178 case 'm': /* message 'type' */
179 if (proc_type(optarg
))
182 case 'o': /* object type */
183 if (proc_object(optarg
))
186 case 'c': /* message class */
187 if (proc_class(optarg
))
190 case 'u': /* form audit user */
191 case 'e': /* form effective user */
192 case 'r': /* form real user */
193 case 'f': /* form effective group */
194 case 'g': /* form real group */
195 if (proc_id(optarg
, opt
))
198 case 's': /* session ID */
199 if (proc_sid(optarg
))
202 case 'z': /* zone name */
203 if (proc_zonename(optarg
))
206 case 't': /* termial ID reserved for later */
211 (void) fprintf(stderr
,
212 gettext("%s command line error - %s.\n"),
217 /* catch '-' option for stdin processing - getopt() won't see it */
219 if (argv
[optind
][0] == '-' && argv
[optind
][1] == '\0') {
226 * Give a default value for 'b' option if not specified.
229 m_before
= MAXLONG
; /* forever */
231 * Validate combinations of options.
232 * The following are done:
233 * 1. Can't have 'M' or 'S' or 'R' with filenames.
234 * 2. Can't have an after ('a') time after a before ('b') time.
235 * 3. Delete ('D') must have 'C' and 'A' and 'O' with it.
236 * 4. Input from stdin ('-') can't have filenames too.
238 if ((f_machine
|| f_server
|| f_root
) && (argc
!= optind
)) {
240 "no filenames allowed with 'M' or 'S' or 'R' options");
243 if (m_after
>= m_before
) {
245 gettext("'a' parameter must be before 'b' parameter");
249 (!f_complete
|| !f_all
|| !f_outfile
)) {
251 "'C', 'A', and 'O' must be specified with 'D'");
254 if (f_stdin
&& (argc
!= optind
)) {
255 error_str
= gettext("no filenames allowed with '-' option");
259 * If error with option combos then print message and exit.
260 * If there was an error with just an option then exit.
263 (void) fprintf(stderr
,
264 gettext("%s command line error - %s.\n"), ar
, error_str
);
268 f_root
= "/etc/security/audit";
270 * Now handle any filenames included in the command line.
272 return (process_fileopt(argc
, argv
, optind
));
276 proc_subject(char *optarg
)
278 if (flags
& M_SUBJECT
) {
279 error_str
= gettext("'j' option specified multiple times");
283 subj_id
= atol(optarg
);
288 proc_sid(char *optarg
)
291 error_str
= gettext("'s' option specified multiple times");
295 m_sid
= (au_asid_t
)atol(optarg
);
300 proc_object(char *optarg
)
310 if (flags
& M_OBJECT
) {
311 error_str
= gettext("'o' option specified multiple times");
315 if ((obj_arg
= strdup(optarg
)) == NULL
)
317 if ((obj_str
= strtok(optarg
, "=")) == NULL
||
318 (oep
= obj_lkup(obj_str
)) == (obj_ent_t
*)0 ||
319 (obj_val
= strtok(NULL
, "=")) == NULL
) {
320 (void) sprintf(errbuf
, gettext("invalid object arg (%s)"),
326 obj_flag
= oep
->obj_flag
;
330 if ((error_str
= re_comp2(obj_val
)) != NULL
) {
335 if (!a_isnum(obj_val
, TRUE
)) {
336 obj_id
= atol(obj_val
);
337 socket_flag
= SOCKFLG_PORT
;
340 if (*obj_val
== '0') {
341 (void) sscanf(obj_val
, "%x", (uint_t
*)&obj_id
);
342 socket_flag
= SOCKFLG_PORT
;
346 he
= getipnodebyname((const void *)obj_val
, AF_INET6
, 0, &err
);
348 he
= getipnodebyname((const void *)obj_val
, AF_INET
,
351 (void) sprintf(errbuf
,
352 gettext("invalid machine name (%s)"),
359 if (he
->h_addrtype
== AF_INET6
) {
361 if (IN6_IS_ADDR_V4MAPPED(
362 (in6_addr_t
*)he
->h_addr_list
[0])) {
363 /* address is IPv4 (32 bits) */
364 (void) memcpy(&obj_id
,
365 he
->h_addr_list
[0] + 12, 4);
368 (void) memcpy(ip_ipv6
, he
->h_addr_list
[0], 16);
372 /* address is IPv4 (32 bits) */
373 (void) memcpy(&obj_id
, he
->h_addr_list
[0], 4);
378 socket_flag
= SOCKFLG_MACHINE
;
384 obj_id
= atol(obj_val
);
391 return (proc_group(obj_val
, &obj_group
));
397 return (proc_user(obj_val
, &obj_owner
));
399 return (proc_fmri(obj_val
));
401 return (proc_user(obj_val
, &obj_user
));
402 case OBJ_LP
: /* lp objects have not yet been defined */
403 default: /* impossible */
404 (void) sprintf(errbuf
, gettext("invalid object type (%s)"),
414 obj_lkup(char *obj_str
)
418 for (i
= 0; i
< sizeof (obj_tbl
) / sizeof (obj_ent_t
); i
++)
419 if (strcmp(obj_str
, obj_tbl
[i
].obj_str
) == 0)
420 return (&obj_tbl
[i
]);
428 * .func proc_type - process record type.
429 * .desc Process a record type. It is either as a number or a mnemonic.
430 * .call ret = proc_type(optstr).
431 * .arg optstr - ptr to name or number.
432 * .ret 0 - no errors detected.
433 * .ret -1 - error detected (error_str contains description).
436 proc_type(char *optstr
)
438 struct au_event_ent
*aep
;
441 * Either a number or a name.
444 if (flags
& M_TYPE
) {
445 error_str
= gettext("'m' option specified multiple times");
450 if (a_isnum(optstr
, TRUE
)) {
451 if ((aep
= getauevnam(optstr
)) != NULL
)
452 m_type
= aep
->ae_number
;
454 if ((aep
= getauevnum((au_event_t
)atoi(optstr
))) != NULL
)
455 m_type
= aep
->ae_number
;
458 (void) sprintf(errbuf
, gettext("invalid event (%s)"), optstr
);
467 * .func a_isnum - is it a number?
468 * .desc Determine if a string is a number or a name.
469 * A number may have a leading '+' or '-', but then must be
471 * .call ret = a_isnum(str).
472 * .arg str - ptr to the string.
473 * .arg leading - TRUE if leading '+-' allowed.
474 * .ret 0 - is a number.
475 * .ret 1 - is not a number.
478 a_isnum(char *str
, int leading
)
482 if ((leading
== TRUE
) && (*str
== '-' || *str
== '+'))
487 if (strlen(strs
) == strspn(strs
, "0123456789"))
495 * .func proc_id - process user/group id's/
496 * .desc Process either a user number/name or group number/name.
497 * For names check to see if the name is active in the system
498 * to derive the number. If it is not active then fail. For a number
499 * also check to see if it is active, but only print a warning if it
500 * is not. An administrator may be looking at activity of a 'phantom'
502 * .call ret = proc_id(optstr, opt).
503 * .arg optstr - ptr to name or number.
504 * .arg opt - 'u' - audit user, 'e' - effective user, 'r' - real user,
505 * 'g' - group, 'f' - effective group.
506 * .ret 0 - no errors detected.
507 * .ret -1 - error detected (error_str contains description).
510 proc_id(char *optstr
, int opt
)
513 case 'e': /* effective user id */
514 if (flags
& M_USERE
) {
516 "'e' option specified multiple times");
520 return (proc_user(optstr
, &m_usere
));
521 case 'f': /* effective group id */
522 if (flags
& M_GROUPE
) {
524 "'f' option specified multiple times");
528 return (proc_group(optstr
, &m_groupe
));
529 case 'r': /* real user id */
530 if (flags
& M_USERR
) {
532 "'r' option specified multiple times");
536 return (proc_user(optstr
, &m_userr
));
537 case 'u': /* audit user id */
538 if (flags
& M_USERA
) {
540 "'u' option specified multiple times");
544 return (proc_user(optstr
, &m_usera
));
545 case 'g': /* real group id */
546 if (flags
& M_GROUPR
) {
548 "'g' option specified multiple times");
552 return (proc_group(optstr
, &m_groupr
));
553 default: /* impossible */
554 (void) sprintf(errbuf
, gettext("'%c' unknown option"), opt
);
563 proc_group(char *optstr
, gid_t
*gid
)
567 if ((grp
= getgrnam(optstr
)) == NULL
) {
568 if (!a_isnum(optstr
, TRUE
)) {
569 *gid
= (gid_t
)atoi(optstr
);
572 (void) sprintf(errbuf
, gettext("group name invalid (%s)"),
583 proc_user(char *optstr
, uid_t
*uid
)
587 if ((usr
= getpwnam(optstr
)) == NULL
) {
588 if (!a_isnum(optstr
, TRUE
)) {
589 *uid
= (uid_t
)atoi(optstr
);
592 (void) sprintf(errbuf
, gettext("user name invalid (%s)"),
603 * .func proc_date - process date argument.
604 * .desc Handle a date/time argument. See if the user has erred in combining
605 * the types of date arguments. Then parse the string and check for
606 * validity of each part.
607 * .call ret = proc_date(optstr, opt).
608 * .arg optstr - ptr to date/time string.
609 * .arg opt - 'd' for day, 'a' for after, or 'b' for before.
610 * .ret 0 - no errors detected.
611 * .ret -1 - errors detected (error_str knows what it is).
614 proc_date(char *optstr
, int opt
)
616 static int m_day
= FALSE
;
621 "'d' option may not be used with 'a' or 'b'");
626 if ((opt
== 'd') && (m_before
|| m_after
)) {
628 "'d' option may not be used with 'a' or 'b'");
631 if ((opt
== 'a' || opt
== 'b') && m_day
) {
633 "'a' or 'b' option may not be used with 'd'");
636 if ((opt
== 'a') && (m_after
!= 0)) {
637 error_str
= gettext("'a' option specified multiple times");
640 if ((opt
== 'b') && (m_before
!= 0)) {
641 error_str
= gettext("'b' option specified multiple times");
644 if (parse_time(optstr
, opt
))
651 * .func proc_class - process message class argument.
652 * .desc Process class type and see if it is for real.
653 * .call ret = proc_class(optstr).
654 * .arg optstr - ptr to class.
655 * .ret 0 - class has class.
656 * .ret -1 - class in no good.
659 proc_class(char *optstr
)
661 if (flags
& M_CLASS
) {
662 error_str
= gettext("'c' option specified multiple times");
667 if (getauditflagsbin(optstr
, &mask
) != 0) {
668 (void) sprintf(errbuf
, gettext("unknown class (%s)"), optstr
);
673 if (mask
.am_success
!= mask
.am_failure
) {
682 * .func process_fileopt - process command line file options.
683 * .desc Process the command line file options and gather the specified files
684 * together in file groups based upon file name suffix. The user can
685 * specify files explicitly on the command line or via a directory.
686 * This is called after the command line flags are processed (as
688 * .call ret = process_fileopt(argc, argv, optindex).
689 * .arg argc - current value of argc.
690 * .arg argv - current value of argv.
691 * .arg optindex- current index into argv (as setup by getopt()).
692 * .ret 0 - no errors detected.
693 * .ret -1 - error detected (message already printed).
696 process_fileopt(int argc
, char **argv
, int optindex
)
698 int f_mode
= FM_ALLDIR
;
699 char f_dr
[MAXNAMLEN
+1];
702 static char *std
= "standard input";
709 * Take input from stdin, not any files.
710 * Use a single fcb to do this.
713 fcb
= (audit_fcb_t
*)a_calloc(1, sizeof (*fcb
) + strlen(std
));
714 (void) strcpy(fcb
->fcb_file
, std
);
715 fcb
->fcb_suffix
= fcb
->fcb_name
= fcb
->fcb_file
;
716 fcb
->fcb_next
= NULL
;
718 fcb
->fcb_end
= MAXLONG
; /* forever */
719 if ((pcb
= get_next_pcb(NULL
)) == NULL
)
721 pcb
->pcb_suffix
= fcb
->fcb_file
;
722 pcb
->pcb_dfirst
= pcb
->pcb_first
= fcb
; /* one-item list */
723 pcb
->pcb_dlast
= pcb
->pcb_last
= fcb
;
727 * No files specified on the command line.
728 * Process a directory of files or subdirectories.
730 else if (argc
== optindex
) {
732 * A specific server directory was requested.
735 if (strchr(f_server
, '/')) { /* given full path */
737 f_mode
= FM_ALLFILE
; /* all files here */
738 } else { /* directory off audit root */
740 (void) strcat(f_dir
, f_root
);
741 (void) strcat(f_dir
, "/");
742 (void) strcat(f_dir
, f_server
);
747 * Gather all of the files in the directory 'f_dir'.
749 if (f_mode
== FM_ALLFILE
) {
750 if (gather_dir(f_dir
)) { /* get those files together */
755 * Gather all of the files in all of the
756 * directories in 'f_root'.
758 if ((dirp
= opendir(f_root
)) == NULL
) {
759 (void) sprintf(errbuf
, gettext(
760 "%s can't open directory %s"), ar
, f_root
);
764 /* read the directory and process all of the subs */
765 for (dp
= readdir(dirp
);
766 dp
!= NULL
; dp
= readdir(dirp
)) {
767 if (dp
->d_name
[0] == '.')
770 (void) strcat(f_dir
, f_root
);
771 (void) strcat(f_dir
, "/");
772 (void) strcat(f_dir
, dp
->d_name
);
773 if (gather_dir(f_dir
)) /* process a sub */
776 (void) closedir(dirp
);
780 * User specified filenames on the comm and line.
783 for (; optindex
< argc
; optindex
++) {
784 fname
= argv
[optindex
]; /* get a filename */
785 if (proc_file(fname
, FALSE
))
794 * .func gather_dir - gather a directory's files together.
795 * .desc Process all of the files in a specific directory. The files may
796 * be checked for adherence to the file name form at.
797 * If the directory can't be opened that is ok - just print
798 * a message and continue.
799 * .call ret = gather_dir(dir).
800 * .arg dir - ptr to full pathname of directory.
801 * .ret 0 - no errors detected.
802 * .ret -1 - error detected (message already printed).
805 gather_dir(char *dir
)
807 char dname
[MAXNAMLEN
+1];
808 char fname
[MAXNAMLEN
+1];
812 (void) snprintf(dname
, sizeof (dname
), "%s/files", dir
);
814 if ((dirp
= opendir(dname
)) == NULL
) {
815 if (errno
!= ENOTDIR
) {
816 (void) sprintf(errbuf
,
817 gettext("%s can't open directory - %s"), ar
, dname
);
822 for (dp
= readdir(dirp
); dp
!= NULL
; dp
= readdir(dirp
)) {
823 if (dp
->d_name
[0] == '.') /* can't see hidden files */
826 (void) strcat(fname
, dname
); /* create pathname of file */
827 (void) strcat(fname
, "/");
828 (void) strcat(fname
, dp
->d_name
);
829 if (proc_file(fname
, TRUE
))
832 (void) closedir(dirp
);
838 * .func proc_file - process a single candidate file.
839 * .desc Check out a file to see if it should be used in the merge.
840 * This includes checking the name (mode is TRUE) against the
841 * file format, checking access rights to the file, and thence
842 * getting and fcb and installing the fcb into the correct pcb.
843 * If the file fails then the fcb is not installed into a pcb
844 * and the file dissapears from view.
845 * .call proc_file(fname, mode).
846 * .arg fname - ptr to full pathna me of file.
847 * .arg mode - TRUE if checking adherence to file name format.
848 * .ret 0 - no fatal errors detected.
849 * .ret -1 - fatal error detected - quit altogether
850 * (message already printed).
853 proc_file(char *fname
, int mode
)
857 struct stat stat_buf
;
858 audit_fcb_t
*fcb
, *fcbp
, *fcbprev
;
862 * See if it is a weird file like a directory or
863 * character special (around here?).
865 if (stat(fname
, &stat_buf
)) {
868 if (!S_ISREG(stat_buf
.st_mode
))
871 * Allocate a new fcb to hold fcb and full filename.
873 len
= sizeof (audit_fcb_t
) + strlen(fname
);
874 fcb
= (audit_fcb_t
*)a_calloc(1, len
);
875 (void) strcpy(fcb
->fcb_file
, fname
);
876 if (check_file(fcb
, mode
)) { /* check file name */
878 (void) fprintf(stderr
, "%s %s:\n %s.\n", ar
,
884 * Check against file criteria.
885 * Check finish-time here, and start-time later on
887 * This is because the start time on a file can be after
888 * the first record(s).
890 if (f_complete
&& (fcb
->fcb_flags
& FF_NOTTERM
) && !f_cmdline
)
892 if (!f_all
&& (fcb
->fcb_end
< m_after
))
895 if (strlen(fcb
->fcb_suffix
) != strlen(f_machine
) ||
896 (strcmp(fcb
->fcb_suffix
, f_machine
) != 0)) {
901 if (reject
== FALSE
) {
902 filenum
++; /* count of total files to be processed */
903 fcb
->fcb_next
= NULL
;
904 if ((pcb
= get_next_pcb(fcb
->fcb_suffix
)) == NULL
) {
907 /* Place FCB into the PCB in order - oldest first. */
908 fcbp
= pcb
->pcb_first
;
910 while (fcbp
!= NULL
) {
911 if (fcb
->fcb_start
< fcbp
->fcb_start
) {
913 fcbprev
->fcb_next
= fcb
;
915 pcb
->pcb_dfirst
= pcb
->pcb_first
= fcb
;
916 fcb
->fcb_next
= fcbp
;
920 fcbp
= fcbp
->fcb_next
;
922 /* younger than all || empty list */
923 if (!fcb
->fcb_next
) {
924 if (pcb
->pcb_first
== NULL
)
925 pcb
->pcb_dfirst
= pcb
->pcb_first
= fcb
;
926 pcb
->pcb_dlast
= pcb
->pcb_last
= fcb
;
928 fcbprev
->fcb_next
= fcb
;
931 free((char *)fcb
); /* rejected */
938 * .func check_file - check filename and setup fcb.
939 * .desc Check adherence to the file format (do_check is TRUE) and setup
940 * the fcb with useful information.
941 * filename format: yyyymmddhhmmss.yyyymmddhhmmss.suffix
942 * yyyymmddhhmmss.not_terminated.suffix
943 * If do_check is FALSE then still see if the filename does confirm
944 * to the format. If it does then extract useful information from
945 * it (start time and end time). But if it doesn't then don't print
946 * any error messages.
947 * .call ret = check_file(fcb, do_check).
948 * .arg fcb - ptr to fcb that holds the file.
949 * .arg do_check - if TRUE do check adherence to file format.
950 * .ret 0 - no errors detected.
951 * .ret -1 - file failed somehow (error_str tells why).
954 check_file(audit_fcb_t
*fcb
, int do_check
)
958 char errb
[256]; /* build error message */
962 /* get just the filename */
963 for (slp
= namep
= fcb
->fcb_file
; *namep
; namep
++) {
965 slp
= namep
+ 1; /* slp -> the filename itself */
967 if (do_check
== FALSE
) {
968 fcb
->fcb_end
= MAXLONG
; /* forever */
969 fcb
->fcb_suffix
= NULL
;
975 if ((int)strlen(slp
) < 31) {
976 (void) sprintf(errbuf
, gettext("filename too short (%d)"),
982 * Get working copy of filename.
984 namep
= (char *)a_calloc(1, strlen(slp
) + 1);
985 (void) strcpy(namep
, slp
);
986 if (namep
[14] != '.' || namep
[29] != '.') {
987 (void) sprintf(errbuf
,
988 gettext("invalid filename format (%c or %c)"), namep
[14],
994 namep
[14] = '\0'; /* mark off start time */
995 namep
[29] = '\0'; /* mark off finish time */
996 if (derive_date(namep
, &tme
)) {
997 (void) strcat(errb
, gettext("starting time-stamp invalid - "));
998 (void) strcat(errb
, error_str
);
999 (void) strcpy(errbuf
, errb
);
1005 * Keep start time from filename. Use it to order files in
1006 * the file list. Later we will update this when we read
1007 * the first record from the file.
1009 fcb
->fcb_start
= tm_to_secs(&tme
);
1011 if (strcmp(&namep
[15], "not_terminated") == 0) {
1012 fcb
->fcb_end
= MAXLONG
; /* forever */
1014 * Only treat a 'not_terminated' file as such if
1015 * it is not on the command line.
1017 if (do_check
== TRUE
)
1018 fcb
->fcb_flags
|= FF_NOTTERM
;
1019 } else if (derive_date(&namep
[15], &tme
)) {
1020 (void) strcat(errb
, gettext("ending time-stamp invalid - "));
1021 (void) strcat(errb
, error_str
);
1022 (void) strcpy(errbuf
, errb
);
1027 fcb
->fcb_end
= tm_to_secs(&tme
);
1029 fcb
->fcb_name
= slp
;
1030 fcb
->fcb_suffix
= &slp
[30];
1037 * .func get_next_pcb - get a pcb to use.
1038 * .desc The pcb's in the array audit_pcbs are used to hold single file
1039 * groups in the form of a linked list. Each pcb holds files that
1040 * are tied together by a common suffix in the file name. Here we
1041 * get either 1. the existing pcb holding a specified sufix or
1042 * 2. a new pcb if we can't find an existing one.
1043 * .call pcb = get_next_pcb(suffix).
1044 * .arg suffix - ptr to suffix we are seeking.
1045 * .ret pcb - ptr to pcb that hold s the sought suffix.
1046 * .ret NULL- serious failure in memory allocation. Quit processing.
1049 get_next_pcb(char *suffix
)
1056 /* Search through (maybe) entire array. */
1057 while (i
< pcbsize
) {
1058 pcb
= &audit_pcbs
[i
++];
1059 if (pcb
->pcb_first
== NULL
) {
1060 proc_pcb(pcb
, suffix
, i
);
1061 return (pcb
); /* came to an unused one */
1064 if (strcmp(pcb
->pcb_suffix
, suffix
) == 0)
1065 return (pcb
); /* matched one with suffix */
1069 * Uh-oh, the entire array is used and we haven't gotten one yet.
1070 * Allocate a bigger array.
1073 size
= pcbsize
* sizeof (audit_pcb_t
);
1074 zerosize
= size
- ((pcbsize
- PCB_INC
) * sizeof (audit_pcb_t
));
1075 if ((audit_pcbs
= (audit_pcb_t
*)realloc((char *)audit_pcbs
, size
)) ==
1077 (void) sprintf(errbuf
,
1078 gettext("%s memory reallocation failed (%d bytes)"), ar
,
1081 audit_stats(); /* give user statistics on usage */
1082 return (NULL
); /* really bad thing to have happen */
1085 * Don't know if realloc clears the new memory like calloc would.
1087 (void) memset(&audit_pcbs
[pcbsize
-PCB_INC
], 0, (size_t)zerosize
);
1088 pcb
= &audit_pcbs
[pcbsize
-PCB_INC
]; /* allocate the first new one */
1089 proc_pcb(pcb
, suffix
, pcbsize
- PCB_INC
);
1095 * .func proc_pcb - process pcb.
1096 * .desc Common pcb processing for above routine.
1097 * .call proc_pcb(pcb, suffix, i).
1098 * .arg pcb - ptr to pcb.
1099 * .arg suffix - prt to suffix tha t ties this group together.
1100 * .arg i - index into audit_pcbs[ ].
1104 proc_pcb(audit_pcb_t
*pcb
, char *suffix
, int i
)
1107 pcb
->pcb_suffix
= suffix
;
1108 pcbnum
++; /* one more pcb in use */
1109 pcb
->pcb_size
= AUDITBUFSIZE
;
1110 pcb
->pcb_rec
= (char *)a_calloc(1, AUDITBUFSIZE
);
1112 pcb
->pcb_flags
|= PF_USEFILE
; /* note this one controls files */
1113 pcb
->pcb_procno
= i
; /* save index into audit_pcbs [] for id */
1117 * proc_zonename - pick up zone name.
1119 * all non-empty and not-too-long strings are valid since any name
1122 * ret 0: non-empty string
1123 * ret -1: empty string or string is too long.
1126 proc_zonename(char *optstr
)
1128 size_t length
= strlen(optstr
);
1129 if ((length
< 1) || (length
> ZONENAME_MAX
)) {
1130 (void) sprintf(errbuf
,
1131 gettext("invalid zone name: %s"), optstr
);
1135 zonename
= strdup(optstr
);
1136 flags
|= M_ZONENAME
;
1141 * proc_frmi - set up frmi for pattern matching.
1142 * Logic ripped off of scf_walk_fmri()
1143 * Thanks to the smf team.
1149 proc_fmri(char *optstr
)
1151 if (strpbrk(optstr
, "*?[") != NULL
) {
1152 /* have a pattern to glob for */
1154 fmri
.sp_type
= PATTERN_GLOB
;
1155 if (optstr
[0] == '*' ||
1156 (strlen(optstr
) >= 4 && optstr
[3] == ':')) {
1157 fmri
.sp_arg
= strdup(optstr
);
1158 } else if ((fmri
.sp_arg
= malloc(strlen(optstr
) + 6)) != NULL
) {
1159 (void) snprintf(fmri
.sp_arg
, strlen(optstr
) + 6,
1163 fmri
.sp_type
= PATTERN_PARTIAL
;
1164 fmri
.sp_arg
= strdup(optstr
);
1166 if (fmri
.sp_arg
== NULL
)