From b0695cc9f5478daa14d3f451ecdd39ba6e6abe0f Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Tue, 19 Jan 2016 15:29:22 +0100
Subject: [PATCH] authorized_keys_command
---
pam_ssh_agent_auth-0.9.3/CONTRIBUTORS | 2 +
pam_ssh_agent_auth-0.9.3/Makefile.in | 28 +-
pam_ssh_agent_auth-0.9.3/README | 38 +++
pam_ssh_agent_auth-0.9.3/configure.ac | 27 +-
pam_ssh_agent_auth-0.9.3/get_command_line.c | 113 +++++++
pam_ssh_agent_auth-0.9.3/get_command_line.h | 40 +++
pam_ssh_agent_auth-0.9.3/identity.h | 24 ++
pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c | 137 ++++++++-
pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h | 2 +-
pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c | 16 +-
pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod | 50 ++-
pam_ssh_agent_auth-0.9.3/pam_static_macros.h | 29 ++
.../pam_user_authorized_keys.c | 23 +-
.../pam_user_authorized_keys.h | 2 +-
pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c | 334 ++++++++++++++++-----
pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h | 3 +-
pam_ssh_agent_auth-0.9.3/secure_filename.c | 51 +++-
pam_ssh_agent_auth-0.9.3/secure_filename.h | 4 +-
pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c | 20 +-
pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h | 2 +-
20 files changed, 805 insertions(+), 140 deletions(-)
create mode 100644 pam_ssh_agent_auth-0.9.3/README
create mode 100644 pam_ssh_agent_auth-0.9.3/get_command_line.c
create mode 100644 pam_ssh_agent_auth-0.9.3/get_command_line.h
diff --git a/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS b/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS
index d5a21cb..22b424a 100644
--- a/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS
+++ b/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS
@@ -1,3 +1,5 @@
* Foremost, OpenSSH from which this project is derived.
* Jamie Beverly
* Rafael D'Halleweyn - 2011-06-05 18:56:24 EDT
+* Jan-Pieter Cornet ( johnpc ) - 2012-03-23 03:25:52 PDT
+* chrysn@fsfe.org
diff --git a/pam_ssh_agent_auth-0.9.3/Makefile.in b/pam_ssh_agent_auth-0.9.3/Makefile.in
index 47bb103..4977838 100644
--- a/pam_ssh_agent_auth-0.9.3/Makefile.in
+++ b/pam_ssh_agent_auth-0.9.3/Makefile.in
@@ -1,4 +1,28 @@
# $Id: Makefile.in,v 1.289 2008/03/13 01:41:31 djm Exp $
+#
+# Copyright (c) 2000 Markus Friedl. All rights reserved.
+# Modifications Copyright (c) 2008-2014 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 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.
+#
# uncomment if you run a non bourne compatable shell. Ie. csh
#SHELL = @SH@
@@ -46,9 +70,9 @@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
PAM_MODULES=pam_ssh_agent_auth.so
-SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o
+SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o uidswap.o
-PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o
+PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o get_command_line.o
MANPAGES_IN = pam_ssh_agent_auth.pod
diff --git a/pam_ssh_agent_auth-0.9.3/README b/pam_ssh_agent_auth-0.9.3/README
new file mode 100644
index 0000000..c1a49ef
--- /dev/null
+++ b/pam_ssh_agent_auth-0.9.3/README
@@ -0,0 +1,38 @@
+pam_ssh_agent_auth is a PAM module which permits PAM authentication via your
+keyring in a forwarded ssh-agent.
+
+Release 0.10.1 is stable, and has been tested on FreeBSD, Solaris 10, Solaris 11,
+RHEL5, RHEL6, Debian Wheezy, Ubuntu 12.04 (LTS), Ubuntu 13.10,
+and MacOS X 10.7.
+
+This module can be used to provide authentication for anything run locally that
+supports PAM. It was written specifically with the intention of permitting
+authentication for sudo without password entry, and also has been proven useful
+for use with su as an alternative to wheel.
+
+It serves as middle ground between the two most common, and suboptimal
+alternatives for large-scale system administration: allowing rootlogin via ssh,
+or using NOPASSWD in sudoers. This module allows for ssh public-key
+authentication, and it does this by leveraging an authentication mechanism you
+are probably already using, ssh-agent.
+
+There are caveats of course, ssh-agent forwarding has it’s own security risks
+which must be carefully considered for your environment. In cases where there
+are not untrustworthy intermediate servers, and you wish to retain traceability,
+accountability, and required authentication for privileged command invocation,
+the benefits should outweigh the risks. Release 0.10.1 can be downloaded from
+SourceForge: https://sourceforge.net/project/showfiles.php?group_id=249556
+
+If you encounter any issues with usability or security, please use the project's
+SourceForge tracker:
+https://sourceforge.net/tracker2/?group_id=249556&atid=1126337
+
+Note that if you wish to use this for sudo, you will need a version of sudo that
+preserves the env_keep environment during authentication; and ideally a version
+incorporating my minor patch which ensures RUSER is set during PAM authentication.
+
+sudo 1.6.8p12 does not work correctly with this PAM module, because it clears the
+environment (even env_keep variables) prior to attempting PAM authentication.
+
+sudo 1.7.2p1 or later is preferred, as it correctly sets PAM_RUSER for
+authentication.
diff --git a/pam_ssh_agent_auth-0.9.3/configure.ac b/pam_ssh_agent_auth-0.9.3/configure.ac
index 1f372ce..4eb1f32 100644
--- a/pam_ssh_agent_auth-0.9.3/configure.ac
+++ b/pam_ssh_agent_auth-0.9.3/configure.ac
@@ -18,8 +18,10 @@ AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org)
AC_REVISION($Revision: 1.397 $)
AC_CONFIG_SRCDIR([pam_ssh_agent_auth.c])
-AC_CONFIG_HEADER(config.h)
+AC_CONFIG_SRCDIR([config.h.in])
+AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
+AC_C_INLINE
AC_CANONICAL_HOST
AC_C_BIGENDIAN
@@ -117,7 +119,6 @@ if test -z "$LD" ; then
fi
AC_SUBST(LD)
-AC_C_INLINE
AC_CHECK_DECL(LLONG_MAX, have_llong_max=1, , [#include <limits.h>])
@@ -151,7 +152,7 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
;;
2.*) no_attrib_nonnull=1 ;;
3.*) CFLAGS="$CFLAGS -Wsign-compare" ;;
- 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;;
+ 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wall -Wextra" ;;
*) ;;
esac
@@ -1656,11 +1657,11 @@ fi
if test "x$check_for_conflicting_getspnam" = "x1"; then
AC_MSG_CHECKING(for conflicting getspnam in shadow.h)
- AC_COMPILE_IFELSE(
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[
#include <shadow.h>
int main(void) {exit(0);}
- ],
+ ])],
[
AC_MSG_RESULT(no)
],
@@ -2720,7 +2721,7 @@ fi
dnl make sure we're using the real structure members and not defines
AC_CACHE_CHECK([for msg_accrights field in struct msghdr],
ac_cv_have_accrights_in_msghdr, [
- AC_COMPILE_IFELSE(
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[
#include <sys/types.h>
#include <sys/socket.h>
@@ -2734,7 +2735,7 @@ struct msghdr m;
m.msg_accrights = 0;
exit(0);
}
- ],
+ ])],
[ ac_cv_have_accrights_in_msghdr="yes" ],
[ ac_cv_have_accrights_in_msghdr="no" ]
)
@@ -2747,7 +2748,7 @@ fi
AC_CACHE_CHECK([for msg_control field in struct msghdr],
ac_cv_have_control_in_msghdr, [
- AC_COMPILE_IFELSE(
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[
#include <sys/types.h>
#include <sys/socket.h>
@@ -2761,7 +2762,7 @@ struct msghdr m;
m.msg_control = 0;
exit(0);
}
- ],
+ ])],
[ ac_cv_have_control_in_msghdr="yes" ],
[ ac_cv_have_control_in_msghdr="no" ]
)
@@ -2891,14 +2892,14 @@ AC_SEARCH_LIBS(getrrsetbyname, resolv,
saved_LIBS="$LIBS"
LIBS="$LIBS -lresolv"
AC_MSG_CHECKING(for res_query in -lresolv)
- AC_LINK_IFELSE([
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <resolv.h>
int main()
{
res_query (0, 0, 0, 0, 0);
return 0;
}
- ],
+ ])],
[LIBS="$LIBS -lresolv"
AC_MSG_RESULT(yes)],
[LIBS="$saved_LIBS"
@@ -2915,7 +2916,7 @@ int main()
])
AC_MSG_CHECKING(if struct __res_state _res is an extern)
-AC_LINK_IFELSE([
+AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
@@ -2925,7 +2926,7 @@ AC_LINK_IFELSE([
#include <resolv.h>
extern struct __res_state _res;
int main() { return 0; }
- ],
+ ])],
[AC_MSG_RESULT(yes)
AC_DEFINE(HAVE__RES_EXTERN, 1,
[Define if you have struct __res_state _res as an extern])
diff --git a/pam_ssh_agent_auth-0.9.3/get_command_line.c b/pam_ssh_agent_auth-0.9.3/get_command_line.c
new file mode 100644
index 0000000..e880fee
--- /dev/null
+++ b/pam_ssh_agent_auth-0.9.3/get_command_line.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, 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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "includes.h"
+#include "xmalloc.h"
+#include "get_command_line.h"
+
+#ifdef HAVE_PROC_PID_CMDLINE
+
+static size_t
+proc_pid_cmdline(char *** inargv)
+{
+ pid_t pid;
+ FILE *f = NULL;
+ char filename[64] = { 0 }, c = '\0';
+ char ** argv;
+ char argbuf[MAX_LEN_PER_CMDLINE_ARG + 1] = { 0 };
+ size_t count = 0, len = 0;
+
+ pid = getpid();
+ argv = NULL;
+
+ snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
+ f = fopen(filename, "r");
+
+ if (f) {
+ while (!feof(f) && count < MAX_CMDLINE_ARGS) {
+ if (len > MAX_LEN_PER_CMDLINE_ARG) {
+ while (!feof(f) && (c = fgetc(f)) != '\0');
+ }
+ else {
+ c = fgetc(f);
+ }
+ switch (c) {
+ case EOF:
+ case '\0':
+ if (len > 0) {
+ argv = xrealloc(argv, count + 1, sizeof(*argv));
+ argv[count] = xcalloc(len + 1, sizeof(*argv[count]));
+ strncpy(argv[count++], argbuf, len);
+ memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1);
+ len = 0;
+ }
+ break;
+ default:
+ argbuf[len++] = c;
+ break;
+ }
+ }
+ fclose(f);
+ }
+ *inargv = argv;
+ return count;
+}
+#endif
+
+
+/*
+ * takes a pointer to an unallocated array of arrays of strings, populates the
+ * given pointer with the address of the allocated array of strings collected
+ */
+size_t
+pamsshagentauth_get_command_line(char *** argv)
+{
+#ifdef HAVE_PROC_PID_CMDLINE
+ return proc_pid_cmdline(argv);
+#else
+ /* No other supported implementations at this time */
+ return 0;
+#endif
+}
+
+void
+pamsshagentauth_free_command_line(char ** argv, size_t n_args)
+{
+ size_t i;
+ for (i = 0; i < n_args; i++)
+ free(argv[i]);
+
+ free(argv);
+ return;
+}
+
diff --git a/pam_ssh_agent_auth-0.9.3/get_command_line.h b/pam_ssh_agent_auth-0.9.3/get_command_line.h
new file mode 100644
index 0000000..37cd077
--- /dev/null
+++ b/pam_ssh_agent_auth-0.9.3/get_command_line.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef _GET_COMMAND_LINE_H
+#define _GET_COMMAND_LINE_H
+
+#include "includes.h"
+
+size_t pamsshagentauth_get_command_line(char ***);
+void pamsshagentauth_free_command_line(char **, size_t);
+#define MAX_CMDLINE_ARGS 255
+#define MAX_LEN_PER_CMDLINE_ARG 255
+
+#endif
diff --git a/pam_ssh_agent_auth-0.9.3/identity.h b/pam_ssh_agent_auth-0.9.3/identity.h
index eb21320..0bde782 100644
--- a/pam_ssh_agent_auth-0.9.3/identity.h
+++ b/pam_ssh_agent_auth-0.9.3/identity.h
@@ -1,3 +1,27 @@
+/*
+ * 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
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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.
+ */
+
#ifndef _IDENTITY_H
#define _IDENTITY_H
#include "includes.h"
diff --git a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c
index 11ab6e2..6b4d531 100644
--- a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c
+++ b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c
@@ -28,6 +28,8 @@
*/
+#include <string.h>
+
#include "includes.h"
#include "config.h"
@@ -48,26 +50,75 @@
#include <errno.h>
#include <fcntl.h>
#include <openssl/evp.h>
+#include "ssh2.h"
+#include "misc.h"
#include "userauth_pubkey_from_id.h"
#include "identity.h"
+#include "get_command_line.h"
+extern char **environ;
+
+#define PAM_SSH_AGENT_AUTH_REQUESTv1 101
+
+static char *
+log_action(char ** action, size_t count)
+{
+ size_t i;
+ char *buf = NULL;
+
+ if (count == 0)
+ return NULL;
+
+ buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf));
+ for (i = 0; i < count; i++) {
+ strcat(buf, (i > 0) ? " '" : "'");
+ strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG);
+ strcat(buf, "'");
+ }
+ return buf;
+}
+
+void
+agent_action(Buffer *buf, char ** action, size_t count)
+{
+ size_t i;
+ buffer_init(buf);
-u_char * session_id2 = NULL;
-uint8_t session_id_len = 0;
+ buffer_put_int(buf, count);
+
+ for (i = 0; i < count; i++) {
+ buffer_put_cstring(buf, action[i]);
+ }
+}
-u_char *
-session_id2_gen()
+void
+session_id2_gen(Buffer * session_id2, const char * user,
+ const char * ruser, const char * servicename)
{
char *cookie = NULL;
uint8_t i = 0;
uint32_t rnd = 0;
+ uint8_t cookie_len;
+ char hostname[256] = { 0 };
+ char pwd[1024] = { 0 };
+ time_t ts;
+ char ** reported_argv = NULL;
+ size_t count = 0;
+ char * action_logbuf = NULL;
+ Buffer action_agentbuf;
+ uint8_t free_logbuf = 0;
+ char * retc;
+ int32_t reti;
rnd = arc4random();
- session_id_len = (uint8_t) rnd;
+ cookie_len = ((uint8_t) rnd);
+ while (cookie_len < 16) {
+ cookie_len += 16; /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */
+ }
- cookie = calloc(1,session_id_len);
+ cookie = xcalloc(1, cookie_len);
- for (i = 0; i < session_id_len; i++) {
+ for (i = 0; i < cookie_len; i++) {
if (i % 4 == 0) {
rnd = arc4random();
}
@@ -75,7 +126,64 @@ session_id2_gen()
rnd >>= 8;
}
- return cookie;
+ count = pamsshagentauth_get_command_line(&reported_argv);
+ if (count > 0) {
+ free_logbuf = 1;
+ action_logbuf = log_action(reported_argv, count);
+ agent_action(&action_agentbuf, reported_argv, count);
+ pamsshagentauth_free_command_line(reported_argv, count);
+ }
+ else {
+ action_logbuf = "unknown on this platform";
+ buffer_init(&action_agentbuf); /* stays empty, means unavailable */
+ }
+
+ /*
+ action = getenv("SUDO_COMMAND");
+ if(!action) {
+ action = getenv("PAM_AUTHORIZED_ACTION");
+ if(!action) {
+ action = empty;
+ }
+ }
+ */
+
+ reti = gethostname(hostname, sizeof(hostname) - 1);
+ retc = getcwd(pwd, sizeof(pwd) - 1);
+ time(&ts);
+
+ buffer_init(session_id2);
+
+ buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1);
+ /* debug3("cookie: %s", tohex(cookie, cookie_len)); */
+ buffer_put_string(session_id2, cookie, cookie_len);
+ /* debug3("user: %s", user); */
+ buffer_put_cstring(session_id2, user);
+ /* debug3("ruser: %s", ruser); */
+ buffer_put_cstring(session_id2, ruser);
+ /* debug3("servicename: %s", servicename); */
+ buffer_put_cstring(session_id2, servicename);
+ /* debug3("pwd: %s", pwd); */
+ if(retc)
+ buffer_put_cstring(session_id2, pwd);
+ else
+ buffer_put_cstring(session_id2, "");
+ /* debug3("action: %s", action_logbuf); */
+ buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset);
+ if (free_logbuf) {
+ free(action_logbuf);
+ buffer_free(&action_agentbuf);
+ }
+ /* debug3("hostname: %s", hostname); */
+ if(reti >= 0)
+ buffer_put_cstring(session_id2, hostname);
+ else
+ buffer_put_cstring(session_id2, "");
+ /* debug3("ts: %ld", ts); */
+ buffer_put_int64(session_id2, (uint64_t) ts);
+
+ free(cookie);
+ return;
}
/*
@@ -174,19 +282,21 @@ ssh_get_authentication_connection_for_uid(uid_t uid)
}
int
-find_authorized_keys(uid_t uid)
+find_authorized_keys(const char * user, const char * ruser, const char * servicename)
{
+ Buffer session_id2 = { 0 };
Identity *id;
Key *key;
AuthenticationConnection *ac;
char *comment;
uint8_t retval = 0;
+ uid_t uid = getpwnam(ruser)->pw_uid;
OpenSSL_add_all_digests();
- session_id2 = session_id2_gen();
+ session_id2_gen(&session_id2, user, ruser, servicename);
if ((ac = ssh_get_authentication_connection_for_uid(uid))) {
- verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid);
+ verbose("Contacted ssh-agent of user %s (%u)", ruser, uid);
for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2))
{
if(key != NULL) {
@@ -194,7 +304,7 @@ find_authorized_keys(uid_t uid)
id->key = key;
id->filename = comment;
id->ac = ac;
- if(userauth_pubkey_from_id(id)) {
+ if(userauth_pubkey_from_id(ruser, id, &session_id2)) {
retval = 1;
}
free(id->filename);
@@ -204,12 +314,13 @@ find_authorized_keys(uid_t uid)
break;
}
}
+ buffer_free(&session_id2);
ssh_close_authentication_connection(ac);
}
else {
verbose("No ssh-agent could be contacted");
}
- free(session_id2);
+ /*free(session_id2);*/
EVP_cleanup();
return retval;
}
diff --git a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h
index ed7549e..e6c75aa 100644
--- a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h
+++ b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h
@@ -31,6 +31,6 @@
#ifndef _ITERATE_SSH_AGENT_KEYS_H
#define _ITERATE_SSH_AGENT_KEYS_H
-int find_authorized_keys(uid_t);
+int find_authorized_keys(const char * user, const char * ruser, const char * servicename);
#endif
diff --git a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c
index d3f4325..37309f7 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c
+++ b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c
@@ -59,9 +59,12 @@
#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;
@@ -90,6 +93,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
facility = SYSLOG_FACILITY_AUTHPRIV;
#endif
+ UNUSED(flags);
pam_get_item(pamh, PAM_SERVICE, (void *) &servicename);
/*
* XXX:
@@ -113,6 +117,12 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
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);
@@ -182,7 +192,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
/*
* 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(find_authorized_keys(getpwnam(ruser)->pw_uid)) {
+ if(find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */
logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file);
retval = PAM_SUCCESS;
} else {
@@ -207,6 +217,10 @@ cleanexit:
PAM_EXTERN int __attribute__ ((visibility ("default")))
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;
}
diff --git a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod
index 4570746..76b1f0f 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod
+++ b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod
@@ -1,8 +1,12 @@
-=head1 PAM_SSH_AGENT_AUTH
+=head1 NAME
+
+pam_ssh_agent_auth - PAM module for granting permissions based on SSH agent requests
+
+=head1 DESCRIPTION
This module provides authentication via ssh-agent. If an ssh-agent listening at SSH_AUTH_SOCK can successfully authenticate that it has the secret key for a public key in the specified file, authentication is granted, otherwise authentication fails.
-=head1 SUMMARY
+=head1 CONFIGURATION
=over
@@ -10,7 +14,8 @@ This module provides authentication via ssh-agent. If an ssh-agent listening at
auth sufficient pam_ssh_agent_auth.so file=/etc/security/authorized_keys
=item /etc/sudoers:
-
+
+In older versions of sudo (< 1.8.5) it was necessary to set:
Defaults env_keep += "SSH_AUTH_SOCK"
=back
@@ -33,6 +38,15 @@ Specify the path to the authorized_keys file(s) you would like to use for authen
A flag which enables authorized_keys files to be owned by the invoking user, instead of root. This flag is enabled automatically whenever
the expansions %h or ~ are used.
+=item authorized_keys_command=<path to executable>
+
+Specify an external command to run, which should take a single argument, the username of the person being authenticated, and emit to its stdout a file in authorized_keys format.
+This is ideally suited for use with sssd's sss_ssh_authorizedkeys, for authenticating users via authorized_keys stored in ldap or other sssd supported security service.
+
+=item authorized_keys_command_user=<username>
+
+Specify a user to run the authorized_keys_command as. If this option is not specified, the authorized_keys_command will be run as the user being authenticated.
+
=item debug
A flag which enables verbose logging
@@ -105,4 +119,34 @@ so this file must be owned by root.
=back
+=head1 COPYRIGHT
+
+ Copyright (c) 2008-2014, Jamie Beverly.
+ And is based on openssh, and the included works by Markus Friedl, Darren Tucker,
+ Todd C. Miller, Ben Lindstrom, Tim Rice, Damien Miller, and many others.
+
+ All rights reserved.
+
+ See sources for complete attributions.
+
+ 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.
+
=cut
diff --git a/pam_ssh_agent_auth-0.9.3/pam_static_macros.h b/pam_ssh_agent_auth-0.9.3/pam_static_macros.h
index a4938d3..a991704 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_static_macros.h
+++ b/pam_ssh_agent_auth-0.9.3/pam_static_macros.h
@@ -1,3 +1,32 @@
+/*
+ * 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.
+ */
+
#ifndef __PAM_STATIC_MACROS_H
#define __PAM_STATIC_MACROS_H
diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c
index 60bef68..abc0a62 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c
+++ b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2008, Jamie Beverly.
* All rights reserved.
*
@@ -80,9 +80,15 @@
#include "identity.h"
#include "pam_user_key_allowed2.h"
-extern char *authorized_keys_file;
-extern uint8_t allow_user_owned_authorized_keys_file;
-uid_t authorized_keys_file_allowed_owner_uid;
+extern char *authorized_keys_file;
+
+extern char *authorized_keys_command;
+
+extern char *authorized_keys_command_user;
+
+extern uint8_t allow_user_owned_authorized_keys_file;
+
+uid_t authorized_keys_file_allowed_owner_uid;
void
parse_authorized_key_file(const char *user, const char *authorized_keys_file_input)
@@ -137,8 +143,11 @@ parse_authorized_key_file(const char *user, const char *authorized_keys_file_inp
}
int
-pam_user_key_allowed(Key * key)
+pam_user_key_allowed(const char *ruser, Key * key)
{
return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file)
- || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file);
+ || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file)
+ || pam_user_key_command_allowed2(authorized_keys_command,
+ authorized_keys_command_user,
+ getpwnam(ruser), key);
}
diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h
index ae9a4b8..a871bf0 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h
+++ b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h
@@ -32,7 +32,7 @@
#define _PAM_USER_KEY_ALLOWED_H
#include "identity.h"
-int pam_user_key_allowed(Key *);
+int pam_user_key_allowed(const char *, Key *);
void parse_authorized_key_file(const char *, const char *);
#endif
diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
index c6680e4..4aceecb 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
+++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,9 +33,14 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
#include "xmalloc.h"
#include "ssh.h"
@@ -48,87 +53,263 @@
#include "pathnames.h"
#include "misc.h"
#include "secure_filename.h"
+#include "uidswap.h"
+#include <unistd.h>
#include "identity.h"
/* return 1 if user allows given key */
/* Modified slightly from original found in auth2-pubkey.c */
+static int
+pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key)
+{
+ char line[SSH_MAX_PUBKEY_BYTES];
+ int found_key = 0;
+ u_long linenum = 0;
+ Key *found;
+ char *fp;
+
+ found_key = 0;
+ found = key_new(key->type);
+
+ while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+ char *cp = NULL; /* *key_options = NULL; */
+
+ /* Skip leading whitespace, empty and comment lines. */
+ for(cp = line; *cp == ' ' || *cp == '\t'; cp++);
+ if(!*cp || *cp == '\n' || *cp == '#')
+ continue;
+
+ if(key_read(found, &cp) != 1) {
+ /* no key? check if there are options for this key */
+ int quoted = 0;
+
+ verbose("user_key_allowed: check options: '%s'", cp);
+ /* key_options = cp; */
+ for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+ if(*cp == '\\' && cp[1] == '"')
+ cp++; /* Skip both */
+ else if(*cp == '"')
+ quoted = !quoted;
+ }
+ /* Skip remaining whitespace. */
+ for(; *cp == ' ' || *cp == '\t'; cp++);
+ if(key_read(found, &cp) != 1) {
+ verbose("user_key_allowed: advance: '%s'", cp);
+ /* still no key? advance to next line */
+ continue;
+ }
+ }
+ if(key_equal(found, key)) {
+ found_key = 1;
+ logit("matching key found: file/command %s, line %lu", file,
+ linenum);
+ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+ logit("Found matching %s key: %s",
+ key_type(found), fp);
+ free(fp);
+ break;
+ }
+ }
+ key_free(found);
+ if(!found_key)
+ verbose("key not found");
+ return found_key;
+}
+
+/*
+ * Checks whether key is allowed in file.
+ * returns 1 if the key is allowed or 0 otherwise.
+ */
int
pam_user_key_allowed2(struct passwd *pw, Key *key, char *file)
{
- char line[SSH_MAX_PUBKEY_BYTES];
- int found_key = 0;
- FILE *f;
- u_long linenum = 0;
- struct stat st;
- Key *found;
- char *fp;
-
- verbose("trying public key file %s", file);
-
- /* Fail not so quietly if file does not exist */
- if (stat(file, &st) < 0) {
+ FILE *f;
+ int found_key = 0;
+ struct stat st;
+ char buf[SSH_MAX_PUBKEY_BYTES];
+
+ /* Temporarily use the user's uid. */
+ verbose("trying public key file %s", file);
+
+ /* Fail not so quietly if file does not exist */
+ if(stat(file, &st) < 0) {
verbose("File not found: %s", file);
- return 0;
- }
- /* Open the file containing the authorized keys. */
- f = fopen(file, "r");
- if (!f) {
- return 0;
- }
- if (
- secure_filename(f, file, pw, line, sizeof(line)) != 0) {
- fclose(f);
- logit("Authentication refused: %s", line);
- return 0;
- }
-
- found_key = 0;
- found = key_new(key->type);
-
- while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
- char *cp, *key_options = NULL;
-
- /* Skip leading whitespace, empty and comment lines. */
- for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (!*cp || *cp == '\n' || *cp == '#')
- continue;
-
- if (key_read(found, &cp) != 1) {
- /* no key? check if there are options for this key */
- int quoted = 0;
- verbose("user_key_allowed: check options: '%s'", cp);
- key_options = cp;
- for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
- if (*cp == '\\' && cp[1] == '"')
- cp++; /* Skip both */
- else if (*cp == '"')
- quoted = !quoted;
- }
- /* Skip remaining whitespace. */
- for (; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (key_read(found, &cp) != 1) {
- verbose("user_key_allowed: advance: '%s'", cp);
- /* still no key? advance to next line*/
- continue;
- }
- }
- if (key_equal(found, key)) {
- found_key = 1;
- logit("matching key found: file %s, line %lu",
- file, linenum);
- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
- logit("Found matching %s key: %s",
- key_type(found), fp);
- free(fp);
- break;
- }
- }
- fclose(f);
- key_free(found);
- if (!found_key)
- verbose("key not found");
- return found_key;
+ return 0;
+ }
+
+ /* Open the file containing the authorized keys. */
+ f = fopen(file, "r");
+ if(!f) {
+ return 0;
+ }
+
+ if(secure_filename(f, file, pw, buf, sizeof(buf)) != 0) {
+ fclose(f);
+ logit("Authentication refused: %s", buf);
+ return 0;
+ }
+
+ found_key = pamsshagentauth_check_authkeys_file(f, file, key);
+ fclose(f);
+ return found_key;
+}
+
+/*
+ * Checks whether key is allowed in output of command.
+ * returns 1 if the key is allowed or 0 otherwise.
+ */
+int
+pam_user_key_command_allowed2(char *authorized_keys_command,
+ char *authorized_keys_command_user,
+ struct passwd *user_pw, Key * key)
+{
+ FILE *f;
+ int ok, found_key = 0;
+ struct passwd *pw;
+ struct stat st;
+ int status, devnull, p[2], i;
+ pid_t pid;
+ char errmsg[512];
+ char username[512] = { 0 };
+
+
+
+ if(authorized_keys_command == NULL || authorized_keys_command[0] != '/')
+ return 0;
+
+
+ /* getpwnam of authorized_keys_command_user will overwrite the statics used by getpwnam (including pw_name) */
+ strncpy(username, user_pw->pw_name, sizeof(username) - 1);
+
+ /* If no user specified to run commands the default to target user */
+ if(authorized_keys_command_user == NULL) {
+ pw = user_pw;
+ }
+ else {
+ pw = getpwnam(authorized_keys_command_user);
+ if(pw == NULL) {
+ error("authorized_keys_command_user \"%s\" not found: %s",
+ authorized_keys_command_user, strerror(errno));
+ return 0;
+ }
+ }
+
+ temporarily_use_uid(pw);
+
+ if(stat(authorized_keys_command, &st) < 0) {
+ error
+ ("Could not stat AuthorizedKeysCommand \"%s\": %s",
+ authorized_keys_command, strerror(errno));
+ goto out;
+ }
+ if(pamsshagentauth_auth_secure_path
+ (authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
+ error("Unsafe AuthorizedKeysCommand: %s", errmsg);
+ goto out;
+ }
+
+ /* open the pipe and read the keys */
+ if(pipe(p) != 0) {
+ error("%s: pipe: %s", __func__, strerror(errno));
+ goto out;
+ }
+
+ debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"",
+ authorized_keys_command, pw->pw_name, username);
+
+ /*
+ * Don't want to call this in the child, where it can fatal() and
+ * run cleanup_exit() code.
+ */
+ restore_uid();
+
+ switch ((pid = fork())) {
+ case -1: /* error */
+ error("%s: fork: %s", __func__, strerror(errno));
+ close(p[0]);
+ close(p[1]);
+ return 0;
+ case 0: /* child */
+ for(i = 0; i < NSIG; i++)
+ signal(i, SIG_DFL);
+
+ /* do this before the setresuid so thta they can be logged */
+ if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+ error("%s: open %s: %s", __func__, _PATH_DEVNULL,
+ strerror(errno));
+ _exit(1);
+ }
+ if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1
+ || dup2(devnull, STDERR_FILENO) == -1) {
+ error("%s: dup2: %s", __func__, strerror(errno));
+ _exit(1);
+ }
+#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID)
+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
+#else
+ if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) {
+#endif
+ error("setresgid %u: %s", (u_int) pw->pw_gid,
+ strerror(errno));
+ _exit(1);
+ }
+
+#ifdef HAVE_SETRESUID
+ if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
+#else
+ if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) {
+#endif
+ error("setresuid %u: %s", (u_int) pw->pw_uid,
+ strerror(errno));
+ _exit(1);
+ }
+
+ close(p[0]);
+ closefrom(STDERR_FILENO + 1);
+
+ execl(authorized_keys_command, authorized_keys_command, username, (char *)NULL);
+
+ /* pretty sure this will barf because we are now suid, but since we
+ should't reach this anyway, I'll leave it here */
+ error("AuthorizedKeysCommand %s exec failed: %s",
+ authorized_keys_command, strerror(errno));
+ _exit(127);
+ default: /* parent */
+ break;
+ }
+
+ temporarily_use_uid(pw);
+
+ close(p[1]);
+ if((f = fdopen(p[0], "r")) == NULL) {
+ error("%s: fdopen: %s", __func__, strerror(errno));
+ close(p[0]);
+ /* Don't leave zombie child */
+ while(waitpid(pid, NULL, 0) == -1 && errno == EINTR);
+ goto out;
+ }
+ ok = pamsshagentauth_check_authkeys_file(f, authorized_keys_command, key);
+ fclose(f);
+
+ while(waitpid(pid, &status, 0) == -1) {
+ if(errno != EINTR) {
+ error("%s: waitpid: %s", __func__,
+ strerror(errno));
+ goto out;
+ }
+ }
+ if(WIFSIGNALED(status)) {
+ error("AuthorizedKeysCommand %s exited on signal %d",
+ authorized_keys_command, WTERMSIG(status));
+ goto out;
+ } else if(WEXITSTATUS(status) != 0) {
+ error("AuthorizedKeysCommand %s returned status %d",
+ authorized_keys_command, WEXITSTATUS(status));
+ goto out;
+ }
+ found_key = ok;
+ out:
+ restore_uid();
+ return found_key;
}
diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h
index 416d055..24533a0 100644
--- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h
+++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h
@@ -32,5 +32,6 @@
#include "identity.h"
int pam_user_key_allowed2(struct passwd *, Key *, char *);
+int pam_user_key_command_allowed2(char *, char *, struct passwd *, Key *);
#endif
diff --git a/pam_ssh_agent_auth-0.9.3/secure_filename.c b/pam_ssh_agent_auth-0.9.3/secure_filename.c
index c24cab2..d685599 100644
--- a/pam_ssh_agent_auth-0.9.3/secure_filename.c
+++ b/pam_ssh_agent_auth-0.9.3/secure_filename.c
@@ -71,29 +71,38 @@
* Returns 0 on success and -1 on failure
*/
int
-secure_filename(FILE *f, const char *file, struct passwd *pw,
- char *err, size_t errlen)
+pamsshagentauth_auth_secure_path(const char *name, struct stat *stp,
+ const char *pw_dir, uid_t uid, char *err, size_t errlen)
{
- uid_t uid = pw->pw_uid;
char buf[MAXPATHLEN], homedir[MAXPATHLEN];
char *cp;
int comparehome = 0;
struct stat st;
- verbose("secure_filename: checking for uid: %u", uid);
+ verbose("auth_secure_filename: checking for uid: %u", uid);
- if (realpath(file, buf) == NULL) {
- snprintf(err, errlen, "realpath %s failed: %s", file,
+ /* if (realpath(pw->pw_dir, homedir) != NULL) */
+ if (realpath(name, buf) == NULL) {
+ snprintf(err, errlen, "realpath %s failed: %s", name,
strerror(errno));
return -1;
}
- if (realpath(pw->pw_dir, homedir) != NULL)
+ if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
comparehome = 1;
/* check the open file to avoid races */
- if (fstat(fileno(f), &st) < 0 ||
- (st.st_uid != 0 && st.st_uid != uid) ||
- (st.st_mode & 022) != 0) {
+ /*
+ * if (fstat(fileno(f), &st) < 0 ||
+ * (st.st_uid != 0 && st.st_uid != uid) ||
+ * (st.st_mode & 022) != 0) {
+ */
+ if (!S_ISREG(stp->st_mode)) {
+ snprintf(err, errlen, "%s is not a regular file", buf);
+ return -1;
+ }
+
+ if ((stp->st_uid != 0 && stp->st_uid != uid) ||
+ (stp->st_mode & 022) != 0) {
snprintf(err, errlen, "bad ownership or modes for file %s",
buf);
return -1;
@@ -132,3 +141,25 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,
return 0;
}
+/*
+ * Version of secure_path() that accepts an open file descriptor to
+ * avoid races.
+ *
+ * Returns 0 on success and -1 on failure
+ */
+int
+secure_filename(FILE *f, const char *file, struct passwd *pw,
+ char *err, size_t errlen)
+{
+ struct stat st;
+ char buf[MAXPATHLEN] = { 0 };
+
+ /* check the open file to avoid races */
+ if (fstat(fileno(f), &st) < 0) {
+ snprintf(err, errlen, "cannot stat file %s: %s",
+ buf, strerror(errno));
+ return -1;
+ }
+ return pamsshagentauth_auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
+}
+
diff --git a/pam_ssh_agent_auth-0.9.3/secure_filename.h b/pam_ssh_agent_auth-0.9.3/secure_filename.h
index 198c13d..4c1a208 100644
--- a/pam_ssh_agent_auth-0.9.3/secure_filename.h
+++ b/pam_ssh_agent_auth-0.9.3/secure_filename.h
@@ -28,5 +28,7 @@
#define _SECURE_FILENAME_H
#include <pwd.h>
#include <stdio.h>
+struct stat;
int secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
+int pamsshagentauth_auth_secure_path(const char *, struct stat *, const char *, uid_t, char *, size_t);
#endif
diff --git a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c
index 163278b..31849f8 100644
--- a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c
+++ b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c
@@ -48,11 +48,14 @@
#include "identity.h"
#include "pam_user_authorized_keys.h"
-extern u_char *session_id2;
+#define SSH2_MSG_USERAUTH_TRUST_REQUEST 54
+
+/* extern u_char *session_id2;
extern uint8_t session_id_len;
+ */
int
-userauth_pubkey_from_id(Identity * id)
+userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2)
{
Buffer b = { 0 };
char *pkalg = NULL;
@@ -63,7 +66,7 @@ userauth_pubkey_from_id(Identity * id)
pkalg = (char *) key_ssh_name(id->key);
/* first test if this key is even allowed */
- if(! pam_user_key_allowed(id->key))
+ if(! pam_user_key_allowed(ruser, id->key))
goto user_auth_clean_exit;
if(key_to_blob(id->key, &pkblob, &blen) == 0)
@@ -72,10 +75,10 @@ userauth_pubkey_from_id(Identity * id)
/* construct packet to sign and test */
buffer_init(&b);
- buffer_put_string(&b, session_id2, session_id_len);
- buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
- buffer_put_cstring(&b, "root");
- buffer_put_cstring(&b, "ssh-userauth");
+ buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset);
+ buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST);
+ buffer_put_cstring(&b, ruser);
+ buffer_put_cstring(&b, "pam_ssh_agent_auth");
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, 1);
buffer_put_cstring(&b, pkalg);
@@ -89,8 +92,7 @@ userauth_pubkey_from_id(Identity * id)
authenticated = 1;
user_auth_clean_exit:
- if(&b != NULL)
- buffer_free(&b);
+ buffer_free(&b);
if(sig != NULL)
free(sig);
if(pkblob != NULL)
diff --git a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h
index 1e14231..7758808 100644
--- a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h
+++ b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h
@@ -32,6 +32,6 @@
#define _USERAUTH_PUBKEY_FROM_ID_H
#include <identity.h>
-int userauth_pubkey_from_id(Identity *);
+int userauth_pubkey_from_id(const char *, Identity *, Buffer *);
#endif
--
2.5.0
--- openssh-6.6p1/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c.psaa-command 2016-04-20 09:31:32.164686370 +0200
+++ openssh-6.6p1/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c 2016-04-20 09:35:49.778344576 +0200
@@ -145,8 +145,12 @@
int
pam_user_key_allowed(const char *ruser, Key * key)
{
- return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file)
- || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file)
+ struct passwd *pw;
+ return
+ ((pw = getpwuid(authorized_keys_file_allowed_owner_uid)) &&
+ pam_user_key_allowed2(pw, key, authorized_keys_file))
+ || ((pw = getpwuid(0)) &&
+ pam_user_key_allowed2(pw, key, authorized_keys_file))
|| pam_user_key_command_allowed2(authorized_keys_command,
authorized_keys_command_user,
getpwnam(ruser), key);