cockpit/0001-users-Support-for-watching-lastlog2-and-wutmp-on-ove.patch

138 lines
5.2 KiB
Diff

From b95268ea4002fe7bcc7839d0bc7587c4e76306c5 Mon Sep 17 00:00:00 2001
From: Luna <luna.dragon@suse.com>
Date: Wed, 5 Jun 2024 10:34:15 +0530
Subject: [PATCH] users: Support for watching lastlog2 and wutmp on overview
page
---
pkg/users/account-details.js | 27 ++++++++++++++++++---------
pkg/users/users.js | 22 ++++++++++++++--------
pkg/users/utils.js | 14 ++++++++++++++
3 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/pkg/users/account-details.js b/pkg/users/account-details.js
index 9edd70c41..94710912a 100644
--- a/pkg/users/account-details.js
+++ b/pkg/users/account-details.js
@@ -48,7 +48,8 @@ import { account_shell_dialog } from "./shell-dialog.js";
import { set_password_dialog, reset_password_dialog } from "./password-dialogs.js";
import { AccountLogs } from "./account-logs-panel.jsx";
import { AuthorizedKeys } from "./authorized-keys-panel.js";
-import { get_locked } from "./utils.js";
+import { get_locked, getUtmpPath } from "./utils.js";
+import { useInit } from 'hooks.js';
const _ = cockpit.gettext;
@@ -98,16 +99,24 @@ function get_expire(name) {
export function AccountDetails({ accounts, groups, current_user, user, shells }) {
const [expiration, setExpiration] = useState(null);
- useEffect(() => {
- get_expire(user).then(setExpiration);
+ const [utmppath, setUtmpPath] = useState(null);
+
+ useInit(async () => {
+ setUtmpPath(await getUtmpPath());
+ });
- // Watch `/var/run/utmp` to register when user logs in or out
- const handle = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
- handle.watch(() => {
+ useEffect(() => {
+ if (utmppath !== null) {
get_expire(user).then(setExpiration);
- });
- return handle.close;
- }, [user, accounts]);
+
+ // Watch `/var/run/utmp` to register when user logs in or out
+ const handle = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
+ handle.watch(() => {
+ get_expire(user).then(setExpiration);
+ });
+ return handle.close;
+ }
+ }, [user, accounts, utmppath]);
const [edited_real_name, set_edited_real_name] = useState(null);
const [committing_real_name, set_committing_real_name] = useState(false);
diff --git a/pkg/users/users.js b/pkg/users/users.js
index 8f35be519..ecafc3472 100755
--- a/pkg/users/users.js
+++ b/pkg/users/users.js
@@ -29,7 +29,7 @@ import { usePageLocation, useLoggedInUser, useFile, useInit } from "hooks.js";
import { etc_passwd_syntax, etc_group_syntax, etc_shells_syntax } from "pam_user_parser.js";
import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";
-import { get_locked } from "./utils.js";
+import { get_locked, getUtmpPath } from "./utils.js";
import { AccountsMain } from "./accounts-list.js";
import { AccountDetails } from "./account-details.js";
@@ -86,13 +86,17 @@ function AccountsPage() {
}, [logindef]);
const [details, setDetails] = useState(null);
- useInit(() => {
+ useInit(async () => {
+ const utmppath = await getUtmpPath();
+
getLogins().then(setDetails);
// Watch `/var/run/utmp` to register when user logs in or out
- const handleUtmp = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
- handleUtmp.watch(() => getLogins().then(setDetails), { read: false });
-
+ let handleUtmp;
+ if (utmppath !== null) {
+ handleUtmp = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
+ handleUtmp.watch(() => getLogins().then(setDetails), { read: false });
+ }
// Watch /etc/shadow to register lock/unlock/expire changes; but avoid reading it, it's sensitive data
const handleShadow = cockpit.file("/etc/shadow", { superuser: "try" });
handleShadow.watch(() => getLogins().then(setDetails), { read: false });
@@ -151,12 +155,14 @@ function AccountsPage() {
}
async function getLogins() {
- let lastlog = "";
+ let LastLogPath;
try {
- lastlog = await cockpit.spawn(["lastlog"], { environ: ["LC_ALL=C"] });
+ await cockpit.spawn(["test", "-e", "/var/lib/lastlog/lastlog2.db"], { err: "ignore" });
+ LastLogPath = "lastlog2";
} catch (err) {
- console.warn("Unexpected error when getting last login information", err);
+ LastLogPath = "lastlog";
}
+ const lastlog = await cockpit.spawn([LastLogPath], { environ: ["LC_ALL=C"] });
let currentLogins = [];
try {
diff --git a/pkg/users/utils.js b/pkg/users/utils.js
index 7b2efed05..3cbe295a5 100644
--- a/pkg/users/utils.js
+++ b/pkg/users/utils.js
@@ -8,3 +8,17 @@ export const get_locked = name =>
return status == "LK" || status == "L";
})
.catch(() => null);
+
+export async function getUtmpPath() {
+ try {
+ await cockpit.spawn(["test", "-e", "/var/run/utmp"], { err: "ignore" });
+ return "/var/run/utmp";
+ } catch (err1) {
+ try {
+ await cockpit.spawn(["test", "-e", "/var/lib/wtmpdb/wtmp.db"], { err: "ignore" });
+ return "/var/lib/wtmpdb/wtmp.db";
+ } catch (err2) {
+ return null;
+ }
+ }
+}
--
2.45.1