Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 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 | |
Dan Walsh | f2051b2 | 2013-10-09 17:37:42 -0400 | [diff] [blame] | 57 | static int local_lock_fd = -1; |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 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. */ |
Dan Walsh | 1376042 | 2012-01-24 11:24:37 -0500 | [diff] [blame] | 122 | g_io_channel_read_chars |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 123 | (source, buffer, |
| 124 | sizeof (buffer), |
Dan Walsh | 1376042 | 2012-01-24 11:24:37 -0500 | [diff] [blame] | 125 | &bytes_read, NULL); |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 126 | |
Dan Walsh | 4a145b7 | 2011-10-06 16:05:03 -0400 | [diff] [blame] | 127 | if (! bytes_read) { |
| 128 | /* Sesssion/Terminal Ended */ |
| 129 | exit(0); |
| 130 | } |
| 131 | |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 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) { |
Dan Walsh | 1376042 | 2012-01-24 11:24:37 -0500 | [diff] [blame] | 156 | g_io_channel_shutdown (source, 0, NULL); |
Dan Walsh | 4a145b7 | 2011-10-06 16:05:03 -0400 | [diff] [blame] | 157 | exit(0); |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 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 | |
Nicolas Iooss | c4a4a1a | 2014-09-14 23:41:49 +0200 | [diff] [blame] | 197 | static int local_server(void) { |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 198 | // ! dbus, run as local service |
| 199 | char *ptr=NULL; |
Dan Walsh | 9961ca6 | 2011-08-09 09:58:53 -0400 | [diff] [blame] | 200 | if (asprintf(&ptr, "%s/.restorecond", homedir) < 0) { |
| 201 | if (debug_mode) |
| 202 | perror("asprintf"); |
| 203 | return -1; |
| 204 | } |
Dan Walsh | f2051b2 | 2013-10-09 17:37:42 -0400 | [diff] [blame] | 205 | local_lock_fd = open(ptr, O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, S_IRUSR | S_IWUSR); |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 206 | if (debug_mode) |
| 207 | g_warning ("Lock file: %s", ptr); |
| 208 | |
| 209 | free(ptr); |
Dan Walsh | f2051b2 | 2013-10-09 17:37:42 -0400 | [diff] [blame] | 210 | if (local_lock_fd < 0) { |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 211 | if (debug_mode) |
| 212 | perror("open"); |
| 213 | return -1; |
| 214 | } |
Dan Walsh | f2051b2 | 2013-10-09 17:37:42 -0400 | [diff] [blame] | 215 | if (flock(local_lock_fd, LOCK_EX | LOCK_NB) < 0) { |
| 216 | close(local_lock_fd); |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 217 | if (debug_mode) |
| 218 | perror("flock"); |
| 219 | return -1; |
| 220 | } |
Dan Walsh | 4a145b7 | 2011-10-06 16:05:03 -0400 | [diff] [blame] | 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 | |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 228 | return 0; |
| 229 | } |
| 230 | |
Dan Walsh | f2051b2 | 2013-10-09 17:37:42 -0400 | [diff] [blame] | 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 | |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 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 */ |
Dan Walsh | 4a145b7 | 2011-10-06 16:05:03 -0400 | [diff] [blame] | 245 | if (local_server()) |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 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: |
Dan Walsh | f2051b2 | 2013-10-09 17:37:42 -0400 | [diff] [blame] | 264 | end_local_server(); |
Eric Paris | 48681bb | 2011-08-03 11:40:47 -0400 | [diff] [blame] | 265 | g_main_loop_unref (loop); |
| 266 | return 0; |
| 267 | } |
| 268 | |