1/*
2 * restorecond
3 *
4 * Copyright (C) 2006-2009 Red Hat
5 * see file 'COPYING' for use and warranty information
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16.*
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 * 02111-1307  USA
21 *
22 * Authors:
23 *   Dan Walsh <dwalsh@redhat.com>
24 *
25*/
26
27/*
28 * PURPOSE:
29 * This daemon program watches for the creation of files listed in a config file
30 * and makes sure that there security context matches the systems defaults
31 *
32 * USAGE:
33 * restorecond [-d] [-u] [-v] [-f restorecond_file ]
34 *
35 * -d   Run in debug mode
36 * -f   Use alternative restorecond_file
37 * -u   Run in user mode
38 * -v   Run in verbose mode (Report missing files)
39 *
40 * EXAMPLE USAGE:
41 * restorecond
42 *
43 */
44
45#define _GNU_SOURCE
46#include <sys/inotify.h>
47#include <errno.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <signal.h>
51#include <string.h>
52#include <unistd.h>
53#include "../setfiles/restore.h"
54#include <sys/types.h>
55#include <syslog.h>
56#include <limits.h>
57#include <pwd.h>
58#include <sys/stat.h>
59#include <string.h>
60#include <stdio.h>
61#include <fcntl.h>
62#include "restorecond.h"
63#include "utmpwatcher.h"
64
65const char *homedir;
66static int master_fd = -1;
67
68static const char *server_watch_file  = "/etc/selinux/restorecond.conf";
69static const char *user_watch_file  = "/etc/selinux/restorecond_user.conf";
70static const char *watch_file;
71static struct restore_opts r_opts;
72
73#include <selinux/selinux.h>
74
75int debug_mode = 0;
76int terminate = 0;
77int master_wd = -1;
78int run_as_user = 0;
79
80static void done(void) {
81	watch_list_free(master_fd);
82	close(master_fd);
83	utmpwatcher_free();
84	matchpathcon_fini();
85}
86
87static const char *pidfile = "/var/run/restorecond.pid";
88
89static int write_pid_file(void)
90{
91	int pidfd, len;
92	char val[16];
93
94	len = snprintf(val, sizeof(val), "%u\n", getpid());
95	if (len < 0) {
96		syslog(LOG_ERR, "Pid error (%s)", strerror(errno));
97		pidfile = 0;
98		return 1;
99	}
100	pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644);
101	if (pidfd < 0) {
102		syslog(LOG_ERR, "Unable to set pidfile (%s)", strerror(errno));
103		pidfile = 0;
104		return 1;
105	}
106	(void)write(pidfd, val, (unsigned int)len);
107	close(pidfd);
108	return 0;
109}
110
111/*
112 * SIGTERM handler
113 */
114static void term_handler(int s __attribute__ ((unused)))
115{
116	terminate = 1;
117	/* trigger a failure in the watch */
118	close(master_fd);
119}
120
121static void usage(char *program)
122{
123	printf("%s [-d] [-f restorecond_file ] [-u] [-v] \n", program);
124}
125
126void exitApp(const char *msg)
127{
128	perror(msg);
129	exit(-1);
130}
131
132/*
133   Add a file to the watch list.  We are watching for file creation, so we actually
134   put the watch on the directory and then examine all files created in that directory
135   to see if it is one that we are watching.
136*/
137
138int main(int argc, char **argv)
139{
140	int opt;
141	struct sigaction sa;
142
143	memset(&r_opts, 0, sizeof(r_opts));
144
145	r_opts.progress = 0;
146	r_opts.count = 0;
147	r_opts.debug = 0;
148	r_opts.change = 1;
149	r_opts.verbose = 0;
150	r_opts.logging = 0;
151	r_opts.rootpath = NULL;
152	r_opts.rootpathlen = 0;
153	r_opts.outfile = NULL;
154	r_opts.force = 0;
155	r_opts.hard_links = 0;
156	r_opts.abort_on_error = 0;
157	r_opts.add_assoc = 0;
158	r_opts.expand_realpath = 0;
159	r_opts.fts_flags = FTS_PHYSICAL;
160	r_opts.selabel_opt_validate = NULL;
161	r_opts.selabel_opt_path = NULL;
162	r_opts.ignore_enoent = 1;
163
164	restore_init(&r_opts);
165	/* If we are not running SELinux then just exit */
166	if (is_selinux_enabled() != 1) return 0;
167
168	/* Register sighandlers */
169	sa.sa_flags = 0;
170	sa.sa_handler = term_handler;
171	sigemptyset(&sa.sa_mask);
172	sigaction(SIGTERM, &sa, NULL);
173
174	set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
175
176	exclude_non_seclabel_mounts();
177	atexit( done );
178	while ((opt = getopt(argc, argv, "hdf:uv")) > 0) {
179		switch (opt) {
180		case 'd':
181			debug_mode = 1;
182			break;
183		case 'f':
184			watch_file = optarg;
185			break;
186		case 'u':
187			run_as_user = 1;
188			break;
189		case 'h':
190			usage(argv[0]);
191			exit(0);
192			break;
193		case 'v':
194			r_opts.verbose++;
195			break;
196		case '?':
197			usage(argv[0]);
198			exit(-1);
199		}
200	}
201
202	master_fd = inotify_init();
203	if (master_fd < 0)
204		exitApp("inotify_init");
205
206	uid_t uid = getuid();
207	struct passwd *pwd = getpwuid(uid);
208	if (!pwd)
209		exitApp("getpwuid");
210
211	homedir = pwd->pw_dir;
212	if (uid != 0) {
213		if (run_as_user)
214			return server(master_fd, user_watch_file);
215		if (start() != 0)
216			return server(master_fd, user_watch_file);
217		return 0;
218	}
219
220	watch_file = server_watch_file;
221	read_config(master_fd, watch_file);
222
223	if (!debug_mode)
224		daemon(0, 0);
225
226	write_pid_file();
227
228	while (watch(master_fd, watch_file) == 0) {
229	};
230
231	watch_list_free(master_fd);
232	close(master_fd);
233	matchpathcon_fini();
234	if (pidfile)
235		unlink(pidfile);
236
237	return 0;
238}
239