forked from cockpit/cockpit
Adam Majer
95a20dc719
- new version 316: * cockpit.js API: Fix format_bytes() units - add users_support_for_lastlog_001.patch (bsc#1220551) - add users_support_for_lastlog_002.patch (bsc#1220551) ------------------------------------ OBS-URL: https://build.opensuse.org/request/show/1175756 OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:cockpit/cockpit?expand=0&rev=172
158 lines
6.3 KiB
Diff
158 lines
6.3 KiB
Diff
From 059a8d35a3d9e54d86ff8178967a8fc98f428f11 Mon Sep 17 00:00:00 2001
|
|
From: Luna <luna.dragon@suse.com>
|
|
Date: Tue, 21 May 2024 13:21:54 +0530
|
|
Subject: [PATCH] users: Support for watching lastlog2 and wutmp on overview
|
|
page
|
|
|
|
---
|
|
pkg/users/account-details.js | 26 ++++++++++----------------
|
|
pkg/users/users.js | 27 +++++++++++++++++----------
|
|
pkg/users/utils.js | 14 ++++++++++++++
|
|
3 files changed, 41 insertions(+), 26 deletions(-)
|
|
|
|
diff --git a/pkg/users/account-details.js b/pkg/users/account-details.js
|
|
index 11c7870af..8159a1cf3 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,32 +99,25 @@ function get_expire(name) {
|
|
|
|
export function AccountDetails({ accounts, groups, current_user, user, shells }) {
|
|
const [expiration, setExpiration] = useState(null);
|
|
- const [lastlogpath, setLastlogPath] = useState(null);
|
|
+ const [utmppath, setUtmpPath] = useState(null);
|
|
|
|
- useEffect(() => {
|
|
- cockpit.spawn(["test", "-e", "/var/run/utmp"], { err: "ignore" }).then(() => {
|
|
- setLastlogPath("/var/run/utmp");
|
|
- }).catch(() => {
|
|
- cockpit.spawn(["test", "-e", "/var/lib/lastlog/lastlog2.db"], { err: "ignore" }).then(() => {
|
|
- setLastlogPath("/var/lib/lastlog/lastlog2.db");
|
|
- }).catch(() => {
|
|
- setLastlogPath(null);
|
|
- });
|
|
- });
|
|
- }, []);
|
|
+ // react wants sync functions that wrap async ones to prevent race conditions
|
|
+ useInit(async () => {
|
|
+ setUtmpPath(await getUtmpPath());
|
|
+ });
|
|
|
|
useEffect(() => {
|
|
- if (lastlogpath !== null) {
|
|
+ if (utmppath !== null) {
|
|
get_expire(user).then(setExpiration);
|
|
|
|
// Watch lastlog log to register when user logs in or out
|
|
- const handle = cockpit.file(lastlogpath, { superuser: "try", binary: true });
|
|
+ const handle = cockpit.file(utmppath, { superuser: "try", binary: true });
|
|
handle.watch(() => {
|
|
get_expire(user).then(setExpiration);
|
|
}, { read: false });
|
|
return handle.close;
|
|
}
|
|
- }, [user, accounts, lastlogpath]);
|
|
+ }, [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 08029bdfa..006acf1c3 100755
|
|
--- a/pkg/users/users.js
|
|
+++ b/pkg/users/users.js
|
|
@@ -31,7 +31,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";
|
|
|
|
@@ -69,15 +69,19 @@ function AccountsPage() {
|
|
const [max_uid, setMaxUid] = useState(60000);
|
|
const [details, setDetails] = useState(null);
|
|
|
|
- useInit(() => {
|
|
+ useInit(async () => {
|
|
+ const utmppath = await getUtmpPath();
|
|
const debouncedGetLogins = debounce(100, () => {
|
|
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(() => debouncedGetLogins(), { read: false });
|
|
+ let handleUtmp;
|
|
|
|
+ if (utmppath !== null) {
|
|
+ // Watch `/var/run/utmp` or `/var/lib/wtmpdb/wtmp.db` to register when user logs in or out
|
|
+ handleUtmp = cockpit.file(utmppath, { superuser: "try", binary: true });
|
|
+ handleUtmp.watch(() => debouncedGetLogins(), { 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(() => debouncedGetLogins(), { read: false });
|
|
@@ -153,19 +157,22 @@ function AccountsPage() {
|
|
} else if (path.length === 1) {
|
|
return (
|
|
<AccountDetails accounts={accountsInfo} groups={groupsExtraInfo}
|
|
- current_user={current_user_info?.name} user={path[0]} shells={shells} />
|
|
+ current_user={current_user_info?.name} user={path[0]} shells={shells} />
|
|
);
|
|
} else return null;
|
|
}
|
|
|
|
async function getLogins() {
|
|
- let lastlog = "";
|
|
+ let LastLogPath;
|
|
try {
|
|
- lastlog = await cockpit.spawn(["lastlog"], { environ: ["LC_ALL=C"] });
|
|
- } catch (err) {
|
|
- console.warn("Unexpected error when getting last login information", err);
|
|
+ await cockpit.spawn(["test", "-e", "/var/lib/lastlog/lastlog2.db"], { err: "ignore" });
|
|
+ LastLogPath = "lastlog2";
|
|
+ } catch (err1) {
|
|
+ LastLogPath = "lastlog";
|
|
}
|
|
|
|
+ const lastlog = await cockpit.spawn([LastLogPath], { environ: ["LC_ALL=C"] });
|
|
+
|
|
let currentLogins = [];
|
|
try {
|
|
const w = await cockpit.spawn(["w", "-sh"], { environ: ["LC_ALL=C"] });
|
|
diff --git a/pkg/users/utils.js b/pkg/users/utils.js
|
|
index a3837ef3c..b28c6188e 100644
|
|
--- a/pkg/users/utils.js
|
|
+++ b/pkg/users/utils.js
|
|
@@ -12,3 +12,17 @@ export const get_locked = name =>
|
|
console.warn(`Failed to obtain account lock information for ${name}`, exc);
|
|
}
|
|
});
|
|
+
|
|
+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
|
|
|