auth-pam.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
*
* 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.
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
#ifdef USE_PAM
#include "xmalloc.h"
#include "log.h"
#include "auth.h"
#include "auth-options.h"
#include "auth-pam.h"
#include "servconf.h"
#include "canohost.h"
#include "compat.h"
#include "misc.h"
#include "sshlogin.h"
#include "monitor_wrap.h"
#include <security/pam_appl.h>
extern char *__progname;
extern int use_privsep;
extern ServerOptions options;
extern Authmethod method_kbdint;
RCSID("$Id: auth-pam.c,v 1.54 2002/07/28 20:24:08 stevesk Exp $");
#pragma ident "%Z%%M% %I% %E% SMI"
#define NEW_AUTHTOK_MSG \
"Warning: Your password has expired, please change it now."
#define NEW_AUTHTOK_MSG_PRIVSEP \
"Your password has expired, the session cannot proceed."
/* PAM conversation for non-interactive userauth methods */
static void do_pam_cleanup_proc(void *context);
/* PAM conversation for non-interactive userauth methods */
(int (*)())do_pam_conversation,
};
static
char *
{
if (!authctxt)
return "(unknown)";
if (!compat20)
"(sshv1-unknown)";
return "(sshv2-unknown)";
}
const
char *
{
if (!method_name)
fatal("Userauth method unknown while starting PAM");
/* For SSHv2 we use "sshd-<userauth name> */
return "sshd-none";
}
return "sshd-password";
}
/* "keyboard-interactive" is too long, shorten it */
return "sshd-kbdint";
}
/* "publickey" is too long, shorten it */
return "sshd-pubkey";
}
/* "hostbased" can't really be shortened... */
return "sshd-hostbased";
}
/* "hostbased" can't really be shortened... */
return "sshd-gssapi";
}
}
return "sshd-v1"; /* SSHv1 doesn't get to be so cool */
}
void
{
int retval;
fatal("Internal error during userauth");
fatal("Userauth method unknown while starting PAM");
/* PAM service selected here */
/* Cleanup previous PAM state */
}
/*
* pam->last_pam_retval has to be and is considered
* along with pam->state.
*
* pam->state = 0; -> no PAM auth, account, etc, work
* done yet. (Set by memset() above.)
*
* pam->last_pam_retval = PAM_SUCCESS; -> meaningless at
* this point.
*
* See finish_userauth_do_pam() below.
*/
if (__pam_msg) {
}
fatal("PAM initialization failed during %s userauth",
}
fatal_add_cleanup((void (*)(void *)) &do_pam_cleanup_proc,
fatal("Could not set PAM_RHOST item during %s userauth",
}
fatal("Could not set PAM_TTY item during %s userauth",
}
}
/*
* To be called from userauth methods, directly (as in keyboard-interactive) or
* indirectly (from auth_pam_password() or from do_pam_non_initial_userauth().
*
* The caller is responsible for calling new_start_pam() first.
*
* PAM state is not cleaned up here on error. This is left to subsequent calls
* to new_start_pam() or to the cleanup function upon authentication error.
*/
int
{
int retval;
/* Various checks; fail gracefully */
return PAM_SYSTEM_ERR; /* shouldn't happen */
if (compat20) {
return PAM_SYSTEM_ERR; /* shouldn't happen */
return PAM_SYSTEM_ERR; /* shouldn't happen */
if (AUTHPAM_DONE(authctxt))
return PAM_SYSTEM_ERR; /* shouldn't happen */
if (retval == PAM_NEW_AUTHTOK_REQD) {
return retval;
}
if (retval != PAM_SUCCESS)
return retval;
}
/*
* Handle PAM_USER change, if any.
*
* We do this before pam_open_session() because we need the PAM_USER's
* UID for:
*
* a) PermitRootLogin checking
* b) to get at the lastlog entry before pam_open_session() updates it.
*/
if (retval != PAM_SUCCESS) {
fatal("PAM failure: pam_get_item(PAM_USER) "
"returned %d: %.200s", retval,
}
debug("PAM set NULL PAM_USER");
return PAM_PERM_DENIED;
}
log("PAM changed the SSH username");
}
debug2("PAM set PAM_USER to unknown user");
/*
* Return success, userauth_finish() will catch
* this and send back a failure message.
*/
return PAM_SUCCESS;
}
/* Check PermitRootLogin semantics */
return PAM_PERM_DENIED;
if (retval != PAM_SUCCESS)
return retval;
#ifdef GSSAPI
/*
* Store GSS-API delegated creds after pam_setcred(), which may
* have set the current credential store.
*/
#endif /* GSSAPI */
}
/*
* On Solaris pam_unix_session.so updates the lastlog, but does
* not converse a PAM_TEXT_INFO message about it. So we need to
* fetch the lastlog entry here and save it for use later.
*/
sizeof(authctxt->last_login_host));
if (retval != PAM_SUCCESS)
return retval;
}
/*
* All PAM work done successfully.
*
* PAM handle stays around so we can call pam_close_session() on
* it later.
*/
return PAM_SUCCESS;
}
/*
* PAM conversation function for non-interactive userauth methods that
* really cannot do any prompting. Password userauth and CHANGEREQ can
* always set the PAM_AUTHTOK and PAM_OLDAUTHTOK items to avoid
* conversation (and if they do and nonetheless some module tries to
* converse, then password userauth / CHANGEREQ MUST fail).
*
* Except, PAM_TEXT_INFO and PAM_ERROR_MSG prompts can be squirelled
* away and shown to the user later.
*
* Keyboard-interactive userauth has its own much more interesting
* conversation function.
*
*/
static int
{
struct pam_response *reply;
int count;
/* PAM will free this later */
/*
* We can't use stdio yet, queue messages for
* printing later
*/
case PAM_PROMPT_ECHO_ON:
return PAM_CONV_ERR;
case PAM_PROMPT_ECHO_OFF:
return PAM_CONV_ERR;
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
}
break;
default:
return PAM_CONV_ERR;
}
}
return PAM_SUCCESS;
}
/* Called at exit to cleanly shutdown PAM */
static void
do_pam_cleanup_proc(void *context)
{
int pam_retval;
return;
}
return;
/*
* We're in fatal_cleanup() or not in userauth or without a
* channel -- can't converse now, too bad.
*/
if (pam_retval != PAM_SUCCESS) {
log("Cannot remove PAM conv, close session or delete creds[%d]: %.200s",
goto cleanup;
}
if (pam_retval != PAM_SUCCESS)
log("Cannot close PAM session[%d]: %.200s",
}
if (pam_retval != PAM_SUCCESS)
debug("Cannot delete credentials[%d]: %.200s",
}
/* Use the previous PAM result, if not PAM_SUCCESS for pam_end() */
else if (pam_retval != PAM_SUCCESS)
else
if (pam_retval != PAM_SUCCESS)
log("Cannot release PAM authentication[%d]: %.200s",
}
/* Attempt password authentation using PAM */
int
{
int retval;
/* Ensure we have a fresh PAM handle / state */
if (retval != PAM_SUCCESS)
return 1;
options.permit_empty_passwd ? 0 :
if (retval != PAM_SUCCESS)
return 0;
return 0;
return 1;
}
int
{
}
/* Cleanly shutdown PAM */
{
}
static
char **
{
char **p;
int len;
else
return (p);
}
return (NULL);
}
/* Return list of PAM environment strings */
char **
{
#ifdef HAVE_PAM_GETENVLIST
char **penv;
return (NULL);
return (penv);
#else /* HAVE_PAM_GETENVLIST */
return(NULL);
#endif /* HAVE_PAM_GETENVLIST */
}
void free_pam_environment(char **env)
{
int i;
}
}
/* Print any messages that have been generated during authentication */
/* or account checking to stderr */
void print_pam_messages(void)
{
}
/* Append a message to buffer */
void message_cat(char **p, const char *a)
{
char *cp;
if (*p) {
} else
}
#endif /* USE_PAM */