diff --git a/src/auth.h b/src/auth.h index 0e854fbb..78c39c3e 100644 --- a/src/auth.h +++ b/src/auth.h @@ -129,6 +129,7 @@ struct AuthState { char *pw_shell; char *pw_name; char *pw_passwd; + char *org_username; /* save org userid given and set this in envvar SSH_ORGUSER */ #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT struct PubKeyOptions* pubkey_options; char *pubkey_info; diff --git a/src/default_options.h b/src/default_options.h index 5d59cccd..69339927 100644 --- a/src/default_options.h +++ b/src/default_options.h @@ -22,12 +22,15 @@ IMPORTANT: Some options will require "make clean" after changes */ /* Default hostkey paths - these can be specified on the command line. * Homedir is prepended if path begins with ~/ + * when running as root, default directory is /etc/dropbear + * when running with a nonroot user, default directory is ~/.ssh + * any other Homedir can be given during runtime with option -H ~/ */ -#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key" -#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key" -#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key" -#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key" - +#define DSS_PRIV_FILENAME "dropbear_dss_host_key" +#define RSA_PRIV_FILENAME "dropbear_rsa_host_key" +#define ECDSA_PRIV_FILENAME "dropbear_ecdsa_host_key" +#define ED25519_PRIV_FILENAME "dropbear_ed25519_host_key" + /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens * on chosen ports and keeps accepting connections. This is the default. * diff --git a/src/runopts.h b/src/runopts.h index c4061a07..481cee23 100644 --- a/src/runopts.h +++ b/src/runopts.h @@ -127,6 +127,9 @@ typedef struct svr_runopts { char * forced_command; char* interface; + char *hostdir; + char *forceuser; + #if DROPBEAR_PLUGIN /* malloced */ char *pubkey_plugin; diff --git a/src/svr-auth.c b/src/svr-auth.c index 98cc518f..334c1e42 100644 --- a/src/svr-auth.c +++ b/src/svr-auth.c @@ -110,6 +110,16 @@ void recv_msg_userauth_request() { dropbear_exit("unknown service in auth"); } + /* if we need to force logins to a specific user, this is a good place to do it. */ + if (svr_opts.forceuser) { + /* first save original user, which we can specify in envvar SSH_ORGUSER */ + ses.authstate.org_username = m_strdup(username); + /* now point to the user we want to have */ + m_free(username); + username=m_strdup(svr_opts.forceuser); + userlen=strlen(username); + } + /* check username is good before continuing. * the 'incrfail' varies depending on the auth method to * avoid giving away which users exist on the system through @@ -313,6 +323,11 @@ static int checkusername(const char *username, unsigned int userlen) { usershell = "/bin/sh"; } + /* ignore shell check if user is forced */ + if (svr_opts.forceuser) { + goto goodshell; + } + /* check the shell is valid. If /etc/shells doesn't exist, getusershell() * should return some standard shells like "/bin/sh" and "/bin/csh" (this * is platform-specific) */ diff --git a/src/svr-chansession.c b/src/svr-chansession.c index 2ca6fc14..371b494a 100644 --- a/src/svr-chansession.c +++ b/src/svr-chansession.c @@ -1035,6 +1035,10 @@ static void execchild(const void *user_data) { if (chansess->client_string) { addnewvar("SSH_CLIENT", chansess->client_string); } + + if (ses.authstate.org_username != NULL) { + addnewvar("SSH_ORGUSER", ses.authstate.org_username); + } if (chansess->original_command) { addnewvar("SSH_ORIGINAL_COMMAND", chansess->original_command); diff --git a/src/svr-kex.c b/src/svr-kex.c index 14df08a1..a2da2c85 100644 --- a/src/svr-kex.c +++ b/src/svr-kex.c @@ -146,7 +146,14 @@ static void svr_ensure_hostkey() { dropbear_assert(0); } - expand_fn = expand_homedir_path(fn); + /* if svr_opts.hostdir is set and fn does not point to absolute path or homedir */ + if (svr_opts.hostdir && fn[0] != '/' && strncmp(fn,"~/",2) != 0) { + int len = strlen(fn) + strlen(svr_opts.hostdir) + 2; + expand_fn = m_malloc(len); + snprintf(expand_fn, len, "%s/%s", svr_opts.hostdir, fn); + } else { + expand_fn = expand_homedir_path(fn); + } ret = readhostkey(expand_fn, svr_opts.hostkey, &type); if (ret == DROPBEAR_SUCCESS) { diff --git a/src/svr-runopts.c b/src/svr-runopts.c index 709dc576..4c42f062 100644 --- a/src/svr-runopts.c +++ b/src/svr-runopts.c @@ -47,6 +47,7 @@ static void printhelp(const char * progname) { "-b bannerfile Display the contents of bannerfile" " before user login\n" " (default: none)\n" + "-H directory Default hostkeys directory: %s\n" "-r keyfile Specify hostkeys (repeatable)\n" " defaults: \n" #if DROPBEAR_DSS @@ -87,6 +88,7 @@ static void printhelp(const char * progname) { "-B Allow blank password logins\n" "-t Enable two-factor authentication (both password and public key required)\n" #endif + "-U userid Force any logins to this userid\n" "-T Maximum authentication tries (default %d)\n" #if DROPBEAR_SVR_LOCALANYFWD "-j Disable local port forwarding\n" @@ -122,6 +124,7 @@ static void printhelp(const char * progname) { "-v verbose (repeat for more verbose)\n" #endif ,DROPBEAR_VERSION, progname, + svr_opts.hostdir, #if DROPBEAR_DSS DSS_PRIV_FILENAME, #endif @@ -194,6 +197,19 @@ void svr_getopts(int argc, char ** argv) { opts.allow_compress = 1; #endif + svr_opts.hostdir = m_strdup("/etc/dropbear"); /* default directory for host keys */ + svr_opts.forceuser = NULL; /* no force user if we are root */ + if ( geteuid() != 0 ) { /* we are a nonroot user */ + struct passwd *pw; + pw = getpwuid( geteuid() ); + if (pw) { + int len=strlen(pw->pw_dir)+6; /* use default directory /.ssh */ + svr_opts.hostdir=m_malloc(len); + snprintf(svr_opts.hostdir,len,"%s/.ssh",pw->pw_dir); + svr_opts.forceuser=m_strdup(pw->pw_name); + } + } + /* not yet opts.ipv4 = 1; opts.ipv6 = 1; @@ -324,6 +340,12 @@ void svr_getopts(int argc, char ** argv) { svr_opts.multiauthmethod = 1; break; #endif + case 'H': + next = &svr_opts.hostdir; + break; + case 'U': + next = &svr_opts.forceuser; + break; case 'h': printhelp(argv[0]); exit(EXIT_SUCCESS);