auth.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 2000 Markus Friedl. 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"
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef HAVE_LOGIN_H
#include <login.h>
#endif
#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
#include <shadow.h>
#endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
#endif
#include "xmalloc.h"
#include "match.h"
#include "groupaccess.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
#include "auth-options.h"
#include "canohost.h"
#include "buffer.h"
#include "bufaux.h"
#include "uidswap.h"
#include "tildexpand.h"
#include "misc.h"
#include "bufaux.h"
#include "packet.h"
#ifdef HAVE_BSM
#include "bsmaudit.h"
#endif /* HAVE_BSM */
/* import */
extern ServerOptions options;
/* Debugging messages */
int auth_debug_init;
/*
* Check if the user is allowed to log in via ssh. If user is listed
* in DenyUsers or one of user's groups is listed in DenyGroups, false
* will be returned. If AllowUsers isn't empty and user isn't listed
* there, or if AllowGroups isn't empty and one of user's groups isn't
* listed there, false will be returned.
* If the user's shell is not executable, false will be returned.
* Otherwise true is returned.
*/
int
{
char *shell;
int i;
#ifdef WITH_AIXAUTHENTICATE
char *loginmsg;
#endif /* WITH_AIXAUTHENTICATE */
#if !defined(USE_PAM) && defined(HAVE_SHADOW_H) && \
!defined(DISABLE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
return 0;
debug3("allowed_user: today %d sp_expire %d sp_lstchg %d"
/*
* We assume account and password expiration occurs the
* day after the day specified.
*/
return 0;
}
log("User %.100s password has expired (root forced)",
return 0;
}
log("User %.100s password has expired (password aged)",
return 0;
}
}
#else
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
return 0;
#endif
/*
* Get the shell from the password data. An empty shell field is
*/
/* deny if shell does not exists or is not executable */
log("User %.100s not allowed because shell %.100s does not exist",
return 0;
}
log("User %.100s not allowed because shell %.100s is not executable",
return 0;
}
ipaddr = get_remote_ipaddr();
}
/* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) {
for (i = 0; i < options.num_deny_users; i++)
options.deny_users[i])) {
log("User %.100s not allowed because listed in DenyUsers",
return 0;
}
}
/* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) {
for (i = 0; i < options.num_allow_users; i++)
options.allow_users[i]))
break;
/* i < options.num_allow_users iff we break for loop */
if (i >= options.num_allow_users) {
log("User %.100s not allowed because not listed in AllowUsers",
return 0;
}
}
/* Get the user's group access list (primary and supplementary) */
log("User %.100s not allowed because not in any group",
return 0;
}
/* Return false if one of user's groups is listed in DenyGroups */
if (options.num_deny_groups > 0)
ga_free();
log("User %.100s not allowed because a group is listed in DenyGroups",
return 0;
}
/*
* Return false if AllowGroups isn't empty and one of user's groups
* isn't listed there
*/
if (options.num_allow_groups > 0)
ga_free();
log("User %.100s not allowed because none of user's groups are listed in AllowGroups",
return 0;
}
ga_free();
}
#ifdef WITH_AIXAUTHENTICATE
/* Remove embedded newlines (if any) */
char *p;
for (p = loginmsg; *p; p++) {
if (*p == '\n')
*p = ' ';
}
/* Remove trailing newline */
*--p = '\0';
}
return 0;
}
#endif /* WITH_AIXAUTHENTICATE */
/* We found no reason not to let this user try to log on... */
return 1;
}
Authctxt *
authctxt_new(void)
{
return authctxt;
}
void
{
/* Raise logging level */
authmsg = "Failed";
authmsg = "Abandoned";
authmsg = "Partially accepted";
else
authmsg = "Accepted";
}
else
authmsg = "Failed";
}
else {
}
user_str = "<implicit>";
user_str = "<invalid username>";
else
authlog("%s %s for %s from %.200s port %d%s",
info);
#ifdef WITH_AIXAUTHENTICATE
"ssh");
#endif /* WITH_AIXAUTHENTICATE */
}
#ifdef HAVE_BSM
void
audit_failed_login_cleanup(void *ctxt)
{
/* Internal error */
else
}
#endif /* HAVE_BSM */
/*
* Check whether root logins are disallowed.
*/
int
auth_root_allowed(char *method)
{
switch (options.permit_root_login) {
case PERMIT_YES:
return 1;
break;
case PERMIT_NO_PASSWD:
return 1;
break;
case PERMIT_FORCED_ONLY:
if (forced_command) {
log("Root login accepted for forced command.");
return 1;
}
break;
}
return 0;
}
/*
* Given a template and a passwd structure, build a filename
* by substituting % tokenised options. Currently, %% becomes '%',
* %h becomes the home directory and %u the username.
*
* This returns a buffer allocated by xmalloc.
*/
char *
{
char *file;
const char *cp;
if (pw == 0)
return NULL; /* shouldn't happen */
/*
* Build the filename string in the buffer by making the appropriate
* substitutions to the given file name.
*/
cp++;
continue;
}
cp++;
continue;
}
cp++;
continue;
}
}
/*
* Ensure that filename starts anchored. If not, be backward
* compatible and prepend the '%h/'
*/
if (*cp != '/')
else
return file;
}
char *
{
}
char *
{
}
/* return ok if key exists in sysfile or userfile */
{
char *user_hostfile;
/* Check if we know the host and its host key. */
if (options.strict_modes &&
log("Authentication refused for %.100s: "
"bad owner or modes for %.200s",
} else {
restore_uid();
}
}
return host_status;
}
/*
* Check a given file for security. This is defined as all components
* of the path to the file must be owned by either the owner of
* of the file or root and no directories must be group or world writable.
*
* XXX Should any specific check be done for sym links ?
*
* Takes an open file descriptor, the file name, a uid and and
* error buffer plus max size as arguments.
*
* Returns 0 on success and -1 on failure
*/
int
{
char *cp;
return 0;
return -1;
}
return -1;
}
/* check the open file to avoid races */
buf);
return -1;
}
/* for each component of the canonical path, walking upwards */
for (;;) {
return -1;
}
"bad ownership or modes for directory %s", buf);
return -1;
}
/* If are passed the homedir then we can stop */
debug3("secure_filename: terminating check at '%s'",
buf);
break;
}
/*
* dirname should always complete with a "/" path,
* but we can be paranoid and check for "." too
*/
break;
}
return 0;
}
struct passwd *
getpwnamallow(const char *user)
{
#ifdef HAVE_LOGIN_CAP
extern login_cap_t *lc;
#ifdef BSD_AUTH
#endif
#endif
return (NULL); /* implicit user, will be set later */
log("Illegal user %.100s from %.100s",
user, get_remote_ipaddr());
return (NULL);
}
if (!allowed_user(pw))
return (NULL);
#ifdef HAVE_LOGIN_CAP
return (NULL);
}
#ifdef BSD_AUTH
}
auth_close(as);
#endif
#endif
return (NULL);
}
void
auth_debug_add(const char *fmt,...)
{
char buf[1024];
if (!auth_debug_init)
return;
}
void
auth_debug_send(void)
{
char *msg;
if (!auth_debug_init)
return;
while (buffer_len(&auth_debug)) {
}
}
void
auth_debug_reset(void)
{
if (auth_debug_init)
else {
auth_debug_init = 1;
}
}