- Security Fix in PAM handling
Obtained from: des
This commit is contained in:
parent
3429858e20
commit
91f368c344
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/head/; revision=89406
10 changed files with 1016 additions and 160 deletions
|
@ -7,7 +7,7 @@
|
|||
|
||||
PORTNAME= openssh
|
||||
PORTVERSION= 3.6.1p2
|
||||
PORTREVISION= 4
|
||||
PORTREVISION= 5
|
||||
CATEGORIES= security ipv6
|
||||
MASTER_SITES= ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/ \
|
||||
ftp://carroll.cac.psu.edu/pub/OpenBSD/OpenSSH/portable/
|
||||
|
@ -16,8 +16,6 @@ PKGNAMESUFFIX?= -portable
|
|||
MAINTAINER= dinoex@FreeBSD.org
|
||||
COMMENT= The portable version of OpenBSD's OpenSSH
|
||||
|
||||
FORBIDDEN= Security Problem with PAM
|
||||
|
||||
MAN1= sftp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 scp.1 ssh.1
|
||||
MLINKS= ssh.1 slogin.1
|
||||
MAN5= ssh_config.5 sshd_config.5
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
* 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
|
||||
|
@ -33,35 +30,96 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$FreeBSD: /tmp/pcvs/ports/security/hpn-ssh/files/Attic/auth2-pam-freebsd.c,v 1.4 2002-10-17 04:40:20 dinoex Exp $");
|
||||
RCSID("$FreeBSD: /tmp/pcvs/ports/security/hpn-ssh/files/Attic/auth2-pam-freebsd.c,v 1.5 2003-09-26 02:42:39 dinoex Exp $");
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
#include "auth.h"
|
||||
#include "auth-pam.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "canohost.h"
|
||||
#include "log.h"
|
||||
#include "monitor_wrap.h"
|
||||
#include "msg.h"
|
||||
#include "packet.h"
|
||||
#include "readpass.h"
|
||||
#include "servconf.h"
|
||||
#include "ssh2.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#ifdef USE_POSIX_THREADS
|
||||
#include <pthread.h>
|
||||
#else
|
||||
/*
|
||||
* Simulate threads with processes.
|
||||
*/
|
||||
typedef pid_t pthread_t;
|
||||
|
||||
static void
|
||||
pthread_exit(void *value __unused)
|
||||
{
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_create(pthread_t *thread, const void *attr __unused,
|
||||
void *(*thread_start)(void *), void *arg)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
switch ((pid = fork())) {
|
||||
case -1:
|
||||
error("fork(): %s", strerror(errno));
|
||||
return (-1);
|
||||
case 0:
|
||||
thread_start(arg);
|
||||
_exit(1);
|
||||
default:
|
||||
*thread = pid;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_cancel(pthread_t thread)
|
||||
{
|
||||
return (kill(thread, SIGTERM));
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_join(pthread_t thread, void **value __unused)
|
||||
{
|
||||
int status;
|
||||
|
||||
waitpid(thread, &status, 0);
|
||||
return (status);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static pam_handle_t *pam_handle;
|
||||
static int pam_err;
|
||||
static int pam_authenticated;
|
||||
static int pam_new_authtok_reqd;
|
||||
static int pam_session_open;
|
||||
static int pam_cred_established;
|
||||
|
||||
struct pam_ctxt {
|
||||
char *pam_user;
|
||||
pid_t pam_pid;
|
||||
int pam_sock;
|
||||
pthread_t pam_thread;
|
||||
int pam_psock;
|
||||
int pam_csock;
|
||||
int pam_done;
|
||||
};
|
||||
|
||||
static void pam_free_ctx(void *);
|
||||
|
||||
/*
|
||||
* Conversation function for child process.
|
||||
* Conversation function for authentication thread.
|
||||
*/
|
||||
static int
|
||||
pam_child_conv(int n,
|
||||
pam_thread_conv(int n,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
void *data)
|
||||
|
@ -76,32 +134,32 @@ pam_child_conv(int n,
|
|||
*resp = xmalloc(n * sizeof **resp);
|
||||
buffer_init(&buffer);
|
||||
for (i = 0; i < n; ++i) {
|
||||
resp[i]->resp_retcode = 0;
|
||||
resp[i]->resp = NULL;
|
||||
(*resp)[i].resp_retcode = 0;
|
||||
(*resp)[i].resp = NULL;
|
||||
switch (msg[i]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_sock, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_csock, &buffer);
|
||||
if (buffer_get_char(&buffer) != PAM_AUTHTOK)
|
||||
goto fail;
|
||||
resp[i]->resp = buffer_get_string(&buffer, NULL);
|
||||
(*resp)[i].resp = buffer_get_string(&buffer, NULL);
|
||||
break;
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_sock, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_csock, &buffer);
|
||||
if (buffer_get_char(&buffer) != PAM_AUTHTOK)
|
||||
goto fail;
|
||||
resp[i]->resp = buffer_get_string(&buffer, NULL);
|
||||
(*resp)[i].resp = buffer_get_string(&buffer, NULL);
|
||||
break;
|
||||
case PAM_ERROR_MSG:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
break;
|
||||
case PAM_TEXT_INFO:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
|
@ -111,8 +169,6 @@ pam_child_conv(int n,
|
|||
buffer_free(&buffer);
|
||||
return (PAM_SUCCESS);
|
||||
fail:
|
||||
while (i)
|
||||
xfree(resp[--i]);
|
||||
xfree(*resp);
|
||||
*resp = NULL;
|
||||
buffer_free(&buffer);
|
||||
|
@ -120,51 +176,119 @@ pam_child_conv(int n,
|
|||
}
|
||||
|
||||
/*
|
||||
* Child process.
|
||||
* Authentication thread.
|
||||
*/
|
||||
static void *
|
||||
pam_child(struct pam_ctxt *ctxt)
|
||||
pam_thread(void *ctxtp)
|
||||
{
|
||||
struct pam_ctxt *ctxt = ctxtp;
|
||||
Buffer buffer;
|
||||
struct pam_conv pam_conv;
|
||||
pam_handle_t *pamh;
|
||||
int pam_err;
|
||||
struct pam_conv pam_conv = { pam_thread_conv, ctxt };
|
||||
|
||||
pam_conv.conv = pam_child_conv;
|
||||
pam_conv.appdata_ptr = ctxt;
|
||||
#ifndef USE_POSIX_THREADS
|
||||
{
|
||||
const char *pam_user;
|
||||
|
||||
pam_get_item(pam_handle, PAM_USER, (const void **)&pam_user);
|
||||
setproctitle("%s [pam]", pam_user);
|
||||
}
|
||||
#endif
|
||||
buffer_init(&buffer);
|
||||
setproctitle("%s [pam]", ctxt->pam_user);
|
||||
pam_err = pam_start("sshd", ctxt->pam_user, &pam_conv, &pamh);
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&pam_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
pam_err = pam_authenticate(pamh, 0);
|
||||
pam_err = pam_authenticate(pam_handle, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
pam_err = pam_acct_mgmt(pamh, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
pam_err = pam_acct_mgmt(pam_handle, 0);
|
||||
if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
|
||||
goto auth_fail;
|
||||
buffer_put_cstring(&buffer, "OK");
|
||||
ssh_msg_send(ctxt->pam_sock, PAM_SUCCESS, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, pam_err, &buffer);
|
||||
buffer_free(&buffer);
|
||||
pam_end(pamh, pam_err);
|
||||
exit(0);
|
||||
pthread_exit(NULL);
|
||||
auth_fail:
|
||||
buffer_put_cstring(&buffer, pam_strerror(pamh, pam_err));
|
||||
ssh_msg_send(ctxt->pam_sock, PAM_AUTH_ERR, &buffer);
|
||||
buffer_put_cstring(&buffer,
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
|
||||
buffer_free(&buffer);
|
||||
pam_end(pamh, pam_err);
|
||||
exit(0);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pam_cleanup(void *ctxtp)
|
||||
pam_thread_cleanup(void *ctxtp)
|
||||
{
|
||||
struct pam_ctxt *ctxt = ctxtp;
|
||||
int status;
|
||||
|
||||
close(ctxt->pam_sock);
|
||||
kill(ctxt->pam_pid, SIGHUP);
|
||||
waitpid(ctxt->pam_pid, &status, 0);
|
||||
pthread_cancel(ctxt->pam_thread);
|
||||
pthread_join(ctxt->pam_thread, NULL);
|
||||
close(ctxt->pam_psock);
|
||||
close(ctxt->pam_csock);
|
||||
}
|
||||
|
||||
static int
|
||||
pam_null_conv(int n,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
void *data)
|
||||
{
|
||||
|
||||
return (PAM_CONV_ERR);
|
||||
}
|
||||
|
||||
static struct pam_conv null_conv = { pam_null_conv, NULL };
|
||||
|
||||
static void
|
||||
pam_cleanup(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
debug("PAM: cleanup");
|
||||
pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
|
||||
if (pam_cred_established) {
|
||||
pam_setcred(pam_handle, PAM_DELETE_CRED);
|
||||
pam_cred_established = 0;
|
||||
}
|
||||
if (pam_session_open) {
|
||||
pam_close_session(pam_handle, PAM_SILENT);
|
||||
pam_session_open = 0;
|
||||
}
|
||||
pam_authenticated = pam_new_authtok_reqd = 0;
|
||||
pam_end(pam_handle, pam_err);
|
||||
pam_handle = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
pam_init(const char *user)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
extern u_int utmp_len;
|
||||
const char *pam_rhost, *pam_user;
|
||||
|
||||
if (pam_handle != NULL) {
|
||||
/* We already have a PAM context; check if the user matches */
|
||||
pam_err = pam_get_item(pam_handle,
|
||||
PAM_USER, (const void **)&pam_user);
|
||||
if (pam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
|
||||
return (0);
|
||||
fatal_remove_cleanup(pam_cleanup, NULL);
|
||||
pam_end(pam_handle, pam_err);
|
||||
pam_handle = NULL;
|
||||
}
|
||||
debug("PAM: initializing for \"%s\"", user);
|
||||
pam_err = pam_start("sshd", user, &null_conv, &pam_handle);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
return (-1);
|
||||
pam_rhost = get_remote_name_or_ip(utmp_len,
|
||||
options.verify_reverse_mapping);
|
||||
debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
|
||||
pam_err = pam_set_item(pam_handle, PAM_RHOST, pam_rhost);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
pam_end(pam_handle, pam_err);
|
||||
pam_handle = NULL;
|
||||
return (-1);
|
||||
}
|
||||
fatal_add_cleanup(pam_cleanup, NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void *
|
||||
|
@ -172,38 +296,33 @@ pam_init_ctx(Authctxt *authctxt)
|
|||
{
|
||||
struct pam_ctxt *ctxt;
|
||||
int socks[2];
|
||||
int i;
|
||||
|
||||
/* Initialize PAM */
|
||||
if (pam_init(authctxt->user) == -1) {
|
||||
error("PAM: initialization failed");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ctxt = xmalloc(sizeof *ctxt);
|
||||
ctxt->pam_user = xstrdup(authctxt->user);
|
||||
ctxt->pam_done = 0;
|
||||
|
||||
/* Start the authentication thread */
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
|
||||
error("%s: failed create sockets: %s",
|
||||
__func__, strerror(errno));
|
||||
error("PAM: failed create sockets: %s", strerror(errno));
|
||||
xfree(ctxt);
|
||||
return (NULL);
|
||||
}
|
||||
if ((ctxt->pam_pid = fork()) == -1) {
|
||||
error("%s: failed to fork auth-pam child: %s",
|
||||
__func__, strerror(errno));
|
||||
ctxt->pam_psock = socks[0];
|
||||
ctxt->pam_csock = socks[1];
|
||||
if (pthread_create(&ctxt->pam_thread, NULL, pam_thread, ctxt) == -1) {
|
||||
error("PAM: failed to start authentication thread: %s",
|
||||
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 = 3; 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]);
|
||||
fatal_add_cleanup(pam_cleanup, ctxt);
|
||||
fatal_add_cleanup(pam_thread_cleanup, ctxt);
|
||||
return (ctxt);
|
||||
}
|
||||
|
||||
|
@ -224,7 +343,7 @@ pam_query(void *ctx, char **name, char **info,
|
|||
**prompts = NULL;
|
||||
plen = 0;
|
||||
*echo_on = xmalloc(sizeof(u_int));
|
||||
while (ssh_msg_recv(ctxt->pam_sock, &buffer) == 0) {
|
||||
while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
|
||||
type = buffer_get_char(&buffer);
|
||||
msg = buffer_get_string(&buffer, NULL);
|
||||
switch (type) {
|
||||
|
@ -243,6 +362,9 @@ pam_query(void *ctx, char **name, char **info,
|
|||
plen += sprintf(**prompts + plen, "%s", msg);
|
||||
xfree(msg);
|
||||
break;
|
||||
case PAM_NEW_AUTHTOK_REQD:
|
||||
pam_new_authtok_reqd = 1;
|
||||
/* FALLTHROUGH */
|
||||
case PAM_SUCCESS:
|
||||
case PAM_AUTH_ERR:
|
||||
if (**prompts != NULL) {
|
||||
|
@ -264,7 +386,7 @@ pam_query(void *ctx, char **name, char **info,
|
|||
xfree(msg);
|
||||
return (0);
|
||||
}
|
||||
error("%s", msg);
|
||||
error("PAM: %s", msg);
|
||||
default:
|
||||
*num = 0;
|
||||
**echo_on = 0;
|
||||
|
@ -283,22 +405,23 @@ pam_respond(void *ctx, u_int num, char **resp)
|
|||
struct pam_ctxt *ctxt = ctx;
|
||||
char *msg;
|
||||
|
||||
debug2(__func__);
|
||||
debug2("PAM: %s", __func__);
|
||||
switch (ctxt->pam_done) {
|
||||
case 1:
|
||||
return (0);
|
||||
pam_authenticated = 1;
|
||||
return (0);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
if (num != 1) {
|
||||
error("expected one response, got %u", num);
|
||||
error("PAM: expected one response, got %u", num);
|
||||
return (-1);
|
||||
}
|
||||
buffer_init(&buffer);
|
||||
buffer_put_cstring(&buffer, *resp);
|
||||
ssh_msg_send(ctxt->pam_sock, PAM_AUTHTOK, &buffer);
|
||||
ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer);
|
||||
buffer_free(&buffer);
|
||||
return (1);
|
||||
}
|
||||
|
@ -307,14 +430,16 @@ static void
|
|||
pam_free_ctx(void *ctxtp)
|
||||
{
|
||||
struct pam_ctxt *ctxt = ctxtp;
|
||||
int status;
|
||||
|
||||
fatal_remove_cleanup(pam_cleanup, ctxt);
|
||||
close(ctxt->pam_sock);
|
||||
kill(ctxt->pam_pid, SIGHUP);
|
||||
waitpid(ctxt->pam_pid, &status, 0);
|
||||
xfree(ctxt->pam_user);
|
||||
fatal_remove_cleanup(pam_thread_cleanup, ctxt);
|
||||
pam_thread_cleanup(ctxtp);
|
||||
xfree(ctxt);
|
||||
/*
|
||||
* We don't call pam_cleanup() here because we may need the PAM
|
||||
* handle at a later stage, e.g. when setting up a session. It's
|
||||
* still on the cleanup list, so pam_end() *will* be called before
|
||||
* the server process terminates.
|
||||
*/
|
||||
}
|
||||
|
||||
KbdintDevice pam_device = {
|
||||
|
@ -333,4 +458,169 @@ KbdintDevice mm_pam_device = {
|
|||
mm_pam_free_ctx
|
||||
};
|
||||
|
||||
/*
|
||||
* This replaces auth-pam.c
|
||||
*/
|
||||
void
|
||||
start_pam(const char *user)
|
||||
{
|
||||
if (pam_init(user) == -1)
|
||||
fatal("PAM: initialisation failed");
|
||||
}
|
||||
|
||||
void
|
||||
finish_pam(void)
|
||||
{
|
||||
fatal_remove_cleanup(pam_cleanup, NULL);
|
||||
pam_cleanup(NULL);
|
||||
}
|
||||
|
||||
int
|
||||
do_pam_account(const char *user, const char *ruser)
|
||||
{
|
||||
/* XXX */
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
do_pam_session(const char *user, const char *tty)
|
||||
{
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_CONV: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
debug("PAM: setting PAM_TTY to \"%s\"", tty);
|
||||
pam_err = pam_set_item(pam_handle, PAM_TTY, tty);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_TTY: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
pam_err = pam_open_session(pam_handle, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: pam_open_session(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
pam_session_open = 1;
|
||||
}
|
||||
|
||||
void
|
||||
do_pam_setcred(int init)
|
||||
{
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_CONV: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
if (init) {
|
||||
debug("PAM: establishing credentials");
|
||||
pam_err = pam_setcred(pam_handle, PAM_ESTABLISH_CRED);
|
||||
} else {
|
||||
debug("PAM: reinitializing credentials");
|
||||
pam_err = pam_setcred(pam_handle, PAM_REINITIALIZE_CRED);
|
||||
}
|
||||
if (pam_err == PAM_SUCCESS) {
|
||||
pam_cred_established = 1;
|
||||
return;
|
||||
}
|
||||
if (pam_authenticated)
|
||||
fatal("PAM: pam_setcred(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
else
|
||||
debug("PAM: pam_setcred(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
}
|
||||
|
||||
int
|
||||
is_pam_password_change_required(void)
|
||||
{
|
||||
return (pam_new_authtok_reqd);
|
||||
}
|
||||
|
||||
static int
|
||||
pam_chauthtok_conv(int n,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
void *data)
|
||||
{
|
||||
char input[PAM_MAX_MSG_SIZE];
|
||||
int i;
|
||||
|
||||
if (n <= 0 || n > PAM_MAX_NUM_MSG)
|
||||
return (PAM_CONV_ERR);
|
||||
*resp = xmalloc(n * sizeof **resp);
|
||||
for (i = 0; i < n; ++i) {
|
||||
switch (msg[i]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
(*resp)[i].resp =
|
||||
read_passphrase(msg[i]->msg, RP_ALLOW_STDIN);
|
||||
(*resp)[i].resp_retcode = PAM_SUCCESS;
|
||||
break;
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
fputs(msg[i]->msg, stderr);
|
||||
fgets(input, sizeof input, stdin);
|
||||
(*resp)[i].resp = xstrdup(input);
|
||||
(*resp)[i].resp_retcode = PAM_SUCCESS;
|
||||
break;
|
||||
case PAM_ERROR_MSG:
|
||||
case PAM_TEXT_INFO:
|
||||
fputs(msg[i]->msg, stderr);
|
||||
(*resp)[i].resp_retcode = PAM_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return (PAM_SUCCESS);
|
||||
fail:
|
||||
xfree(*resp);
|
||||
*resp = NULL;
|
||||
return (PAM_CONV_ERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX this should be done in the authentication phase, but ssh1 doesn't
|
||||
* support that
|
||||
*/
|
||||
void
|
||||
do_pam_chauthtok(void)
|
||||
{
|
||||
struct pam_conv pam_conv = { pam_chauthtok_conv, NULL };
|
||||
|
||||
if (use_privsep)
|
||||
fatal("PAM: chauthtok not supprted with privsep");
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&pam_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_CONV: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
debug("PAM: changing password");
|
||||
pam_err = pam_chauthtok(pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: pam_chauthtok(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
}
|
||||
|
||||
void
|
||||
print_pam_messages(void)
|
||||
{
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
char **
|
||||
fetch_pam_environment(void)
|
||||
{
|
||||
#ifdef HAVE_PAM_GETENVLIST
|
||||
debug("PAM: retrieving environment");
|
||||
return (pam_getenvlist(pam_handle));
|
||||
#else
|
||||
return (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
free_pam_environment(char **env)
|
||||
{
|
||||
char **envp;
|
||||
|
||||
for (envp = env; *envp; envp++)
|
||||
xfree(*envp);
|
||||
xfree(env);
|
||||
}
|
||||
|
||||
#endif /* USE_PAM */
|
||||
|
|
36
security/hpn-ssh/files/patch-auth-chall.c
Normal file
36
security/hpn-ssh/files/patch-auth-chall.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
--- auth-chall.c Tue Jun 5 20:56:17 2001
|
||||
+++ cvs-current/auth-chall.c Wed Sep 24 20:24:27 2003
|
||||
@@ -76,7 +77,33 @@
|
||||
return 0;
|
||||
resp[0] = (char *)response;
|
||||
res = device->respond(authctxt->kbdintctxt, 1, resp);
|
||||
+ if (res == 1) {
|
||||
+ /* postponed - send a null query just in case */
|
||||
+ char *name, *info, **prompts;
|
||||
+ u_int i, numprompts, *echo_on;
|
||||
+
|
||||
+ res = device->query(authctxt->kbdintctxt, &name, &info,
|
||||
+ &numprompts, &prompts, &echo_on);
|
||||
+ if (res == 0) {
|
||||
+ for (i = 0; i < numprompts; i++)
|
||||
+ xfree(prompts[i]);
|
||||
+ xfree(prompts);
|
||||
+ xfree(name);
|
||||
+ xfree(echo_on);
|
||||
+ xfree(info);
|
||||
+ }
|
||||
+ /* if we received more prompts, we're screwed */
|
||||
+ res = (res == 0 && numprompts == 0) ? 0 : -1;
|
||||
+ }
|
||||
device->free_ctx(authctxt->kbdintctxt);
|
||||
authctxt->kbdintctxt = NULL;
|
||||
return res ? 0 : 1;
|
||||
+}
|
||||
+void
|
||||
+abandon_challenge_response(Authctxt *authctxt)
|
||||
+{
|
||||
+ if (authctxt->kbdintctxt != NULL) {
|
||||
+ device->free_ctx(authctxt->kbdintctxt);
|
||||
+ authctxt->kbdintctxt = NULL;
|
||||
+ }
|
||||
}
|
91
security/hpn-ssh/files/patch-auth-pam.c
Normal file
91
security/hpn-ssh/files/patch-auth-pam.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
--- auth-pam.c.orig Tue Apr 29 11:12:08 2003
|
||||
+++ auth-pam.c Thu Sep 25 22:42:45 2003
|
||||
@@ -228,7 +228,7 @@
|
||||
}
|
||||
|
||||
/* Do account management using PAM */
|
||||
-int do_pam_account(char *username, char *remote_user)
|
||||
+int old_do_pam_account(const char *username, const char *remote_user)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
}
|
||||
|
||||
/* Do PAM-specific session initialisation */
|
||||
-void do_pam_session(char *username, const char *ttyname)
|
||||
+void old_do_pam_session(const char *username, const char *ttyname)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -294,7 +294,7 @@
|
||||
}
|
||||
|
||||
/* Set PAM credentials */
|
||||
-void do_pam_setcred(int init)
|
||||
+void old_do_pam_setcred(int init)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
}
|
||||
|
||||
/* accessor function for file scope static variable */
|
||||
-int is_pam_password_change_required(void)
|
||||
+int old_is_pam_password_change_required(void)
|
||||
{
|
||||
return password_change_required;
|
||||
}
|
||||
@@ -329,7 +329,7 @@
|
||||
* session is established and the user's pty is connected to
|
||||
* stdin/stdout/stderr.
|
||||
*/
|
||||
-void do_pam_chauthtok(void)
|
||||
+void old_do_pam_chauthtok(void)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -357,14 +357,14 @@
|
||||
}
|
||||
|
||||
/* Cleanly shutdown PAM */
|
||||
-void finish_pam(void)
|
||||
+void old_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(const char *user)
|
||||
+void old_start_pam(const char *user)
|
||||
{
|
||||
int pam_retval;
|
||||
extern ServerOptions options;
|
||||
@@ -404,7 +404,7 @@
|
||||
}
|
||||
|
||||
/* Return list of PAM environment strings */
|
||||
-char **fetch_pam_environment(void)
|
||||
+char **old_fetch_pam_environment(void)
|
||||
{
|
||||
#ifdef HAVE_PAM_GETENVLIST
|
||||
return(pam_getenvlist(__pamh));
|
||||
@@ -413,7 +413,7 @@
|
||||
#endif /* HAVE_PAM_GETENVLIST */
|
||||
}
|
||||
|
||||
-void free_pam_environment(char **env)
|
||||
+void old_free_pam_environment(char **env)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
|
||||
/* Print any messages that have been generated during authentication */
|
||||
/* or account checking to stderr */
|
||||
-void print_pam_messages(void)
|
||||
+void old_print_pam_messages(void)
|
||||
{
|
||||
if (__pam_msg != NULL)
|
||||
fputs(__pam_msg, stderr);
|
13
security/hpn-ssh/files/patch-auth-pam.h
Normal file
13
security/hpn-ssh/files/patch-auth-pam.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
--- auth-pam.h Tue Jul 23 02:44:07 2002
|
||||
+++ cvs-current/auth-pam.h Sat Dec 14 14:52:39 2002
|
||||
@@ -37,8 +38,8 @@
|
||||
char **fetch_pam_environment(void);
|
||||
void free_pam_environment(char **env);
|
||||
int do_pam_authenticate(int flags);
|
||||
-int do_pam_account(char *username, char *remote_user);
|
||||
-void do_pam_session(char *username, const char *ttyname);
|
||||
+int do_pam_account(const char *username, const char *remote_user);
|
||||
+void do_pam_session(const char *username, const char *ttyname);
|
||||
void do_pam_setcred(int init);
|
||||
void print_pam_messages(void);
|
||||
int is_pam_password_change_required(void);
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
PORTNAME= openssh
|
||||
PORTVERSION= 3.6.1p2
|
||||
PORTREVISION= 4
|
||||
PORTREVISION= 5
|
||||
CATEGORIES= security ipv6
|
||||
MASTER_SITES= ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/ \
|
||||
ftp://carroll.cac.psu.edu/pub/OpenBSD/OpenSSH/portable/
|
||||
|
@ -16,8 +16,6 @@ PKGNAMESUFFIX?= -portable
|
|||
MAINTAINER= dinoex@FreeBSD.org
|
||||
COMMENT= The portable version of OpenBSD's OpenSSH
|
||||
|
||||
FORBIDDEN= Security Problem with PAM
|
||||
|
||||
MAN1= sftp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 scp.1 ssh.1
|
||||
MLINKS= ssh.1 slogin.1
|
||||
MAN5= ssh_config.5 sshd_config.5
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
* 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
|
||||
|
@ -33,35 +30,96 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh-portable/files/Attic/auth2-pam-freebsd.c,v 1.4 2002-10-17 04:40:20 dinoex Exp $");
|
||||
RCSID("$FreeBSD: /tmp/pcvs/ports/security/openssh-portable/files/Attic/auth2-pam-freebsd.c,v 1.5 2003-09-26 02:42:39 dinoex Exp $");
|
||||
|
||||
#ifdef USE_PAM
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
#include "auth.h"
|
||||
#include "auth-pam.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "canohost.h"
|
||||
#include "log.h"
|
||||
#include "monitor_wrap.h"
|
||||
#include "msg.h"
|
||||
#include "packet.h"
|
||||
#include "readpass.h"
|
||||
#include "servconf.h"
|
||||
#include "ssh2.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#ifdef USE_POSIX_THREADS
|
||||
#include <pthread.h>
|
||||
#else
|
||||
/*
|
||||
* Simulate threads with processes.
|
||||
*/
|
||||
typedef pid_t pthread_t;
|
||||
|
||||
static void
|
||||
pthread_exit(void *value __unused)
|
||||
{
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_create(pthread_t *thread, const void *attr __unused,
|
||||
void *(*thread_start)(void *), void *arg)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
switch ((pid = fork())) {
|
||||
case -1:
|
||||
error("fork(): %s", strerror(errno));
|
||||
return (-1);
|
||||
case 0:
|
||||
thread_start(arg);
|
||||
_exit(1);
|
||||
default:
|
||||
*thread = pid;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_cancel(pthread_t thread)
|
||||
{
|
||||
return (kill(thread, SIGTERM));
|
||||
}
|
||||
|
||||
static int
|
||||
pthread_join(pthread_t thread, void **value __unused)
|
||||
{
|
||||
int status;
|
||||
|
||||
waitpid(thread, &status, 0);
|
||||
return (status);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static pam_handle_t *pam_handle;
|
||||
static int pam_err;
|
||||
static int pam_authenticated;
|
||||
static int pam_new_authtok_reqd;
|
||||
static int pam_session_open;
|
||||
static int pam_cred_established;
|
||||
|
||||
struct pam_ctxt {
|
||||
char *pam_user;
|
||||
pid_t pam_pid;
|
||||
int pam_sock;
|
||||
pthread_t pam_thread;
|
||||
int pam_psock;
|
||||
int pam_csock;
|
||||
int pam_done;
|
||||
};
|
||||
|
||||
static void pam_free_ctx(void *);
|
||||
|
||||
/*
|
||||
* Conversation function for child process.
|
||||
* Conversation function for authentication thread.
|
||||
*/
|
||||
static int
|
||||
pam_child_conv(int n,
|
||||
pam_thread_conv(int n,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
void *data)
|
||||
|
@ -76,32 +134,32 @@ pam_child_conv(int n,
|
|||
*resp = xmalloc(n * sizeof **resp);
|
||||
buffer_init(&buffer);
|
||||
for (i = 0; i < n; ++i) {
|
||||
resp[i]->resp_retcode = 0;
|
||||
resp[i]->resp = NULL;
|
||||
(*resp)[i].resp_retcode = 0;
|
||||
(*resp)[i].resp = NULL;
|
||||
switch (msg[i]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_sock, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_csock, &buffer);
|
||||
if (buffer_get_char(&buffer) != PAM_AUTHTOK)
|
||||
goto fail;
|
||||
resp[i]->resp = buffer_get_string(&buffer, NULL);
|
||||
(*resp)[i].resp = buffer_get_string(&buffer, NULL);
|
||||
break;
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_sock, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_recv(ctxt->pam_csock, &buffer);
|
||||
if (buffer_get_char(&buffer) != PAM_AUTHTOK)
|
||||
goto fail;
|
||||
resp[i]->resp = buffer_get_string(&buffer, NULL);
|
||||
(*resp)[i].resp = buffer_get_string(&buffer, NULL);
|
||||
break;
|
||||
case PAM_ERROR_MSG:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
break;
|
||||
case PAM_TEXT_INFO:
|
||||
buffer_put_cstring(&buffer, msg[i]->msg);
|
||||
ssh_msg_send(ctxt->pam_sock, msg[i]->msg_style, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, msg[i]->msg_style, &buffer);
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
|
@ -111,8 +169,6 @@ pam_child_conv(int n,
|
|||
buffer_free(&buffer);
|
||||
return (PAM_SUCCESS);
|
||||
fail:
|
||||
while (i)
|
||||
xfree(resp[--i]);
|
||||
xfree(*resp);
|
||||
*resp = NULL;
|
||||
buffer_free(&buffer);
|
||||
|
@ -120,51 +176,119 @@ pam_child_conv(int n,
|
|||
}
|
||||
|
||||
/*
|
||||
* Child process.
|
||||
* Authentication thread.
|
||||
*/
|
||||
static void *
|
||||
pam_child(struct pam_ctxt *ctxt)
|
||||
pam_thread(void *ctxtp)
|
||||
{
|
||||
struct pam_ctxt *ctxt = ctxtp;
|
||||
Buffer buffer;
|
||||
struct pam_conv pam_conv;
|
||||
pam_handle_t *pamh;
|
||||
int pam_err;
|
||||
struct pam_conv pam_conv = { pam_thread_conv, ctxt };
|
||||
|
||||
pam_conv.conv = pam_child_conv;
|
||||
pam_conv.appdata_ptr = ctxt;
|
||||
#ifndef USE_POSIX_THREADS
|
||||
{
|
||||
const char *pam_user;
|
||||
|
||||
pam_get_item(pam_handle, PAM_USER, (const void **)&pam_user);
|
||||
setproctitle("%s [pam]", pam_user);
|
||||
}
|
||||
#endif
|
||||
buffer_init(&buffer);
|
||||
setproctitle("%s [pam]", ctxt->pam_user);
|
||||
pam_err = pam_start("sshd", ctxt->pam_user, &pam_conv, &pamh);
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&pam_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
pam_err = pam_authenticate(pamh, 0);
|
||||
pam_err = pam_authenticate(pam_handle, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
pam_err = pam_acct_mgmt(pamh, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
pam_err = pam_acct_mgmt(pam_handle, 0);
|
||||
if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
|
||||
goto auth_fail;
|
||||
buffer_put_cstring(&buffer, "OK");
|
||||
ssh_msg_send(ctxt->pam_sock, PAM_SUCCESS, &buffer);
|
||||
ssh_msg_send(ctxt->pam_csock, pam_err, &buffer);
|
||||
buffer_free(&buffer);
|
||||
pam_end(pamh, pam_err);
|
||||
exit(0);
|
||||
pthread_exit(NULL);
|
||||
auth_fail:
|
||||
buffer_put_cstring(&buffer, pam_strerror(pamh, pam_err));
|
||||
ssh_msg_send(ctxt->pam_sock, PAM_AUTH_ERR, &buffer);
|
||||
buffer_put_cstring(&buffer,
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
|
||||
buffer_free(&buffer);
|
||||
pam_end(pamh, pam_err);
|
||||
exit(0);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pam_cleanup(void *ctxtp)
|
||||
pam_thread_cleanup(void *ctxtp)
|
||||
{
|
||||
struct pam_ctxt *ctxt = ctxtp;
|
||||
int status;
|
||||
|
||||
close(ctxt->pam_sock);
|
||||
kill(ctxt->pam_pid, SIGHUP);
|
||||
waitpid(ctxt->pam_pid, &status, 0);
|
||||
pthread_cancel(ctxt->pam_thread);
|
||||
pthread_join(ctxt->pam_thread, NULL);
|
||||
close(ctxt->pam_psock);
|
||||
close(ctxt->pam_csock);
|
||||
}
|
||||
|
||||
static int
|
||||
pam_null_conv(int n,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
void *data)
|
||||
{
|
||||
|
||||
return (PAM_CONV_ERR);
|
||||
}
|
||||
|
||||
static struct pam_conv null_conv = { pam_null_conv, NULL };
|
||||
|
||||
static void
|
||||
pam_cleanup(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
debug("PAM: cleanup");
|
||||
pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
|
||||
if (pam_cred_established) {
|
||||
pam_setcred(pam_handle, PAM_DELETE_CRED);
|
||||
pam_cred_established = 0;
|
||||
}
|
||||
if (pam_session_open) {
|
||||
pam_close_session(pam_handle, PAM_SILENT);
|
||||
pam_session_open = 0;
|
||||
}
|
||||
pam_authenticated = pam_new_authtok_reqd = 0;
|
||||
pam_end(pam_handle, pam_err);
|
||||
pam_handle = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
pam_init(const char *user)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
extern u_int utmp_len;
|
||||
const char *pam_rhost, *pam_user;
|
||||
|
||||
if (pam_handle != NULL) {
|
||||
/* We already have a PAM context; check if the user matches */
|
||||
pam_err = pam_get_item(pam_handle,
|
||||
PAM_USER, (const void **)&pam_user);
|
||||
if (pam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
|
||||
return (0);
|
||||
fatal_remove_cleanup(pam_cleanup, NULL);
|
||||
pam_end(pam_handle, pam_err);
|
||||
pam_handle = NULL;
|
||||
}
|
||||
debug("PAM: initializing for \"%s\"", user);
|
||||
pam_err = pam_start("sshd", user, &null_conv, &pam_handle);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
return (-1);
|
||||
pam_rhost = get_remote_name_or_ip(utmp_len,
|
||||
options.verify_reverse_mapping);
|
||||
debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
|
||||
pam_err = pam_set_item(pam_handle, PAM_RHOST, pam_rhost);
|
||||
if (pam_err != PAM_SUCCESS) {
|
||||
pam_end(pam_handle, pam_err);
|
||||
pam_handle = NULL;
|
||||
return (-1);
|
||||
}
|
||||
fatal_add_cleanup(pam_cleanup, NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void *
|
||||
|
@ -172,38 +296,33 @@ pam_init_ctx(Authctxt *authctxt)
|
|||
{
|
||||
struct pam_ctxt *ctxt;
|
||||
int socks[2];
|
||||
int i;
|
||||
|
||||
/* Initialize PAM */
|
||||
if (pam_init(authctxt->user) == -1) {
|
||||
error("PAM: initialization failed");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ctxt = xmalloc(sizeof *ctxt);
|
||||
ctxt->pam_user = xstrdup(authctxt->user);
|
||||
ctxt->pam_done = 0;
|
||||
|
||||
/* Start the authentication thread */
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
|
||||
error("%s: failed create sockets: %s",
|
||||
__func__, strerror(errno));
|
||||
error("PAM: failed create sockets: %s", strerror(errno));
|
||||
xfree(ctxt);
|
||||
return (NULL);
|
||||
}
|
||||
if ((ctxt->pam_pid = fork()) == -1) {
|
||||
error("%s: failed to fork auth-pam child: %s",
|
||||
__func__, strerror(errno));
|
||||
ctxt->pam_psock = socks[0];
|
||||
ctxt->pam_csock = socks[1];
|
||||
if (pthread_create(&ctxt->pam_thread, NULL, pam_thread, ctxt) == -1) {
|
||||
error("PAM: failed to start authentication thread: %s",
|
||||
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 = 3; 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]);
|
||||
fatal_add_cleanup(pam_cleanup, ctxt);
|
||||
fatal_add_cleanup(pam_thread_cleanup, ctxt);
|
||||
return (ctxt);
|
||||
}
|
||||
|
||||
|
@ -224,7 +343,7 @@ pam_query(void *ctx, char **name, char **info,
|
|||
**prompts = NULL;
|
||||
plen = 0;
|
||||
*echo_on = xmalloc(sizeof(u_int));
|
||||
while (ssh_msg_recv(ctxt->pam_sock, &buffer) == 0) {
|
||||
while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
|
||||
type = buffer_get_char(&buffer);
|
||||
msg = buffer_get_string(&buffer, NULL);
|
||||
switch (type) {
|
||||
|
@ -243,6 +362,9 @@ pam_query(void *ctx, char **name, char **info,
|
|||
plen += sprintf(**prompts + plen, "%s", msg);
|
||||
xfree(msg);
|
||||
break;
|
||||
case PAM_NEW_AUTHTOK_REQD:
|
||||
pam_new_authtok_reqd = 1;
|
||||
/* FALLTHROUGH */
|
||||
case PAM_SUCCESS:
|
||||
case PAM_AUTH_ERR:
|
||||
if (**prompts != NULL) {
|
||||
|
@ -264,7 +386,7 @@ pam_query(void *ctx, char **name, char **info,
|
|||
xfree(msg);
|
||||
return (0);
|
||||
}
|
||||
error("%s", msg);
|
||||
error("PAM: %s", msg);
|
||||
default:
|
||||
*num = 0;
|
||||
**echo_on = 0;
|
||||
|
@ -283,22 +405,23 @@ pam_respond(void *ctx, u_int num, char **resp)
|
|||
struct pam_ctxt *ctxt = ctx;
|
||||
char *msg;
|
||||
|
||||
debug2(__func__);
|
||||
debug2("PAM: %s", __func__);
|
||||
switch (ctxt->pam_done) {
|
||||
case 1:
|
||||
return (0);
|
||||
pam_authenticated = 1;
|
||||
return (0);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
if (num != 1) {
|
||||
error("expected one response, got %u", num);
|
||||
error("PAM: expected one response, got %u", num);
|
||||
return (-1);
|
||||
}
|
||||
buffer_init(&buffer);
|
||||
buffer_put_cstring(&buffer, *resp);
|
||||
ssh_msg_send(ctxt->pam_sock, PAM_AUTHTOK, &buffer);
|
||||
ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer);
|
||||
buffer_free(&buffer);
|
||||
return (1);
|
||||
}
|
||||
|
@ -307,14 +430,16 @@ static void
|
|||
pam_free_ctx(void *ctxtp)
|
||||
{
|
||||
struct pam_ctxt *ctxt = ctxtp;
|
||||
int status;
|
||||
|
||||
fatal_remove_cleanup(pam_cleanup, ctxt);
|
||||
close(ctxt->pam_sock);
|
||||
kill(ctxt->pam_pid, SIGHUP);
|
||||
waitpid(ctxt->pam_pid, &status, 0);
|
||||
xfree(ctxt->pam_user);
|
||||
fatal_remove_cleanup(pam_thread_cleanup, ctxt);
|
||||
pam_thread_cleanup(ctxtp);
|
||||
xfree(ctxt);
|
||||
/*
|
||||
* We don't call pam_cleanup() here because we may need the PAM
|
||||
* handle at a later stage, e.g. when setting up a session. It's
|
||||
* still on the cleanup list, so pam_end() *will* be called before
|
||||
* the server process terminates.
|
||||
*/
|
||||
}
|
||||
|
||||
KbdintDevice pam_device = {
|
||||
|
@ -333,4 +458,169 @@ KbdintDevice mm_pam_device = {
|
|||
mm_pam_free_ctx
|
||||
};
|
||||
|
||||
/*
|
||||
* This replaces auth-pam.c
|
||||
*/
|
||||
void
|
||||
start_pam(const char *user)
|
||||
{
|
||||
if (pam_init(user) == -1)
|
||||
fatal("PAM: initialisation failed");
|
||||
}
|
||||
|
||||
void
|
||||
finish_pam(void)
|
||||
{
|
||||
fatal_remove_cleanup(pam_cleanup, NULL);
|
||||
pam_cleanup(NULL);
|
||||
}
|
||||
|
||||
int
|
||||
do_pam_account(const char *user, const char *ruser)
|
||||
{
|
||||
/* XXX */
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
do_pam_session(const char *user, const char *tty)
|
||||
{
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_CONV: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
debug("PAM: setting PAM_TTY to \"%s\"", tty);
|
||||
pam_err = pam_set_item(pam_handle, PAM_TTY, tty);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_TTY: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
pam_err = pam_open_session(pam_handle, 0);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: pam_open_session(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
pam_session_open = 1;
|
||||
}
|
||||
|
||||
void
|
||||
do_pam_setcred(int init)
|
||||
{
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&null_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_CONV: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
if (init) {
|
||||
debug("PAM: establishing credentials");
|
||||
pam_err = pam_setcred(pam_handle, PAM_ESTABLISH_CRED);
|
||||
} else {
|
||||
debug("PAM: reinitializing credentials");
|
||||
pam_err = pam_setcred(pam_handle, PAM_REINITIALIZE_CRED);
|
||||
}
|
||||
if (pam_err == PAM_SUCCESS) {
|
||||
pam_cred_established = 1;
|
||||
return;
|
||||
}
|
||||
if (pam_authenticated)
|
||||
fatal("PAM: pam_setcred(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
else
|
||||
debug("PAM: pam_setcred(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
}
|
||||
|
||||
int
|
||||
is_pam_password_change_required(void)
|
||||
{
|
||||
return (pam_new_authtok_reqd);
|
||||
}
|
||||
|
||||
static int
|
||||
pam_chauthtok_conv(int n,
|
||||
const struct pam_message **msg,
|
||||
struct pam_response **resp,
|
||||
void *data)
|
||||
{
|
||||
char input[PAM_MAX_MSG_SIZE];
|
||||
int i;
|
||||
|
||||
if (n <= 0 || n > PAM_MAX_NUM_MSG)
|
||||
return (PAM_CONV_ERR);
|
||||
*resp = xmalloc(n * sizeof **resp);
|
||||
for (i = 0; i < n; ++i) {
|
||||
switch (msg[i]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
(*resp)[i].resp =
|
||||
read_passphrase(msg[i]->msg, RP_ALLOW_STDIN);
|
||||
(*resp)[i].resp_retcode = PAM_SUCCESS;
|
||||
break;
|
||||
case PAM_PROMPT_ECHO_ON:
|
||||
fputs(msg[i]->msg, stderr);
|
||||
fgets(input, sizeof input, stdin);
|
||||
(*resp)[i].resp = xstrdup(input);
|
||||
(*resp)[i].resp_retcode = PAM_SUCCESS;
|
||||
break;
|
||||
case PAM_ERROR_MSG:
|
||||
case PAM_TEXT_INFO:
|
||||
fputs(msg[i]->msg, stderr);
|
||||
(*resp)[i].resp_retcode = PAM_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return (PAM_SUCCESS);
|
||||
fail:
|
||||
xfree(*resp);
|
||||
*resp = NULL;
|
||||
return (PAM_CONV_ERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX this should be done in the authentication phase, but ssh1 doesn't
|
||||
* support that
|
||||
*/
|
||||
void
|
||||
do_pam_chauthtok(void)
|
||||
{
|
||||
struct pam_conv pam_conv = { pam_chauthtok_conv, NULL };
|
||||
|
||||
if (use_privsep)
|
||||
fatal("PAM: chauthtok not supprted with privsep");
|
||||
pam_err = pam_set_item(pam_handle, PAM_CONV, (const void *)&pam_conv);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: failed to set PAM_CONV: %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
debug("PAM: changing password");
|
||||
pam_err = pam_chauthtok(pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
if (pam_err != PAM_SUCCESS)
|
||||
fatal("PAM: pam_chauthtok(): %s",
|
||||
pam_strerror(pam_handle, pam_err));
|
||||
}
|
||||
|
||||
void
|
||||
print_pam_messages(void)
|
||||
{
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
char **
|
||||
fetch_pam_environment(void)
|
||||
{
|
||||
#ifdef HAVE_PAM_GETENVLIST
|
||||
debug("PAM: retrieving environment");
|
||||
return (pam_getenvlist(pam_handle));
|
||||
#else
|
||||
return (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
free_pam_environment(char **env)
|
||||
{
|
||||
char **envp;
|
||||
|
||||
for (envp = env; *envp; envp++)
|
||||
xfree(*envp);
|
||||
xfree(env);
|
||||
}
|
||||
|
||||
#endif /* USE_PAM */
|
||||
|
|
36
security/openssh-portable/files/patch-auth-chall.c
Normal file
36
security/openssh-portable/files/patch-auth-chall.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
--- auth-chall.c Tue Jun 5 20:56:17 2001
|
||||
+++ cvs-current/auth-chall.c Wed Sep 24 20:24:27 2003
|
||||
@@ -76,7 +77,33 @@
|
||||
return 0;
|
||||
resp[0] = (char *)response;
|
||||
res = device->respond(authctxt->kbdintctxt, 1, resp);
|
||||
+ if (res == 1) {
|
||||
+ /* postponed - send a null query just in case */
|
||||
+ char *name, *info, **prompts;
|
||||
+ u_int i, numprompts, *echo_on;
|
||||
+
|
||||
+ res = device->query(authctxt->kbdintctxt, &name, &info,
|
||||
+ &numprompts, &prompts, &echo_on);
|
||||
+ if (res == 0) {
|
||||
+ for (i = 0; i < numprompts; i++)
|
||||
+ xfree(prompts[i]);
|
||||
+ xfree(prompts);
|
||||
+ xfree(name);
|
||||
+ xfree(echo_on);
|
||||
+ xfree(info);
|
||||
+ }
|
||||
+ /* if we received more prompts, we're screwed */
|
||||
+ res = (res == 0 && numprompts == 0) ? 0 : -1;
|
||||
+ }
|
||||
device->free_ctx(authctxt->kbdintctxt);
|
||||
authctxt->kbdintctxt = NULL;
|
||||
return res ? 0 : 1;
|
||||
+}
|
||||
+void
|
||||
+abandon_challenge_response(Authctxt *authctxt)
|
||||
+{
|
||||
+ if (authctxt->kbdintctxt != NULL) {
|
||||
+ device->free_ctx(authctxt->kbdintctxt);
|
||||
+ authctxt->kbdintctxt = NULL;
|
||||
+ }
|
||||
}
|
91
security/openssh-portable/files/patch-auth-pam.c
Normal file
91
security/openssh-portable/files/patch-auth-pam.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
--- auth-pam.c.orig Tue Apr 29 11:12:08 2003
|
||||
+++ auth-pam.c Thu Sep 25 22:42:45 2003
|
||||
@@ -228,7 +228,7 @@
|
||||
}
|
||||
|
||||
/* Do account management using PAM */
|
||||
-int do_pam_account(char *username, char *remote_user)
|
||||
+int old_do_pam_account(const char *username, const char *remote_user)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
}
|
||||
|
||||
/* Do PAM-specific session initialisation */
|
||||
-void do_pam_session(char *username, const char *ttyname)
|
||||
+void old_do_pam_session(const char *username, const char *ttyname)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -294,7 +294,7 @@
|
||||
}
|
||||
|
||||
/* Set PAM credentials */
|
||||
-void do_pam_setcred(int init)
|
||||
+void old_do_pam_setcred(int init)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
}
|
||||
|
||||
/* accessor function for file scope static variable */
|
||||
-int is_pam_password_change_required(void)
|
||||
+int old_is_pam_password_change_required(void)
|
||||
{
|
||||
return password_change_required;
|
||||
}
|
||||
@@ -329,7 +329,7 @@
|
||||
* session is established and the user's pty is connected to
|
||||
* stdin/stdout/stderr.
|
||||
*/
|
||||
-void do_pam_chauthtok(void)
|
||||
+void old_do_pam_chauthtok(void)
|
||||
{
|
||||
int pam_retval;
|
||||
|
||||
@@ -357,14 +357,14 @@
|
||||
}
|
||||
|
||||
/* Cleanly shutdown PAM */
|
||||
-void finish_pam(void)
|
||||
+void old_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(const char *user)
|
||||
+void old_start_pam(const char *user)
|
||||
{
|
||||
int pam_retval;
|
||||
extern ServerOptions options;
|
||||
@@ -404,7 +404,7 @@
|
||||
}
|
||||
|
||||
/* Return list of PAM environment strings */
|
||||
-char **fetch_pam_environment(void)
|
||||
+char **old_fetch_pam_environment(void)
|
||||
{
|
||||
#ifdef HAVE_PAM_GETENVLIST
|
||||
return(pam_getenvlist(__pamh));
|
||||
@@ -413,7 +413,7 @@
|
||||
#endif /* HAVE_PAM_GETENVLIST */
|
||||
}
|
||||
|
||||
-void free_pam_environment(char **env)
|
||||
+void old_free_pam_environment(char **env)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -425,7 +425,7 @@
|
||||
|
||||
/* Print any messages that have been generated during authentication */
|
||||
/* or account checking to stderr */
|
||||
-void print_pam_messages(void)
|
||||
+void old_print_pam_messages(void)
|
||||
{
|
||||
if (__pam_msg != NULL)
|
||||
fputs(__pam_msg, stderr);
|
13
security/openssh-portable/files/patch-auth-pam.h
Normal file
13
security/openssh-portable/files/patch-auth-pam.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
--- auth-pam.h Tue Jul 23 02:44:07 2002
|
||||
+++ cvs-current/auth-pam.h Sat Dec 14 14:52:39 2002
|
||||
@@ -37,8 +38,8 @@
|
||||
char **fetch_pam_environment(void);
|
||||
void free_pam_environment(char **env);
|
||||
int do_pam_authenticate(int flags);
|
||||
-int do_pam_account(char *username, char *remote_user);
|
||||
-void do_pam_session(char *username, const char *ttyname);
|
||||
+int do_pam_account(const char *username, const char *remote_user);
|
||||
+void do_pam_session(const char *username, const char *ttyname);
|
||||
void do_pam_setcred(int init);
|
||||
void print_pam_messages(void);
|
||||
int is_pam_password_change_required(void);
|
Loading…
Reference in a new issue