chiark / gitweb /
logind: add new loginctl lock-sessions command
[elogind.git] / src / login / loginctl.c
index 7e0056c..b80b2e6 100644 (file)
@@ -6,16 +6,16 @@
   Copyright 2010 Lennart Poettering
 
   systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
   (at your option) any later version.
 
   systemd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
+  Lesser General Public License for more details.
 
-  You should have received a copy of the GNU General Public License
+  You should have received a copy of the GNU Lesser General Public License
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
@@ -35,6 +35,7 @@
 #include "strv.h"
 #include "cgroup-show.h"
 #include "sysfs-show.h"
+#include "spawn-polkit-agent.h"
 
 static char **arg_property = NULL;
 static bool arg_all = false;
@@ -46,6 +47,7 @@ static enum transport {
         TRANSPORT_SSH,
         TRANSPORT_POLKIT
 } arg_transport = TRANSPORT_NORMAL;
+static bool arg_ask_password = true;
 static const char *arg_host = NULL;
 
 static bool on_tty(void) {
@@ -68,8 +70,20 @@ static void pager_open_if_enabled(void) {
         /* Cache result before we open the pager */
         on_tty();
 
-        if (!arg_no_pager)
-                pager_open();
+        if (arg_no_pager)
+                return;
+
+        pager_open();
+}
+
+static void polkit_agent_open_if_enabled(void) {
+
+        /* Open the polkit agent as a child process if necessary */
+
+        if (!arg_ask_password)
+                return;
+
+        polkit_agent_open();
 }
 
 static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
@@ -338,7 +352,7 @@ typedef struct SessionStatusInfo {
         uid_t uid;
         const char *name;
         usec_t timestamp;
-        const char *control_group;
+        const char *default_control_group;
         int vtnr;
         const char *seat;
         const char *tty;
@@ -349,14 +363,15 @@ typedef struct SessionStatusInfo {
         const char *service;
         pid_t leader;
         const char *type;
-        bool active;
+        const char *class;
+        const char *state;
 } SessionStatusInfo;
 
 typedef struct UserStatusInfo {
         uid_t uid;
         const char *name;
         usec_t timestamp;
-        const char *control_group;
+        const char *default_control_group;
         const char *state;
         char **sessions;
         const char *display;
@@ -431,16 +446,25 @@ static void print_session_status_info(SessionStatusInfo *i) {
                 if (i->type)
                         printf("; type %s", i->type);
 
+                if (i->class)
+                        printf("; class %s", i->class);
+
                 printf("\n");
-        } else if (i->type)
+        } else if (i->type) {
                 printf("\t    Type: %s\n", i->type);
 
-        printf("\t  Active: %s\n", yes_no(i->active));
+                if (i->class)
+                        printf("; class %s", i->class);
+        } else if (i->class)
+                printf("\t   Class: %s\n", i->class);
+
+        if (i->state)
+                printf("\t   State: %s\n", i->state);
 
-        if (i->control_group) {
+        if (i->default_control_group) {
                 unsigned c;
 
-                printf("\t  CGroup: %s\n", i->control_group);
+                printf("\t  CGroup: %s\n", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         c = columns();
@@ -449,7 +473,7 @@ static void print_session_status_info(SessionStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false);
+                        show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, arg_all, &i->leader, i->leader > 0 ? 1 : 0);
                 }
         }
 }
@@ -489,10 +513,10 @@ static void print_user_status_info(UserStatusInfo *i) {
                 printf("\n");
         }
 
-        if (i->control_group) {
+        if (i->default_control_group) {
                 unsigned c;
 
-                printf("\t  CGroup: %s\n", i->control_group);
+                printf("\t  CGroup: %s\n", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         c = columns();
@@ -501,7 +525,7 @@ static void print_user_status_info(UserStatusInfo *i) {
                         else
                                 c = 0;
 
-                        show_cgroup_by_path(i->control_group, "\t\t  ", c, false);
+                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false, arg_all);
                 }
         }
 }
@@ -557,8 +581,8 @@ static int status_property_session(const char *name, DBusMessageIter *iter, Sess
                                 i->id = s;
                         else if (streq(name, "Name"))
                                 i->name = s;
-                        else if (streq(name, "ControlGroupPath"))
-                                i->control_group = s;
+                        else if (streq(name, "DefaultControlGroup"))
+                                i->default_control_group = s;
                         else if (streq(name, "TTY"))
                                 i->tty = s;
                         else if (streq(name, "Display"))
@@ -571,6 +595,10 @@ static int status_property_session(const char *name, DBusMessageIter *iter, Sess
                                 i->service = s;
                         else if (streq(name, "Type"))
                                 i->type = s;
+                        else if (streq(name, "Class"))
+                                i->class = s;
+                        else if (streq(name, "State"))
+                                i->state = s;
                 }
                 break;
         }
@@ -595,8 +623,6 @@ static int status_property_session(const char *name, DBusMessageIter *iter, Sess
 
                 if (streq(name, "Remote"))
                         i->remote = b;
-                else if (streq(name, "Active"))
-                        i->active = b;
 
                 break;
         }
@@ -654,8 +680,8 @@ static int status_property_user(const char *name, DBusMessageIter *iter, UserSta
                 if (!isempty(s)) {
                         if (streq(name, "Name"))
                                 i->name = s;
-                        else if (streq(name, "ControlGroupPath"))
-                                i->control_group = s;
+                        else if (streq(name, "DefaultControlGroup"))
+                                i->default_control_group = s;
                         else if (streq(name, "State"))
                                 i->state = s;
                 }
@@ -1063,7 +1089,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                         uid_t uid;
                         uint32_t u;
 
-                        ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                        ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
                         if (ret < 0) {
                                 log_error("User %s unknown.", args[i]);
                                 goto finish;
@@ -1234,7 +1260,7 @@ static int kill_session(DBusConnection *bus, char **args, unsigned n) {
                 if (!dbus_message_append_args(m,
                                               DBUS_TYPE_STRING, &args[i],
                                               DBUS_TYPE_STRING, &arg_kill_who,
-                                              DBUS_TYPE_INT32, arg_signal,
+                                              DBUS_TYPE_INT32, &arg_signal,
                                               DBUS_TYPE_INVALID)) {
                         log_error("Could not append arguments to message.");
                         ret = -ENOMEM;
@@ -1274,6 +1300,8 @@ static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
+        polkit_agent_open_if_enabled();
+
         b = streq(args[0], "enable-linger");
 
         for (i = 1; i < n; i++) {
@@ -1292,7 +1320,7 @@ static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
                         goto finish;
                 }
 
-                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
                 if (ret < 0) {
                         log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
                         goto finish;
@@ -1359,7 +1387,7 @@ static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
                         goto finish;
                 }
 
-                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
                 if (ret < 0) {
                         log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
                         goto finish;
@@ -1427,7 +1455,7 @@ static int kill_user(DBusConnection *bus, char **args, unsigned n) {
                         goto finish;
                 }
 
-                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
+                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
                 if (ret < 0) {
                         log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
                         goto finish;
@@ -1436,7 +1464,7 @@ static int kill_user(DBusConnection *bus, char **args, unsigned n) {
                 u = (uint32_t) uid;
                 if (!dbus_message_append_args(m,
                                               DBUS_TYPE_UINT32, &u,
-                                              DBUS_TYPE_INT32, arg_signal,
+                                              DBUS_TYPE_INT32, &arg_signal,
                                               DBUS_TYPE_INVALID)) {
                         log_error("Could not append arguments to message.");
                         ret = -ENOMEM;
@@ -1478,6 +1506,8 @@ static int attach(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
+        polkit_agent_open_if_enabled();
+
         for (i = 2; i < n; i++) {
                 DBusMessage *reply;
 
@@ -1534,6 +1564,8 @@ static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
+        polkit_agent_open_if_enabled();
+
         m = dbus_message_new_method_call(
                         "org.freedesktop.login1",
                         "/org/freedesktop/login1",
@@ -1572,6 +1604,48 @@ finish:
         return ret;
 }
 
+static int lock_sessions(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        int ret = 0;
+        DBusError error;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        polkit_agent_open_if_enabled();
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "LockSessions");
+        if (!m) {
+                log_error("Could not allocate message.");
+                ret = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                ret = -EIO;
+                goto finish;
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return ret;
+}
+
 static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
         DBusMessage *m = NULL;
         int ret = 0;
@@ -1647,6 +1721,7 @@ static int help(void) {
                "  activate [ID]                   Activate a session\n"
                "  lock-session [ID...]            Screen lock one or more sessions\n"
                "  unlock-session [ID...]          Screen unlock one or more sessions\n"
+               "  lock-sessions                   Screen lock all current sessions\n"
                "  terminate-session [ID...]       Terminate one or more sessions\n"
                "  kill-session [ID...]            Send signal to processes of a session\n"
                "  list-users                      List users\n"
@@ -1672,7 +1747,8 @@ static int parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_VERSION = 0x100,
                 ARG_NO_PAGER,
-                ARG_KILL_WHO
+                ARG_KILL_WHO,
+                ARG_NO_ASK_PASSWORD
         };
 
         static const struct option options[] = {
@@ -1685,6 +1761,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "signal",    required_argument, NULL, 's'           },
                 { "host",      required_argument, NULL, 'H'           },
                 { "privileged",no_argument,       NULL, 'P'           },
+                { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -1732,6 +1809,9 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_no_pager = true;
                         break;
 
+                case ARG_NO_ASK_PASSWORD:
+                        arg_ask_password = false;
+
                 case ARG_KILL_WHO:
                         arg_kill_who = optarg;
                         break;
@@ -1783,6 +1863,7 @@ static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "activate",              EQUAL,  2, activate         },
                 { "lock-session",          MORE,   2, activate         },
                 { "unlock-session",        MORE,   2, activate         },
+                { "lock-sessions",         EQUAL,  1, lock_sessions    },
                 { "terminate-session",     MORE,   2, activate         },
                 { "kill-session",          MORE,   2, kill_session     },
                 { "list-users",            EQUAL,  1, list_users       },