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.

99 lines
2.8 KiB

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