1 /* ausearch-options.c - parse commandline options and configure ausearch
2 * Copyright 2005-08,2010-11,2014 Red Hat Inc., Durham, North Carolina.
3 * Copyright (c) 2011 IBM Corp.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Debora Velarde <dvelarde@us.ibm.com>
22 * Steve Grubb <sgrubb@redhat.com>
23 * Marcelo Henrique Cerri <mhcerri@br.ibm.com>
34 #include "ausearch-options.h"
35 #include "ausearch-time.h"
36 #include "ausearch-int.h"
40 /* Global vars that will be accessed by the main program */
41 char *user_file = NULL;
44 /* Global vars that will be accessed by the match model */
45 unsigned int event_id = -1;
46 gid_t event_gid = -1, event_egid = -1;
47 ilist *event_type = NULL;
48 pid_t event_pid = -1, event_ppid = -1;
49 success_t event_success = S_UNSET;
50 int event_exact_match = 0;
51 uid_t event_uid = -1, event_euid = -1, event_loginuid = -2;
52 int event_syscall = -1, event_machine = -1;
53 int event_ua = 0, event_ga = 0, event_se = 0;
55 uint32_t event_session_id = -2;
56 long long event_exit = 0;
57 int event_exit_is_set = 0;
58 int line_buffered = 0;
60 int checkpt_timeonly = 0;
61 const char *event_key = NULL;
62 const char *event_filename = NULL;
63 const char *event_exe = NULL;
64 const char *event_comm = NULL;
65 const char *event_hostname = NULL;
66 const char *event_terminal = NULL;
67 const char *event_subject = NULL;
68 const char *event_object = NULL;
69 const char *event_uuid = NULL;
70 const char *event_vmname = NULL;
71 const char *checkpt_filename = NULL; /* checkpoint filename if present */
72 report_t report_format = RPT_DEFAULT;
75 slist *event_node_list = NULL;
83 enum { S_EVENT, S_COMM, S_FILENAME, S_ALL_GID, S_EFF_GID, S_GID, S_HELP,
84 S_HOSTNAME, S_INTERP, S_INFILE, S_MESSAGE_TYPE, S_PID, S_SYSCALL, S_OSUCCESS,
85 S_TIME_END, S_TIME_START, S_TERMINAL, S_ALL_UID, S_EFF_UID, S_UID, S_LOGINID,
86 S_VERSION, S_EXACT_MATCH, S_EXECUTABLE, S_CONTEXT, S_SUBJECT, S_OBJECT,
87 S_PPID, S_KEY, S_RAW, S_NODE, S_IN_LOGS, S_JUST_ONE, S_SESSION, S_EXIT,
88 S_LINEBUFFERED, S_UUID, S_VMNAME, S_DEBUG, S_CHECKPOINT, S_ARCH };
90 static struct nv_pair optiontab[] = {
93 { S_EVENT, "--event" },
96 { S_CHECKPOINT, "--checkpoint" },
97 { S_DEBUG, "--debug" },
100 { S_FILENAME, "-f" },
101 { S_FILENAME, "--file" },
102 { S_ALL_GID, "-ga" },
103 { S_ALL_GID, "--gid-all" },
104 { S_EFF_GID, "-ge" },
105 { S_EFF_GID, "--gid-effective" },
109 { S_HELP, "--help" },
110 { S_HOSTNAME, "-hn" },
111 { S_HOSTNAME, "--host" },
113 { S_INTERP, "--interpret" },
115 { S_INFILE, "--input" },
116 { S_IN_LOGS, "--input-logs" },
117 { S_JUST_ONE, "--just-one" },
120 { S_LINEBUFFERED, "-l" },
121 { S_LINEBUFFERED, "--line-buffered" },
122 { S_MESSAGE_TYPE, "-m" },
123 { S_MESSAGE_TYPE, "--message" },
125 { S_NODE, "--node" },
127 { S_OBJECT, "--object" },
131 { S_PPID, "--ppid" },
134 { S_SYSCALL, "-sc" },
135 { S_SYSCALL, "--syscall" },
136 { S_CONTEXT, "-se" },
137 { S_CONTEXT, "--context" },
138 { S_SESSION, "--session" },
139 { S_SUBJECT, "-su" },
140 { S_SUBJECT, "--subject" },
141 { S_OSUCCESS, "-sv" },
142 { S_OSUCCESS, "--success" },
143 { S_TIME_END, "-te"},
144 { S_TIME_END, "--end"},
145 { S_TIME_START, "-ts" },
146 { S_TIME_START, "--start" },
147 { S_TERMINAL, "-tm" },
148 { S_TERMINAL, "--terminal" },
149 { S_ALL_UID, "-ua" },
150 { S_ALL_UID, "--uid-all" },
151 { S_EFF_UID, "-ue" },
152 { S_EFF_UID, "--uid-effective" },
156 { S_UUID, "--uuid" },
157 { S_LOGINID, "-ul" },
158 { S_LOGINID, "--loginuid" },
160 { S_VERSION, "--version" },
162 { S_VMNAME, "--vm-name" },
163 { S_EXACT_MATCH, "-w" },
164 { S_EXACT_MATCH, "--word" },
165 { S_EXECUTABLE, "-x" },
166 { S_EXECUTABLE, "--executable" }
168 #define OPTION_NAMES (sizeof(optiontab)/sizeof(optiontab[0]))
171 static int audit_lookup_option(const char *name)
175 for (i = 0; i < OPTION_NAMES; i++)
176 if (!strcmp(optiontab[i].name, name))
177 return optiontab[i].value;
181 static void usage(void)
183 printf("usage: ausearch [options]\n"
184 "\t-a,--event <Audit event id>\tsearch based on audit event id\n"
185 "\t--arch <CPU>\t\t\tsearch based on the CPU architecture\n"
186 "\t-c,--comm <Comm name>\t\tsearch based on command line name\n"
187 "\t--checkpoint <checkpoint file>\tsearch from last complete event\n"
188 "\t--debug\t\t\tWrite malformed events that are skipped to stderr\n"
189 "\t-e,--exit <Exit code or errno>\tsearch based on syscall exit code\n"
190 "\t-f,--file <File name>\t\tsearch based on file name\n"
191 "\t-ga,--gid-all <all Group id>\tsearch based on All group ids\n"
192 "\t-ge,--gid-effective <effective Group id> search based on Effective\n\t\t\t\t\tgroup id\n"
193 "\t-gi,--gid <Group Id>\t\tsearch based on group id\n"
194 "\t-h,--help\t\t\thelp\n"
195 "\t-hn,--host <Host Name>\t\tsearch based on remote host name\n"
196 "\t-i,--interpret\t\t\tInterpret results to be human readable\n"
197 "\t-if,--input <Input File name>\tuse this file instead of current logs\n"
198 "\t--input-logs\t\t\tUse the logs even if stdin is a pipe\n"
199 "\t--just-one\t\t\tEmit just one event\n"
200 "\t-k,--key <key string>\t\tsearch based on key field\n"
201 "\t-l, --line-buffered\t\tFlush output on every line\n"
202 "\t-m,--message <Message type>\tsearch based on message type\n"
203 "\t-n,--node <Node name>\t\tsearch based on machine's name\n"
204 "\t-o,--object <SE Linux Object context> search based on context of object\n"
205 "\t-p,--pid <Process id>\t\tsearch based on process id\n"
206 "\t-pp,--ppid <Parent Process id>\tsearch based on parent process id\n"
207 "\t-r,--raw\t\t\toutput is completely unformatted\n"
208 "\t-sc,--syscall <SysCall name>\tsearch based on syscall name or number\n"
209 "\t-se,--context <SE Linux context> search based on either subject or\n\t\t\t\t\t object\n"
210 "\t--session <login session id>\tsearch based on login session id\n"
211 "\t-su,--subject <SE Linux context> search based on context of the Subject\n"
212 "\t-sv,--success <Success Value>\tsearch based on syscall or event\n\t\t\t\t\tsuccess value\n"
213 "\t-te,--end [end date] [end time]\tending date & time for search\n"
214 "\t-ts,--start [start date] [start time]\tstarting data & time for search\n"
215 "\t-tm,--terminal <TerMinal>\tsearch based on terminal\n"
216 "\t-ua,--uid-all <all User id>\tsearch based on All user id's\n"
217 "\t-ue,--uid-effective <effective User id> search based on Effective\n\t\t\t\t\tuser id\n"
218 "\t-ui,--uid <User Id>\t\tsearch based on user id\n"
219 "\t-ul,--loginuid <login id>\tsearch based on the User's Login id\n"
220 "\t-uu,--uuid <guest UUID>\t\tsearch for events related to the virtual\n"
221 "\t\t\t\t\tmachine with the given UUID.\n"
222 "\t-v,--version\t\t\tversion\n"
223 "\t-vm,--vm-name <guest name>\tsearch for events related to the virtual\n"
224 "\t\t\t\t\tmachine with the name.\n"
225 "\t-w,--word\t\t\tstring matches are whole word\n"
226 "\t-x,--executable <executable name> search based on executable name\n"
230 static int convert_str_to_msg(const char *optarg)
234 if (isdigit(optarg[0])) {
236 tmp = strtoul(optarg, NULL, 10);
239 "Numeric message type conversion error (%s) for %s\n",
240 strerror(errno), optarg);
244 tmp = audit_name_to_msg_type(optarg);
249 if (event_type == NULL) {
250 event_type = malloc(sizeof(ilist));
251 if (event_type == NULL)
253 ilist_create(event_type);
255 ilist_append(event_type, tmp, 1, 0);
260 static int parse_msg(const char *optarg)
265 if (strchr(optarg, ',')) {
266 char *ptr, *tmp = strdup(optarg);
269 ptr = strtok_r(tmp, ",", &saved);
271 retval = convert_str_to_msg(ptr);
274 ptr = strtok_r(NULL, ",", &saved);
280 return convert_str_to_msg(optarg);
284 * This function examines the commandline parameters and sets various
285 * search options. It returns a 0 on success and < 0 on failure
287 int check_params(int count, char *vars[])
297 while (c < count && retval == 0) {
298 // Go ahead and point to the next argument
300 if (vars[c+1][0] != '-')
307 switch (audit_lookup_option(vars[c])) {
311 "Argument is required for %s\n",
316 if (isdigit(optarg[0])) {
318 event_id = strtoul(optarg, NULL, 10);
321 "Illegal value for audit event ID");
327 "Audit event id must be a numeric value, was %s\n",
335 "Argument is required for %s\n",
340 event_comm = strdup(optarg);
341 if (event_comm == NULL)
349 "Argument is required for %s\n",
353 event_filename = strdup(optarg);
354 if (event_filename == NULL)
362 "Argument is required for %s\n",
366 event_key = strdup(optarg);
367 if (event_key == NULL)
375 "Argument is required for %s\n",
380 if (isdigit(optarg[0])) {
382 event_gid = strtoul(optarg,NULL,10);
385 "Numeric group ID conversion error (%s) for %s\n",
386 strerror(errno), optarg);
392 gr = getgrnam(optarg) ;
395 "Group ID is non-numeric and unknown (%s)\n",
400 event_gid = gr->gr_gid;
402 event_egid = event_gid;
409 "Argument is required for %s\n",
414 if (isdigit(optarg[0])) {
416 event_egid = strtoul(optarg,NULL,10);
419 "Numeric group ID conversion error (%s) for %s\n",
420 strerror(errno), optarg);
426 gr = getgrnam(optarg) ;
429 "Effective group ID is non-numeric and unknown (%s)\n",
434 event_egid = gr->gr_gid;
441 "Argument is required for %s\n",
446 if (isdigit(optarg[0])) {
448 event_gid = strtoul(optarg,NULL,10);
451 "Numeric group ID conversion error (%s) for %s\n",
452 strerror(errno), optarg);
458 gr = getgrnam(optarg) ;
461 "Group ID is non-numeric and unknown (%s)\n",
466 event_gid = gr->gr_gid;
477 "Argument is required for %s\n",
481 event_hostname = strdup(optarg);
482 if (event_hostname == NULL)
488 if (report_format == RPT_DEFAULT)
489 report_format = RPT_INTERP;
492 "Conflicting output format %s\n",
498 "Argument is NOT required for %s\n",
506 "Argument is required for %s\n",
510 user_file = strdup(optarg);
511 if (user_file == NULL)
519 "Argument is required for %s\n",
523 if (strcasecmp(optarg, "ALL") != 0) {
524 retval = parse_msg(optarg);
531 "Valid message types are: ALL ");
532 for (i=AUDIT_USER;i<=AUDIT_LAST_VIRT_MSG;i++){
534 if (i == AUDIT_WATCH_INS) // Skip a few
535 i = AUDIT_FIRST_USER_MSG;
536 name = audit_msg_type_to_name(i);
538 fprintf(stderr, "%s ", name);
540 fprintf(stderr, "\n");
546 "Argument is required for %s\n",
551 event_object = strdup(optarg);
552 if (event_object == NULL)
560 "Argument is required for %s\n",
565 if (isdigit(optarg[0])) {
567 event_ppid = strtol(optarg,NULL,10);
573 "Parent process id must be a numeric value, was %s\n",
581 "Argument is required for %s\n",
586 if (isdigit(optarg[0])) {
588 event_pid = strtol(optarg,NULL,10);
594 "Process id must be a numeric value, was %s\n",
600 if (report_format == RPT_DEFAULT)
601 report_format = RPT_RAW;
604 "Conflicting output format --raw\n");
609 "Argument is NOT required for --raw\n");
616 "Argument is required for %s\n",
623 if (!event_node_list) {
624 event_node_list = malloc(sizeof (slist));
625 if (!event_node_list) {
629 slist_create(event_node_list);
632 sn.str = strdup(optarg);
635 slist_append(event_node_list, &sn);
641 "Argument is required for %s\n",
646 if (isdigit(optarg[0])) {
648 event_syscall = (int)strtoul(optarg, NULL, 10);
651 "Syscall numeric conversion error (%s) for %s\n",
652 strerror(errno), optarg);
656 if (event_machine == -1) {
658 machine = audit_detect_machine();
661 "Error detecting machine type");
665 event_machine = machine;
667 event_syscall = audit_name_to_syscall(optarg,
669 if (event_syscall == -1) {
671 "Syscall %s not found\n",
681 "Argument is required for %s\n",
686 event_subject = strdup(optarg);
687 if (event_subject == NULL)
689 event_object = strdup(optarg);
690 if (event_object == NULL)
699 "Argument is required for %s\n",
704 event_subject = strdup(optarg);
705 if (event_subject == NULL)
713 "Argument is required for %s\n",
718 if ( (strstr(optarg, "yes")!=NULL) ||
719 (strstr(optarg, "no")!=NULL) ) {
720 if (strcmp(optarg, "yes") == 0)
721 event_success = S_SUCCESS;
723 event_success = S_FAILED;
726 "Success must be 'yes' or 'no'.\n");
733 if ((c+1 < count) && vars[c+1])
737 "Argument is required for %s\n",
744 size_t len = strlen(optarg);
745 if (isdigit(optarg[0])) {
747 event_session_id = strtoul(optarg,NULL,10);
751 } else if (len >= 2 && *(optarg)=='-' &&
752 (isdigit(optarg[1]))) {
754 event_session_id = strtoul(optarg, NULL, 0);
757 fprintf(stderr, "Error converting %s\n",
763 "Session id must be a numeric value, was %s\n",
771 if ((c+1 < count) && vars[c+1])
775 "Argument is required for %s\n",
782 size_t len = strlen(optarg);
783 if (isdigit(optarg[0])) {
785 event_exit = strtoll(optarg, NULL, 0);
788 fprintf(stderr, "Error converting %s\n",
791 } else if (len >= 2 && *(optarg)=='-' &&
792 (isdigit(optarg[1]))) {
794 event_exit = strtoll(optarg, NULL, 0);
797 fprintf(stderr, "Error converting %s\n",
801 event_exit = audit_name_to_errno(optarg);
802 if (event_exit == 0) {
805 "Unknown errno, was %s\n",
811 event_exit_is_set = 1;
816 if ( (c+2 < count) && vars[c+2] &&
817 (vars[c+2][0] != '-') ) {
818 /* Have both date and time - check order*/
819 if (strchr(optarg, ':')) {
820 if (ausearch_time_end(vars[c+2],
824 if (ausearch_time_end(optarg,
830 // Check against recognized words
831 int t = lookup_time(optarg);
833 if (ausearch_time_end(optarg,
836 } else if ( (strchr(optarg, ':')) == NULL) {
838 if (ausearch_time_end(optarg,
843 if (ausearch_time_end(NULL,
852 "%s requires either date and/or time\n",
858 if ( (c+2 < count) && vars[c+2] &&
859 (vars[c+2][0] != '-') ) {
860 /* Have both date and time - check order */
861 if (strchr(optarg, ':')) {
862 if (ausearch_time_start(
863 vars[c+2], optarg) != 0)
866 if (ausearch_time_start(optarg,
872 // Check against recognized words
873 int t = lookup_time(optarg);
875 if (ausearch_time_start(optarg,
878 } else if (strcmp(optarg,
879 "checkpoint") == 0) {
880 // Only use the timestamp from within
881 // the checkpoint file
883 } else if (strchr(optarg, ':') == NULL){
885 if (ausearch_time_start(optarg,
890 if (ausearch_time_start(NULL,
899 "%s requires either date and/or time\n",
906 "Argument is required for %s\n",
910 event_terminal = strdup(optarg);
911 if (event_terminal == NULL)
919 "Argument is required for %s\n",
924 if (isdigit(optarg[0])) {
926 event_uid = strtoul(optarg,NULL,10);
929 "Numeric user ID conversion error (%s) for %s\n",
930 strerror(errno), optarg);
936 pw = getpwnam(optarg);
939 "Effective user ID is non-numeric and unknown (%s)\n",
944 event_uid = pw->pw_uid;
951 "Argument is required for %s\n",
956 if (isdigit(optarg[0])) {
958 event_euid = strtoul(optarg,NULL,10);
961 "Numeric user ID conversion error (%s) for %s\n",
962 strerror(errno), optarg);
968 pw = getpwnam(optarg) ;
971 "User ID is non-numeric and unknown (%s)\n",
976 event_euid = pw->pw_uid;
983 "Argument is required for %s\n",
988 if (isdigit(optarg[0])) {
990 event_uid = strtoul(optarg,NULL,10);
993 "Numeric user ID conversion error (%s) for %s\n",
994 strerror(errno), optarg);
1000 pw = getpwnam(optarg) ;
1003 "User ID is non-numeric and unknown (%s)\n",
1008 event_uid = pw->pw_uid;
1011 event_euid = event_uid;
1012 event_loginuid = event_uid;
1017 if ((c+1 < count) && vars[c+1])
1021 "Argument is required for %s\n",
1028 size_t len = strlen(optarg);
1029 if (isdigit(optarg[0])) {
1031 event_loginuid = strtoul(optarg,NULL,10);
1034 "Numeric user ID conversion error (%s) for %s\n",
1035 strerror(errno), optarg);
1038 } else if (len >= 2 && *(optarg)=='-' &&
1039 (isdigit(optarg[1]))) {
1041 event_loginuid = strtol(optarg, NULL, 0);
1044 fprintf(stderr, "Error converting %s\n",
1050 pw = getpwnam(optarg) ;
1053 "Login user ID is non-numeric and unknown (%s)\n",
1058 event_loginuid = pw->pw_uid;
1066 "Argument is required for %s\n",
1070 event_uuid = strdup(optarg);
1071 if (event_uuid == NULL) {
1080 "Argument is required for %s\n",
1084 event_vmname= strdup(optarg);
1085 if (event_vmname == NULL) {
1092 printf("ausearch version %s\n", VERSION);
1096 event_exact_match=1;
1107 "Argument is required for %s\n",
1111 event_exe = strdup(optarg);
1112 if (event_exe == NULL)
1117 case S_LINEBUFFERED:
1126 "Argument is required for %s\n",
1130 checkpt_filename = strdup(optarg);
1131 if (checkpt_filename == NULL)
1139 "Argument is required for %s\n",
1144 if (event_machine != -1) {
1145 if (event_syscall != -1)
1147 "Arch needs to be defined before the syscall\n");
1150 "Arch is already defined\n");
1154 int machine = audit_determine_machine(optarg);
1156 fprintf(stderr, "Unknown arch %s\n",
1160 event_machine = machine;
1165 fprintf(stderr, "%s is an unsupported option\n",