Skip to content

Conversation

@calsys456
Copy link
Contributor

@calsys456 calsys456 commented Dec 18, 2025

  • Merge HelperApp into Auth
  • Move Auth & UserSession into daemon
  • Simplify Auth, remove redundant logics

This commit largely simplify the code.

Note that the function of starting sessions other than treeland will temporarily not work after this commit, due to some wrongly designed obsolete code. This will be fixed soon in the next commit.

Summary by Sourcery

Merge authentication and session management into the daemon, removing the separate helper components and simplifying the login/session startup flow.

Enhancements:

  • Inline the former HelperApp and auth library logic into a new daemon-side Auth class that owns PAM and UserSession lifecycle.
  • Refactor UserSession to be controlled directly by Auth and simplify session startup paths for X11 and Wayland, including error handling and exit status reporting.
  • Streamline Display and Greeter interactions with Auth by using direct properties and reduced signals, removing request/prompt handling and greeter-side display-server notification hooks.

Build:

  • Remove the standalone auth and helper subprojects from the build and add Auth, Pam, and UserSession sources into the daemon target, updating dependencies to link against common and PAM.

@deepin-ci-robot
Copy link

Hi @calsys456. Thanks for your PR.

I'm waiting for a linuxdeepin member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 18, 2025

Reviewer's Guide

Refactors authentication and session startup by inlining the former helper process into the daemon: introduces a new in-process Auth implementation using PAM and UserSession, removes the separate auth/helper submodules, converts Auth from a request-driven QObject API to a simple state/field-based class, and rewires Display and Greeter to use the new interface and exit-status enum while simplifying session handling and greeter plumbing.

Sequence diagram for authentication and user session startup with new Auth

sequenceDiagram
    autonumber
    actor User
    participant Greeter
    participant Display
    participant Auth
    participant Pam
    participant UserSession

    User ->> Greeter: enter credentials
    Greeter ->> Auth: new Auth(parent)
    Greeter ->> Auth: set fields (user, displayServerCmd, sessionPath, singleMode, skipAuth)
    Note over Greeter,Auth: For normal login Display creates Auth and sets session info

    par Identify_only_or_full
        Display ->> Auth: start(secret)
    and
        Greeter ->> Auth: start(secret_or_empty)
    end

    Auth ->> Pam: user = user
    Auth ->> Pam: start()
    Pam -->> Auth: bool started
    alt PAM start failed
        Auth -->> Display: authentication(user, false, identifyOnly)
        Auth -->> Greeter: authentication(user, false, identifyOnly)
        Auth ->> Auth: utmpLogin(..., authSuccessful=false)
        Auth -->> Display: finished(AUTH_ERROR)
        Auth -->> Greeter: finished(AUTH_ERROR)
    else PAM started
        alt skipAuth is false
            Auth ->> Pam: authenticate(secret)
            Pam -->> Auth: bool success
            alt auth failed
                Auth -->> Display: authentication(user, false, identifyOnly)
                Auth -->> Greeter: authentication(user, false, identifyOnly)
                Auth ->> Auth: utmpLogin(..., authSuccessful=false)
                Auth -->> Display: finished(AUTH_ERROR)
                Auth -->> Greeter: finished(AUTH_ERROR)
            else auth ok
                Auth -->> Display: authentication(user, true, identifyOnly)
                Auth -->> Greeter: authentication(user, true, identifyOnly)
            end
        else skipAuth is true
            Auth -->> Display: authentication(user, true, identifyOnly)
            Auth -->> Greeter: authentication(user, true, identifyOnly)
        end

        opt sessionPath not empty
            Auth ->> Pam: openSession(environment)
            Pam -->> Auth: env or failure
            alt openSession failed
                Auth -->> Display: sessionStarted(false, 0)
                Auth -->> Greeter: sessionStarted(false, 0)
                Auth -->> Display: finished(SESSION_ERROR)
                Auth -->> Greeter: finished(SESSION_ERROR)
            else openSession ok
                Auth ->> Auth: fill HOME,PWD,SHELL,USER,LOGNAME
                Auth ->> UserSession: setProcessEnvironment(env)
                Auth ->> UserSession: start()
                Auth ->> Auth: utmpLogin(..., authSuccessful=true)
                Auth ->> Auth: xdgSessionId = env[XDG_SESSION_ID]
                Auth -->> Display: sessionStarted(true, xdgSessionId)
                Auth -->> Greeter: sessionStarted(true, xdgSessionId)
            end
        end
    end

    rect rgb(235,235,235)
    Note over UserSession,Auth: Later, when UserSession exits, Auth emits finished status via UserSession finished connection
    end
Loading

Class diagram for new in-daemon Auth and UserSession model

classDiagram
    class Auth {
        <<QObject>>
        +bool active
        +QString displayServerCmd
        +QString sessionPath
        +Session_Type sessionType
        +QString sessionFileName
        +QString user
        +QByteArray cookie
        +bool autologin
        +bool greeter
        +bool singleMode
        +bool identifyOnly
        +bool skipAuth
        +QProcessEnvironment environment
        +int id
        +static int lastId
        +QString sessionId
        +int tty
        +int xdgSessionId
        +Auth(QObject *parent)
        +~Auth()
        +void start(QByteArray secret)
        +void stop()
        +void authentication(QString user, bool success, bool identifyOnly)
        +void sessionStarted(bool success, int xdgSessionId)
        +void finished(Auth_ExitStatus status)
        -Pam *m_pam
        -UserSession *m_session
        -void utmpLogin(QString vt, QString displayName, QString user, qint64 pid, bool authSuccessful)
        -void utmpLogout(QString vt, QString displayName, qint64 pid)
    }

    class Auth_ExitStatus {
        <<enumeration>>
        SUCCESS
        AUTH_ERROR
        SESSION_ERROR
        OTHER_ERROR
        DISPLAYSERVER_ERROR
        TTY_ERROR
    }

    class UserSession {
        <<QProcess>>
        +qint64 cachedProcessId
        +UserSession(Auth *parent)
        +void start()
        +void stop()
        -void childModifier()
        -QTemporaryFile m_xauthFile
        -Auth *m_auth
    }

    class Pam {
        +QString user
        +bool sessionOpened
        +Pam(QObject *parent)
        +bool start()
        +bool authenticate(QByteArray secret)
        +std_optional_QProcessEnvironment openSession(QProcessEnvironment baseEnv)
        +void closeSession()
    }

    class Display {
        +QVector~Auth*~ m_auths
        +Auth *m_currentAuth
        +int m_terminalId
        +int m_sessionTerminalId
        +void identifyUser(QString user, QString password)
        +void startAuth(QString user, QString password, Session session)
        +void slotAuthenticationFinished(QString user, bool success, bool identifyOnly)
        +void slotSessionStarted(bool success, int xdgSessionId)
        +void slotHelperFinished(Auth_ExitStatus status)
    }

    class Greeter {
        +Auth *m_auth
        +bool m_singleMode
        +bool m_userActivated
        +QString m_user
        +QString m_displayServerCmd
        +void start()
        +void onSessionStarted(bool success, int xdgSessionId)
        +void onHelperFinished(Auth_ExitStatus status)
        +bool isRunning() const
    }

    Auth "1" o-- "1" Pam : owns
    Auth "1" o-- "1" UserSession : owns
    UserSession --> Auth : parent
    Display --> Auth : manages
    Greeter --> Auth : manages
Loading

File-Level Changes

Change Details Files
Move UserSession into the daemon and bind it directly to Auth instead of the removed HelperApp helper process.
  • Relocate UserSession from src/helper to src/daemon and adjust includes and build configuration accordingly
  • Change UserSession constructor to take an Auth parent and expose a public cachedProcessId field instead of a getter
  • Simplify UserSession::start to be void, removing start-status logic and all greeter-specific helper binaries
  • Replace usage of HelperApp APIs (cookie, user, singleMode, path, displayServerCommand) with direct access to corresponding Auth fields
  • Normalize childModifier error paths to use the new Auth::ExitStatus values and remove platform-specific (FreeBSD) branches and unused includes
src/helper/UserSession.cpp
src/daemon/UserSession.cpp
src/helper/UserSession.h
src/daemon/UserSession.h
Introduce a new in-daemon Auth class that owns PAM and UserSession, and handles authentication, session startup, and utmp/wtmp accounting synchronously.
  • Add src/daemon/Auth.h/Auth.cpp implementing Auth as a QObject with simple public fields (user, sessionPath, sessionType, cookie, tty, environment, flags) and a start(secret) method
  • Implement PAM interaction via a Pam member and a UserSession member, opening the session, populating env (HOME, SHELL, USER, etc.), and starting the UserSession with that environment
  • Add utmp/wtmp/btmp login/logout helpers (utmpLogin/utmpLogout) called in start/stop using display/VT info from the environment and session process ID
  • Define a compact Auth::ExitStatus enum used by both Auth and UserSession for error reporting and lifecycle management
  • Track per-Auth IDs via a static lastId and an id field
src/daemon/Auth.h
src/daemon/Auth.cpp
Simplify Display to the new Auth API and remove all request/prompt-driven helper wiring and info/error propagation.
  • Replace Auth accessor methods (user(), tty(), session(), sessionFileName(), sessionType(), isActive(), isSingleMode(), identifyOnly(), sessionId(), xdgSessionId(), set* and insertEnvironment) with direct field access on Auth instances
  • Update authentication and session start paths to construct/configure Auth by setting fields (user, tty, sessionPath, sessionType, sessionFileName, sessionId, environment, singleMode, identifyOnly) and calling start(password.toLocal8Bit())
  • Wire Auth::finished to slotHelperFinished(Auth::ExitStatus) and adjust logic to use the new ExitStatus values, including AUTH_ERROR for auth failures
  • Remove connections and slots for Auth::requestChanged, info, and error, and drop all PAM prompt handling and socket messaging around those signals
  • Adjust login success/cleanup logic (loginedSession, last user/session tracking, display server recreation, and session removal) to use the new fields and the new exit-status enum
src/daemon/Display.cpp
src/daemon/Display.h
Simplify Greeter’s interaction with Auth to use the new field-based API and ExitStatus enum, dropping all request/display-server-ready plumbing.
  • Update Greeter to create Auth without verbose/requestChanged/info/error wiring, connecting only sessionStarted and finished(Auth::ExitStatus)
  • Populate Auth fields directly (user, displayServerCmd, sessionPath, singleMode, greeter, environment, skipAuth) and start it with start("")
  • Remove onRequestChanged and onDisplayServerReady slots and associated signal connections, along with greeter-side authInfo/authError logging
  • Adjust greeter retry logic and completion handling to use the new Auth::ExitStatus values (DISPLAYSERVER_ERROR, TTY_ERROR, SESSION_ERROR, SUCCESS) and the simplified start interface
  • Use Auth::active instead of isActive() for isRunning() checks
src/daemon/Greeter.cpp
src/daemon/Greeter.h
Update build system to inline former auth/helper components into the daemon and link the correct libraries for PAM and common code.
  • Remove src/auth and src/helper subdirectories from the top-level src CMake configuration
  • Add Auth.cpp, Pam.cpp, and UserSession.cpp to the daemon target sources
  • Switch ddm target linkage from the removed auth library to a common library and add PAM libraries to the link list
src/CMakeLists.txt
src/daemon/CMakeLists.txt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • The new UserSession::cachedProcessId member is never updated (previously m_cachedProcessId was set after waitForStarted()), so Auth::stop() may log out with an invalid PID and skip utmp/wtmp logout; consider updating cachedProcessId on process start/finish and using it in utmpLogout.
  • In Auth::start(), the LOGIN_FAILED macro uses environment to derive DISPLAY/XDG_VTNR, but environment may still be empty at that point, so failed logins will be recorded with missing TTY/display; consider passing in or constructing a minimal environment (or TTY/display) before calling utmpLogin on failure.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `UserSession::cachedProcessId` member is never updated (previously `m_cachedProcessId` was set after `waitForStarted()`), so `Auth::stop()` may log out with an invalid PID and skip utmp/wtmp logout; consider updating `cachedProcessId` on process start/finish and using it in `utmpLogout`.
- In `Auth::start()`, the `LOGIN_FAILED` macro uses `environment` to derive `DISPLAY`/`XDG_VTNR`, but `environment` may still be empty at that point, so failed logins will be recorded with missing TTY/display; consider passing in or constructing a minimal environment (or TTY/display) before calling `utmpLogin` on failure.

## Individual Comments

### Comment 1
<location> `src/daemon/Auth.cpp:108-117` </location>
<code_context>
+    void Auth::stop() {
+        Q_ASSERT(getuid() == 0);
+
+        qint64 pid = m_session->processId();
+        m_session->stop();
+        if (!identifyOnly && m_pam->sessionOpened) {
+            m_pam->closeSession();
+        }
+
+        // write logout to utmp/wtmp
+        if (pid < 0)
+            return;
+        QProcessEnvironment env = m_session->processEnvironment();
+        QString vt = env.value(QStringLiteral("XDG_VTNR"));
+        QString displayId = env.value(QStringLiteral("DISPLAY"));
+        utmpLogout(vt, displayId, pid);
+    }
+
</code_context>

<issue_to_address>
**issue:** `pid < 0` check likely won’t filter out the "no process" case, leading to bogus utmp logout records.

In `Auth::stop()` you fetch the PID before stopping the session:
```cpp
qint64 pid = m_session->processId();
...
// write logout to utmp/wtmp
if (pid < 0)
    return;
...
utmpLogout(vt, displayId, pid);
```
On Qt, `QProcess::processId()` usually returns `0` when there is no running process, not a negative value, so this guard won’t stop a logout with PID 0 for sessions that never actually started. Please use a check that matches the documented “no process” value, e.g. `pid <= 0`, before calling `utmpLogout`.
</issue_to_address>

### Comment 2
<location> `src/daemon/Auth.cpp:72-42` </location>
<code_context>
+
+        Q_EMIT authentication(user, true, identifyOnly);
+
+        if (!sessionPath.isEmpty()) {
+            auto sessionEnv = m_pam->openSession(environment);
+            if (!sessionEnv.has_value()) {
+                Q_EMIT sessionStarted(false, 0);
+                Q_EMIT finished(SESSION_ERROR);
+                return;
+            }
+
+            QProcessEnvironment env = *sessionEnv;
</code_context>

<issue_to_address>
**issue (bug_risk):** `Auth::start()` never emits `finished()` when no session is started (e.g. identify-only), so listeners may leak state.

`finished(...)` is only emitted inside the `!sessionPath.isEmpty()` branch (either on `SESSION_ERROR` or via `UserSession` exit). When `sessionPath` is empty (identify-only), `Auth::start()` returns without ever emitting `finished`, but callers like `Display::identifyUser()` still rely on it (e.g. `slotHelperFinished` removing the `Auth` from `m_auths`). This can leave stale `Auth` instances and inconsistent state. Please emit `finished(SUCCESS)` (or another appropriate status) at the end of `Auth::start()` when `sessionPath` is empty to keep the lifecycle consistent.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

zccrs
zccrs previously approved these changes Dec 18, 2025
- Merge HelperApp into Auth
- Move Auth & UserSession into daemon
- Simplify Auth, remove redundant logics

This commit largely simplify the code.

Note that the function of starting sessions other than treeland will
temporarily not work after this commit, due to some wrongly designed
obsolete code. This will be fixed soon in the next commit.
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: calsys456, zccrs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@zccrs zccrs merged commit 4d68247 into linuxdeepin:master Dec 22, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants