238 lines
8.5 KiB
C
238 lines
8.5 KiB
C
/*
|
|
* Copyright (c) 2008, Jamie Beverly.
|
|
* 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 Jamie Beverly ``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 Jamie Beverly 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.
|
|
*
|
|
* The views and conclusions contained in the software and documentation are those of the
|
|
* authors and should not be interpreted as representing official policies, either expressed
|
|
* or implied, of Jamie Beverly.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <syslog.h>
|
|
|
|
#ifdef HAVE_SECURITY_PAM_APPL_H
|
|
|
|
#include <security/pam_appl.h>
|
|
#define PAM_SM_AUTH
|
|
#include <security/pam_modules.h>
|
|
|
|
#elif HAVE_PAM_PAM_APPL_H
|
|
|
|
#include <pam/pam_appl.h>
|
|
#define PAM_SM_AUTH
|
|
#include <pam/pam_modules.h>
|
|
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
#include <strings.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <pwd.h>
|
|
#include <unistd.h>
|
|
#include "iterate_ssh_agent_keys.h"
|
|
#include "includes.h"
|
|
#include "log.h"
|
|
#include "ssh.h"
|
|
#include "pam_static_macros.h"
|
|
#include "pam_user_authorized_keys.h"
|
|
|
|
#define strncasecmp_literal(A,B) strncasecmp( A, B, sizeof(B) - 1)
|
|
#define UNUSED(expr) do { (void)(expr); } while (0)
|
|
|
|
char *authorized_keys_file = NULL;
|
|
uint8_t allow_user_owned_authorized_keys_file = 0;
|
|
char *authorized_keys_command = NULL;
|
|
char *authorized_keys_command_user = NULL;
|
|
|
|
#if ! HAVE___PROGNAME || HAVE_BUNDLE
|
|
char *__progname;
|
|
#else
|
|
extern char *__progname;
|
|
#endif
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
|
|
{
|
|
char **argv_ptr;
|
|
const char *user = NULL;
|
|
char *ruser_ptr = NULL;
|
|
char *servicename = NULL;
|
|
char *authorized_keys_file_input = NULL;
|
|
char sudo_service_name[128] = "sudo";
|
|
char ruser[128] = "";
|
|
|
|
int i = 0;
|
|
int retval = PAM_AUTH_ERR;
|
|
|
|
LogLevel log_lvl = SYSLOG_LEVEL_INFO;
|
|
SyslogFacility facility = SYSLOG_FACILITY_AUTH;
|
|
|
|
#ifdef LOG_AUTHPRIV
|
|
facility = SYSLOG_FACILITY_AUTHPRIV;
|
|
#endif
|
|
|
|
UNUSED(flags);
|
|
pam_get_item(pamh, PAM_SERVICE, (void *) &servicename);
|
|
/*
|
|
* XXX:
|
|
* When testing on MacOS (and I presume them same would be true on other a.out systems)
|
|
* I tried '-undefined supress -flat_namespace', but then rather than compilation errors, I
|
|
* received dl_open errors about the unresolvable symbol. So I just made my own symbol, and it
|
|
* works quite nicely... if you know of a better way than this kludge, I'd be most appreciative for
|
|
* a patch 8-)
|
|
*/
|
|
#if ! HAVE___PROGNAME || HAVE_BUNDLE
|
|
__progname = pamsshagentauth_xstrdup(servicename);
|
|
#endif
|
|
|
|
for(i = argc, argv_ptr = (char **) argv; i > 0; ++argv_ptr, i--) {
|
|
if(strncasecmp_literal(*argv_ptr, "debug") == 0) {
|
|
log_lvl = SYSLOG_LEVEL_DEBUG3;
|
|
}
|
|
if(strncasecmp_literal(*argv_ptr, "allow_user_owned_authorized_keys_file") == 0) {
|
|
allow_user_owned_authorized_keys_file = 1;
|
|
}
|
|
if(strncasecmp_literal(*argv_ptr, "file=") == 0 ) {
|
|
authorized_keys_file_input = *argv_ptr + sizeof("file=") - 1;
|
|
}
|
|
if(strncasecmp_literal(*argv_ptr, "authorized_keys_command=") == 0 ) {
|
|
authorized_keys_command = *argv_ptr + sizeof("authorized_keys_command=") - 1;
|
|
}
|
|
if(strncasecmp_literal(*argv_ptr, "authorized_keys_command_user=") == 0 ) {
|
|
authorized_keys_command_user = *argv_ptr + sizeof("authorized_keys_command_user=") - 1;
|
|
}
|
|
#ifdef ENABLE_SUDO_HACK
|
|
if(strncasecmp_literal(*argv_ptr, "sudo_service_name=") == 0) {
|
|
strncpy( sudo_service_name, *argv_ptr + sizeof("sudo_service_name=") - 1, sizeof(sudo_service_name) - 1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
pamsshagentauth_log_init(__progname, log_lvl, facility, 0);
|
|
pam_get_item(pamh, PAM_USER, (void *) &user);
|
|
pam_get_item(pamh, PAM_RUSER, (void *) &ruser_ptr);
|
|
|
|
pamsshagentauth_verbose("Beginning pam_ssh_agent_auth for user %s", user);
|
|
|
|
if(ruser_ptr) {
|
|
strncpy(ruser, ruser_ptr, sizeof(ruser) - 1);
|
|
} else {
|
|
/*
|
|
* XXX: XXX: XXX: XXX: XXX: XXX: XXX: XXX: XXX:
|
|
* This is a kludge to address a bug in sudo wherein PAM_RUSER is left unset at the time
|
|
* pam_authenticate is called, and so we cannot reliably know who invoked the process except
|
|
* via the SUDO_USER environment variable. I've submitted a patch to sudo which fixes this,
|
|
* and so this should not be enabled with versions of sudo which contain it.
|
|
*/
|
|
#ifdef ENABLE_SUDO_HACK
|
|
if( (strlen(sudo_service_name) > 0) && strncasecmp(servicename, sudo_service_name, sizeof(sudo_service_name) - 1) == 0 && getenv("SUDO_USER") ) {
|
|
strncpy(ruser, getenv("SUDO_USER"), sizeof(ruser) - 1 );
|
|
pamsshagentauth_verbose( "Using environment variable SUDO_USER (%s)", ruser );
|
|
} else
|
|
#endif
|
|
{
|
|
if( ! getpwuid(getuid()) ) {
|
|
pamsshagentauth_verbose("Unable to getpwuid(getuid())");
|
|
goto cleanexit;
|
|
}
|
|
strncpy(ruser, getpwuid(getuid())->pw_name, sizeof(ruser) - 1);
|
|
}
|
|
}
|
|
|
|
/* Might as well explicitely confirm the user exists here */
|
|
if(! getpwnam(ruser) ) {
|
|
pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", ruser);
|
|
goto cleanexit;
|
|
}
|
|
if( ! getpwnam(user) ) {
|
|
pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", user);
|
|
goto cleanexit;
|
|
}
|
|
|
|
if(authorized_keys_file_input && user) {
|
|
/*
|
|
* user is the name of the target-user, and so must be used for validating the authorized_keys file
|
|
*/
|
|
parse_authorized_key_file(user, authorized_keys_file_input);
|
|
} else {
|
|
pamsshagentauth_verbose("Using default file=/etc/security/authorized_keys");
|
|
authorized_keys_file = pamsshagentauth_xstrdup("/etc/security/authorized_keys");
|
|
}
|
|
|
|
/*
|
|
* PAM_USER and PAM_RUSER do not necessarily have to get set by the calling application, and we may be unable to divine the latter.
|
|
* In those cases we should fail
|
|
*/
|
|
|
|
if(user && strlen(ruser) > 0) {
|
|
pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file);
|
|
|
|
/*
|
|
* this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user
|
|
*/
|
|
if(pamsshagentauth_find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */
|
|
pamsshagentauth_logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file);
|
|
retval = PAM_SUCCESS;
|
|
} else {
|
|
pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file);
|
|
}
|
|
} else {
|
|
pamsshagentauth_logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" );
|
|
}
|
|
|
|
cleanexit:
|
|
|
|
#if ! HAVE___PROGNAME || HAVE_BUNDLE
|
|
free(__progname);
|
|
#endif
|
|
|
|
free(authorized_keys_file);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv)
|
|
{
|
|
UNUSED(pamh);
|
|
UNUSED(flags);
|
|
UNUSED(argc);
|
|
UNUSED(argv);
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
#ifdef PAM_STATIC
|
|
struct pam_module _pam_ssh_agent_auth_modstruct = {
|
|
"pam_ssh_agent_auth",
|
|
pam_sm_authenticate,
|
|
pam_sm_setcred,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
#endif
|