From 79eb4385bd34e8ee06b35637f092ee45dc3e3706 Mon Sep 17 00:00:00 2001 From: Dylan Araps Date: Sat, 14 Mar 2026 09:31:51 +0200 Subject: dfm: Add privilege escalation. Pressing 'Z' (default) will spawn a nested dfm by escalating privileges using the value of DFM_SU (default 'sudo'). Pressing 'Z' again inside of this escalated mode returns to the original dfm. --- README.md | 16 ++++++++++++++++ config.h.in | 7 +++++++ config_key.h.in | 1 + configure | 2 +- dfm.c | 29 +++++++++++++++++++++++++++++ lib/util.h | 9 +++++++++ 6 files changed, 63 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa537c7..9563d24 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Initial Announcement: https://dylan.gr/1772192922 * [Searching](#searching) * [Marking](#marking) * [Commands](#commands) + * [Privilege Escalation](#privilege-escalation) * [Bound Commands](#bound-commands) * [Design Considerations](#design-considerations) * [Conclusion](#conclusion) @@ -190,6 +191,8 @@ environment, default values are derived from the `config.h.in` file. - DFM_TRASH_DIR (Path to trash directory) - DFM_IMG_MODE (Image mode to use: 'chafa' (default), 'kitty') + +- DFM_SU (Privilege escalation tool to use: 'sudo' (default)) ``` ### CD On Exit @@ -386,6 +389,19 @@ and sends it all to the shell. ``` +### Privilege Escalation + +Commands can be run as root by prepending `sudo` or a similar tool on the +command-line. For more complex situations, pressing `Z` by default will use +`DFM_SU` (default `sudo`) to spawn another `dfm` as `root`. The statusline will +be a different color, show the nest level and display an `R` indicator to make +the escalation obvious. Pressing `Z` again inside of this escalated mode quits +and returns to the original `dfm`. + +This can be configured at runtime using the environment variable `DFM_SU` and +at compile time via the `config.h.in` file. + + ### Bound Commands Commands can be bound to keys. When a command is bound it can either run diff --git a/config.h.in b/config.h.in index f6fb6d4..23f4258 100644 --- a/config.h.in +++ b/config.h.in @@ -33,6 +33,13 @@ #define DFM_BOOKMARK_8 "" #define DFM_BOOKMARK_9 "" +// +// Default privilege escalation utiliy. +// This is used to become root in dfm (default 'Z'). +// Values: "sudo", "doas", "ssu", "su", "run0", etc +// +#define DFM_SU "sudo" + // // Default image viewer. // The command is executed as follows: diff --git a/config_key.h.in b/config_key.h.in index 0026853..4c087bf 100644 --- a/config_key.h.in +++ b/config_key.h.in @@ -91,6 +91,7 @@ static inline void (*fm_key(u32 cp))(struct fm *) case 'x': return act_stat; case 'i': return act_view_image; case 'z': return act_alt_buffer; + case 'Z': return act_toggle_root; case 'p': return cmd_chmod; case 'P': return cmd_chown; case 'B': return cmd_bulk_rename; diff --git a/configure b/configure index 90710c6..3515ec8 100755 --- a/configure +++ b/configure @@ -19,7 +19,7 @@ # Program configuration. # export CFG_NAME=dfm -export CFG_VERSION=1.0.0 +export CFG_VERSION=1.0.1 export c_version=c99 # diff --git a/dfm.c b/dfm.c index 23d0b68..02a1d9b 100644 --- a/dfm.c +++ b/dfm.c @@ -196,6 +196,7 @@ struct fm { s64 tz; u8 nl; u8 im; + const char *a0; }; // Entry Virtual {{{ @@ -2852,6 +2853,33 @@ act_quit_print_pwd(struct fm *p) act_quit(p); } +static inline void +act_toggle_root(struct fm *p) +{ + cut pe = get_env("DFM_SU", DFM_SU); + if (p->f & FM_ROOT) + term_set_dead(&p->t, 1); + else if (!pe.l) + fm_draw_err(p, S("DFM_SU not set"), 0); + else { + usize o = p->ppwd.l; + STR_PUSH(&p->ppwd, "env DFM_LEVEL="); + str_push_c(&p->ppwd, p->nl ? p->nl : '0'); + str_push_c(&p->ppwd, ' '); + str_push_s(&p->ppwd, p->a0); + str_terminate(&p->ppwd); + p->ppwd.l = o; + if (!strcmp(basename_l(pe.d, pe.l), "su")) { + const char *const a[] = { pe.d, "-c", p->ppwd.m + o, NULL }; + fm_exec(p, -1, NULL, a, 0, 1); + } else { + p->ppwd.m[o + 15] = 0; + const char *const a[] = { pe.d, "env", p->ppwd.m + 5, p->a0, NULL }; + fm_exec(p, -1, NULL, a, 0, 1); + } + } +} + static inline void act_cd_home(struct fm *p) { @@ -3700,6 +3728,7 @@ int main(int argc, char *argv[]) { static struct fm p; + p.a0 = argv[0]; str *s = &p.pwd; if (fm_init(&p) < 0) { diff --git a/lib/util.h b/lib/util.h index 9a69746..1eeb8dd 100644 --- a/lib/util.h +++ b/lib/util.h @@ -336,5 +336,14 @@ path_resolve(char *s, usize l) return w; } +static inline const char * +basename_l(const char *s, usize l) +{ + for (usize i = l; i; i--) + if (s[i - 1] == '/') + return s + i; + return s; +} + #endif // DYLAN_UTIL_H -- cgit v1.2.3