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 #define _GNU_SOURCE
28 #include <sys/inotify.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <syslog.h>
39 #include <limits.h>
40 #include <fcntl.h>
41
42 #include "restorecond.h"
43 #include "stringslist.h"
44 #include <glib.h>
45 #ifdef HAVE_DBUS
46 #include <dbus/dbus.h>
47 #include <dbus/dbus-glib.h>
48 #include <dbus/dbus-glib-lowlevel.h>
49
50 static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data);
51
52 static const char *PATH="/org/selinux/Restorecond";
53 //static const char *BUSNAME="org.selinux.Restorecond";
54 static const char *INTERFACE="org.selinux.RestorecondIface";
55 static const char *RULE="type='signal',interface='org.selinux.RestorecondIface'";
56
57 static int local_lock_fd = -1;
58
59 static DBusHandlerResult
signal_filter(DBusConnection * connection,DBusMessage * message,void * user_data)60 signal_filter (DBusConnection *connection __attribute__ ((__unused__)), DBusMessage *message, void *user_data)
61 {
62 /* User data is the event loop we are running in */
63 GMainLoop *loop = user_data;
64
65 /* A signal from the bus saying we are about to be disconnected */
66 if (dbus_message_is_signal
67 (message, INTERFACE, "Stop")) {
68
69 /* Tell the main loop to quit */
70 g_main_loop_quit (loop);
71 /* We have handled this message, don't pass it on */
72 return DBUS_HANDLER_RESULT_HANDLED;
73 }
74 /* A Ping signal on the com.burtonini.dbus.Signal interface */
75 else if (dbus_message_is_signal (message, INTERFACE, "Start")) {
76 DBusError error;
77 dbus_error_init (&error);
78 g_print("Start received\n");
79 return DBUS_HANDLER_RESULT_HANDLED;
80 }
81 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
82 }
83
dbus_server(GMainLoop * loop)84 static int dbus_server(GMainLoop *loop) {
85 DBusConnection *bus;
86 DBusError error;
87 dbus_error_init (&error);
88 bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
89 if (bus) {
90 dbus_connection_setup_with_g_main (bus, NULL);
91
92 /* listening to messages from all objects as no path is specified */
93 dbus_bus_add_match (bus, RULE, &error); // see signals from the given interfacey
94 dbus_connection_add_filter (bus, signal_filter, loop, NULL);
95 return 0;
96 }
97 return -1;
98 }
99
100 #endif
101 #include <selinux/selinux.h>
102 #include <sys/file.h>
103
104 /* size of the event structure, not counting name */
105 #define EVENT_SIZE (sizeof (struct inotify_event))
106 /* reasonable guess as to size of 1024 events */
107 #define BUF_LEN (1024 * (EVENT_SIZE + 16))
108
109 static gboolean
io_channel_callback(GIOChannel * source,GIOCondition condition,gpointer data)110 io_channel_callback
111 (GIOChannel *source,
112 GIOCondition condition,
113 gpointer data __attribute__((__unused__)))
114 {
115
116 char buffer[BUF_LEN+1];
117 gsize bytes_read;
118 unsigned int i = 0;
119
120 if (condition & G_IO_IN) {
121 /* Data is available. */
122 g_io_channel_read_chars
123 (source, buffer,
124 sizeof (buffer),
125 &bytes_read, NULL);
126
127 if (! bytes_read) {
128 /* Sesssion/Terminal Ended */
129 exit(0);
130 }
131
132 while (i < bytes_read) {
133 struct inotify_event *event;
134 event = (struct inotify_event *)&buffer[i];
135 if (debug_mode)
136 printf("wd=%d mask=%u cookie=%u len=%u\n",
137 event->wd, event->mask,
138 event->cookie, event->len);
139 if (event->len)
140 watch_list_find(event->wd, event->name);
141
142 i += EVENT_SIZE + event->len;
143 }
144 }
145
146 /* An error happened while reading
147 the file. */
148
149 if (condition & G_IO_NVAL)
150 return FALSE;
151
152 /* We have reached the end of the
153 file. */
154
155 if (condition & G_IO_HUP) {
156 g_io_channel_shutdown (source, 0, NULL);
157 exit(0);
158 return FALSE;
159 }
160
161 /* Returning TRUE will make sure
162 the callback remains associated
163 to the channel. */
164
165 return TRUE;
166 }
167
start()168 int start() {
169 #ifdef HAVE_DBUS
170 DBusConnection *bus;
171 DBusError error;
172 DBusMessage *message;
173
174 /* Get a connection to the session bus */
175 dbus_error_init (&error);
176 bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
177 if (!bus) {
178 if (debug_mode)
179 g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
180 dbus_error_free (&error);
181 return 1;
182 }
183
184
185 /* Create a new signal "Start" on the interface,
186 * from the object */
187 message = dbus_message_new_signal (PATH,
188 INTERFACE, "Start");
189 /* Send the signal */
190 dbus_connection_send (bus, message, NULL);
191 /* Free the signal now we have finished with it */
192 dbus_message_unref (message);
193 #endif /* HAVE_DBUS */
194 return 0;
195 }
196
local_server(void)197 static int local_server(void) {
198 // ! dbus, run as local service
199 char *ptr=NULL;
200 if (asprintf(&ptr, "%s/.restorecond", homedir) < 0) {
201 if (debug_mode)
202 perror("asprintf");
203 return -1;
204 }
205 local_lock_fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR);
206 if (debug_mode)
207 g_warning ("Lock file: %s", ptr);
208
209 free(ptr);
210 if (local_lock_fd < 0) {
211 if (debug_mode)
212 perror("open");
213 return -1;
214 }
215 if (flock(local_lock_fd, LOCK_EX | LOCK_NB) < 0) {
216 close(local_lock_fd);
217 if (debug_mode)
218 perror("flock");
219 return -1;
220 }
221 /* watch for stdin/terminal going away */
222 GIOChannel *in = g_io_channel_unix_new(0);
223 g_io_add_watch_full( in,
224 G_PRIORITY_HIGH,
225 G_IO_IN|G_IO_ERR|G_IO_HUP,
226 io_channel_callback, NULL, NULL);
227
228 return 0;
229 }
230
end_local_server(void)231 static void end_local_server(void) {
232 if (local_lock_fd >= 0)
233 close(local_lock_fd);
234 local_lock_fd = -1;
235 }
236
server(int master_fd,const char * watch_file)237 int server(int master_fd, const char *watch_file) {
238 GMainLoop *loop;
239
240 loop = g_main_loop_new (NULL, FALSE);
241
242 #ifdef HAVE_DBUS
243 if (dbus_server(loop) != 0)
244 #endif /* HAVE_DBUS */
245 if (local_server())
246 goto end;
247
248 read_config(master_fd, watch_file);
249
250 if (watch_list_isempty()) goto end;
251
252 set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
253
254 GIOChannel *c = g_io_channel_unix_new(master_fd);
255
256 g_io_add_watch_full( c,
257 G_PRIORITY_HIGH,
258 G_IO_IN|G_IO_ERR|G_IO_HUP,
259 io_channel_callback, NULL, NULL);
260
261 g_main_loop_run (loop);
262
263 end:
264 end_local_server();
265 g_main_loop_unref (loop);
266 return 0;
267 }
268
269