mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-04-02 18:31:50 -04:00
Support specify csd-wrapper
This commit is contained in:
parent
13be9179f5
commit
662e4d0b8a
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -4,6 +4,7 @@
|
|||||||
"bincode",
|
"bincode",
|
||||||
"chacha",
|
"chacha",
|
||||||
"clientos",
|
"clientos",
|
||||||
|
"cstring",
|
||||||
"datetime",
|
"datetime",
|
||||||
"disconnectable",
|
"disconnectable",
|
||||||
"distro",
|
"distro",
|
||||||
|
@ -7,7 +7,10 @@ use gpapi::{
|
|||||||
gateway::gateway_login,
|
gateway::gateway_login,
|
||||||
gp_params::{ClientOs, GpParams},
|
gp_params::{ClientOs, GpParams},
|
||||||
portal::{prelogin, retrieve_config, PortalError, Prelogin},
|
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,
|
utils::shutdown_signal,
|
||||||
GP_USER_AGENT,
|
GP_USER_AGENT,
|
||||||
};
|
};
|
||||||
@ -27,6 +30,13 @@ pub(crate) struct ConnectArgs {
|
|||||||
user: Option<String>,
|
user: Option<String>,
|
||||||
#[arg(long, short, help = "The VPNC script to use")]
|
#[arg(long, short, help = "The VPNC script to use")]
|
||||||
script: Option<String>,
|
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")]
|
#[arg(long, default_value = GP_USER_AGENT, help = "The user agent to use")]
|
||||||
user_agent: String,
|
user_agent: String,
|
||||||
#[arg(long, default_value = "Linux")]
|
#[arg(long, default_value = "Linux")]
|
||||||
@ -133,7 +143,7 @@ impl<'a> ConnectHandler<'a> {
|
|||||||
gp_params.set_is_gateway(true);
|
gp_params.set_is_gateway(true);
|
||||||
|
|
||||||
let prelogin = prelogin(gateway, &gp_params).await?;
|
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?;
|
let cookie = gateway_login(gateway, &cred, &gp_params).await?;
|
||||||
|
|
||||||
@ -141,9 +151,13 @@ impl<'a> ConnectHandler<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn connect_gateway(&self, gateway: &str, cookie: &str) -> anyhow::Result<()> {
|
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)
|
let vpn = Vpn::builder(gateway, cookie)
|
||||||
.user_agent(self.args.user_agent.clone())
|
.user_agent(self.args.user_agent.clone())
|
||||||
.script(self.args.script.clone())
|
.script(self.args.script.clone())
|
||||||
|
.csd_uid(csd_uid)
|
||||||
|
.csd_wrapper(self.args.csd_wrapper.clone())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let vpn = Arc::new(vpn);
|
let vpn = Arc::new(vpn);
|
||||||
@ -211,3 +225,11 @@ fn write_pid_file() {
|
|||||||
fs::write(GP_CLIENT_LOCK_FILE, pid.to_string()).unwrap();
|
fs::write(GP_CLIENT_LOCK_FILE, pid.to_string()).unwrap();
|
||||||
info!("Wrote PID {} to {}", pid, GP_CLIENT_LOCK_FILE);
|
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()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use anyhow::bail;
|
use std::ffi::OsStr;
|
||||||
use std::{env, ffi::OsStr};
|
|
||||||
use tokio::process::Command;
|
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 {
|
pub trait CommandExt {
|
||||||
fn new_pkexec<S: AsRef<OsStr>>(program: S) -> Command;
|
fn new_pkexec<S: AsRef<OsStr>>(program: S) -> Command;
|
||||||
@ -34,29 +35,3 @@ impl CommandExt for Command {
|
|||||||
Ok(self)
|
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(¤t_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,5 +1,6 @@
|
|||||||
pub(crate) mod command_traits;
|
pub(crate) mod command_traits;
|
||||||
|
|
||||||
|
pub mod users;
|
||||||
pub mod auth_launcher;
|
pub mod auth_launcher;
|
||||||
#[cfg(feature = "browser-auth")]
|
#[cfg(feature = "browser-auth")]
|
||||||
pub mod browser_authenticator;
|
pub mod browser_authenticator;
|
||||||
|
34
crates/gpapi/src/process/users.rs
Normal file
34
crates/gpapi/src/process/users.rs
Normal file
@ -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(¤t_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"))
|
||||||
|
}
|
@ -15,6 +15,9 @@ pub(crate) struct ConnectOptions {
|
|||||||
pub os: *const c_char,
|
pub os: *const c_char,
|
||||||
pub certificate: *const c_char,
|
pub certificate: *const c_char,
|
||||||
pub servercert: *const c_char,
|
pub servercert: *const c_char,
|
||||||
|
|
||||||
|
pub csd_uid: u32,
|
||||||
|
pub csd_wrapper: *const c_char,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[link(name = "vpn")]
|
#[link(name = "vpn")]
|
||||||
|
@ -61,6 +61,8 @@ int vpn_connect(const vpn_options *options, vpn_connected_callback callback)
|
|||||||
INFO("User agent: %s", options->user_agent);
|
INFO("User agent: %s", options->user_agent);
|
||||||
INFO("VPNC script: %s", options->script);
|
INFO("VPNC script: %s", options->script);
|
||||||
INFO("OS: %s", options->os);
|
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);
|
vpninfo = openconnect_vpninfo_new(options->user_agent, validate_peer_cert, NULL, NULL, print_progress, NULL);
|
||||||
|
|
||||||
@ -91,6 +93,10 @@ int vpn_connect(const vpn_options *options, vpn_connected_callback callback)
|
|||||||
openconnect_set_system_trust(vpninfo, 0);
|
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);
|
g_cmd_pipe_fd = openconnect_setup_cmd_pipe(vpninfo);
|
||||||
if (g_cmd_pipe_fd < 0)
|
if (g_cmd_pipe_fd < 0)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,9 @@ typedef struct vpn_options
|
|||||||
const char *os;
|
const char *os;
|
||||||
const char *certificate;
|
const char *certificate;
|
||||||
const char *servercert;
|
const char *servercert;
|
||||||
|
|
||||||
|
const uid_t csd_uid;
|
||||||
|
const char *csd_wrapper;
|
||||||
} vpn_options;
|
} vpn_options;
|
||||||
|
|
||||||
int vpn_connect(const vpn_options *options, vpn_connected_callback callback);
|
int vpn_connect(const vpn_options *options, vpn_connected_callback callback);
|
||||||
|
@ -18,6 +18,9 @@ pub struct Vpn {
|
|||||||
certificate: Option<CString>,
|
certificate: Option<CString>,
|
||||||
servercert: Option<CString>,
|
servercert: Option<CString>,
|
||||||
|
|
||||||
|
csd_uid: u32,
|
||||||
|
csd_wrapper: Option<CString>,
|
||||||
|
|
||||||
callback: OnConnectedCallback,
|
callback: OnConnectedCallback,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +59,9 @@ impl Vpn {
|
|||||||
os: self.os.as_ptr(),
|
os: self.os.as_ptr(),
|
||||||
certificate: Self::option_to_ptr(&self.certificate),
|
certificate: Self::option_to_ptr(&self.certificate),
|
||||||
servercert: Self::option_to_ptr(&self.servercert),
|
servercert: Self::option_to_ptr(&self.servercert),
|
||||||
|
|
||||||
|
csd_uid: self.csd_uid,
|
||||||
|
csd_wrapper: Self::option_to_ptr(&self.csd_wrapper),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +79,9 @@ pub struct VpnBuilder {
|
|||||||
user_agent: Option<String>,
|
user_agent: Option<String>,
|
||||||
script: Option<String>,
|
script: Option<String>,
|
||||||
os: Option<String>,
|
os: Option<String>,
|
||||||
|
|
||||||
|
csd_uid: u32,
|
||||||
|
csd_wrapper: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VpnBuilder {
|
impl VpnBuilder {
|
||||||
@ -83,6 +92,8 @@ impl VpnBuilder {
|
|||||||
user_agent: None,
|
user_agent: None,
|
||||||
script: None,
|
script: None,
|
||||||
os: None,
|
os: None,
|
||||||
|
csd_uid: 0,
|
||||||
|
csd_wrapper: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +112,16 @@ impl VpnBuilder {
|
|||||||
self
|
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 {
|
pub fn build(self) -> Vpn {
|
||||||
let user_agent = self.user_agent.unwrap_or_default();
|
let user_agent = self.user_agent.unwrap_or_default();
|
||||||
let script = self.script.or_else(find_default_vpnc_script).unwrap_or_default();
|
let script = self.script.or_else(find_default_vpnc_script).unwrap_or_default();
|
||||||
@ -114,6 +135,10 @@ impl VpnBuilder {
|
|||||||
os: Self::to_cstring(&os),
|
os: Self::to_cstring(&os),
|
||||||
certificate: None,
|
certificate: None,
|
||||||
servercert: None,
|
servercert: None,
|
||||||
|
|
||||||
|
csd_uid: self.csd_uid,
|
||||||
|
csd_wrapper: self.csd_wrapper.as_deref().map(Self::to_cstring),
|
||||||
|
|
||||||
callback: Default::default(),
|
callback: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user