LockScreen: use /etc/pam.d/ files for auth

This commit is contained in:
Lysec
2026-01-27 14:15:45 +01:00
parent 382e548d2b
commit 3e1f371912
4 changed files with 74 additions and 61 deletions
+27
View File
@@ -0,0 +1,27 @@
import QtQuick
import Quickshell
QtObject {
id: root
function migrate(adapter, logger, rawJson) {
logger.i("Migration46", "Removing legacy PAM configuration file");
const shellName = "noctalia";
const configDir = Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/";
const pamConfigDir = configDir + "pam";
const pamConfigFile = pamConfigDir + "/password.conf";
// Remove the file if it exists
const script = `rm -f '${pamConfigFile}'`;
Quickshell.execDetached(["sh", "-c", script]);
// Attempt to remove the directory if empty (ignore errors)
const rmdirScript = `rmdir '${pamConfigDir}' 2>/dev/null || true`;
Quickshell.execDetached(["sh", "-c", rmdirScript]);
logger.d("Migration46", "Cleaned up legacy PAM config");
return true;
}
}
+2
View File
@@ -20,6 +20,7 @@ QtObject {
43: migration43Component,
44: migration44Component,
45: migration45Component
// 46: migration46Component
})
// Migration components
@@ -36,4 +37,5 @@ QtObject {
property Component migration43Component: Migration43 {}
property Component migration44Component: Migration44 {}
property Component migration45Component: Migration45 {}
// property Component migration46Component: Migration46 {}
}
-55
View File
@@ -48,11 +48,6 @@ Singleton {
Quickshell.execDetached(["mkdir", "-p", configDir]);
Quickshell.execDetached(["mkdir", "-p", cacheDir]);
// Ensure PAM config file exists in configDir (create once, never override)
if (!Quickshell.env("NOCTALIA_PAM_CONFIG")) {
ensurePamConfig();
}
// Mark directories as created and trigger file loading
directoriesCreated = true;
@@ -1102,56 +1097,6 @@ Singleton {
}
}
// -----------------------------------------------------
// Ensure PAM password.conf exists in configDir (create once, never override)
function ensurePamConfig() {
var pamConfigDir = configDir + "pam";
var pamConfigFile = pamConfigDir + "/password.conf";
// Check if file already exists
fileCheckPamProcess.command = ["test", "-f", pamConfigFile];
fileCheckPamProcess.running = true;
}
function doCreatePamConfig() {
var pamConfigDir = configDir + "pam";
var pamConfigFile = pamConfigDir + "/password.conf";
var pamConfigDirEsc = pamConfigDir.replace(/'/g, "'\\''");
var pamConfigFileEsc = pamConfigFile.replace(/'/g, "'\\''");
// Ensure directory exists
Quickshell.execDetached(["mkdir", "-p", pamConfigDir]);
// Generate the PAM config file content
var configContent = "auth sufficient pam_fprintd.so timeout=-1\n";
configContent += "auth sufficient /run/current-system/sw/lib/security/pam_fprintd.so timeout=-1 # for NixOS\n";
configContent += "auth required pam_unix.so\n";
// Write the config file using heredoc to avoid escaping issues
var script = `cat > '${pamConfigFileEsc}' << 'EOF'\n`;
script += configContent;
script += "EOF\n";
Quickshell.execDetached(["sh", "-c", script]);
Logger.d("Settings", "PAM config file created at:", pamConfigFile);
}
// Process for checking if PAM config file exists
Process {
id: fileCheckPamProcess
running: false
onExited: function (exitCode) {
if (exitCode === 0) {
// File exists, skip creation
Logger.d("Settings", "PAM config file already exists, skipping creation");
} else {
// File doesn't exist, create it
doCreatePamConfig();
}
}
}
// -----------------------------------------------------
// Function to clean up deprecated user/custom bar widgets settings
function upgradeWidget(widget) {
+45 -6
View File
@@ -19,16 +19,50 @@ Scope {
property string infoMessage: ""
property bool fprintdAvailable: false
readonly property string pamConfigDirectory: Quickshell.env("NOCTALIA_PAM_CONFIG") ? "/etc/pam.d" : Settings.configDir + "pam"
readonly property string pamConfig: Quickshell.env("NOCTALIA_PAM_CONFIG") || "password.conf"
readonly property string pamConfigDirectory: "/etc/pam.d"
property string pamConfig: Quickshell.env("NOCTALIA_PAM_SERVICE") || "login"
property bool pamReady: false
Component.onCompleted: {
checkFprintdProc.running = true;
if (Quickshell.env("NOCTALIA_PAM_CONFIG")) {
Logger.i("LockContext", "NOCTALIA_PAM_CONFIG is set, using system PAM config: /etc/pam.d/" + pamConfig);
if (Quickshell.env("NOCTALIA_PAM_SERVICE")) {
Logger.i("LockContext", "NOCTALIA_PAM_SERVICE is set, using system PAM config: /etc/pam.d/" + pamConfig);
pamReady = true;
} else {
Logger.i("LockContext", "Using generated PAM config:", pamConfigDirectory + "/" + pamConfig);
Logger.i("LockContext", "Probing for best PAM service...");
detectPamServiceProc.running = true;
}
}
Process {
id: detectPamServiceProc
command: ["sh", "-c", "
if [ -f /etc/pam.d/login ]; then echo 'login'; exit 0; fi;
if [ -f /etc/pam.d/system-auth ]; then echo 'system-auth'; exit 0; fi;
if [ -f /etc/pam.d/common-auth ]; then echo 'common-auth'; exit 0; fi;
echo 'login';
"]
stdout: StdioCollector {
onStreamFinished: {
const service = String(text || "").trim();
if (service.length > 0) {
root.pamConfig = service;
Logger.i("LockContext", "Detected PAM service: " + service);
} else {
Logger.w("LockContext", "Failed to detect PAM service, defaulting to login");
}
root.pamReady = true;
}
}
stderr: StdioCollector {}
}
onPamReadyChanged: {
if (pamReady) {
if (Settings.data.general.autoStartAuth && currentText === "") {
pam.start();
}
}
}
@@ -56,13 +90,18 @@ Scope {
}
} else {
occupyFingerprintSensorProc.running = false;
if (Settings.data.general.autoStartAuth) {
if (pamReady && Settings.data.general.autoStartAuth) {
pam.start();
}
}
}
function tryUnlock() {
if (!pamReady) {
Logger.w("LockContext", "PAM not ready yet, ignoring unlock attempt");
return;
}
if (waitingForPassword) {
pam.respond(currentText);
unlockInProgress = true;