Hello Matt,
> De : Matt Johnston [[email protected]]
> On Wed, Aug 20, 2014 at 01:25:21PM +0000, DELOGET, Emmanuel wrote:
> > Hello,
> >
> > Yet in my use case I have to authenticate users whose
> > login/password information is stored in a distant database.
> > Everytime I try to log in with such a user, dropear answers
> > me that the user is unknown - and that's true : the user is
> > unknown, because the whole point is to not have him/her
> > in /etc/passwd but on a distant database.
> >
> > That's where things break : dropbear seems to assume that
> > the user must be known on the system where it runs - that's
> > one of the purpose of checkusername() in svr-auth.c. If the
> > user is not found in /etc/passwd then it's not a valid user and
> > login fails.
>
> Hi Emmanuel,
>
> Is this a normal Unix type system or something more
> embedded? From what I've seen the normal approach for remote
I'm working in the embedded world.
> DB auth (LDAP etc) is to have nsswitch.conf set up to know
> about the users, then optionally a PAM module if there isn't
> a straightforward mapping to Unix password crypts. Would
> that work for your situation? The benefit there is that all
> programs know about the user using the standard user APIs.
If I had though to that before, I would have tried to do it that
way. Unfortunately, I'm a bit too late in the development cycle.
> Dropbear's PAM currently only allows username/password,
> though there's a dev branch that should allow kind of
> authentication conversation. It doesn't handle user
> remapping though since that seems out of PAM's scope. Note
> that the branch also needs some attention in terms of setting up PAM
> login sessions properly.
I tried to go another route - a dirty hack that does not please
me (and it won't please you either ; see the attached patch) : when I
don't know the username, I still accept it (I fill the authstate structure
by myself using somewhat dummy values). After a successful auth, I
refill the authstate structure with the unix mapped user (root in this
case, which is silly but sufficiently extreme to show me that everything
worked as intended). This is cheap and hacky (please, don't judge
me :))
(BTW the above patch, against an olfder version of dropbear, enables
a command line option -A to tell dropbear to favor PAM auth instead
of password auth - both can be activated with the change. If you beleive
it might be interesting I can refine this patch against the latest tree).
> Cheers,
> Matt
--- a/runopts.h
+++ b/runopts.h
@@ -77,6 +77,7 @@ typedef struct svr_runopts {
int noauthpass;
int norootpass;
+ int enablepam;
#ifdef ENABLE_SVR_REMOTETCPFWD
int noremotetcp;
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -103,6 +103,28 @@ static void send_msg_userauth_banner() {
TRACE(("leave send_msg_userauth_banner"))
}
+#ifdef ENABLE_SVR_PAM_AUTH
+static void remap_user(void)
+{
+ TRACE(("enter remap_user"));
+
+ if (ses.authstate.authdone != 1) {
+ TRACE(("enter remap_user: auth failed"));
+ return;
+ }
+
+ /* user is authenticated with PAM, yet it might be an unknown user */
+ if (strcmp(ses.authstate.pw_name, "root") != 0) {
+ TRACE(("remap_user '%s' to root", ses.authstate.pw_name));
+ free(ses.authstate.username);
+ ses.authstate.username = strdup("root");
+ fill_passwd(ses.authstate.username);
+ }
+
+ TRACE(("enter remap_user: auth succeeded"));
+}
+#endif
+
/* handle a userauth request, check validity, pass to password or pubkey
* checking, and handle success or failure */
void recv_msg_userauth_request() {
@@ -159,6 +185,7 @@ void recv_msg_userauth_request() {
#ifdef ENABLE_SVR_PASSWORD_AUTH
if (!svr_opts.noauthpass &&
+ !svr_opts.enablepam &&
!(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
/* user wants to try password auth */
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
@@ -172,12 +199,14 @@ void recv_msg_userauth_request() {
#ifdef ENABLE_SVR_PAM_AUTH
if (!svr_opts.noauthpass &&
+ svr_opts.enablepam &&
!(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
/* user wants to try password auth */
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
svr_auth_pam();
+ remap_user();
goto out;
}
}
@@ -230,6 +259,20 @@ static int checkusername(unsigned char *
ses.authstate.username = m_strdup(username);
}
+#if defined(ENABLE_SVR_PAM_AUTH)
+ if (!ses.authstate.pw_name) {
+ /* try this username anyway in PAM mode */
+ authclear();
+ ses.authstate.pw_name = strdup(username);
+ ses.authstate.username = m_strdup(username);
+ ses.authstate.pw_uid = 65535;
+ ses.authstate.pw_gid = 65535;
+ ses.authstate.pw_dir = m_strdup("/");
+ ses.authstate.pw_shell = m_strdup("");
+ ses.authstate.pw_passwd = m_strdup("");
+ }
+#endif
+
/* check that user exists */
if (!ses.authstate.pw_name) {
TRACE(("leave checkusername: user '%s' doesn't exist", username))
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -64,6 +64,9 @@ static void printhelp(const char * progn
"-s Disable password logins\n"
"-g Disable password logins for root\n"
#endif
+#ifdef ENABLE_SVR_PAM_AUTH
+ "-A enable PAM authentification\n"
+#endif
#ifdef ENABLE_SVR_LOCALTCPFWD
"-j Disable local port forwarding\n"
#endif
@@ -115,6 +118,7 @@ void svr_getopts(int argc, char ** argv)
svr_opts.norootlogin = 0;
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
+ svr_opts.enablepam = 0;
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
svr_opts.hostkey = NULL;
@@ -232,6 +236,11 @@ void svr_getopts(int argc, char ** argv)
svr_opts.norootpass = 1;
break;
#endif
+#ifdef ENABLE_SVR_PAM_AUTH
+ case 'A':
+ svr_opts.enablepam = 1;
+ break;
+#endif
case 'h':
printhelp(argv[0]);
exit(EXIT_FAILURE);
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -172,10 +172,6 @@
#define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
#endif
-#if defined(ENABLE_SVR_PASSWORD_AUTH) && defined(ENABLE_SVR_PAM_AUTH)
-#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h"
-#endif
-
#if defined(DROPBEAR_RANDOM_DEV) && defined(DROPBEAR_PRNGD_SOCKET)
#error "You can't turn on DROPBEAR_PRNGD_SOCKET and DROPBEAR_RANDOM_DEV at once"
#endif
--- a/svr-authpam.c
+++ b/svr-authpam.c
@@ -98,7 +98,7 @@ pamConvFunc(int num_msg,
case PAM_PROMPT_ECHO_OFF:
- if (!(strcmp(compare_message, "password:") == 0)) {
+ if (!strcasestr(compare_message, "password:")) {
/* We don't recognise the prompt as asking for a password,
so can't handle it. Add more above as required for
different pam modules/implementations */