Index: openssh-9.3p2/misc.c =================================================================== --- openssh-9.3p2.orig/misc.c +++ openssh-9.3p2/misc.c @@ -2770,6 +2770,13 @@ subprocess(const char *tag, const char * error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } +#ifdef WITH_SELINUX + if (sshd_selinux_setup_env_variables() < 0) { + error ("failed to copy environment: %s", + strerror(errno)); + _exit(127); + } +#endif if (env != NULL) execve(av[0], av, env); else #Index: openssh-9.3p2/HOWTO.ssh-keycat #=================================================================== #--- /dev/null #+++ openssh-9.3p2/HOWTO.ssh-keycat #@@ -0,0 +1,12 @@ #+The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys #+of an user in any environment. This includes environments with #+polyinstantiation of home directories and SELinux MLS policy enabled. #+ #+To use ssh-keycat, set these options in /etc/ssh/sshd_config file: #+ AuthorizedKeysCommand /usr/libexec/openssh/ssh-keycat #+ AuthorizedKeysCommandUser root #+ #+Do not forget to enable public key authentication: #+ PubkeyAuthentication yes #+ #+ #Index: openssh-9.3p2/Makefile.in #=================================================================== #--- openssh-9.3p2.orig/Makefile.in #+++ openssh-9.3p2/Makefile.in #@@ -27,6 +27,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server # ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass # SFTP_SERVER=$(libexecdir)/sftp-server # SSH_KEYSIGN=$(libexecdir)/ssh-keysign #+SSH_KEYCAT=$(libexecdir)/ssh-keycat # SSHD_SESSION=$(libexecdir)/sshd-session # SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper # SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper #@@ -57,6 +58,7 @@ CHANNELLIBS=@CHANNELLIBS@ # K5LIBS=@K5LIBS@ # GSSLIBS=@GSSLIBS@ # SSHDLIBS=@SSHDLIBS@ #+KEYCATLIBS=@KEYCATLIBS@ # LIBEDIT=@LIBEDIT@ # LIBFIDO2=@LIBFIDO2@ # LIBWTMPDB=@LIBWTMPDB@ #@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@ # # .SUFFIXES: .lo # #-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) #+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ssh-keycat$(EXEEXT) # # TARGETS += cavstest-ctr$(EXEEXT) cavstest-kdf$(EXEEXT) # #@@ -245,6 +247,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) # ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS) # $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) $(CHANNELLIBS) # #+ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o uidswap.o #+ $(LD) -o $@ ssh-keycat.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat $(KEYCATLIBS) $(LIBS) #+ # ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSCAN_OBJS) # $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) $(CHANNELLIBS) # #@@ -431,6 +436,7 @@ install-files: # $(INSTALL) -m 0755 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ # fi # $(INSTALL) -m 0755 $(STRIP_OPT) ssh-sk-helper$(EXEEXT) $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT) #+ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) # $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) # $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) # $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-ctr$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-ctr$(EXEEXT) Index: openssh-9.3p2/openbsd-compat/port-linux.h =================================================================== --- openssh-9.3p2.orig/openbsd-compat/port-linux.h +++ openssh-9.3p2/openbsd-compat/port-linux.h @@ -23,8 +23,10 @@ void ssh_selinux_setup_pty(char *, const void ssh_selinux_change_context(const char *); void ssh_selinux_setfscreatecon(const char *); +int sshd_selinux_enabled(void); void sshd_selinux_copy_context(void); void sshd_selinux_setup_exec_context(char *); +int sshd_selinux_setup_env_variables(void); #endif #ifdef LINUX_OOM_ADJUST Index: openssh-9.3p2/openbsd-compat/port-linux-sshd.c =================================================================== --- openssh-9.3p2.orig/openbsd-compat/port-linux-sshd.c +++ openssh-9.3p2/openbsd-compat/port-linux-sshd.c @@ -54,6 +54,20 @@ extern Authctxt *the_authctxt; extern Authctxt *the_authctxt; extern int inetd_flag; +/* Wrapper around is_selinux_enabled() to log its return value once only */ +int +sshd_selinux_enabled(void) +{ + static int enabled = -1; + + if (enabled == -1) { + enabled = (is_selinux_enabled() == 1); + debug("SELinux support %s", enabled ? "enabled" : "disabled"); + } + + return (enabled); +} + /* Send audit message */ static int sshd_selinux_send_audit_message(int success, security_context_t default_context, @@ -318,7 +332,7 @@ sshd_selinux_getctxbyname(char *pwname, /* Setup environment variables for pam_selinux */ static int -sshd_selinux_setup_pam_variables(void) +sshd_selinux_setup_variables(int(*set_it)(char *, const char *)) { const char *reqlvl; char *role; @@ -319,16 +333,16 @@ sshd_selinux_setup_pam_variables(void) ssh_selinux_get_role_level(&role, &reqlvl); - rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); if (inetd_flag) { use_current = "1"; } else { use_current = ""; - rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: ""); + rv = rv || set_it("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: ""); } - rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current); + rv = rv || set_it("SELINUX_USE_CURRENT_RANGE", use_current); if (role != NULL) free(role); @@ -346,6 +360,24 @@ sshd_selinux_setup_pam_variables(void) return rv; } +static int +sshd_selinux_setup_pam_variables(void) +{ + return sshd_selinux_setup_variables(do_pam_putenv); +} + +static int +do_setenv(char *name, const char *value) +{ + return setenv(name, value, 1); +} + +int +sshd_selinux_setup_env_variables(void) +{ + return sshd_selinux_setup_variables(do_setenv); +} + /* Set the execution context to the default for the specified user */ void sshd_selinux_setup_exec_context(char *pwname) @@ -354,7 +386,7 @@ sshd_selinux_setup_exec_context(char *pw int r = 0; security_context_t default_ctx = NULL; - if (!ssh_selinux_enabled()) + if (!sshd_selinux_enabled()) return; if (options.use_pam) { @@ -421,7 +453,7 @@ sshd_selinux_copy_context(void) { security_context_t *ctx; - if (!ssh_selinux_enabled()) + if (!sshd_selinux_enabled()) return; if (getexeccon((security_context_t *)&ctx) != 0) { Index: openssh-9.3p2/platform.c =================================================================== --- openssh-9.3p2.orig/platform.c +++ openssh-9.3p2/platform.c @@ -100,7 +100,7 @@ platform_setusercontext(struct passwd *p { #ifdef WITH_SELINUX /* Cache selinux status for later use */ - (void)ssh_selinux_enabled(); + (void)sshd_selinux_enabled(); #endif #ifdef USE_SOLARIS_PROJECTS #Index: openssh-9.3p2/ssh-keycat.c #=================================================================== #--- /dev/null #+++ openssh-9.3p2/ssh-keycat.c #@@ -0,0 +1,241 @@ #+/* #+ * 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, and the entire permission notice in its entirety, #+ * including the disclaimer of warranties. #+ * 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. #+ * 3. The name of the author may not be used to endorse or promote #+ * products derived from this software without specific prior #+ * written permission. #+ * #+ * ALTERNATIVELY, this product may be distributed under the terms of #+ * the GNU Public License, in which case the provisions of the GPL are #+ * required INSTEAD OF the above restrictions. (This clause is #+ * necessary due to a potential bad interaction between the GPL and #+ * the restrictions contained in a BSD-style copyright.) #+ * #+ * THIS SOFTWARE IS PROVIDED ``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 (c) 2011 Red Hat, Inc. #+ * Written by Tomas Mraz #+*/ #+ #+#define _GNU_SOURCE #+ #+#include "config.h" #+#include #+#include #+#include #+#include #+#include #+#include #+#include #+#include #+#ifdef HAVE_STDINT_H #+#include #+#endif #+ #+#include #+ #+#include "uidswap.h" #+#include "misc.h" #+ #+#define ERR_USAGE 1 #+#define ERR_PAM_START 2 #+#define ERR_OPEN_SESSION 3 #+#define ERR_CLOSE_SESSION 4 #+#define ERR_PAM_END 5 #+#define ERR_GETPWNAM 6 #+#define ERR_MEMORY 7 #+#define ERR_OPEN 8 #+#define ERR_FILE_MODE 9 #+#define ERR_FDOPEN 10 #+#define ERR_STAT 11 #+#define ERR_WRITE 12 #+#define ERR_PAM_PUTENV 13 #+#define BUFLEN 4096 #+ #+/* Just ignore the messages in the conversation function */ #+static int #+dummy_conv(int num_msg, const struct pam_message **msgm, #+ struct pam_response **response, void *appdata_ptr) #+{ #+ struct pam_response *rsp; #+ #+ (void)msgm; #+ (void)appdata_ptr; #+ #+ if (num_msg <= 0) #+ return PAM_CONV_ERR; #+ #+ /* Just allocate the array as empty responses */ #+ rsp = calloc (num_msg, sizeof (struct pam_response)); #+ if (rsp == NULL) #+ return PAM_CONV_ERR; #+ #+ *response = rsp; #+ return PAM_SUCCESS; #+} #+ #+static struct pam_conv conv = { #+ dummy_conv, #+ NULL #+}; #+ #+char * #+make_auth_keys_name(const struct passwd *pwd) #+{ #+ char *fname; #+ #+ if (asprintf(&fname, "%s/.ssh/authorized_keys", pwd->pw_dir) < 0) #+ return NULL; #+ #+ return fname; #+} #+ #+int #+dump_keys(const char *user) #+{ #+ struct passwd *pwd; #+ int fd = -1; #+ FILE *f = NULL; #+ char *fname = NULL; #+ int rv = 0; #+ char buf[BUFLEN]; #+ size_t len; #+ struct stat st; #+ #+ if ((pwd = getpwnam(user)) == NULL) { #+ return ERR_GETPWNAM; #+ } #+ #+ if ((fname = make_auth_keys_name(pwd)) == NULL) { #+ return ERR_MEMORY; #+ } #+ #+ temporarily_use_uid(pwd); #+ #+ if ((fd = open(fname, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) { #+ rv = ERR_OPEN; #+ goto fail; #+ } #+ #+ if (fstat(fd, &st) < 0) { #+ rv = ERR_STAT; #+ goto fail; #+ } #+ #+ if (!S_ISREG(st.st_mode) || #+ (st.st_uid != pwd->pw_uid && st.st_uid != 0)) { #+ rv = ERR_FILE_MODE; #+ goto fail; #+ } #+ #+ unset_nonblock(fd); #+ #+ if ((f = fdopen(fd, "r")) == NULL) { #+ rv = ERR_FDOPEN; #+ goto fail; #+ } #+ #+ fd = -1; #+ #+ while ((len = fread(buf, 1, sizeof(buf), f)) > 0) { #+ rv = fwrite(buf, 1, len, stdout) != len ? ERR_WRITE : 0; #+ } #+ #+fail: #+ if (fd != -1) #+ close(fd); #+ if (f != NULL) #+ fclose(f); #+ free(fname); #+ restore_uid(); #+ return rv; #+} #+ #+static const char *env_names[] = { "SELINUX_ROLE_REQUESTED", #+ "SELINUX_LEVEL_REQUESTED", #+ "SELINUX_USE_CURRENT_RANGE" #+}; #+ #+extern char **environ; #+ #+int #+set_pam_environment(pam_handle_t *pamh) #+{ #+ int i; #+ size_t j; #+ #+ for (j = 0; j < sizeof(env_names)/sizeof(env_names[0]); ++j) { #+ int len = strlen(env_names[j]); #+ #+ for (i = 0; environ[i] != NULL; ++i) { #+ if (strncmp(env_names[j], environ[i], len) == 0 && #+ environ[i][len] == '=') { #+ if (pam_putenv(pamh, environ[i]) != PAM_SUCCESS) #+ return ERR_PAM_PUTENV; #+ } #+ } #+ } #+ #+ return 0; #+} #+ #+int #+main(int argc, char *argv[]) #+{ #+ pam_handle_t *pamh = NULL; #+ int retval; #+ int ev = 0; #+ #+ if (argc != 2) { #+ fprintf(stderr, "Usage: %s \n", argv[0]); #+ return ERR_USAGE; #+ } #+ #+ retval = pam_start("ssh-keycat", argv[1], &conv, &pamh); #+ if (retval != PAM_SUCCESS) { #+ return ERR_PAM_START; #+ } #+ #+ ev = set_pam_environment(pamh); #+ if (ev != 0) #+ goto finish; #+ #+ retval = pam_open_session(pamh, PAM_SILENT); #+ if (retval != PAM_SUCCESS) { #+ ev = ERR_OPEN_SESSION; #+ goto finish; #+ } #+ #+ ev = dump_keys(argv[1]); #+ #+ retval = pam_close_session(pamh, PAM_SILENT); #+ if (retval != PAM_SUCCESS) { #+ ev = ERR_CLOSE_SESSION; #+ } #+ #+finish: #+ retval = pam_end (pamh,retval); #+ if (retval != PAM_SUCCESS) { #+ ev = ERR_PAM_END; #+ } #+ return ev; #+} #Index: openssh-9.3p2/configure.ac #=================================================================== #--- openssh-9.3p2.orig/configure.ac #+++ openssh-9.3p2/configure.ac #@@ -3632,6 +3632,7 @@ AC_ARG_WITH([pam], # PAM_MSG="yes" # # SSHDLIBS="$SSHDLIBS -lpam" #+ KEYCATLIBS="$KEYCATLIBS -lpam" # AC_DEFINE([USE_PAM], [1], # [Define if you want to enable PAM support]) # #@@ -3642,6 +3643,7 @@ AC_ARG_WITH([pam], # ;; # *) # SSHDLIBS="$SSHDLIBS -ldl" #+ KEYCATLIBS="$KEYCATLIBS -ldl" # ;; # esac # fi #@@ -4875,6 +4877,7 @@ AC_ARG_WITH([selinux], # fi ] # ) # AC_SUBST([SSHDLIBS]) #+AC_SUBST([KEYCATLIBS]) # # # Check whether user wants Kerberos 5 support # KRB5_MSG="no" #@@ -5905,6 +5908,9 @@ fi # if test ! -z "${SSHDLIBS}"; then # echo " +for sshd: ${SSHDLIBS}" # fi #+if test ! -z "${KEYCATLIBS}"; then #+echo " +for ssh-keycat: ${KEYCATLIBS}" #+fi # # echo "" #