示例#1
0
static void signal_plugins(int sig)
{
	lnode *conf;

	plist_first(&plugin_conf);
	conf = plist_get_cur(&plugin_conf);
	while (conf) {
		if (conf->p && conf->p->pid)
			kill(conf->p->pid, sig);
		conf = plist_next(&plugin_conf);
	}
}
示例#2
0
static int start_plugins(conf_llist *plugin)
{
	/* spawn children */
	lnode *conf;
	int active = 0;

	plist_first(plugin);
	conf = plist_get_cur(plugin);
	if (conf == NULL || conf->p == NULL)
		return active;

	do {
		if (conf->p && conf->p->active == A_YES) {
			if (start_one_plugin(conf))
				active++;
		}
	} while ((conf = plist_next(plugin)));
	return active;
}
示例#3
0
/*
 * SIGCHLD handler
 */
static void child_handler( int sig )
{
	int status;
	pid_t pid;
	
	pid = waitpid(-1, &status, WNOHANG);
	if (pid > 0) {
		// Mark the child pid as 0 in the configs
		lnode *tpconf;
		plist_first(&plugin_conf);
		tpconf = plist_get_cur(&plugin_conf);
		while (tpconf) {
			if (tpconf->p && tpconf->p->pid == pid) {
				tpconf->p->pid = 0;
				break;
			}
			tpconf = plist_next(&plugin_conf);
		}
	}
}
示例#4
0
/* Move to the next file depending on the options set, the user
 * request and whether or not there are files in the queue. */
static void go_to_another_file ()
{
	int shuffle = options_get_int ("Shuffle");
	int go_next = (play_next || options_get_int("AutoNext"));
	int curr_playing_curr_pos;
	/* XXX: Shouldn't play_next be protected by mutex? */

	LOCK (curr_playing_mut);
	LOCK (plist_mut);

	/* If we move forward in the playlist and there are some songs in
	 * the queue, then play them. */
	if (plist_count(&queue) && go_next) {
		logit ("Playing file from queue");

		if (!before_queue_fname && curr_playing_fname)
			before_queue_fname = xstrdup (curr_playing_fname);

		curr_plist = &queue;
		curr_playing = plist_next (&queue, -1);

		server_queue_pop (queue.items[curr_playing].file);
		plist_delete (&queue, curr_playing);
	}
	else {
		/* If we just finished playing files from the queue and the
		 * appropriate option is set, continue with the file played
		 * before playing the queue. */
		if (before_queue_fname && options_get_int("QueueNextSongReturn")) {
			free (curr_playing_fname);
			curr_playing_fname = before_queue_fname;
			before_queue_fname = NULL;
		}

		if (shuffle) {
			curr_plist = &shuffled_plist;

			if (plist_count(&playlist)
					&& !plist_count(&shuffled_plist)) {
				plist_cat (&shuffled_plist, &playlist);
				plist_shuffle (&shuffled_plist);

				if (curr_playing_fname)
					plist_swap_first_fname (&shuffled_plist,
							curr_playing_fname);
			}
		}
		else
			curr_plist = &playlist;

		curr_playing_curr_pos = plist_find_fname (curr_plist,
				curr_playing_fname);

		/* If we came from the queue and the last file in
		 * queue wasn't in the playlist, we try to revert to
		 * the QueueNextSongReturn = 1 behaviour. */
		if (curr_playing_curr_pos == -1 && before_queue_fname) {
			curr_playing_curr_pos = plist_find_fname (curr_plist,
					before_queue_fname);
		}

		if (play_prev && plist_count(curr_plist)) {
			logit ("Playing previous...");

			if (curr_playing_curr_pos == -1
					|| started_playing_in_queue) {
				curr_playing = plist_prev (curr_plist, -1);
				started_playing_in_queue = 0;
			}
			else
				curr_playing = plist_prev (curr_plist,
						curr_playing_curr_pos);

			if (curr_playing == -1) {
				if (options_get_int("Repeat"))
					curr_playing = plist_last (curr_plist);
				logit ("Beginning of the list.");
			}
			else
				logit ("Previous item.");
		}
		else if (go_next && plist_count(curr_plist)) {
			logit ("Playing next...");

			if (curr_playing_curr_pos == -1
					|| started_playing_in_queue) {
				curr_playing = plist_next (curr_plist, -1);
				started_playing_in_queue = 0;
			}
			else
				curr_playing = plist_next (curr_plist,
						curr_playing_curr_pos);

			if (curr_playing == -1 && options_get_int("Repeat")) {
				if (shuffle) {
					plist_clear (&shuffled_plist);
					plist_cat (&shuffled_plist, &playlist);
					plist_shuffle (&shuffled_plist);
				}
				curr_playing = plist_next (curr_plist, -1);
				logit ("Going back to the first item.");
			}
			else if (curr_playing == -1)
				logit ("End of the list");
			else
				logit ("Next item");

		}
		else if (!options_get_int("Repeat")) {
			curr_playing = -1;
		}
		else
			debug ("Repeating file");

		if (before_queue_fname)
			free (before_queue_fname);
		before_queue_fname = NULL;
	}

	UNLOCK (plist_mut);
	UNLOCK (curr_playing_mut);
}
示例#5
0
/* Returns 0 on stop, and 1 on HUP */
static int event_loop(void)
{
	char *name = NULL, tmp_name[255];

	/* Get the host name representation */
	switch (daemon_config.node_name_format)
	{
		case N_NONE:
			break;
		case N_HOSTNAME:
			if (gethostname(tmp_name, sizeof(tmp_name))) {
				syslog(LOG_ERR, "Unable to get machine name");
				name = strdup("?");
			} else
				name = strdup(tmp_name);
			break;
		case N_USER:
			if (daemon_config.name)
				name = strdup(daemon_config.name);
			else {
				syslog(LOG_ERR, "User defined name missing");
				name = strdup("?");
			}
			break;
		case N_FQD:
			if (gethostname(tmp_name, sizeof(tmp_name))) {
				syslog(LOG_ERR, "Unable to get machine name");
				name = strdup("?");
			} else {
				int rc;
				struct addrinfo *ai;
				struct addrinfo hints;

				memset(&hints, 0, sizeof(hints));
				hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
				hints.ai_socktype = SOCK_STREAM;

				rc = getaddrinfo(tmp_name, NULL, &hints, &ai);
				if (rc != 0) {
					syslog(LOG_ERR,
					"Cannot resolve hostname %s (%s)",
					tmp_name, gai_strerror(rc));
					name = strdup("?");
					break;
				}
				name = strdup(ai->ai_canonname);
				freeaddrinfo(ai);
			}
			break;
		case N_NUMERIC:
			if (gethostname(tmp_name, sizeof(tmp_name))) {
				syslog(LOG_ERR, "Unable to get machine name");
				name = strdup("?");
			} else {
				int rc;
				struct addrinfo *ai;
				struct addrinfo hints;

				memset(&hints, 0, sizeof(hints));
				hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
				hints.ai_socktype = SOCK_STREAM;

				rc = getaddrinfo(tmp_name, NULL, &hints, &ai);
				if (rc != 0) {
					syslog(LOG_ERR,
					"Cannot resolve hostname %s (%s)",
					tmp_name, gai_strerror(rc));
					name = strdup("?");
					break;
				}
				inet_ntop(ai->ai_family,
						ai->ai_family == AF_INET ?
		(void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr :
		(void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
						tmp_name, INET6_ADDRSTRLEN);
				freeaddrinfo(ai);
				name = strdup(tmp_name);
			}
			break;
	}

	/* Figure out the format for the af_unix socket */
	while (stop == 0) {
		event_t *e;
		const char *type;
		char *v, *ptr, unknown[32];
		unsigned int len;
		lnode *conf;

		/* This is where we block until we have an event */
		e = dequeue();
		if (e == NULL) {
			if (hup) {
				free(name);
				return 1;
			}
			continue;
		}

		/* Get the event formatted */
		type = audit_msg_type_to_name(e->hdr.type);
		if (type == NULL) {
			snprintf(unknown, sizeof(unknown),
				"UNKNOWN[%d]", e->hdr.type);
			type = unknown;
		}

		if (daemon_config.node_name_format != N_NONE) {
			len = asprintf(&v, "node=%s type=%s msg=%.*s\n", 
				name, type, e->hdr.size, e->data);
		} else
			len = asprintf(&v, "type=%s msg=%.*s\n", 
				type, e->hdr.size, e->data);
		if (len <= 0) {
			free(e); /* Either corrupted event or no memory */
			continue;
		}

		/* Strip newlines from event record */
		ptr = v;
		while ((ptr = strchr(ptr, 0x0A)) != NULL) {
			if (ptr != &v[len-1])
				*ptr = ' ';
			else
				break; /* Done - exit loop */
		}

		/* Distribute event to the plugins */
		plist_first(&plugin_conf);
		conf = plist_get_cur(&plugin_conf);
		do {
			if (conf == NULL || conf->p == NULL)
				continue;
			if (conf->p->active == A_NO)
				continue;

			/* Now send the event to the right child */
			if (conf->p->type == S_SYSLOG) 
				send_syslog(v);
			else if (conf->p->type == S_AF_UNIX) {
				if (conf->p->format == F_STRING)
					send_af_unix_string(v, len);
				else
					send_af_unix_binary(e);
			} else if (conf->p->type == S_ALWAYS) {
				int rc;
				rc = write_to_plugin(e, v, len, conf);
				if (rc < 0 && errno == EPIPE) {
					/* Child disappeared ? */
					syslog(LOG_ERR,
					"plugin %s terminated unexpectedly", 
								conf->p->path);
					conf->p->pid = 0;
					conf->p->restart_cnt++;
					if (conf->p->restart_cnt >
						daemon_config.max_restarts) {
						syslog(LOG_ERR,
					"plugin %s has exceeded max_restarts",
								conf->p->path);
					}
					close(conf->p->plug_pipe[1]);
					conf->p->plug_pipe[1] = -1;
					conf->p->active = A_NO;
					if (start_one_plugin(conf)) {
						rc = write_to_plugin(e, v, len,
								     conf);
						syslog(LOG_NOTICE,
						"plugin %s was restarted",
							conf->p->path);
						conf->p->active = A_YES;
					} 
				}
			}
		} while ((conf = plist_next(&plugin_conf)));

		/* Done with the memory...release it */
		free(v);
		free(e);
		if (hup)
			break;
	}
	free(name);
	if (stop)
		return 0;
	else
		return 1;
}
示例#6
0
int main(int argc, char *argv[])
{
	lnode *conf;
	struct sigaction sa;
	int i;

#ifndef DEBUG
	/* Make sure we are root */
	if (getuid() != 0) {
		fprintf(stderr, "You must be root to run this program.\n");
		return 4;
	}
#endif
	set_aumessage_mode(MSG_SYSLOG, DBG_YES);

	/* Register sighandlers */
	sa.sa_flags = 0;
	sigemptyset(&sa.sa_mask);
	/* Ignore all signals by default */
	sa.sa_handler = SIG_IGN;
	for (i=1; i<NSIG; i++)
		sigaction(i, &sa, NULL);
	/* Set handler for the ones we care about */
	sa.sa_handler = term_handler;
	sigaction(SIGTERM, &sa, NULL);
	sa.sa_handler = hup_handler;
	sigaction(SIGHUP, &sa, NULL);
	sa.sa_handler = alarm_handler;
	sigaction(SIGALRM, &sa, NULL);
	sa.sa_handler = child_handler;
	sigaction(SIGCHLD, &sa, NULL);

	/* move stdin to its own fd */
	if (argc == 3 && strcmp(argv[1], "--input") == 0) 
		audit_fd = open(argv[2], O_RDONLY);
	else
		audit_fd = dup(0);
	if (audit_fd < 0) {
		syslog(LOG_ERR, "Failed setting up input, exiting");
		return 1;
	}

	/* Make all descriptors point to dev null */
	i = open("/dev/null", O_RDWR);
	if (i >= 0) {
		if (dup2(0, i) < 0 || dup2(1, i) < 0 || dup2(2, i) < 0) {
			syslog(LOG_ERR, "Failed duping /dev/null %s, exiting",
					strerror(errno));
			return 1;
		}
		close(i);
	} else {
		syslog(LOG_ERR, "Failed opening /dev/null %s, exiting",
					strerror(errno));
		return 1;
	}
	if (fcntl(audit_fd, F_SETFD, FD_CLOEXEC) < 0) {
		syslog(LOG_ERR, "Failed protecting input %s, exiting",
					strerror(errno));
		return 1;
	}

	/* init the daemon's config */
	if (load_config(&daemon_config, config_file))
		return 6;

	load_plugin_conf(&plugin_conf);

	/* if no plugins - exit */
	if (plist_count(&plugin_conf) == 0) {
		syslog(LOG_ERR, "No plugins found, exiting");
		return 0;
	}

	/* Plugins are started with the auditd priority */
	i = start_plugins(&plugin_conf);

	/* Now boost priority to make sure we are getting time slices */
	if (daemon_config.priority_boost != 0) {
		errno = 0;
		(void) nice((int)-daemon_config.priority_boost);
		if (errno) {
			syslog(LOG_ERR, "Cannot change priority (%s)",
					strerror(errno));
			/* Stay alive as this is better than stopping */
		}
	}

	/* Let the queue initialize */
	init_queue(daemon_config.q_depth);
	syslog(LOG_NOTICE, 
		"audispd initialized with q_depth=%d and %d active plugins",
		daemon_config.q_depth, i);

	/* Tell it to poll the audit fd */
	if (add_event(audit_fd, process_inbound_event) < 0) {
		syslog(LOG_ERR, "Cannot add event, exiting");
		return 1;
	}

	/* Create inbound thread */
	pthread_create(&inbound_thread, NULL, inbound_thread_main, NULL); 

	/* Start event loop */
	while (event_loop()) {
		hup = 0;
		reconfigure();
	}

	/* Tell plugins we are going down */
	signal_plugins(SIGTERM);

	/* Cleanup builtin plugins */
	destroy_af_unix();
	destroy_syslog();

	/* Give it 5 seconds to clear the queue */
	alarm(5);
	pthread_join(inbound_thread, NULL);

	/* Release configs */
	plist_first(&plugin_conf);
	conf = plist_get_cur(&plugin_conf);
	while (conf) {
		free_pconfig(conf->p);
		conf = plist_next(&plugin_conf);
	}
	plist_clear(&plugin_conf);

	/* Cleanup the queue */
	destroy_queue();
	free_config(&daemon_config);
	
	return 0;
}
示例#7
0
static void reconfigure(void)
{
	int rc;
	daemon_conf_t tdc;
	conf_llist tmp_plugin;
	lnode *tpconf;

	/* Read new daemon config */
	rc = load_config(&tdc, config_file);
	if (rc == 0) {
		if (tdc.q_depth > daemon_config.q_depth) {
			increase_queue_depth(tdc.q_depth);
			daemon_config.q_depth = tdc.q_depth;
		}
		daemon_config.overflow_action = tdc.overflow_action;
		reset_suspended();
		/* We just fill these in because they are used by this
		 * same thread when we return
		 */
		daemon_config.node_name_format = tdc.node_name_format;
		free((char *)daemon_config.name);
		daemon_config.name = tdc.name;
	}

	/* The idea for handling SIGHUP to children goes like this:
	 * 1) load the current config in temp list
	 * 2) mark all in real list unchecked
	 * 3) for each one in tmp list, scan old list
	 * 4) if new, start it, append to list, mark done
	 * 5) else check if there was a change to active state
	 * 6) if so, copy config over and start
	 * 7) If no change, send sighup to non-builtins and mark done
	 * 8) Finally, scan real list for unchecked, terminate and deactivate
	 */
	load_plugin_conf(&tmp_plugin);
	plist_mark_all_unchecked(&plugin_conf);

	plist_first(&tmp_plugin);
	tpconf = plist_get_cur(&tmp_plugin);
	while (tpconf && tpconf->p) {
		lnode *opconf;
		
		opconf = plist_find_name(&plugin_conf, tpconf->p->name);
		if (opconf == NULL) {
			/* We have a new service */
			if (tpconf->p->active == A_YES) {
				tpconf->p->checked = 1;
				plist_last(&plugin_conf);
				plist_append(&plugin_conf, tpconf->p);
				free(tpconf->p);
				tpconf->p = NULL;
				start_one_plugin(plist_get_cur(&plugin_conf));
			}
		} else {
			if (opconf->p->active == tpconf->p->active) {
				if (opconf->p->type == S_ALWAYS)
					kill(opconf->p->pid, SIGHUP);
				opconf->p->checked = 1;
			} else {
				/* A change in state */
				if (tpconf->p->active == A_YES) {
					/* starting - copy config and exec */
					free_pconfig(opconf->p);
					free(opconf->p);
					opconf->p = tpconf->p;
					opconf->p->checked = 1;
					start_one_plugin(opconf);
					tpconf->p = NULL;
				}
			}
		}

		tpconf = plist_next(&tmp_plugin);
	}

	/* Now see what's left over */
	while ( (tpconf = plist_find_unchecked(&plugin_conf)) ) {
		/* Anything not checked is something removed from the config */
		tpconf->p->active = A_NO;
		kill(tpconf->p->pid, SIGTERM);
		tpconf->p->pid = 0;
		tpconf->p->checked = 1;
	}
	
	/* Release memory from temp config */
	plist_first(&tmp_plugin);
	tpconf = plist_get_cur(&tmp_plugin);
	while (tpconf) {
		free_pconfig(tpconf->p);
		tpconf = plist_next(&tmp_plugin);
	}
	plist_clear(&tmp_plugin);
}