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 50static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data); 51 52static const char *PATH="/org/selinux/Restorecond"; 53//static const char *BUSNAME="org.selinux.Restorecond"; 54static const char *INTERFACE="org.selinux.RestorecondIface"; 55static const char *RULE="type='signal',interface='org.selinux.RestorecondIface'"; 56 57static int local_lock_fd = -1; 58 59static DBusHandlerResult 60signal_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 84static 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 109static gboolean 110io_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 168int 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 197static 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 231static void end_local_server(void) { 232 if (local_lock_fd >= 0) 233 close(local_lock_fd); 234 local_lock_fd = -1; 235} 236 237int 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 263end: 264 end_local_server(); 265 g_main_loop_unref (loop); 266 return 0; 267} 268 269