1- use std:: io ;
1+ use std:: { env , io } ;
22
33use crate :: common:: { HARDENED_ENUM_VALUE_0 , HARDENED_ENUM_VALUE_1 , HARDENED_ENUM_VALUE_2 } ;
44use crate :: exec:: { RunOptions , Umask } ;
@@ -34,6 +34,9 @@ pub struct Context {
3434 pub use_pty : bool ,
3535 pub noexec : bool ,
3636 pub umask : Umask ,
37+ // sudoedit
38+ #[ cfg_attr( not( feature = "sudoedit" ) , allow( unused) ) ]
39+ pub files_to_edit : Vec < Option < SudoPath > > ,
3740}
3841
3942#[ derive( Clone , Copy , Debug , Default , PartialEq , Eq ) ]
@@ -74,7 +77,7 @@ impl Context {
7477 let path = if let Some ( path) = override_path {
7578 path
7679 } else {
77- system_path = std :: env:: var ( "PATH" ) . unwrap_or_default ( ) ;
80+ system_path = env:: var ( "PATH" ) . unwrap_or_default ( ) ;
7881 system_path. as_ref ( )
7982 } ;
8083
@@ -98,6 +101,7 @@ impl Context {
98101 use_pty : true ,
99102 noexec : false ,
100103 umask : Umask :: Preserve ,
104+ files_to_edit : vec ! [ ] ,
101105 } )
102106 }
103107
@@ -109,12 +113,35 @@ impl Context {
109113 let ( target_user, target_group) =
110114 resolve_target_user_and_group ( & sudo_options. user , & sudo_options. group , & current_user) ?;
111115
116+ // resolve file arguments; if something can't be resolved, don't add it to the "edit" list
117+ let resolved_args = sudo_options. positional_args . iter ( ) . map ( |arg| {
118+ crate :: common:: resolve:: canonicalize_newfile ( arg)
119+ . map_err ( |_| arg)
120+ . and_then ( |path| path. into_os_string ( ) . into_string ( ) . map_err ( |_| arg) )
121+ } ) ;
122+
123+ let files_to_edit = resolved_args
124+ . clone ( )
125+ . map ( |path| path. ok ( ) . map ( SudoPath :: from_cli_string) )
126+ . collect ( ) ;
127+
128+ // if a path resolved to something that isn't in UTF-8, it means it isn't in the sudoers file
129+ // as well and so we treat it "as is" wrt. the policy lookup and fail if the user is allowed
130+ // by the policy to edit that file. this is to prevent leaking information.
131+ let arguments = resolved_args
132+ . map ( |arg| match arg {
133+ Ok ( arg) => arg,
134+ Err ( arg) => arg. to_owned ( ) ,
135+ } )
136+ . collect ( ) ;
137+
112138 // TODO: the more Rust way of doing things would be to create an alternative for sudoedit instead;
113139 // but a stringly typed interface feels the most decent thing to do (if we can pull it off)
114- // since "sudoedit" really is like a builtin command to sudo.
140+ // since "sudoedit" really is like a builtin command to sudo. We may want to be a bit 'better' than
141+ // ogsudo in the future.
115142 let command = CommandAndArguments {
116143 command : std:: path:: PathBuf :: from ( "sudoedit" ) ,
117- arguments : sudo_options . positional_args ,
144+ arguments,
118145 ..Default :: default ( )
119146 } ;
120147
@@ -135,6 +162,7 @@ impl Context {
135162 use_pty : true ,
136163 noexec : false ,
137164 umask : Umask :: Preserve ,
165+ files_to_edit,
138166 } )
139167 }
140168 pub fn from_validate_opts ( sudo_options : SudoValidateOptions ) -> Result < Context , Error > {
@@ -160,6 +188,7 @@ impl Context {
160188 use_pty : true ,
161189 noexec : false ,
162190 umask : Umask :: Preserve ,
191+ files_to_edit : vec ! [ ] ,
163192 } )
164193 }
165194
@@ -182,7 +211,7 @@ impl Context {
182211 let path = if let Some ( path) = override_path {
183212 path
184213 } else {
185- system_path = std :: env:: var ( "PATH" ) . unwrap_or_default ( ) ;
214+ system_path = env:: var ( "PATH" ) . unwrap_or_default ( ) ;
186215 system_path. as_ref ( )
187216 } ;
188217
@@ -206,6 +235,7 @@ impl Context {
206235 use_pty : true ,
207236 noexec : false ,
208237 umask : Umask :: Preserve ,
238+ files_to_edit : vec ! [ ] ,
209239 } )
210240 }
211241
0 commit comments