Skip to content

Commit a7d610d

Browse files
committed
[WIP] Error fixes
1 parent d8ab770 commit a7d610d

File tree

12 files changed

+38
-31
lines changed

12 files changed

+38
-31
lines changed

src/pam/converse.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl Drop for SignalGuard {
129129
}
130130

131131
impl CLIConverser {
132-
fn open(&self) -> std::io::Result<(Terminal<'_>, SignalGuard)> {
132+
fn open(&self) -> PamResult<(Terminal<'_>, SignalGuard)> {
133133
let term = if self.use_stdin {
134134
Terminal::open_stdie()?
135135
} else {
@@ -164,12 +164,9 @@ impl Converser for CLIConverser {
164164
Hidden::Yes(())
165165
},
166166
)
167-
.map_err(|err| {
168-
if let io::ErrorKind::TimedOut = err.kind() {
169-
PamError::TimedOut
170-
} else {
171-
PamError::IoError(err)
172-
}
167+
.map_err(|err| match err {
168+
PamError::IoError(err) if err.kind() == io::ErrorKind::TimedOut => PamError::TimedOut,
169+
err => err,
173170
})
174171
}
175172

src/pam/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,10 @@ pub enum PamError {
173173
Utf8Error(Utf8Error),
174174
Pam(PamErrorType),
175175
IoError(std::io::Error),
176+
TtyRequired,
176177
EnvListFailure,
177178
InteractionRequired,
179+
IncorrectPasswordAttempt,
178180
TimedOut,
179181
InvalidUser(String, String),
180182
}
@@ -216,13 +218,15 @@ impl fmt::Display for PamError {
216218
}
217219
PamError::Pam(tp) => write!(f, "PAM error: {}", tp.get_err_msg()),
218220
PamError::IoError(e) => write!(f, "IO error: {e}"),
221+
PamError::TtyRequired => write!(f, "A terminal is required to read the password"),
219222
PamError::EnvListFailure => {
220223
write!(
221224
f,
222225
"It was not possible to get a list of environment variables"
223226
)
224227
}
225228
PamError::InteractionRequired => write!(f, "Interaction is required"),
229+
PamError::IncorrectPasswordAttempt => write!(f, "Incorrect password attempt"),
226230
PamError::TimedOut => write!(f, "timed out"),
227231
PamError::InvalidUser(username, other_user) => {
228232
write!(

src/pam/rpassword.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
/// - the general idea of a "SafeString" type that clears its memory
1414
/// (although much more robust than in the original code)
1515
///
16-
use std::io::{self, Error, ErrorKind, Read};
16+
use std::io::{self, ErrorKind, Read};
1717
use std::os::fd::{AsFd, AsRawFd, BorrowedFd};
1818
use std::time::Instant;
1919
use std::{fs, mem};
2020

2121
use libc::{tcsetattr, termios, ECHO, ECHONL, ICANON, TCSANOW, VEOF, VERASE, VKILL};
2222

2323
use crate::cutils::{cerr, safe_isatty};
24+
use crate::pam::{PamError, PamResult};
2425
use crate::system::time::Duration;
2526

2627
use super::securemem::PamBuffer;
@@ -93,7 +94,7 @@ fn read_unbuffered(
9394
source: &mut dyn io::Read,
9495
sink: &mut dyn io::Write,
9596
hide_input: &Hidden<HiddenInput>,
96-
) -> io::Result<PamBuffer> {
97+
) -> PamResult<PamBuffer> {
9798
struct ExitGuard<'a> {
9899
pw_len: usize,
99100
feedback: bool,
@@ -129,6 +130,10 @@ fn read_unbuffered(
129130

130131
if let Hidden::Yes(input) | Hidden::WithFeedback(input) = hide_input {
131132
if read_byte == input.term_orig.c_cc[VEOF] {
133+
if state.pw_len == 0 {
134+
//return Err(PamError::NeedsPassword);
135+
}
136+
132137
password.fill(0);
133138
break;
134139
}
@@ -161,10 +166,7 @@ fn read_unbuffered(
161166
let _ = state.sink.write(b"*");
162167
}
163168
} else {
164-
return Err(Error::new(
165-
ErrorKind::OutOfMemory,
166-
"incorrect password attempt",
167-
));
169+
return Err(PamError::IncorrectPasswordAttempt);
168170
}
169171
}
170172

@@ -251,14 +253,15 @@ pub enum Terminal<'a> {
251253

252254
impl Terminal<'_> {
253255
/// Open the current TTY for user communication
254-
pub fn open_tty() -> io::Result<Self> {
256+
pub fn open_tty() -> PamResult<Self> {
255257
// control ourselves that we are really talking to a TTY
256258
// mitigates: https://marc.info/?l=oss-security&m=168164424404224
257259
Ok(Terminal::Tty(
258260
fs::OpenOptions::new()
259261
.read(true)
260262
.write(true)
261-
.open("/dev/tty")?,
263+
.open("/dev/tty")
264+
.map_err(|_| PamError::TtyRequired)?,
262265
))
263266
}
264267

@@ -273,7 +276,7 @@ impl Terminal<'_> {
273276
prompt: &str,
274277
timeout: Option<Duration>,
275278
hidden: Hidden<()>,
276-
) -> io::Result<PamBuffer> {
279+
) -> PamResult<PamBuffer> {
277280
fn do_hide_input(
278281
hidden: Hidden<()>,
279282
input: BorrowedFd,

test-framework/sudo-compliance-tests/src/sudo/flag_list/credential_caching.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ fn flag_reset_timestamp() {
8787
let diagnostic = if sudo_test::is_original_sudo() {
8888
"sudo: a password is required"
8989
} else {
90-
"sudo: Authentication failed"
90+
"sudo: A terminal is required to read the password"
9191
};
9292
assert_contains!(output.stderr(), diagnostic);
9393
}

test-framework/sudo-compliance-tests/src/sudo/pass_auth/stdin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn input_longer_than_max_pam_response_size_is_handled_gracefully() {
9696
assert_contains!(stderr, "sudo: 2 incorrect password attempts");
9797
}
9898
} else {
99-
assert_contains!(stderr, "incorrect authentication attempt");
99+
assert_contains!(stderr, "Incorrect password attempt");
100100
assert_not_contains!(stderr, "panic");
101101
}
102102
}
@@ -124,7 +124,7 @@ fn input_longer_than_password_should_not_be_accepted_as_correct_password() {
124124
if sudo_test::is_original_sudo() {
125125
assert_contains!(stderr, "sudo: 1 incorrect password attempt");
126126
} else {
127-
assert_contains!(stderr, "incorrect authentication attempt");
127+
assert_contains!(stderr, "Incorrect password attempt");
128128
}
129129
}
130130
}

test-framework/sudo-compliance-tests/src/sudo/pass_auth/tty.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn no_tty() {
5252
let diagnostic = if sudo_test::is_original_sudo() {
5353
"a terminal is required to read the password"
5454
} else {
55-
"Maximum 3 incorrect authentication attempts"
55+
"A terminal is required to read the password"
5656
};
5757
assert_contains!(output.stderr(), diagnostic);
5858
}
@@ -96,7 +96,7 @@ fn input_longer_than_password_should_not_be_accepted_as_correct_password() {
9696
let diagnostic = if sudo_test::is_original_sudo() {
9797
"sudo: 1 incorrect password attempt"
9898
} else {
99-
"Authentication failed, try again"
99+
"Incorrect password attempt"
100100
};
101101
assert_contains!(stderr, diagnostic);
102102
}

test-framework/sudo-compliance-tests/src/sudo/sudoers/timestamp_timeout.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Defaults timestamp_timeout=0.1"
4646
let diagnostic = if sudo_test::is_original_sudo() {
4747
"a password is required"
4848
} else {
49-
"incorrect authentication attempt"
49+
"A terminal is required to read the password"
5050
};
5151
assert_contains!(output.stderr(), diagnostic);
5252
}
@@ -73,7 +73,7 @@ Defaults timestamp_timeout=0"
7373
let diagnostic = if sudo_test::is_original_sudo() {
7474
"a password is required"
7575
} else {
76-
"incorrect authentication attempt"
76+
"A terminal is required to read the password"
7777
};
7878
assert_contains!(output.stderr(), diagnostic);
7979
}

test-framework/sudo-compliance-tests/src/sudo/timestamp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn by_default_credential_caching_is_local() {
4545
let diagnostic = if sudo_test::is_original_sudo() {
4646
"a password is required"
4747
} else {
48-
"incorrect authentication attempt"
48+
"A terminal is required to read the password"
4949
};
5050
assert_contains!(output.stderr(), diagnostic);
5151
}
@@ -220,7 +220,7 @@ fn cached_credential_not_shared_between_auth_users() {
220220
let diagnostic = if sudo_test::is_original_sudo() {
221221
"a password is required"
222222
} else {
223-
"incorrect authentication attempt"
223+
"A terminal is required to read the password"
224224
};
225225
assert_contains!(output.stderr(), diagnostic);
226226
}

test-framework/sudo-compliance-tests/src/sudo/timestamp/remove.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn also_works_locally() {
8383
let diagnostic = if sudo_test::is_original_sudo() {
8484
"a password is required"
8585
} else {
86-
"Authentication failed"
86+
"A terminal is required to read the password"
8787
};
8888
assert_contains!(output.stderr(), diagnostic);
8989
}

test-framework/sudo-compliance-tests/src/sudo/timestamp/reset.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn it_works() {
2424
let diagnostic = if sudo_test::is_original_sudo() {
2525
"a password is required"
2626
} else {
27-
"incorrect authentication attempt"
27+
"A terminal is required to read the password"
2828
};
2929
assert_contains!(output.stderr(), diagnostic);
3030
}
@@ -72,7 +72,7 @@ fn with_command_prompts_for_password() {
7272
let diagnostic = if sudo_test::is_original_sudo() {
7373
"a password is required"
7474
} else {
75-
"incorrect authentication attempt"
75+
"A terminal is required to read the password"
7676
};
7777
assert_contains!(output.stderr(), diagnostic);
7878
}
@@ -144,7 +144,7 @@ fn with_command_does_not_cache_credentials() {
144144
let diagnostic = if sudo_test::is_original_sudo() {
145145
"a password is required"
146146
} else {
147-
"Authentication failed"
147+
"A terminal is required to read the password"
148148
};
149149
assert_contains!(output.stderr(), diagnostic);
150150
}

0 commit comments

Comments
 (0)