From 23e98b0afb7284faac564c22a5595ebdcd983607 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 29 Oct 2018 07:23:32 +0000 Subject: [PATCH] Uppity: support SSH-2 password change request. This is the first time I've _ever_ been able to test that feature of the client userauth code personally, and pleasingly, it seems to work fine. --- ssh1login-server.c | 2 +- ssh2userauth-server.c | 24 +++++++++++++++++++----- sshserver.h | 7 ++++++- unix/uxserver.c | 31 +++++++++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/ssh1login-server.c b/ssh1login-server.c index 359dcf98..4e3f5a92 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -280,7 +280,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) if (nul) password.len = (const char *)nul - (const char *)password.ptr; - if (auth_password(s->authpolicy, s->username, password)) + if (auth_password(s->authpolicy, s->username, password, NULL)) goto auth_success; } else if (pktin->type == SSH1_CMSG_AUTH_RSA) { s->current_method = AUTHMETHOD_PUBLICKEY; diff --git a/ssh2userauth-server.c b/ssh2userauth-server.c index e642e3de..224097ad 100644 --- a/ssh2userauth-server.c +++ b/ssh2userauth-server.c @@ -163,20 +163,34 @@ static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl) goto failure; } else if (ptrlen_eq_string(s->method, "password")) { int changing; - ptrlen password; + ptrlen password, new_password, *new_password_ptr; s->this_method = AUTHMETHOD_PASSWORD; if (!(s->methods & s->this_method)) goto failure; changing = get_bool(pktin); - if (changing) - goto failure; /* FIXME: not yet supported */ - password = get_string(pktin); - if (!auth_password(s->authpolicy, s->username, password)) + if (changing) { + new_password = get_string(pktin); + new_password_ptr = &new_password; + } else { + new_password_ptr = NULL; + } + + int result = auth_password(s->authpolicy, s->username, + password, new_password_ptr); + if (result == 2) { + pktout = ssh_bpp_new_pktout( + s->ppl.bpp, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ); + put_stringz(pktout, "Please change your password"); + put_stringz(pktout, ""); /* language tag */ + pq_push(s->ppl.out_pq, pktout); + continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */ + } else if (result != 1) { goto failure; + } } else if (ptrlen_eq_string(s->method, "publickey")) { int has_signature, success; ptrlen algorithm, blob, signature; diff --git a/sshserver.h b/sshserver.h index 7081d0cd..846c40c5 100644 --- a/sshserver.h +++ b/sshserver.h @@ -38,7 +38,12 @@ struct AuthKbdIntPrompt { unsigned auth_methods(AuthPolicy *); int auth_none(AuthPolicy *, ptrlen username); -int auth_password(AuthPolicy *, ptrlen username, ptrlen password); + +int auth_password(AuthPolicy *, ptrlen username, ptrlen password, + ptrlen *opt_new_password); +/* auth_password returns 1 for 'accepted', 0 for 'rejected', and 2 for + * 'ok but now you need to change your password' */ + int auth_publickey(AuthPolicy *, ptrlen username, ptrlen public_blob); /* auth_publickey_ssh1 must return the whole public key given the modulus, * because the SSH-1 client never transmits the exponent over the wire. diff --git a/unix/uxserver.c b/unix/uxserver.c index bbb26ef1..dbf5815a 100644 --- a/unix/uxserver.c +++ b/unix/uxserver.c @@ -175,9 +175,36 @@ int auth_none(AuthPolicy *ap, ptrlen username) { return FALSE; } -int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password) +int auth_password(AuthPolicy *ap, ptrlen username, ptrlen password, + ptrlen *new_password_opt) { - return ptrlen_eq_string(password, "weasel"); + const char *PHONY_GOOD_PASSWORD = "weasel"; + const char *PHONY_BAD_PASSWORD = "ferret"; + + if (!new_password_opt) { + /* Accept login with our preconfigured good password */ + if (ptrlen_eq_string(password, PHONY_GOOD_PASSWORD)) + return 1; + /* Don't outright reject the bad password, but insist on a change */ + if (ptrlen_eq_string(password, PHONY_BAD_PASSWORD)) + return 2; + /* Reject anything else */ + return 0; + } else { + /* In a password-change request, expect the bad password as input */ + if (!ptrlen_eq_string(password, PHONY_BAD_PASSWORD)) + return 0; + /* Accept a request to change it to the good password */ + if (ptrlen_eq_string(*new_password_opt, PHONY_GOOD_PASSWORD)) + return 1; + /* Outright reject a request to change it to the same password + * as it already 'was' */ + if (ptrlen_eq_string(*new_password_opt, PHONY_BAD_PASSWORD)) + return 0; + /* Anything else, pretend the new pw wasn't good enough, and + * re-request a change */ + return 2; + } } int auth_publickey(AuthPolicy *ap, ptrlen username, ptrlen public_blob) {