예제 #1
0
static void create_new_session(auparse_state_t *au)
{
	const char *tpid, *tses, *tauid;
	int pid = -1, auid = -1, ses = -1;
	lnode *cur;

	// Get pid
	tpid = auparse_find_field(au, "pid");
	if (tpid)
		pid = auparse_get_field_int(au);

	// Get second auid field
	auparse_find_field(au, "auid");
	auparse_next_field(au);
	tauid = auparse_find_field(au, "auid");
	if (tauid)
		auid = auparse_get_field_int(au);

	// Get second ses field
	auparse_find_field(au, "ses"); 
	auparse_next_field(au);
	tses = auparse_find_field(au, "ses");
	if (tses)
		ses = auparse_get_field_int(au);

	// Check that they are valid
	if (pid == -1 || auid ==-1 || ses == -1) {
		if (debug)
			fprintf(stderr, "Bad login for event: %lu\n",
					auparse_get_serial(au));
		return;
	}

	// See if this session is already open
	//cur = list_find_auid(&l, auid, pid, ses);
	cur = list_find_session(&l, ses);
	if (cur) {
		// This means we have an open session close it out
		cur->status = GONE;
		cur->end = auparse_get_time(au);
		report_session(cur);
		list_delete_cur(&l);
	}

	// If this is supposed to be limited to a specific
	// uid and we don't have that record, skip creating it
	if (cuid != -1 && cuid != auid) {
		if (debug)
			fprintf(stderr,
			    "login reporting limited to %d for event: %lu\n",
				cuid, auparse_get_serial(au));
		return;
	}

	list_create_session(&l, auid, pid, ses, auparse_get_serial(au));
}
예제 #2
0
static void update_session_logout(auparse_state_t *au)
{
	const char *tses, *tauid, *tpid;
	int pid = -1, auid = -1, ses = -1;
	lnode *cur;

	// Get pid field
	tpid = auparse_find_field(au, "pid");
	if (tpid)
		pid = auparse_get_field_int(au);

	// Get auid field
	tauid = auparse_find_field(au, "auid");
	if (tauid)
		auid = auparse_get_field_int(au);

	// Get ses field
	tses = auparse_find_field(au, "ses");
	if (tses)
		ses = auparse_get_field_int(au);

	// Check that they are valid
	if (pid == -1 || auid ==-1 || ses == -1) {
		if (debug)
			fprintf(stderr, "Bad user logout for event: %lu\n",
					auparse_get_serial(au));
		return;
	}

	// See if this session is already open
	cur = list_find_auid(&l, auid, pid, ses);
	if (cur) {
		// if time never got updated, this must be a cron or su 
		// session...so we will just delete it.
		if (cur->start) {
			// This means we have an open session close it out
			time_t end = auparse_get_time(au);
			list_update_logout(&l, end, auparse_get_serial(au));
			report_session(cur);
		} else if (debug)
			fprintf(stderr, "start time error for event: %lu\n",
					auparse_get_serial(au));
		list_delete_cur(&l);
	}
}
예제 #3
0
파일: auvirt.c 프로젝트: yubo/audit
int add_start_guest_event(auparse_state_t *au)
{
	struct event *start;
	uid_t uid;
	time_t time;
	const char *uuid, *name;
	int success;
	list_node_t *it;

	/* Just skip this record if it failed to get some of the fields */
	if (extract_virt_fields(au, &uuid, &uid, &time, &name, &success))
		return 0;

	/* On failure, loop backwards to update all the resources associated to
	 * the last session of this guest. When a machine_id or a stop event is
	 * found the loop can be broken because a machine_id is created at the
	 * beginning of a session and a stop event indicates a previous
	 * session.
	 */
	if (!success) {
		for (it = events->tail; it; it = it->prev) {
			struct event *event = it->data;
			if (event->success && event->uuid &&
			    strcmp(uuid, event->uuid) == 0) {
				if (event->type == ET_STOP ||
				    event->type == ET_MACHINE_ID) {
					/* An old session found. */
					break;
				} else if (event->type == ET_RES &&
				           event->end == 0) {
					event->end = time;
					add_proof(event, au);
				}
			}
		}
	}

	start = event_alloc();
	if (start == NULL)
		return 1;
	start->type = ET_START;
	start->uuid = copy_str(uuid);
	start->name = copy_str(name);
	start->success = success;
	start->uid = uid;
	start->start = time;
	auparse_first_record(au);
	if (auparse_find_field(au, "vm-pid"))
		start->pid = auparse_get_field_int(au);
	add_proof(start, au);
	if (list_append(events, start) == NULL) {
		event_free(start);
		return 1;
	}
	return 0;
}
예제 #4
0
파일: auvirt.c 프로젝트: yubo/audit
/* Extract the most common fields from virtualization-related records. */
int extract_virt_fields(auparse_state_t *au, const char **p_uuid,
		uid_t *p_uid, time_t *p_time, const char **p_name,
		int *p_suc)
{
	const char *field;
	auparse_first_record(au);
	/* Order matters */
	if (p_uid) {
		if (!auparse_find_field(au, field = "uid"))
			goto error;
		*p_uid = auparse_get_field_int(au);
	}
	if (p_name) {
		if (!auparse_find_field(au, field = "vm"))
			goto error;
		*p_name = auparse_interpret_field(au);
	}
	if (p_uuid) {
		if (!auparse_find_field(au, field = "uuid"))
			goto error;
		*p_uuid = auparse_get_field_str(au);
	}
	if (p_suc) {
		const char *res = auparse_find_field(au, field = "res");
		if (res == NULL)
			goto error;
		*p_suc = (strcmp("success", res) == 0) ? 1 : 0;
	}
	if (p_time) {
		*p_time = auparse_get_time(au);
	}
	return 0;

error:
	if (debug) {
		fprintf(stderr, "Failed to get field \"%s\" for record "
				"%ld.%03u:%lu\n", field ? field : "",
				auparse_get_time(au),
				auparse_get_milli(au),
				auparse_get_serial(au));
	}
	return 1;
}
예제 #5
0
static void update_session_login(auparse_state_t *au)
{
	const char *tpid, *tses, *tuid, *tacct=NULL, *host, *term, *tres;
	int pid = -1, uid = -1, ses = -1, result = -1;
	time_t start;
	lnode *cur;

	// Get pid
	tpid = auparse_find_field(au, "pid");
	if (tpid)
		pid = auparse_get_field_int(au);

	// Get ses field
	tses = auparse_find_field(au, "ses");
	if (tses)
		ses = auparse_get_field_int(au);

	// Get second uid field - we should be positioned past the first one
	// gdm sends uid, everything else sends id, we try acct as last resort
	tuid = auparse_find_field(au, "uid");
	if (tuid)
		uid = auparse_get_field_int(au);
	else {
		auparse_first_record(au);
		tuid = auparse_find_field(au, "id");
		if (tuid)
			uid = auparse_get_field_int(au);
		else {
			auparse_first_record(au);
			tuid = auparse_find_field(au, "acct");
			if (tuid) {
				const char *tacct = auparse_interpret_field(au);
				struct passwd *pw = getpwnam (tacct);
				if (pw != NULL)
					uid = pw->pw_uid;
			} else
				auparse_first_record(au);
		}
	}

	start = auparse_get_time(au);

	host = auparse_find_field(au, "hostname");
	if (host && strcmp(host, "?") == 0)
		host = auparse_find_field(au, "addr");

	term = auparse_find_field(au, "terminal");
	if (term == NULL)
		term = "?";
	tres = auparse_find_field(au, "res");
	if (tres)
		tres = auparse_interpret_field(au);
	if (tres) {
		if (strcmp(tres, "success") == 0)
			result = 0;
		else
			result = 1;
	}
	// We only get tacct when its a bad login
	if (result == 1) {
		auparse_first_record(au);
		tacct = auparse_find_field(au, "acct");
		if (tacct)
			tacct = auparse_interpret_field(au);
	} else {
		// Check that they are valid
		if (pid == -1 || uid ==-1 || ses == -1) { 
			if (debug)
				fprintf(stderr,
					"Bad user login for event: %lu\n",
					auparse_get_serial(au));
			return;
		}
	}

	// See if this session is already open
	if (result == 0)
		cur = list_find_auid(&l, uid, pid, ses);
	else
		cur = NULL;
	if (cur) {
		// If we are limited to a specific terminal and
		// we find out the session is not associated with
		// the terminal of interest, delete the current node
		if (cterm && strstr(term, cterm) == NULL) {
			list_delete_cur(&l);
			if (debug)
				fprintf(stderr,
				"User login limited to %s for event: %lu\n",
					cterm, auparse_get_serial(au));
			return;
		}

		// This means we have an open session - update it
		list_update_start(&l, start, host, term, result,
				auparse_get_serial(au));

		// If the results were failed, we can close it out
		/* FIXME: result cannot be true. This is dead code.
		if (result) {
			report_session(cur);
			list_delete_cur(&l);
		} */
	} else if (bad == 1 && result == 1) {
		// If it were a bad login and we are wanting bad logins
		// create the record and report it.
		lnode n;

		n.auid = uid;
		n.start = start;
		n.end = start;
		n.name = tacct;
		n.host = host;
		n.term = term;
		n.result = result;
		n.status = LOG_OUT;
		n.loginuid_proof = auparse_get_serial(au);
		report_session(&n); 
	}
}
예제 #6
0
파일: auvirt.c 프로젝트: yubo/audit
int add_stop_guest_event(auparse_state_t *au)
{
	list_node_t *it;
	struct event *stop, *start = NULL, *event = NULL;
	uid_t uid;
	time_t time;
	const char *uuid, *name;
	int success;

	/* Just skip this record if it failed to get some of the fields */
	if (extract_virt_fields(au, &uuid, &uid, &time, &name, &success))
		return 0;

	/* Loop backwards to find the last start event for the uuid and
	 * update all resource records related to that guest session.
	 */
	for (it = events->tail; it; it = it->prev) {
		event = it->data;
		if (event->success && event->uuid &&
		    strcmp(uuid, event->uuid) == 0) {
			if (event->type == ET_START) {
				/* If an old session is found it's no longer
				 * necessary to update the resource records.
				 */
				if (event->end || start)
					break;
				/* This is the start event related to the
				 * current session. */
				start = event;
			} else if (event->type == ET_STOP ||
				   event->type == ET_MACHINE_ID) {
				/* Old session found. */
				break;
			} else if (event->type == ET_RES && event->end == 0) {
				/* Update the resource assignments. */
				event->end = time;
				add_proof(event, au);
			}
		}
	}
	if (start == NULL) {
		if (debug) {
			fprintf(stderr, "Couldn't find the correlated start "
					"record to the stop event.\n");
		}
		return 0;
	}

	/* Create a new stop event */
	stop = event_alloc();
	if (stop == NULL)
		return 1;
	stop->type = ET_STOP;
	stop->uuid = copy_str(uuid);
	stop->name = copy_str(name);
	stop->success = success;
	stop->uid = uid;
	stop->start = time;
	auparse_first_record(au);
	if (auparse_find_field(au, "vm-pid"))
		stop->pid = auparse_get_field_int(au);
	add_proof(stop, au);
	if (list_append(events, stop) == NULL) {
		event_free(stop);
		return 1;
	}

	/* Update the correlated start event. */
	if (success) {
		start->end = time;
		add_proof(start, au);
	}
	return 0;
}
예제 #7
0
파일: auvirt.c 프로젝트: yubo/audit
/* This function tries to correlate an anomaly record to a guest using the qemu
 * pid or the selinux context. */
int process_anom(auparse_state_t *au)
{
	uid_t uid;
	time_t time;
	pid_t pid = -1;
	list_node_t *it;
	struct event *anom, *start = NULL;

	/* An anomaly record is correlated to a guest by the process id */
	if (auparse_find_field(au, "pid")) {
		pid = auparse_get_field_int(au);
	} else {
		if (debug) {
			fprintf(stderr, "Found an anomaly record "
					"without pid.\n");
		}
	}

	/* Loop backwards to find a running guest with the same pid. */
	if (pid >= 0) {
		for (it = events->tail; it; it = it->next) {
			struct event *event = it->data;
			if (event->pid == pid && event->success) {
				if (event->type == ET_STOP) {
					break;
				} else if (event->type == ET_START) {
					if (event->end == 0)
						start = event;
					break;
				}
			}
		}
	}

	/* Try to match using selinux context */
	if (start == NULL) {
		const char *seclevel;
		struct event *machine_id;

		seclevel = get_seclevel(auparse_find_field(au, "subj"));
		if (seclevel == NULL) {
			if (debug) {
				auparse_first_record(au);
				const char *text = auparse_get_record_text(au);
				fprintf(stderr, "Security context not found "
						"for anomaly event: %s\n",
						text ? text : "");
			}
			return 0;
		}
		machine_id = get_machine_id_by_seclevel(seclevel);
		if (machine_id == NULL) {
			if (debug) {
				fprintf(stderr, "Couldn't get the security "
					"level from the anomaly event.\n");
			}
			return 0;
		}

		for (it = events->tail; it; it = it->next) {
			struct event *event = it->data;
			if (event->success && machine_id->uuid && event->uuid &&
			    strcmp(machine_id->uuid, event->uuid) == 0) {
				if (event->type == ET_STOP) {
					break;
				} else if (event->type == ET_START) {
					if (event->end == 0)
						start = event;
					break;
				}
			}
		}
	}

	if (start == NULL) {
		if (debug) {
			const char *text = auparse_get_record_text(au);
			fprintf(stderr, "Guest not found for "
					"anomaly record: %s.\n",
					text ? text : "");
		}
		return 0;
	}

	if (extract_virt_fields(au, NULL, &uid, &time, NULL, NULL))
		return 0;

	anom = event_alloc();
	if (anom == NULL)
		return 1;
	anom->type = ET_ANOM;
	anom->uuid = copy_str(start->uuid);
	anom->name = copy_str(start->name);
	anom->uid = uid;
	anom->start = time;
	anom->pid = pid;
	memcpy(anom->proof, start->proof, sizeof(anom->proof));
	add_proof(anom, au);
	if (list_append(events, anom) == NULL) {
		event_free(anom);
		return 1;
	}
	return 0;
}
예제 #8
0
/* This function will output a normalized line of audit
 * fields one line per event as an english sentence */
static void text_event(auparse_state_t *au,
		auparse_cb_event_t cb_event_type, void *user_data)
{
	if (cb_event_type != AUPARSE_CB_EVENT_READY)
		return;

	char tmp[20];
        const char *item, *action, *how;
        int rc, type, id = -2;
        time_t t = auparse_get_time(au);
        struct tm *tv = localtime(&t);

	if (tv)
		strftime(tmp, sizeof(tmp), "%T %x", tv);
	else
		strcpy(tmp, "?");
	type = auparse_get_type(au);
	auparse_normalize(au, NORM_OPT_NO_ATTRS);
	item = auparse_get_node(au);
	if (item) {
		printf("On %s at %s ", auparse_interpret_field(au), tmp);
		free((void *)item);
	} else
		printf("At %s ", tmp);

	rc = auparse_normalize_subject_primary(au);
	if (rc == 1) {
		const char *subj = auparse_interpret_field(au);
		id = auparse_get_field_int(au);
		if (strcmp(subj, "unset") == 0)
			subj = "system";
		printf("%s", subj);
	}

	// Need to compare auid and uid before doing this
	rc = auparse_normalize_subject_secondary(au);
	if (rc == 1) {
		int uid = auparse_get_field_int(au);
		if (uid != id && id != -2)
			printf(", acting as %s,", auparse_interpret_field(au));
	}

	rc = auparse_normalize_get_results(au);
	if (rc == 1) {
		int i = 0;
		const char *res[] = { "unsuccessfully", "successfully" };
		item = auparse_interpret_field(au);
		if (strcmp(item, "yes") == 0)
			i = 1;
		else if (strncmp(item, "suc", 3) == 0)
			i = 1;
		else if (auparse_get_field_type(au) == AUPARSE_TYPE_SECCOMP &&
				strcmp(item, "allow") == 0)
			i = 1;
		printf(" %s ", res[i]);
	} else
		putchar(' ');

	action = auparse_normalize_get_action(au);

	if (event_debug) {
		if (action == NULL)
			printf("error on type:%d\n", type);
	}
	printf("%s ", action ? action : "did-unknown");

	rc = auparse_normalize_object_primary(au);
	if (rc == 1) {
		const char *val = NULL;
		int ftype;

		// If we have an object and this is an AVC, add some words
		if (action && strstr(action, "violated"))
			val = "accessing ";

		ftype = auparse_get_field_type(au);
		if (ftype == AUPARSE_TYPE_ESCAPED_FILE)
			val = auparse_interpret_realpath(au);
		else if (ftype == AUPARSE_TYPE_SOCKADDR) {
			val = auparse_interpret_sock_address(au);
			if (val == NULL)
				val = auparse_interpret_sock_family(au);
		}

		if (val == NULL)
			val = auparse_interpret_field(au);

		printf("%s ", val);
	}

	rc = auparse_normalize_object_primary2(au);
	if (rc == 1) {
		const char *val;

		if (auparse_get_field_type(au) == AUPARSE_TYPE_ESCAPED_FILE)
			val = auparse_interpret_realpath(au);
		else
			val = auparse_interpret_field(au);
		printf("to %s ", val);
	}

	how = auparse_normalize_how(au);
	if (how && action && *action != 'e')   // Don't print for ended-session
		printf("using %s", how);

	printf("\n");
}
예제 #9
0
파일: exemon.c 프로젝트: FxChiP/exemon
int main(int argc, char **argv) {
	/* we're probably going to be started by auditd so, you know, whatever */
	/* set up stdin to be searched ruthlessly */

	FILE *log;
	auparse_state_t *auparse;
	uint32_t syscall;
	int auid, uid;
	int wtf;
	uint32_t _argc, i; 
	const char *exe, *path, *success;
	char *cmdline, *tmp_cmd; 
	char _argv[8];
	struct passwd *au, *u;
	char *real_user, *apparent_user; 

	_argc = 0;
	cmdline = NULL;

	log = fopen("/tmp/exemon.log", "w");

/*	auparse = auparse_init(AUSOURCE_LOGS, NULL); */
	auparse = auparse_init(AUSOURCE_FILE_POINTER, stdin); 

	if (!auparse) {
		fprintf(log, "Couldn't do the thing with the thing.\n");
		exit(1);
	}

	while ((wtf = auparse_next_event(auparse)) > 0) {
		/* Start fresh */
		auid = -1;
		uid = -1;
		exe = NULL;
		path = NULL;
		success = NULL;
		_argc = 0;
		if (cmdline) free(cmdline);
		cmdline = NULL;

		/* Now we're doing the thing */
/*		auparse_first_field(auparse); */
/*		auparse_first_record(auparse); */
		auparse_first_field(auparse);
		if (auparse_find_field(auparse, "syscall")) {
			syscall = auparse_get_field_int(auparse);
			if (syscall == 59 || syscall == 11) {
				if (auparse_exhaustive_find_field(auparse, "auid")) {
					auid = auparse_get_field_int(auparse);
					au = getpwuid(auid);
					if (au) real_user = strdup(au->pw_name);
					else asprintf(&real_user, "UID_%i", auid);
					au = NULL;
				}

				if (auparse_exhaustive_find_field(auparse, "uid")) {
					uid = auparse_get_field_int(auparse);
					u = getpwuid(uid);
					if (u) apparent_user = strdup(u->pw_name);
					else asprintf(&apparent_user, "UID_%i", uid);
					u = NULL;
				}

				if (auparse_exhaustive_find_field(auparse, "success"))
					success = auparse_get_field_str(auparse);

				if (auparse_exhaustive_find_field(auparse, "exe"))
					exe = auparse_get_field_str(auparse);

				if (auparse_exhaustive_find_field(auparse, "argc")) {
					_argc = auparse_get_field_int(auparse);
					for (i = 0; i < _argc; i++) {
						snprintf(_argv, 8, "a%i", i);
						if (auparse_find_field(auparse, _argv)) {
							if (!cmdline) asprintf(&cmdline, "%s", auparse_interpret_field(auparse));
							else {
								asprintf(&tmp_cmd, "%s %s", cmdline, auparse_interpret_field(auparse));
								free(cmdline); /* avoid leaking cmdline */
								cmdline = tmp_cmd;
							}
						}
					}
				}

				if (auparse_exhaustive_find_field(auparse, "cwd"))
					path = auparse_get_field_str(auparse);
				else path = strdup("(unknown)");

				if (exe && uid >= 0 && path && success) {
					if (auid == uid || auid == -1) {
						if (cmdline && (success[0] == 'y' || success[0] == 'Y')) {
							fprintf(log, "%s ran %s in path %s with args: %s\n", apparent_user, exe, path, cmdline);
						} else {
							fprintf(log, "%s failed to run %s in path %s\n", apparent_user, exe, path); 
							if (!cmdline) { fprintf(log, "note: no cmdline: record: \n"); auparse_dump_records(auparse, log); }
						}
					} else {
						if (cmdline && (success[0] == 'y' || success[0] == 'Y')) {
							fprintf(log, "%s (as %s) ran %s in path %s with args: %s\n", real_user, apparent_user, exe, path, cmdline);
						} else {
							fprintf(log, "%s (as %s) failed to run %s in path %s\n", real_user, apparent_user, exe, path);
						}
					}
				} else {
					fprintf(log, "Incomplete record? path = %x, success = %x, uid = %i, exe = %x\n", path, success, uid, exe);
					fprintf(log, "record:\n");
					auparse_dump_records(auparse, log);
				}
				fflush(log);

				/* avoid leaking on usernames and unknown paths */
				free(apparent_user);
				free(real_user);
				if (path[0] == '(') { free(path); path = NULL; }
				apparent_user = NULL;
				real_user = NULL;
			}
		}
	}

	fprintf(log, "destroyed\n");
	fclose(log); 

	auparse_destroy(auparse);

	return 0;
}