# HG changeset patch # User Matt Johnston # Date 1094968356 0 # Node ID 3394a7cb30cd6c0699c621c93ea64a33bc27bfb1 # Parent 5312ca05ed48ad375401c82cca2c4b4844fe0022 propagate of 08347df3bca787bd3621602fe2b466c85c9dc3e2 and 717950f4061f1123659ee87c7c168805af920ab7 from branch 'matt.dbclient.rez' to 'matt.dbclient.authpam' diff -r 5312ca05ed48 -r 3394a7cb30cd Makefile.in --- a/Makefile.in Sun Sep 12 04:56:50 2004 +0000 +++ b/Makefile.in Sun Sep 12 05:52:36 2004 +0000 @@ -23,9 +23,8 @@ 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 -r 5312ca05ed48 -r 3394a7cb30cd configure.in --- a/configure.in Sun Sep 12 04:56:50 2004 +0000 +++ b/configure.in Sun Sep 12 05:52:36 2004 +0000 @@ -205,7 +205,7 @@ # 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 diff -r 5312ca05ed48 -r 3394a7cb30cd options.h --- a/options.h Sun Sep 12 04:56:50 2004 +0000 +++ b/options.h Sun Sep 12 05:52:36 2004 +0000 @@ -112,12 +112,11 @@ /* 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 @@ *******************************************************************/ #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 @@ #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) diff -r 5312ca05ed48 -r 3394a7cb30cd svr-auth.c --- a/svr-auth.c Sun Sep 12 04:56:50 2004 +0000 +++ b/svr-auth.c Sun Sep 12 05:52:36 2004 +0000 @@ -55,8 +55,7 @@ #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 @@ } #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 -r 5312ca05ed48 -r 3394a7cb30cd svr-authpam.c --- a/svr-authpam.c Sun Sep 12 04:56:50 2004 +0000 +++ b/svr-authpam.c Sun Sep 12 05:52:36 2004 +0000 @@ -36,180 +36,174 @@ #include #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; + const struct pam_message **msg, + struct pam_response **respp, + void *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); + 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")); + } - 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); + 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; + - 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; - } + 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)); - return rc; + 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; + + struct UserDataS userData; + struct pam_conv pamConv = { + pamConvFunc, + &userData /* submitted to pamvConvFunc as appdata_ptr */ + }; - unsigned char changepw; + 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); - return; - } + /* 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); - password = buf_getstring(ses.payload, &passwordlen); + /* used to pass data to the PAM conversation function */ + userData.user = ses.authstate.printableuser; + userData.passwd = password; - /* 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)); + goto cleanup; + } - /* 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; - } + /* 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)); - /* 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; - } + 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, - "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 */); - } + /* 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 */); + } } - -#endif /* DROPBEAR_PAM_AUTH */ diff -r 5312ca05ed48 -r 3394a7cb30cd svr-authpasswd.c --- a/svr-authpasswd.c Sun Sep 12 04:56:50 2004 +0000 +++ b/svr-authpasswd.c Sun Sep 12 05:52:36 2004 +0000 @@ -80,10 +80,6 @@ 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);