update dropbear, simplify authorized_keys patch
This commit is contained in:
21
overlay.nix
21
overlay.nix
@@ -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"'
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user