also set dumpable to 0, minor improvements
This commit is contained in:
		
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,3 +1,5 @@ | |||||||
|  | # This file is automatically @generated by Cargo. | ||||||
|  | # It is not intended for manual editing. | ||||||
| [[package]] | [[package]] | ||||||
| name = "libc" | name = "libc" | ||||||
| version = "0.2.43" | version = "0.2.43" | ||||||
|   | |||||||
							
								
								
									
										59
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								src/main.rs
									
									
									
									
									
								
							| @@ -1,10 +1,10 @@ | |||||||
| use std::env::Args; | use std::env::Args; | ||||||
| use std::io::{Error, ErrorKind}; |  | ||||||
| use std::fs::File; |  | ||||||
| use std::io::BufReader; |  | ||||||
| use std::io::BufRead; |  | ||||||
| use std::ffi::CString; |  | ||||||
| use std::ffi::CStr; | use std::ffi::CStr; | ||||||
|  | use std::ffi::CString; | ||||||
|  | use std::fs::File; | ||||||
|  | use std::io::BufRead; | ||||||
|  | use std::io::BufReader; | ||||||
|  | use std::io::{Error, ErrorKind}; | ||||||
|  |  | ||||||
| extern crate libc; | extern crate libc; | ||||||
| use libc::passwd; | use libc::passwd; | ||||||
| @@ -35,7 +35,6 @@ impl Entry { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct Passwd { | struct Passwd { | ||||||
|     pw_name: String, |     pw_name: String, | ||||||
|     pw_passwd: String, |     pw_passwd: String, | ||||||
| @@ -46,15 +45,11 @@ struct Passwd { | |||||||
|     pw_shell: String, |     pw_shell: String, | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| fn initgroups(user: &str, group: libc::gid_t) -> std::io::Result<()> { | fn initgroups(user: &str, group: libc::gid_t) -> std::io::Result<()> { | ||||||
|     let userarg = CString::new(user); |     let userarg = CString::new(user); | ||||||
|     return errnowrapper(unsafe { |     return errnowrapper(unsafe { libc::initgroups(userarg.unwrap().as_ptr(), group) }); | ||||||
|         libc::initgroups(userarg.unwrap().as_ptr(), group) |  | ||||||
|     }); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| fn errnowrapper(ret: libc::c_int) -> std::io::Result<()> { | fn errnowrapper(ret: libc::c_int) -> std::io::Result<()> { | ||||||
|     if ret != 0 { |     if ret != 0 { | ||||||
|         return Err(Error::last_os_error()); |         return Err(Error::last_os_error()); | ||||||
| @@ -95,7 +90,6 @@ fn getpwnam(username: &str) -> std::io::Result<Passwd> { | |||||||
|             pw_shell: getstr((*pwnamresult).pw_shell), |             pw_shell: getstr((*pwnamresult).pw_shell), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| fn ensure_allowed(userid: libc::uid_t, entry: &Entry) -> std::io::Result<()> { | fn ensure_allowed(userid: libc::uid_t, entry: &Entry) -> std::io::Result<()> { | ||||||
| @@ -119,7 +113,6 @@ fn ensure_allowed(userid: libc::uid_t, entry: &Entry) -> std::io::Result<()> { | |||||||
|     )); |     )); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| fn usage() { | fn usage() { | ||||||
|     println!("Usage: raou ENRTYNAME"); |     println!("Usage: raou ENRTYNAME"); | ||||||
| } | } | ||||||
| @@ -141,13 +134,12 @@ fn assign(entry: &mut Entry, key: &str, value: &str) { | |||||||
|         "env_vars" => add_multi(&mut entry.inherit_envs, val), |         "env_vars" => add_multi(&mut entry.inherit_envs, val), | ||||||
|         "argv0" => entry.argv0 = val, |         "argv0" => entry.argv0 = val, | ||||||
|         "target_user" => entry.dest_user = val, |         "target_user" => entry.dest_user = val, | ||||||
|         "allow_args" => entry.arbitrary_args = (val == "1" || val == "true"), |         "allow_args" => entry.arbitrary_args = val == "1" || val == "true", | ||||||
|         "args" => entry.args = val, |         "args" => entry.args = val, | ||||||
|         "no_new_privs" => entry.no_new_privs = (val == "1" || val == "true"), |         "no_new_privs" => entry.no_new_privs = val == "1" || val == "true", | ||||||
|         _ => { |         _ => { | ||||||
|             eprintln!("Ignoring invalid key {}", key); |             eprintln!("Ignoring invalid key {}", key); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| fn assign_from_line(entry: &mut Entry, line: &str) { | fn assign_from_line(entry: &mut Entry, line: &str) { | ||||||
| @@ -159,7 +151,6 @@ fn assign_from_line(entry: &mut Entry, line: &str) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     assign(entry, key.unwrap(), value.unwrap()) |     assign(entry, key.unwrap(), value.unwrap()) | ||||||
|  |  | ||||||
| } | } | ||||||
| fn create_entry_from_file(filepath: &str) -> std::io::Result<Entry> { | fn create_entry_from_file(filepath: &str) -> std::io::Result<Entry> { | ||||||
|     let mut entry: Entry = Entry::new(); |     let mut entry: Entry = Entry::new(); | ||||||
| @@ -179,7 +170,8 @@ fn clearenv() -> std::io::Result<()> { | |||||||
| } | } | ||||||
| //TODO: AsRef for envs? | //TODO: AsRef for envs? | ||||||
| fn setup_environment(passwd: &Passwd, envs: &[String]) -> std::io::Result<()> { | fn setup_environment(passwd: &Passwd, envs: &[String]) -> std::io::Result<()> { | ||||||
|     let saved_envs: Vec<String> = envs.iter() |     let saved_envs: Vec<String> = envs | ||||||
|  |         .iter() | ||||||
|         .map(|s| std::env::var(s).expect("No such var")) |         .map(|s| std::env::var(s).expect("No such var")) | ||||||
|         .collect(); |         .collect(); | ||||||
|     clearenv()?; |     clearenv()?; | ||||||
| @@ -194,7 +186,6 @@ fn setup_environment(passwd: &Passwd, envs: &[String]) -> std::io::Result<()> { | |||||||
|         std::env::set_var(&envs[i], item); |         std::env::set_var(&envs[i], item); | ||||||
|     } |     } | ||||||
|     Ok(()) |     Ok(()) | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| fn become_user(passwd: &Passwd) -> std::io::Result<()> { | fn become_user(passwd: &Passwd) -> std::io::Result<()> { | ||||||
| @@ -204,13 +195,12 @@ fn become_user(passwd: &Passwd) -> std::io::Result<()> { | |||||||
|     std::env::set_current_dir(&passwd.pw_dir)?; |     std::env::set_current_dir(&passwd.pw_dir)?; | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| fn init_sandbox(entry: &Entry) -> std::io::Result<()> { |  | ||||||
|     if (entry.no_new_privs) { |  | ||||||
|         errnowrapper(unsafe { |  | ||||||
|             libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) |  | ||||||
|         })?; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  | fn drop_privs(entry: &Entry) -> std::io::Result<()> { | ||||||
|  |     if entry.no_new_privs { | ||||||
|  |         errnowrapper(unsafe { libc::prctl(libc::PR_SET_DUMPABLE, 0) })?; | ||||||
|  |         errnowrapper(unsafe { libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) })?; | ||||||
|  |     } | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -220,8 +210,6 @@ fn to_cstring<T: AsRef<str>>(s: T) -> *const libc::c_char { | |||||||
| } | } | ||||||
|  |  | ||||||
| fn create_execv_args(entry: &Entry, cmdargs: &Vec<String>) -> Vec<*const libc::c_char> { | fn create_execv_args(entry: &Entry, cmdargs: &Vec<String>) -> Vec<*const libc::c_char> { | ||||||
|  |  | ||||||
|  |  | ||||||
|     let mut args: Vec<*const libc::c_char>; |     let mut args: Vec<*const libc::c_char>; | ||||||
|     if entry.arbitrary_args && cmdargs.len() > 2 { |     if entry.arbitrary_args && cmdargs.len() > 2 { | ||||||
|         args = cmdargs.iter().skip(2).map(to_cstring).collect(); |         args = cmdargs.iter().skip(2).map(to_cstring).collect(); | ||||||
| @@ -256,11 +244,8 @@ fn exec(entryname: &str, cmdargs: &Vec<String>) -> std::io::Result<()> { | |||||||
|     let destuserpasswd: Passwd = getpwnam(&entry.dest_user)?; |     let destuserpasswd: Passwd = getpwnam(&entry.dest_user)?; | ||||||
|     let currentuser: u32 = geteuid(); |     let currentuser: u32 = geteuid(); | ||||||
|  |  | ||||||
|  |  | ||||||
|     let args = create_execv_args(&entry, &cmdargs); |     let args = create_execv_args(&entry, &cmdargs); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     ensure_allowed(currentuser, &entry)?; |     ensure_allowed(currentuser, &entry)?; | ||||||
|     become_user(&destuserpasswd).or_else(|e| { |     become_user(&destuserpasswd).or_else(|e| { | ||||||
|         return Err(Error::new( |         return Err(Error::new( | ||||||
| @@ -268,23 +253,22 @@ fn exec(entryname: &str, cmdargs: &Vec<String>) -> std::io::Result<()> { | |||||||
|             "Failed to switch user: ".to_owned() + &e.to_string(), |             "Failed to switch user: ".to_owned() + &e.to_string(), | ||||||
|         )); |         )); | ||||||
|     })?; |     })?; | ||||||
|     setup_environment(&destuserpasswd, &entry.inherit_envs) |     setup_environment(&destuserpasswd, &entry.inherit_envs).or_else(|e| { | ||||||
|         .or_else(|e| { |  | ||||||
|         return Err(Error::new( |         return Err(Error::new( | ||||||
|             ErrorKind::Other, |             ErrorKind::Other, | ||||||
|             "Environment setup failure: ".to_owned() + &e.to_string(), |             "Environment setup failure: ".to_owned() + &e.to_string(), | ||||||
|         )); |         )); | ||||||
|     })?; |     })?; | ||||||
|     init_sandbox(&entry).or_else(|e| { |  | ||||||
|  |     drop_privs(&entry).or_else(|e| { | ||||||
|         return Err(Error::new( |         return Err(Error::new( | ||||||
|             ErrorKind::Other, |             ErrorKind::Other, | ||||||
|             "Sandbox init failure: ".to_owned() + &e.to_string(), |             "Failed to drop priviliges: ".to_owned() + &e.to_string(), | ||||||
|         )); |         )); | ||||||
|     })?; |     })?; | ||||||
|  |  | ||||||
|     unsafe { |     unsafe { | ||||||
|         errnowrapper(libc::execv(to_cstring(entry.cmd), args.as_ptr())) |         errnowrapper(libc::execv(to_cstring(entry.cmd), args.as_ptr())).or_else(|e| { | ||||||
|             .or_else(|e| { |  | ||||||
|             return Err(Error::new( |             return Err(Error::new( | ||||||
|                 ErrorKind::Other, |                 ErrorKind::Other, | ||||||
|                 "execv failed: ".to_owned() + &e.to_string(), |                 "execv failed: ".to_owned() + &e.to_string(), | ||||||
| @@ -292,15 +276,12 @@ fn exec(entryname: &str, cmdargs: &Vec<String>) -> std::io::Result<()> { | |||||||
|         })?; |         })?; | ||||||
|     } |     } | ||||||
|     std::process::exit(0); |     std::process::exit(0); | ||||||
|     Ok(()) |  | ||||||
| } | } | ||||||
| fn main() -> Result<(), std::io::Error> { | fn main() -> Result<(), std::io::Error> { | ||||||
|  |  | ||||||
|     let argv: Args = std::env::args(); |     let argv: Args = std::env::args(); | ||||||
|     let cmdargs: Vec<String> = argv.collect(); |     let cmdargs: Vec<String> = argv.collect(); | ||||||
|     let entryname = cmdargs.get(1); |     let entryname = cmdargs.get(1); | ||||||
|     if entryname.is_some() { |     if entryname.is_some() { | ||||||
|  |  | ||||||
|         match exec(&entryname.unwrap(), &cmdargs) { |         match exec(&entryname.unwrap(), &cmdargs) { | ||||||
|             Err(e) => { |             Err(e) => { | ||||||
|                 eprintln!("The following error ocurred:"); |                 eprintln!("The following error ocurred:"); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user