2
0

update dropbear, simplify authorized_keys patch

This commit is contained in:
2026-03-11 18:22:39 +00:00
parent c364095c44
commit 7f23c5dc0f
2 changed files with 33 additions and 204 deletions

View File

@@ -167,24 +167,9 @@ extraPkgs
dropbear = crossOnly prev.dropbear (
d:
d.overrideAttrs (o: rec {
# nixpkgs 25.05 contains newer dropbear (2025.87) than this,
# we can drop this override when that's ready
version = "2024.85";
src = final.fetchurl {
url = "https://matt.ucc.asn.au/dropbear/releases/dropbear-${version}.tar.bz2";
sha256 = "sha256-hrA2xDOmnYnOUeuuM11lxHc4zPkNE+XrD+qDLlVtpQI=";
};
patches =
# in 24.11 we need to update nixpkgs patch for new version of dropbear
let
passPath = final.runCommand "pass-path" { } ''
sed < ${builtins.head o.patches} -e 's,svr-chansession.c,src/svr-chansession.c,g' > $out
'';
in
[
(if (lib.versionOlder o.version "2024") then passPath else (builtins.head o.patches))
./pkgs/dropbear/add-authkeyfile-option.patch
];
patches = o.patches ++ [
./pkgs/dropbear/add-authkeyfile-option.patch
];
postPatch = ''
(echo '#define DSS_PRIV_FILENAME "/run/dropbear/dropbear_dss_host_key"'
echo '#define RSA_PRIV_FILENAME "/run/dropbear/dropbear_rsa_host_key"'

View File

@@ -1,31 +1,5 @@
From 9c0ac9e41a393e0f16a57e36d9369d61d39e9aa5 Mon Sep 17 00:00:00 2001
From: Daniel Barlow <dan@telent.net>
Date: Fri, 23 Aug 2024 11:33:24 +0100
Subject: [PATCH] add -U otion to set path to authorized_keys file
based on https://github.com/mkj/dropbear/pull/35
by Salvador Fandino sfandino@yahoo.com
- Allow authorized keys inside dirs with the sticky bit set
- Add option -U for customizing authorized_keys path
- Updated for dropbear 2024.85 (source files moved to src/)
- allow %u, %d, %n "format specifiers" in pathname so that the user's
username/homedir/uid can be embedded into the path
---
Makefile.in | 2 +-
manpages/dropbear.8 | 3 +
src/pathexpand.c | 149 +++++++++++++++++++++++++++++++++++++++++++
src/runopts.h | 3 +-
src/svr-authpubkey.c | 86 +++++++++++--------------
src/svr-runopts.c | 10 +++
6 files changed, 203 insertions(+), 50 deletions(-)
create mode 100644 src/pathexpand.c
diff --git a/Makefile.in b/Makefile.in
index 5ebfca2..686fbfb 100644
index fe63a80..b050be3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -51,7 +51,7 @@ COMMONOBJS = $(patsubst %,$(OBJ_DIR)/%,$(_COMMONOBJS))
@@ -38,7 +12,7 @@ index 5ebfca2..686fbfb 100644
_CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
diff --git a/manpages/dropbear.8 b/manpages/dropbear.8
index bdb2ea0..c8d450d 100644
index 72be0ae..78e0a99 100644
--- a/manpages/dropbear.8
+++ b/manpages/dropbear.8
@@ -29,6 +29,9 @@ or automatically with the '-R' option. See "Host Key Files" below.
@@ -207,171 +181,45 @@ index 0000000..07e6955
+ return filename; /* caller must free */
+}
diff --git a/src/runopts.h b/src/runopts.h
index 1c88b5c..707008f 100644
index c8072b3..73ffdb1 100644
--- a/src/runopts.h
+++ b/src/runopts.h
@@ -128,7 +128,8 @@ typedef struct svr_runopts {
@@ -124,6 +124,7 @@ typedef struct svr_runopts {
char * pidfile;
char * forced_command;
- char* interface;
+ char * authkeysfile;
+ char * interface;
char * authorized_keys_dir;
+ char * authorized_keys_file;
#if DROPBEAR_PLUGIN
/* malloced */
char * forced_command;
char* interface;
diff --git a/src/svr-authpubkey.c b/src/svr-authpubkey.c
index 5d298cb..54502f4 100644
index 94ae728..9da6654 100644
--- a/src/svr-authpubkey.c
+++ b/src/svr-authpubkey.c
@@ -73,7 +73,7 @@
@@ -72,6 +72,7 @@
#define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */
static char * authorized_keys_filepath(void);
+extern char * pathexpand(char *input);
static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
const unsigned char* keyblob, unsigned int keybloblen);
-static int checkpubkeyperms(void);
+static int checkpubkeyperms(char *filename, char *base);
static void send_msg_userauth_pk_ok(const char* sigalgo, unsigned int sigalgolen,
const unsigned char* keyblob, unsigned int keybloblen);
static int checkfileperm(char * filename);
@@ -431,6 +431,7 @@ out:
return ret;
}
static int checkpubkeyperms(void);
@@ -441,6 +442,10 @@ static char *authorized_keys_filepath() {
char *pathname = NULL, *dir = NULL;
const char *filename = "authorized_keys";
+extern char *pathexpand(char *input);
/* Checks whether a specified publickey (and associated algorithm) is an
* acceptable key for authentication */
@@ -458,19 +459,12 @@ static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
dropbear_exit("Failed to set euid");
}
#endif
+ filename = pathexpand(svr_opts.authkeysfile);
+ if(svr_opts.authorized_keys_file) {
+ return pathexpand(svr_opts.authorized_keys_file);
+ };
+
/* check file permissions, also whether file exists */
- if (checkpubkeyperms() == DROPBEAR_FAILURE) {
- TRACE(("bad authorized_keys permissions, or file doesn't exist"))
+ if (checkpubkeyperms(filename, ses.authstate.pw_dir) == DROPBEAR_FAILURE) {
+ TRACE(("bad authorized keys permissions on %s, or file doesn't exist", filename))
} else {
- /* we don't need to check pw and pw_dir for validity, since
- * its been done in checkpubkeyperms. */
- len = strlen(ses.authstate.pw_dir);
- /* allocate max required pathname storage,
- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
- filename = m_malloc(len + 22);
- snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
- ses.authstate.pw_dir);
-
authfile = fopen(filename, "r");
if (!authfile) {
TRACE(("checkpubkey: failed opening %s: %s", filename, strerror(errno)))
@@ -486,7 +480,7 @@ static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
if (authfile == NULL) {
goto out;
}
- TRACE(("checkpubkey: opened authorized_keys OK"))
+ TRACE(("checkpubkey: opened %s OK", filename))
dir = expand_homedir_path_home(svr_opts.authorized_keys_dir,
ses.authstate.pw_dir);
line = buf_new(MAX_AUTHKEYS_LINE);
line_num = 0;
@@ -524,53 +518,47 @@ out:
/* Returns DROPBEAR_SUCCESS if file permissions for pubkeys are ok,
* DROPBEAR_FAILURE otherwise.
- * Checks that the user's homedir, ~/.ssh, and
- * ~/.ssh/authorized_keys are all owned by either root or the user, and are
+ * Checks filename and its parent directories recursively until the
+ * base directory (usually ~/) or one of its ancestors (up to /) is
+ * reached.
+ * The files and directories must be all owned by root or the user, and be
* g-w, o-w */
-static int checkpubkeyperms() {
-
- char* filename = NULL;
+static int checkpubkeyperms(char *filename, char *base) {
+ char* path = NULL;
int ret = DROPBEAR_FAILURE;
unsigned int len;
- TRACE(("enter checkpubkeyperms"))
-
- if (ses.authstate.pw_dir == NULL) {
- goto out;
- }
+ TRACE(("enter checkpubkeyperms(%s, %s)", filename, base))
- if ((len = strlen(ses.authstate.pw_dir)) == 0) {
+ if ((base == NULL) || (base[0] != '/') ||
+ (filename == NULL) || (filename[0] != '/')) {
+ /* both filename and base must be absolute paths */
goto out;
}
- /* allocate max required pathname storage,
- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
- len += 22;
- filename = m_malloc(len);
- strlcpy(filename, ses.authstate.pw_dir, len);
+ len = strlen(filename);
+ path = m_strdup(filename);
- /* check ~ */
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-
- /* check ~/.ssh */
- strlcat(filename, "/.ssh", len);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
+ while (checkfileperm(len ? path : "/") == DROPBEAR_SUCCESS) {
+ /* check if we are on base trail and if this is the
+ * case, return success */
+ if ((strncmp(base, path, len) == 0) &&
+ (!len || (base[len] == '\0') || (base[len] == '/'))) {
+ ret = DROPBEAR_SUCCESS;
+ break;
+ }
- /* now check ~/.ssh/authorized_keys */
- strlcat(filename, "/authorized_keys", len);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
+ /* look for parent directory */
+ while (--len) {
+ if (path[len] == '/') {
+ path[len] = '\0';
+ break;
+ }
+ }
}
- /* file looks ok, return success */
- ret = DROPBEAR_SUCCESS;
-
out:
- m_free(filename);
+ m_free(path);
TRACE(("leave checkpubkeyperms"))
return ret;
@@ -596,7 +584,9 @@ static int checkfileperm(char * filename) {
TRACE(("wrong ownership"))
}
/* check permissions - don't want group or others +w */
- if (filestat.st_mode & (S_IWGRP | S_IWOTH)) {
+ /* (unless sticky dir, which is allowed) */
+ if ((filestat.st_mode & (S_IWGRP | S_IWOTH)) &&
+ !(S_ISDIR(filestat.st_mode) && (filestat.st_mode & S_ISVTX))) {
badperm = 1;
TRACE(("wrong perms"))
}
diff --git a/src/svr-runopts.c b/src/svr-runopts.c
index c4f83c1..faddfa2 100644
index 8034c50..986c552 100644
--- a/src/svr-runopts.c
+++ b/src/svr-runopts.c
@@ -147,6 +147,7 @@ void svr_getopts(int argc, char ** argv) {
@@ -150,6 +150,7 @@ void svr_getopts(int argc, char ** argv) {
char* maxauthtries_arg = NULL;
char* reexec_fd_arg = NULL;
char* keyfile = NULL;
@@ -379,16 +227,15 @@ index c4f83c1..faddfa2 100644
char c;
#if DROPBEAR_PLUGIN
char* pubkey_plugin = NULL;
@@ -173,6 +174,8 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.hostkey = NULL;
@@ -177,6 +178,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.delay_hostkey = 0;
svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
+ svr_opts.authkeysfile = "%d/.ssh/authorized_keys";
+
svr_opts.authorized_keys_dir = "~/.ssh";
+ svr_opts.authorized_keys_file = NULL;
#if DROPBEAR_SVR_LOCALANYFWD
svr_opts.nolocaltcp = 0;
#endif
@@ -322,6 +325,9 @@ void svr_getopts(int argc, char ** argv) {
@@ -344,6 +346,9 @@ void svr_getopts(int argc, char ** argv) {
case 'u':
/* backwards compatibility with old urandom option */
break;
@@ -398,17 +245,14 @@ index c4f83c1..faddfa2 100644
#if DROPBEAR_PLUGIN
case 'A':
next = &pubkey_plugin;
@@ -372,6 +378,10 @@ void svr_getopts(int argc, char ** argv) {
@@ -394,6 +399,10 @@ void svr_getopts(int argc, char ** argv) {
addhostkey(keyfile);
keyfile = NULL;
}
+ if (authkeysfile) {
+ svr_opts.authkeysfile = m_strdup(authkeysfile);
+ svr_opts.authorized_keys_file = m_strdup(authkeysfile);
+ authkeysfile = NULL;
+ }
}
}
--
2.47.0