auth2-pam.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
RCSID("$Id: auth2-pam.c,v 1.14 2002/06/28 16:48:12 mouring Exp $");
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef USE_PAM
#include <security/pam_appl.h>
#include "ssh.h"
#include "ssh2.h"
#include "auth.h"
#include "auth-pam.h"
#include "auth-options.h"
#include "packet.h"
#include "xmalloc.h"
#include "dispatch.h"
#include "canohost.h"
#include "log.h"
#include "servconf.h"
#include "monitor_wrap.h"
#include "misc.h"
#ifdef HAVE_BSM
#include "bsmaudit.h"
#endif /* HAVE_BSM */
extern ServerOptions options;
extern Authmethod method_kbdint;
extern Authmethod method_passwd;
#define SSHD_PAM_KBDINT_SVC "sshd-kbdint"
static int do_pam_conv_kbd_int(int num_msg,
void *appdata_ptr);
static void input_userauth_info_response_pam(int type,
void *ctxt);
NULL,
};
void
{
fatal("auth2_pam: internal error: no user");
fatal("auth2_pam: internal error: no method");
/*
* Since password userauth and keyboard-interactive userauth
* both use PAM, and since keyboard-interactive is so much
* better than password userauth, we should not allow the user
* to try password userauth after trying keyboard-interactive.
*/
if (method_passwd.enabled)
*method_passwd.enabled = 0;
}
static void
{
const char *where = "authenticating";
debug2("Calling pam_authenticate()");
goto cleanup;
debug2("kbd-int: pam_authenticate() succeeded");
where = "authorizing";
if (retval == PAM_NEW_AUTHTOK_REQD) {
/*
* Can't use temporarily_use_uid() and restore_uid()
* here because we need (euid == 0 && ruid == pw_uid)
* whereas temporarily_use_uid() arranges for
* (suid = 0 && euid == pw_uid && ruid == pw_uid).
*/
debug2("kbd-int: changing expired password");
where = "changing authentication tokens (password)";
(void) setreuid(0, -1);
} else {
}
}
if (retval != PAM_SUCCESS)
goto cleanup;
if (retval != PAM_SUCCESS)
goto cleanup;
/*
* PAM handle stays around so we can call pam_close_session()
* on it later.
*/
return;
/*
* Check for abandonment and cleanup. When kbdint is abandoned
* authctxt->pam->h is NULLed and by this point a new handle may
* be allocated.
*/
log("Keyboard-interactive (PAM) userauth abandoned "
"while %s", where);
log("Cannot close PAM handle after "
"kbd-int userauth abandonment[%d]: %.200s",
}
/*
* Avoid double counting; these are incremented in
* kbdint_pam_abandon() so that they reflect the correct
* count when userauth_finish() is called before
* unwinding the dispatch_run() loop, but they are
* incremented again in input_userauth_request() when
* the loop is unwound, right here.
*/
}
else {
/* Save error value for pam_end() */
log("Keyboard-interactive (PAM) userauth failed[%d] "
/* pam handle can be reused elsewhere, so no pam_end() here */
}
return;
}
static int
{
int i, j;
char *text;
debug("Missing state during PAM conversation");
return PAM_CONV_ERR;
}
conv_ctxt->num_received = 0;
conv_ctxt->num_expected = 0;
switch (style) {
case PAM_PROMPT_ECHO_ON:
debug2("PAM echo on prompt: %s",
break;
case PAM_PROMPT_ECHO_OFF:
debug2("PAM echo off prompt: %s",
break;
case PAM_TEXT_INFO:
debug2("PAM text info prompt: %s",
break;
case PAM_ERROR_MSG:
debug2("PAM error prompt: %s",
break;
default:
/* Capture all these messages to be sent at once */
break;
}
}
return PAM_SUCCESS;
}
if (text)
for (i = 0, j = 0; i < num_msg; i++) {
/* Skip messages which don't need a reply */
continue;
}
packet_send();
/*
* Here the dispatch_run() loop is nested. It should be unwound
* if keyboard-interactive userauth is abandoned (or restarted;
* same thing).
*
* The condition for breaking out of the nested dispatch_run() loop is
* ((got kbd-int info reponse) || (kbd-int abandoned))
*
* conv_ctxt->finished is set in either of those cases.
*
* When abandonment is detected the conv_ctxt->finished is set as
* is conv_ctxt->abandoned, causing this function to signal
* userauth nested dispatch_run() loop unwinding and to return
* PAM_CONV_ERR;
*/
debug2("Nesting dispatch_run loop");
debug2("Nested dispatch_run loop exited");
debug("PAM conv function returns PAM_CONV_ERR");
return PAM_CONV_ERR;
}
debug("PAM conv function returns PAM_SUCCESS");
return PAM_SUCCESS;
}
debug("PAM conv function returns PAM_CONV_ERR");
return PAM_CONV_ERR;
}
static void
{
char *resp;
fatal("input_userauth_info_response_pam: no authentication context");
/* Check for spurious/unexpected info response */
debug("input_userauth_info_response_pam: no method context");
return;
}
#if 0
fatal("%s: Received incorrect number of responses "
"(expected %d, received %u)", __func__,
#endif
if (nresp > 100)
if (i < conv_ctxt->num_expected) {
}
}
/* XXX - This could make a covert channel... */
debug("Ignoring additional PAM replies");
}
#if 0
int
{
if (!method)
return 0; /* fatal(), really; it'll happen somewhere else */
if (!method->method_data)
return 0;
return 1;
}
#endif
void
{
/*
* But, if it ever becomes desirable and possible to support
* kbd-int userauth abandonment, here's what must be done.
*/
if (!method)
return;
if (!method->method_data)
return;
/* dispatch_run() loop will exit */
/*
* The method_data will be free in the corresponding, active
* conversation function
*/
/* update counts that can't be updated elsewhere */
/* Finally, we cannot re-use the current current PAM handle */
}
#endif