From 6e8f64439d080ee0df76ebece2a325895cd23b14 Mon Sep 17 00:00:00 2001 From: Gijs Burghoorn Date: Sat, 4 Feb 2023 16:06:43 +0100 Subject: [PATCH] Move SessionProcess and start on docs --- lemurs-core/src/lib.rs | 69 +++++++-- lemurs-core/src/session_environment/mod.rs | 138 +++++++++++------- .../src/session_environment/wayland.rs | 6 +- lemurs-core/src/session_environment/x11.rs | 7 +- 4 files changed, 146 insertions(+), 74 deletions(-) diff --git a/lemurs-core/src/lib.rs b/lemurs-core/src/lib.rs index 7347079..1f7795e 100644 --- a/lemurs-core/src/lib.rs +++ b/lemurs-core/src/lib.rs @@ -1,6 +1,37 @@ -//! # API Example +//! *LeMuRS*-core or *Login Manager RuSt* abstracts the complicated behavior needed when creating +//! Login/Display Manager for \*nix systems. +//! +//! The library is compatible works for systems with and without SystemD. It aims to provide +//! low-level control of the its functionality while not requiring the user to know all the details +//! about the session open process. +//! +//! This library provides 2 main functionalities. +//! 1. [Authentication](#authentication): verification of login credentials +//! 2. [Session Environments](#session-environments): opening a X11, Wayland or Shell environment +//! +//! ## Basic example without Authentication +//! +//! The code below illustrates a basic example of how to use the libary. This example does not +//! verify the user credentials. It performs something very similar to the +//! [`startx`](https://www.x.org/releases/X11R7.5/doc/man/man1/startx.1.html) binary. //! //! ```no_run +//! // Fetch the information for the currently active user +//! let user_info = UserInfo::active_user()?; +//! +//! // Define what you want the session to start into +//! let session_environment = SessionEnvironment::X11( +//! &format!("{}/.xinitrc", std::env::get("HOME")?) +//! ); +//! +//! // Start a session environment +//! open_session(&user_info, &session_environment)?.wait()?; +//! ``` +//! +//! ## Basic example with Authentication +//! +//! ```no_run +//! // TODO: Provide your own methods for fetching the user creditionals //! let username = "johndoe"; //! let pasword = "*******"; //! @@ -15,9 +46,19 @@ //! )?; //! //! // Start a session environment -//! start_session(session_user, &session_environment); +//! open_authenticated_session( +//! session_user, +//! &session_environment +//! )?.wait()?; //! ``` //! +//! ## Authentication +//! +//! ## Session Environments +//! +//! # API Example +//! +//! //! # API Expanded //! //! ```no_run @@ -48,7 +89,6 @@ use libc::uid_t; use nix::unistd::{Gid, Uid}; use std::env; use std::fmt::Display; -use std::process::Child; use crate::session_environment::env_variables::{ set_basic_variables, set_display, set_seat_vars, set_session_params, set_session_vars, @@ -185,11 +225,11 @@ pub fn authenticate<'a>( /// In contrast to the [`open_session`] function, this function also allows for finer control of /// the internal operations with the `context` argument. See the [`StartSessionContext`] /// documentation for further explanation of what parameters can be controlled. -pub fn open_session_with_context( +pub fn open_session_with_context<'a>( user_info: &UserInfo, session_environment: &SessionEnvironment, context: &StartSessionContext, -) -> Result, EnvironmentStartError> { +) -> Result, EnvironmentStartError> { let tty = context.tty; let mut env_container = EnvironmentContainer::take_snapshot(); @@ -204,7 +244,8 @@ pub fn open_session_with_context( set_basic_variables(&mut env_container, username, homedir, shell); set_xdg_common_paths(&mut env_container, homedir); - session_environment.spawn(user_info) + unimplemented!() + // session_environment.spawn(user_info) } /// Open a `session_environment` with the given `user_info` and return a handler to the opened @@ -223,10 +264,10 @@ pub fn open_session_with_context( /// the default [`StartSessionContext`]. The default settings can be found in the documentation of /// [`StartSessionContext`]. If more control is needed, the [`open_session_with_context`] can be /// used. -pub fn open_session( +pub fn open_session<'a>( user_info: &UserInfo, session_environment: &SessionEnvironment, -) -> Result, EnvironmentStartError> { +) -> Result, EnvironmentStartError> { let context = StartSessionContext::default(); open_session_with_context(user_info, session_environment, &context) } @@ -246,12 +287,10 @@ pub fn open_authenticated_session_with_context<'a>( session_user: SessionUser<'a>, session_environment: &SessionEnvironment, context: &StartSessionContext, -) -> Result, EnvironmentStartError> { - let session_process = - open_session_with_context(session_user.as_user_info(), session_environment, context)?; - - // Insert the pid into the UTMPX entry, if needed - session_user.set_pid(session_process.pid()); +) -> Result, EnvironmentStartError> { + let mut session_process = open_session_with_context(session_user.as_user_info(), session_environment, context)?; + + session_process.authenticate(session_user); Ok(session_process) } @@ -271,7 +310,7 @@ pub fn open_authenticated_session_with_context<'a>( pub fn open_authenticated_session<'a>( session_user: SessionUser<'a>, session_environment: &SessionEnvironment, -) -> Result, EnvironmentStartError> { +) -> Result, EnvironmentStartError> { let context = StartSessionContext::default(); open_authenticated_session_with_context(session_user, session_environment, &context) } diff --git a/lemurs-core/src/session_environment/mod.rs b/lemurs-core/src/session_environment/mod.rs index fadcc45..48d14d7 100644 --- a/lemurs-core/src/session_environment/mod.rs +++ b/lemurs-core/src/session_environment/mod.rs @@ -8,6 +8,7 @@ use std::io; use std::os::unix::process::CommandExt; use std::process::{Child, Command, Stdio}; +use crate::auth::SessionUser; use crate::session_environment::wayland::WaylandStartContext; use crate::session_environment::x11::X11StartContext; use crate::{can_run, RunError, UserInfo}; @@ -76,11 +77,23 @@ pub enum SessionType { Shell, } +pub struct SessionProcess<'a> { + type_specific_content: SessionProcessContent, + session_user: Option>, +} + #[derive(Debug)] -pub enum SessionProcess { - X11 { server: Child, client: T }, - Wayland(T), - Shell(T), +pub enum SessionProcessContent { + X11 { server: Child, client: Child }, + Wayland(Child), + Shell(Child), +} + +#[derive(Debug)] +pub enum SessionCommand { + X11 { server: Child, client: Command }, + Wayland(Command), + Shell(Command), } #[derive(Debug, Clone)] @@ -140,22 +153,22 @@ impl SessionType { } } -impl SessionProcess { - fn as_ref(&self) -> &T { - match self { - Self::X11 { client, .. } | Self::Wayland(client) | Self::Shell(client) => &client, - } - } - fn as_mut(&mut self) -> &mut T { - match self { - Self::X11 { ref mut client, .. } - | Self::Wayland(ref mut client) - | Self::Shell(ref mut client) => client, - } - } -} +impl<'a> SessionProcess<'a> { + fn as_ref(&self) -> &Child { + use SessionProcessContent::*; + + match &self.type_specific_content { + X11 { client, .. } | Wayland(client) | Shell(client) => &client, + } + } + + pub fn authenticate(&mut self, session_user: SessionUser<'a>) { + // Insert the pid into the UTMPX entry, if needed + session_user.set_pid(self.pid()); + + self.session_user = Some(session_user); + } -impl SessionProcess { pub fn pid(&self) -> u32 { self.as_ref().id() } @@ -164,15 +177,17 @@ impl SessionProcess { self, f: impl Fn(Child) -> Result<(), EnvironmentStartError>, ) -> Result<(), EnvironmentStartError> { - match self { - Self::X11 { mut server, client } => { + use SessionProcessContent::*; + + match self.type_specific_content { + X11 { mut server, client } => { f(client)?; server.kill().map_err(|err| { error!("Failed to kill X11 server, Reason: '{}'", err); EnvironmentStartError::X11ServerKillFailed }) } - Self::Wayland(client) | Self::Shell(client) => f(client), + Wayland(client) | Shell(client) => f(client), } } @@ -223,7 +238,24 @@ impl SessionProcess { } } -impl SessionProcess { +impl<'a> From for SessionProcess<'a> { + fn from(type_specific_content: SessionProcessContent) -> Self { + SessionProcess { + type_specific_content, + session_user: None, + } + } +} + +impl SessionCommand { + fn as_mut(&mut self) -> &mut Command { + match self { + Self::X11 { ref mut client, .. } + | Self::Wayland(ref mut client) + | Self::Shell(ref mut client) => client, + } + } + pub fn pipe_output(&mut self) { self.as_mut().stdout(Stdio::piped()).stderr(Stdio::piped()); } @@ -251,14 +283,17 @@ impl SessionProcess { unsafe { self.as_mut().pre_exec(to_session_user_env) }; } - pub fn spawn(self) -> io::Result> { - Ok(match self { - Self::X11 { server, mut client } => SessionProcess::X11 { - server, - client: client.spawn()?, + pub fn spawn<'a>(self) -> io::Result> { + Ok(SessionProcess { + type_specific_content: match self { + Self::X11 { server, mut client } => SessionProcessContent::X11 { + server, + client: client.spawn()?, + }, + Self::Wayland(mut client) => SessionProcessContent::Wayland(client.spawn()?), + Self::Shell(mut client) => SessionProcessContent::Shell(client.spawn()?), }, - Self::Wayland(mut client) => SessionProcess::Wayland(client.spawn()?), - Self::Shell(mut client) => SessionProcess::Shell(client.spawn()?), + session_user: None, }) } } @@ -272,10 +307,7 @@ impl SessionEnvironment { } } - pub fn spawn( - &self, - session_user: &UserInfo, - ) -> Result, EnvironmentStartError> { + pub fn spawn(&self, session_user: &UserInfo) -> Result { let context = EnvironmentContext::default(); self.spawn_with_context(session_user, &context) } @@ -284,7 +316,7 @@ impl SessionEnvironment { &self, session_user: &UserInfo, context: &EnvironmentContext<'a>, - ) -> Result, EnvironmentStartError> { + ) -> Result { let result = self.internal_spawn_with_context(session_user, context); info!("Switch back to Lemurs virtual terminal"); @@ -301,59 +333,59 @@ impl SessionEnvironment { &self, user_info: &UserInfo, context: &EnvironmentContext<'a>, - ) -> Result, EnvironmentStartError> { + ) -> Result { can_run()?; let uid = user_info.user_id(); let gid = user_info.group_id(); let groups = user_info.groups().to_owned(); - let mut session_process = match self { + let mut session_command = match self { SessionEnvironment::X11(initializer) => { let context = X11StartContext::from(context); - let mut session_process = initializer + let mut session_command = initializer .start_x11(user_info, &context) .map_err(EnvironmentStartError::X11Start)?; // Pipe the stdout and stderr to us so we can read it. - session_process.pipe_output(); + session_command.pipe_output(); - session_process + session_command } SessionEnvironment::Wayland(initializer) => { let context = WaylandStartContext::from(context); - let mut session_process = initializer + let mut session_command = initializer .start_wayland(user_info, &context) .map_err(EnvironmentStartError::WaylandStart)?; // Pipe the stdout and stderr to us so we can read it. - session_process.pipe_output(); + session_command.pipe_output(); - session_process + session_command } SessionEnvironment::Shell => { info!("Starting TTY shell"); let shell = &user_info.shell(); - let mut session_process = SessionProcess::Shell(Command::new(shell)); - session_process.inherit_io(); - session_process + let mut session_command = SessionCommand::Shell(Command::new(shell)); + + session_command.inherit_io(); + + session_command } }; - session_process.lower_permission_pre_exec(uid, gid, groups); + session_command.lower_permission_pre_exec(uid, gid, groups); // Actually spawn the initializer process - let session_process = match session_process.spawn() { - Ok(cmd) => cmd, + match session_command.spawn() { + Ok(cmd) => Ok(cmd.into()), Err(err) => { error!("Failed to start initializer. Reason '{}'", err); - return Err(EnvironmentStartError::InitializerFailed); + Err(EnvironmentStartError::InitializerFailed) } - }; - - Ok(session_process) + } } } diff --git a/lemurs-core/src/session_environment/wayland.rs b/lemurs-core/src/session_environment/wayland.rs index 491376c..f2685c5 100644 --- a/lemurs-core/src/session_environment/wayland.rs +++ b/lemurs-core/src/session_environment/wayland.rs @@ -7,7 +7,7 @@ use std::process::Command; use crate::UserInfo; -use super::{EnvironmentContext, SessionInitializer, SessionProcess}; +use super::{EnvironmentContext, SessionInitializer, SessionCommand}; const WAYLAND_SESSIONS_DIR: &str = "/etc/lemurs/wayland"; @@ -44,7 +44,7 @@ impl SessionInitializer { &self, _user_info: &UserInfo, context: &WaylandStartContext, - ) -> Result, WaylandStartError> { + ) -> Result { info!("Starting Wayland session '{}'", self.name); let mut initializer = Command::new(context.system_shell); @@ -52,7 +52,7 @@ impl SessionInitializer { // Make it run the initializer initializer.arg("-c").arg(&self.path); - Ok(SessionProcess::Wayland(initializer)) + Ok(SessionCommand::Wayland(initializer)) } } diff --git a/lemurs-core/src/session_environment/x11.rs b/lemurs-core/src/session_environment/x11.rs index 95b0b47..6e5db7c 100644 --- a/lemurs-core/src/session_environment/x11.rs +++ b/lemurs-core/src/session_environment/x11.rs @@ -11,8 +11,9 @@ use std::path::PathBuf; use log::{error, info, warn}; use crate::UserInfo; +use crate::session_environment::SessionCommand; -use super::{EnvironmentContext, SessionInitializer, SessionProcess}; +use super::{EnvironmentContext, SessionInitializer}; const SERVER_QUERY_NUM_OF_TRIES: usize = 10; const SERVER_QUERY_TIMEOUT: Duration = Duration::from_millis(1000); @@ -204,7 +205,7 @@ impl SessionInitializer { &self, user_info: &UserInfo, context: &X11StartContext, - ) -> Result, X11StartError> { + ) -> Result { info!("Starting X11 session '{}'", self.name); // Start the X Server @@ -219,7 +220,7 @@ impl SessionInitializer { self.path.display() )); - Ok(SessionProcess::X11 { + Ok(SessionCommand::X11 { server, client: initializer, })