mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-12-25 03:49:00 +07:00
loginctl: implement missing kill verb
This commit is contained in:
parent
a17204af0e
commit
de07ab16c6
149
src/loginctl.c
149
src/loginctl.c
@ -1208,7 +1208,63 @@ finish:
|
||||
}
|
||||
|
||||
static int kill_session(DBusConnection *bus, char **args, unsigned n) {
|
||||
return 0;
|
||||
DBusMessage *m = NULL, *reply = NULL;
|
||||
int ret = 0;
|
||||
DBusError error;
|
||||
unsigned i;
|
||||
|
||||
assert(bus);
|
||||
assert(args);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!arg_kill_who)
|
||||
arg_kill_who = "all";
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
m = dbus_message_new_method_call(
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"KillSession");
|
||||
if (!m) {
|
||||
log_error("Could not allocate message.");
|
||||
ret = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!dbus_message_append_args(m,
|
||||
DBUS_TYPE_STRING, &args[i],
|
||||
DBUS_TYPE_STRING, &arg_kill_who,
|
||||
DBUS_TYPE_INT32, arg_signal,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
log_error("Could not append arguments to 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;
|
||||
}
|
||||
|
||||
dbus_message_unref(m);
|
||||
dbus_message_unref(reply);
|
||||
m = reply = NULL;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (m)
|
||||
dbus_message_unref(m);
|
||||
|
||||
if (reply)
|
||||
dbus_message_unref(reply);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
|
||||
@ -1358,6 +1414,81 @@ finish:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kill_user(DBusConnection *bus, char **args, unsigned n) {
|
||||
DBusMessage *m = NULL, *reply = NULL;
|
||||
int ret = 0;
|
||||
DBusError error;
|
||||
unsigned i;
|
||||
|
||||
assert(bus);
|
||||
assert(args);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!arg_kill_who)
|
||||
arg_kill_who = "all";
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
uint32_t u;
|
||||
|
||||
m = dbus_message_new_method_call(
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"KillUser");
|
||||
if (!m) {
|
||||
log_error("Could not allocate message.");
|
||||
ret = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (safe_atou32(args[i], &u) < 0) {
|
||||
struct passwd *pw;
|
||||
|
||||
errno = 0;
|
||||
pw = getpwnam(args[i]);
|
||||
if (!pw) {
|
||||
ret = errno ? -errno : -ENOENT;
|
||||
log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
u = pw->pw_uid;
|
||||
}
|
||||
|
||||
if (!dbus_message_append_args(m,
|
||||
DBUS_TYPE_UINT32, &u,
|
||||
DBUS_TYPE_INT32, arg_signal,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
log_error("Could not append arguments to 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;
|
||||
}
|
||||
|
||||
dbus_message_unref(m);
|
||||
dbus_message_unref(reply);
|
||||
m = reply = NULL;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (m)
|
||||
dbus_message_unref(m);
|
||||
|
||||
if (reply)
|
||||
dbus_message_unref(reply);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int attach(DBusConnection *bus, char **args, unsigned n) {
|
||||
DBusMessage *m = NULL, *reply = NULL;
|
||||
int ret = 0;
|
||||
@ -1537,7 +1668,7 @@ static int help(void) {
|
||||
"Commands:\n"
|
||||
" list-sessions List sessions\n"
|
||||
" session-status [ID...] Show session status\n"
|
||||
" show-session [ID...] Show property of one or more sessions\n"
|
||||
" show-session [ID...] Show properties of one or more sessions\n"
|
||||
" 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"
|
||||
@ -1545,18 +1676,17 @@ static int help(void) {
|
||||
" kill-session [ID...] Send signal to processes of a session\n"
|
||||
" list-users List users\n"
|
||||
" user-status [USER...] Show user status\n"
|
||||
" show-user [USER...] Show property of one or more users\n"
|
||||
" show-user [USER...] Show properties of one or more users\n"
|
||||
" enable-linger [USER...] Enable linger state of one or more users\n"
|
||||
" disable-linger [USER...] Disable linger state of one or more users\n"
|
||||
" terminate-user [USER...] Terminate all sessions of one or more users\n"
|
||||
" kill-user [USER...] Send signal to processes of a user\n"
|
||||
" list-seats List seats\n"
|
||||
" seat-status [NAME...] Show seat status\n"
|
||||
" show-seat [NAME...] Show property of one or more seats\n"
|
||||
" show-seat [NAME...] Show properties of one or more seats\n"
|
||||
" attach [NAME] [DEVICE...] Attach one or more devices to a seat\n"
|
||||
" flush-devices Flush all device associations\n"
|
||||
" terminate-seat [NAME...] Terminate all sessions on one or more seats\n"
|
||||
" kill-seat [NAME...] Send signal to processes of sessions on a seat\n",
|
||||
" terminate-seat [NAME...] Terminate all sessions on one or more seats\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
@ -1679,21 +1809,20 @@ static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
|
||||
{ "lock-session", MORE, 2, activate },
|
||||
{ "unlock-session", MORE, 2, activate },
|
||||
{ "terminate-session", MORE, 2, activate },
|
||||
{ "kill-session", MORE, 2, kill_session }, /* missing */
|
||||
{ "kill-session", MORE, 2, kill_session },
|
||||
{ "list-users", EQUAL, 1, list_users },
|
||||
{ "user-status", MORE, 2, show },
|
||||
{ "show-user", MORE, 1, show },
|
||||
{ "enable-linger", MORE, 2, enable_linger },
|
||||
{ "disable-linger", MORE, 2, enable_linger },
|
||||
{ "terminate-user", MORE, 2, terminate_user },
|
||||
{ "kill-user", MORE, 2, kill_session }, /* missing */
|
||||
{ "kill-user", MORE, 2, kill_user },
|
||||
{ "list-seats", EQUAL, 1, list_seats },
|
||||
{ "seat-status", MORE, 2, show },
|
||||
{ "show-seat", MORE, 1, show },
|
||||
{ "attach", MORE, 3, attach },
|
||||
{ "flush-devices", EQUAL, 1, flush_devices },
|
||||
{ "terminate-seat", MORE, 2, terminate_seat }, /* missing */
|
||||
{ "kill-seat", MORE, 2, kill_session }, /* missing */
|
||||
{ "terminate-seat", MORE, 2, terminate_seat },
|
||||
};
|
||||
|
||||
int left;
|
||||
|
@ -81,6 +81,15 @@
|
||||
" <method name=\"UnlockSession\">\n" \
|
||||
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"KillSession\">\n" \
|
||||
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"who\" type=\"s\"/>\n" \
|
||||
" <arg name=\"signal\" type=\"s\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"KillUser\">\n" \
|
||||
" <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
|
||||
" <arg name=\"signal\" type=\"s\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"TerminateSession\">\n" \
|
||||
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
|
||||
" </method>\n" \
|
||||
@ -1009,6 +1018,73 @@ static DBusHandlerResult manager_message_handler(
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
|
||||
const char *swho;
|
||||
int32_t signo;
|
||||
KillWho who;
|
||||
const char *name;
|
||||
Session *session;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
message,
|
||||
&error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_STRING, &swho,
|
||||
DBUS_TYPE_INT32, &signo,
|
||||
DBUS_TYPE_INVALID))
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
if (isempty(swho))
|
||||
who = KILL_ALL;
|
||||
else {
|
||||
who = kill_who_from_string(swho);
|
||||
if (who < 0)
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
}
|
||||
|
||||
if (signo <= 0 || signo >= _NSIG)
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
session = hashmap_get(m->sessions, name);
|
||||
if (!session)
|
||||
return bus_send_error_reply(connection, message, &error, -ENOENT);
|
||||
|
||||
r = session_kill(session, who, signo);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
|
||||
uint32_t uid;
|
||||
User *user;
|
||||
int32_t signo;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
message,
|
||||
&error,
|
||||
DBUS_TYPE_UINT32, &uid,
|
||||
DBUS_TYPE_INT32, &signo,
|
||||
DBUS_TYPE_INVALID))
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
if (signo <= 0 || signo >= _NSIG)
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
|
||||
if (!user)
|
||||
return bus_send_error_reply(connection, message, &error, -ENOENT);
|
||||
|
||||
r = user_kill(user, signo);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
|
||||
const char *name;
|
||||
Session *session;
|
||||
|
@ -36,6 +36,10 @@
|
||||
" <method name=\"SetIdleHint\">\n" \
|
||||
" <arg name=\"b\" type=\"b\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"Kill\">\n" \
|
||||
" <arg name=\"who\" type=\"s\"/>\n" \
|
||||
" <arg name=\"signal\" type=\"s\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
|
||||
" <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
|
||||
@ -315,6 +319,38 @@ static DBusHandlerResult session_message_dispatch(
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
|
||||
const char *swho;
|
||||
int32_t signo;
|
||||
KillWho who;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
message,
|
||||
&error,
|
||||
DBUS_TYPE_STRING, &swho,
|
||||
DBUS_TYPE_INT32, &signo,
|
||||
DBUS_TYPE_INVALID))
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
if (isempty(swho))
|
||||
who = KILL_ALL;
|
||||
else {
|
||||
who = kill_who_from_string(swho);
|
||||
if (who < 0)
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
}
|
||||
|
||||
if (signo <= 0 || signo >= _NSIG)
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
r = session_kill(s, who, signo);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else
|
||||
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
|
||||
|
||||
|
@ -588,7 +588,7 @@ static bool session_shall_kill(Session *s) {
|
||||
return strv_contains(s->manager->kill_only_users, s->user->name);
|
||||
}
|
||||
|
||||
static int session_kill_cgroup(Session *s) {
|
||||
static int session_terminate_cgroup(Session *s) {
|
||||
int r;
|
||||
char **k;
|
||||
|
||||
@ -661,7 +661,7 @@ int session_stop(Session *s) {
|
||||
log_info("Removed session %s.", s->id);
|
||||
|
||||
/* Kill cgroup */
|
||||
k = session_kill_cgroup(s);
|
||||
k = session_terminate_cgroup(s);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
@ -886,6 +886,48 @@ void session_add_to_gc_queue(Session *s) {
|
||||
s->in_gc_queue = true;
|
||||
}
|
||||
|
||||
int session_kill(Session *s, KillWho who, int signo) {
|
||||
int r = 0;
|
||||
Set *pid_set = NULL;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (!s->cgroup_path)
|
||||
return -ESRCH;
|
||||
|
||||
if (s->leader <= 0 && who == KILL_LEADER)
|
||||
return -ESRCH;
|
||||
|
||||
if (s->leader > 0)
|
||||
if (kill(s->leader, signo) < 0)
|
||||
r = -errno;
|
||||
|
||||
if (who == KILL_ALL) {
|
||||
int q;
|
||||
|
||||
pid_set = set_new(trivial_hash_func, trivial_compare_func);
|
||||
if (!pid_set)
|
||||
return -ENOMEM;
|
||||
|
||||
if (s->leader > 0) {
|
||||
q = set_put(pid_set, LONG_TO_PTR(s->leader));
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, signo, false, true, false, pid_set);
|
||||
if (q < 0)
|
||||
if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
|
||||
r = q;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (pid_set)
|
||||
set_free(pid_set);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char* const session_type_table[_SESSION_TYPE_MAX] = {
|
||||
[SESSION_TTY] = "tty",
|
||||
[SESSION_X11] = "x11",
|
||||
@ -893,3 +935,10 @@ static const char* const session_type_table[_SESSION_TYPE_MAX] = {
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
|
||||
|
||||
static const char* const kill_who_table[_KILL_WHO_MAX] = {
|
||||
[KILL_LEADER] = "leader",
|
||||
[KILL_ALL] = "all"
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
|
||||
|
@ -38,6 +38,13 @@ typedef enum SessionType {
|
||||
_SESSION_TYPE_INVALID = -1
|
||||
} SessionType;
|
||||
|
||||
typedef enum KillWho {
|
||||
KILL_LEADER,
|
||||
KILL_ALL,
|
||||
_KILL_WHO_MAX,
|
||||
_KILL_WHO_INVALID = -1
|
||||
} KillWho;
|
||||
|
||||
struct Session {
|
||||
Manager *manager;
|
||||
|
||||
@ -98,6 +105,7 @@ int session_start(Session *s);
|
||||
int session_stop(Session *s);
|
||||
int session_save(Session *s);
|
||||
int session_load(Session *s);
|
||||
int session_kill(Session *s, KillWho who, int signo);
|
||||
|
||||
char *session_bus_path(Session *s);
|
||||
|
||||
@ -110,4 +118,7 @@ int session_send_lock(Session *s, bool lock);
|
||||
const char* session_type_to_string(SessionType t);
|
||||
SessionType session_type_from_string(const char *s);
|
||||
|
||||
const char *kill_who_to_string(KillWho k);
|
||||
KillWho kill_who_from_string(const char *s);
|
||||
|
||||
#endif
|
||||
|
@ -29,6 +29,9 @@
|
||||
#define BUS_USER_INTERFACE \
|
||||
" <interface name=\"org.freedesktop.login1.User\">\n" \
|
||||
" <method name=\"Terminate\"/>\n" \
|
||||
" <method name=\"Kill\">\n" \
|
||||
" <arg name=\"signal\" type=\"s\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <property name=\"UID\" type=\"u\" access=\"read\"/>\n" \
|
||||
" <property name=\"GID\" type=\"u\" access=\"read\"/>\n" \
|
||||
" <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
|
||||
@ -250,6 +253,27 @@ static DBusHandlerResult user_message_dispatch(
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.User", "Kill")) {
|
||||
int32_t signo;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
message,
|
||||
&error,
|
||||
DBUS_TYPE_INT32, &signo,
|
||||
DBUS_TYPE_INVALID))
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
if (signo <= 0 || signo >= _NSIG)
|
||||
return bus_send_error_reply(connection, message, &error, -EINVAL);
|
||||
|
||||
r = user_kill(u, signo);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, NULL, r);
|
||||
|
||||
reply = dbus_message_new_method_return(message);
|
||||
if (!reply)
|
||||
goto oom;
|
||||
|
||||
} else
|
||||
return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
|
||||
|
||||
|
@ -325,7 +325,7 @@ static int user_shall_kill(User *u) {
|
||||
return strv_contains(u->manager->kill_only_users, u->name);
|
||||
}
|
||||
|
||||
static int user_kill_cgroup(User *u) {
|
||||
static int user_terminate_cgroup(User *u) {
|
||||
int r;
|
||||
char **k;
|
||||
|
||||
@ -401,7 +401,7 @@ int user_stop(User *u) {
|
||||
r = k;
|
||||
|
||||
/* Kill cgroup */
|
||||
k = user_kill_cgroup(u);
|
||||
k = user_terminate_cgroup(u);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
@ -515,6 +515,31 @@ UserState user_get_state(User *u) {
|
||||
return USER_ONLINE;
|
||||
}
|
||||
|
||||
int user_kill(User *u, int signo) {
|
||||
int r = 0, q;
|
||||
Set *pid_set = NULL;
|
||||
|
||||
assert(u);
|
||||
|
||||
if (!u->cgroup_path)
|
||||
return -ESRCH;
|
||||
|
||||
pid_set = set_new(trivial_hash_func, trivial_compare_func);
|
||||
if (!pid_set)
|
||||
return -ENOMEM;
|
||||
|
||||
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
|
||||
if (q < 0)
|
||||
if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
|
||||
r = q;
|
||||
|
||||
finish:
|
||||
if (pid_set)
|
||||
set_free(pid_set);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char* const user_state_table[_USER_STATE_MAX] = {
|
||||
[USER_OFFLINE] = "offline",
|
||||
[USER_LINGERING] = "lingering",
|
||||
|
@ -71,6 +71,7 @@ UserState user_get_state(User *u);
|
||||
int user_get_idle_hint(User *u, dual_timestamp *t);
|
||||
int user_save(User *u);
|
||||
int user_load(User *u);
|
||||
int user_kill(User *u, int signo);
|
||||
|
||||
char *user_bus_path(User *s);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user