35
35
#include <libhal.h>
36
#include <polkit/polkit.h>
37
38
/* How this works (or "An introduction to this code")
39
40
* - all ACL's granted by this tool is kept in /var/lib/hal/acl-list
41
* See below for the format.
41
43
* - every time tool is launched we read this file and keep each line
42
44
* as an ACLCurrent instance. These are kept in a list.
52
54
* - ACL's to be added are appended to the list and add -> TRUE
53
55
* - we then compute the argument vector to setfacl(1) for adding /
57
* - we emit signals ACLAdded and ACLRemoved
55
58
* - if setfacl(1) succeeds (rc == 0) then we write the new acl-current-list
57
60
* Notably, the HAL daemon will invoke us with --reconfigure on every
83
86
* of ACL's that have been set by HAL and as such are currently
86
* <device-file> <type> <uid-or-gid>
89
* <device-file> <udi> <type> <uid-or-gid>
88
91
* where <type>='u'|'g' for respectively uid and gid (the spacing represent tabs).
92
* /dev/snd/controlC0 u 500
93
* /dev/snd/controlC0 u 501
94
* /dev/snd/controlC0 g 1001
95
* /dev/snd/controlC0 /org/freedesktop/Hal/devices/pci_8086_27d8_alsa_control__1 u 500
96
* /dev/snd/controlC0 /org/freedesktop/Hal/devices/pci_8086_27d8_alsa_control__1 u 501
97
* /dev/snd/controlC0 /org/freedesktop/Hal/devices/pci_8086_27d8_alsa_control__1 g 1001
96
99
typedef struct ACLCurrent_s {
117
static PolKitContext *pk_context = NULL;
119
static LibHalContext *hal_ctx = NULL;
121
static gboolean in_device_added = FALSE;
124
ensure_hal_ctx (void)
130
if (hal_ctx != NULL) {
135
dbus_error_init (&error);
136
if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
137
printf ("%d: Cannot connect to hald: %s: %s\n", getpid (), error.name, error.message);
138
LIBHAL_FREE_DBUS_ERROR (&error);
115
149
hal_acl_free (ACLCurrent *ha)
117
152
g_free (ha->device);
167
202
(ha->type == HAL_ACL_UID) ? 'u' : 'g',
168
203
(ha->type == HAL_ACL_UID) ? ha->v.uid : ha->v.gid,
172
g_string_append_printf (str,
175
(ha->type == HAL_ACL_UID) ? 'u' : 'g',
176
(ha->type == HAL_ACL_UID) ? ha->v.uid : ha->v.gid);
209
g_string_append_printf (str,
213
(ha->type == HAL_ACL_UID) ? 'u' : 'g',
214
(ha->type == HAL_ACL_UID) ? ha->v.uid : ha->v.gid);
178
217
new_acl_file_contents = g_string_free (str, FALSE);
224
263
strlen (new_acl_file_contents),
266
/* now that we've added/removed ACL's: emit D-Bus signals.. we need to do this _after_
267
* having updated the ACL - to avoid possible race conditions
269
messages_were_sent = FALSE;
270
for (i = new_acl_list; i != NULL; i = g_slist_next (i)) {
271
ACLCurrent *ha = (ACLCurrent *) i->data;
273
/* emit signal ACLGranted or ACLRemoved - but avoid doing it on device add because the device
274
* object doesn't exist just yet
276
if (ha->type == HAL_ACL_UID && ha->udi != NULL && (ha->add || ha->remove) && !in_device_added) {
277
DBusMessage *message;
278
DBusConnection *connection;
280
printf ("Emmitting %s for udi %s, uid %d\n",
281
ha->add ? "ACLAdded" : "ACLRemoved",
285
if (!ensure_hal_ctx ()) {
286
printf ("%d: cannot get libhal context\n", getpid ());
290
connection = libhal_ctx_get_dbus_connection (hal_ctx);
291
if (connection == NULL) {
292
printf ("%d: cannot get D-Bus connection\n", getpid());
296
message = dbus_message_new_signal (ha->udi,
297
"org.freedesktop.Hal.Device.AccessControl",
298
ha->add ? "ACLAdded" : "ACLRemoved");
299
if (message == NULL) {
300
printf ("%d: cannot create message\n", getpid());
304
if (!dbus_message_append_args (message,
305
DBUS_TYPE_UINT32, &(ha->v.uid),
306
DBUS_TYPE_INVALID)) {
307
printf ("%d: cannot append to message\n", getpid());
308
dbus_message_unref (message);
312
if (!dbus_connection_send (connection, message, NULL)) {
313
printf ("%d: cannot send message\n", getpid());
314
dbus_message_unref (message);
317
dbus_message_unref (message);
319
messages_were_sent = TRUE;
326
/* apparently we need to flush the signals - otherwise they
327
* may be lost because we're exiting right after this
329
if (messages_were_sent) {
330
if (ensure_hal_ctx ()) {
331
DBusConnection *connection;
332
connection = libhal_ctx_get_dbus_connection (hal_ctx);
333
if (connection != NULL) {
334
dbus_connection_flush (connection);
373
gboolean old_format = FALSE;
376
/* supporting the old format is important; because at hald startup we call hal-acl-tool --remove-all */
262
378
ha = g_new0 (ACLCurrent, 1);
263
379
val = g_strsplit(buf, "\t", 0);
264
if (g_strv_length (val) != 3) {
265
printf ("Line is malformed: '%s'\n", buf);
270
ha->device = g_strdup (val[0]);
271
if (strcmp (val[1], "u") == 0) {
380
if (g_strv_length (val) == 3) {
381
printf ("Line is from old format: '%s'\n", buf);
384
if (g_strv_length (val) != 4) {
385
printf ("Line is malformed: '%s'\n", buf);
393
ha->device = g_strdup (val[n++]);
398
ha->udi = g_strdup (val[n++]);
401
if (strcmp (val[n], "u") == 0) {
272
402
ha->type = HAL_ACL_UID;
273
ha->v.uid = strtol (val[2], &endptr, 10);
403
ha->v.uid = strtol (val[n + 1], &endptr, 10);
274
404
if (*endptr != '\0' && *endptr != '\n') {
275
405
printf ("Line is malformed: '%s'\n", buf);
276
406
g_strfreev (val);
279
} else if (strcmp (val[1], "g") == 0) {
409
} else if (strcmp (val[n], "g") == 0) {
280
410
ha->type = HAL_ACL_GID;
281
ha->v.gid = strtol (val[2], &endptr, 10);
411
ha->v.gid = strtol (val[n + 1], &endptr, 10);
282
412
if (*endptr != '\0' && *endptr != '\n') {
283
413
printf ("Line is malformed: '%s'\n", buf);
284
414
g_strfreev (val);
349
480
sessions = g_strsplit (s, "\t", 0);
350
481
num_sessions_on_seat = g_strv_length (sessions);
352
visitor_cb (seat, num_sessions_on_seat, NULL, 0, FALSE, FALSE, user_data);
483
seat_id = g_strdup_printf ("/org/freedesktop/ConsoleKit/%s", seat);
484
visitor_cb (seat_id, num_sessions_on_seat, NULL, 0, FALSE, FALSE, user_data);
354
486
/* for all sessions on seat */
355
487
for (j = 0; sessions[j] != NULL; j++) {
356
488
char *session = sessions[j];
357
490
gboolean session_is_local;
358
491
gboolean session_is_active;
359
492
uid_t session_uid;
393
visitor_cb (seat, num_sessions_on_seat,
394
session, session_uid, session_is_local, session_is_active, user_data);
526
session_id = g_strdup_printf ("/org/freedesktop/ConsoleKit/%s", session);
528
visitor_cb (seat_id, num_sessions_on_seat,
529
session_id, session_uid, session_is_local, session_is_active, user_data);
397
533
g_strfreev (sessions);
399
536
g_strfreev (seats);
409
546
/* identifying the device */
410
547
char *udi; /* HAL UDI of device */
411
548
char *device; /* device file */
413
/* policy for how to apply ACL's (must be set by the caller prior to visiting the device) */
415
/* access is granted to any session on a local seat */
416
gboolean grant_to_local_seat;
418
/* access is granted only to active sessions on local seats */
419
gboolean grant_to_local_seat_active_only;
549
char *type; /* type of device, access_control.type - used by PolicyKit */
421
551
/* will be set by the visitor */
422
552
GSList *uid; /* list of uid's (int) that should have access to this device */
623
/* apply the policy defined by grant_to_local_seat and grant_to_local_seat_active_only */
625
/* we only grant access to local seats... */
626
if (!session_is_local)
629
/* don't bother giving ACL's to root - he's almighty anyway */
630
if (session_uid == 0)
633
if (afd->grant_to_local_seat)
764
pk_seat = polkit_seat_new ();
765
polkit_seat_set_ck_objref (pk_seat, seat_id);
767
pk_session = polkit_session_new ();
768
polkit_session_set_seat (pk_session, pk_seat);
769
polkit_seat_unref (pk_seat);
770
polkit_session_set_ck_objref (pk_session, session_id);
771
polkit_session_set_uid (pk_session, session_uid);
772
polkit_session_set_ck_is_active (pk_session, session_is_active);
773
polkit_session_set_ck_is_local (pk_session, session_is_local);
774
/* TODO: FIXME: polkit_session_set_ck_remote_host (pk_session, );*/
776
pk_action = polkit_action_new();
777
priv_name = g_strdup_printf ("org.freedesktop.hal.device-access.%s", afd->type);
778
polkit_action_set_action_id (pk_action, priv_name);
781
/* Now ask PolicyKit if the given session should have access */
782
pk_result = polkit_context_can_session_do_action (pk_context,
785
if (pk_result == POLKIT_RESULT_YES) {
634
786
afd_grant_to_uid (afd, session_uid);
636
if (afd->grant_to_local_seat_active_only) {
637
if (session_is_active) {
638
afd_grant_to_uid (afd, session_uid);
789
polkit_action_unref (pk_action);
790
polkit_session_unref (pk_session);
734
883
for (j = afd->uid; j != NULL; j = g_slist_next (j)) {
887
uid = GPOINTER_TO_INT (j->data);
888
/* never grant ACL's to the super user */
736
892
ha = g_new0 (ACLCurrent, 1);
738
894
ha->device = g_strdup (afd->device);
895
ha->udi = g_strdup (afd->udi);
739
896
ha->type = HAL_ACL_UID;
740
ha->v.uid = GPOINTER_TO_INT (j->data);
741
898
current_acl_list = g_slist_prepend (current_acl_list, ha);
743
900
for (j = afd->gid; j != NULL; j = g_slist_next (j)) {
745
902
ha = g_new0 (ACLCurrent, 1);
747
904
ha->device = g_strdup (afd->device);
905
ha->udi = g_strdup (afd->udi);
748
906
ha->type = HAL_ACL_GID;
749
907
ha->v.gid = GPOINTER_TO_INT (j->data);
750
908
current_acl_list = g_slist_prepend (current_acl_list, ha);
789
950
if ((device = getenv ("HAL_PROP_ACCESS_CONTROL_FILE")) == NULL)
953
if ((type = getenv ("HAL_PROP_ACCESS_CONTROL_TYPE")) == NULL)
792
956
afd = acl_for_device_new (udi);
793
957
acl_for_device_set_device (afd, device);
958
acl_for_device_set_type (afd, type);
794
959
afd_list = g_slist_prepend (NULL, afd);
796
961
/* get ACL granting policy from HAL properties */
797
if ((s = getenv ("HAL_PROP_ACCESS_CONTROL_GRANT_LOCAL_SESSION")) != NULL) {
798
afd->grant_to_local_seat = (strcmp (s, "true") == 0);
800
if ((s = getenv ("HAL_PROP_ACCESS_CONTROL_GRANT_LOCAL_ACTIVE_SESSION")) != NULL) {
801
afd->grant_to_local_seat_active_only = (strcmp (s, "true") == 0);
803
962
if ((s = getenv ("HAL_PROP_ACCESS_CONTROL_GRANT_USER")) != NULL) {
805
964
sv = g_strsplit (s, "\t", 0);
879
1038
int num_devices;
881
1040
DBusError error;
882
LibHalContext *hal_ctx;
883
1041
GSList *afd_list = NULL;
885
1043
printf ("%d: reconfiguring all ACL's\n", getpid ());
1045
if (!ensure_hal_ctx ())
887
1048
dbus_error_init (&error);
888
if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
889
printf ("%d: Cannot connect to hald: %s: %s\n", getpid (), error.name, error.message);
890
LIBHAL_FREE_DBUS_ERROR (&error);
894
1049
if ((udis = libhal_find_device_by_capability (hal_ctx, "access_control", &num_devices, &error)) == NULL) {
895
1050
printf ("%d: Cannot get list of devices of capability 'acl'\n", getpid ());
916
1072
key = libhal_psi_get_key (&psi);
917
1073
if (strcmp (key, "access_control.file") == 0) {
918
1074
device = libhal_psi_get_string (&psi);
919
} else if (strcmp (key, "access_control.grant_local_session") == 0) {
920
afd->grant_to_local_seat = libhal_psi_get_bool (&psi);
921
} else if (strcmp (key, "access_control.grant_local_active_session") == 0) {
922
afd->grant_to_local_seat_active_only = libhal_psi_get_bool (&psi);
1075
} else if (strcmp (key, "access_control.type") == 0) {
1076
type = libhal_psi_get_string (&psi);
923
1077
} else if (strcmp (key, "access_control.grant_user") == 0) {
924
1078
sv = libhal_psi_get_strlist (&psi);
925
1079
afd_grant_to_uid_from_userlist (afd, sv);
933
1087
if (device == NULL) {
934
1088
printf ("%d: access_control.file not set for '%s'\n", getpid (), udis[i]);
937
acl_for_device_set_device (afd, device);
938
afd_list = g_slist_prepend (afd_list, afd);
1090
libhal_free_string (type);
1091
acl_for_device_free (afd);
1096
printf ("%d: access_control.type not set for '%s'\n", getpid (), udis[i]);
1098
libhal_free_string (device);
1100
libhal_free_string (type);
1101
acl_for_device_free (afd);
1105
acl_for_device_set_device (afd, device);
1106
acl_for_device_set_type (afd, type);
1107
afd_list = g_slist_prepend (afd_list, afd);
941
1109
libhal_free_property_set (props);
943
1111
libhal_free_string_array (udis);
990
1158
printf ("%d: attempting to get lock on " PACKAGE_LOCALSTATEDIR "/lib/hal/acl-list\n", getpid ());
992
lock_acl_fd = open (PACKAGE_LOCALSTATEDIR "/lib/hal/acl-list", O_CREAT | O_RDWR);
1160
lock_acl_fd = open (PACKAGE_LOCALSTATEDIR "/lib/hal/acl-list", O_CREAT | O_RDWR, 0644);
993
1161
if (lock_acl_fd < 0) {
994
1162
printf ("%d: error opening/creating " PACKAGE_LOCALSTATEDIR "/lib/hal/acl-list\n", getpid ());
1211
pk_context = polkit_context_new ();
1212
if (!polkit_context_init (pk_context, &p_error)) {
1213
printf ("Could not init PolicyKit context: %s\n", polkit_error_get_error_message (p_error));
1041
1217
if (strcmp (argv[1], "--add-device") == 0) {
1042
1218
acl_device_added ();
1043
1219
} else if (strcmp (argv[1], "--remove-device") == 0) {