X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=extras%2Fudev-acl%2Fudev-acl.c;h=35bad76034972e23ff0e6295891b7b2e5518cdc4;hb=eb042a2c92fb857294e1380ff232a7633a2d3725;hp=3eb29fe2f28951bb5ba91f527dcbd0d9472b1537;hpb=fc04059abfc5d1fa9bfe9afb15ca03017a26fb56;p=elogind.git diff --git a/extras/udev-acl/udev-acl.c b/extras/udev-acl/udev-acl.c index 3eb29fe2f..35bad7603 100644 --- a/extras/udev-acl/udev-acl.c +++ b/extras/udev-acl/udev-acl.c @@ -12,23 +12,28 @@ * General Public License for more details: */ -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include -#include #include -#include +#include #include +#include +#include +#include +#include +#include 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; @@ -38,6 +43,10 @@ static int set_facl(const char* filename, uid_t uid, int add) 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) @@ -152,44 +161,109 @@ static GSList *uids_with_local_active_session(const char *own_id) } /* 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; - - if (action == NULL || strcmp(action, "session_active_changed") != 0) - return -1; + const char *s2; + const char *old_session = NULL; - s = getenv("CK_SESSION_IS_LOCAL"); - if (s == NULL) + if (ck_action == NULL || strcmp(ck_action, "seat_active_session_changed") != 0) 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; } @@ -203,7 +277,7 @@ static void apply_acl_to_devices(uid_t uid, int add) /* 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; @@ -223,6 +297,21 @@ static void apply_acl_to_devices(uid_t uid, int add) 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[] = { @@ -233,10 +322,12 @@ int main (int argc, char* argv[]) { "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 */ @@ -251,17 +342,16 @@ int main (int argc, char* argv[]) 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': @@ -269,41 +359,45 @@ int main (int argc, char* argv[]) 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) { /* @@ -321,8 +415,8 @@ int main (int argc, char* argv[]) 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 {