diff options
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | options.h | 17 | ||||
-rw-r--r-- | svr-auth.c | 5 | ||||
-rw-r--r-- | svr-authpam.c | 328 | ||||
-rw-r--r-- | svr-authpasswd.c | 4 |
6 files changed, 175 insertions, 184 deletions
diff --git a/Makefile.in b/Makefile.in index cc221d5..0d77571 100644 --- a/Makefile.in +++ b/Makefile.in @@ -23,9 +23,8 @@ COMMONOBJS=dbutil.o buffer.o \ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ - svr-authpam.o svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\ - svr-tcpfwd.o + svr-tcpfwd.o svr-authpam.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ diff --git a/configure.in b/configure.in index d29ae89..b86fc1d 100644 --- a/configure.in +++ b/configure.in @@ -205,7 +205,7 @@ AC_ARG_ENABLE(shadow, # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h sys/dirent.h security/pam_appl.h pam/pam_appl.h]) +AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -112,12 +112,11 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ /* Authentication types to enable, at least one required. RFC Draft requires pubkey auth, and recommends password */ -//#define DROPBEAR_PASSWORD_AUTH -/* Only set PAM auth if you aren't using PASSWORD auth. Also, you'll need - * to make sure PAM libraries etc are installed */ -#define DROPBEAR_PAM_AUTH -#define DROPBEAR_PUBKEY_AUTH -#define ENABLE_SVR_PASSWORD_AUTH +/*#define ENABLE_SVR_PASSWORD_AUTH*/ +/* Only set PAM auth if you aren't using SVR_PASSWORD_AUTH. Also, you'll need + * to make sure PAM libraries etc are installed. To the client, PAM auth looks + * just like password auth. */ +#define ENABLE_SVR_PAM_AUTH #define ENABLE_SVR_PUBKEY_AUTH #define ENABLE_CLI_PASSWORD_AUTH @@ -178,7 +177,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "0.44test3" +#define DROPBEAR_VERSION "0.44rez1" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION @@ -327,6 +326,10 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #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 + /* We use dropbear_client and dropbear_server as shortcuts to avoid redundant * code, if we're just compiling as client or server */ #if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT) @@ -55,8 +55,7 @@ static void authclear() { #ifdef ENABLE_SVR_PUBKEY_AUTH ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif -#if defined(DROPBEAR_PASSWORD_AUTH) || defined(DROPBEAR_PAM_AUTH) -#ifdef ENABLE_SVR_PASSWORD_AUTH +#if defined(ENABLE_SVR_PUBKEY_AUTH) || defined(ENABLE_SVR_PAM_AUTH) if (!svr_opts.noauthpass) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } @@ -155,7 +154,7 @@ void recv_msg_userauth_request() { } #endif -#ifdef DROPBEAR_PAM_AUTH +#ifdef ENABLE_SVR_PAM_AUTH if (!svr_opts.noauthpass && !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { /* user wants to try password auth */ diff --git a/svr-authpam.c b/svr-authpam.c index cfd4327..e271020 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -36,180 +36,174 @@ #include <pam/pam_appl.h> #endif -#ifdef DROPBEAR_PAM_AUTH - struct UserDataS { - char* user; - char* passwd; + char* user; + char* passwd; }; -/* PAM conversation function */ +/* PAM conversation function - for now we only handle one message */ int pamConvFunc(int num_msg, - const struct pam_message **msg, - struct pam_response **respp, - void *appdata_ptr) { - int rc = PAM_SUCCESS; - struct pam_response* resp = NULL; - struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; - - /* tbd only handles one msg */ - - switch((*msg)->msg_style) { - case PAM_PROMPT_ECHO_OFF: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_OFF: (*msg)->msg=\"%s\"", (*msg)->msg); - - if (strcmp((*msg)->msg, "Password:") == 0) { - resp = (struct pam_response*) malloc(sizeof(struct pam_response)); - resp->resp = (char*) strdup(userDatap->passwd); - /* dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: userDatap->passwd=\"%s\"", userDatap->passwd); */ - resp->resp_retcode = 0; - (*respp) = resp; - } - else { - dropbear_log(LOG_WARNING, "pamConvFunc(): PAM_PROMPT_ECHO_OFF: unrecognized prompt, (*msg)->msg=\"%s\"", (*msg)->msg); - rc = PAM_CONV_ERR; - } - break; - case PAM_PROMPT_ECHO_ON: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: (*msg)->msg=\"%s\"", (*msg)->msg); - - if ((strcmp((*msg)->msg, "login: " ) == 0) || (strcmp((*msg)->msg, "Please enter username: " ) == 0)) { - resp = (struct pam_response*) malloc(sizeof(struct pam_response)); - resp->resp = (char*) strdup(userDatap->user); - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_PROMPT_ECHO_ON: userDatap->user=\"%s\"", userDatap->user); - resp->resp_retcode = 0; - (*respp) = resp; - } - else { - dropbear_log(LOG_WARNING, "pamConvFunc(): PAM_PROMPT_ECHO_ON: unrecognized prompt, (*msg)->msg=\"%s\"", - (*msg)->msg); - rc = PAM_CONV_ERR; - } - break; - case PAM_ERROR_MSG: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_ERROR_MSG: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("error msg: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - case PAM_TEXT_INFO: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_TEXT_INFO: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("text info: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - case PAM_RADIO_TYPE: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_RADIO_TYPE: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("radio type: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - case PAM_BINARY_PROMPT: - dropbear_log(LOG_DEBUG, "pamConvFunc(): PAM_BINARY_PROMPT: (*msg)->msg=\"%s\"", (*msg)->msg); - /* printf("binary prompt: '%s'\n", (*msg)->msg); */ - rc = PAM_CONV_ERR; - break; - default: - dropbear_log(LOG_DEBUG, "pamConvFunc(): Unknown PAM message"); - /* printf("unknown message\n"); */ - rc = PAM_CONV_ERR; - break; - } - - return rc; + const struct pam_message **msg, + struct pam_response **respp, + void *appdata_ptr) { + + int rc = PAM_SUCCESS; + struct pam_response* resp = NULL; + struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; + const char* message = (*msg)->msg; + + TRACE(("enter pamConvFunc")); + TRACE(("msg_style is %d", (*msg)->msg_style)); + if (message) { + TRACE(("message is '%s'", message)); + } else { + TRACE(("null message")); + } + + switch((*msg)->msg_style) { + + case PAM_PROMPT_ECHO_OFF: + + if (strcmp(message, "Password:") != 0) { + TRACE(("PAM_PROMPT_ECHO_OFF: unrecognized prompt")); + rc = PAM_CONV_ERR; + break; + } + + /* XXX leak */ + resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); + /* XXX leak */ + resp->resp = (char*) m_strdup(userDatap->passwd); + resp->resp_retcode = 0; + (*respp) = resp; + break; + + + case PAM_PROMPT_ECHO_ON: + + if ((strcmp(message, "login: " ) != 0) + && (strcmp(message, "login:" ) != 0) + && (strcmp(message, "Please enter username: " ) != 0)) { + TRACE(("PAM_PROMPT_ECHO_ON: unrecognized prompt")); + rc = PAM_CONV_ERR; + break; + } + + /* XXX leak */ + resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); + /* XXX leak */ + resp->resp = (char*) m_strdup(userDatap->user); + TRACE(("userDatap->user='%s'", userDatap->user)); + + resp->resp_retcode = 0; + (*respp) = resp; + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + case PAM_RADIO_TYPE: + case PAM_BINARY_PROMPT: + TRACE(("Unhandled message type")); + rc = PAM_CONV_ERR; + break; + + default: + TRACE(("Unknown message type")); + rc = PAM_CONV_ERR; + break; + } + + TRACE(("leave pamConvFunc, rc %d", rc)); + + return rc; } /* Process a password auth request, sending success or failure messages as - * appropriate */ + * appropriate. To the client it looks like it's doing normal password auth (as opposed to keyboard-interactive or something), so the pam module has to be fairly standard (ie just "what's your username, what's your password, OK"). + * + * Keyboard interactive would be a lot nicer, but since PAM is synchronous, it + * gets very messy trying to send the interactive challenges, and read the + * interactive responses, over the network. */ void svr_auth_pam() { - // PAM stuff - int rc = PAM_SUCCESS; - struct UserDataS userData; - struct pam_conv pamConv = { - pamConvFunc, - &userData /* submitted to pamvConvFunc as appdata_ptr */ - }; - pam_handle_t* pamHandlep = NULL; - unsigned char * password = NULL; - unsigned int passwordlen; - - unsigned char changepw; - - /* check if client wants to change password */ - changepw = buf_getbyte(ses.payload); - if (changepw) { - /* not implemented by this server */ - send_msg_userauth_failure(0, 1); - return; - } - - password = buf_getstring(ses.payload, &passwordlen); - - /* clear the buffer containing the password */ - buf_incrpos(ses.payload, -passwordlen - 4); - m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4); - - /* used to pass data to the PAM conversation function */ - userData.user = ses.authstate.printableuser; - TRACE(("user is %s\n", userData.user)); - userData.passwd = password; - - /* Init pam */ - if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { - dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - /* fprintf(stderr, "pam_start() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ - goto clean; - } - - /* - if ((rc = pam_set_item(pamHandlep, PAM_RHOST, webReqp->ipaddr) != PAM_SUCCESS)) { - dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - return; - } - */ - - /* just to set it to something */ - if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { - dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - goto clean; - } - - (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); - - /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ - - if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { - dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - /* fprintf(stderr, "pam_authenticate() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ - dropbear_log(LOG_WARNING, - "bad pam password attempt for '%s'", - ses.authstate.printableuser); - send_msg_userauth_failure(0, 1); - goto clean; - } - - if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { - dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); - /* fprintf(stderr, "pam_acct_mgmt() failed, rc=%d, %s\n", rc, pam_strerror(pamHandlep, rc)); */ - dropbear_log(LOG_WARNING, - "bad pam password attempt for '%s'", - ses.authstate.printableuser); - send_msg_userauth_failure(0, 1); - goto clean; - } - - /* successful authentication */ - dropbear_log(LOG_NOTICE, - "password auth succeeded for '%s'", - ses.authstate.printableuser); - send_msg_userauth_success(); - - clean: - if (password != NULL) { - m_burn(password, passwordlen); - m_free(password); - } - if (pamHandlep != NULL) { - (void) pam_end(pamHandlep, 0 /* pam_status */); - } -} -#endif /* DROPBEAR_PAM_AUTH */ + struct UserDataS userData; + struct pam_conv pamConv = { + pamConvFunc, + &userData /* submitted to pamvConvFunc as appdata_ptr */ + }; + + pam_handle_t* pamHandlep = NULL; + + unsigned char * password = NULL; + unsigned int passwordlen; + + int rc = PAM_SUCCESS; + unsigned char changepw; + + /* check if client wants to change password */ + changepw = buf_getbyte(ses.payload); + if (changepw) { + /* not implemented by this server */ + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + password = buf_getstring(ses.payload, &passwordlen); + + /* used to pass data to the PAM conversation function */ + userData.user = ses.authstate.printableuser; + userData.passwd = password; + + /* Init pam */ + if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + + /* just to set it to something */ + if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { + dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + + (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); + + /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ + + if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + /* successful authentication */ + dropbear_log(LOG_NOTICE, "pam password auth succeeded for '%s'", + ses.authstate.printableuser); + send_msg_userauth_success(); + +cleanup: + if (password != NULL) { + m_burn(password, passwordlen); + m_free(password); + } + if (pamHandlep != NULL) { + (void) pam_end(pamHandlep, 0 /* pam_status */); + } +} diff --git a/svr-authpasswd.c b/svr-authpasswd.c index 6f7c909..458deef 100644 --- a/svr-authpasswd.c +++ b/svr-authpasswd.c @@ -80,10 +80,6 @@ void svr_auth_password() { password = buf_getstring(ses.payload, &passwordlen); - /* clear the buffer containing the password */ - buf_incrpos(ses.payload, -passwordlen - 4); - m_burn(buf_getptr(ses.payload, passwordlen + 4), passwordlen + 4); - /* the first bytes of passwdcrypt are the salt */ testcrypt = crypt((char*)password, passwdcrypt); m_burn(password, passwordlen); |