Skip to content

Commit

Permalink
Support specify csd-wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
yuezk committed Feb 3, 2024
1 parent 13be917 commit 662e4d0
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 31 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"bincode",
"chacha",
"clientos",
"cstring",
"datetime",
"disconnectable",
"distro",
Expand Down
26 changes: 24 additions & 2 deletions apps/gpclient/src/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use gpapi::{
gateway::gateway_login,
gp_params::{ClientOs, GpParams},
portal::{prelogin, retrieve_config, PortalError, Prelogin},
process::auth_launcher::SamlAuthLauncher,
process::{
auth_launcher::SamlAuthLauncher,
users::{get_non_root_user, get_user_by_name},
},
utils::shutdown_signal,
GP_USER_AGENT,
};
Expand All @@ -27,6 +30,13 @@ pub(crate) struct ConnectArgs {
user: Option<String>,
#[arg(long, short, help = "The VPNC script to use")]
script: Option<String>,

#[arg(long, help = "Same as the '--csd-user' option in the openconnect command")]
csd_user: Option<String>,

#[arg(long, help = "Same as the '--csd-wrapper' option in the openconnect command")]
csd_wrapper: Option<String>,

#[arg(long, default_value = GP_USER_AGENT, help = "The user agent to use")]
user_agent: String,
#[arg(long, default_value = "Linux")]
Expand Down Expand Up @@ -133,17 +143,21 @@ impl<'a> ConnectHandler<'a> {
gp_params.set_is_gateway(true);

let prelogin = prelogin(gateway, &gp_params).await?;
let cred = self.obtain_credential(&prelogin, &gateway).await?;
let cred = self.obtain_credential(&prelogin, gateway).await?;

let cookie = gateway_login(gateway, &cred, &gp_params).await?;

self.connect_gateway(gateway, &cookie).await
}

async fn connect_gateway(&self, gateway: &str, cookie: &str) -> anyhow::Result<()> {
let csd_uid = get_csd_uid(&self.args.csd_user)?;

let vpn = Vpn::builder(gateway, cookie)
.user_agent(self.args.user_agent.clone())
.script(self.args.script.clone())
.csd_uid(csd_uid)
.csd_wrapper(self.args.csd_wrapper.clone())
.build();

let vpn = Arc::new(vpn);
Expand Down Expand Up @@ -211,3 +225,11 @@ fn write_pid_file() {
fs::write(GP_CLIENT_LOCK_FILE, pid.to_string()).unwrap();
info!("Wrote PID {} to {}", pid, GP_CLIENT_LOCK_FILE);
}

fn get_csd_uid(csd_user: &Option<String>) -> anyhow::Result<u32> {
if let Some(csd_user) = csd_user {
get_user_by_name(csd_user).map(|user| user.uid())
} else {
get_non_root_user().map_or_else(|_| Ok(0), |user| Ok(user.uid()))
}
}
33 changes: 4 additions & 29 deletions crates/gpapi/src/process/command_traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use anyhow::bail;
use std::{env, ffi::OsStr};
use std::ffi::OsStr;
use tokio::process::Command;
use uzers::{os::unix::UserExt, User};
use uzers::os::unix::UserExt;

use super::users::get_non_root_user;

pub trait CommandExt {
fn new_pkexec<S: AsRef<OsStr>>(program: S) -> Command;
Expand Down Expand Up @@ -34,29 +35,3 @@ impl CommandExt for Command {
Ok(self)
}
}

fn get_non_root_user() -> anyhow::Result<User> {
let current_user = whoami::username();

let user = if current_user == "root" {
get_real_user()?
} else {
uzers::get_user_by_name(&current_user).ok_or_else(|| anyhow::anyhow!("User ({}) not found", current_user))?
};

if user.uid() == 0 {
bail!("Non-root user not found")
}

Ok(user)
}

fn get_real_user() -> anyhow::Result<User> {
// Read the UID from SUDO_UID or PKEXEC_UID environment variable if available.
let uid = match env::var("SUDO_UID") {
Ok(uid) => uid.parse::<u32>()?,
_ => env::var("PKEXEC_UID")?.parse::<u32>()?,
};

uzers::get_user_by_uid(uid).ok_or_else(|| anyhow::anyhow!("User not found"))
}
1 change: 1 addition & 0 deletions crates/gpapi/src/process/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub(crate) mod command_traits;

pub mod users;
pub mod auth_launcher;
#[cfg(feature = "browser-auth")]
pub mod browser_authenticator;
Expand Down
34 changes: 34 additions & 0 deletions crates/gpapi/src/process/users.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::env;

use anyhow::bail;
use uzers::User;

pub fn get_user_by_name(username: &str) -> anyhow::Result<User> {
uzers::get_user_by_name(username).ok_or_else(|| anyhow::anyhow!("User ({}) not found", username))
}

pub fn get_non_root_user() -> anyhow::Result<User> {
let current_user = whoami::username();

let user = if current_user == "root" {
get_real_user()?
} else {
get_user_by_name(&current_user)?
};

if user.uid() == 0 {
bail!("Non-root user not found")
}

Ok(user)
}

fn get_real_user() -> anyhow::Result<User> {
// Read the UID from SUDO_UID or PKEXEC_UID environment variable if available.
let uid = match env::var("SUDO_UID") {
Ok(uid) => uid.parse::<u32>()?,
_ => env::var("PKEXEC_UID")?.parse::<u32>()?,
};

uzers::get_user_by_uid(uid).ok_or_else(|| anyhow::anyhow!("User not found"))
}
3 changes: 3 additions & 0 deletions crates/openconnect/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub(crate) struct ConnectOptions {
pub os: *const c_char,
pub certificate: *const c_char,
pub servercert: *const c_char,

pub csd_uid: u32,
pub csd_wrapper: *const c_char,
}

#[link(name = "vpn")]
Expand Down
6 changes: 6 additions & 0 deletions crates/openconnect/src/ffi/vpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ int vpn_connect(const vpn_options *options, vpn_connected_callback callback)
INFO("User agent: %s", options->user_agent);
INFO("VPNC script: %s", options->script);
INFO("OS: %s", options->os);
INFO("CSD_USER: %d", options->csd_uid);
INFO("CSD_WRAPPER: %s", options->csd_wrapper);

vpninfo = openconnect_vpninfo_new(options->user_agent, validate_peer_cert, NULL, NULL, print_progress, NULL);

Expand Down Expand Up @@ -91,6 +93,10 @@ int vpn_connect(const vpn_options *options, vpn_connected_callback callback)
openconnect_set_system_trust(vpninfo, 0);
}

if (options->csd_wrapper) {
openconnect_setup_csd(vpninfo, options->csd_uid, 1, options->csd_wrapper);
}

g_cmd_pipe_fd = openconnect_setup_cmd_pipe(vpninfo);
if (g_cmd_pipe_fd < 0)
{
Expand Down
3 changes: 3 additions & 0 deletions crates/openconnect/src/ffi/vpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ typedef struct vpn_options
const char *os;
const char *certificate;
const char *servercert;

const uid_t csd_uid;
const char *csd_wrapper;
} vpn_options;

int vpn_connect(const vpn_options *options, vpn_connected_callback callback);
Expand Down
25 changes: 25 additions & 0 deletions crates/openconnect/src/vpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub struct Vpn {
certificate: Option<CString>,
servercert: Option<CString>,

csd_uid: u32,
csd_wrapper: Option<CString>,

callback: OnConnectedCallback,
}

Expand Down Expand Up @@ -56,6 +59,9 @@ impl Vpn {
os: self.os.as_ptr(),
certificate: Self::option_to_ptr(&self.certificate),
servercert: Self::option_to_ptr(&self.servercert),

csd_uid: self.csd_uid,
csd_wrapper: Self::option_to_ptr(&self.csd_wrapper),
}
}

Expand All @@ -73,6 +79,9 @@ pub struct VpnBuilder {
user_agent: Option<String>,
script: Option<String>,
os: Option<String>,

csd_uid: u32,
csd_wrapper: Option<String>,
}

impl VpnBuilder {
Expand All @@ -83,6 +92,8 @@ impl VpnBuilder {
user_agent: None,
script: None,
os: None,
csd_uid: 0,
csd_wrapper: None,
}
}

Expand All @@ -101,6 +112,16 @@ impl VpnBuilder {
self
}

pub fn csd_uid(mut self, csd_uid: u32) -> Self {
self.csd_uid = csd_uid;
self
}

pub fn csd_wrapper<T: Into<Option<String>>>(mut self, csd_wrapper: T) -> Self {
self.csd_wrapper = csd_wrapper.into();
self
}

pub fn build(self) -> Vpn {
let user_agent = self.user_agent.unwrap_or_default();
let script = self.script.or_else(find_default_vpnc_script).unwrap_or_default();
Expand All @@ -114,6 +135,10 @@ impl VpnBuilder {
os: Self::to_cstring(&os),
certificate: None,
servercert: None,

csd_uid: self.csd_uid,
csd_wrapper: self.csd_wrapper.as_deref().map(Self::to_cstring),

callback: Default::default(),
}
}
Expand Down

0 comments on commit 662e4d0

Please sign in to comment.