Skip to content

Authentication architecture redesign

matt335672 edited this page Jan 17, 2023 · 12 revisions

Summary

This page summarises some architectural changes that will enable these features:-

Updates

Date Comment
23-Aug-2021 Extended to cover xrdp-sesadmin dataflows
24-Aug-2021 Addressed review comments from @aquesnel and separated out connect and authentication phases
26-Aug-2021 Clarifications and typos identified by @aquesnel are fixed.
6-May-2022 Add UDS authentication and file descriptor detail
18-May-2022 PAM conversation extracted as separate dataflow, and implementation details added.
6-Sep-2022 Clarifications - no changes
21-Nov-2022 Use 'login' rather than 'authenticate'. Clarify multiple UDS logins are unsupported. Replace 'xrdp done' with 'logout' and 'close connection'.
11-Jan-2023 Specify file descriptor passing
17-Jan-2023 Replace sdriver with sesexec

Diagrams

This page contains some embedded PlantUML diagrams, the source of which is in the dropdown below.

Diagram sources
/'============================================================================
  Overview diagram

This has mostly been put together by @aquesnel =========================================================================='/

@startuml overview participant "Rdp Client" AS client participant "Xrdp" AS xrdpListner collections "xrdp per client" AS xrdp participant "Session Manager (xrdp-sesman)" AS sesman collections "Session Executive" AS sesexec participant "PAM" AS pam participant "Window Manager" AS wm participant "X Server" AS x participant "Channel Server (xrdp-chansrv)" AS chansrv

== Session Initialize ==

activate xrdpListner activate client client -> xrdpListner: connect xrdpListner -> xrdp: fork \n[xrdp_listen_fork(/xrdp/xrdp/xrdp_listen.c)] activate xrdp deactivate xrdpListner

== Connect ==

client -> xrdp: send credentials xrdp -> sesman: connect activate sesman

== Login ==

xrdp -> sesman : Login using PAM create sesexec activate sesexec sesman -> sesexec: fork and set up a communications link sesman -> sesexec: Login using PAM with this xrdp file descriptor sesman -X sesman : Sesman closes xrdp file descriptor copy.

ref over xrdp, sesexec, pam : PAM Conversation

sesman <- sesexec : Login result success, + xrdp file descriptor sesexec -X sesexec : sesexec closes file descriptor copy xrdp <- sesman : Login result success

=== New session ===

xrdp -> sesman : Connect to session sesman -> sesexec : Start session on display D + xrdp file descriptor sesman -X sesman : sesman closes xrdp file descriptor copy deactivate sesman

sesexec -> x: fork activate x sesexec -> chansrv: fork activate chansrv chansrv -> x: connect sesexec -> wm: fork activate wm wm -> x: connect

xrdp <- sesexec : Session started OK on display D xrdp -X xrdp : xrdp closes the file descriptor to sesman/sesexec sesexec -X sesexec : sesexec closes xrdp file descriptor copy sesexec -> sesexec: wait for window manager process to terminate deactivate sesexec

xrdp -> x: connect \n[lib_mod_connect(/xrdp/xup/xup.c)] xrdp -> chansrv: connect

== Session In Progress ==

loop until window manager process terminates x -> xrdp: display data xrdp -> client: display data chansrv -> xrdp: channel data xrdp -> client: channel data

client -> xrdp: input data xrdp -> x: input data client -> xrdp: channel data xrdp -> chansrv: channel data end

== Session End ==

note right of wm Some event (eg. user input) causes the Window Manager to terminate end note

destroy wm wm -> sesexec: window manager terminated activate sesexec

sesexec -> x: send SIGTERM sesexec -> x: wait for X server process to terminate xrdp <- x : X server closes connection xrdp -> client: disconnect destroy x destroy xrdp destroy client sesexec <- x: X server terminated

sesexec -> chansrv: send SIGTERM sesexec -> chansrv: wait for channel server to terminate destroy chansrv sesexec <- chansrv: Channel server terminated

sesexec -> pam: end PAM session destroy pam

sesexec -> sesexec: clean up sockets destroy sesexec sesexec -> sesman: Xrdp-Session terminated activate sesman sesman -> sesman: remove session from list of active sessions \n[sig_sesman_session_end(/xrdp/sesman/sig.c)] deactivate sesman

@enduml

'============================================================================

@startuml connect participant xrdp participant sesman

activate xrdp activate sesman

xrdp -> sesman : connect

@enduml

'============================================================================

@startuml uds-login-fail participant xrdp participant sesman

activate xrdp activate sesman

xrdp -> sesman : Login using UDS credentials xrdp <- sesman : Login result fail xrdp X- sesman : Sesman closes connection note over xrdp: No retries are allowed for UDS login attempts destroy xrdp

@enduml

'============================================================================

@startuml uds-login-ok participant xrdp participant sesman

activate xrdp activate sesman

xrdp -> sesman : Login using UDS credentials xrdp <- sesman : Login result success

@enduml

'============================================================================

@startuml pam-conversation participant xrdp participant sesexec participant "PAM" AS pam

activate xrdp activate sesexec activate pam sesexec -> pam: pam_start() sesexec <- pam : pam_conv() callback 1 xrdp <- sesexec : PAM prompt 1 xrdp -> sesexec : PAM response 1 ... Some messages ... sesexec <- pam : pam_conv() callback n xrdp <- sesexec : PAM prompt n xrdp -> sesexec : PAM response n sesexec <- pam : login result (success/fail) destroy pam

@enduml

'============================================================================

@startuml pam-login-fail participant xrdp participant sesman participant sesexec participant "PAM" AS pam

activate xrdp activate sesman

xrdp -> sesman : Login using PAM alt If sesexec not active for connection create sesexec activate sesexec sesman -> sesexec : fork and set up a communications link end sesman -> sesexec: Login using PAM with this xrdp file descriptor sesman -X sesman : Sesman closes xrdp file descriptor copy. deactivate sesman

ref over xrdp, sesexec, pam : PAM Conversation sesman <- sesexec : Login result fail activate sesman deactivate sesexec xrdp <- sesman : Login result fail note over sesman: Login result fail message contains a retry flag alt sesman detects MaxLoginRetryLimit reached (#1739)

xrdp X- sesman : Sesman closes connection note over xrdp: xrdp checks retry flag and exits destroy xrdp activate sesexec sesman -X sesexec : Closes sesexec connection sesexec -> sesexec : sesexec exits destroy sesexec

else limit not reached note over xrdp xrdp can issue another login message end note end

@enduml

'============================================================================

@startuml pam-login-ok participant xrdp participant sesman participant sesexec participant "PAM" AS pam

activate xrdp activate sesman

xrdp -> sesman : Login using PAM alt If sesexec not active for connection create sesexec activate sesexec sesman -> sesexec : fork and set up a communications link end sesman -> sesexec: Login using PAM with this xrdp file descriptor sesman -X sesman : Sesman closes xrdp file descriptor copy.

ref over xrdp, sesexec, pam : PAM Conversation sesman <- sesexec : Login result success, + xrdp file descriptor sesexec -X sesexec : sesexec closes xrdp file descriptor copy deactivate sesexec xrdp <- sesman : Login result success

@enduml

'============================================================================

@startuml newsession

participant xrdp participant sesman participant sesexec participant "PAM" AS pam participant "Session Processes" AS wmsession

ref over xrdp, sesman, sesexec, pam : This is preceded by a successful login sequence

activate xrdp activate sesman activate pam

xrdp -> sesman : Connect to session alt If sesexec not active for connection create sesexec activate sesexec sesman -> sesexec : fork and set up a communications link end note over sesman : sesman picks a suitable display number sesman -> sesexec : Start session on display D with this xrdp file descriptor sesman -X sesman : sesman closes xrdp file descriptor copy deactivate sesman sesexec -> pam : pam_open_session() sesexec -> wmsession : sesexec forks session processes on display D activate wmsession xrdp <- sesexec : Session started OK on display D xrdp -X xrdp : xrdp closes the file descriptor to sesman/sesexec sesexec -X sesexec : sesexec closes xrdp file descriptor copy note over sesman, sesexec : No more direct messages are exchanged with xrdp

@enduml

'============================================================================

@startuml samesession participant xrdp participant sesman participant sesexec

ref over xrdp, sesman, sesexec : This is preceded by a successful login sequence

activate xrdp activate sesexec activate sesman

xrdp -> sesman : Connect to session note over sesman: Sesman finds an already active session xrdp <- sesman: Connect to display D xrdp -X xrdp : xrdp closes the file descriptor to sesman sesman -X sesman : sesman closes xrdp file descriptor alt If sesexec was activated to authenticate user sesman -> sesexec : Closedown sesexec -X sesexec : sesexec exits destroy sesexec end

@enduml

'============================================================================

@startuml runsession

participant xrdp participant sesman participant sesexec participant "PAM" AS pam participant "Session Processes" AS wmsession

ref over xrdp, sesman, sesexec, pam, wmsession : This is preceded by connect session

activate xrdp activate sesexec activate pam activate wmsession

xrdp -> wmsession : xrdp connects to session ... Session runs ... sesexec <- wmsession : User closes session xrdp <- wmsession : X server exits destroy xrdp destroy wmsession sesexec -> pam : pam_close_session() / pam_end() destroy pam

activate sesman sesman X- sesexec : sesexec closes sesman connection and exits destroy sesexec

sesman -> sesman: remove session from list of active sessions

@enduml

'============================================================================

@startuml list-sessions participant xrdp participant sesman

ref over xrdp, sesman : This is preceded by a successful login sequence

activate xrdp activate sesman

xrdp -> sesman : List sessions loop for each session xrdp <- sesman : Session data note right : Contains end-of-list marker end

@enduml

'============================================================================

@startuml logout participant xrdp participant sesman participant sesexec participant "PAM" AS pam

activate xrdp activate sesman activate sesexec activate pam

ref over xrdp, sesman, sesexec, pam : This is preceded by a successful login sequence

xrdp -> sesman : xrdp sends logout message alt If sesexec was activated to authenticate user sesman -> sesexec : Closedown sesexec -> pam : pam_close_session() / pam_end() as appropriate sesexec -X sesexec : sesexec exits sesman X- sesexec : sesexec closes sesman connection and exits destroy sesexec destroy pam sesman -> sesman: remove any state data\nrelating to sesexec process

@enduml

'============================================================================

@startuml close-connection participant xrdp participant sesman

activate xrdp activate sesman

xrdp -> sesman : xrdp sends close connection message xrdp -> xrdp : xrdp closes connection destroy xrdp

sesman ->sesman : tidies up xrdp connection without\ngenerating errors in the log.

@enduml

To regenerate the diagrams, pull this library, run the generate_auth_images.sh script, commit the changes and push the library.

Drivers and scope

See https://github.com/neutrinolabs/xrdp/discussions/1961

Terminology

Login

This encompasses both 'authentication' (who the user is) and 'authorization' (what the user is allowed to do).

Early versions of this page used 'authentication' or 'auth' in an unclear way. These uses have been replaced with 'login'.

Session

Session is a word which has become somewhat overloaded in computing.

For the purposes of this document, 'session' encompasses the time from a successful login up until the time the user explicitly logs out of the desktop. It's more or less equivalent to a window manager session, a PAM session, or a systemd session.

Session executive

During the exploration of #1684, it was determined that all the PAM calls relating to a PAM session need to be made from the same single thread of execution. The lifetime of this thread needs to encompass the lifetime of the session, as it is responsible for the lifecycle management of the session.

An superficially attractive idea is to incorporate this thread into the sesman process itself. There are many reasons why this isn't a great idea, but there is also at least one show-stopper; On systemd-based systems; when pam_systemd.so is called to start a new session, the entire process which makes the call is added to a systemd session. So the lifecycle management thread for a session needs to be in a separate process.

It is proposed to call this process the session executive or sesexec for short. It's been difficult to find a clear term for this which won't get confused with "session manager" or "session leader", both of which are used in this name space. "Session driver" was used in earlier versions of this document but it doesn't abbreviate well.

This process is also a good place to incorporate other logic relating to a single session:-

  • Starting the X server, window manager and chansrv processes.
  • Stopping the above processes.
  • (out-of-scope) User accounting (see #1408)
  • (out-of-scope) Secret key refreshes for auto-reconnect (see #1443)

Other notes

Support for other login mechanisms

Since #2472 was merged, sesman supports UDS-based logins (regardless of whether or not PAM login is supported). Consequently alse logins are also considered in this document in separate sequence diagrams.

As well as PAM, xrdp supports login via *BSD auth_userokay(), direct password file access and raw kerberos. These will continue to be supported as alternatives to PAM.

xrdp-sesrun

The xrdp-sesrun utility will require updating to use these dataflows. In the diagrams below, simply substitute xrdp-sesman for xrdp. Additionally, code will need to be added to xrdp-sesman to interact with the user at the terminal.

This utility can then be used as a diagnostic for the dataflows below.

xrdp-sesadmin

This utility has been updated to use UDS login (#2472), so the user has a simple way to query sesman state.

File descriptors

While logging in the user via PAM, it will be necessary for both sesman and sesexec to communicate with xrdp at different times.

PR #2494 adds file descriptor passing to the libipm middleware used by xrdp. This allows the file descriptor from xrdp to be passed back and forth between these processes in a natural way.

Using this facility is assumed in this document.

Process Responsibilities

xrdp-sesman

There is a single instance of this process running on a system. It is responsible for:-

  • Providing a single point-of-contact for xrdp and the xrdp-sesrun and xrdp-sesadmin utilities.
  • Acting as a directory for existing xrdp sessions.
  • Allocating X servers for new xrdp sessions.

xrdp-sesexec

There is an instance of this process running for each xrdp session on a system. It is responsible for:-

  • Starting and stopping session executables (X server, window manager and chansrv)
  • All interactions with the PAM stack
  • All session lifecycle management operations.

xrdp

There is a single master instance of this process running on a system, plus a separate forked process for each active xrdp connection.

It is responsible for:-

  • User interation during the logging in phase
  • Managing connections
  • Fowarding/converting data between the RDP client, the backend X server and chansrv.

Data flows

The following diagrams show the interactions between xrdp, sesman,the session executive (sesexec) and the PAM stack

Interactions will generally follow the following three stages:-

  1. A connection phase, where xrdp connects to sesman/sesexec
  2. A logging in phase where the user is authenticated and authorized.
  3. A command phase, where a command is executed for the logged in user.

PAM conversation

Several of these dataflows contain a reference to a PAM conversation.

The conversation happens between the xrdp process (which is responsible for prompting the user) and the PAM stack which logs the user in to the system.

The sesexec process acts as a middle-man between these two actors as follows:-

Connection phase

Login phase

UDS Login

Failed UDS Login

Successful UDS Login

PAM Login

Failed PAM Login

Successful PAM Login

Command phase

Connect session (new session started)

Connect session (existing session reconnected)

Connection session prologue

Following either of the two preceding sequences, xrdp connects to the session as follows:-

List existing sessions

This dataflow is currently exclusive to the xrdp-sesadmin utility. In the diagram, read xrdp-sesadmin for xrdp.

It should be now clear how other commands apart from 'list sessions' can be dropped in to this model.

This also illustrates that SCP messages:-

  • Should be relatively small (i.e. we don't send an array with megabytes of data)
  • Should not be queued. If an SCP message cannot be sent in a timely fashion an error should be generated.

Other dataflows

logout

This dataflow is also by xrdp (or xrdp-sesadmin) to log a user out.

This can be used for simply authenticating a user without a session (i.e. when using xrdp as a VNC/RDP proxy)

close connection

This dataflow is also by xrdp (or xrdp-sesadmin) before closing a connection.

'sesman' can use this as an indicator not to log errors when the connection closes.

Overview

This diagram shows a complete overview of an xrdp session, including the RDP client. The session has these characteristics:-

  • Login is successful with no retries
  • A new session is started
  • the client remains connected for the whole of the session.

Implementation details

The current proposal is to implement the above architecture within the lifetime of the 1.x.x xrdp release series.

The initial release of the architecture will not contain an implementation of the PAM conversation - the existing non-interactive PAM handshake will be retained.

The PAM conversation requires interactive elements to be added to xrdp and xrdp-sesrun, and is likely to be complex. Implementing this aspect may delay availability of the initial release. Once the basic architecture is in place, implementation of the conversation can be added at a slower pace.