A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
3.7 KiB

7 years ago
8 years ago
7 years ago
8 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
  1. use std::error::Error;
  2. use std::io::Result as IoResult;
  3. use std::process::Command;
  4. use std::process::Output;
  5. pub trait CommandRunner {
  6. fn run_with_args(&self, program: &str, args: &[&str]) -> IoResult<Output>;
  7. fn get_output(&self, program: &str, args: &[&str]) -> Result<Vec<u8>, Box<Error>> {
  8. let output = try!(self.run_with_args(program, args));
  9. if !output.status.success() {
  10. return Err(try!(String::from_utf8(output.stderr)).into());
  11. }
  12. Ok(output.stdout)
  13. }
  14. fn get_stderr(&self, program: &str, args: &[&str]) -> Result<Vec<u8>, Box<Error>> {
  15. let output = try!(self.run_with_args(program, args));
  16. if !output.status.success() {
  17. return Err(try!(String::from_utf8(output.stderr)).into());
  18. }
  19. Ok(output.stderr)
  20. }
  21. fn run_successfully(&self, program: &str, args: &[&str]) -> Result<(), Box<Error>> {
  22. let output = try!(self.run_with_args(program, args));
  23. if output.status.success() {
  24. Ok(())
  25. } else {
  26. Err(try!(String::from_utf8(output.stderr)).into())
  27. }
  28. }
  29. }
  30. #[derive(Debug)]
  31. pub struct StdCommandRunner;
  32. impl CommandRunner for StdCommandRunner {
  33. fn run_with_args(&self, program: &str, args: &[&str]) -> IoResult<Output> {
  34. // FIXME: logger
  35. println!("{} {:?}", program, args);
  36. let res = Command::new(program).args(args).output();
  37. println!("{:?}", res);
  38. res
  39. }
  40. }
  41. #[derive(Debug)]
  42. pub struct SetuidCommandRunner<'a, C> where C: 'a + CommandRunner {
  43. command_runner: &'a C,
  44. user_name: &'a str
  45. }
  46. impl<'a, C> SetuidCommandRunner<'a, C> where C: 'a + CommandRunner {
  47. pub fn new(user_name: &'a str, command_runner: &'a C) -> SetuidCommandRunner<'a, C> {
  48. SetuidCommandRunner {
  49. command_runner: command_runner,
  50. user_name: user_name
  51. }
  52. }
  53. }
  54. use std::os::unix::process::CommandExt;
  55. use std::env;
  56. use users::get_user_by_name;
  57. struct TempSetEnv<'a> { name: &'a str, old_value: Option<String> }
  58. impl<'a> TempSetEnv<'a> {
  59. fn new(name: &'a str, new_value: String) -> TempSetEnv<'a> {
  60. let old_value = env::var(name);
  61. env::set_var(name, new_value);
  62. TempSetEnv { name: name, old_value: old_value.ok() }
  63. }
  64. }
  65. impl<'a> Drop for TempSetEnv<'a> {
  66. fn drop(&mut self) {
  67. match self.old_value {
  68. Some(ref val) => env::set_var(self.name, val),
  69. None => env::remove_var(self.name)
  70. }
  71. }
  72. }
  73. impl<'a, C> CommandRunner for SetuidCommandRunner<'a, C> where C: 'a + CommandRunner {
  74. fn run_with_args(&self, program: &str, args: &[&str]) -> IoResult<Output> {
  75. let uid = get_user_by_name(self.user_name).expect("User does not exist").uid();
  76. let set_home = TempSetEnv::new("HOME", format!("/home/{}", self.user_name));
  77. let set_dbus = TempSetEnv::new("XDG_RUNTIME_DIR", format!("/run/user/{}", uid));
  78. println!("{} {:?}", program, args);
  79. let res = Command::new(program).uid(uid).gid(uid).args(args).output();
  80. println!("{:?}", res);
  81. res
  82. }
  83. }
  84. #[derive(Debug)]
  85. pub struct SuCommandRunner<'a, C> where C: 'a + CommandRunner {
  86. command_runner: &'a C,
  87. user_name: &'a str
  88. }
  89. impl<'a, C> SuCommandRunner<'a, C> where C: 'a + CommandRunner {
  90. pub fn new(user_name: &'a str, command_runner: &'a C) -> SuCommandRunner<'a, C> {
  91. SuCommandRunner {
  92. command_runner: command_runner,
  93. user_name: user_name
  94. }
  95. }
  96. }
  97. // Su doesn't set XDG_RUNTIME_DIR
  98. // https://github.com/systemd/systemd/blob/master/src/login/pam_systemd.c#L439
  99. impl<'a, C> CommandRunner for SuCommandRunner<'a, C> where C: 'a + CommandRunner {
  100. fn run_with_args(&self, program: &str, args: &[&str]) -> IoResult<Output> {
  101. let mut new_args = vec![self.user_name, "-s", "/usr/bin/env", "--", program];
  102. new_args.extend_from_slice(args);
  103. self.command_runner.run_with_args("su", &new_args)
  104. }
  105. }
  106. #[cfg(test)]
  107. mod test {
  108. }