gardesk/garcard / 505f11b

Browse files

Infer retention options from action policy

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
505f11bb1c357dc4f69879cc39029a6bb6d4bd09
Parents
007ef69
Tree
65d1d6b

1 changed file

StatusFile+-
M garcard/src/agent.rs 110 1
garcard/src/agent.rsmodified
@@ -57,6 +57,18 @@ pub struct PolkitBackendConfig {
5757
 type Subject = (String, HashMap<String, OwnedValue>);
5858
 type Details = HashMap<String, String>;
5959
 type TemporaryAuthorization = (String, String, Subject, u64, u64);
60
+type ActionDescription = (
61
+    String,
62
+    String,
63
+    String,
64
+    String,
65
+    String,
66
+    String,
67
+    u32,
68
+    u32,
69
+    u32,
70
+    Details,
71
+);
6072
 
6173
 #[derive(Debug, Clone, serde::Serialize)]
6274
 pub struct TemporaryAuthorizationRecord {
@@ -396,7 +408,8 @@ impl PolkitRuntime {
396408
         {
397409
             identity_options.insert(0, username.clone());
398410
         }
399
-        let retention_options = retention_options_from_details(&request.details);
411
+        let retention_options =
412
+            retention_options_with_policy_fallback(&request.action_id, &request.details);
400413
 
401414
         tracing::debug!(
402415
             identity_summary = %summarize_identities(&request.identities),
@@ -1189,6 +1202,61 @@ fn retention_options_from_details(details: &Details) -> Vec<RetentionPolicy> {
11891202
     options
11901203
 }
11911204
 
1205
+fn retention_options_with_policy_fallback(
1206
+    action_id: &str,
1207
+    details: &Details,
1208
+) -> Vec<RetentionPolicy> {
1209
+    let options = retention_options_from_details(details);
1210
+    if options.len() > 1 {
1211
+        return options;
1212
+    }
1213
+
1214
+    match retention_options_from_action_policy(action_id) {
1215
+        Ok(Some(policy_options)) if policy_options.len() > 1 => policy_options,
1216
+        Ok(_) => options,
1217
+        Err(err) => {
1218
+            tracing::debug!(
1219
+                action_id = %action_id,
1220
+                error = %err,
1221
+                "Unable to infer retention options from polkit action policy"
1222
+            );
1223
+            options
1224
+        }
1225
+    }
1226
+}
1227
+
1228
+fn retention_options_from_action_policy(action_id: &str) -> Result<Option<Vec<RetentionPolicy>>> {
1229
+    let connection = Connection::system().context("failed to connect to system bus")?;
1230
+    let proxy = PolkitAgent::proxy(&connection)?;
1231
+    let actions: Vec<ActionDescription> = proxy.call("EnumerateActions", &"")?;
1232
+    Ok(retention_options_from_action_descriptions(
1233
+        action_id, &actions,
1234
+    ))
1235
+}
1236
+
1237
+fn retention_options_from_action_descriptions(
1238
+    action_id: &str,
1239
+    actions: &[ActionDescription],
1240
+) -> Option<Vec<RetentionPolicy>> {
1241
+    let mut options = vec![RetentionPolicy::OneShot];
1242
+    let (_, _, _, _, _, _, implicit_any, implicit_inactive, implicit_active, _) =
1243
+        actions.iter().find(|(id, ..)| id == action_id)?;
1244
+
1245
+    if implicit_authorization_supports_retention(*implicit_any)
1246
+        || implicit_authorization_supports_retention(*implicit_inactive)
1247
+        || implicit_authorization_supports_retention(*implicit_active)
1248
+    {
1249
+        options.push(RetentionPolicy::Session);
1250
+    }
1251
+
1252
+    Some(options)
1253
+}
1254
+
1255
+fn implicit_authorization_supports_retention(value: u32) -> bool {
1256
+    // 3/4 are *_RETAINED variants in PolkitImplicitAuthorization.
1257
+    value == 3 || value == 4
1258
+}
1259
+
11921260
 fn first_detail_value(details: &Details, keys: &[&str]) -> Option<String> {
11931261
     for key in keys {
11941262
         let Some(value) = details.get(*key) else {
@@ -2311,6 +2379,47 @@ mod tests {
23112379
         );
23122380
     }
23132381
 
2382
+    #[test]
2383
+    fn retention_options_from_action_descriptions_support_retained_policies() {
2384
+        let actions = vec![(
2385
+            "com.gardesk.test".to_string(),
2386
+            "desc".to_string(),
2387
+            "msg".to_string(),
2388
+            "vendor".to_string(),
2389
+            "url".to_string(),
2390
+            "icon".to_string(),
2391
+            0_u32,
2392
+            0_u32,
2393
+            4_u32,
2394
+            HashMap::new(),
2395
+        )];
2396
+
2397
+        let options = retention_options_from_action_descriptions("com.gardesk.test", &actions)
2398
+            .expect("action should resolve");
2399
+        assert_eq!(
2400
+            options,
2401
+            vec![RetentionPolicy::OneShot, RetentionPolicy::Session]
2402
+        );
2403
+    }
2404
+
2405
+    #[test]
2406
+    fn retention_options_from_action_descriptions_handle_missing_action() {
2407
+        let actions = vec![(
2408
+            "com.gardesk.other".to_string(),
2409
+            "desc".to_string(),
2410
+            "msg".to_string(),
2411
+            "vendor".to_string(),
2412
+            "url".to_string(),
2413
+            "icon".to_string(),
2414
+            0_u32,
2415
+            0_u32,
2416
+            0_u32,
2417
+            HashMap::new(),
2418
+        )];
2419
+
2420
+        assert!(retention_options_from_action_descriptions("com.gardesk.test", &actions).is_none());
2421
+    }
2422
+
23142423
     #[test]
23152424
     fn parse_retention_selection_accepts_index_and_label() {
23162425
         let options = vec![