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 (at) 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 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 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 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 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 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 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 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