]>
Commit | Line | Data |
---|---|---|
61cccc46 JR |
1 | diff --git a/NEWS b/NEWS |
2 | index 81c3225..cf06a31 100644 | |
3 | --- a/NEWS | |
4 | +++ b/NEWS | |
5 | @@ -1,4 +1,11 @@ | |
6 | ============== | |
7 | +Version 0.4.5 | |
8 | +============== | |
9 | + | |
10 | + * Loop around opening /dev/console to deal with BKL-less kernels (Colin Watson) | |
11 | + * systemd fixes (Lennart Poettering) | |
12 | + | |
13 | +============== | |
14 | Version 0.4.4 | |
15 | ============== | |
16 | ||
17 | diff --git a/configure.ac b/configure.ac | |
18 | index 0efc489..7a3b33f 100644 | |
19 | --- a/configure.ac | |
20 | +++ b/configure.ac | |
21 | @@ -1,7 +1,7 @@ | |
22 | ||
23 | -AC_PREREQ(2.59c) | |
24 | +AC_PREREQ([2.68]) | |
25 | AC_INIT([ConsoleKit], | |
26 | - [0.4.5], | |
27 | + [0.4.6], | |
28 | [https://bugs.freedesktop.org/enter_bug.cgi?product=ConsoleKit], | |
29 | [ConsoleKit]) | |
30 | ||
31 | @@ -12,13 +12,14 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) | |
32 | AM_MAINTAINER_MODE | |
33 | ||
34 | # for O_NOFOLLOW support | |
35 | -AC_GNU_SOURCE | |
36 | +AC_USE_SYSTEM_EXTENSIONS | |
37 | ||
38 | -AC_ISC_POSIX | |
39 | +AC_SEARCH_LIBS([strerror],[cposix]) | |
40 | AC_PROG_CC | |
41 | -AC_STDC_HEADERS | |
42 | +AM_PROG_CC_C_O | |
43 | +AC_HEADER_STDC | |
44 | AC_DISABLE_STATIC | |
45 | -AC_PROG_LIBTOOL | |
46 | +LT_INIT | |
47 | ||
48 | AC_HEADER_STDC | |
49 | ||
50 | @@ -88,50 +89,15 @@ case "$host" in | |
51 | ;; | |
52 | esac | |
53 | ||
54 | -# Find out the version of DBUS we're using | |
55 | - | |
56 | -dbus_version=`pkg-config --modversion dbus-1` | |
57 | -DBUS_VERSION_MAJOR=`echo $dbus_version | awk -F. '{print $1}'` | |
58 | -DBUS_VERSION_MINOR=`echo $dbus_version | awk -F. '{print $2}'` | |
59 | -DBUS_VERSION_MICRO=`echo $dbus_version | awk -F. '{print $3}'` | |
60 | -if test "z$DBUS_VERSION_MAJOR" = "z"; then | |
61 | - DBUS_VERSION_MAJOR="0" | |
62 | -fi | |
63 | -if test "z$DBUS_VERSION_MINOR" = "z"; then | |
64 | - DBUS_VERSION_MINOR="0" | |
65 | -fi | |
66 | -if test "z$DBUS_VERSION_MICRO" = "z"; then | |
67 | - DBUS_VERSION_MICRO="0" | |
68 | -fi | |
69 | - | |
70 | -if test "z$DBUS_VERSION_MAJOR" = "z0" -a "z$DBUS_VERSION_MINOR" = "z0" -a "z$DBUS_VERSION_MICRO" = "z0"; then echo "Error: Couldn't determine the version of your DBUS package." | |
71 | - echo " This is probably an error in this script, please report it" | |
72 | - echo " along with the following information:" | |
73 | - echo " Base DBUS version ='$dbus_version'" | |
74 | - echo " DBUS_VERSION_MAJOR='$DBUS_VERSION_MAJOR'" | |
75 | - echo " DBUS_VERSION_MINOR='$DBUS_VERSION_MINOR'" | |
76 | - echo " DBUS_VERSION_MICRO='$DBUS_VERSION_MICRO'" | |
77 | - exit 1 | |
78 | -else | |
79 | - | |
80 | - echo "Your dbus version is $DBUS_VERSION_MAJOR,$DBUS_VERSION_MINOR,$DBUS_VERSION_MICRO." | |
81 | - DBUS_CFLAGS="$DBUS_CFLAGS -DDBUS_VERSION_MAJOR=$DBUS_VERSION_MAJOR" | |
82 | - DBUS_CFLAGS="$DBUS_CFLAGS -DDBUS_VERSION_MINOR=$DBUS_VERSION_MINOR" | |
83 | - DBUS_CFLAGS="$DBUS_CFLAGS -DDBUS_VERSION_MICRO=$DBUS_VERSION_MICRO" | |
84 | - | |
85 | - AC_SUBST(DBUS_CFLAGS) | |
86 | -fi | |
87 | ||
88 | dnl --------------------------------------------------------------------------- | |
89 | dnl - Are we specifying a different dbus root ? | |
90 | dnl --------------------------------------------------------------------------- | |
91 | ||
92 | AC_ARG_WITH(dbus-sys, | |
93 | - [AC_HELP_STRING([--with-dbus-sys=<dir>], | |
94 | - [where D-BUS system.d directory is])]) | |
95 | + [AS_HELP_STRING([--with-dbus-sys=<dir>],[where D-BUS system.d directory is])]) | |
96 | AC_ARG_WITH(dbus-services, | |
97 | - [AC_HELP_STRING([--with-dbus-services=<dir>], | |
98 | - [where D-BUS services directory is])]) | |
99 | + [AS_HELP_STRING([--with-dbus-services=<dir>],[where D-BUS services directory is])]) | |
100 | if ! test -z "$with_dbus_sys" ; then | |
101 | DBUS_SYS_DIR="$with_dbus_sys" | |
102 | else | |
103 | @@ -158,8 +124,7 @@ dnl - PID file | |
104 | dnl --------------------------------------------------------------------------- | |
105 | ||
106 | AC_ARG_WITH(pid-file, | |
107 | - [AC_HELP_STRING([--with-pid-file=<file>], | |
108 | - [pid file location])]) | |
109 | + [AS_HELP_STRING([--with-pid-file=<file>],[pid file location])]) | |
110 | ||
111 | if ! test -z "$with_pid_file"; then | |
112 | CONSOLE_KIT_PID_FILE=$with_pid_file | |
113 | @@ -190,6 +155,9 @@ case "$host" in | |
114 | *-*-solaris*) | |
115 | CK_BACKEND="solaris" | |
116 | ;; | |
117 | + *-*-gnu*) | |
118 | + CK_BACKEND="gnu" | |
119 | + ;; | |
120 | *) | |
121 | AC_MSG_ERROR([No sysdeps back-end implemented for host $host]) | |
122 | ;; | |
123 | @@ -200,6 +168,7 @@ AC_SUBST(KVM_LIBS) | |
124 | AM_CONDITIONAL(CK_COMPILE_LINUX, test x$CK_BACKEND = xlinux, [Compiling for Linux]) | |
125 | AM_CONDITIONAL(CK_COMPILE_FREEBSD, test x$CK_BACKEND = xfreebsd, [Compiling for FreeBSD]) | |
126 | AM_CONDITIONAL(CK_COMPILE_SOLARIS, test x$CK_BACKEND = xsolaris, [Compiling for Solaris]) | |
127 | +AM_CONDITIONAL(CK_COMPILE_GNU, test x$CK_BACKEND = xgnu, [Compiling for GNU]) | |
128 | AC_SUBST(CK_BACKEND) | |
129 | ||
130 | dnl --------------------------------------------------------------------------- | |
131 | @@ -221,8 +190,7 @@ AC_CHECK_LIB(pam, pam_syslog, [AC_DEFINE(HAVE_PAM_SYSLOG, [], [Define to 1 if yo | |
132 | # Check if we should build the PAM module | |
133 | msg_pam_module=no | |
134 | AC_ARG_ENABLE(pam-module, | |
135 | - [AC_HELP_STRING([--enable-pam-module], | |
136 | - [build PAM module])], | |
137 | + [AS_HELP_STRING([--enable-pam-module],[build PAM module])], | |
138 | , enable_pam_module=no) | |
139 | if test "x$enable_pam_module" = "xyes"; then | |
140 | if test "x$have_pam" = "xno"; then | |
141 | @@ -233,13 +201,32 @@ if test "x$enable_pam_module" = "xyes"; then | |
142 | fi | |
143 | AM_CONDITIONAL(ENABLE_PAM_MODULE, test "x$enable_pam_module" = "xyes") | |
144 | ||
145 | +dnl ------------------------------------------------------------------------------ | |
146 | +dnl udev-acl - apply ACLs for users with local forground sessions | |
147 | +dnl ------------------------------------------------------------------------------ | |
148 | +AC_ARG_ENABLE([udev-acl], | |
149 | + AS_HELP_STRING([--enable-udev-acl], [enable local user acl permissions support @<:@default=disabled@:>@]), | |
150 | + [], [enable_udev_acl=no]) | |
151 | +AS_IF([test "x$enable_udev_acl" = "xyes"], [ | |
152 | + | |
153 | + PKG_CHECK_MODULES([UDEV_ACL], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0 libudev]) | |
154 | + AC_CHECK_LIB([acl], [acl_init], [UDEV_ACL_LIBS="$UDEV_ACL_LIBS -lacl"], AC_MSG_ERROR([libacl not found])) | |
155 | + AC_CHECK_HEADER([acl/libacl.h], [:], AC_MSG_ERROR([libacl header not found])) | |
156 | + UDEVDIR=`$PKG_CONFIG --variable udevdir udev` | |
157 | + if test -z "$UDEVDIR" ; then | |
158 | + UDEVDIR="/lib/udev" | |
159 | + fi | |
160 | + AC_SUBST(UDEVDIR) | |
161 | +]) | |
162 | +AM_CONDITIONAL([ENABLE_UDEV_ACL], [test "x$enable_udev_acl" = "xyes"]) | |
163 | + | |
164 | + | |
165 | dnl --------------------------------------------------------------------------- | |
166 | dnl - Install directory for PAM security module | |
167 | dnl --------------------------------------------------------------------------- | |
168 | ||
169 | AC_ARG_WITH(pam-module-dir, | |
170 | - [AC_HELP_STRING([--with-pam-module-dir=<dir>], | |
171 | - [directory to install PAM security module])]) | |
172 | + [AS_HELP_STRING([--with-pam-module-dir=<dir>],[directory to install PAM security module])]) | |
173 | if ! test -z "$with_pam_module_dir"; then | |
174 | PAM_MODULE_DIR="$with_pam_module_dir" | |
175 | else | |
176 | @@ -252,8 +239,7 @@ dnl - DocBook Documentation | |
177 | dnl --------------------------------------------------------------------------- | |
178 | ||
179 | AC_ARG_ENABLE(docbook-docs, | |
180 | - [AC_HELP_STRING([--enable-docbook-docs], | |
181 | - [build documentation (requires xmlto)])], | |
182 | + [AS_HELP_STRING([--enable-docbook-docs],[build documentation (requires xmlto)])], | |
183 | enable_docbook_docs=$enableval,enable_docbook_docs=no) | |
184 | AC_PATH_PROG(XMLTO, xmlto, no) | |
185 | AC_MSG_CHECKING([whether to build DocBook documentation]) | |
186 | @@ -308,8 +294,7 @@ dnl --------------------------------------------------------------------------- | |
187 | ||
188 | msg_rbac_shutdown=no | |
189 | AC_ARG_ENABLE(rbac-shutdown, | |
190 | - [AC_HELP_STRING([--enable-rbac-shutdown=<key>], | |
191 | - [Build with RBAC support specifying shutdown/reboot RBAC authentication key])], | |
192 | + [AS_HELP_STRING([--enable-rbac-shutdown=<key>],[Build with RBAC support specifying shutdown/reboot RBAC authentication key])], | |
193 | enable_rbac_shutdown=$enableval,enable_rbac_shutdown=no) | |
194 | if test "x$enable_rbac_shutdown" != "xno"; then | |
195 | RBAC_LIBS="-lsecdb -lsocket -lnsl" | |
196 | @@ -326,8 +311,7 @@ dnl --------------------------------------------------------------------------- | |
197 | # Turn on the additional warnings last, so -Werror doesn't affect other tests. | |
198 | ||
199 | AC_ARG_ENABLE(more-warnings, | |
200 | - [AC_HELP_STRING([--enable-more-warnings], | |
201 | - [Maximum compiler warnings])], | |
202 | + [AS_HELP_STRING([--enable-more-warnings],[Maximum compiler warnings])], | |
203 | set_more_warnings="$enableval",[ | |
204 | if test -d $srcdir/.git; then | |
205 | set_more_warnings=yes | |
206 | @@ -349,9 +333,7 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then | |
207 | SAVE_CFLAGS="$CFLAGS" | |
208 | CFLAGS="$CFLAGS $option" | |
209 | AC_MSG_CHECKING([whether gcc understands $option]) | |
210 | - AC_TRY_COMPILE([], [], | |
211 | - has_option=yes, | |
212 | - has_option=no,) | |
213 | + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[has_option=yes],[has_option=no]) | |
214 | if test $has_option = no; then | |
215 | CFLAGS="$SAVE_CFLAGS" | |
216 | fi | |
217 | @@ -368,8 +350,7 @@ fi | |
218 | # Enable Debug | |
219 | # | |
220 | AC_ARG_ENABLE(debug, | |
221 | - [AC_HELP_STRING([--enable-debug], | |
222 | - [turn on debugging])], | |
223 | + [AS_HELP_STRING([--enable-debug],[turn on debugging])], | |
224 | , enable_debug=yes) | |
225 | if test "$enable_debug" = "yes"; then | |
226 | DEBUG_CFLAGS="-DG_ENABLE_DEBUG" | |
227 | @@ -395,10 +376,9 @@ AC_SUBST(LDFLAGS) | |
228 | ||
229 | AC_ARG_WITH([systemdsystemunitdir], | |
230 | AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), | |
231 | - [], | |
232 | - [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) | |
233 | -AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) | |
234 | -AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir"]) | |
235 | + [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) | |
236 | +AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])]) | |
237 | +AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != "xno"]) | |
238 | ||
239 | # Files | |
240 | ||
241 | @@ -445,6 +425,7 @@ echo " | |
242 | Build backend: ${CK_BACKEND} | |
243 | PAM module dir: ${PAM_MODULE_DIR} | |
244 | Build PAM module: ${msg_pam_module} | |
245 | + Build udev-acl: ${enable_udev_acl} | |
246 | Build docs: ${enable_docbook_docs} | |
247 | ||
248 | PolicyKit support ${have_polkit} | |
249 | diff --git a/pam-ck-connector/pam-ck-connector.c b/pam-ck-connector/pam-ck-connector.c | |
250 | index 9bdef51..949a9b0 100644 | |
251 | --- a/pam-ck-connector/pam-ck-connector.c | |
252 | +++ b/pam-ck-connector/pam-ck-connector.c | |
253 | @@ -244,12 +244,12 @@ pam_sm_open_session (pam_handle_t *pamh, | |
254 | const char *s; | |
255 | uid_t uid; | |
256 | char buf[256]; | |
257 | - char ttybuf[PATH_MAX]; | |
258 | + char *ttybuf; | |
259 | DBusError error; | |
260 | dbus_bool_t is_local; | |
261 | ||
262 | ret = PAM_IGNORE; | |
263 | - | |
264 | + ttybuf = NULL; | |
265 | is_local = TRUE; | |
266 | ||
267 | _parse_pam_args (pamh, flags, argc, argv); | |
268 | @@ -295,7 +295,13 @@ pam_sm_open_session (pam_handle_t *pamh, | |
269 | x11_display = display_device; | |
270 | display_device = ""; | |
271 | } else if (strncmp (_PATH_DEV, display_device, 5) != 0) { | |
272 | - snprintf (ttybuf, sizeof (ttybuf), _PATH_DEV "%s", display_device); | |
273 | + int len = strlen (_PATH_DEV) + strlen (display_device) + 1; | |
274 | + ttybuf = malloc (len); | |
275 | + if (ttybuf == NULL) { | |
276 | + ck_pam_syslog (pamh, LOG_ERR, "oom allocating ttybuf"); | |
277 | + goto out; | |
278 | + } | |
279 | + snprintf (ttybuf, len, _PATH_DEV "%s", display_device); | |
280 | display_device = ttybuf; | |
281 | } | |
282 | ||
283 | @@ -411,6 +417,8 @@ pam_sm_open_session (pam_handle_t *pamh, | |
284 | ret = PAM_SUCCESS; | |
285 | ||
286 | out: | |
287 | + free (ttybuf); | |
288 | + | |
289 | return ret; | |
290 | } | |
291 | ||
292 | diff --git a/src/Makefile.am b/src/Makefile.am | |
293 | index 869decd..217e531 100644 | |
294 | --- a/src/Makefile.am | |
295 | +++ b/src/Makefile.am | |
296 | @@ -57,11 +57,18 @@ libck_la_SOURCES += \ | |
297 | $(NULL) | |
298 | libck_la_LIBADD = $(KVM_LIBS) | |
299 | endif | |
300 | +if CK_COMPILE_GNU | |
301 | +libck_la_SOURCES += \ | |
302 | + ck-sysdeps-gnu.c \ | |
303 | + $(NULL) | |
304 | +libck_la_LIBADD = -lps | |
305 | +endif | |
306 | ||
307 | EXTRA_libck_la_SOURCES = \ | |
308 | ck-sysdeps-linux.c \ | |
309 | ck-sysdeps-solaris.c \ | |
310 | ck-sysdeps-freebsd.c \ | |
311 | + ck-sysdeps-gnu.c \ | |
312 | $(NULL) | |
313 | ||
314 | sbin_PROGRAMS = \ | |
315 | diff --git a/src/ck-sysdeps-gnu.c b/src/ck-sysdeps-gnu.c | |
316 | new file mode 100644 | |
317 | index 0000000..254f7ef | |
318 | --- /dev/null | |
319 | +++ b/src/ck-sysdeps-gnu.c | |
320 | @@ -0,0 +1,402 @@ | |
321 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- | |
322 | + * | |
323 | + * Copyright (C) 2009 Pino Toscano <pino@kde.org> | |
324 | + * | |
325 | + * This program is free software; you can redistribute it and/or modify | |
326 | + * it under the terms of the GNU General Public License as published by | |
327 | + * the Free Software Foundation; either version 2 of the License, or | |
328 | + * (at your option) any later version. | |
329 | + * | |
330 | + * This program is distributed in the hope that it will be useful, | |
331 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
332 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
333 | + * GNU General Public License for more details. | |
334 | + * | |
335 | + * You should have received a copy of the GNU General Public License | |
336 | + * along with this program; if not, write to the Free Software | |
337 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
338 | + * | |
339 | + */ | |
340 | + | |
341 | +#include "config.h" | |
342 | + | |
343 | +#include <stdlib.h> | |
344 | +#include <stdio.h> | |
345 | +#include <unistd.h> | |
346 | +#include <string.h> | |
347 | +#include <errno.h> | |
348 | + | |
349 | +#include <hurd.h> | |
350 | +#include <dirent.h> | |
351 | +#include <ps.h> | |
352 | +#include <ttyent.h> | |
353 | + | |
354 | +#ifdef HAVE_PATHS_H | |
355 | +#include <paths.h> | |
356 | +#endif /* HAVE_PATHS_H */ | |
357 | + | |
358 | +#include "ck-sysdeps.h" | |
359 | + | |
360 | +struct _CkProcessStat | |
361 | +{ | |
362 | + struct proc_stat *ps; /* the statistics of a process */ | |
363 | +}; | |
364 | + | |
365 | +static struct ps_context *pc = NULL; | |
366 | + | |
367 | +static gboolean | |
368 | +get_proc_stat_from_pid (pid_t pid, | |
369 | + ps_flags_t flags, | |
370 | + struct proc_stat **res_ps) | |
371 | +{ | |
372 | + error_t err; | |
373 | + struct proc_stat *ps; | |
374 | + | |
375 | + g_assert (pid >= 0); | |
376 | + g_assert (res_ps != NULL); | |
377 | + | |
378 | + if (pc == NULL) { | |
379 | + err = ps_context_create (getproc (), &pc); | |
380 | + if (err) { | |
381 | + return FALSE; | |
382 | + } | |
383 | + } | |
384 | + | |
385 | + err = _proc_stat_create (pid, pc, &ps); | |
386 | + if (err) { | |
387 | + return FALSE; | |
388 | + } | |
389 | + | |
390 | + err = proc_stat_set_flags (ps, PSTAT_PID | flags); | |
391 | + if (err) { | |
392 | + return FALSE; | |
393 | + } | |
394 | + | |
395 | + *res_ps = ps; | |
396 | + return TRUE; | |
397 | +} | |
398 | + | |
399 | + | |
400 | +pid_t | |
401 | +ck_process_stat_get_ppid (CkProcessStat *stat) | |
402 | +{ | |
403 | + g_return_val_if_fail (stat != NULL, -1); | |
404 | + | |
405 | + return proc_stat_pid (stat->ps); | |
406 | +} | |
407 | + | |
408 | +char * | |
409 | +ck_process_stat_get_cmd (CkProcessStat *stat) | |
410 | +{ | |
411 | + g_return_val_if_fail (stat != NULL, NULL); | |
412 | + | |
413 | + return g_strdup (proc_stat_args (stat->ps)); | |
414 | +} | |
415 | + | |
416 | +char * | |
417 | +ck_process_stat_get_tty (CkProcessStat *stat) | |
418 | +{ | |
419 | + struct ps_tty *tty; | |
420 | + | |
421 | + g_return_val_if_fail (stat != NULL, NULL); | |
422 | + | |
423 | + tty = proc_stat_tty (stat->ps); | |
424 | + | |
425 | + return tty ? g_strdup (ps_tty_name (tty)) : NULL; | |
426 | +} | |
427 | + | |
428 | +gboolean | |
429 | +ck_process_stat_new_for_unix_pid (pid_t pid, | |
430 | + CkProcessStat **stat, | |
431 | + GError **error) | |
432 | +{ | |
433 | + gboolean res; | |
434 | + struct proc_stat *ps; | |
435 | + CkProcessStat *proc; | |
436 | + | |
437 | + g_return_val_if_fail (pid > 1, FALSE); | |
438 | + | |
439 | + if (stat == NULL) { | |
440 | + return FALSE; | |
441 | + } | |
442 | + | |
443 | + *stat = NULL; | |
444 | + | |
445 | + res = get_proc_stat_from_pid (pid, PSTAT_ARGS | PSTAT_TTY, &ps); | |
446 | + if (!res) { | |
447 | + return FALSE; | |
448 | + } | |
449 | + | |
450 | + proc = g_new0 (CkProcessStat, 1); | |
451 | + proc->ps = ps; | |
452 | + *stat = proc; | |
453 | + | |
454 | + return TRUE; | |
455 | +} | |
456 | + | |
457 | +void | |
458 | +ck_process_stat_free (CkProcessStat *stat) | |
459 | +{ | |
460 | + _proc_stat_free (stat->ps); | |
461 | + | |
462 | + g_free (stat); | |
463 | +} | |
464 | + | |
465 | +GHashTable * | |
466 | +ck_unix_pid_get_env_hash (pid_t pid) | |
467 | +{ | |
468 | + struct proc_stat *ps; | |
469 | + char *env_p; | |
470 | + size_t env_index; | |
471 | + size_t env_l; | |
472 | + gboolean res; | |
473 | + GHashTable *hash; | |
474 | + | |
475 | + g_return_val_if_fail (pid > 1, NULL); | |
476 | + | |
477 | + res = get_proc_stat_from_pid (pid, PSTAT_ENV, &ps); | |
478 | + if (!res) { | |
479 | + return NULL; | |
480 | + } | |
481 | + | |
482 | + hash = g_hash_table_new_full (g_str_hash, | |
483 | + g_str_equal, | |
484 | + g_free, | |
485 | + g_free); | |
486 | + | |
487 | + env_index = 0; | |
488 | + env_l = 0; | |
489 | + env_p = proc_stat_env (ps); | |
490 | + while (env_index < proc_stat_env_len (ps)) { | |
491 | + env_l = strlen (env_p); | |
492 | + env_index += env_l + 1; | |
493 | + if (env_l) { | |
494 | + char **vals; | |
495 | + vals = g_strsplit (env_p, "=", 2); | |
496 | + if (vals != NULL) { | |
497 | + g_hash_table_insert (hash, | |
498 | + g_strdup (vals[0]), | |
499 | + g_strdup (vals[1])); | |
500 | + g_strfreev (vals); | |
501 | + } | |
502 | + } | |
503 | + env_p = env_p + env_l + 1; | |
504 | + } | |
505 | + | |
506 | + _proc_stat_free (ps); | |
507 | + | |
508 | + return hash; | |
509 | +} | |
510 | + | |
511 | +char * | |
512 | +ck_unix_pid_get_env (pid_t pid, | |
513 | + const char *var) | |
514 | +{ | |
515 | + struct proc_stat *ps; | |
516 | + char *env_p; | |
517 | + size_t env_index; | |
518 | + size_t env_l; | |
519 | + char *prefix; | |
520 | + int prefix_len; | |
521 | + char *val; | |
522 | + gboolean res; | |
523 | + | |
524 | + g_return_val_if_fail (pid > 1, NULL); | |
525 | + | |
526 | + val = NULL; | |
527 | + | |
528 | + res = get_proc_stat_from_pid (pid, PSTAT_ENV, &ps); | |
529 | + if (!res) { | |
530 | + return NULL; | |
531 | + } | |
532 | + | |
533 | + prefix = g_strdup_printf ("%s=", var); | |
534 | + prefix_len = strlen (prefix); | |
535 | + | |
536 | + env_index = 0; | |
537 | + env_l = 0; | |
538 | + env_p = proc_stat_env (ps); | |
539 | + while (env_index < proc_stat_env_len (ps)) { | |
540 | + env_l = strlen (env_p); | |
541 | + env_index += env_l + 1; | |
542 | + if (env_l && g_str_has_prefix (env_p, prefix)) { | |
543 | + val = g_strdup (env_p + prefix_len); | |
544 | + break; | |
545 | + } | |
546 | + env_p = env_p + env_l + 1; | |
547 | + } | |
548 | + | |
549 | + g_free (prefix); | |
550 | + | |
551 | + _proc_stat_free (ps); | |
552 | + | |
553 | + return val; | |
554 | +} | |
555 | + | |
556 | +uid_t | |
557 | +ck_unix_pid_get_uid (pid_t pid) | |
558 | +{ | |
559 | + struct proc_stat *ps; | |
560 | + gboolean res; | |
561 | + uid_t uid; | |
562 | + | |
563 | + g_return_val_if_fail (pid > 1, 0); | |
564 | + | |
565 | + res = get_proc_stat_from_pid (pid, PSTAT_OWNER_UID, &ps); | |
566 | + if (!res) { | |
567 | + return 0; | |
568 | + } | |
569 | + | |
570 | + uid = proc_stat_owner_uid (ps); | |
571 | + | |
572 | + _proc_stat_free (ps); | |
573 | + | |
574 | + return uid; | |
575 | +} | |
576 | + | |
577 | +pid_t | |
578 | +ck_unix_pid_get_ppid (pid_t pid) | |
579 | +{ | |
580 | + struct proc_stat *ps; | |
581 | + gboolean res; | |
582 | + pid_t ppid; | |
583 | + | |
584 | + g_return_val_if_fail (pid > 1, 0); | |
585 | + | |
586 | + res = get_proc_stat_from_pid (pid, PSTAT_PROC_INFO, &ps); | |
587 | + if (!res) { | |
588 | + return 0; | |
589 | + } | |
590 | + | |
591 | + ppid = proc_stat_proc_info (ps)->ppid; | |
592 | + | |
593 | + _proc_stat_free (ps); | |
594 | + | |
595 | + return ppid; | |
596 | +} | |
597 | + | |
598 | +gboolean | |
599 | +ck_unix_pid_get_login_session_id (pid_t pid, | |
600 | + char **idp) | |
601 | +{ | |
602 | + g_return_val_if_fail (pid > 1, FALSE); | |
603 | + | |
604 | + return FALSE; | |
605 | +} | |
606 | + | |
607 | +gboolean | |
608 | +ck_get_max_num_consoles (guint *num) | |
609 | +{ | |
610 | + int max_consoles; | |
611 | + int res; | |
612 | + gboolean ret; | |
613 | + struct ttyent *t; | |
614 | + | |
615 | + ret = FALSE; | |
616 | + max_consoles = 0; | |
617 | + | |
618 | + res = setttyent (); | |
619 | + if (res == 0) { | |
620 | + goto done; | |
621 | + } | |
622 | + | |
623 | + while ((t = getttyent ()) != NULL) { | |
624 | + if (t->ty_status & TTY_ON && strncmp (t->ty_name, "tty", 3) == 0) | |
625 | + max_consoles++; | |
626 | + } | |
627 | + | |
628 | + /* Increment one more so that all consoles are properly counted | |
629 | + * this is arguable a bug in vt_add_watches(). | |
630 | + */ | |
631 | + max_consoles++; | |
632 | + | |
633 | + ret = TRUE; | |
634 | + | |
635 | + endttyent (); | |
636 | + | |
637 | +done: | |
638 | + if (num != NULL) { | |
639 | + *num = max_consoles; | |
640 | + } | |
641 | + | |
642 | + return ret; | |
643 | +} | |
644 | + | |
645 | +gboolean | |
646 | +ck_supports_activatable_consoles (void) | |
647 | +{ | |
648 | + return TRUE; | |
649 | +} | |
650 | + | |
651 | +char * | |
652 | +ck_get_console_device_for_num (guint num) | |
653 | +{ | |
654 | + char *device; | |
655 | + | |
656 | + device = g_strdup_printf (_PATH_TTY "%u", num); | |
657 | + | |
658 | + return device; | |
659 | +} | |
660 | + | |
661 | +gboolean | |
662 | +ck_get_console_num_from_device (const char *device, | |
663 | + guint *num) | |
664 | +{ | |
665 | + guint n; | |
666 | + gboolean ret; | |
667 | + | |
668 | + n = 0; | |
669 | + ret = FALSE; | |
670 | + | |
671 | + if (device == NULL) { | |
672 | + return FALSE; | |
673 | + } | |
674 | + | |
675 | + if (sscanf (device, _PATH_TTY "%u", &n) == 1) { | |
676 | + ret = TRUE; | |
677 | + } | |
678 | + | |
679 | + if (num != NULL) { | |
680 | + *num = n; | |
681 | + } | |
682 | + | |
683 | + return ret; | |
684 | +} | |
685 | + | |
686 | +gboolean | |
687 | +ck_get_active_console_num (int console_fd, | |
688 | + guint *num) | |
689 | +{ | |
690 | + gboolean ret; | |
691 | + int res; | |
692 | + long cur_active; | |
693 | + char buf[30]; | |
694 | + guint active; | |
695 | + | |
696 | + g_assert (console_fd != -1); | |
697 | + | |
698 | + active = 0; | |
699 | + ret = FALSE; | |
700 | + | |
701 | + res = readlink ("/dev/cons/vcs", buf, sizeof (buf)); | |
702 | + if (res > 0) { | |
703 | + /* the resolved path is like "/dev/vcs/$number", so skip | |
704 | + the non-number part at the start */ | |
705 | + const char *p = buf; | |
706 | + while ((*p) && ((*p < '0') || (*p > '9'))) { | |
707 | + ++p; | |
708 | + } | |
709 | + if (*p) { | |
710 | + cur_active = strtol (p, NULL, 10); | |
711 | + g_debug ("Current VT: tty%ld", cur_active); | |
712 | + active = cur_active; | |
713 | + ret = TRUE; | |
714 | + } | |
715 | + } | |
716 | + | |
717 | + if (num != NULL) { | |
718 | + *num = active; | |
719 | + } | |
720 | + | |
721 | + return ret; | |
722 | +} | |
723 | diff --git a/tools/70-udev-acl.rules b/tools/70-udev-acl.rules | |
724 | new file mode 100644 | |
725 | index 0000000..2dac283 | |
726 | --- /dev/null | |
727 | +++ b/tools/70-udev-acl.rules | |
728 | @@ -0,0 +1,76 @@ | |
729 | +# do not edit this file, it will be overwritten on update | |
730 | + | |
731 | +# Do not use TAG+="udev-acl" outside of this file. This variable is private to | |
732 | +# udev-acl of this udev release and may be replaced at any time. | |
733 | + | |
734 | +ENV{MAJOR}=="", GOTO="acl_end" | |
735 | +ACTION=="remove", GOTO="acl_apply" | |
736 | + | |
737 | +# systemd replaces udev-acl entirely, skip if active | |
738 | +TEST=="/sys/fs/cgroup/systemd", TAG=="uaccess", GOTO="acl_end" | |
739 | + | |
740 | +# PTP/MTP protocol devices, cameras, portable media players | |
741 | +SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="udev-acl" | |
742 | + | |
743 | +# digicams with proprietary protocol | |
744 | +ENV{ID_GPHOTO2}=="*?", TAG+="udev-acl" | |
745 | + | |
746 | +# SCSI and USB scanners | |
747 | +ENV{libsane_matched}=="yes", TAG+="udev-acl" | |
748 | + | |
749 | +# HPLIP devices (necessary for ink level check and HP tool maintenance) | |
750 | +ENV{ID_HPLIP}=="1", TAG+="udev-acl" | |
751 | + | |
752 | +# optical drives | |
753 | +SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="udev-acl" | |
754 | +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="udev-acl" | |
755 | + | |
756 | +# sound devices | |
757 | +SUBSYSTEM=="sound", TAG+="udev-acl" | |
758 | + | |
759 | +# ffado is an userspace driver for firewire sound cards | |
760 | +SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="udev-acl" | |
761 | + | |
762 | +# webcams, frame grabber, TV cards | |
763 | +SUBSYSTEM=="video4linux", TAG+="udev-acl" | |
764 | +SUBSYSTEM=="dvb", TAG+="udev-acl" | |
765 | + | |
766 | +# IIDC devices: industrial cameras and some webcams | |
767 | +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="udev-acl" | |
768 | +SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="udev-acl" | |
769 | +# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more | |
770 | +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="udev-acl" | |
771 | +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="udev-acl" | |
772 | + | |
773 | +# DRI video devices | |
774 | +SUBSYSTEM=="drm", KERNEL=="card*", TAG+="udev-acl" | |
775 | + | |
776 | +# KVM | |
777 | +SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="udev-acl" | |
778 | + | |
779 | +# smart-card readers | |
780 | +ENV{ID_SMARTCARD_READER}=="*?", TAG+="udev-acl" | |
781 | + | |
782 | +# PDA devices | |
783 | +ENV{ID_PDA}=="*?", TAG+="udev-acl" | |
784 | + | |
785 | +# Programmable remote control | |
786 | +ENV{ID_REMOTE_CONTROL}=="1", TAG+="udev-acl" | |
787 | + | |
788 | +# joysticks | |
789 | +SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="udev-acl" | |
790 | + | |
791 | +# color measurement devices | |
792 | +ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="udev-acl" | |
793 | + | |
794 | +# DDC/CI device, usually high-end monitors such as the DreamColor | |
795 | +ENV{DDC_DEVICE}=="*?", TAG+="udev-acl" | |
796 | + | |
797 | +# media player raw devices (for user-mode drivers, Android SDK, etc.) | |
798 | +SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="udev-acl" | |
799 | + | |
800 | +# apply ACL for all locally logged in users | |
801 | +LABEL="acl_apply", TAG=="udev-acl", TEST=="/var/run/ConsoleKit/database", \ | |
802 | + RUN+="udev-acl --action=$env{ACTION} --device=$env{DEVNAME}" | |
803 | + | |
804 | +LABEL="acl_end" | |
805 | diff --git a/tools/Makefile.am b/tools/Makefile.am | |
806 | index 13c191f..88f3c91 100644 | |
807 | --- a/tools/Makefile.am | |
808 | +++ b/tools/Makefile.am | |
809 | @@ -143,6 +143,21 @@ ck_get_x11_display_device_LDADD = \ | |
810 | $(top_builddir)/src/libck.la \ | |
811 | $(NULL) | |
812 | ||
813 | +if ENABLE_UDEV_ACL | |
814 | +udevdir = $(UDEVDIR) | |
815 | +udevrulesdir = $(UDEVDIR)/rules.d | |
816 | + | |
817 | +dist_udevrules_DATA = 70-udev-acl.rules | |
818 | +udev_PROGRAMS = udev-acl | |
819 | + | |
820 | +udev_acl_SOURCES = udev-acl.c | |
821 | +udev_acl_LDADD = $(UDEV_ACL_LIBS) | |
822 | +udev_acl_CFLAGS = $(UDEV_ACL_CFLAGS) | |
823 | + | |
824 | +install-exec-hook: | |
825 | + mkdir -p $(DESTDIR)$(prefix)/lib/ConsoleKit/run-seat.d | |
826 | + ln -sf $(UDEVDIR)/udev-acl $(DESTDIR)$(prefix)/lib/ConsoleKit/run-seat.d/udev-acl.ck | |
827 | +endif | |
828 | ||
829 | EXTRA_DIST = \ | |
830 | $(NULL) | |
831 | diff --git a/tools/ck-history.c b/tools/ck-history.c | |
832 | index d02caaa..85d9e6f 100644 | |
833 | --- a/tools/ck-history.c | |
834 | +++ b/tools/ck-history.c | |
835 | @@ -804,7 +804,7 @@ generate_report_frequent (int uid, | |
836 | data = user_counts->data; | |
837 | ||
838 | username = get_user_name_for_uid (data->uid); | |
839 | - g_print ("%-8.8s %u\n", username, data->count); | |
840 | + g_print ("%-8s %u\n", username, data->count); | |
841 | g_free (data); | |
842 | user_counts = g_list_delete_link (user_counts, user_counts); | |
843 | g_free (username); | |
844 | diff --git a/tools/udev-acl.c b/tools/udev-acl.c | |
845 | new file mode 100644 | |
846 | index 0000000..628cfbe | |
847 | --- /dev/null | |
848 | +++ b/tools/udev-acl.c | |
849 | @@ -0,0 +1,430 @@ | |
850 | +/* | |
851 | + * Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org> | |
852 | + * | |
853 | + * This program is free software; you can redistribute it and/or | |
854 | + * modify it under the terms of the GNU General Public License as | |
855 | + * published by the Free Software Foundation; either version 2 of the | |
856 | + * License, or (at your option) any later version. | |
857 | + * | |
858 | + * This program is distributed in the hope that it will be useful, but | |
859 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
860 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
861 | + * General Public License for more details: | |
862 | + */ | |
863 | + | |
864 | +#include <acl/libacl.h> | |
865 | +#include <sys/stat.h> | |
866 | +#include <errno.h> | |
867 | +#include <getopt.h> | |
868 | +#include <glib.h> | |
869 | +#include <inttypes.h> | |
870 | +#include <libudev.h> | |
871 | +#include <stdbool.h> | |
872 | +#include <stdio.h> | |
873 | +#include <stdlib.h> | |
874 | +#include <string.h> | |
875 | +#include <unistd.h> | |
876 | + | |
877 | +static int debug; | |
878 | + | |
879 | +enum{ | |
880 | + ACTION_NONE = 0, | |
881 | + ACTION_REMOVE, | |
882 | + ACTION_ADD, | |
883 | + ACTION_CHANGE | |
884 | +}; | |
885 | + | |
886 | +static int set_facl(const char* filename, uid_t uid, int add) | |
887 | +{ | |
888 | + int get; | |
889 | + acl_t acl; | |
890 | + acl_entry_t entry = NULL; | |
891 | + acl_entry_t e; | |
892 | + acl_permset_t permset; | |
893 | + int ret; | |
894 | + | |
895 | + /* don't touch ACLs for root */ | |
896 | + if (uid == 0) | |
897 | + return 0; | |
898 | + | |
899 | + /* read current record */ | |
900 | + acl = acl_get_file(filename, ACL_TYPE_ACCESS); | |
901 | + if (!acl) | |
902 | + return -1; | |
903 | + | |
904 | + /* locate ACL_USER entry for uid */ | |
905 | + get = acl_get_entry(acl, ACL_FIRST_ENTRY, &e); | |
906 | + while (get == 1) { | |
907 | + acl_tag_t t; | |
908 | + | |
909 | + acl_get_tag_type(e, &t); | |
910 | + if (t == ACL_USER) { | |
911 | + uid_t *u; | |
912 | + | |
913 | + u = (uid_t*)acl_get_qualifier(e); | |
914 | + if (u == NULL) { | |
915 | + ret = -1; | |
916 | + goto out; | |
917 | + } | |
918 | + if (*u == uid) { | |
919 | + entry = e; | |
920 | + acl_free(u); | |
921 | + break; | |
922 | + } | |
923 | + acl_free(u); | |
924 | + } | |
925 | + | |
926 | + get = acl_get_entry(acl, ACL_NEXT_ENTRY, &e); | |
927 | + } | |
928 | + | |
929 | + /* remove ACL_USER entry for uid */ | |
930 | + if (!add) { | |
931 | + if (entry == NULL) { | |
932 | + ret = 0; | |
933 | + goto out; | |
934 | + } | |
935 | + acl_delete_entry(acl, entry); | |
936 | + goto update; | |
937 | + } | |
938 | + | |
939 | + /* create ACL_USER entry for uid */ | |
940 | + if (entry == NULL) { | |
941 | + ret = acl_create_entry(&acl, &entry); | |
942 | + if (ret != 0) | |
943 | + goto out; | |
944 | + acl_set_tag_type(entry, ACL_USER); | |
945 | + acl_set_qualifier(entry, &uid); | |
946 | + } | |
947 | + | |
948 | + /* add permissions for uid */ | |
949 | + acl_get_permset(entry, &permset); | |
950 | + acl_add_perm(permset, ACL_READ|ACL_WRITE); | |
951 | +update: | |
952 | + /* update record */ | |
953 | + if (debug) | |
954 | + printf("%c%u %s\n", add ? '+' : '-', uid, filename); | |
955 | + acl_calc_mask(&acl); | |
956 | + ret = acl_set_file(filename, ACL_TYPE_ACCESS, acl); | |
957 | + if (ret != 0) | |
958 | + goto out; | |
959 | +out: | |
960 | + acl_free(acl); | |
961 | + return ret; | |
962 | +} | |
963 | + | |
964 | +/* check if a given uid is listed */ | |
965 | +static int uid_in_list(GSList *list, uid_t uid) | |
966 | +{ | |
967 | + GSList *l; | |
968 | + | |
969 | + for (l = list; l != NULL; l = g_slist_next(l)) | |
970 | + if (uid == GPOINTER_TO_UINT(l->data)) | |
971 | + return 1; | |
972 | + return 0; | |
973 | +} | |
974 | + | |
975 | +/* return list of current uids of local active sessions */ | |
976 | +static GSList *uids_with_local_active_session(const char *own_id) | |
977 | +{ | |
978 | + GSList *list = NULL; | |
979 | + GKeyFile *keyfile; | |
980 | + | |
981 | + keyfile = g_key_file_new(); | |
982 | + if (g_key_file_load_from_file(keyfile, "/var/run/ConsoleKit/database", 0, NULL)) { | |
983 | + gchar **groups; | |
984 | + | |
985 | + groups = g_key_file_get_groups(keyfile, NULL); | |
986 | + if (groups != NULL) { | |
987 | + int i; | |
988 | + | |
989 | + for (i = 0; groups[i] != NULL; i++) { | |
990 | + uid_t u; | |
991 | + | |
992 | + if (!g_str_has_prefix(groups[i], "Session ")) | |
993 | + continue; | |
994 | + if (own_id != NULL &&g_str_has_suffix(groups[i], own_id)) | |
995 | + continue; | |
996 | + if (!g_key_file_get_boolean(keyfile, groups[i], "is_local", NULL)) | |
997 | + continue; | |
998 | + if (!g_key_file_get_boolean(keyfile, groups[i], "is_active", NULL)) | |
999 | + continue; | |
1000 | + u = g_key_file_get_integer(keyfile, groups[i], "uid", NULL); | |
1001 | + if (u > 0 && !uid_in_list(list, u)) | |
1002 | + list = g_slist_prepend(list, GUINT_TO_POINTER(u)); | |
1003 | + } | |
1004 | + g_strfreev(groups); | |
1005 | + } | |
1006 | + } | |
1007 | + g_key_file_free(keyfile); | |
1008 | + | |
1009 | + return list; | |
1010 | +} | |
1011 | + | |
1012 | +/* ConsoleKit calls us with special variables */ | |
1013 | +static int consolekit_called(const char *ck_action, uid_t *uid, uid_t *uid2, const char **remove_session_id, int *action) | |
1014 | +{ | |
1015 | + int a = ACTION_NONE; | |
1016 | + uid_t u = 0; | |
1017 | + uid_t u2 = 0; | |
1018 | + const char *s; | |
1019 | + const char *s2; | |
1020 | + const char *old_session = NULL; | |
1021 | + | |
1022 | + if (ck_action == NULL || strcmp(ck_action, "seat_active_session_changed") != 0) | |
1023 | + return -1; | |
1024 | + | |
1025 | + /* We can have one of: remove, add, change, no-change */ | |
1026 | + s = getenv("CK_SEAT_OLD_SESSION_ID"); | |
1027 | + s2 = getenv("CK_SEAT_SESSION_ID"); | |
1028 | + if (s == NULL && s2 == NULL) { | |
1029 | + return -1; | |
1030 | + } else if (s2 == NULL) { | |
1031 | + a = ACTION_REMOVE; | |
1032 | + } else if (s == NULL) { | |
1033 | + a = ACTION_ADD; | |
1034 | + } else { | |
1035 | + a = ACTION_CHANGE; | |
1036 | + } | |
1037 | + | |
1038 | + switch (a) { | |
1039 | + case ACTION_ADD: | |
1040 | + s = getenv("CK_SEAT_SESSION_USER_UID"); | |
1041 | + if (s == NULL) | |
1042 | + return -1; | |
1043 | + u = strtoul(s, NULL, 10); | |
1044 | + | |
1045 | + s = getenv("CK_SEAT_SESSION_IS_LOCAL"); | |
1046 | + if (s == NULL) | |
1047 | + return -1; | |
1048 | + if (strcmp(s, "true") != 0) | |
1049 | + return 0; | |
1050 | + | |
1051 | + break; | |
1052 | + case ACTION_REMOVE: | |
1053 | + s = getenv("CK_SEAT_OLD_SESSION_USER_UID"); | |
1054 | + if (s == NULL) | |
1055 | + return -1; | |
1056 | + u = strtoul(s, NULL, 10); | |
1057 | + | |
1058 | + s = getenv("CK_SEAT_OLD_SESSION_IS_LOCAL"); | |
1059 | + if (s == NULL) | |
1060 | + return -1; | |
1061 | + if (strcmp(s, "true") != 0) | |
1062 | + return 0; | |
1063 | + | |
1064 | + old_session = getenv("CK_SEAT_OLD_SESSION_ID"); | |
1065 | + if (old_session == NULL) | |
1066 | + return -1; | |
1067 | + | |
1068 | + break; | |
1069 | + case ACTION_CHANGE: | |
1070 | + s = getenv("CK_SEAT_OLD_SESSION_USER_UID"); | |
1071 | + if (s == NULL) | |
1072 | + return -1; | |
1073 | + u = strtoul(s, NULL, 10); | |
1074 | + s = getenv("CK_SEAT_SESSION_USER_UID"); | |
1075 | + if (s == NULL) | |
1076 | + return -1; | |
1077 | + u2 = strtoul(s, NULL, 10); | |
1078 | + | |
1079 | + s = getenv("CK_SEAT_OLD_SESSION_IS_LOCAL"); | |
1080 | + s2 = getenv("CK_SEAT_SESSION_IS_LOCAL"); | |
1081 | + if (s == NULL || s2 == NULL) | |
1082 | + return -1; | |
1083 | + /* don't process non-local session changes */ | |
1084 | + if (strcmp(s, "true") != 0 && strcmp(s2, "true") != 0) | |
1085 | + return 0; | |
1086 | + | |
1087 | + if (strcmp(s, "true") == 0 && strcmp(s, "true") == 0) { | |
1088 | + /* process the change */ | |
1089 | + if (u == u2) { | |
1090 | + /* special case: we noop if we are | |
1091 | + * changing between local sessions for | |
1092 | + * the same uid */ | |
1093 | + a = ACTION_NONE; | |
1094 | + } | |
1095 | + old_session = getenv("CK_SEAT_OLD_SESSION_ID"); | |
1096 | + if (old_session == NULL) | |
1097 | + return -1; | |
1098 | + } else if (strcmp(s, "true") == 0) { | |
1099 | + /* only process the removal */ | |
1100 | + a = ACTION_REMOVE; | |
1101 | + old_session = getenv("CK_SEAT_OLD_SESSION_ID"); | |
1102 | + if (old_session == NULL) | |
1103 | + return -1; | |
1104 | + } else if (strcmp(s2, "true") == 0) { | |
1105 | + /* only process the addition */ | |
1106 | + a = ACTION_ADD; | |
1107 | + u = u2; | |
1108 | + } | |
1109 | + break; | |
1110 | + } | |
1111 | + | |
1112 | + *remove_session_id = old_session; | |
1113 | + *uid = u; | |
1114 | + *uid2 = u2; | |
1115 | + *action = a; | |
1116 | + return 0; | |
1117 | +} | |
1118 | + | |
1119 | +/* add or remove a ACL for a given uid from all matching devices */ | |
1120 | +static void apply_acl_to_devices(uid_t uid, int add) | |
1121 | +{ | |
1122 | + struct udev *udev; | |
1123 | + struct udev_enumerate *enumerate; | |
1124 | + struct udev_list_entry *list_entry; | |
1125 | + | |
1126 | + /* iterate over all devices tagged with ACL_SET */ | |
1127 | + udev = udev_new(); | |
1128 | + enumerate = udev_enumerate_new(udev); | |
1129 | + udev_enumerate_add_match_tag(enumerate, "udev-acl"); | |
1130 | + udev_enumerate_scan_devices(enumerate); | |
1131 | + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { | |
1132 | + struct udev_device *device; | |
1133 | + const char *node; | |
1134 | + | |
1135 | + device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), | |
1136 | + udev_list_entry_get_name(list_entry)); | |
1137 | + if (device == NULL) | |
1138 | + continue; | |
1139 | + node = udev_device_get_devnode(device); | |
1140 | + if (node == NULL) { | |
1141 | + udev_device_unref(device); | |
1142 | + continue; | |
1143 | + } | |
1144 | + set_facl(node, uid, add); | |
1145 | + udev_device_unref(device); | |
1146 | + } | |
1147 | + udev_enumerate_unref(enumerate); | |
1148 | + udev_unref(udev); | |
1149 | +} | |
1150 | + | |
1151 | +static void | |
1152 | +remove_uid (uid_t uid, const char *remove_session_id) | |
1153 | +{ | |
1154 | + /* | |
1155 | + * Remove ACL for given uid from all matching devices | |
1156 | + * when there is currently no local active session. | |
1157 | + */ | |
1158 | + GSList *list; | |
1159 | + | |
1160 | + list = uids_with_local_active_session(remove_session_id); | |
1161 | + if (!uid_in_list(list, uid)) | |
1162 | + apply_acl_to_devices(uid, 0); | |
1163 | + g_slist_free(list); | |
1164 | +} | |
1165 | + | |
1166 | +int main (int argc, char* argv[]) | |
1167 | +{ | |
1168 | + static const struct option options[] = { | |
1169 | + { "action", required_argument, NULL, 'a' }, | |
1170 | + { "device", required_argument, NULL, 'D' }, | |
1171 | + { "user", required_argument, NULL, 'u' }, | |
1172 | + { "debug", no_argument, NULL, 'd' }, | |
1173 | + { "help", no_argument, NULL, 'h' }, | |
1174 | + {} | |
1175 | + }; | |
1176 | + int action = -1; | |
1177 | + const char *device = NULL; | |
1178 | + bool uid_given = false; | |
1179 | + uid_t uid = 0; | |
1180 | + uid_t uid2 = 0; | |
1181 | + const char* remove_session_id = NULL; | |
1182 | + int rc = 0; | |
1183 | + | |
1184 | + /* valgrind is more important to us than a slice allocator */ | |
1185 | + g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, 1); | |
1186 | + | |
1187 | + while (1) { | |
1188 | + int option; | |
1189 | + | |
1190 | + option = getopt_long(argc, argv, "+a:D:u:dh", options, NULL); | |
1191 | + if (option == -1) | |
1192 | + break; | |
1193 | + | |
1194 | + switch (option) { | |
1195 | + case 'a': | |
1196 | + if (strcmp(optarg, "remove") == 0) | |
1197 | + action = ACTION_REMOVE; | |
1198 | + else | |
1199 | + action = ACTION_ADD; | |
1200 | + break; | |
1201 | + case 'D': | |
1202 | + device = optarg; | |
1203 | + break; | |
1204 | + case 'u': | |
1205 | + uid_given = true; | |
1206 | + uid = strtoul(optarg, NULL, 10); | |
1207 | + break; | |
1208 | + case 'd': | |
1209 | + debug = 1; | |
1210 | + break; | |
1211 | + case 'h': | |
1212 | + printf("Usage: udev-acl --action=ACTION [--device=DEVICEFILE] [--user=UID]\n\n"); | |
1213 | + goto out; | |
1214 | + } | |
1215 | + } | |
1216 | + | |
1217 | + if (action < 0 && device == NULL && !uid_given) | |
1218 | + if (!consolekit_called(argv[optind], &uid, &uid2, &remove_session_id, &action)) | |
1219 | + uid_given = true; | |
1220 | + | |
1221 | + if (action < 0) { | |
1222 | + fprintf(stderr, "missing action\n\n"); | |
1223 | + rc = 2; | |
1224 | + goto out; | |
1225 | + } | |
1226 | + | |
1227 | + if (device != NULL && uid_given) { | |
1228 | + fprintf(stderr, "only one option, --device=DEVICEFILE or --user=UID expected\n\n"); | |
1229 | + rc = 3; | |
1230 | + goto out; | |
1231 | + } | |
1232 | + | |
1233 | + if (uid_given) { | |
1234 | + switch (action) { | |
1235 | + case ACTION_ADD: | |
1236 | + /* Add ACL for given uid to all matching devices. */ | |
1237 | + apply_acl_to_devices(uid, 1); | |
1238 | + break; | |
1239 | + case ACTION_REMOVE: | |
1240 | + remove_uid(uid, remove_session_id); | |
1241 | + break; | |
1242 | + case ACTION_CHANGE: | |
1243 | + remove_uid(uid, remove_session_id); | |
1244 | + apply_acl_to_devices(uid2, 1); | |
1245 | + break; | |
1246 | + case ACTION_NONE: | |
1247 | + goto out; | |
1248 | + break; | |
1249 | + default: | |
1250 | + g_assert_not_reached(); | |
1251 | + break; | |
1252 | + } | |
1253 | + } else if (device != NULL) { | |
1254 | + /* | |
1255 | + * Add ACLs for all current session uids to a given device. | |
1256 | + * | |
1257 | + * Or remove ACLs for uids which do not have any current local | |
1258 | + * active session. Remove is not really interesting, because in | |
1259 | + * most cases the device node is removed anyway. | |
1260 | + */ | |
1261 | + GSList *list; | |
1262 | + GSList *l; | |
1263 | + | |
1264 | + list = uids_with_local_active_session(NULL); | |
1265 | + for (l = list; l != NULL; l = g_slist_next(l)) { | |
1266 | + uid_t u; | |
1267 | + | |
1268 | + u = GPOINTER_TO_UINT(l->data); | |
1269 | + if (action == ACTION_ADD || !uid_in_list(list, u)) | |
1270 | + set_facl(device, u, action == ACTION_ADD); | |
1271 | + } | |
1272 | + g_slist_free(list); | |
1273 | + } else { | |
1274 | + fprintf(stderr, "--device=DEVICEFILE or --user=UID expected\n\n"); | |
1275 | + rc = 3; | |
1276 | + } | |
1277 | +out: | |
1278 | + return rc; | |
1279 | +} |