chiark / gitweb /
logind: open up most bus calls for unpriviliged processes, using PolicyKit
[elogind.git] / src / login / loginctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <getopt.h>
26 #include <pwd.h>
27 #include <locale.h>
28
29 #include "sd-bus.h"
30 #include "bus-util.h"
31 #include "bus-error.h"
32 #include "log.h"
33 #include "util.h"
34 #include "macro.h"
35 #include "pager.h"
36 #include "build.h"
37 #include "strv.h"
38 #include "unit-name.h"
39 #include "sysfs-show.h"
40 #include "logs-show.h"
41 #include "cgroup-show.h"
42 #include "cgroup-util.h"
43 #include "spawn-polkit-agent.h"
44 #include "verbs.h"
45
46 static char **arg_property = NULL;
47 static bool arg_all = false;
48 static bool arg_full = false;
49 static bool arg_no_pager = false;
50 static bool arg_legend = true;
51 static const char *arg_kill_who = NULL;
52 static int arg_signal = SIGTERM;
53 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
54 static char *arg_host = NULL;
55 static bool arg_ask_password = true;
56 static unsigned arg_lines = 10;
57 static OutputMode arg_output = OUTPUT_SHORT;
58
59 static void pager_open_if_enabled(void) {
60
61         if (arg_no_pager)
62                 return;
63
64         pager_open(false);
65 }
66
67 static void polkit_agent_open_if_enabled(void) {
68
69         /* Open the polkit agent as a child process if necessary */
70
71         if (!arg_ask_password)
72                 return;
73
74         if (arg_transport != BUS_TRANSPORT_LOCAL)
75                 return;
76
77         polkit_agent_open();
78 }
79
80 static OutputFlags get_output_flags(void) {
81
82         return
83                 arg_all * OUTPUT_SHOW_ALL |
84                 arg_full * OUTPUT_FULL_WIDTH |
85                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
86                 on_tty() * OUTPUT_COLOR;
87 }
88
89 static int list_sessions(int argc, char *argv[], void *userdata) {
90         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
91         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
92         const char *id, *user, *seat, *object;
93         sd_bus *bus = userdata;
94         unsigned k = 0;
95         uint32_t uid;
96         int r;
97
98         assert(bus);
99         assert(argv);
100
101         pager_open_if_enabled();
102
103         r = sd_bus_call_method(
104                         bus,
105                         "org.freedesktop.login1",
106                         "/org/freedesktop/login1",
107                         "org.freedesktop.login1.Manager",
108                         "ListSessions",
109                         &error, &reply,
110                         "");
111         if (r < 0) {
112                 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
113                 return r;
114         }
115
116         r = sd_bus_message_enter_container(reply, 'a', "(susso)");
117         if (r < 0)
118                 return bus_log_parse_error(r);
119
120         if (arg_legend)
121                 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
122
123         while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
124                 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
125                 k++;
126         }
127         if (r < 0)
128                 return bus_log_parse_error(r);
129
130         if (arg_legend)
131                 printf("\n%u sessions listed.\n", k);
132
133         return 0;
134 }
135
136 static int list_users(int argc, char *argv[], void *userdata) {
137         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
138         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
139         const char *user, *object;
140         sd_bus *bus = userdata;
141         unsigned k = 0;
142         uint32_t uid;
143         int r;
144
145         assert(bus);
146         assert(argv);
147
148         pager_open_if_enabled();
149
150         r = sd_bus_call_method(
151                         bus,
152                         "org.freedesktop.login1",
153                         "/org/freedesktop/login1",
154                         "org.freedesktop.login1.Manager",
155                         "ListUsers",
156                         &error, &reply,
157                         "");
158         if (r < 0) {
159                 log_error("Failed to list users: %s", bus_error_message(&error, r));
160                 return r;
161         }
162
163         r = sd_bus_message_enter_container(reply, 'a', "(uso)");
164         if (r < 0)
165                 return bus_log_parse_error(r);
166
167         if (arg_legend)
168                 printf("%10s %-16s\n", "UID", "USER");
169
170         while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
171                 printf("%10u %-16s\n", (unsigned) uid, user);
172                 k++;
173         }
174         if (r < 0)
175                 return bus_log_parse_error(r);
176
177         if (arg_legend)
178                 printf("\n%u users listed.\n", k);
179
180         return 0;
181 }
182
183 static int list_seats(int argc, char *argv[], void *userdata) {
184         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
185         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
186         const char *seat, *object;
187         sd_bus *bus = userdata;
188         unsigned k = 0;
189         int r;
190
191         assert(bus);
192         assert(argv);
193
194         pager_open_if_enabled();
195
196         r = sd_bus_call_method(
197                         bus,
198                         "org.freedesktop.login1",
199                         "/org/freedesktop/login1",
200                         "org.freedesktop.login1.Manager",
201                         "ListSeats",
202                         &error, &reply,
203                         "");
204         if (r < 0) {
205                 log_error("Failed to list seats: %s", bus_error_message(&error, r));
206                 return r;
207         }
208
209         r = sd_bus_message_enter_container(reply, 'a', "(so)");
210         if (r < 0)
211                 return bus_log_parse_error(r);
212
213         if (arg_legend)
214                 printf("%-16s\n", "SEAT");
215
216         while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
217                 printf("%-16s\n", seat);
218                 k++;
219         }
220         if (r < 0)
221                 return bus_log_parse_error(r);
222
223         if (arg_legend)
224                 printf("\n%u seats listed.\n", k);
225
226         return 0;
227 }
228
229 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
230         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
231         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
232         _cleanup_free_ char *path = NULL;
233         const char *cgroup;
234         int r;
235         unsigned c;
236
237         assert(bus);
238         assert(unit);
239
240         if (arg_transport != BUS_TRANSPORT_LOCAL)
241                 return 0;
242
243         path = unit_dbus_path_from_name(unit);
244         if (!path)
245                 return -ENOMEM;
246
247         r = sd_bus_get_property(
248                         bus,
249                         "org.freedesktop.systemd1",
250                         path,
251                         interface,
252                         "ControlGroup",
253                         &error, &reply, "s");
254         if (r < 0)
255                 return r;
256
257         r = sd_bus_message_read(reply, "s", &cgroup);
258         if (r < 0)
259                 return r;
260
261         if (isempty(cgroup))
262                 return 0;
263
264         if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
265                 return 0;
266
267         c = columns();
268         if (c > 18)
269                 c -= 18;
270         else
271                 c = 0;
272
273         show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, get_output_flags());
274         return 0;
275 }
276
277 typedef struct SessionStatusInfo {
278         const char *id;
279         uid_t uid;
280         const char *name;
281         struct dual_timestamp timestamp;
282         unsigned int vtnr;
283         const char *seat;
284         const char *tty;
285         const char *display;
286         bool remote;
287         const char *remote_host;
288         const char *remote_user;
289         const char *service;
290         pid_t leader;
291         const char *type;
292         const char *class;
293         const char *state;
294         const char *scope;
295         const char *desktop;
296 } SessionStatusInfo;
297
298 typedef struct UserStatusInfo {
299         uid_t uid;
300         const char *name;
301         struct dual_timestamp timestamp;
302         const char *state;
303         char **sessions;
304         const char *display;
305         const char *slice;
306 } UserStatusInfo;
307
308 typedef struct SeatStatusInfo {
309         const char *id;
310         const char *active_session;
311         char **sessions;
312 } SeatStatusInfo;
313
314 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
315         const char *contents;
316         int r;
317
318         r = sd_bus_message_peek_type(m, NULL, &contents);
319         if (r < 0)
320                 return r;
321
322         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
323         if (r < 0)
324                 return r;
325
326         if (contents[0] == 's' || contents[0] == 'o') {
327                 const char *s;
328                 char **p = (char **) userdata;
329
330                 r = sd_bus_message_read_basic(m, contents[0], &s);
331                 if (r < 0)
332                         return r;
333
334                 free(*p);
335                 *p = strdup(s);
336
337                 if (!*p)
338                         return -ENOMEM;
339         } else {
340                 r = sd_bus_message_read_basic(m, contents[0], userdata);
341                 if (r < 0)
342                         return r;
343         }
344
345         r = sd_bus_message_skip(m, contents+1);
346         if (r < 0)
347                 return r;
348
349         r = sd_bus_message_exit_container(m);
350         if (r < 0)
351                 return r;
352
353         return 0;
354 }
355
356 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
357         const char *name;
358         int r;
359
360         assert(bus);
361         assert(m);
362
363         r = sd_bus_message_enter_container(m, 'a', "(so)");
364         if (r < 0)
365                 return r;
366
367         while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
368                 r = strv_extend(userdata, name);
369                 if (r < 0)
370                         return r;
371         }
372         if (r < 0)
373                 return r;
374
375         return sd_bus_message_exit_container(m);
376 }
377
378 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
379
380         static const struct bus_properties_map map[]  = {
381                 { "Id",                  "s",    NULL,                     offsetof(SessionStatusInfo, id)                  },
382                 { "Name",                "s",    NULL,                     offsetof(SessionStatusInfo, name)                },
383                 { "TTY",                 "s",    NULL,                     offsetof(SessionStatusInfo, tty)                 },
384                 { "Display",             "s",    NULL,                     offsetof(SessionStatusInfo, display)             },
385                 { "RemoteHost",          "s",    NULL,                     offsetof(SessionStatusInfo, remote_host)         },
386                 { "RemoteUser",          "s",    NULL,                     offsetof(SessionStatusInfo, remote_user)         },
387                 { "Service",             "s",    NULL,                     offsetof(SessionStatusInfo, service)             },
388                 { "Desktop",             "s",    NULL,                     offsetof(SessionStatusInfo, desktop)             },
389                 { "Type",                "s",    NULL,                     offsetof(SessionStatusInfo, type)                },
390                 { "Class",               "s",    NULL,                     offsetof(SessionStatusInfo, class)               },
391                 { "Scope",               "s",    NULL,                     offsetof(SessionStatusInfo, scope)               },
392                 { "State",               "s",    NULL,                     offsetof(SessionStatusInfo, state)               },
393                 { "VTNr",                "u",    NULL,                     offsetof(SessionStatusInfo, vtnr)                },
394                 { "Leader",              "u",    NULL,                     offsetof(SessionStatusInfo, leader)              },
395                 { "Remote",              "b",    NULL,                     offsetof(SessionStatusInfo, remote)              },
396                 { "Timestamp",           "t",    NULL,                     offsetof(SessionStatusInfo, timestamp.realtime)  },
397                 { "TimestampMonotonic",  "t",    NULL,                     offsetof(SessionStatusInfo, timestamp.monotonic) },
398                 { "User",                "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid)                 },
399                 { "Seat",                "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat)                },
400                 {}
401         };
402
403         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
404         char since2[FORMAT_TIMESTAMP_MAX], *s2;
405         SessionStatusInfo i = {};
406         int r;
407
408         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
409         if (r < 0)
410                 return log_error_errno(r, "Could not get properties: %m");
411
412         if (*new_line)
413                 printf("\n");
414
415         *new_line = true;
416
417         printf("%s - ", strna(i.id));
418
419         if (i.name)
420                 printf("%s (%u)\n", i.name, (unsigned) i.uid);
421         else
422                 printf("%u\n", (unsigned) i.uid);
423
424         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
425         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
426
427         if (s1)
428                 printf("\t   Since: %s; %s\n", s2, s1);
429         else if (s2)
430                 printf("\t   Since: %s\n", s2);
431
432         if (i.leader > 0) {
433                 _cleanup_free_ char *t = NULL;
434
435                 printf("\t  Leader: %u", (unsigned) i.leader);
436
437                 get_process_comm(i.leader, &t);
438                 if (t)
439                         printf(" (%s)", t);
440
441                 printf("\n");
442         }
443
444         if (!isempty(i.seat)) {
445                 printf("\t    Seat: %s", i.seat);
446
447                 if (i.vtnr > 0)
448                         printf("; vc%u", i.vtnr);
449
450                 printf("\n");
451         }
452
453         if (i.tty)
454                 printf("\t     TTY: %s\n", i.tty);
455         else if (i.display)
456                 printf("\t Display: %s\n", i.display);
457
458         if (i.remote_host && i.remote_user)
459                 printf("\t  Remote: %s@%s\n", i.remote_user, i.remote_host);
460         else if (i.remote_host)
461                 printf("\t  Remote: %s\n", i.remote_host);
462         else if (i.remote_user)
463                 printf("\t  Remote: user %s\n", i.remote_user);
464         else if (i.remote)
465                 printf("\t  Remote: Yes\n");
466
467         if (i.service) {
468                 printf("\t Service: %s", i.service);
469
470                 if (i.type)
471                         printf("; type %s", i.type);
472
473                 if (i.class)
474                         printf("; class %s", i.class);
475
476                 printf("\n");
477         } else if (i.type) {
478                 printf("\t    Type: %s", i.type);
479
480                 if (i.class)
481                         printf("; class %s", i.class);
482
483                 printf("\n");
484         } else if (i.class)
485                 printf("\t   Class: %s\n", i.class);
486
487         if (!isempty(i.desktop))
488                 printf("\t Desktop: %s\n", i.desktop);
489
490         if (i.state)
491                 printf("\t   State: %s\n", i.state);
492
493         if (i.scope) {
494                 printf("\t    Unit: %s\n", i.scope);
495                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
496
497                 if (arg_transport == BUS_TRANSPORT_LOCAL) {
498
499                         show_journal_by_unit(
500                                         stdout,
501                                         i.scope,
502                                         arg_output,
503                                         0,
504                                         i.timestamp.monotonic,
505                                         arg_lines,
506                                         0,
507                                         get_output_flags() | OUTPUT_BEGIN_NEWLINE,
508                                         SD_JOURNAL_LOCAL_ONLY,
509                                         true,
510                                         NULL);
511                 }
512         }
513
514         return 0;
515 }
516
517 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
518
519         static const struct bus_properties_map map[]  = {
520                 { "Name",               "s",     NULL,                     offsetof(UserStatusInfo, name)                },
521                 { "Slice",              "s",     NULL,                     offsetof(UserStatusInfo, slice)               },
522                 { "State",              "s",     NULL,                     offsetof(UserStatusInfo, state)               },
523                 { "UID",                "u",     NULL,                     offsetof(UserStatusInfo, uid)                 },
524                 { "Timestamp",          "t",     NULL,                     offsetof(UserStatusInfo, timestamp.realtime)  },
525                 { "TimestampMonotonic", "t",     NULL,                     offsetof(UserStatusInfo, timestamp.monotonic) },
526                 { "Display",            "(so)",  prop_map_first_of_struct, offsetof(UserStatusInfo, display)             },
527                 { "Sessions",           "a(so)", prop_map_sessions_strv,   offsetof(UserStatusInfo, sessions)            },
528                 {}
529         };
530
531         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
532         char since2[FORMAT_TIMESTAMP_MAX], *s2;
533         UserStatusInfo i = {};
534         int r;
535
536         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
537         if (r < 0) {
538                 log_error_errno(r, "Could not get properties: %m");
539                 goto finish;
540         }
541
542         if (*new_line)
543                 printf("\n");
544
545         *new_line = true;
546
547         if (i.name)
548                 printf("%s (%u)\n", i.name, (unsigned) i.uid);
549         else
550                 printf("%u\n", (unsigned) i.uid);
551
552         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
553         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
554
555         if (s1)
556                 printf("\t   Since: %s; %s\n", s2, s1);
557         else if (s2)
558                 printf("\t   Since: %s\n", s2);
559
560         if (!isempty(i.state))
561                 printf("\t   State: %s\n", i.state);
562
563         if (!strv_isempty(i.sessions)) {
564                 char **l;
565                 printf("\tSessions:");
566
567                 STRV_FOREACH(l, i.sessions) {
568                         if (streq_ptr(*l, i.display))
569                                 printf(" *%s", *l);
570                         else
571                                 printf(" %s", *l);
572                 }
573
574                 printf("\n");
575         }
576
577         if (i.slice) {
578                 printf("\t    Unit: %s\n", i.slice);
579                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
580
581                 show_journal_by_unit(
582                                 stdout,
583                                 i.slice,
584                                 arg_output,
585                                 0,
586                                 i.timestamp.monotonic,
587                                 arg_lines,
588                                 0,
589                                 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
590                                 SD_JOURNAL_LOCAL_ONLY,
591                                 true,
592                                 NULL);
593         }
594
595 finish:
596         strv_free(i.sessions);
597
598         return r;
599 }
600
601 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
602
603         static const struct bus_properties_map map[]  = {
604                 { "Id",            "s",     NULL, offsetof(SeatStatusInfo, id) },
605                 { "ActiveSession", "(so)",  prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
606                 { "Sessions",      "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
607                 {}
608         };
609
610         SeatStatusInfo i = {};
611         int r;
612
613         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
614         if (r < 0) {
615                 log_error_errno(r, "Could not get properties: %m");
616                 goto finish;
617         }
618
619         if (*new_line)
620                 printf("\n");
621
622         *new_line = true;
623
624         printf("%s\n", strna(i.id));
625
626         if (!strv_isempty(i.sessions)) {
627                 char **l;
628                 printf("\tSessions:");
629
630                 STRV_FOREACH(l, i.sessions) {
631                         if (streq_ptr(*l, i.active_session))
632                                 printf(" *%s", *l);
633                         else
634                                 printf(" %s", *l);
635                 }
636
637                 printf("\n");
638         }
639
640         if (arg_transport == BUS_TRANSPORT_LOCAL) {
641                 unsigned c;
642
643                 c = columns();
644                 if (c > 21)
645                         c -= 21;
646                 else
647                         c = 0;
648
649                 printf("\t Devices:\n");
650
651                 show_sysfs(i.id, "\t\t  ", c);
652         }
653
654 finish:
655         strv_free(i.sessions);
656
657         return r;
658 }
659
660 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
661         int r;
662
663         if (*new_line)
664                 printf("\n");
665
666         *new_line = true;
667
668         r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
669         if (r < 0)
670                 log_error_errno(r, "Could not get properties: %m");
671
672         return r;
673 }
674
675 static int show_session(int argc, char *argv[], void *userdata) {
676         bool properties, new_line = false;
677         sd_bus *bus = userdata;
678         int r, i;
679
680         assert(bus);
681         assert(argv);
682
683         properties = !strstr(argv[0], "status");
684
685         pager_open_if_enabled();
686
687         if (argc <= 1) {
688                 /* If not argument is specified inspect the manager
689                  * itself */
690                 if (properties)
691                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
692
693                 /* And in the pretty case, show data of the calling session */
694                 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
695         }
696
697         for (i = 1; i < argc; i++) {
698                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
699                 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
700                 const char *path = NULL;
701
702                 r = sd_bus_call_method(
703                                 bus,
704                                 "org.freedesktop.login1",
705                                 "/org/freedesktop/login1",
706                                 "org.freedesktop.login1.Manager",
707                                 "GetSession",
708                                 &error, &reply,
709                                 "s", argv[i]);
710                 if (r < 0) {
711                         log_error("Failed to get session: %s", bus_error_message(&error, r));
712                         return r;
713                 }
714
715                 r = sd_bus_message_read(reply, "o", &path);
716                 if (r < 0)
717                         return bus_log_parse_error(r);
718
719                 if (properties)
720                         r = show_properties(bus, path, &new_line);
721                 else
722                         r = print_session_status_info(bus, path, &new_line);
723
724                 if (r < 0)
725                         return r;
726         }
727
728         return 0;
729 }
730
731 static int show_user(int argc, char *argv[], void *userdata) {
732         bool properties, new_line = false;
733         sd_bus *bus = userdata;
734         int r, i;
735
736         assert(bus);
737         assert(argv);
738
739         properties = !strstr(argv[0], "status");
740
741         pager_open_if_enabled();
742
743         if (argc <= 1) {
744                 /* If not argument is specified inspect the manager
745                  * itself */
746                 if (properties)
747                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
748
749                 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
750         }
751
752         for (i = 1; i < argc; i++) {
753                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
754                 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
755                 const char *path = NULL;
756                 uid_t uid;
757
758                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
759                 if (r < 0)
760                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
761
762                 r = sd_bus_call_method(
763                                 bus,
764                                 "org.freedesktop.login1",
765                                 "/org/freedesktop/login1",
766                                 "org.freedesktop.login1.Manager",
767                                 "GetUser",
768                                 &error, &reply,
769                                 "u", (uint32_t) uid);
770                 if (r < 0) {
771                         log_error("Failed to get user: %s", bus_error_message(&error, r));
772                         return r;
773                 }
774
775                 r = sd_bus_message_read(reply, "o", &path);
776                 if (r < 0)
777                         return bus_log_parse_error(r);
778
779                 if (properties)
780                         r = show_properties(bus, path, &new_line);
781                 else
782                         r = print_user_status_info(bus, path, &new_line);
783
784                 if (r < 0)
785                         return r;
786         }
787
788         return 0;
789 }
790
791 static int show_seat(int argc, char *argv[], void *userdata) {
792         bool properties, new_line = false;
793         sd_bus *bus = userdata;
794         int r, i;
795
796         assert(bus);
797         assert(argv);
798
799         properties = !strstr(argv[0], "status");
800
801         pager_open_if_enabled();
802
803         if (argc <= 1) {
804                 /* If not argument is specified inspect the manager
805                  * itself */
806                 if (properties)
807                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
808
809                 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
810         }
811
812         for (i = 1; i < argc; i++) {
813                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
814                 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
815                 const char *path = NULL;
816
817                 r = sd_bus_call_method(
818                                 bus,
819                                 "org.freedesktop.login1",
820                                 "/org/freedesktop/login1",
821                                 "org.freedesktop.login1.Manager",
822                                 "GetSeat",
823                                 &error, &reply,
824                                 "s", argv[i]);
825                 if (r < 0) {
826                         log_error("Failed to get seat: %s", bus_error_message(&error, r));
827                         return r;
828                 }
829
830                 r = sd_bus_message_read(reply, "o", &path);
831                 if (r < 0)
832                         return bus_log_parse_error(r);
833
834                 if (properties)
835                         r = show_properties(bus, path, &new_line);
836                 else
837                         r = print_seat_status_info(bus, path, &new_line);
838
839                 if (r < 0)
840                         return r;
841         }
842
843         return 0;
844 }
845
846 static int activate(int argc, char *argv[], void *userdata) {
847         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
848         sd_bus *bus = userdata;
849         char *short_argv[3];
850         int r, i;
851
852         assert(bus);
853         assert(argv);
854
855         polkit_agent_open_if_enabled();
856
857         if (argc < 2) {
858                 /* No argument? Let's convert this into the empty
859                  * session name, which the calls will then resolve to
860                  * the caller's session. */
861
862                 short_argv[0] = argv[0];
863                 short_argv[1] = (char*) "";
864                 short_argv[2] = NULL;
865
866                 argv = short_argv;
867                 argc = 2;
868         }
869
870         for (i = 1; i < argc; i++) {
871
872                 r = sd_bus_call_method(
873                                 bus,
874                                 "org.freedesktop.login1",
875                                 "/org/freedesktop/login1",
876                                 "org.freedesktop.login1.Manager",
877                                 streq(argv[0], "lock-session")      ? "LockSession" :
878                                 streq(argv[0], "unlock-session")    ? "UnlockSession" :
879                                 streq(argv[0], "terminate-session") ? "TerminateSession" :
880                                                                       "ActivateSession",
881                                 &error, NULL,
882                                 "s", argv[i]);
883                 if (r < 0) {
884                         log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
885                         return r;
886                 }
887         }
888
889         return 0;
890 }
891
892 static int kill_session(int argc, char *argv[], void *userdata) {
893         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
894         sd_bus *bus = userdata;
895         int r, i;
896
897         assert(bus);
898         assert(argv);
899
900         polkit_agent_open_if_enabled();
901
902         if (!arg_kill_who)
903                 arg_kill_who = "all";
904
905         for (i = 1; i < argc; i++) {
906
907                 r = sd_bus_call_method(
908                         bus,
909                         "org.freedesktop.login1",
910                         "/org/freedesktop/login1",
911                         "org.freedesktop.login1.Manager",
912                         "KillSession",
913                         &error, NULL,
914                         "ssi", argv[i], arg_kill_who, arg_signal);
915                 if (r < 0) {
916                         log_error("Could not kill session: %s", bus_error_message(&error, -r));
917                         return r;
918                 }
919         }
920
921         return 0;
922 }
923
924 static int enable_linger(int argc, char *argv[], void *userdata) {
925         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
926         sd_bus *bus = userdata;
927         char* short_argv[3];
928         bool b;
929         int r, i;
930
931         assert(bus);
932         assert(argv);
933
934         polkit_agent_open_if_enabled();
935
936         b = streq(argv[0], "enable-linger");
937
938         if (argc < 2) {
939                 short_argv[0] = argv[0];
940                 short_argv[1] = (char*) "";
941                 short_argv[2] = NULL;
942                 argv = short_argv;
943                 argc = 2;
944         }
945
946         for (i = 1; i < argc; i++) {
947                 uid_t uid;
948
949                 if (isempty(argv[i]))
950                         uid = UID_INVALID;
951                 else {
952                         r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
953                         if (r < 0)
954                                 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
955                 }
956
957                 r = sd_bus_call_method(
958                         bus,
959                         "org.freedesktop.login1",
960                         "/org/freedesktop/login1",
961                         "org.freedesktop.login1.Manager",
962                         "SetUserLinger",
963                         &error, NULL,
964                         "ubb", (uint32_t) uid, b, true);
965                 if (r < 0) {
966                         log_error("Could not enable linger: %s", bus_error_message(&error, -r));
967                         return r;
968                 }
969         }
970
971         return 0;
972 }
973
974 static int terminate_user(int argc, char *argv[], void *userdata) {
975         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
976         sd_bus *bus = userdata;
977         int r, i;
978
979         assert(bus);
980         assert(argv);
981
982         polkit_agent_open_if_enabled();
983
984         for (i = 1; i < argc; i++) {
985                 uid_t uid;
986
987                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
988                 if (r < 0)
989                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
990
991                 r = sd_bus_call_method(
992                         bus,
993                         "org.freedesktop.login1",
994                         "/org/freedesktop/login1",
995                         "org.freedesktop.login1.Manager",
996                         "TerminateUser",
997                         &error, NULL,
998                         "u", (uint32_t) uid);
999                 if (r < 0) {
1000                         log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1001                         return r;
1002                 }
1003         }
1004
1005         return 0;
1006 }
1007
1008 static int kill_user(int argc, char *argv[], void *userdata) {
1009         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1010         sd_bus *bus = userdata;
1011         int r, i;
1012
1013         assert(bus);
1014         assert(argv);
1015
1016         polkit_agent_open_if_enabled();
1017
1018         if (!arg_kill_who)
1019                 arg_kill_who = "all";
1020
1021         for (i = 1; i < argc; i++) {
1022                 uid_t uid;
1023
1024                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1025                 if (r < 0)
1026                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1027
1028                 r = sd_bus_call_method(
1029                         bus,
1030                         "org.freedesktop.login1",
1031                         "/org/freedesktop/login1",
1032                         "org.freedesktop.login1.Manager",
1033                         "KillUser",
1034                         &error, NULL,
1035                         "ui", (uint32_t) uid, arg_signal);
1036                 if (r < 0) {
1037                         log_error("Could not kill user: %s", bus_error_message(&error, -r));
1038                         return r;
1039                 }
1040         }
1041
1042         return 0;
1043 }
1044
1045 static int attach(int argc, char *argv[], void *userdata) {
1046         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1047         sd_bus *bus = userdata;
1048         int r, i;
1049
1050         assert(bus);
1051         assert(argv);
1052
1053         polkit_agent_open_if_enabled();
1054
1055         for (i = 2; i < argc; i++) {
1056
1057                 r = sd_bus_call_method(
1058                         bus,
1059                         "org.freedesktop.login1",
1060                         "/org/freedesktop/login1",
1061                         "org.freedesktop.login1.Manager",
1062                         "AttachDevice",
1063                         &error, NULL,
1064                         "ssb", argv[1], argv[i], true);
1065
1066                 if (r < 0) {
1067                         log_error("Could not attach device: %s", bus_error_message(&error, -r));
1068                         return r;
1069                 }
1070         }
1071
1072         return 0;
1073 }
1074
1075 static int flush_devices(int argc, char *argv[], void *userdata) {
1076         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1077         sd_bus *bus = userdata;
1078         int r;
1079
1080         assert(bus);
1081         assert(argv);
1082
1083         polkit_agent_open_if_enabled();
1084
1085         r = sd_bus_call_method(
1086                         bus,
1087                         "org.freedesktop.login1",
1088                         "/org/freedesktop/login1",
1089                         "org.freedesktop.login1.Manager",
1090                         "FlushDevices",
1091                         &error, NULL,
1092                         "b", true);
1093         if (r < 0)
1094                 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1095
1096         return r;
1097 }
1098
1099 static int lock_sessions(int argc, char *argv[], void *userdata) {
1100         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1101         sd_bus *bus = userdata;
1102         int r;
1103
1104         assert(bus);
1105         assert(argv);
1106
1107         polkit_agent_open_if_enabled();
1108
1109         r = sd_bus_call_method(
1110                         bus,
1111                         "org.freedesktop.login1",
1112                         "/org/freedesktop/login1",
1113                         "org.freedesktop.login1.Manager",
1114                         streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1115                         &error, NULL,
1116                         NULL);
1117         if (r < 0)
1118                 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1119
1120         return r;
1121 }
1122
1123 static int terminate_seat(int argc, char *argv[], void *userdata) {
1124         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1125         sd_bus *bus = userdata;
1126         int r, i;
1127
1128         assert(bus);
1129         assert(argv);
1130
1131         polkit_agent_open_if_enabled();
1132
1133         for (i = 1; i < argc; i++) {
1134
1135                 r = sd_bus_call_method(
1136                         bus,
1137                         "org.freedesktop.login1",
1138                         "/org/freedesktop/login1",
1139                         "org.freedesktop.login1.Manager",
1140                         "TerminateSeat",
1141                         &error, NULL,
1142                         "s", argv[i]);
1143                 if (r < 0) {
1144                         log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1145                         return r;
1146                 }
1147         }
1148
1149         return 0;
1150 }
1151
1152 static int help(int argc, char *argv[], void *userdata) {
1153
1154         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1155                "Send control commands to or query the login manager.\n\n"
1156                "  -h --help                Show this help\n"
1157                "     --version             Show package version\n"
1158                "     --no-pager            Do not pipe output into a pager\n"
1159                "     --no-legend           Do not show the headers and footers\n"
1160                "     --no-ask-password     Don't prompt for password\n"
1161                "  -H --host=[USER@]HOST    Operate on remote host\n"
1162                "  -M --machine=CONTAINER   Operate on local container\n"
1163                "  -p --property=NAME       Show only properties by this name\n"
1164                "  -a --all                 Show all properties, including empty ones\n"
1165                "  -l --full                Do not ellipsize output\n"
1166                "     --kill-who=WHO        Who to send signal to\n"
1167                "  -s --signal=SIGNAL       Which signal to send\n"
1168                "  -n --lines=INTEGER       Number of journal entries to show\n"
1169                "  -o --output=STRING       Change journal output mode (short, short-monotonic,\n"
1170                "                           verbose, export, json, json-pretty, json-sse, cat)\n\n"
1171                "Session Commands:\n"
1172                "  list-sessions            List sessions\n"
1173                "  session-status [ID...]   Show session status\n"
1174                "  show-session [ID...]     Show properties of sessions or the manager\n"
1175                "  activate [ID]            Activate a session\n"
1176                "  lock-session [ID...]     Screen lock one or more sessions\n"
1177                "  unlock-session [ID...]   Screen unlock one or more sessions\n"
1178                "  lock-sessions            Screen lock all current sessions\n"
1179                "  unlock-sessions          Screen unlock all current sessions\n"
1180                "  terminate-session ID...  Terminate one or more sessions\n"
1181                "  kill-session ID...       Send signal to processes of a session\n\n"
1182                "User Commands:\n"
1183                "  list-users               List users\n"
1184                "  user-status [USER...]    Show user status\n"
1185                "  show-user [USER...]      Show properties of users or the manager\n"
1186                "  enable-linger [USER...]  Enable linger state of one or more users\n"
1187                "  disable-linger [USER...] Disable linger state of one or more users\n"
1188                "  terminate-user USER...   Terminate all sessions of one or more users\n"
1189                "  kill-user USER...        Send signal to processes of a user\n\n"
1190                "Seat Commands:\n"
1191                "  list-seats               List seats\n"
1192                "  seat-status [NAME...]    Show seat status\n"
1193                "  show-seat [NAME...]      Show properties of seats or the manager\n"
1194                "  attach NAME DEVICE...    Attach one or more devices to a seat\n"
1195                "  flush-devices            Flush all device associations\n"
1196                "  terminate-seat NAME...   Terminate all sessions on one or more seats\n"
1197                , program_invocation_short_name);
1198
1199         return 0;
1200 }
1201
1202 static int parse_argv(int argc, char *argv[]) {
1203
1204         enum {
1205                 ARG_VERSION = 0x100,
1206                 ARG_NO_PAGER,
1207                 ARG_NO_LEGEND,
1208                 ARG_KILL_WHO,
1209                 ARG_NO_ASK_PASSWORD,
1210         };
1211
1212         static const struct option options[] = {
1213                 { "help",            no_argument,       NULL, 'h'                 },
1214                 { "version",         no_argument,       NULL, ARG_VERSION         },
1215                 { "property",        required_argument, NULL, 'p'                 },
1216                 { "all",             no_argument,       NULL, 'a'                 },
1217                 { "full",            no_argument,       NULL, 'l'                 },
1218                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
1219                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
1220                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
1221                 { "signal",          required_argument, NULL, 's'                 },
1222                 { "host",            required_argument, NULL, 'H'                 },
1223                 { "machine",         required_argument, NULL, 'M'                 },
1224                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
1225                 { "lines",           required_argument, NULL, 'n'                 },
1226                 { "output",          required_argument, NULL, 'o'                 },
1227                 {}
1228         };
1229
1230         int c, r;
1231
1232         assert(argc >= 0);
1233         assert(argv);
1234
1235         while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1236
1237                 switch (c) {
1238
1239                 case 'h':
1240                         help(0, NULL, NULL);
1241                         return 0;
1242
1243                 case ARG_VERSION:
1244                         puts(PACKAGE_STRING);
1245                         puts(SYSTEMD_FEATURES);
1246                         return 0;
1247
1248                 case 'p': {
1249                         r = strv_extend(&arg_property, optarg);
1250                         if (r < 0)
1251                                 return log_oom();
1252
1253                         /* If the user asked for a particular
1254                          * property, show it to him, even if it is
1255                          * empty. */
1256                         arg_all = true;
1257                         break;
1258                 }
1259
1260                 case 'a':
1261                         arg_all = true;
1262                         break;
1263
1264                 case 'l':
1265                         arg_full = true;
1266                         break;
1267
1268                 case 'n':
1269                         if (safe_atou(optarg, &arg_lines) < 0) {
1270                                 log_error("Failed to parse lines '%s'", optarg);
1271                                 return -EINVAL;
1272                         }
1273                         break;
1274
1275                 case 'o':
1276                         arg_output = output_mode_from_string(optarg);
1277                         if (arg_output < 0) {
1278                                 log_error("Unknown output '%s'.", optarg);
1279                                 return -EINVAL;
1280                         }
1281                         break;
1282
1283                 case ARG_NO_PAGER:
1284                         arg_no_pager = true;
1285                         break;
1286
1287                 case ARG_NO_LEGEND:
1288                         arg_legend = false;
1289                         break;
1290
1291                 case ARG_NO_ASK_PASSWORD:
1292                         arg_ask_password = false;
1293                         break;
1294
1295                 case ARG_KILL_WHO:
1296                         arg_kill_who = optarg;
1297                         break;
1298
1299                 case 's':
1300                         arg_signal = signal_from_string_try_harder(optarg);
1301                         if (arg_signal < 0) {
1302                                 log_error("Failed to parse signal string %s.", optarg);
1303                                 return -EINVAL;
1304                         }
1305                         break;
1306
1307                 case 'H':
1308                         arg_transport = BUS_TRANSPORT_REMOTE;
1309                         arg_host = optarg;
1310                         break;
1311
1312                 case 'M':
1313                         arg_transport = BUS_TRANSPORT_MACHINE;
1314                         arg_host = optarg;
1315                         break;
1316
1317                 case '?':
1318                         return -EINVAL;
1319
1320                 default:
1321                         assert_not_reached("Unhandled option");
1322                 }
1323
1324         return 1;
1325 }
1326
1327 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1328
1329         static const Verb verbs[] = {
1330                 { "help",              VERB_ANY, VERB_ANY, 0,            help              },
1331                 { "list-sessions",     VERB_ANY, 1,        VERB_DEFAULT, list_sessions     },
1332                 { "session-status",    VERB_ANY, VERB_ANY, 0,            show_session      },
1333                 { "show-session",      VERB_ANY, VERB_ANY, 0,            show_session      },
1334                 { "activate",          VERB_ANY, 2,        0,            activate          },
1335                 { "lock-session",      VERB_ANY, VERB_ANY, 0,            activate          },
1336                 { "unlock-session",    VERB_ANY, VERB_ANY, 0,            activate          },
1337                 { "lock-sessions",     VERB_ANY, 1,        0,            lock_sessions     },
1338                 { "unlock-sessions",   VERB_ANY, 1,        0,            lock_sessions     },
1339                 { "terminate-session", 2,        VERB_ANY, 0,            activate          },
1340                 { "kill-session",      2,        VERB_ANY, 0,            kill_session      },
1341                 { "list-users",        VERB_ANY, 1,        0,            list_users        },
1342                 { "user-status",       VERB_ANY, VERB_ANY, 0,            show_user         },
1343                 { "show-user",         VERB_ANY, VERB_ANY, 0,            show_user         },
1344                 { "enable-linger",     VERB_ANY, VERB_ANY, 0,            enable_linger     },
1345                 { "disable-linger",    VERB_ANY, VERB_ANY, 0,            enable_linger     },
1346                 { "terminate-user",    2,        VERB_ANY, 0,            terminate_user    },
1347                 { "kill-user",         2,        VERB_ANY, 0,            kill_user         },
1348                 { "list-seats",        VERB_ANY, 1,        0,            list_seats        },
1349                 { "seat-status",       VERB_ANY, VERB_ANY, 0,            show_seat         },
1350                 { "show-seat",         VERB_ANY, VERB_ANY, 0,            show_seat         },
1351                 { "attach",            3,        VERB_ANY, 0,            attach            },
1352                 { "flush-devices",     VERB_ANY, 1,        0,            flush_devices     },
1353                 { "terminate-seat",    2,        VERB_ANY, 0,            terminate_seat    },
1354                 {}
1355         };
1356
1357         return dispatch_verb(argc, argv, verbs, bus);
1358 }
1359
1360 int main(int argc, char *argv[]) {
1361         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1362         int r;
1363
1364         setlocale(LC_ALL, "");
1365         log_parse_environment();
1366         log_open();
1367
1368         r = parse_argv(argc, argv);
1369         if (r <= 0)
1370                 goto finish;
1371
1372         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1373         if (r < 0) {
1374                 log_error_errno(r, "Failed to create bus connection: %m");
1375                 goto finish;
1376         }
1377
1378         sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1379
1380         r = loginctl_main(argc, argv, bus);
1381
1382 finish:
1383         pager_close();
1384         polkit_agent_close();
1385
1386         strv_free(arg_property);
1387
1388         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1389 }