Prefer session user for helper auth
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
18ebea40bbd216b351b5d97c393014a8bb874344- Parents
-
5ad012e - Tree
f0cdfeb
18ebea4
18ebea40bbd216b351b5d97c393014a8bb8743445ad012e
f0cdfeb| Status | File | + | - |
|---|---|---|---|
| M |
garcard/src/agent.rs
|
50 | 8 |
| M |
garcard/src/polkit_helper.rs
|
19 | 15 |
garcard/src/agent.rsmodified@@ -200,6 +200,7 @@ impl PolkitRuntime { | ||
| 200 | 200 | action_id = %active.action_id, |
| 201 | 201 | icon_name = %active.icon_name, |
| 202 | 202 | detail_count = active.detail_count, |
| 203 | + username = %active.username, | |
| 203 | 204 | "Processing polkit auth request" |
| 204 | 205 | ); |
| 205 | 206 | |
@@ -317,24 +318,45 @@ impl PolkitRuntime { | ||
| 317 | 318 | } |
| 318 | 319 | |
| 319 | 320 | fn resolve_identity_username(identities: &[Subject]) -> Option<String> { |
| 321 | + let current = current_username(); | |
| 322 | + if let Some(current_name) = current.as_deref() { | |
| 323 | + for (kind, details) in identities { | |
| 324 | + if kind != "unix-user" { | |
| 325 | + continue; | |
| 326 | + } | |
| 327 | + | |
| 328 | + if let Some(name) = identity_name(details) { | |
| 329 | + if name == current_name { | |
| 330 | + return Some(name); | |
| 331 | + } | |
| 332 | + } | |
| 333 | + } | |
| 334 | + } | |
| 335 | + | |
| 320 | 336 | for (kind, details) in identities { |
| 321 | 337 | if kind != "unix-user" { |
| 322 | 338 | continue; |
| 323 | 339 | } |
| 324 | 340 | |
| 325 | - if let Some(value) = details.get("name") { | |
| 326 | - if let Ok(name) = <&str>::try_from(value) { | |
| 327 | - return Some(name.to_string()); | |
| 328 | - } | |
| 341 | + if let Some(name) = identity_name(details) { | |
| 342 | + return Some(name); | |
| 329 | 343 | } |
| 344 | + } | |
| 330 | 345 | |
| 331 | - if let Some(uid) = details.get("uid").and_then(parse_uid) { | |
| 332 | - if let Some(name) = username_for_uid(uid) { | |
| 333 | - return Some(name); | |
| 334 | - } | |
| 346 | + None | |
| 347 | +} | |
| 348 | + | |
| 349 | +fn identity_name(details: &HashMap<String, OwnedValue>) -> Option<String> { | |
| 350 | + if let Some(value) = details.get("name") { | |
| 351 | + if let Ok(name) = <&str>::try_from(value) { | |
| 352 | + return Some(name.to_string()); | |
| 335 | 353 | } |
| 336 | 354 | } |
| 337 | 355 | |
| 356 | + if let Some(uid) = details.get("uid").and_then(parse_uid) { | |
| 357 | + return username_for_uid(uid); | |
| 358 | + } | |
| 359 | + | |
| 338 | 360 | None |
| 339 | 361 | } |
| 340 | 362 | |
@@ -826,4 +848,24 @@ mod tests { | ||
| 826 | 848 | let resolved = resolve_identity_username(&identities); |
| 827 | 849 | assert_eq!(resolved, current_username()); |
| 828 | 850 | } |
| 851 | + | |
| 852 | + #[test] | |
| 853 | + fn resolve_identity_username_prefers_current_user_name() { | |
| 854 | + let mut first = HashMap::new(); | |
| 855 | + first.insert("uid".to_string(), OwnedValue::from(0_u32)); | |
| 856 | + | |
| 857 | + let mut second = HashMap::new(); | |
| 858 | + second.insert( | |
| 859 | + "uid".to_string(), | |
| 860 | + OwnedValue::from(nix::unistd::geteuid().as_raw()), | |
| 861 | + ); | |
| 862 | + | |
| 863 | + let identities = vec![ | |
| 864 | + ("unix-user".to_string(), first), | |
| 865 | + ("unix-user".to_string(), second), | |
| 866 | + ]; | |
| 867 | + | |
| 868 | + let resolved = resolve_identity_username(&identities); | |
| 869 | + assert_eq!(resolved, current_username()); | |
| 870 | + } | |
| 829 | 871 | } |
garcard/src/polkit_helper.rsmodified@@ -99,6 +99,10 @@ impl HelperSocketClient { | ||
| 99 | 99 | if bytes == 0 { |
| 100 | 100 | anyhow::bail!("helper closed connection unexpectedly"); |
| 101 | 101 | } |
| 102 | + tracing::debug!( | |
| 103 | + helper_line = %line.trim_end_matches('\n').trim_end_matches('\r'), | |
| 104 | + "Received helper protocol line" | |
| 105 | + ); | |
| 102 | 106 | |
| 103 | 107 | let event = match parse_helper_line(&line) { |
| 104 | 108 | Ok(event) => event, |
@@ -211,17 +215,14 @@ pub fn parse_helper_line(raw: &str) -> Result<HelperEvent> { | ||
| 211 | 215 | return Ok(HelperEvent::Info(message.to_string())); |
| 212 | 216 | } |
| 213 | 217 | |
| 214 | - // Some helper builds emit plain-text diagnostics instead of PAM_* protocol | |
| 215 | - // lines. Classify known auth failures so callers can present proper retry UX | |
| 216 | - // without treating successful paths as generic errors. | |
| 217 | - let lower = line.to_ascii_lowercase(); | |
| 218 | - if lower.contains("pam_authenticate failed") | |
| 219 | - || lower.contains("authentication failure") | |
| 220 | - || lower.contains("no session for cookie") | |
| 221 | - { | |
| 222 | - return Ok(HelperEvent::Failure); | |
| 223 | - } | |
| 224 | 218 | if line.starts_with("polkit-agent-helper-1:") { |
| 219 | + let lower = line.to_ascii_lowercase(); | |
| 220 | + if lower.contains("pam_authenticate failed") | |
| 221 | + || lower.contains("authentication failure") | |
| 222 | + || lower.contains("no session for cookie") | |
| 223 | + { | |
| 224 | + return Ok(HelperEvent::Error(line.to_string())); | |
| 225 | + } | |
| 225 | 226 | return Ok(HelperEvent::Info(line.to_string())); |
| 226 | 227 | } |
| 227 | 228 | |
@@ -325,18 +326,21 @@ mod tests { | ||
| 325 | 326 | } |
| 326 | 327 | |
| 327 | 328 | #[test] |
| 328 | - fn parse_helper_line_maps_plaintext_failure_diagnostics() { | |
| 329 | + fn parse_helper_line_maps_plaintext_failure_diagnostics_to_error() { | |
| 329 | 330 | assert_eq!( |
| 330 | 331 | parse_helper_line( |
| 331 | 332 | "polkit-agent-helper-1: pam_authenticate failed: Authentication failure" |
| 332 | 333 | ) |
| 333 | - .expect("maps failure"), | |
| 334 | - HelperEvent::Failure | |
| 334 | + .expect("maps error"), | |
| 335 | + HelperEvent::Error( | |
| 336 | + "polkit-agent-helper-1: pam_authenticate failed: Authentication failure" | |
| 337 | + .to_string() | |
| 338 | + ) | |
| 335 | 339 | ); |
| 336 | 340 | assert_eq!( |
| 337 | 341 | parse_helper_line("polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie") |
| 338 | - .expect("maps cookie failure"), | |
| 339 | - HelperEvent::Failure | |
| 342 | + .expect("maps cookie error"), | |
| 343 | + HelperEvent::Error("polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie".to_string()) | |
| 340 | 344 | ); |
| 341 | 345 | } |
| 342 | 346 | |