* General Public License for more details:
*/
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include <acl/libacl.h>
+#include <sys/stat.h>
#include <errno.h>
#include <getopt.h>
-#include <sys/stat.h>
#include <glib.h>
-#include <acl/libacl.h>
+#include <inttypes.h>
#include <libudev.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
static int debug;
+enum{
+ ACTION_NONE = 0,
+ ACTION_REMOVE,
+ ACTION_ADD,
+ ACTION_CHANGE
+};
+
static int set_facl(const char* filename, uid_t uid, int add)
{
int get;
acl_permset_t permset;
int ret;
+ /* don't touch ACLs for root */
+ if (uid == 0)
+ return 0;
+
/* read current record */
acl = acl_get_file(filename, ACL_TYPE_ACCESS);
if (!acl)
}
/* ConsoleKit calls us with special variables */
-static int consolekit_called(const char *action, uid_t *uid, const char **own_session, int *add)
+static int consolekit_called(const char *ck_action, uid_t *uid, uid_t *uid2, const char **remove_session_id, int *action)
{
- int a;
- uid_t u;
+ int a = ACTION_NONE;
+ uid_t u = 0;
+ uid_t u2 = 0;
const char *s;
- const char *session;
+ const char *s2;
+ const char *old_session = NULL;
- if (strcmp(action, "session_active_changed") != 0)
+ if (ck_action == NULL || strcmp(ck_action, "seat_active_session_changed") != 0)
return -1;
- s = getenv("CK_SESSION_IS_LOCAL");
- if (s == NULL)
- return -1;
- if (strcmp(s, "true") != 0)
- return 0;
-
- s = getenv("CK_SESSION_IS_ACTIVE");
- if (s == NULL)
- return -1;
- if (strcmp(s, "true") == 0)
- a = 1;
- else
- a = 0;
-
- session = getenv("CK_SESSION_ID");
- if (session == NULL)
+ /* We can have one of: remove, add, change, no-change */
+ s = getenv("CK_SEAT_OLD_SESSION_ID");
+ s2 = getenv("CK_SEAT_SESSION_ID");
+ if (s == NULL && s2 == NULL) {
return -1;
+ } else if (s2 == NULL) {
+ a = ACTION_REMOVE;
+ } else if (s == NULL) {
+ a = ACTION_ADD;
+ } else {
+ a = ACTION_CHANGE;
+ }
- s = getenv("CK_SESSION_USER_UID");
- if (s == NULL)
- return -1;
- u = strtoul(s, NULL, 10);
- if (u == 0)
- return 0;
+ switch (a) {
+ case ACTION_ADD:
+ s = getenv("CK_SEAT_SESSION_USER_UID");
+ if (s == NULL)
+ return -1;
+ u = strtoul(s, NULL, 10);
+
+ s = getenv("CK_SEAT_SESSION_IS_LOCAL");
+ if (s == NULL)
+ return -1;
+ if (strcmp(s, "true") != 0)
+ return 0;
+
+ break;
+ case ACTION_REMOVE:
+ s = getenv("CK_SEAT_OLD_SESSION_USER_UID");
+ if (s == NULL)
+ return -1;
+ u = strtoul(s, NULL, 10);
+
+ s = getenv("CK_SEAT_OLD_SESSION_IS_LOCAL");
+ if (s == NULL)
+ return -1;
+ if (strcmp(s, "true") != 0)
+ return 0;
+
+ old_session = getenv("CK_SEAT_OLD_SESSION_ID");
+ if (old_session == NULL)
+ return -1;
+
+ break;
+ case ACTION_CHANGE:
+ s = getenv("CK_SEAT_OLD_SESSION_USER_UID");
+ if (s == NULL)
+ return -1;
+ u = strtoul(s, NULL, 10);
+ s = getenv("CK_SEAT_SESSION_USER_UID");
+ if (s == NULL)
+ return -1;
+ u2 = strtoul(s, NULL, 10);
+
+ s = getenv("CK_SEAT_OLD_SESSION_IS_LOCAL");
+ s2 = getenv("CK_SEAT_SESSION_IS_LOCAL");
+ if (s == NULL || s2 == NULL)
+ return -1;
+ /* don't process non-local session changes */
+ if (strcmp(s, "true") != 0 && strcmp(s2, "true") != 0)
+ return 0;
+
+ if (strcmp(s, "true") == 0 && strcmp(s, "true") == 0) {
+ /* process the change */
+ if (u == u2) {
+ /* special case: we noop if we are
+ * changing between local sessions for
+ * the same uid */
+ a = ACTION_NONE;
+ }
+ old_session = getenv("CK_SEAT_OLD_SESSION_ID");
+ if (old_session == NULL)
+ return -1;
+ } else if (strcmp(s, "true") == 0) {
+ /* only process the removal */
+ a = ACTION_REMOVE;
+ old_session = getenv("CK_SEAT_OLD_SESSION_ID");
+ if (old_session == NULL)
+ return -1;
+ } else if (strcmp(s2, "true") == 0) {
+ /* only process the addition */
+ a = ACTION_ADD;
+ u = u2;
+ }
+ break;
+ }
- *own_session = session;
+ *remove_session_id = old_session;
*uid = u;
- *add = a;
+ *uid2 = u2;
+ *action = a;
return 0;
}
/* iterate over all devices tagged with ACL_SET */
udev = udev_new();
enumerate = udev_enumerate_new(udev);
- udev_enumerate_add_match_property(enumerate, "ACL_MANAGE", "*");
+ udev_enumerate_add_match_tag(enumerate, "udev-acl");
udev_enumerate_scan_devices(enumerate);
udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
struct udev_device *device;
if (device == NULL)
continue;
node = udev_device_get_devnode(device);
- if (node == NULL)
+ if (node == NULL) {
+ udev_device_unref(device);
continue;
+ }
set_facl(node, uid, add);
udev_device_unref(device);
}
udev_unref(udev);
}
+static void
+remove_uid (uid_t uid, const char *remove_session_id)
+{
+ /*
+ * Remove ACL for given uid from all matching devices
+ * when there is currently no local active session.
+ */
+ GSList *list;
+
+ list = uids_with_local_active_session(remove_session_id);
+ if (!uid_in_list(list, uid))
+ apply_acl_to_devices(uid, 0);
+ g_slist_free(list);
+}
+
int main (int argc, char* argv[])
{
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{}
};
- int add = -1;
+ int action = -1;
const char *device = NULL;
+ bool uid_given = false;
uid_t uid = 0;
- const char* own_session = NULL;
+ uid_t uid2 = 0;
+ const char* remove_session_id = NULL;
int rc = 0;
/* valgrind is more important to us than a slice allocator */
switch (option) {
case 'a':
- if (strcmp(optarg, "add") == 0 || strcmp(optarg, "change") == 0)
- add = 1;
- else if (strcmp(optarg, "remove") == 0)
- add = 0;
+ if (strcmp(optarg, "remove") == 0)
+ action = ACTION_REMOVE;
else
- goto out;
+ action = ACTION_ADD;
break;
case 'D':
device = optarg;
break;
case 'u':
+ uid_given = true;
uid = strtoul(optarg, NULL, 10);
break;
case 'd':
break;
case 'h':
printf("Usage: udev-acl --action=ACTION [--device=DEVICEFILE] [--user=UID]\n\n");
- default:
goto out;
}
}
- if (add < 0 && device == NULL && uid == 0)
- consolekit_called(argv[optind], &uid, &own_session, &add);
+ if (action < 0 && device == NULL && !uid_given)
+ if (!consolekit_called(argv[optind], &uid, &uid2, &remove_session_id, &action))
+ uid_given = true;
- if (add < 0) {
+ if (action < 0) {
fprintf(stderr, "missing action\n\n");
rc = 2;
goto out;
}
- if (device != NULL && uid != 0) {
+ if (device != NULL && uid_given) {
fprintf(stderr, "only one option, --device=DEVICEFILE or --user=UID expected\n\n");
rc = 3;
goto out;
}
- if (uid != 0) {
- if (add) {
+ if (uid_given) {
+ switch (action) {
+ case ACTION_ADD:
/* Add ACL for given uid to all matching devices. */
apply_acl_to_devices(uid, 1);
- } else {
- /*
- * Remove ACL for given uid from all matching devices
- * when there is currently no local active session.
- */
- GSList *list;
-
- list = uids_with_local_active_session(own_session);
- if (!uid_in_list(list, uid))
- apply_acl_to_devices(uid, 0);
- g_slist_free(list);
+ break;
+ case ACTION_REMOVE:
+ remove_uid(uid, remove_session_id);
+ break;
+ case ACTION_CHANGE:
+ remove_uid(uid, remove_session_id);
+ apply_acl_to_devices(uid2, 1);
+ break;
+ case ACTION_NONE:
+ goto out;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
}
} else if (device != NULL) {
/*
uid_t u;
u = GPOINTER_TO_UINT(l->data);
- if (add || !uid_in_list(list, u))
- set_facl(device, u, add);
+ if (action == ACTION_ADD || !uid_in_list(list, u))
+ set_facl(device, u, action == ACTION_ADD);
}
g_slist_free(list);
} else {