aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Araps <dylan.araps@gmail.com>2026-03-14 09:31:51 +0200
committerDylan Araps <dylan.araps@gmail.com>2026-03-14 09:31:51 +0200
commit79eb4385bd34e8ee06b35637f092ee45dc3e3706 (patch)
tree4c3de5583733e9c9cfdc7b5f31a56f8d2ba205ba
parentf3416de0e2fd920dda7379c3b7dc2b3087cc30c6 (diff)
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.
-rw-r--r--README.md16
-rw-r--r--config.h.in7
-rw-r--r--config_key.h.in1
-rwxr-xr-xconfigure2
-rw-r--r--dfm.c29
-rw-r--r--lib/util.h9
6 files changed, 63 insertions, 1 deletions
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
@@ -34,6 +34,13 @@
#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:
// 'arg0' 'arg1' '{col}x{row}' 'img'
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 {{{
@@ -2853,6 +2854,33 @@ act_quit_print_pwd(struct fm *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)
{
cut h = get_env("HOME", "");
@@ -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