Skip to content

Commit

Permalink
Add option -U for customizing authorized_keys path
Browse files Browse the repository at this point in the history
This patch adds support for the new command line flag -U which allows
one to customize the location of the file containing the authorized
keys. This is usefull when running several unrelated and isolated SSH
services on one machine, using different sets of authentication keys.

The new -U flag accept both absolute and relative paths. When a
relative path is used it is appended to the user home directory.

Authentication fails when any intermediate directory between the user
home and the location of the file (both inclusive) is group or world
writeable.

When an absolute directory is given all the ancestor directories are
checked until some common parent between the authorized keys path and
the user home (up to the root directory) is reached.

For instance, if home is '/home/bar', and the authorized keys path
given is '/home/root/.ssh/authorized_keys', the objects checked are
'/home/root/.ssh/authorized_keys', '/home/root/.ssh', '/home/root'
and '/home'.
  • Loading branch information
salva committed Jun 9, 2016
1 parent e0c6e81 commit 0197473
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 45 deletions.
3 changes: 3 additions & 0 deletions dropbear.8
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ or automatically with the '-R' option. See "Host Key Files" below.
.B \-R
Generate hostkeys automatically. See "Host Key Files" below.
.TP
.B \-U \fIauthorized_keys
Path to file containing authorized user keys inside the user home directory. Defaults to '.ssh/authorized_keys'.
.TP
.B \-F
Don't fork into background.
.TP
Expand Down
2 changes: 2 additions & 0 deletions runopts.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ typedef struct svr_runopts {

char * forced_command;

char * authkeysfile;

} svr_runopts;

extern svr_runopts svr_opts;
Expand Down
89 changes: 44 additions & 45 deletions svr-authpubkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "ssh.h"
#include "packet.h"
#include "algo.h"
#include "runopts.h"

#if DROPBEAR_SVR_PUBKEY_AUTH

Expand All @@ -72,7 +73,7 @@

static int checkpubkey(char* algo, unsigned int algolen,
unsigned char* keyblob, unsigned int keybloblen);
static int checkpubkeyperms(void);
static int checkpubkeyperms(char *filename, char *base);
static void send_msg_userauth_pk_ok(char* algo, unsigned int algolen,
unsigned char* keyblob, unsigned int keybloblen);
static int checkfileperm(char * filename);
Expand Down Expand Up @@ -196,6 +197,7 @@ static int checkpubkey(char* algo, unsigned int algolen,

FILE * authfile = NULL;
char * filename = NULL;
char * relfilename = NULL;
int ret = DROPBEAR_FAILURE;
buffer * line = NULL;
unsigned int len, pos;
Expand All @@ -212,21 +214,23 @@ static int checkpubkey(char* algo, unsigned int algolen,
goto out;
}

/* check file permissions, also whether file exists */
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
relfilename = ( svr_opts.authkeysfile
? svr_opts.authkeysfile
: ".ssh/authorized_keys" );
if (relfilename[0] == '/') { /* name is absolute */
filename = m_strdup(relfilename);
}
else {
len = strlen(ses.authstate.pw_dir) + strlen(relfilename) + 2;
filename = m_malloc(len);
snprintf(filename, len, "%s/%s", ses.authstate.pw_dir, relfilename);
}

if (checkpubkeyperms(filename, ses.authstate.pw_dir) != DROPBEAR_SUCCESS) {
TRACE(("bad authorized_keys permissions, or file doesn't exist"))
goto out;
}

/* 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);

/* open the file */
authfile = fopen(filename, "r");
if (authfile == NULL) {
Expand Down Expand Up @@ -362,52 +366,47 @@ static int checkpubkey(char* algo, unsigned int algolen,

/* 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"))
TRACE(("enter checkpubkeyperms(%s, %s)", filename, base))

if (ses.authstate.pw_dir == NULL) {
if ((base == NULL) || (base[0] != '/') ||
(filename == NULL) || (filename[0] != '/')) {
/* both filename and base must be absolute paths */
goto out;
}

if ((len = strlen(ses.authstate.pw_dir)) == 0) {
goto out;
}

/* allocate max required pathname storage,
* = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
filename = m_malloc(len + 22);
strncpy(filename, ses.authstate.pw_dir, len+1);

/* check ~ */
if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
goto out;
}
len = strlen(filename);
path = m_strdup(filename);

/* check ~/.ssh */
strncat(filename, "/.ssh", 5); /* strlen("/.ssh") == 5 */
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 */
strncat(filename, "/authorized_keys", 16);
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;
Expand Down
10 changes: 10 additions & 0 deletions svr-runopts.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ void svr_getopts(int argc, char ** argv) {
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char* keyfile = NULL;
char* authkeysfile = NULL;
char c;


Expand All @@ -137,6 +138,8 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.hostkey = NULL;
svr_opts.delay_hostkey = 0;
svr_opts.pidfile = DROPBEAR_PIDFILE;
svr_opts.authkeysfile = NULL;

#if DROPBEAR_SVR_LOCALTCPFWD
svr_opts.nolocaltcp = 0;
#endif
Expand Down Expand Up @@ -253,6 +256,9 @@ void svr_getopts(int argc, char ** argv) {
case 'u':
/* backwards compatibility with old urandom option */
break;
case 'U':
next = &authkeysfile;
break;
#if DEBUG_TRACE
case 'v':
debug_trace = 1;
Expand Down Expand Up @@ -295,6 +301,10 @@ void svr_getopts(int argc, char ** argv) {
addhostkey(keyfile);
keyfile = NULL;
}
if (authkeysfile) {
svr_opts.authkeysfile = m_strdup(authkeysfile);
authkeysfile = NULL;
}
}
}

Expand Down

0 comments on commit 0197473

Please sign in to comment.