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_label(char *);
93 static int proc_subject(char *);
94 static int proc_sid(char *);
95 static int proc_type(char *);
96 static int proc_user(char *, uid_t
*);
97 static int proc_zonename(char *);
98 static int proc_fmri(char *);
101 * .func process_options - process command line options.
102 * .desc Process the user's command line options. These are of two types:
103 * single letter flags that are denoted by '-', and filenames. Some
104 * of the flags have arguments. Getopt() is used to get the flags.
105 * When this is done it calls process_fileopt() to handle any filenames
107 * .call ret = process_options(argc, argv).
108 * .arg argc - the original value.
109 * .arg argv - the original value.
110 * .ret 0 - no errors detected.
111 * .ret -1 - command line error detected (message already printed).
114 process_options(int argc
, char **argv
)
118 int error_combo
= FALSE
;
119 extern int optind
; /* in getopt() */
120 extern char *optarg
; /* in getopt() - holds arg to flag */
122 static char *options
= "ACD:M:NQR:S:VO:"
123 "a:b:c:d:e:g:j:l:m:o:r:s:t:u:z:";
125 error_str
= gettext("general error");
129 * Big switch to process the flags.
130 * Start_over: is for handling the '-' for standard input. Getopt()
131 * doesn't recognize it.
134 while ((opt
= getopt(argc
, argv
, options
)) != EOF
) {
136 case 'A': /* all records from the files */
139 case 'C': /* process only completed files */
142 case 'D': /* delete the files when done */
143 /* force 'A' 'C' 'O' to be active */
144 f_all
= f_complete
= TRUE
;
148 case 'M': /* only files from a certain machine */
151 case 'N': /* new object selection mode */
154 case 'Q': /* no file error reporting */
157 case 'R': /* from specified root */
160 case 'S': /* from specified server */
163 case 'V': /* list all files as they are opened */
166 case 'O': /* write to outfile */
169 case 'a': /* after 'date' */
170 case 'b': /* before 'date' */
171 case 'd': /* from 'day' */
172 if (proc_date(optarg
, opt
))
175 case 'j': /* subject */
176 if (proc_subject(optarg
))
179 case 'm': /* message 'type' */
180 if (proc_type(optarg
))
183 case 'o': /* object type */
184 if (proc_object(optarg
))
187 case 'c': /* message class */
188 if (proc_class(optarg
))
191 case 'u': /* form audit user */
192 case 'e': /* form effective user */
193 case 'r': /* form real user */
194 case 'f': /* form effective group */
195 case 'g': /* form real group */
196 if (proc_id(optarg
, opt
))
199 case 'l': /* TX label range */
200 if (!is_system_labeled()) {
201 (void) fprintf(stderr
,
202 gettext("%s option 'l' requires "
203 "Trusted Extensions.\n"), ar
);
206 if (proc_label(optarg
))
209 case 's': /* session ID */
210 if (proc_sid(optarg
))
213 case 'z': /* zone name */
214 if (proc_zonename(optarg
))
217 case 't': /* termial ID reserved for later */
222 (void) fprintf(stderr
,
223 gettext("%s command line error - %s.\n"),
228 /* catch '-' option for stdin processing - getopt() won't see it */
230 if (argv
[optind
][0] == '-' && argv
[optind
][1] == '\0') {
237 * Give a default value for 'b' option if not specified.
240 m_before
= MAXLONG
; /* forever */
242 * Validate combinations of options.
243 * The following are done:
244 * 1. Can't have 'M' or 'S' or 'R' with filenames.
245 * 2. Can't have an after ('a') time after a before ('b') time.
246 * 3. Delete ('D') must have 'C' and 'A' and 'O' with it.
247 * 4. Input from stdin ('-') can't have filenames too.
249 if ((f_machine
|| f_server
|| f_root
) && (argc
!= optind
)) {
251 "no filenames allowed with 'M' or 'S' or 'R' options");
254 if (m_after
>= m_before
) {
256 gettext("'a' parameter must be before 'b' parameter");
260 (!f_complete
|| !f_all
|| !f_outfile
)) {
262 "'C', 'A', and 'O' must be specified with 'D'");
265 if (f_stdin
&& (argc
!= optind
)) {
266 error_str
= gettext("no filenames allowed with '-' option");
270 * If error with option combos then print message and exit.
271 * If there was an error with just an option then exit.
274 (void) fprintf(stderr
,
275 gettext("%s command line error - %s.\n"), ar
, error_str
);
279 f_root
= "/etc/security/audit";
281 * Now handle any filenames included in the command line.
283 return (process_fileopt(argc
, argv
, optind
));
287 proc_subject(char *optarg
)
289 if (flags
& M_SUBJECT
) {
290 error_str
= gettext("'j' option specified multiple times");
294 subj_id
= atol(optarg
);
299 proc_sid(char *optarg
)
302 error_str
= gettext("'s' option specified multiple times");
306 m_sid
= (au_asid_t
)atol(optarg
);
311 proc_object(char *optarg
)
321 if (flags
& M_OBJECT
) {
322 error_str
= gettext("'o' option specified multiple times");
326 if ((obj_arg
= strdup(optarg
)) == (char *)0)
328 if ((obj_str
= strtok(optarg
, "=")) == (char *)0 ||
329 (oep
= obj_lkup(obj_str
)) == (obj_ent_t
*)0 ||
330 (obj_val
= strtok((char *)0, "=")) == (char *)0) {
331 (void) sprintf(errbuf
, gettext("invalid object arg (%s)"),
337 obj_flag
= oep
->obj_flag
;
341 if ((error_str
= re_comp2(obj_val
)) != (char *)NULL
) {
346 if (!a_isnum(obj_val
, TRUE
)) {
347 obj_id
= atol(obj_val
);
348 socket_flag
= SOCKFLG_PORT
;
351 if (*obj_val
== '0') {
352 (void) sscanf(obj_val
, "%x", (uint_t
*)&obj_id
);
353 socket_flag
= SOCKFLG_PORT
;
357 he
= getipnodebyname((const void *)obj_val
, AF_INET6
, 0, &err
);
359 he
= getipnodebyname((const void *)obj_val
, AF_INET
,
362 (void) sprintf(errbuf
,
363 gettext("invalid machine name (%s)"),
370 if (he
->h_addrtype
== AF_INET6
) {
372 if (IN6_IS_ADDR_V4MAPPED(
373 (in6_addr_t
*)he
->h_addr_list
[0])) {
374 /* address is IPv4 (32 bits) */
375 (void) memcpy(&obj_id
,
376 he
->h_addr_list
[0] + 12, 4);
379 (void) memcpy(ip_ipv6
, he
->h_addr_list
[0], 16);
383 /* address is IPv4 (32 bits) */
384 (void) memcpy(&obj_id
, he
->h_addr_list
[0], 4);
389 socket_flag
= SOCKFLG_MACHINE
;
395 obj_id
= atol(obj_val
);
402 return (proc_group(obj_val
, &obj_group
));
408 return (proc_user(obj_val
, &obj_owner
));
410 return (proc_fmri(obj_val
));
412 return (proc_user(obj_val
, &obj_user
));
413 case OBJ_LP
: /* lp objects have not yet been defined */
414 default: /* impossible */
415 (void) sprintf(errbuf
, gettext("invalid object type (%s)"),
425 obj_lkup(char *obj_str
)
429 for (i
= 0; i
< sizeof (obj_tbl
) / sizeof (obj_ent_t
); i
++)
430 if (strcmp(obj_str
, obj_tbl
[i
].obj_str
) == 0)
431 return (&obj_tbl
[i
]);
439 * .func proc_type - process record type.
440 * .desc Process a record type. It is either as a number or a mnemonic.
441 * .call ret = proc_type(optstr).
442 * .arg optstr - ptr to name or number.
443 * .ret 0 - no errors detected.
444 * .ret -1 - error detected (error_str contains description).
447 proc_type(char *optstr
)
449 struct au_event_ent
*aep
;
452 * Either a number or a name.
455 if (flags
& M_TYPE
) {
456 error_str
= gettext("'m' option specified multiple times");
461 if (a_isnum(optstr
, TRUE
)) {
462 if ((aep
= getauevnam(optstr
)) != NULL
)
463 m_type
= aep
->ae_number
;
465 if ((aep
= getauevnum((au_event_t
)atoi(optstr
))) !=
466 (struct au_event_ent
*)NULL
)
467 m_type
= aep
->ae_number
;
470 (void) sprintf(errbuf
, gettext("invalid event (%s)"), optstr
);
479 * .func a_isnum - is it a number?
480 * .desc Determine if a string is a number or a name.
481 * A number may have a leading '+' or '-', but then must be
483 * .call ret = a_isnum(str).
484 * .arg str - ptr to the string.
485 * .arg leading - TRUE if leading '+-' allowed.
486 * .ret 0 - is a number.
487 * .ret 1 - is not a number.
490 a_isnum(char *str
, int leading
)
494 if ((leading
== TRUE
) && (*str
== '-' || *str
== '+'))
499 if (strlen(strs
) == strspn(strs
, "0123456789"))
507 * .func proc_id - process user/group id's/
508 * .desc Process either a user number/name or group number/name.
509 * For names check to see if the name is active in the system
510 * to derive the number. If it is not active then fail. For a number
511 * also check to see if it is active, but only print a warning if it
512 * is not. An administrator may be looking at activity of a 'phantom'
514 * .call ret = proc_id(optstr, opt).
515 * .arg optstr - ptr to name or number.
516 * .arg opt - 'u' - audit user, 'e' - effective user, 'r' - real user,
517 * 'g' - group, 'f' - effective group.
518 * .ret 0 - no errors detected.
519 * .ret -1 - error detected (error_str contains description).
522 proc_id(char *optstr
, int opt
)
525 case 'e': /* effective user id */
526 if (flags
& M_USERE
) {
528 "'e' option specified multiple times");
532 return (proc_user(optstr
, &m_usere
));
533 case 'f': /* effective group id */
534 if (flags
& M_GROUPE
) {
536 "'f' option specified multiple times");
540 return (proc_group(optstr
, &m_groupe
));
541 case 'r': /* real user id */
542 if (flags
& M_USERR
) {
544 "'r' option specified multiple times");
548 return (proc_user(optstr
, &m_userr
));
549 case 'u': /* audit user id */
550 if (flags
& M_USERA
) {
552 "'u' option specified multiple times");
556 return (proc_user(optstr
, &m_usera
));
557 case 'g': /* real group id */
558 if (flags
& M_GROUPR
) {
560 "'g' option specified multiple times");
564 return (proc_group(optstr
, &m_groupr
));
565 default: /* impossible */
566 (void) sprintf(errbuf
, gettext("'%c' unknown option"), opt
);
575 proc_group(char *optstr
, gid_t
*gid
)
579 if ((grp
= getgrnam(optstr
)) == NULL
) {
580 if (!a_isnum(optstr
, TRUE
)) {
581 *gid
= (gid_t
)atoi(optstr
);
584 (void) sprintf(errbuf
, gettext("group name invalid (%s)"),
595 proc_user(char *optstr
, uid_t
*uid
)
599 if ((usr
= getpwnam(optstr
)) == NULL
) {
600 if (!a_isnum(optstr
, TRUE
)) {
601 *uid
= (uid_t
)atoi(optstr
);
604 (void) sprintf(errbuf
, gettext("user name invalid (%s)"),
615 * .func proc_date - process date argument.
616 * .desc Handle a date/time argument. See if the user has erred in combining
617 * the types of date arguments. Then parse the string and check for
618 * validity of each part.
619 * .call ret = proc_date(optstr, opt).
620 * .arg optstr - ptr to date/time string.
621 * .arg opt - 'd' for day, 'a' for after, or 'b' for before.
622 * .ret 0 - no errors detected.
623 * .ret -1 - errors detected (error_str knows what it is).
626 proc_date(char *optstr
, int opt
)
628 static int m_day
= FALSE
;
633 "'d' option may not be used with 'a' or 'b'");
638 if ((opt
== 'd') && (m_before
|| m_after
)) {
640 "'d' option may not be used with 'a' or 'b'");
643 if ((opt
== 'a' || opt
== 'b') && m_day
) {
645 "'a' or 'b' option may not be used with 'd'");
648 if ((opt
== 'a') && (m_after
!= 0)) {
649 error_str
= gettext("'a' option specified multiple times");
652 if ((opt
== 'b') && (m_before
!= 0)) {
653 error_str
= gettext("'b' option specified multiple times");
656 if (parse_time(optstr
, opt
))
663 * .func proc_class - process message class argument.
664 * .desc Process class type and see if it is for real.
665 * .call ret = proc_class(optstr).
666 * .arg optstr - ptr to class.
667 * .ret 0 - class has class.
668 * .ret -1 - class in no good.
671 proc_class(char *optstr
)
673 if (flags
& M_CLASS
) {
674 error_str
= gettext("'c' option specified multiple times");
679 if (getauditflagsbin(optstr
, &mask
) != 0) {
680 (void) sprintf(errbuf
, gettext("unknown class (%s)"), optstr
);
685 if (mask
.am_success
!= mask
.am_failure
) {
694 * .func process_fileopt - process command line file options.
695 * .desc Process the command line file options and gather the specified files
696 * together in file groups based upon file name suffix. The user can
697 * specify files explicitly on the command line or via a directory.
698 * This is called after the command line flags are processed (as
700 * .call ret = process_fileopt(argc, argv, optindex).
701 * .arg argc - current value of argc.
702 * .arg argv - current value of argv.
703 * .arg optindex- current index into argv (as setup by getopt()).
704 * .ret 0 - no errors detected.
705 * .ret -1 - error detected (message already printed).
708 process_fileopt(int argc
, char **argv
, int optindex
)
710 int f_mode
= FM_ALLDIR
;
711 char f_dr
[MAXNAMLEN
+1];
714 static char *std
= "standard input";
721 * Take input from stdin, not any files.
722 * Use a single fcb to do this.
725 fcb
= (audit_fcb_t
*)a_calloc(1, sizeof (*fcb
) + strlen(std
));
726 (void) strcpy(fcb
->fcb_file
, std
);
727 fcb
->fcb_suffix
= fcb
->fcb_name
= fcb
->fcb_file
;
728 fcb
->fcb_next
= NULL
;
730 fcb
->fcb_end
= MAXLONG
; /* forever */
731 if ((pcb
= get_next_pcb((char *)NULL
)) == (audit_pcb_t
*)NULL
)
733 pcb
->pcb_suffix
= fcb
->fcb_file
;
734 pcb
->pcb_dfirst
= pcb
->pcb_first
= fcb
; /* one-item list */
735 pcb
->pcb_dlast
= pcb
->pcb_last
= fcb
;
739 * No files specified on the command line.
740 * Process a directory of files or subdirectories.
742 else if (argc
== optindex
) {
744 * A specific server directory was requested.
747 if (strchr(f_server
, '/')) { /* given full path */
749 f_mode
= FM_ALLFILE
; /* all files here */
750 } else { /* directory off audit root */
752 (void) strcat(f_dir
, f_root
);
753 (void) strcat(f_dir
, "/");
754 (void) strcat(f_dir
, f_server
);
759 * Gather all of the files in the directory 'f_dir'.
761 if (f_mode
== FM_ALLFILE
) {
762 if (gather_dir(f_dir
)) { /* get those files together */
767 * Gather all of the files in all of the
768 * directories in 'f_root'.
770 if ((dirp
= opendir(f_root
)) == NULL
) {
771 (void) sprintf(errbuf
, gettext(
772 "%s can't open directory %s"), ar
, f_root
);
776 /* read the directory and process all of the subs */
777 for (dp
= readdir(dirp
);
778 dp
!= NULL
; dp
= readdir(dirp
)) {
779 if (dp
->d_name
[0] == '.')
782 (void) strcat(f_dir
, f_root
);
783 (void) strcat(f_dir
, "/");
784 (void) strcat(f_dir
, dp
->d_name
);
785 if (gather_dir(f_dir
)) /* process a sub */
788 (void) closedir(dirp
);
792 * User specified filenames on the comm and line.
795 for (; optindex
< argc
; optindex
++) {
796 fname
= argv
[optindex
]; /* get a filename */
797 if (proc_file(fname
, FALSE
))
806 * .func gather_dir - gather a directory's files together.
807 * .desc Process all of the files in a specific directory. The files may
808 * be checked for adherence to the file name form at.
809 * If the directory can't be opened that is ok - just print
810 * a message and continue.
811 * .call ret = gather_dir(dir).
812 * .arg dir - ptr to full pathname of directory.
813 * .ret 0 - no errors detected.
814 * .ret -1 - error detected (message already printed).
817 gather_dir(char *dir
)
819 char dname
[MAXNAMLEN
+1];
820 char fname
[MAXNAMLEN
+1];
824 (void) snprintf(dname
, sizeof (dname
), "%s/files", dir
);
826 if ((dirp
= opendir(dname
)) == NULL
) {
827 if (errno
!= ENOTDIR
) {
828 (void) sprintf(errbuf
,
829 gettext("%s can't open directory - %s"), ar
, dname
);
834 for (dp
= readdir(dirp
); dp
!= NULL
; dp
= readdir(dirp
)) {
835 if (dp
->d_name
[0] == '.') /* can't see hidden files */
838 (void) strcat(fname
, dname
); /* create pathname of file */
839 (void) strcat(fname
, "/");
840 (void) strcat(fname
, dp
->d_name
);
841 if (proc_file(fname
, TRUE
))
844 (void) closedir(dirp
);
850 * .func proc_file - process a single candidate file.
851 * .desc Check out a file to see if it should be used in the merge.
852 * This includes checking the name (mode is TRUE) against the
853 * file format, checking access rights to the file, and thence
854 * getting and fcb and installing the fcb into the correct pcb.
855 * If the file fails then the fcb is not installed into a pcb
856 * and the file dissapears from view.
857 * .call proc_file(fname, mode).
858 * .arg fname - ptr to full pathna me of file.
859 * .arg mode - TRUE if checking adherence to file name format.
860 * .ret 0 - no fatal errors detected.
861 * .ret -1 - fatal error detected - quit altogether
862 * (message already printed).
865 proc_file(char *fname
, int mode
)
869 struct stat stat_buf
;
870 audit_fcb_t
*fcb
, *fcbp
, *fcbprev
;
874 * See if it is a weird file like a directory or
875 * character special (around here?).
877 if (stat(fname
, &stat_buf
)) {
880 if (!S_ISREG(stat_buf
.st_mode
))
883 * Allocate a new fcb to hold fcb and full filename.
885 len
= sizeof (audit_fcb_t
) + strlen(fname
);
886 fcb
= (audit_fcb_t
*)a_calloc(1, len
);
887 (void) strcpy(fcb
->fcb_file
, fname
);
888 if (check_file(fcb
, mode
)) { /* check file name */
890 (void) fprintf(stderr
, "%s %s:\n %s.\n", ar
,
896 * Check against file criteria.
897 * Check finish-time here, and start-time later on
899 * This is because the start time on a file can be after
900 * the first record(s).
902 if (f_complete
&& (fcb
->fcb_flags
& FF_NOTTERM
) && !f_cmdline
)
904 if (!f_all
&& (fcb
->fcb_end
< m_after
))
907 if (strlen(fcb
->fcb_suffix
) != strlen(f_machine
) ||
908 (strcmp(fcb
->fcb_suffix
, f_machine
) != 0)) {
913 if (reject
== FALSE
) {
914 filenum
++; /* count of total files to be processed */
915 fcb
->fcb_next
= NULL
;
916 if ((pcb
= get_next_pcb(fcb
->fcb_suffix
)) == NULL
) {
919 /* Place FCB into the PCB in order - oldest first. */
920 fcbp
= pcb
->pcb_first
;
922 while (fcbp
!= NULL
) {
923 if (fcb
->fcb_start
< fcbp
->fcb_start
) {
925 fcbprev
->fcb_next
= fcb
;
927 pcb
->pcb_dfirst
= pcb
->pcb_first
= fcb
;
928 fcb
->fcb_next
= fcbp
;
932 fcbp
= fcbp
->fcb_next
;
934 /* younger than all || empty list */
935 if (!fcb
->fcb_next
) {
936 if (pcb
->pcb_first
== NULL
)
937 pcb
->pcb_dfirst
= pcb
->pcb_first
= fcb
;
938 pcb
->pcb_dlast
= pcb
->pcb_last
= fcb
;
940 fcbprev
->fcb_next
= fcb
;
943 free((char *)fcb
); /* rejected */
950 * .func check_file - check filename and setup fcb.
951 * .desc Check adherence to the file format (do_check is TRUE) and setup
952 * the fcb with useful information.
953 * filename format: yyyymmddhhmmss.yyyymmddhhmmss.suffix
954 * yyyymmddhhmmss.not_terminated.suffix
955 * If do_check is FALSE then still see if the filename does confirm
956 * to the format. If it does then extract useful information from
957 * it (start time and end time). But if it doesn't then don't print
958 * any error messages.
959 * .call ret = check_file(fcb, do_check).
960 * .arg fcb - ptr to fcb that holds the file.
961 * .arg do_check - if TRUE do check adherence to file format.
962 * .ret 0 - no errors detected.
963 * .ret -1 - file failed somehow (error_str tells why).
966 check_file(audit_fcb_t
*fcb
, int do_check
)
970 char errb
[256]; /* build error message */
974 /* get just the filename */
975 for (slp
= namep
= fcb
->fcb_file
; *namep
; namep
++) {
977 slp
= namep
+ 1; /* slp -> the filename itself */
979 if (do_check
== FALSE
) {
980 fcb
->fcb_end
= MAXLONG
; /* forever */
981 fcb
->fcb_suffix
= NULL
;
987 if ((int)strlen(slp
) < 31) {
988 (void) sprintf(errbuf
, gettext("filename too short (%d)"),
994 * Get working copy of filename.
996 namep
= (char *)a_calloc(1, strlen(slp
) + 1);
997 (void) strcpy(namep
, slp
);
998 if (namep
[14] != '.' || namep
[29] != '.') {
999 (void) sprintf(errbuf
,
1000 gettext("invalid filename format (%c or %c)"), namep
[14],
1006 namep
[14] = '\0'; /* mark off start time */
1007 namep
[29] = '\0'; /* mark off finish time */
1008 if (derive_date(namep
, &tme
)) {
1009 (void) strcat(errb
, gettext("starting time-stamp invalid - "));
1010 (void) strcat(errb
, error_str
);
1011 (void) strcpy(errbuf
, errb
);
1017 * Keep start time from filename. Use it to order files in
1018 * the file list. Later we will update this when we read
1019 * the first record from the file.
1021 fcb
->fcb_start
= tm_to_secs(&tme
);
1023 if (strcmp(&namep
[15], "not_terminated") == 0) {
1024 fcb
->fcb_end
= MAXLONG
; /* forever */
1026 * Only treat a 'not_terminated' file as such if
1027 * it is not on the command line.
1029 if (do_check
== TRUE
)
1030 fcb
->fcb_flags
|= FF_NOTTERM
;
1031 } else if (derive_date(&namep
[15], &tme
)) {
1032 (void) strcat(errb
, gettext("ending time-stamp invalid - "));
1033 (void) strcat(errb
, error_str
);
1034 (void) strcpy(errbuf
, errb
);
1039 fcb
->fcb_end
= tm_to_secs(&tme
);
1041 fcb
->fcb_name
= slp
;
1042 fcb
->fcb_suffix
= &slp
[30];
1049 * .func get_next_pcb - get a pcb to use.
1050 * .desc The pcb's in the array audit_pcbs are used to hold single file
1051 * groups in the form of a linked list. Each pcb holds files that
1052 * are tied together by a common suffix in the file name. Here we
1053 * get either 1. the existing pcb holding a specified sufix or
1054 * 2. a new pcb if we can't find an existing one.
1055 * .call pcb = get_next_pcb(suffix).
1056 * .arg suffix - ptr to suffix we are seeking.
1057 * .ret pcb - ptr to pcb that hold s the sought suffix.
1058 * .ret NULL- serious failure in memory allocation. Quit processing.
1061 get_next_pcb(char *suffix
)
1068 /* Search through (maybe) entire array. */
1069 while (i
< pcbsize
) {
1070 pcb
= &audit_pcbs
[i
++];
1071 if (pcb
->pcb_first
== NULL
) {
1072 proc_pcb(pcb
, suffix
, i
);
1073 return (pcb
); /* came to an unused one */
1076 if (strcmp(pcb
->pcb_suffix
, suffix
) == 0)
1077 return (pcb
); /* matched one with suffix */
1081 * Uh-oh, the entire array is used and we haven't gotten one yet.
1082 * Allocate a bigger array.
1085 size
= pcbsize
* sizeof (audit_pcb_t
);
1086 zerosize
= size
- ((pcbsize
- PCB_INC
) * sizeof (audit_pcb_t
));
1087 if ((audit_pcbs
= (audit_pcb_t
*)realloc((char *)audit_pcbs
, size
)) ==
1089 (void) sprintf(errbuf
,
1090 gettext("%s memory reallocation failed (%d bytes)"), ar
,
1093 audit_stats(); /* give user statistics on usage */
1094 return (NULL
); /* really bad thing to have happen */
1097 * Don't know if realloc clears the new memory like calloc would.
1099 (void) memset((void *) & audit_pcbs
[pcbsize
-PCB_INC
], 0,
1101 pcb
= &audit_pcbs
[pcbsize
-PCB_INC
]; /* allocate the first new one */
1102 proc_pcb(pcb
, suffix
, pcbsize
- PCB_INC
);
1108 * .func proc_pcb - process pcb.
1109 * .desc Common pcb processing for above routine.
1110 * .call proc_pcb(pcb, suffix, i).
1111 * .arg pcb - ptr to pcb.
1112 * .arg suffix - prt to suffix tha t ties this group together.
1113 * .arg i - index into audit_pcbs[ ].
1117 proc_pcb(audit_pcb_t
*pcb
, char *suffix
, int i
)
1120 pcb
->pcb_suffix
= suffix
;
1121 pcbnum
++; /* one more pcb in use */
1122 pcb
->pcb_size
= AUDITBUFSIZE
;
1123 pcb
->pcb_rec
= (char *)a_calloc(1, AUDITBUFSIZE
);
1125 pcb
->pcb_flags
|= PF_USEFILE
; /* note this one controls files */
1126 pcb
->pcb_procno
= i
; /* save index into audit_pcbs [] for id */
1131 * .func proc_label - process label range argument.
1132 * .desc Parse label range lower-bound[;upper-bound]
1133 * .call ret = proc_label(optstr).
1134 * .arg opstr - ptr to label range string
1135 * .ret 0 - no errors detected.
1136 * .ret -1 - errors detected (error_str set).
1140 proc_label(char *optstr
)
1145 if (flags
& M_LABEL
) {
1146 error_str
= gettext("'l' option specified multiple times");
1151 if ((m_label
= malloc(sizeof (m_range_t
))) == NULL
) {
1154 m_label
->lower_bound
= NULL
;
1155 m_label
->upper_bound
= NULL
;
1157 p
= strchr(optstr
, ';');
1159 /* exact label match, lower and upper range bounds the same */
1160 if (str_to_label(optstr
, &m_label
->lower_bound
, MAC_LABEL
,
1161 L_NO_CORRECTION
, &error
) == -1) {
1162 (void) sprintf(errbuf
,
1163 gettext("invalid sensitivity label (%s) err %d"),
1168 m_label
->upper_bound
= m_label
->lower_bound
;
1172 /* lower bound is not specified .. default is admin_low */
1173 if (str_to_label(ADMIN_LOW
, &m_label
->lower_bound
, MAC_LABEL
,
1174 L_NO_CORRECTION
, &error
) == -1) {
1180 /* upper bound not specified .. default is admin_high */
1181 if (str_to_label(ADMIN_HIGH
, &m_label
->upper_bound
,
1182 MAC_LABEL
, L_NO_CORRECTION
, &error
) == -1) {
1186 if (str_to_label(p
, &m_label
->upper_bound
, MAC_LABEL
,
1187 L_NO_CORRECTION
, &error
) == -1) {
1188 (void) sprintf(errbuf
, gettext(
1189 "invalid sensitivity label (%s) err %d"),
1198 if (str_to_label(optstr
, &m_label
->lower_bound
, MAC_LABEL
,
1199 L_NO_CORRECTION
, &error
) == -1) {
1200 (void) sprintf(errbuf
,
1201 gettext("invalid sensitivity label (%s) err %d"), optstr
,
1207 /* upper bound is not specified .. default is admin_high */
1208 if (str_to_label(ADMIN_HIGH
, &m_label
->upper_bound
,
1209 MAC_LABEL
, L_NO_CORRECTION
, &error
) == -1) {
1213 if (str_to_label(p
, &m_label
->upper_bound
, MAC_LABEL
,
1214 L_NO_CORRECTION
, &error
) == -1) {
1215 (void) sprintf(errbuf
,
1216 gettext("invalid sensitivity label (%s) err %d"),
1222 /* make sure that upper bound dominates the lower bound */
1223 if (!bldominates(m_label
->upper_bound
, m_label
->lower_bound
)) {
1225 (void) sprintf(errbuf
,
1226 gettext("invalid sensitivity label range (%s)"), optstr
);
1233 m_label_free(m_label
->upper_bound
);
1234 m_label_free(m_label
->lower_bound
);
1241 * proc_zonename - pick up zone name.
1243 * all non-empty and not-too-long strings are valid since any name
1246 * ret 0: non-empty string
1247 * ret -1: empty string or string is too long.
1250 proc_zonename(char *optstr
)
1252 size_t length
= strlen(optstr
);
1253 if ((length
< 1) || (length
> ZONENAME_MAX
)) {
1254 (void) sprintf(errbuf
,
1255 gettext("invalid zone name: %s"), optstr
);
1259 zonename
= strdup(optstr
);
1260 flags
|= M_ZONENAME
;
1265 * proc_frmi - set up frmi for pattern matching.
1266 * Logic ripped off of scf_walk_fmri()
1267 * Thanks to the smf team.
1273 proc_fmri(char *optstr
)
1275 if (strpbrk(optstr
, "*?[") != NULL
) {
1276 /* have a pattern to glob for */
1278 fmri
.sp_type
= PATTERN_GLOB
;
1279 if (optstr
[0] == '*' ||
1280 (strlen(optstr
) >= 4 && optstr
[3] == ':')) {
1281 fmri
.sp_arg
= strdup(optstr
);
1282 } else if ((fmri
.sp_arg
= malloc(strlen(optstr
) + 6)) != NULL
) {
1283 (void) snprintf(fmri
.sp_arg
, strlen(optstr
) + 6,
1287 fmri
.sp_type
= PATTERN_PARTIAL
;
1288 fmri
.sp_arg
= strdup(optstr
);
1290 if (fmri
.sp_arg
== NULL
)