1
- use std:: io ;
1
+ use std:: { env , io } ;
2
2
3
3
use crate :: common:: { HARDENED_ENUM_VALUE_0 , HARDENED_ENUM_VALUE_1 , HARDENED_ENUM_VALUE_2 } ;
4
4
use crate :: exec:: { RunOptions , Umask } ;
@@ -34,6 +34,9 @@ pub struct Context {
34
34
pub use_pty : bool ,
35
35
pub noexec : bool ,
36
36
pub umask : Umask ,
37
+ // sudoedit
38
+ #[ cfg_attr( not( feature = "sudoedit" ) , allow( unused) ) ]
39
+ pub files_to_edit : Vec < Option < SudoPath > > ,
37
40
}
38
41
39
42
#[ derive( Clone , Copy , Debug , Default , PartialEq , Eq ) ]
@@ -74,7 +77,7 @@ impl Context {
74
77
let path = if let Some ( path) = override_path {
75
78
path
76
79
} else {
77
- system_path = std :: env:: var ( "PATH" ) . unwrap_or_default ( ) ;
80
+ system_path = env:: var ( "PATH" ) . unwrap_or_default ( ) ;
78
81
system_path. as_ref ( )
79
82
} ;
80
83
@@ -98,6 +101,7 @@ impl Context {
98
101
use_pty : true ,
99
102
noexec : false ,
100
103
umask : Umask :: Preserve ,
104
+ files_to_edit : vec ! [ ] ,
101
105
} )
102
106
}
103
107
@@ -109,12 +113,35 @@ impl Context {
109
113
let ( target_user, target_group) =
110
114
resolve_target_user_and_group ( & sudo_options. user , & sudo_options. group , & current_user) ?;
111
115
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
+
112
138
// TODO: the more Rust way of doing things would be to create an alternative for sudoedit instead;
113
139
// 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.
115
142
let command = CommandAndArguments {
116
143
command : std:: path:: PathBuf :: from ( "sudoedit" ) ,
117
- arguments : sudo_options . positional_args ,
144
+ arguments,
118
145
..Default :: default ( )
119
146
} ;
120
147
@@ -135,6 +162,7 @@ impl Context {
135
162
use_pty : true ,
136
163
noexec : false ,
137
164
umask : Umask :: Preserve ,
165
+ files_to_edit,
138
166
} )
139
167
}
140
168
pub fn from_validate_opts ( sudo_options : SudoValidateOptions ) -> Result < Context , Error > {
@@ -160,6 +188,7 @@ impl Context {
160
188
use_pty : true ,
161
189
noexec : false ,
162
190
umask : Umask :: Preserve ,
191
+ files_to_edit : vec ! [ ] ,
163
192
} )
164
193
}
165
194
@@ -182,7 +211,7 @@ impl Context {
182
211
let path = if let Some ( path) = override_path {
183
212
path
184
213
} else {
185
- system_path = std :: env:: var ( "PATH" ) . unwrap_or_default ( ) ;
214
+ system_path = env:: var ( "PATH" ) . unwrap_or_default ( ) ;
186
215
system_path. as_ref ( )
187
216
} ;
188
217
@@ -206,6 +235,7 @@ impl Context {
206
235
use_pty : true ,
207
236
noexec : false ,
208
237
umask : Umask :: Preserve ,
238
+ files_to_edit : vec ! [ ] ,
209
239
} )
210
240
}
211
241
0 commit comments