From bacadca039ef6a2c74ba0ef0c95cf108eb3a0222 Mon Sep 17 00:00:00 2001 From: dinoex Date: Mon, 24 Jun 2002 22:57:13 +0000 Subject: Enable privilege separation as default, create user and home if it not exists. --- security/openssh/Makefile | 23 +- security/openssh/files/auth-pam.c | 825 ++++++++++++++++++++++++++++ security/openssh/files/auth-pam.h | 39 ++ security/openssh/files/auth2-pam.c | 333 ++++++++++++ security/openssh/files/patch-Makefile.inc | 7 +- security/openssh/files/patch-auth-pam.c | 826 ----------------------------- security/openssh/files/patch-auth-pam.h | 42 -- security/openssh/files/patch-auth1.c | 21 +- security/openssh/files/patch-auth2-pam.c | 336 ------------ security/openssh/files/patch-sshd-Makefile | 21 +- security/openssh/files/patch-sshd_config | 2 +- 11 files changed, 1244 insertions(+), 1231 deletions(-) create mode 100644 security/openssh/files/auth-pam.c create mode 100644 security/openssh/files/auth-pam.h create mode 100644 security/openssh/files/auth2-pam.c delete mode 100644 security/openssh/files/patch-auth-pam.c delete mode 100644 security/openssh/files/patch-auth-pam.h delete mode 100644 security/openssh/files/patch-auth2-pam.c diff --git a/security/openssh/Makefile b/security/openssh/Makefile index 1243e9ef86ce..ec8912aa0fb4 100644 --- a/security/openssh/Makefile +++ b/security/openssh/Makefile @@ -7,7 +7,7 @@ PORTNAME= openssh PORTVERSION= 3.3 -PORTREVISION= 1 +PORTREVISION= 2 CATEGORIES= security MASTER_SITES= ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/ \ ftp://ftp.usa.openbsd.org/pub/OpenBSD/OpenSSH/ \ @@ -29,10 +29,14 @@ MODIFY= ssh.h sshd_config sshd.sh pathnames.h FIXME= lib/Makefile scp/Makefile sftp/Makefile sftp-server/Makefile \ ssh/Makefile ssh-add/Makefile ssh-agent/Makefile \ ssh-keygen/Makefile ssh-keyscan/Makefile sshd/Makefile +ADDME+= netdb.h auth-pam.c auth-pam.h auth2-pam.c +ADDLIB+= strlcat.c strlcpy.c \ + getaddrinfo.c name6.c bindresvport.c rcmd.c getnameinfo.c PRECIOUS= ssh_config sshd_config \ ssh_host_key ssh_host_key.pub \ ssh_host_rsa_key ssh_host_rsa_key.pub \ ssh_host_dsa_key ssh_host_dsa_key.pub +PAM=no .include @@ -69,14 +73,13 @@ ETCSSH= ${PREFIX}/etc/ssh WRKSRC= ${WRKDIR}/ssh post-extract: - @${CP} ${FILESDIR}/strlcat.c ${FILESDIR}/strlcpy.c ${WRKSRC}/lib/ @${CP} ${FILESDIR}/sshd.sh ${WRKSRC}/ -.if ${OSVERSION} < 400014 - @${CP} ${FILESDIR}/getaddrinfo.c ${FILESDIR}/name6.c ${WRKSRC}/lib/ - @${CP} ${FILESDIR}/bindresvport.c ${FILESDIR}/rcmd.c ${WRKSRC}/lib/ - @${CP} ${FILESDIR}/getnameinfo.c ${WRKSRC}/lib/ - @${CP} ${FILESDIR}/netdb.h ${WRKSRC}/ -.endif +.for i in ${ADDLIB} + @${CP} ${FILESDIR}/${i} ${WRKSRC}/lib/ +.endfor +.for i in ${ADDME} + @${CP} ${FILESDIR}/${i} ${WRKSRC}/ +.endfor post-patch: .for i in ${MODIFY:S/pathnames.h//} ${MAN1:S/slogin.1//} ${MAN5} ${MAN8} @@ -101,11 +104,15 @@ post-configure: -e "s=AFS[:]L=AFS=" \ -e "s=TCP_WRAPPERS[:]L=TCP_WRAPPERS=" \ -e "s=SKEY[:]L=SKEY=" \ + -e "s=PAM[:]L=PAM=" \ ${WRKSRC}/${i}.sed >${WRKSRC}/${i} .endfor .endif pre-install: + if ! pw groupshow sshd; then pw groupadd sshd -g 22; fi + if ! pw usershow sshd; then pw useradd sshd -g sshd -u 22 \ + -h - -d ${PREFIX}/empty -s /nonexistent -c "sshd privilege separation"; fi ${MKDIR} ${PREFIX}/libdata/ssh ${MKDIR} ${PREFIX}/empty ${MKDIR} ${ETCSSH} diff --git a/security/openssh/files/auth-pam.c b/security/openssh/files/auth-pam.c new file mode 100644 index 000000000000..66fb3870eb5d --- /dev/null +++ b/security/openssh/files/auth-pam.c @@ -0,0 +1,825 @@ +/* + * Copyright (c) 2000 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef USE_PAM +#include +#include "ssh.h" +#include "xmalloc.h" +#include "log.h" +#include "servconf.h" +#include "readpass.h" +#include "canohost.h" +#include "auth.h" +#include "auth-pam.h" + +RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth-pam.c,v 1.1 2002-06-24 22:57:13 dinoex Exp $"); + +#define NEW_AUTHTOK_MSG \ + "Warning: Your password has expired, please change it now" + +#define SSHD_PAM_SERVICE "sshd" +#define PAM_STRERROR(a, b) pam_strerror((a), (b)) + +/* Callbacks */ +static int do_pam_conversation(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr); +void do_pam_cleanup_proc(void *context); +void pam_msg_cat(const char *msg); + +/* module-local variables */ +static struct pam_conv conv = { + do_pam_conversation, + NULL +}; +static pam_handle_t *pamh = NULL; +static const char *pampasswd = NULL; +static char *pam_msg = NULL; +extern ServerOptions options; + +/* states for do_pam_conversation() */ +typedef enum { INITIAL_LOGIN, OTHER } pamstates; +static pamstates pamstate = INITIAL_LOGIN; +/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */ +static int password_change_required = 0; +/* remember whether the last pam_authenticate() succeeded or not */ +static int was_authenticated = 0; + +/* Remember what has been initialised */ +static int session_opened = 0; +static int creds_set = 0; + +/* + * accessor which allows us to switch conversation structs according to + * the authentication method being used + */ +void do_pam_set_conv(struct pam_conv *conv) +{ + pam_set_item(pamh, PAM_CONV, conv); +} + +/* + * PAM conversation function. + * There are two states this can run in. + * + * INITIAL_LOGIN mode simply feeds the password from the client into + * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output + * messages with pam_msg_cat(). This is used during initial + * authentication to bypass the normal PAM password prompt. + * + * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1) + * and outputs messages to stderr. This mode is used if pam_chauthtok() + * is called to update expired passwords. + */ +static int do_pam_conversation(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + struct pam_response *reply; + int count; + char buf[1024]; + + /* PAM will free this later */ + reply = malloc(num_msg * sizeof(*reply)); + if (reply == NULL) + return PAM_CONV_ERR; + + for (count = 0; count < num_msg; count++) { + switch ((*msg)[count].msg_style) { + case PAM_PROMPT_ECHO_ON: + if (pamstate == INITIAL_LOGIN) { + free(reply); + return PAM_CONV_ERR; + } else { + fputs((*msg)[count].msg, stderr); + fgets(buf, sizeof(buf), stdin); + reply[count].resp = xstrdup(buf); + reply[count].resp_retcode = PAM_SUCCESS; + break; + } + case PAM_PROMPT_ECHO_OFF: + if (pamstate == INITIAL_LOGIN) { + if (pampasswd == NULL) { + free(reply); + return PAM_CONV_ERR; + } + reply[count].resp = xstrdup(pampasswd); + } else { + reply[count].resp = + xstrdup(read_passphrase((*msg)[count].msg, 1)); + } + reply[count].resp_retcode = PAM_SUCCESS; + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + if ((*msg)[count].msg != NULL) { + if (pamstate == INITIAL_LOGIN) + pam_msg_cat((*msg)[count].msg); + else { + fputs((*msg)[count].msg, stderr); + fputs("\n", stderr); + } + } + reply[count].resp = xstrdup(""); + reply[count].resp_retcode = PAM_SUCCESS; + break; + default: + free(reply); + return PAM_CONV_ERR; + } + } + + *resp = reply; + + return PAM_SUCCESS; +} + +/* Called at exit to cleanly shutdown PAM */ +void do_pam_cleanup_proc(void *context) +{ + int pam_retval; + + if (pamh != NULL && session_opened) { + pam_retval = pam_close_session(pamh, 0); + if (pam_retval != PAM_SUCCESS) { + log("Cannot close PAM session[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + } + + if (pamh != NULL && creds_set) { + pam_retval = pam_setcred(pamh, PAM_DELETE_CRED); + if (pam_retval != PAM_SUCCESS) { + debug("Cannot delete credentials[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + } + + if (pamh != NULL) { + pam_retval = pam_end(pamh, pam_retval); + if (pam_retval != PAM_SUCCESS) { + log("Cannot release PAM authentication[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + } +} + +/* Attempt password authentation using PAM */ +int auth_pam_password(Authctxt *authctxt, const char *password) +{ + struct passwd *pw = authctxt->pw; + int pam_retval; + + do_pam_set_conv(&conv); + + /* deny if no user. */ + if (pw == NULL) + return 0; + if (pw->pw_uid == 0 && options.permit_root_login == 2) + return 0; + if (*password == '\0' && options.permit_empty_passwd == 0) + return 0; + + pampasswd = password; + + pamstate = INITIAL_LOGIN; + pam_retval = pam_authenticate(pamh, 0); + was_authenticated = (pam_retval == PAM_SUCCESS); + if (pam_retval == PAM_SUCCESS) { + debug("PAM Password authentication accepted for user \"%.100s\"", + pw->pw_name); + return 1; + } else { + debug("PAM Password authentication for \"%.100s\" failed[%d]: %s", + pw->pw_name, pam_retval, PAM_STRERROR(pamh, pam_retval)); + return 0; + } +} + +/* Do account management using PAM */ +int do_pam_account(char *username, char *remote_user) +{ + int pam_retval; + + do_pam_set_conv(&conv); + + debug("PAM setting rhost to \"%.200s\"", + get_canonical_hostname(options.verify_reverse_mapping)); + pam_retval = pam_set_item(pamh, PAM_RHOST, + get_canonical_hostname(options.verify_reverse_mapping)); + if (pam_retval != PAM_SUCCESS) { + fatal("PAM set rhost failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + + if (remote_user != NULL) { + debug("PAM setting ruser to \"%.200s\"", remote_user); + pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user); + if (pam_retval != PAM_SUCCESS) { + fatal("PAM set ruser failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + } + + pam_retval = pam_acct_mgmt(pamh, 0); + switch (pam_retval) { + case PAM_SUCCESS: + /* This is what we want */ + break; + case PAM_NEW_AUTHTOK_REQD: + pam_msg_cat(NEW_AUTHTOK_MSG); + /* flag that password change is necessary */ + password_change_required = 1; + break; + default: + log("PAM rejected by account configuration[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + return(0); + } + + return(1); +} + +/* Do PAM-specific session initialisation */ +void do_pam_session(char *username, const char *ttyname) +{ + int pam_retval; + + do_pam_set_conv(&conv); + + if (ttyname != NULL) { + debug("PAM setting tty to \"%.200s\"", ttyname); + pam_retval = pam_set_item(pamh, PAM_TTY, ttyname); + if (pam_retval != PAM_SUCCESS) { + fatal("PAM set tty failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + } + + debug("do_pam_session: euid %u, uid %u", geteuid(), getuid()); + pam_retval = pam_open_session(pamh, 0); + if (pam_retval != PAM_SUCCESS) { + fatal("PAM session setup failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + + session_opened = 1; +} + +/* Set PAM credentials */ +void do_pam_setcred(void) +{ + int pam_retval; + + do_pam_set_conv(&conv); + + debug("PAM establishing creds"); + pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED); + if (pam_retval != PAM_SUCCESS) { + if (was_authenticated) + fatal("PAM setcred failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + else + debug("PAM setcred failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } else + creds_set = 1; +} + +/* accessor function for file scope static variable */ +int pam_password_change_required(void) +{ + return password_change_required; +} + +/* + * Have user change authentication token if pam_acct_mgmt() indicated + * it was expired. This needs to be called after an interactive + * session is established and the user's pty is connected to + * stdin/stout/stderr. + */ +void do_pam_chauthtok(void) +{ + int pam_retval; + + do_pam_set_conv(&conv); + + if (password_change_required) { + pamstate = OTHER; + /* + * XXX: should we really loop forever? + */ + do { + pam_retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + if (pam_retval != PAM_SUCCESS) { + log("PAM pam_chauthtok failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + } while (pam_retval != PAM_SUCCESS); + } +} + +/* Cleanly shutdown PAM */ +void finish_pam(void) +{ + do_pam_cleanup_proc(NULL); + fatal_remove_cleanup(&do_pam_cleanup_proc, NULL); +} + +/* Start PAM authentication for specified account */ +void start_pam(struct passwd *pw) +{ + int pam_retval; + + debug("Starting up PAM with username \"%.200s\"", pw->pw_name); + + pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv, &pamh); + + if (pam_retval != PAM_SUCCESS) { + fatal("PAM initialisation failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } + +#ifdef PAM_TTY_KLUDGE + /* + * Some PAM modules (e.g. pam_time) require a TTY to operate, + * and will fail in various stupid ways if they don't get one. + * sshd doesn't set the tty until too late in the auth process and may + * not even need one (for tty-less connections) + * Kludge: Set a fake PAM_TTY + */ + pam_retval = pam_set_item(pamh, PAM_TTY, "ssh"); + if (pam_retval != PAM_SUCCESS) { + fatal("PAM set tty failed[%d]: %.200s", + pam_retval, PAM_STRERROR(pamh, pam_retval)); + } +#endif /* PAM_TTY_KLUDGE */ + + fatal_add_cleanup(&do_pam_cleanup_proc, NULL); +} + +/* Return list of PAM enviornment strings */ +char **fetch_pam_environment(void) +{ +#ifdef HAVE_PAM_GETENVLIST + return(pam_getenvlist(pamh)); +#else /* HAVE_PAM_GETENVLIST */ + return(NULL); +#endif /* HAVE_PAM_GETENVLIST */ +} + +/* Print any messages that have been generated during authentication */ +/* or account checking to stderr */ +void print_pam_messages(void) +{ + if (pam_msg != NULL) + fputs(pam_msg, stderr); +} + +/* Append a message to the PAM message buffer */ +void pam_msg_cat(const char *msg) +{ + char *p; + size_t new_msg_len; + size_t pam_msg_len; + + new_msg_len = strlen(msg); + + if (pam_msg) { + pam_msg_len = strlen(pam_msg); + pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2); + p = pam_msg + pam_msg_len; + } else { + pam_msg = p = xmalloc(new_msg_len + 2); + } + + memcpy(p, msg, new_msg_len); + p[new_msg_len] = '\n'; + p[new_msg_len + 1] = '\0'; +} + +struct inverted_pam_userdata { + /* + * Pipe for telling whether we are doing conversation or sending + * authentication results. + */ + int statefd[2]; + int challengefd[2]; + int responsefd[2]; + + /* Whether we have sent off our challenge */ + int state; +}; + +#define STATE_CONV 1 +#define STATE_AUTH_OK 2 +#define STATE_AUTH_FAIL 3 + +int +ssh_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, + void *userdata) { + int i; + FILE *reader; + char buf[1024]; + struct pam_response *reply = NULL; + char state_to_write = STATE_CONV; /* One char to write */ + struct inverted_pam_userdata *ud = userdata; + char *response = NULL; + + /* The stdio functions are more convenient for the read half */ + reader = fdopen(ud->responsefd[0], "rb"); + if (reader == NULL) + goto protocol_failure; + + reply = malloc(num_msg * sizeof(struct pam_response)); + if (reply == NULL) + return PAM_CONV_ERR; + + if (write(ud->statefd[1], &state_to_write, 1) != 1) + goto protocol_failure; + + /* + * Re-package our data and send it off to our better half (the actual SSH + * process) + */ + if (write(ud->challengefd[1], buf, + sprintf(buf, "%d\n", num_msg)) == -1) + goto protocol_failure; + for (i = 0; i < num_msg; i++) { + if (write(ud->challengefd[1], buf, + sprintf(buf, "%d\n", msg[i]->msg_style)) == -1) + goto protocol_failure; + if (write(ud->challengefd[1], buf, + sprintf(buf, "%d\n", strlen(msg[i]->msg))) == -1) + goto protocol_failure; + if (write(ud->challengefd[1], msg[i]->msg, + strlen(msg[i]->msg)) == -1) + goto protocol_failure; + } + /* + * Read back responses. These may not be as nice as we want, as the SSH + * protocol isn't exactly a perfect fit with PAM. + */ + + for (i = 0; i < num_msg; i++) { + char buf[1024]; + char *endptr; + size_t len; /* Length of the response */ + + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_ON: + if (fgets(buf, sizeof(buf), reader) == NULL) + goto protocol_failure; + len = (size_t)strtoul(buf, &endptr, 10); + /* The length is supposed to stand on a line by itself */ + if (endptr == NULL || *endptr != '\n') + goto protocol_failure; + response = malloc(len+1); + if (response == NULL) + goto protocol_failure; + if (fread(response, len, 1, reader) != 1) + goto protocol_failure; + response[len] = '\0'; + reply[i].resp = response; + response = NULL; + break; + default: + reply[i].resp = NULL; + break; + } + } + *resp = reply; + return PAM_SUCCESS; + protocol_failure: + free(reply); + return PAM_CONV_ERR; +} + +void +ipam_free_cookie(struct inverted_pam_cookie *cookie) { + struct inverted_pam_userdata *ud; + int i; + + if (cookie == NULL) + return; + ud = cookie->userdata; + cookie->userdata = NULL; + /* Free userdata if allocated */ + if (ud) { + /* Close any opened file descriptors */ + if (ud->statefd[0] != -1) + close(ud->statefd[0]); + if (ud->statefd[1] != -1) + close(ud->statefd[1]); + if (ud->challengefd[0] != -1) + close(ud->challengefd[0]); + if (ud->challengefd[1] != -1) + close(ud->challengefd[1]); + if (ud->responsefd[0] != -1) + close(ud->responsefd[0]); + if (ud->responsefd[1] != -1) + close(ud->responsefd[1]); + free(ud); + ud = NULL; + } + /* Now free the normal cookie */ + if (cookie->pid != 0 && cookie->pid != -1) { + int status; + + /* XXX Use different signal? */ + kill(cookie->pid, SIGKILL); + waitpid(cookie->pid, &status, 0); + } + for (i = 0; i < cookie->num_msg; i++) { + if (cookie->resp && cookie->resp[i]) { + free(cookie->resp[i]->resp); + free(cookie->resp[i]); + } + if (cookie->msg && cookie->msg[i]) { + free((void *)cookie->msg[i]->msg); + free(cookie->msg[i]); + } + } + free(cookie->msg); + free(cookie->resp); + free(cookie); +} + +/* + * Do first half of PAM authentication - this comes to the point where + * you get a message to send to the user. + */ +struct inverted_pam_cookie * +ipam_start_auth(const char *service, const char *username) { + struct inverted_pam_cookie *cookie; + struct inverted_pam_userdata *ud; + static struct pam_conv conv = { + ssh_conv, + NULL + }; + const char *rhost; + + cookie = malloc(sizeof(*cookie)); + if (cookie == NULL) + return NULL; + cookie->state = 0; + /* Set up the cookie so ipam_freecookie can be used on it */ + cookie->num_msg = 0; + cookie->msg = NULL; + cookie->resp = NULL; + cookie->pid = -1; + + ud = calloc(sizeof(*ud), 1); + if (ud == NULL) { + free(cookie); + return NULL; + } + cookie->userdata = ud; + ud->statefd[0] = ud->statefd[1] = -1; + ud->challengefd[0] = ud->challengefd[1] = -1; + ud->responsefd[0] = ud->responsefd[1] = -1; + + if (pipe(ud->statefd) != 0) { + ud->statefd[0] = ud->statefd[1] = -1; + ipam_free_cookie(cookie); + return NULL; + } + if (pipe(ud->challengefd) != 0) { + ud->challengefd[0] = ud->challengefd[1] = -1; + ipam_free_cookie(cookie); + return NULL; + } + if (pipe(ud->responsefd) != 0) { + ud->responsefd[0] = ud->responsefd[1] = -1; + ipam_free_cookie(cookie); + return NULL; + } + rhost = get_canonical_hostname(options.verify_reverse_mapping); + cookie->pid = fork(); + if (cookie->pid == -1) { + ipam_free_cookie(cookie); + return NULL; + } else if (cookie->pid != 0) { + int num_msgs; /* Number of messages from PAM */ + char *endptr; + char buf[1024]; + FILE *reader; + size_t num_msg; + int i; + char state; /* Which state did the connection just enter? */ + + /* We are the parent - wait for a call to the communications + function to turn up, or the challenge to be finished */ + if (read(ud->statefd[0], &state, 1) != 1) { + ipam_free_cookie(cookie); + return NULL; + } + cookie->state = state; + switch (state) { + case STATE_CONV: + /* We are running the conversation function */ + /* The stdio functions are more convenient for read */ + reader = fdopen(ud->challengefd[0], "r"); + if (reader == NULL) { + ipam_free_cookie(cookie); + return NULL; + } + if (fgets(buf, 4, reader) == NULL) { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + num_msg = (size_t)strtoul(buf, &endptr, 10); + /* The length is supposed to stand on a line by itself */ + if (endptr == NULL || *endptr != '\n') { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + cookie->msg = + malloc(sizeof(struct pam_message *) * num_msg); + cookie->resp = + malloc(sizeof(struct pam_response *) * num_msg); + if (cookie->msg == NULL || cookie->resp == NULL) { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + for (i = 0; i < num_msg; i++) { + cookie->msg[i] = + malloc(sizeof(struct pam_message)); + cookie->resp[i] = + malloc(sizeof(struct pam_response)); + if (cookie->msg[i] == NULL || + cookie->resp[i] == NULL) { + for (;;) { + free(cookie->msg[i]); + free(cookie->resp[i]); + if (i == 0) + break; + i--; + } + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + cookie->msg[i]->msg = NULL; + cookie->resp[i]->resp = NULL; + cookie->resp[i]->resp_retcode = 0; + } + /* Set up so the above will be freed on failure */ + cookie->num_msg = num_msg; + /* + * We have a an allocated response and message for + * each of the entries in the PAM structure - transfer + * the data sent to the conversation function over. + */ + for (i = 0; i < num_msg; i++) { + size_t len; + + if (fgets(buf, sizeof(buf), reader) == NULL) { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + cookie->msg[i]->msg_style = + (size_t)strtoul(buf, &endptr, 10); + if (endptr == NULL || *endptr != '\n') { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + if (fgets(buf, sizeof(buf), reader) == NULL) { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + len = (size_t)strtoul(buf, &endptr, 10); + if (endptr == NULL || *endptr != '\n') { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + cookie->msg[i]->msg = malloc(len + 1); + if (cookie->msg[i]->msg == NULL) { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + if (fread((char *)cookie->msg[i]->msg, len, 1, reader) != + 1) { + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + *(char *)&(cookie->msg[i]->msg[len]) = '\0'; + } + break; + case STATE_AUTH_OK: + case STATE_AUTH_FAIL: + break; + default: + /* Internal failure, somehow */ + fclose(reader); + ipam_free_cookie(cookie); + return NULL; + } + return cookie; + } else { + /* We are the child */ + pam_handle_t *pamh=NULL; + int retval; + char state; + + conv.appdata_ptr = ud; + retval = pam_start(service, username, &conv, &pamh); + fprintf(stderr, "pam_start returned %d\n", retval); + if (retval == PAM_SUCCESS) + retval = pam_set_item(pamh, PAM_RHOST, rhost); + /* Is user really user? */ + if (retval == PAM_SUCCESS) + retval = pam_authenticate(pamh, 0); + /* permitted access? */ + if (retval == PAM_SUCCESS) + retval = pam_acct_mgmt(pamh, 0); + /* This is where we have been authorized or not. */ + + /* Be conservative - flag as auth failure if we can't close */ + /* + * XXX This is based on example code from Linux-PAM - + * but can it really be correct to pam_end if + * pam_start failed? + */ + if (pam_end(pamh, retval) != PAM_SUCCESS) + retval = PAM_AUTH_ERR; + + /* Message to parent */ + state = retval == PAM_SUCCESS ? STATE_AUTH_OK : STATE_AUTH_FAIL; + if (write(ud->statefd[1], &state, 1) != 1) { + _exit(1); + } + /* FDs will be closed, so further communication will stop */ + _exit(0); + } +} + +/* + * Do second half of PAM authentication - cookie should now be filled + * in with the response to the challenge. + */ + +int +ipam_complete_auth(struct inverted_pam_cookie *cookie) { + int i; + char buf[1024]; + struct inverted_pam_userdata *ud = cookie->userdata; + char state; + + /* Send over our responses */ + for (i = 0; i < cookie->num_msg; i++) { + if (cookie->msg[i]->msg_style != PAM_PROMPT_ECHO_ON && + cookie->msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) + continue; + if (write(ud->responsefd[1], buf, + sprintf(buf, "%d\n", strlen(cookie->resp[i]->resp))) == -1) { + ipam_free_cookie(cookie); + return 0; + } + if (write(ud->responsefd[1], cookie->resp[i]->resp, + strlen(cookie->resp[i]->resp)) == -1) { + ipam_free_cookie(cookie); + return 0; + } + } + /* Find out what state we are changing to */ + if (read(ud->statefd[0], &state, 1) != 1) { + ipam_free_cookie(cookie); + return 0; + } + + return state == STATE_AUTH_OK ? 1 : 0; +} + +#endif /* USE_PAM */ diff --git a/security/openssh/files/auth-pam.h b/security/openssh/files/auth-pam.h new file mode 100644 index 000000000000..887ccfcafef6 --- /dev/null +++ b/security/openssh/files/auth-pam.h @@ -0,0 +1,39 @@ +/* + * OpenSSH PAM authentication support. + * + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth-pam.h,v 1.1 2002-06-24 22:57:13 dinoex Exp $ + */ +#ifndef AUTH_PAM_H +#define AUTH_PAM_H +#include "includes.h" +#ifdef USE_PAM + +#include "auth.h" +#include /* For struct passwd */ + +void start_pam(struct passwd *pw); +void finish_pam(void); +int auth_pam_password(Authctxt *authctxt, const char *password); +char **fetch_pam_environment(void); +int do_pam_account(char *username, char *remote_user); +void do_pam_session(char *username, const char *ttyname); +void do_pam_setcred(void); +void print_pam_messages(void); +int pam_password_change_required(void); +void do_pam_chauthtok(void); + +struct inverted_pam_cookie { + int state; /* Which state have we reached? */ + pid_t pid; /* PID of child process */ + + /* Only valid in state STATE_CONV */ + int num_msg; /* Number of messages */ + struct pam_message **msg; /* Message structures */ + struct pam_response **resp; /* Response structures */ + struct inverted_pam_userdata *userdata; +}; +void ipam_free_cookie(struct inverted_pam_cookie *cookie); +struct inverted_pam_cookie *ipam_start_auth(const char *, const char *); + +#endif /* USE_PAM */ +#endif /* AUTH_PAM_H */ diff --git a/security/openssh/files/auth2-pam.c b/security/openssh/files/auth2-pam.c new file mode 100644 index 000000000000..38c53ef93aa3 --- /dev/null +++ b/security/openssh/files/auth2-pam.c @@ -0,0 +1,333 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by ThinkSec AS and + * NAI Labs, the Security Research Division of Network Associates, Inc. + * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the + * DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth2-pam.c,v 1.1 2002-06-24 22:57:13 dinoex Exp $ + */ + +#ifdef USE_PAM +#include "includes.h" +RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/auth2-pam.c,v 1.1 2002-06-24 22:57:13 dinoex Exp $"); + +#include + +#include "auth.h" +#include "log.h" +#include "xmalloc.h" + +struct pam_ctxt { + char *pam_user; + pid_t pam_pid; + int pam_sock; + int pam_done; +}; + +static void pam_free_ctx(void *); + +/* + * Send message to parent or child. + */ +static int +pam_send(struct pam_ctxt *ctxt, char *fmt, ...) +{ + va_list ap; + char *mstr; + size_t len; + int r; + + va_start(ap, fmt); + len = vasprintf(&mstr, fmt, ap); + va_end(ap); + if (mstr == NULL) + exit(1); + if (ctxt->pam_pid != 0) + debug2("to child: %s", mstr); + r = send(ctxt->pam_sock, mstr, len + 1, MSG_EOR); + free(mstr); + return (r); +} + +/* + * Peek at first byte of next message. + */ +static int +pam_peek(struct pam_ctxt *ctxt) +{ + char ch; + + if (recv(ctxt->pam_sock, &ch, 1, MSG_PEEK) < 1) + return (-1); + return (ch); +} + +/* + * Receive a message from parent or child. + */ +static char * +pam_receive(struct pam_ctxt *ctxt) +{ + char *buf; + size_t len; + ssize_t rlen; + + len = 64; + buf = NULL; + do { + len *= 2; + buf = xrealloc(buf, len); + rlen = recv(ctxt->pam_sock, buf, len, MSG_PEEK); + if (rlen < 1) { + xfree(buf); + return (NULL); + } + } while (rlen == len); + if (recv(ctxt->pam_sock, buf, len, 0) != rlen) { + xfree(buf); + return (NULL); + } + if (ctxt->pam_pid != 0) + debug2("from child: %s", buf); + return (buf); +} + +/* + * Conversation function for child process. + */ +static int +pam_child_conv(int n, + const struct pam_message **msg, + struct pam_response **resp, + void *data) +{ + struct pam_ctxt *ctxt; + int i; + + ctxt = data; + if (n <= 0 || n > PAM_MAX_NUM_MSG) + return (PAM_CONV_ERR); + if ((*resp = calloc(n, sizeof **resp)) == NULL) + return (PAM_BUF_ERR); + for (i = 0; i < n; ++i) { + resp[i]->resp_retcode = 0; + resp[i]->resp = NULL; + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + pam_send(ctxt, "p%s", msg[i]->msg); + resp[i]->resp = pam_receive(ctxt); + break; + case PAM_PROMPT_ECHO_ON: + pam_send(ctxt, "P%s", msg[i]->msg); + resp[i]->resp = pam_receive(ctxt); + break; + case PAM_ERROR_MSG: + /*pam_send(ctxt, "e%s", msg[i]->msg);*/ + break; + case PAM_TEXT_INFO: + /*pam_send(ctxt, "i%s", msg[i]->msg);*/ + break; + default: + goto fail; + } + } + return (PAM_SUCCESS); + fail: + while (i) + free(resp[--i]); + free(*resp); + *resp = NULL; + return (PAM_CONV_ERR); +} + +/* + * Child process. + */ +static void * +pam_child(struct pam_ctxt *ctxt) +{ + struct pam_conv pam_conv = { pam_child_conv, ctxt }; + pam_handle_t *pamh; + int pam_err; + + pam_err = pam_start("sshd", ctxt->pam_user, &pam_conv, &pamh); + if (pam_err != PAM_SUCCESS) + goto auth_fail; + pam_err = pam_authenticate(pamh, 0); + if (pam_err != PAM_SUCCESS) + goto auth_fail; + pam_send(ctxt, "=OK"); + pam_end(pamh, pam_err); + exit(0); + auth_fail: + pam_send(ctxt, "!%s", pam_strerror(pamh, pam_err)); + pam_end(pamh, pam_err); + exit(0); +} + +static void * +pam_init_ctx(Authctxt *authctxt) +{ + struct pam_ctxt *ctxt; + int socks[2]; + int i; + + ctxt = xmalloc(sizeof *ctxt); + ctxt->pam_user = xstrdup(authctxt->user); + ctxt->pam_done = 0; + if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, socks) == -1) { + error("%s: failed create sockets: %s", + __func__, strerror(errno)); + xfree(ctxt); + return (NULL); + } + if ((ctxt->pam_pid = fork()) == -1) { + error("%s: failed to fork auth-pam child: %s", + __func__, strerror(errno)); + close(socks[0]); + close(socks[1]); + xfree(ctxt); + return (NULL); + } + if (ctxt->pam_pid == 0) { + /* close everything except our end of the pipe */ + ctxt->pam_sock = socks[1]; + for (i = 0; i < getdtablesize(); ++i) + if (i != ctxt->pam_sock) + close(i); + pam_child(ctxt); + /* not reached */ + exit(1); + } + ctxt->pam_sock = socks[0]; + close(socks[1]); + return (ctxt); +} + +static int +pam_query(void *ctx, char **name, char **info, + u_int *num, char ***prompts, u_int **echo_on) +{ + struct pam_ctxt *ctxt = ctx; + char *msg; + + if ((msg = pam_receive(ctxt)) == NULL) + return (-1); + *name = xstrdup(""); + *info = xstrdup(""); + *prompts = xmalloc(sizeof(char *)); + *echo_on = xmalloc(sizeof(u_int)); + switch (*msg) { + case 'P': + **echo_on = 1; + case 'p': + *num = 1; + **prompts = xstrdup(msg + 1); + **echo_on = (*msg == 'P'); + break; + case '=': + *num = 0; + **echo_on = 0; + ctxt->pam_done = 1; + break; + case '!': + error("%s", msg + 1); + default: + *num = 0; + **echo_on = 0; + xfree(msg); + ctxt->pam_done = -1; + return (-1); + } + xfree(msg); + return (0); +} + +static int +pam_respond(void *ctx, u_int num, char **resp) +{ + struct pam_ctxt *ctxt = ctx; + char *msg; + + debug2(__func__); + switch (ctxt->pam_done) { + case 1: + return (0); + case 0: + break; + default: + return (-1); + } + if (num != 1) { + error("expected one response, got %u", num); + return (-1); + } + pam_send(ctxt, "%s", *resp); + switch (pam_peek(ctxt)) { + case 'P': + case 'p': + return (1); + case '=': + msg = pam_receive(ctxt); + xfree(msg); + ctxt->pam_done = 1; + return (0); + default: + msg = pam_receive(ctxt); + if (*msg == '!') + error("%s", msg + 1); + xfree(msg); + ctxt->pam_done = -1; + return (-1); + } +} + +static void +pam_free_ctx(void *ctxtp) +{ + struct pam_ctxt *ctxt = ctxtp; + int status; + + close(ctxt->pam_sock); + kill(ctxt->pam_pid, SIGHUP); + waitpid(ctxt->pam_pid, &status, 0); + xfree(ctxt->pam_user); + xfree(ctxt); +} + +KbdintDevice pam_device = { + "pam", + pam_init_ctx, + pam_query, + pam_respond, + pam_free_ctx +}; + +#endif /* USE_PAM */ diff --git a/security/openssh/files/patch-Makefile.inc b/security/openssh/files/patch-Makefile.inc index 1a2997645cdd..ad173cc96722 100644 --- a/security/openssh/files/patch-Makefile.inc +++ b/security/openssh/files/patch-Makefile.inc @@ -1,6 +1,6 @@ --- Makefile.inc.orig Wed Mar 6 01:23:27 2002 -+++ Makefile.inc Mon Jun 24 20:28:00 2002 -@@ -17,10 +17,19 @@ ++++ Makefile.inc Mon Jun 24 23:43:18 2002 +@@ -17,10 +17,16 @@ .include @@ -20,7 +20,4 @@ +.if !defined(IGNORE_LIBSSH) LDADD+= -L${.CURDIR}/../lib -lssh DPADD+= ${.CURDIR}/../lib/libssh.a -+.if (${SKEY} == "yes") -+LDADD+= -lopie -+.endif .endif diff --git a/security/openssh/files/patch-auth-pam.c b/security/openssh/files/patch-auth-pam.c deleted file mode 100644 index 9f9bea9c4eaa..000000000000 --- a/security/openssh/files/patch-auth-pam.c +++ /dev/null @@ -1,826 +0,0 @@ ---- auth-pam.c.orig Mon Jun 24 06:55:51 2002 -+++ auth-pam.c Thu Mar 21 13:55:21 2002 -@@ -0,0 +1,823 @@ -+/* -+ * Copyright (c) 2000 Damien Miller. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "includes.h" -+ -+#ifdef USE_PAM -+#include -+#include "ssh.h" -+#include "xmalloc.h" -+#include "log.h" -+#include "servconf.h" -+#include "readpass.h" -+#include "canohost.h" -+ -+RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/patch-auth-pam.c,v 1.1 2002-06-24 21:13:06 dinoex Exp $"); -+ -+#define NEW_AUTHTOK_MSG \ -+ "Warning: Your password has expired, please change it now" -+ -+#define SSHD_PAM_SERVICE "sshd" -+#define PAM_STRERROR(a, b) pam_strerror((a), (b)) -+ -+/* Callbacks */ -+static int do_pam_conversation(int num_msg, const struct pam_message **msg, -+ struct pam_response **resp, void *appdata_ptr); -+void do_pam_cleanup_proc(void *context); -+void pam_msg_cat(const char *msg); -+ -+/* module-local variables */ -+static struct pam_conv conv = { -+ do_pam_conversation, -+ NULL -+}; -+static pam_handle_t *pamh = NULL; -+static const char *pampasswd = NULL; -+static char *pam_msg = NULL; -+extern ServerOptions options; -+ -+/* states for do_pam_conversation() */ -+typedef enum { INITIAL_LOGIN, OTHER } pamstates; -+static pamstates pamstate = INITIAL_LOGIN; -+/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */ -+static int password_change_required = 0; -+/* remember whether the last pam_authenticate() succeeded or not */ -+static int was_authenticated = 0; -+ -+/* Remember what has been initialised */ -+static int session_opened = 0; -+static int creds_set = 0; -+ -+/* -+ * accessor which allows us to switch conversation structs according to -+ * the authentication method being used -+ */ -+void do_pam_set_conv(struct pam_conv *conv) -+{ -+ pam_set_item(pamh, PAM_CONV, conv); -+} -+ -+/* -+ * PAM conversation function. -+ * There are two states this can run in. -+ * -+ * INITIAL_LOGIN mode simply feeds the password from the client into -+ * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output -+ * messages with pam_msg_cat(). This is used during initial -+ * authentication to bypass the normal PAM password prompt. -+ * -+ * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1) -+ * and outputs messages to stderr. This mode is used if pam_chauthtok() -+ * is called to update expired passwords. -+ */ -+static int do_pam_conversation(int num_msg, const struct pam_message **msg, -+ struct pam_response **resp, void *appdata_ptr) -+{ -+ struct pam_response *reply; -+ int count; -+ char buf[1024]; -+ -+ /* PAM will free this later */ -+ reply = malloc(num_msg * sizeof(*reply)); -+ if (reply == NULL) -+ return PAM_CONV_ERR; -+ -+ for (count = 0; count < num_msg; count++) { -+ switch ((*msg)[count].msg_style) { -+ case PAM_PROMPT_ECHO_ON: -+ if (pamstate == INITIAL_LOGIN) { -+ free(reply); -+ return PAM_CONV_ERR; -+ } else { -+ fputs((*msg)[count].msg, stderr); -+ fgets(buf, sizeof(buf), stdin); -+ reply[count].resp = xstrdup(buf); -+ reply[count].resp_retcode = PAM_SUCCESS; -+ break; -+ } -+ case PAM_PROMPT_ECHO_OFF: -+ if (pamstate == INITIAL_LOGIN) { -+ if (pampasswd == NULL) { -+ free(reply); -+ return PAM_CONV_ERR; -+ } -+ reply[count].resp = xstrdup(pampasswd); -+ } else { -+ reply[count].resp = -+ xstrdup(read_passphrase((*msg)[count].msg, 1)); -+ } -+ reply[count].resp_retcode = PAM_SUCCESS; -+ break; -+ case PAM_ERROR_MSG: -+ case PAM_TEXT_INFO: -+ if ((*msg)[count].msg != NULL) { -+ if (pamstate == INITIAL_LOGIN) -+ pam_msg_cat((*msg)[count].msg); -+ else { -+ fputs((*msg)[count].msg, stderr); -+ fputs("\n", stderr); -+ } -+ } -+ reply[count].resp = xstrdup(""); -+ reply[count].resp_retcode = PAM_SUCCESS; -+ break; -+ default: -+ free(reply); -+ return PAM_CONV_ERR; -+ } -+ } -+ -+ *resp = reply; -+ -+ return PAM_SUCCESS; -+} -+ -+/* Called at exit to cleanly shutdown PAM */ -+void do_pam_cleanup_proc(void *context) -+{ -+ int pam_retval; -+ -+ if (pamh != NULL && session_opened) { -+ pam_retval = pam_close_session(pamh, 0); -+ if (pam_retval != PAM_SUCCESS) { -+ log("Cannot close PAM session[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ } -+ -+ if (pamh != NULL && creds_set) { -+ pam_retval = pam_setcred(pamh, PAM_DELETE_CRED); -+ if (pam_retval != PAM_SUCCESS) { -+ debug("Cannot delete credentials[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ } -+ -+ if (pamh != NULL) { -+ pam_retval = pam_end(pamh, pam_retval); -+ if (pam_retval != PAM_SUCCESS) { -+ log("Cannot release PAM authentication[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ } -+} -+ -+/* Attempt password authentation using PAM */ -+int auth_pam_password(Authctxt *authctxt, const char *password) -+{ -+ struct passwd *pw = authctxt->pw; -+ int pam_retval; -+ -+ do_pam_set_conv(&conv); -+ -+ /* deny if no user. */ -+ if (pw == NULL) -+ return 0; -+ if (pw->pw_uid == 0 && options.permit_root_login == 2) -+ return 0; -+ if (*password == '\0' && options.permit_empty_passwd == 0) -+ return 0; -+ -+ pampasswd = password; -+ -+ pamstate = INITIAL_LOGIN; -+ pam_retval = pam_authenticate(pamh, 0); -+ was_authenticated = (pam_retval == PAM_SUCCESS); -+ if (pam_retval == PAM_SUCCESS) { -+ debug("PAM Password authentication accepted for user \"%.100s\"", -+ pw->pw_name); -+ return 1; -+ } else { -+ debug("PAM Password authentication for \"%.100s\" failed[%d]: %s", -+ pw->pw_name, pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ return 0; -+ } -+} -+ -+/* Do account management using PAM */ -+int do_pam_account(char *username, char *remote_user) -+{ -+ int pam_retval; -+ -+ do_pam_set_conv(&conv); -+ -+ debug("PAM setting rhost to \"%.200s\"", -+ get_canonical_hostname(options.verify_reverse_mapping)); -+ pam_retval = pam_set_item(pamh, PAM_RHOST, -+ get_canonical_hostname(options.verify_reverse_mapping)); -+ if (pam_retval != PAM_SUCCESS) { -+ fatal("PAM set rhost failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ -+ if (remote_user != NULL) { -+ debug("PAM setting ruser to \"%.200s\"", remote_user); -+ pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user); -+ if (pam_retval != PAM_SUCCESS) { -+ fatal("PAM set ruser failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ } -+ -+ pam_retval = pam_acct_mgmt(pamh, 0); -+ switch (pam_retval) { -+ case PAM_SUCCESS: -+ /* This is what we want */ -+ break; -+ case PAM_NEW_AUTHTOK_REQD: -+ pam_msg_cat(NEW_AUTHTOK_MSG); -+ /* flag that password change is necessary */ -+ password_change_required = 1; -+ break; -+ default: -+ log("PAM rejected by account configuration[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ return(0); -+ } -+ -+ return(1); -+} -+ -+/* Do PAM-specific session initialisation */ -+void do_pam_session(char *username, const char *ttyname) -+{ -+ int pam_retval; -+ -+ do_pam_set_conv(&conv); -+ -+ if (ttyname != NULL) { -+ debug("PAM setting tty to \"%.200s\"", ttyname); -+ pam_retval = pam_set_item(pamh, PAM_TTY, ttyname); -+ if (pam_retval != PAM_SUCCESS) { -+ fatal("PAM set tty failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ } -+ -+ debug("do_pam_session: euid %u, uid %u", geteuid(), getuid()); -+ pam_retval = pam_open_session(pamh, 0); -+ if (pam_retval != PAM_SUCCESS) { -+ fatal("PAM session setup failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ -+ session_opened = 1; -+} -+ -+/* Set PAM credentials */ -+void do_pam_setcred(void) -+{ -+ int pam_retval; -+ -+ do_pam_set_conv(&conv); -+ -+ debug("PAM establishing creds"); -+ pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED); -+ if (pam_retval != PAM_SUCCESS) { -+ if (was_authenticated) -+ fatal("PAM setcred failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ else -+ debug("PAM setcred failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } else -+ creds_set = 1; -+} -+ -+/* accessor function for file scope static variable */ -+int pam_password_change_required(void) -+{ -+ return password_change_required; -+} -+ -+/* -+ * Have user change authentication token if pam_acct_mgmt() indicated -+ * it was expired. This needs to be called after an interactive -+ * session is established and the user's pty is connected to -+ * stdin/stout/stderr. -+ */ -+void do_pam_chauthtok(void) -+{ -+ int pam_retval; -+ -+ do_pam_set_conv(&conv); -+ -+ if (password_change_required) { -+ pamstate = OTHER; -+ /* -+ * XXX: should we really loop forever? -+ */ -+ do { -+ pam_retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); -+ if (pam_retval != PAM_SUCCESS) { -+ log("PAM pam_chauthtok failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ } while (pam_retval != PAM_SUCCESS); -+ } -+} -+ -+/* Cleanly shutdown PAM */ -+void finish_pam(void) -+{ -+ do_pam_cleanup_proc(NULL); -+ fatal_remove_cleanup(&do_pam_cleanup_proc, NULL); -+} -+ -+/* Start PAM authentication for specified account */ -+void start_pam(struct passwd *pw) -+{ -+ int pam_retval; -+ -+ debug("Starting up PAM with username \"%.200s\"", pw->pw_name); -+ -+ pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv, &pamh); -+ -+ if (pam_retval != PAM_SUCCESS) { -+ fatal("PAM initialisation failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+ -+#ifdef PAM_TTY_KLUDGE -+ /* -+ * Some PAM modules (e.g. pam_time) require a TTY to operate, -+ * and will fail in various stupid ways if they don't get one. -+ * sshd doesn't set the tty until too late in the auth process and may -+ * not even need one (for tty-less connections) -+ * Kludge: Set a fake PAM_TTY -+ */ -+ pam_retval = pam_set_item(pamh, PAM_TTY, "ssh"); -+ if (pam_retval != PAM_SUCCESS) { -+ fatal("PAM set tty failed[%d]: %.200s", -+ pam_retval, PAM_STRERROR(pamh, pam_retval)); -+ } -+#endif /* PAM_TTY_KLUDGE */ -+ -+ fatal_add_cleanup(&do_pam_cleanup_proc, NULL); -+} -+ -+/* Return list of PAM enviornment strings */ -+char **fetch_pam_environment(void) -+{ -+#ifdef HAVE_PAM_GETENVLIST -+ return(pam_getenvlist(pamh)); -+#else /* HAVE_PAM_GETENVLIST */ -+ return(NULL); -+#endif /* HAVE_PAM_GETENVLIST */ -+} -+ -+/* Print any messages that have been generated during authentication */ -+/* or account checking to stderr */ -+void print_pam_messages(void) -+{ -+ if (pam_msg != NULL) -+ fputs(pam_msg, stderr); -+} -+ -+/* Append a message to the PAM message buffer */ -+void pam_msg_cat(const char *msg) -+{ -+ char *p; -+ size_t new_msg_len; -+ size_t pam_msg_len; -+ -+ new_msg_len = strlen(msg); -+ -+ if (pam_msg) { -+ pam_msg_len = strlen(pam_msg); -+ pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2); -+ p = pam_msg + pam_msg_len; -+ } else { -+ pam_msg = p = xmalloc(new_msg_len + 2); -+ } -+ -+ memcpy(p, msg, new_msg_len); -+ p[new_msg_len] = '\n'; -+ p[new_msg_len + 1] = '\0'; -+} -+ -+struct inverted_pam_userdata { -+ /* -+ * Pipe for telling whether we are doing conversation or sending -+ * authentication results. -+ */ -+ int statefd[2]; -+ int challengefd[2]; -+ int responsefd[2]; -+ -+ /* Whether we have sent off our challenge */ -+ int state; -+}; -+ -+#define STATE_CONV 1 -+#define STATE_AUTH_OK 2 -+#define STATE_AUTH_FAIL 3 -+ -+int -+ssh_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, -+ void *userdata) { -+ int i; -+ FILE *reader; -+ char buf[1024]; -+ struct pam_response *reply = NULL; -+ char state_to_write = STATE_CONV; /* One char to write */ -+ struct inverted_pam_userdata *ud = userdata; -+ char *response = NULL; -+ -+ /* The stdio functions are more convenient for the read half */ -+ reader = fdopen(ud->responsefd[0], "rb"); -+ if (reader == NULL) -+ goto protocol_failure; -+ -+ reply = malloc(num_msg * sizeof(struct pam_response)); -+ if (reply == NULL) -+ return PAM_CONV_ERR; -+ -+ if (write(ud->statefd[1], &state_to_write, 1) != 1) -+ goto protocol_failure; -+ -+ /* -+ * Re-package our data and send it off to our better half (the actual SSH -+ * process) -+ */ -+ if (write(ud->challengefd[1], buf, -+ sprintf(buf, "%d\n", num_msg)) == -1) -+ goto protocol_failure; -+ for (i = 0; i < num_msg; i++) { -+ if (write(ud->challengefd[1], buf, -+ sprintf(buf, "%d\n", msg[i]->msg_style)) == -1) -+ goto protocol_failure; -+ if (write(ud->challengefd[1], buf, -+ sprintf(buf, "%d\n", strlen(msg[i]->msg))) == -1) -+ goto protocol_failure; -+ if (write(ud->challengefd[1], msg[i]->msg, -+ strlen(msg[i]->msg)) == -1) -+ goto protocol_failure; -+ } -+ /* -+ * Read back responses. These may not be as nice as we want, as the SSH -+ * protocol isn't exactly a perfect fit with PAM. -+ */ -+ -+ for (i = 0; i < num_msg; i++) { -+ char buf[1024]; -+ char *endptr; -+ size_t len; /* Length of the response */ -+ -+ switch (msg[i]->msg_style) { -+ case PAM_PROMPT_ECHO_OFF: -+ case PAM_PROMPT_ECHO_ON: -+ if (fgets(buf, sizeof(buf), reader) == NULL) -+ goto protocol_failure; -+ len = (size_t)strtoul(buf, &endptr, 10); -+ /* The length is supposed to stand on a line by itself */ -+ if (endptr == NULL || *endptr != '\n') -+ goto protocol_failure; -+ response = malloc(len+1); -+ if (response == NULL) -+ goto protocol_failure; -+ if (fread(response, len, 1, reader) != 1) -+ goto protocol_failure; -+ response[len] = '\0'; -+ reply[i].resp = response; -+ response = NULL; -+ break; -+ default: -+ reply[i].resp = NULL; -+ break; -+ } -+ } -+ *resp = reply; -+ return PAM_SUCCESS; -+ protocol_failure: -+ free(reply); -+ return PAM_CONV_ERR; -+} -+ -+void -+ipam_free_cookie(struct inverted_pam_cookie *cookie) { -+ struct inverted_pam_userdata *ud; -+ int i; -+ -+ if (cookie == NULL) -+ return; -+ ud = cookie->userdata; -+ cookie->userdata = NULL; -+ /* Free userdata if allocated */ -+ if (ud) { -+ /* Close any opened file descriptors */ -+ if (ud->statefd[0] != -1) -+ close(ud->statefd[0]); -+ if (ud->statefd[1] != -1) -+ close(ud->statefd[1]); -+ if (ud->challengefd[0] != -1) -+ close(ud->challengefd[0]); -+ if (ud->challengefd[1] != -1) -+ close(ud->challengefd[1]); -+ if (ud->responsefd[0] != -1) -+ close(ud->responsefd[0]); -+ if (ud->responsefd[1] != -1) -+ close(ud->responsefd[1]); -+ free(ud); -+ ud = NULL; -+ } -+ /* Now free the normal cookie */ -+ if (cookie->pid != 0 && cookie->pid != -1) { -+ int status; -+ -+ /* XXX Use different signal? */ -+ kill(cookie->pid, SIGKILL); -+ waitpid(cookie->pid, &status, 0); -+ } -+ for (i = 0; i < cookie->num_msg; i++) { -+ if (cookie->resp && cookie->resp[i]) { -+ free(cookie->resp[i]->resp); -+ free(cookie->resp[i]); -+ } -+ if (cookie->msg && cookie->msg[i]) { -+ free((void *)cookie->msg[i]->msg); -+ free(cookie->msg[i]); -+ } -+ } -+ free(cookie->msg); -+ free(cookie->resp); -+ free(cookie); -+} -+ -+/* -+ * Do first half of PAM authentication - this comes to the point where -+ * you get a message to send to the user. -+ */ -+struct inverted_pam_cookie * -+ipam_start_auth(const char *service, const char *username) { -+ struct inverted_pam_cookie *cookie; -+ struct inverted_pam_userdata *ud; -+ static struct pam_conv conv = { -+ ssh_conv, -+ NULL -+ }; -+ const char *rhost; -+ -+ cookie = malloc(sizeof(*cookie)); -+ if (cookie == NULL) -+ return NULL; -+ cookie->state = 0; -+ /* Set up the cookie so ipam_freecookie can be used on it */ -+ cookie->num_msg = 0; -+ cookie->msg = NULL; -+ cookie->resp = NULL; -+ cookie->pid = -1; -+ -+ ud = calloc(sizeof(*ud), 1); -+ if (ud == NULL) { -+ free(cookie); -+ return NULL; -+ } -+ cookie->userdata = ud; -+ ud->statefd[0] = ud->statefd[1] = -1; -+ ud->challengefd[0] = ud->challengefd[1] = -1; -+ ud->responsefd[0] = ud->responsefd[1] = -1; -+ -+ if (pipe(ud->statefd) != 0) { -+ ud->statefd[0] = ud->statefd[1] = -1; -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ if (pipe(ud->challengefd) != 0) { -+ ud->challengefd[0] = ud->challengefd[1] = -1; -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ if (pipe(ud->responsefd) != 0) { -+ ud->responsefd[0] = ud->responsefd[1] = -1; -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ rhost = get_canonical_hostname(options.verify_reverse_mapping); -+ cookie->pid = fork(); -+ if (cookie->pid == -1) { -+ ipam_free_cookie(cookie); -+ return NULL; -+ } else if (cookie->pid != 0) { -+ int num_msgs; /* Number of messages from PAM */ -+ char *endptr; -+ char buf[1024]; -+ FILE *reader; -+ size_t num_msg; -+ int i; -+ char state; /* Which state did the connection just enter? */ -+ -+ /* We are the parent - wait for a call to the communications -+ function to turn up, or the challenge to be finished */ -+ if (read(ud->statefd[0], &state, 1) != 1) { -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ cookie->state = state; -+ switch (state) { -+ case STATE_CONV: -+ /* We are running the conversation function */ -+ /* The stdio functions are more convenient for read */ -+ reader = fdopen(ud->challengefd[0], "r"); -+ if (reader == NULL) { -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ if (fgets(buf, 4, reader) == NULL) { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ num_msg = (size_t)strtoul(buf, &endptr, 10); -+ /* The length is supposed to stand on a line by itself */ -+ if (endptr == NULL || *endptr != '\n') { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ cookie->msg = -+ malloc(sizeof(struct pam_message *) * num_msg); -+ cookie->resp = -+ malloc(sizeof(struct pam_response *) * num_msg); -+ if (cookie->msg == NULL || cookie->resp == NULL) { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ for (i = 0; i < num_msg; i++) { -+ cookie->msg[i] = -+ malloc(sizeof(struct pam_message)); -+ cookie->resp[i] = -+ malloc(sizeof(struct pam_response)); -+ if (cookie->msg[i] == NULL || -+ cookie->resp[i] == NULL) { -+ for (;;) { -+ free(cookie->msg[i]); -+ free(cookie->resp[i]); -+ if (i == 0) -+ break; -+ i--; -+ } -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ cookie->msg[i]->msg = NULL; -+ cookie->resp[i]->resp = NULL; -+ cookie->resp[i]->resp_retcode = 0; -+ } -+ /* Set up so the above will be freed on failure */ -+ cookie->num_msg = num_msg; -+ /* -+ * We have a an allocated response and message for -+ * each of the entries in the PAM structure - transfer -+ * the data sent to the conversation function over. -+ */ -+ for (i = 0; i < num_msg; i++) { -+ size_t len; -+ -+ if (fgets(buf, sizeof(buf), reader) == NULL) { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ cookie->msg[i]->msg_style = -+ (size_t)strtoul(buf, &endptr, 10); -+ if (endptr == NULL || *endptr != '\n') { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ if (fgets(buf, sizeof(buf), reader) == NULL) { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ len = (size_t)strtoul(buf, &endptr, 10); -+ if (endptr == NULL || *endptr != '\n') { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ cookie->msg[i]->msg = malloc(len + 1); -+ if (cookie->msg[i]->msg == NULL) { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ if (fread((char *)cookie->msg[i]->msg, len, 1, reader) != -+ 1) { -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ *(char *)&(cookie->msg[i]->msg[len]) = '\0'; -+ } -+ break; -+ case STATE_AUTH_OK: -+ case STATE_AUTH_FAIL: -+ break; -+ default: -+ /* Internal failure, somehow */ -+ fclose(reader); -+ ipam_free_cookie(cookie); -+ return NULL; -+ } -+ return cookie; -+ } else { -+ /* We are the child */ -+ pam_handle_t *pamh=NULL; -+ int retval; -+ char state; -+ -+ conv.appdata_ptr = ud; -+ retval = pam_start(service, username, &conv, &pamh); -+ fprintf(stderr, "pam_start returned %d\n", retval); -+ if (retval == PAM_SUCCESS) -+ retval = pam_set_item(pamh, PAM_RHOST, rhost); -+ /* Is user really user? */ -+ if (retval == PAM_SUCCESS) -+ retval = pam_authenticate(pamh, 0); -+ /* permitted access? */ -+ if (retval == PAM_SUCCESS) -+ retval = pam_acct_mgmt(pamh, 0); -+ /* This is where we have been authorized or not. */ -+ -+ /* Be conservative - flag as auth failure if we can't close */ -+ /* -+ * XXX This is based on example code from Linux-PAM - -+ * but can it really be correct to pam_end if -+ * pam_start failed? -+ */ -+ if (pam_end(pamh, retval) != PAM_SUCCESS) -+ retval = PAM_AUTH_ERR; -+ -+ /* Message to parent */ -+ state = retval == PAM_SUCCESS ? STATE_AUTH_OK : STATE_AUTH_FAIL; -+ if (write(ud->statefd[1], &state, 1) != 1) { -+ _exit(1); -+ } -+ /* FDs will be closed, so further communication will stop */ -+ _exit(0); -+ } -+} -+ -+/* -+ * Do second half of PAM authentication - cookie should now be filled -+ * in with the response to the challenge. -+ */ -+ -+int -+ipam_complete_auth(struct inverted_pam_cookie *cookie) { -+ int i; -+ char buf[1024]; -+ struct inverted_pam_userdata *ud = cookie->userdata; -+ char state; -+ -+ /* Send over our responses */ -+ for (i = 0; i < cookie->num_msg; i++) { -+ if (cookie->msg[i]->msg_style != PAM_PROMPT_ECHO_ON && -+ cookie->msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) -+ continue; -+ if (write(ud->responsefd[1], buf, -+ sprintf(buf, "%d\n", strlen(cookie->resp[i]->resp))) == -1) { -+ ipam_free_cookie(cookie); -+ return 0; -+ } -+ if (write(ud->responsefd[1], cookie->resp[i]->resp, -+ strlen(cookie->resp[i]->resp)) == -1) { -+ ipam_free_cookie(cookie); -+ return 0; -+ } -+ } -+ /* Find out what state we are changing to */ -+ if (read(ud->statefd[0], &state, 1) != 1) { -+ ipam_free_cookie(cookie); -+ return 0; -+ } -+ -+ return state == STATE_AUTH_OK ? 1 : 0; -+} -+ -+#endif /* USE_PAM */ diff --git a/security/openssh/files/patch-auth-pam.h b/security/openssh/files/patch-auth-pam.h deleted file mode 100644 index 0d25afb860fa..000000000000 --- a/security/openssh/files/patch-auth-pam.h +++ /dev/null @@ -1,42 +0,0 @@ ---- auth-pam.h.orig Mon Jun 24 06:55:53 2002 -+++ auth-pam.h Sat May 5 03:12:45 2001 -@@ -0,0 +1,39 @@ -+/* -+ * OpenSSH PAM authentication support. -+ * -+ * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/patch-auth-pam.h,v 1.1 2002-06-24 21:13:06 dinoex Exp $ -+ */ -+#ifndef AUTH_PAM_H -+#define AUTH_PAM_H -+#include "includes.h" -+#ifdef USE_PAM -+ -+#include "auth.h" -+#include /* For struct passwd */ -+ -+void start_pam(struct passwd *pw); -+void finish_pam(void); -+int auth_pam_password(Authctxt *authctxt, const char *password); -+char **fetch_pam_environment(void); -+int do_pam_account(char *username, char *remote_user); -+void do_pam_session(char *username, const char *ttyname); -+void do_pam_setcred(void); -+void print_pam_messages(void); -+int pam_password_change_required(void); -+void do_pam_chauthtok(void); -+ -+struct inverted_pam_cookie { -+ int state; /* Which state have we reached? */ -+ pid_t pid; /* PID of child process */ -+ -+ /* Only valid in state STATE_CONV */ -+ int num_msg; /* Number of messages */ -+ struct pam_message **msg; /* Message structures */ -+ struct pam_response **resp; /* Response structures */ -+ struct inverted_pam_userdata *userdata; -+}; -+void ipam_free_cookie(struct inverted_pam_cookie *cookie); -+struct inverted_pam_cookie *ipam_start_auth(const char *, const char *); -+ -+#endif /* USE_PAM */ -+#endif /* AUTH_PAM_H */ diff --git a/security/openssh/files/patch-auth1.c b/security/openssh/files/patch-auth1.c index 1db999b0ad57..aa1b085f3beb 100644 --- a/security/openssh/files/patch-auth1.c +++ b/security/openssh/files/patch-auth1.c @@ -1,6 +1,6 @@ --- auth1.c.orig Wed Jun 19 02:27:55 2002 -+++ auth1.c Mon Jun 24 21:18:53 2002 -@@ -27,6 +27,14 @@ ++++ auth1.c Mon Jun 24 23:54:35 2002 +@@ -27,6 +27,15 @@ #include "uidswap.h" #include "monitor_wrap.h" @@ -8,6 +8,7 @@ +#include +#endif /* HAVE_LOGIN_CAP */ +#ifdef USE_PAM ++#include "canohost.h" +#include "auth-pam.h" +#include +#endif /* USE_PAM */ @@ -15,7 +16,7 @@ /* import */ extern ServerOptions options; -@@ -75,6 +83,16 @@ +@@ -75,6 +84,16 @@ u_int ulen; int type = 0; struct passwd *pw = authctxt->pw; @@ -32,7 +33,7 @@ debug("Attempting authentication for %s%.100s.", authctxt->valid ? "" : "illegal user ", authctxt->user); -@@ -84,7 +102,11 @@ +@@ -84,7 +103,11 @@ #if defined(KRB4) || defined(KRB5) (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif @@ -45,7 +46,7 @@ auth_log(authctxt, 1, "without authentication", ""); return; } -@@ -94,6 +116,8 @@ +@@ -94,6 +117,8 @@ packet_send(); packet_write_wait(); @@ -54,7 +55,7 @@ for (;;) { /* default to fail */ authenticated = 0; -@@ -243,12 +267,48 @@ +@@ -243,12 +268,48 @@ packet_check_eom(); /* Try authentication with the password. */ @@ -104,7 +105,7 @@ case SSH_CMSG_AUTH_TIS: debug("rcvd SSH_CMSG_AUTH_TIS"); if (options.challenge_response_authentication == 1) { -@@ -275,6 +335,12 @@ +@@ -275,6 +336,12 @@ xfree(response); } break; @@ -117,7 +118,7 @@ default: /* -@@ -284,6 +350,34 @@ +@@ -284,6 +351,34 @@ log("Unknown message during authentication: type %d", type); break; } @@ -152,7 +153,7 @@ #ifdef BSD_AUTH if (authctxt->as) { auth_close(authctxt->as); -@@ -299,9 +393,24 @@ +@@ -299,9 +394,24 @@ !auth_root_allowed(get_authname(type))) authenticated = 0; @@ -178,7 +179,7 @@ if (authenticated) return; -@@ -354,6 +463,11 @@ +@@ -354,6 +464,11 @@ authctxt->valid = 1; else debug("do_authentication: illegal user %s", user); diff --git a/security/openssh/files/patch-auth2-pam.c b/security/openssh/files/patch-auth2-pam.c deleted file mode 100644 index 73605e236db2..000000000000 --- a/security/openssh/files/patch-auth2-pam.c +++ /dev/null @@ -1,336 +0,0 @@ ---- auth2-pam.c.orig Mon Jun 24 06:54:42 2002 -+++ auth2-pam.c Mon Apr 22 08:25:13 2002 -@@ -0,0 +1,333 @@ -+/*- -+ * Copyright (c) 2002 Networks Associates Technology, Inc. -+ * All rights reserved. -+ * -+ * This software was developed for the FreeBSD Project by ThinkSec AS and -+ * NAI Labs, the Security Research Division of Network Associates, Inc. -+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the -+ * DARPA CHATS research program. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote -+ * products derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -+ * SUCH DAMAGE. -+ * -+ * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/patch-auth2-pam.c,v 1.1 2002-06-24 21:13:06 dinoex Exp $ -+ */ -+ -+#ifdef USE_PAM -+#include "includes.h" -+RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/patch-auth2-pam.c,v 1.1 2002-06-24 21:13:06 dinoex Exp $"); -+ -+#include -+ -+#include "auth.h" -+#include "log.h" -+#include "xmalloc.h" -+ -+struct pam_ctxt { -+ char *pam_user; -+ pid_t pam_pid; -+ int pam_sock; -+ int pam_done; -+}; -+ -+static void pam_free_ctx(void *); -+ -+/* -+ * Send message to parent or child. -+ */ -+static int -+pam_send(struct pam_ctxt *ctxt, char *fmt, ...) -+{ -+ va_list ap; -+ char *mstr; -+ size_t len; -+ int r; -+ -+ va_start(ap, fmt); -+ len = vasprintf(&mstr, fmt, ap); -+ va_end(ap); -+ if (mstr == NULL) -+ exit(1); -+ if (ctxt->pam_pid != 0) -+ debug2("to child: %s", mstr); -+ r = send(ctxt->pam_sock, mstr, len + 1, MSG_EOR); -+ free(mstr); -+ return (r); -+} -+ -+/* -+ * Peek at first byte of next message. -+ */ -+static int -+pam_peek(struct pam_ctxt *ctxt) -+{ -+ char ch; -+ -+ if (recv(ctxt->pam_sock, &ch, 1, MSG_PEEK) < 1) -+ return (-1); -+ return (ch); -+} -+ -+/* -+ * Receive a message from parent or child. -+ */ -+static char * -+pam_receive(struct pam_ctxt *ctxt) -+{ -+ char *buf; -+ size_t len; -+ ssize_t rlen; -+ -+ len = 64; -+ buf = NULL; -+ do { -+ len *= 2; -+ buf = xrealloc(buf, len); -+ rlen = recv(ctxt->pam_sock, buf, len, MSG_PEEK); -+ if (rlen < 1) { -+ xfree(buf); -+ return (NULL); -+ } -+ } while (rlen == len); -+ if (recv(ctxt->pam_sock, buf, len, 0) != rlen) { -+ xfree(buf); -+ return (NULL); -+ } -+ if (ctxt->pam_pid != 0) -+ debug2("from child: %s", buf); -+ return (buf); -+} -+ -+/* -+ * Conversation function for child process. -+ */ -+static int -+pam_child_conv(int n, -+ const struct pam_message **msg, -+ struct pam_response **resp, -+ void *data) -+{ -+ struct pam_ctxt *ctxt; -+ int i; -+ -+ ctxt = data; -+ if (n <= 0 || n > PAM_MAX_NUM_MSG) -+ return (PAM_CONV_ERR); -+ if ((*resp = calloc(n, sizeof **resp)) == NULL) -+ return (PAM_BUF_ERR); -+ for (i = 0; i < n; ++i) { -+ resp[i]->resp_retcode = 0; -+ resp[i]->resp = NULL; -+ switch (msg[i]->msg_style) { -+ case PAM_PROMPT_ECHO_OFF: -+ pam_send(ctxt, "p%s", msg[i]->msg); -+ resp[i]->resp = pam_receive(ctxt); -+ break; -+ case PAM_PROMPT_ECHO_ON: -+ pam_send(ctxt, "P%s", msg[i]->msg); -+ resp[i]->resp = pam_receive(ctxt); -+ break; -+ case PAM_ERROR_MSG: -+ /*pam_send(ctxt, "e%s", msg[i]->msg);*/ -+ break; -+ case PAM_TEXT_INFO: -+ /*pam_send(ctxt, "i%s", msg[i]->msg);*/ -+ break; -+ default: -+ goto fail; -+ } -+ } -+ return (PAM_SUCCESS); -+ fail: -+ while (i) -+ free(resp[--i]); -+ free(*resp); -+ *resp = NULL; -+ return (PAM_CONV_ERR); -+} -+ -+/* -+ * Child process. -+ */ -+static void * -+pam_child(struct pam_ctxt *ctxt) -+{ -+ struct pam_conv pam_conv = { pam_child_conv, ctxt }; -+ pam_handle_t *pamh; -+ int pam_err; -+ -+ pam_err = pam_start("sshd", ctxt->pam_user, &pam_conv, &pamh); -+ if (pam_err != PAM_SUCCESS) -+ goto auth_fail; -+ pam_err = pam_authenticate(pamh, 0); -+ if (pam_err != PAM_SUCCESS) -+ goto auth_fail; -+ pam_send(ctxt, "=OK"); -+ pam_end(pamh, pam_err); -+ exit(0); -+ auth_fail: -+ pam_send(ctxt, "!%s", pam_strerror(pamh, pam_err)); -+ pam_end(pamh, pam_err); -+ exit(0); -+} -+ -+static void * -+pam_init_ctx(Authctxt *authctxt) -+{ -+ struct pam_ctxt *ctxt; -+ int socks[2]; -+ int i; -+ -+ ctxt = xmalloc(sizeof *ctxt); -+ ctxt->pam_user = xstrdup(authctxt->user); -+ ctxt->pam_done = 0; -+ if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, socks) == -1) { -+ error("%s: failed create sockets: %s", -+ __func__, strerror(errno)); -+ xfree(ctxt); -+ return (NULL); -+ } -+ if ((ctxt->pam_pid = fork()) == -1) { -+ error("%s: failed to fork auth-pam child: %s", -+ __func__, strerror(errno)); -+ close(socks[0]); -+ close(socks[1]); -+ xfree(ctxt); -+ return (NULL); -+ } -+ if (ctxt->pam_pid == 0) { -+ /* close everything except our end of the pipe */ -+ ctxt->pam_sock = socks[1]; -+ for (i = 0; i < getdtablesize(); ++i) -+ if (i != ctxt->pam_sock) -+ close(i); -+ pam_child(ctxt); -+ /* not reached */ -+ exit(1); -+ } -+ ctxt->pam_sock = socks[0]; -+ close(socks[1]); -+ return (ctxt); -+} -+ -+static int -+pam_query(void *ctx, char **name, char **info, -+ u_int *num, char ***prompts, u_int **echo_on) -+{ -+ struct pam_ctxt *ctxt = ctx; -+ char *msg; -+ -+ if ((msg = pam_receive(ctxt)) == NULL) -+ return (-1); -+ *name = xstrdup(""); -+ *info = xstrdup(""); -+ *prompts = xmalloc(sizeof(char *)); -+ *echo_on = xmalloc(sizeof(u_int)); -+ switch (*msg) { -+ case 'P': -+ **echo_on = 1; -+ case 'p': -+ *num = 1; -+ **prompts = xstrdup(msg + 1); -+ **echo_on = (*msg == 'P'); -+ break; -+ case '=': -+ *num = 0; -+ **echo_on = 0; -+ ctxt->pam_done = 1; -+ break; -+ case '!': -+ error("%s", msg + 1); -+ default: -+ *num = 0; -+ **echo_on = 0; -+ xfree(msg); -+ ctxt->pam_done = -1; -+ return (-1); -+ } -+ xfree(msg); -+ return (0); -+} -+ -+static int -+pam_respond(void *ctx, u_int num, char **resp) -+{ -+ struct pam_ctxt *ctxt = ctx; -+ char *msg; -+ -+ debug2(__func__); -+ switch (ctxt->pam_done) { -+ case 1: -+ return (0); -+ case 0: -+ break; -+ default: -+ return (-1); -+ } -+ if (num != 1) { -+ error("expected one response, got %u", num); -+ return (-1); -+ } -+ pam_send(ctxt, "%s", *resp); -+ switch (pam_peek(ctxt)) { -+ case 'P': -+ case 'p': -+ return (1); -+ case '=': -+ msg = pam_receive(ctxt); -+ xfree(msg); -+ ctxt->pam_done = 1; -+ return (0); -+ default: -+ msg = pam_receive(ctxt); -+ if (*msg == '!') -+ error("%s", msg + 1); -+ xfree(msg); -+ ctxt->pam_done = -1; -+ return (-1); -+ } -+} -+ -+static void -+pam_free_ctx(void *ctxtp) -+{ -+ struct pam_ctxt *ctxt = ctxtp; -+ int status; -+ -+ close(ctxt->pam_sock); -+ kill(ctxt->pam_pid, SIGHUP); -+ waitpid(ctxt->pam_pid, &status, 0); -+ xfree(ctxt->pam_user); -+ xfree(ctxt); -+} -+ -+KbdintDevice pam_device = { -+ "pam", -+ pam_init_ctx, -+ pam_query, -+ pam_respond, -+ pam_free_ctx -+}; -+ -+#endif /* USE_PAM */ diff --git a/security/openssh/files/patch-sshd-Makefile b/security/openssh/files/patch-sshd-Makefile index de200f14054a..aaccee5203f8 100644 --- a/security/openssh/files/patch-sshd-Makefile +++ b/security/openssh/files/patch-sshd-Makefile @@ -1,5 +1,5 @@ ---- sshd/Makefile.orig Fri Jun 21 23:06:22 2002 -+++ sshd/Makefile Fri Jun 21 23:06:56 2002 +--- sshd/Makefile.orig Tue Jun 25 00:07:14 2002 ++++ sshd/Makefile Tue Jun 25 00:17:30 2002 @@ -5,8 +5,9 @@ PROG= sshd BINOWN= root @@ -24,7 +24,7 @@ SRCS+= auth-krb5.c LDADD+= -lkrb5 -lkafs -lasn1 -lcom_err DPADD+= ${LIBKRB5} ${LIBKAFS} ${LIBASN1} ${LIBCOM_ERR} -@@ -33,15 +35,15 @@ +@@ -33,15 +35,22 @@ LDADD+= -lkafs DPADD+= ${LIBKAFS} .endif # AFS @@ -36,6 +36,13 @@ DPADD+= ${LIBKRB} .endif # KERBEROS ++.if (${PAM:L} == "yes") ++CFLAGS+= -DUSE_PAM -Dmm_auth_pam_password=auth_pam_password ++SRCS+= auth-pam.c auth2-pam.c ++LDADD+= -lpam ++DPADD+= ${PAM} ++.endif ++ .include -LDADD+= -lcrypto -lutil -lz -ldes @@ -43,3 +50,11 @@ DPADD+= ${LIBCRYPTO} ${LIBUTIL} ${LIBZ} ${LIBDES} .if (${TCP_WRAPPERS:L} == "yes") +@@ -52,6 +61,6 @@ + + .if (${SKEY:L} == "yes") + CFLAGS+= -DSKEY +-LDADD+= -lskey ++LDADD+= -lopie + DPADD+= ${SKEY} + .endif diff --git a/security/openssh/files/patch-sshd_config b/security/openssh/files/patch-sshd_config index d650766c0293..c96c15a99851 100644 --- a/security/openssh/files/patch-sshd_config +++ b/security/openssh/files/patch-sshd_config @@ -6,7 +6,7 @@ #UseLogin no +UseLogin yes #UsePrivilegeSeparation yes -+UsePrivilegeSeparation no ++UsePrivilegeSeparation yes #Compression yes #MaxStartups 10 -- cgit