* Aktivate selinux support.
* Aktivate audit support.
* Add a bunch of patches to fix errors and provide new features.
Fixes #130.
include $(PKGROOT)/Include
PKG_NAME = openssh
-PKG_VER = 5.4p1
-PKG_REL = 2
+PKG_VER = 5.8p1
+PKG_REL = 3
PKG_MAINTAINER =
PKG_GROUP = Application/Internet
PKG_LICENSE = MIT
PKG_SUMMARY = An open source implementation of SSH protocol versions 1 and 2.
-PKG_BUILD_DEPS+= libselinux-devel openssl-devel pam-devel zlib-devel
+PKG_BUILD_DEPS+= audit-devel libselinux-devel nss-devel openssl-devel pam-devel \
+ zlib-devel
PKG_DEPS-openssh = openssh-clients=$(THISVER) openssh-server=$(THISVER)
define PKG_DESCRIPTION
/usr/bin/ \
/usr/lib/ \
/usr/share/
+
+# Apply patches in a special order
+PKG_PATCHES = openssh-5.6p1-redhat.patch
+PKG_PATCHES += openssh-5.8p1-fingerprint.patch
+PKG_PATCHES += openssh-5.8p1-authorized-keys-command.patch
+PKG_PATCHES += openssh-5.8p1-selinux.patch
+PKG_PATCHES += openssh-5.8p1-selinux-role.patch
+PKG_PATCHES += openssh-5.8p1-mls.patch
+PKG_PATCHES += openssh-5.6p1-keygen.patch
+PKG_PATCHES += openssh-5.2p1-allow-ip-opts.patch
+PKG_PATCHES += openssh-5.8p1-randclean.patch
+PKG_PATCHES += openssh-5.8p1-kuserok.patch
+PKG_PATCHES += openssh-5.5p1-x11.patch
+PKG_PATCHES += openssh-5.6p1-exit-deadlock.patch
+PKG_PATCHES += openssh-5.1p1-askpass-progress.patch
+PKG_PATCHES += openssh-4.3p2-askpass-grab-info.patch
+PKG_PATCHES += openssh-5.2p1-edns.patch
+PKG_PATCHES += openssh-5.1p1-scp-manpage.patch
CONFIGURE_OPTIONS += \
--sysconfdir=/etc/ssh \
--with-md5-passwords \
--with-privsep-path=/var/lib/sshd \
--with-pam \
- --with-selinux
+ --with-selinux \
+ --with-nss \
+ --with-audit=linux
define STAGE_INSTALL_CMDS
-mkdir -pv $(BUILDROOT)/etc/ssh
--- /dev/null
+--- openssh-4.3p2/contrib/gnome-ssh-askpass2.c.grab-info 2006-07-17 15:10:11.000000000 +0200
++++ openssh-4.3p2/contrib/gnome-ssh-askpass2.c 2006-07-17 15:25:04.000000000 +0200
+@@ -65,9 +65,12 @@
+ err = gtk_message_dialog_new(NULL, 0,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+- "Could not grab %s. "
+- "A malicious client may be eavesdropping "
+- "on your session.", what);
++ "SSH password dialog could not grab the %s input.\n"
++ "This might be caused by application such as screensaver, "
++ "however it could also mean that someone may be eavesdropping "
++ "on your session.\n"
++ "Either close the application which grabs the %s or "
++ "log out and log in again to prevent this from happening.", what, what);
+ gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
+ gtk_label_set_line_wrap(GTK_LABEL((GTK_MESSAGE_DIALOG(err))->label),
+ TRUE);
--- /dev/null
+diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contrib/gnome-ssh-askpass2.c
+--- openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress 2008-07-23 19:05:26.000000000 +0200
++++ openssh-5.1p1/contrib/gnome-ssh-askpass2.c 2008-07-23 19:05:26.000000000 +0200
+@@ -53,6 +53,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <X11/Xlib.h>
++#include <glib.h>
+ #include <gtk/gtk.h>
+ #include <gdk/gdkx.h>
+
+@@ -83,13 +84,24 @@ ok_dialog(GtkWidget *entry, gpointer dia
+ gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+ }
+
++static void
++move_progress(GtkWidget *entry, gpointer progress)
++{
++ gdouble step;
++ g_return_if_fail(GTK_IS_PROGRESS_BAR(progress));
++
++ step = g_random_double_range(0.03, 0.1);
++ gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progress), step);
++ gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress));
++}
++
+ static int
+ passphrase_dialog(char *message)
+ {
+ const char *failed;
+ char *passphrase, *local;
+ int result, grab_tries, grab_server, grab_pointer;
+- GtkWidget *dialog, *entry;
++ GtkWidget *dialog, *entry, *progress, *hbox;
+ GdkGrabStatus status;
+
+ grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
+@@ -102,13 +114,31 @@ passphrase_dialog(char *message)
+ "%s",
+ message);
+
++ hbox = gtk_hbox_new(FALSE, 0);
++ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE,
++ FALSE, 0);
++ gtk_widget_show(hbox);
++
+ entry = gtk_entry_new();
+- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE,
++ gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE,
+ FALSE, 0);
++ gtk_entry_set_width_chars(GTK_ENTRY(entry), 2);
+ gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+ gtk_widget_grab_focus(entry);
+ gtk_widget_show(entry);
+
++ hbox = gtk_hbox_new(FALSE, 0);
++ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE,
++ FALSE, 8);
++ gtk_widget_show(hbox);
++
++ progress = gtk_progress_bar_new();
++
++ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), "Passphrase length hidden intentionally");
++ gtk_box_pack_start(GTK_BOX(hbox), progress, TRUE,
++ TRUE, 5);
++ gtk_widget_show(progress);
++
+ gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH");
+ gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+ gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+@@ -119,6 +149,8 @@ passphrase_dialog(char *message)
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+ g_signal_connect(G_OBJECT(entry), "activate",
+ G_CALLBACK(ok_dialog), dialog);
++ g_signal_connect(G_OBJECT(entry), "changed",
++ G_CALLBACK(move_progress), progress);
+
+ gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+
--- /dev/null
+diff -up openssh-5.1p1/scp.1.manpage openssh-5.1p1/scp.1
+--- openssh-5.1p1/scp.1.manpage 2008-07-12 09:12:49.000000000 +0200
++++ openssh-5.1p1/scp.1 2008-07-23 19:18:15.000000000 +0200
+@@ -66,6 +66,14 @@ treating file names containing
+ as host specifiers.
+ Copies between two remote hosts are also permitted.
+ .Pp
++When copying a source file to a target file which already exists,
++.Nm
++will replace the contents of the target file (keeping the inode).
++.Pp
++If the target file does not yet exist, an empty file with the target
++file name is created, then filled with the source file contents.
++No attempt is made at "near-atomic" transfer using temporary files.
++.Pp
+ The options are as follows:
+ .Bl -tag -width Ds
+ .It Fl 1
--- /dev/null
+diff -up openssh-5.2p1/canohost.c.ip-opts openssh-5.2p1/canohost.c
+--- openssh-5.2p1/canohost.c.ip-opts 2009-02-14 06:28:21.000000000 +0100
++++ openssh-5.2p1/canohost.c 2009-09-01 15:31:29.000000000 +0200
+@@ -169,12 +169,27 @@ check_ip_options(int sock, char *ipaddr)
+ option_size = sizeof(options);
+ if (getsockopt(sock, ipproto, IP_OPTIONS, options,
+ &option_size) >= 0 && option_size != 0) {
+- text[0] = '\0';
+- for (i = 0; i < option_size; i++)
+- snprintf(text + i*3, sizeof(text) - i*3,
+- " %2.2x", options[i]);
+- fatal("Connection from %.100s with IP options:%.800s",
+- ipaddr, text);
++ i = 0;
++ do {
++ switch (options[i]) {
++ case 0:
++ case 1:
++ ++i;
++ break;
++ case 131:
++ case 137:
++ /* Fail, fatally, if we detect either loose or strict
++ * source routing options. */
++ text[0] = '\0';
++ for (i = 0; i < option_size; i++)
++ snprintf(text + i*3, sizeof(text) - i*3,
++ " %2.2x", options[i]);
++ fatal("Connection from %.100s with IP options:%.800s",
++ ipaddr, text);
++ default:
++ i += options[i + 1];
++ }
++ } while (i < option_size);
+ }
+ #endif /* IP_OPTIONS */
+ }
--- /dev/null
+diff -up openssh-5.2p1/dns.c.rh205842 openssh-5.2p1/dns.c
+--- openssh-5.2p1/dns.c.rh205842 2009-07-27 16:25:28.000000000 +0200
++++ openssh-5.2p1/dns.c 2009-07-27 16:40:59.000000000 +0200
+@@ -176,6 +176,7 @@ verify_host_key_dns(const char *hostname
+ {
+ u_int counter;
+ int result;
++ unsigned int rrset_flags = 0;
+ struct rrsetinfo *fingerprints = NULL;
+
+ u_int8_t hostkey_algorithm;
+@@ -199,8 +200,19 @@ verify_host_key_dns(const char *hostname
+ return -1;
+ }
+
++ /*
++ * Original getrrsetbyname function, found on OpenBSD for example,
++ * doesn't accept any flag and prerequisite for obtaining AD bit in
++ * DNS response is set by "options edns0" in resolv.conf.
++ *
++ * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
++ */
++#ifndef HAVE_GETRRSETBYNAME
++ rrset_flags |= RRSET_FORCE_EDNS0;
++#endif
+ result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
+- DNS_RDATATYPE_SSHFP, 0, &fingerprints);
++ DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);
++
+ if (result) {
+ verbose("DNS lookup error: %s", dns_result_totext(result));
+ return -1;
+diff -up openssh-5.2p1/openbsd-compat/getrrsetbyname.c.rh205842 openssh-5.2p1/openbsd-compat/getrrsetbyname.c
+--- openssh-5.2p1/openbsd-compat/getrrsetbyname.c.rh205842 2009-07-27 16:22:23.000000000 +0200
++++ openssh-5.2p1/openbsd-compat/getrrsetbyname.c 2009-07-27 16:41:55.000000000 +0200
+@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, uns
+ goto fail;
+ }
+
+- /* don't allow flags yet, unimplemented */
+- if (flags) {
++ /* Allow RRSET_FORCE_EDNS0 flag only. */
++ if ((flags & !RRSET_FORCE_EDNS0) != 0) {
+ result = ERRSET_INVAL;
+ goto fail;
+ }
+@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, uns
+ #endif /* DEBUG */
+
+ #ifdef RES_USE_DNSSEC
+- /* turn on DNSSEC if EDNS0 is configured */
+- if (_resp->options & RES_USE_EDNS0)
+- _resp->options |= RES_USE_DNSSEC;
++ /* turn on DNSSEC if required */
++ if (flags & RRSET_FORCE_EDNS0)
++ _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC);
+ #endif /* RES_USE_DNSEC */
+
+ /* make query */
+diff -up openssh-5.2p1/openbsd-compat/getrrsetbyname.h.rh205842 openssh-5.2p1/openbsd-compat/getrrsetbyname.h
+--- openssh-5.2p1/openbsd-compat/getrrsetbyname.h.rh205842 2009-07-27 16:35:02.000000000 +0200
++++ openssh-5.2p1/openbsd-compat/getrrsetbyname.h 2009-07-27 16:36:09.000000000 +0200
+@@ -72,6 +72,9 @@
+ #ifndef RRSET_VALIDATED
+ # define RRSET_VALIDATED 1
+ #endif
++#ifndef RRSET_FORCE_EDNS0
++# define RRSET_FORCE_EDNS0 0x0001
++#endif
+
+ /*
+ * Return codes for getrrsetbyname()
--- /dev/null
+diff -up openssh-5.3p1/channels.c.bz595935 openssh-5.3p1/channels.c
+--- openssh-5.3p1/channels.c.bz595935 2010-08-12 14:19:28.000000000 +0200
++++ openssh-5.3p1/channels.c 2010-08-12 14:33:51.000000000 +0200
+@@ -3185,7 +3185,7 @@ x11_create_display_inet(int x11_display_
+ }
+
+ static int
+-connect_local_xsocket_path(const char *pathname)
++connect_local_xsocket_path(const char *pathname, int len)
+ {
+ int sock;
+ struct sockaddr_un addr;
+@@ -3195,11 +3195,14 @@ connect_local_xsocket_path(const char *p
+ error("socket: %.100s", strerror(errno));
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+- strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
+- if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
++ if (len <= 0)
++ return -1;
++ if (len > sizeof addr.sun_path)
++ len = sizeof addr.sun_path;
++ memcpy(addr.sun_path, pathname, len);
++ if (connect(sock, (struct sockaddr *)&addr, sizeof addr - (sizeof addr.sun_path - len) ) == 0)
+ return sock;
+ close(sock);
+- error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
+ return -1;
+ }
+
+@@ -3207,8 +3210,21 @@ static int
+ connect_local_xsocket(u_int dnr)
+ {
+ char buf[1024];
+- snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
+- return connect_local_xsocket_path(buf);
++ int len;
++#ifdef linux
++ int ret;
++#endif
++ len = snprintf(buf + 1, sizeof (buf) - 1, _PATH_UNIX_X, dnr);
++#ifdef linux
++ /* try abstract socket first */
++ buf[0] = '\0';
++ if ((ret = connect_local_xsocket_path(buf, len + 1)) >= 0)
++ return ret;
++#endif
++ if ((ret = connect_local_xsocket_path(buf + 1, len)) >= 0)
++ return ret;
++ error("connect %.100s: %.100s", buf + 1, strerror(errno));
++ return -1;
+ }
+
+ int
--- /dev/null
+diff -up openssh-5.6p1/channels.c.exit-deadlock openssh-5.6p1/channels.c
+--- openssh-5.6p1/channels.c.exit-deadlock 2010-08-05 15:09:48.000000000 +0200
++++ openssh-5.6p1/channels.c 2010-08-23 12:41:43.000000000 +0200
+@@ -1647,6 +1647,10 @@ channel_handle_wfd(Channel *c, fd_set *r
+ u_int dlen, olen = 0;
+ int len;
+
++ if(c->wfd != -1 && buffer_len(&c->output) > 0 && c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
++ debug("channel %d: forcing write", c->self);
++ FD_SET(c->wfd, writeset);
++ }
+ /* Send buffered output data to the socket. */
+ if (c->wfd != -1 &&
+ FD_ISSET(c->wfd, writeset) &&
--- /dev/null
+diff -up openssh-5.6p1/ssh-keygen.0.keygen openssh-5.6p1/ssh-keygen.0
+--- openssh-5.6p1/ssh-keygen.0.keygen 2010-08-22 16:30:03.000000000 +0200
++++ openssh-5.6p1/ssh-keygen.0 2010-08-23 12:37:19.000000000 +0200
+@@ -4,7 +4,7 @@ NAME
+ ssh-keygen - authentication key generation, management and conversion
+
+ SYNOPSIS
+- ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment]
++ ssh-keygen [-q] [-o] [-b bits] -t type [-N new_passphrase] [-C comment]
+ [-f output_keyfile]
+ ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
+ ssh-keygen -i [-m key_format] [-f input_keyfile]
+@@ -232,6 +232,8 @@ DESCRIPTION
+
+ -q Silence ssh-keygen. Used by /etc/rc when creating a new key.
+
++ -o Overwrite the key without prompting user.
++
+ -R hostname
+ Removes all keys belonging to hostname from a known_hosts file.
+ This option is useful to delete hashed hosts (see the -H option
+diff -up openssh-5.6p1/ssh-keygen.1.keygen openssh-5.6p1/ssh-keygen.1
+--- openssh-5.6p1/ssh-keygen.1.keygen 2010-08-05 05:05:32.000000000 +0200
++++ openssh-5.6p1/ssh-keygen.1 2010-08-23 12:36:25.000000000 +0200
+@@ -47,6 +47,7 @@
+ .Bk -words
+ .Nm ssh-keygen
+ .Op Fl q
++.Op Fl o
+ .Op Fl b Ar bits
+ .Fl t Ar type
+ .Op Fl N Ar new_passphrase
+@@ -397,6 +398,8 @@ Silence
+ Used by
+ .Pa /etc/rc
+ when creating a new key.
++.It Fl o
++Overwrite the key without prompting user.
+ .It Fl R Ar hostname
+ Removes all keys belonging to
+ .Ar hostname
+diff -up openssh-5.6p1/ssh-keygen.c.keygen openssh-5.6p1/ssh-keygen.c
+--- openssh-5.6p1/ssh-keygen.c.keygen 2010-08-05 05:05:32.000000000 +0200
++++ openssh-5.6p1/ssh-keygen.c 2010-08-23 12:34:40.000000000 +0200
+@@ -72,6 +72,7 @@ int change_passphrase = 0;
+ int change_comment = 0;
+
+ int quiet = 0;
++int overwrite = 0;
+
+ int log_level = SYSLOG_LEVEL_INFO;
+
+@@ -1798,7 +1799,7 @@ main(int argc, char **argv)
+ exit(1);
+ }
+
+- while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:"
++ while ((opt = getopt(argc, argv, "degiqopclBHLhvxXyF:b:f:t:D:I:P:m:N:n:"
+ "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) {
+ switch (opt) {
+ case 'b':
+@@ -1878,6 +1879,9 @@ main(int argc, char **argv)
+ case 'q':
+ quiet = 1;
+ break;
++ case 'o':
++ overwrite = 1;
++ break;
+ case 'e':
+ case 'x':
+ /* export key */
+@@ -2124,7 +2128,7 @@ main(int argc, char **argv)
+ }
+ }
+ /* If the file already exists, ask the user to confirm. */
+- if (stat(identity_file, &st) >= 0) {
++ if (!overwrite && stat(identity_file, &st) >= 0) {
+ char yesno[3];
+ printf("%s already exists.\n", identity_file);
+ printf("Overwrite (y/n)? ");
--- /dev/null
+diff -up openssh-5.6p1/ssh_config.redhat openssh-5.6p1/ssh_config
+--- openssh-5.6p1/ssh_config.redhat 2010-01-12 09:40:27.000000000 +0100
++++ openssh-5.6p1/ssh_config 2010-09-03 15:21:17.000000000 +0200
+@@ -45,3 +45,14 @@
+ # PermitLocalCommand no
+ # VisualHostKey no
+ # ProxyCommand ssh -q -W %h:%p gateway.example.com
++Host *
++ GSSAPIAuthentication yes
++# If this option is set to yes then remote X11 clients will have full access
++# to the original X11 display. As virtually no X11 client supports the untrusted
++# mode correctly we set this to yes.
++ ForwardX11Trusted yes
++# Send locale-related environment variables
++ SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
++ SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
++ SendEnv LC_IDENTIFICATION LC_ALL LANGUAGE
++ SendEnv XMODIFIERS
+diff -up openssh-5.6p1/sshd_config.0.redhat openssh-5.6p1/sshd_config.0
+--- openssh-5.6p1/sshd_config.0.redhat 2010-08-23 05:24:16.000000000 +0200
++++ openssh-5.6p1/sshd_config.0 2010-09-03 15:23:20.000000000 +0200
+@@ -537,9 +537,9 @@ DESCRIPTION
+
+ SyslogFacility
+ Gives the facility code that is used when logging messages from
+- sshd(8). The possible values are: DAEMON, USER, AUTH, LOCAL0,
+- LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The
+- default is AUTH.
++ sshd(8). The possible values are: DAEMON, USER, AUTH, AUTHPRIV,
++ LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
++ The default is AUTH.
+
+ TCPKeepAlive
+ Specifies whether the system should send TCP keepalive messages
+diff -up openssh-5.6p1/sshd_config.5.redhat openssh-5.6p1/sshd_config.5
+--- openssh-5.6p1/sshd_config.5.redhat 2010-07-02 05:37:17.000000000 +0200
++++ openssh-5.6p1/sshd_config.5 2010-09-03 15:21:17.000000000 +0200
+@@ -919,7 +919,7 @@ Note that this option applies to protoco
+ .It Cm SyslogFacility
+ Gives the facility code that is used when logging messages from
+ .Xr sshd 8 .
+-The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
++The possible values are: DAEMON, USER, AUTH, AUTHPRIV, LOCAL0, LOCAL1, LOCAL2,
+ LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
+ The default is AUTH.
+ .It Cm TCPKeepAlive
+diff -up openssh-5.6p1/sshd_config.redhat openssh-5.6p1/sshd_config
+--- openssh-5.6p1/sshd_config.redhat 2009-10-11 12:51:09.000000000 +0200
++++ openssh-5.6p1/sshd_config 2010-09-03 15:21:17.000000000 +0200
+@@ -31,6 +31,7 @@
+ # Logging
+ # obsoletes QuietMode and FascistLogging
+ #SyslogFacility AUTH
++SyslogFacility AUTHPRIV
+ #LogLevel INFO
+
+ # Authentication:
+@@ -58,9 +59,11 @@
+ # To disable tunneled clear text passwords, change to no here!
+ #PasswordAuthentication yes
+ #PermitEmptyPasswords no
++PasswordAuthentication yes
+
+ # Change to no to disable s/key passwords
+ #ChallengeResponseAuthentication yes
++ChallengeResponseAuthentication no
+
+ # Kerberos options
+ #KerberosAuthentication no
+@@ -70,7 +73,9 @@
+
+ # GSSAPI options
+ #GSSAPIAuthentication no
++GSSAPIAuthentication yes
+ #GSSAPICleanupCredentials yes
++GSSAPICleanupCredentials yes
+
+ # Set this to 'yes' to enable PAM authentication, account processing,
+ # and session processing. If this is enabled, PAM authentication will
+@@ -82,11 +87,19 @@
+ # PAM authentication, then enable this but set PasswordAuthentication
+ # and ChallengeResponseAuthentication to 'no'.
+ #UsePAM no
++UsePAM yes
++
++# Accept locale-related environment variables
++AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
++AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
++AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
++AcceptEnv XMODIFIERS
+
+ #AllowAgentForwarding yes
+ #AllowTcpForwarding yes
+ #GatewayPorts no
+ #X11Forwarding no
++X11Forwarding yes
+ #X11DisplayOffset 10
+ #X11UseLocalhost yes
+ #PrintMotd yes
--- /dev/null
+diff -up openssh-5.8p1/auth2-pubkey.c.akc openssh-5.8p1/auth2-pubkey.c
+--- openssh-5.8p1/auth2-pubkey.c.akc 2011-02-10 13:21:27.000000000 +0100
++++ openssh-5.8p1/auth2-pubkey.c 2011-02-10 13:21:28.000000000 +0100
+@@ -27,6 +27,7 @@
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <sys/wait.h>
+
+ #include <fcntl.h>
+ #include <pwd.h>
+@@ -268,27 +269,15 @@ match_principals_file(char *file, struct
+
+ /* return 1 if user allows given key */
+ static int
+-user_key_allowed2(struct passwd *pw, Key *key, char *file)
++user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
+ {
+ char line[SSH_MAX_PUBKEY_BYTES];
+ const char *reason;
+ int found_key = 0;
+- FILE *f;
+ u_long linenum = 0;
+ Key *found;
+ char *fp;
+
+- /* Temporarily use the user's uid. */
+- temporarily_use_uid(pw);
+-
+- debug("trying public key file %s", file);
+- f = auth_openkeyfile(file, pw, options.strict_modes);
+-
+- if (!f) {
+- restore_uid();
+- return 0;
+- }
+-
+ found_key = 0;
+ found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
+
+@@ -381,8 +370,6 @@ user_key_allowed2(struct passwd *pw, Key
+ break;
+ }
+ }
+- restore_uid();
+- fclose(f);
+ key_free(found);
+ if (!found_key)
+ debug2("key not found");
+@@ -444,13 +431,191 @@ user_cert_trusted_ca(struct passwd *pw,
+ return ret;
+ }
+
+-/* check whether given key is in .ssh/authorized_keys* */
++/* return 1 if user allows given key */
++static int
++user_key_allowed2(struct passwd *pw, Key *key, char *file)
++{
++ FILE *f;
++ int found_key = 0;
++
++ /* Temporarily use the user's uid. */
++ temporarily_use_uid(pw);
++
++ debug("trying public key file %s", file);
++ f = auth_openkeyfile(file, pw, options.strict_modes);
++
++ if (f) {
++ found_key = user_search_key_in_file (f, file, key, pw);
++ fclose(f);
++ }
++
++ restore_uid();
++ return found_key;
++}
++
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++
++#define WHITESPACE " \t\r\n"
++
++/* return 1 if user allows given key */
++static int
++user_key_via_command_allowed2(struct passwd *pw, Key *key)
++{
++ FILE *f;
++ int found_key = 0;
++ char *progname = NULL;
++ char *cp;
++ struct passwd *runas_pw;
++ struct stat st;
++ int childdescriptors[2], i;
++ pid_t pstat, pid, child;
++
++ if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/')
++ return -1;
++
++ /* get the run as identity from config */
++ runas_pw = (options.authorized_keys_command_runas == NULL)? pw
++ : getpwnam (options.authorized_keys_command_runas);
++ if (!runas_pw) {
++ error("%s: getpwnam(\"%s\"): %s", __func__,
++ options.authorized_keys_command_runas, strerror(errno));
++ return 0;
++ }
++
++ /* Temporarily use the specified uid. */
++ if (runas_pw->pw_uid != 0)
++ temporarily_use_uid(runas_pw);
++
++ progname = xstrdup(options.authorized_keys_command);
++
++ debug3("%s: checking program '%s'", __func__, progname);
++
++ if (stat (progname, &st) < 0) {
++ error("%s: stat(\"%s\"): %s", __func__,
++ progname, strerror(errno));
++ goto go_away;
++ }
++
++ if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
++ error("bad ownership or modes for AuthorizedKeysCommand \"%s\"",
++ progname);
++ goto go_away;
++ }
++
++ if (!S_ISREG(st.st_mode)) {
++ error("AuthorizedKeysCommand \"%s\" is not a regular file",
++ progname);
++ goto go_away;
++ }
++
++ /*
++ * Descend the path, checking that each component is a
++ * root-owned directory with strict permissions.
++ */
++ do {
++ if ((cp = strrchr(progname, '/')) == NULL)
++ break;
++ else
++ *cp = '\0';
++
++ debug3("%s: checking component '%s'", __func__, (*progname == '\0' ? "/" : progname));
++
++ if (stat((*progname == '\0' ? "/" : progname), &st) != 0) {
++ error("%s: stat(\"%s\"): %s", __func__,
++ progname, strerror(errno));
++ goto go_away;
++ }
++ if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
++ error("bad ownership or modes for AuthorizedKeysCommand path component \"%s\"",
++ progname);
++ goto go_away;
++ }
++ if (!S_ISDIR(st.st_mode)) {
++ error("AuthorizedKeysCommand path component \"%s\" is not a directory",
++ progname);
++ goto go_away;
++ }
++ } while (1);
++
++ /* open the pipe and read the keys */
++ if (pipe(childdescriptors)) {
++ error("failed to pipe(2) for AuthorizedKeysCommand: %s",
++ strerror(errno));
++ goto go_away;
++ }
++
++ child = fork();
++ if (child == -1) {
++ error("failed to fork(2) for AuthorizedKeysCommand: %s",
++ strerror(errno));
++ goto go_away;
++ } else if (child == 0) {
++ /* we're in the child process here -- we should never return from this block. */
++ /* permanently drop privs in child process */
++ if (runas_pw->pw_uid != 0) {
++ restore_uid();
++ permanently_set_uid(runas_pw);
++ }
++
++ close(childdescriptors[0]);
++ /* put the write end of the pipe on stdout (FD 1) */
++ if (dup2(childdescriptors[1], 1) == -1) {
++ error("failed to dup2(2) from AuthorizedKeysCommand: %s",
++ strerror(errno));
++ _exit(127);
++ }
++
++ debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name);
++ /* see session.c:child_close_fds() */
++ for (i = 3; i < 64; ++i) {
++ close(i);
++ }
++
++ execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL);
++
++ /* if we got here, it didn't work */
++ error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */
++ _exit(127);
++ }
++
++ close(childdescriptors[1]);
++ f = fdopen(childdescriptors[0], "r");
++ if (!f) {
++ error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__,
++ options.authorized_keys_command, strerror (errno));
++ goto go_away;
++ }
++
++ found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw);
++ fclose (f);
++ do {
++ pid = waitpid(child, &pstat, 0);
++ } while (pid == -1 && errno == EINTR);
++
++ /* what about the return value from the child process? */
++go_away:
++ if (progname)
++ xfree (progname);
++
++ if (runas_pw->pw_uid != 0)
++ restore_uid();
++ return found_key;
++}
++#endif
++
++/* check whether given key is in <AuthorizedKeysCommand or .ssh/authorized_keys* */
+ int
+ user_key_allowed(struct passwd *pw, Key *key)
+ {
+ int success;
+ char *file;
+
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++ success = user_key_via_command_allowed2(pw, key);
++ if (success > 0)
++ return success;
++#endif
++
+ if (auth_key_is_revoked(key))
+ return 0;
+ if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
+diff -up openssh-5.8p1/configure.ac.akc openssh-5.8p1/configure.ac
+--- openssh-5.8p1/configure.ac.akc 2011-02-10 13:21:28.000000000 +0100
++++ openssh-5.8p1/configure.ac 2011-02-10 13:21:28.000000000 +0100
+@@ -1422,6 +1422,18 @@ AC_ARG_WITH(audit,
+ esac ]
+ )
+
++# Check whether user wants AuthorizedKeysCommand support
++AKC_MSG="no"
++AC_ARG_WITH(authorized-keys-command,
++ [ --with-authorized-keys-command Enable AuthorizedKeysCommand support],
++ [
++ if test "x$withval" != "xno" ; then
++ AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support])
++ AKC_MSG="yes"
++ fi
++ ]
++)
++
+ dnl Checks for library functions. Please keep in alphabetical order
+ AC_CHECK_FUNCS( \
+ arc4random \
+@@ -4325,6 +4337,7 @@ echo " SELinux support
+ echo " Smartcard support: $SCARD_MSG"
+ echo " S/KEY support: $SKEY_MSG"
+ echo " TCP Wrappers support: $TCPW_MSG"
++echo " AuthorizedKeysCommand support: $AKC_MSG"
+ echo " MD5 password support: $MD5_MSG"
+ echo " libedit support: $LIBEDIT_MSG"
+ echo " Solaris process contract support: $SPC_MSG"
+diff -up openssh-5.8p1/servconf.c.akc openssh-5.8p1/servconf.c
+--- openssh-5.8p1/servconf.c.akc 2011-02-10 13:21:28.000000000 +0100
++++ openssh-5.8p1/servconf.c 2011-02-10 13:28:21.000000000 +0100
+@@ -134,6 +134,8 @@ initialize_server_options(ServerOptions
+ options->num_permitted_opens = -1;
+ options->adm_forced_command = NULL;
+ options->chroot_directory = NULL;
++ options->authorized_keys_command = NULL;
++ options->authorized_keys_command_runas = NULL;
+ options->zero_knowledge_password_authentication = -1;
+ options->revoked_keys_file = NULL;
+ options->trusted_user_ca_keys = NULL;
+@@ -331,6 +333,7 @@ typedef enum {
+ sZeroKnowledgePasswordAuthentication, sHostCertificate,
+ sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+ sKexAlgorithms, sIPQoS,
++ sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
+ sDeprecated, sUnsupported
+ } ServerOpCodes;
+
+@@ -456,6 +459,13 @@ static struct {
+ { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
+ { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+ { "ipqos", sIPQoS, SSHCFG_ALL },
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++ { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
++ { "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL },
++#else
++ { "authorizedkeyscommand", sUnsupported, SSHCFG_ALL },
++ { "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL },
++#endif
+ { NULL, sBadOption, 0 }
+ };
+
+@@ -1406,6 +1416,20 @@ process_server_config_line(ServerOptions
+ }
+ break;
+
++ case sAuthorizedKeysCommand:
++ len = strspn(cp, WHITESPACE);
++ if (*activep && options->authorized_keys_command == NULL)
++ options->authorized_keys_command = xstrdup(cp + len);
++ return 0;
++
++ case sAuthorizedKeysCommandRunAs:
++ charptr = &options->authorized_keys_command_runas;
++
++ arg = strdelim(&cp);
++ if (*activep && *charptr == NULL)
++ *charptr = xstrdup(arg);
++ break;
++
+ case sDeprecated:
+ logit("%s line %d: Deprecated option %s",
+ filename, linenum, arg);
+@@ -1499,6 +1523,8 @@ copy_set_server_options(ServerOptions *d
+ M_CP_INTOPT(gss_authentication);
+ M_CP_INTOPT(rsa_authentication);
+ M_CP_INTOPT(pubkey_authentication);
++ M_CP_STROPT(authorized_keys_command);
++ M_CP_STROPT(authorized_keys_command_runas);
+ M_CP_INTOPT(kerberos_authentication);
+ M_CP_INTOPT(hostbased_authentication);
+ M_CP_INTOPT(hostbased_uses_name_from_packet_only);
+@@ -1753,6 +1779,8 @@ dump_config(ServerOptions *o)
+ dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+ dump_cfg_string(sAuthorizedPrincipalsFile,
+ o->authorized_principals_file);
++ dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
++ dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas);
+
+ /* string arguments requiring a lookup */
+ dump_cfg_string(sLogLevel, log_level_name(o->log_level));
+diff -up openssh-5.8p1/servconf.h.akc openssh-5.8p1/servconf.h
+--- openssh-5.8p1/servconf.h.akc 2011-02-10 13:21:28.000000000 +0100
++++ openssh-5.8p1/servconf.h 2011-02-10 13:21:28.000000000 +0100
+@@ -161,6 +161,8 @@ typedef struct {
+ char *revoked_keys_file;
+ char *trusted_user_ca_keys;
+ char *authorized_principals_file;
++ char *authorized_keys_command;
++ char *authorized_keys_command_runas;
+ } ServerOptions;
+
+ void initialize_server_options(ServerOptions *);
+diff -up openssh-5.8p1/sshd_config.0.akc openssh-5.8p1/sshd_config.0
+--- openssh-5.8p1/sshd_config.0.akc 2011-02-10 13:21:28.000000000 +0100
++++ openssh-5.8p1/sshd_config.0 2011-02-10 13:21:28.000000000 +0100
+@@ -71,6 +71,23 @@ DESCRIPTION
+
+ See PATTERNS in ssh_config(5) for more information on patterns.
+
++ AuthorizedKeysCommand
++
++ Specifies a program to be used for lookup of the user's
++ public keys. The program will be invoked with its first
++ argument the name of the user being authorized, and should produce
++ on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
++ in sshd(8)). By default (or when set to the empty string) there is no
++ AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
++ authorize the user, authorization falls through to the
++ AuthorizedKeysFile. Note that this option has an effect
++ only with PubkeyAuthentication turned on.
++
++ AuthorizedKeysCommandRunAs
++ Specifies the user under whose account the AuthorizedKeysCommand is run.
++ Empty string (the default value) means the user being authorized
++ is used.
++
+ AuthorizedKeysFile
+ Specifies the file that contains the public keys that can be used
+ for user authentication. The format is described in the
+@@ -398,7 +415,8 @@ DESCRIPTION
+
+ Only a subset of keywords may be used on the lines following a
+ Match keyword. Available keywords are AllowAgentForwarding,
+- AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
++ AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand,
++ AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile,
+ Banner, ChrootDirectory, ForceCommand, GatewayPorts,
+ GSSAPIAuthentication, HostbasedAuthentication,
+ HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
+diff -up openssh-5.8p1/sshd_config.5.akc openssh-5.8p1/sshd_config.5
+--- openssh-5.8p1/sshd_config.5.akc 2011-02-10 13:21:28.000000000 +0100
++++ openssh-5.8p1/sshd_config.5 2011-02-10 13:21:28.000000000 +0100
+@@ -703,6 +703,8 @@ Available keywords are
+ .Cm AllowAgentForwarding ,
+ .Cm AllowTcpForwarding ,
+ .Cm AuthorizedKeysFile ,
++.Cm AuthorizedKeysCommand ,
++.Cm AuthorizedKeysCommandRunAs ,
+ .Cm AuthorizedPrincipalsFile ,
+ .Cm Banner ,
+ .Cm ChrootDirectory ,
+@@ -715,6 +717,7 @@ Available keywords are
+ .Cm KerberosAuthentication ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
++.Cm PubkeyAuthentication ,
+ .Cm PasswordAuthentication ,
+ .Cm PermitEmptyPasswords ,
+ .Cm PermitOpen ,
+@@ -917,6 +920,20 @@ Specifies a list of revoked public keys.
+ Keys listed in this file will be refused for public key authentication.
+ Note that if this file is not readable, then public key authentication will
+ be refused for all users.
++.It Cm AuthorizedKeysCommand
++Specifies a program to be used for lookup of the user's
++public keys. The program will be invoked with its first
++argument the name of the user being authorized, and should produce
++on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
++in sshd(8)). By default (or when set to the empty string) there is no
++AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not successfully
++authorize the user, authorization falls through to the
++AuthorizedKeysFile. Note that this option has an effect
++only with PubkeyAuthentication turned on.
++.It Cm AuthorizedKeysCommandRunAs
++Specifies the user under whose account the AuthorizedKeysCommand is run. Empty
++string (the default value) means the user being authorized is used.
++.Dq
+ .It Cm RhostsRSAAuthentication
+ Specifies whether rhosts or /etc/hosts.equiv authentication together
+ with successful RSA host authentication is allowed.
+diff -up openssh-5.8p1/sshd_config.akc openssh-5.8p1/sshd_config
+--- openssh-5.8p1/sshd_config.akc 2011-02-10 13:21:28.000000000 +0100
++++ openssh-5.8p1/sshd_config 2011-02-10 13:21:28.000000000 +0100
+@@ -46,6 +46,8 @@ SyslogFacility AUTHPRIV
+ #RSAAuthentication yes
+ #PubkeyAuthentication yes
+ #AuthorizedKeysFile .ssh/authorized_keys
++#AuthorizedKeysCommand none
++#AuthorizedKeysCommandRunAs nobody
+
+ # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+ #RhostsRSAAuthentication no
--- /dev/null
+diff -up openssh-5.8p1/auth2-hostbased.c.fingerprint openssh-5.8p1/auth2-hostbased.c
+--- openssh-5.8p1/auth2-hostbased.c.fingerprint 2010-08-05 05:04:50.000000000 +0200
++++ openssh-5.8p1/auth2-hostbased.c 2011-02-25 09:17:18.000000000 +0100
+@@ -196,16 +196,18 @@ hostbased_key_allowed(struct passwd *pw,
+
+ if (host_status == HOST_OK) {
+ if (key_is_cert(key)) {
+- fp = key_fingerprint(key->cert->signature_key,
+- SSH_FP_MD5, SSH_FP_HEX);
++ fp = key_selected_fingerprint(key->cert->signature_key,
++ SSH_FP_HEX);
+ verbose("Accepted certificate ID \"%s\" signed by "
+- "%s CA %s from %s@%s", key->cert->key_id,
+- key_type(key->cert->signature_key), fp,
++ "%s CA %s%s from %s@%s", key->cert->key_id,
++ key_type(key->cert->signature_key),
++ key_fingerprint_prefix(), fp,
+ cuser, lookup);
+ } else {
+- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+- verbose("Accepted %s public key %s from %s@%s",
+- key_type(key), fp, cuser, lookup);
++ fp = key_selected_fingerprint(key, SSH_FP_HEX);
++ verbose("Accepted %s public key %s%s from %s@%s",
++ key_type(key), key_fingerprint_prefix(),
++ fp, cuser, lookup);
+ }
+ xfree(fp);
+ }
+diff -up openssh-5.8p1/auth2-pubkey.c.fingerprint openssh-5.8p1/auth2-pubkey.c
+--- openssh-5.8p1/auth2-pubkey.c.fingerprint 2010-12-01 01:50:14.000000000 +0100
++++ openssh-5.8p1/auth2-pubkey.c 2011-02-25 09:17:18.000000000 +0100
+@@ -319,10 +319,10 @@ user_key_allowed2(struct passwd *pw, Key
+ continue;
+ if (!key_is_cert_authority)
+ continue;
+- fp = key_fingerprint(found, SSH_FP_MD5,
+- SSH_FP_HEX);
+- debug("matching CA found: file %s, line %lu, %s %s",
+- file, linenum, key_type(found), fp);
++ fp = key_selected_fingerprint(found, SSH_FP_HEX);
++ debug("matching CA found: file %s, line %lu, %s %s%s",
++ file, linenum, key_type(found),
++ key_fingerprint_prefix(), fp);
+ /*
+ * If the user has specified a list of principals as
+ * a key option, then prefer that list to matching
+@@ -362,9 +362,9 @@ user_key_allowed2(struct passwd *pw, Key
+ found_key = 1;
+ debug("matching key found: file %s, line %lu",
+ file, linenum);
+- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+- verbose("Found matching %s key: %s",
+- key_type(found), fp);
++ fp = key_selected_fingerprint(found, SSH_FP_HEX);
++ verbose("Found matching %s key: %s%s",
++ key_type(found), key_fingerprint_prefix(), fp);
+ xfree(fp);
+ break;
+ }
+@@ -388,13 +388,13 @@ user_cert_trusted_ca(struct passwd *pw,
+ if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
+ return 0;
+
+- ca_fp = key_fingerprint(key->cert->signature_key,
+- SSH_FP_MD5, SSH_FP_HEX);
++ ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
+
+ if (key_in_file(key->cert->signature_key,
+ options.trusted_user_ca_keys, 1) != 1) {
+- debug2("%s: CA %s %s is not listed in %s", __func__,
+- key_type(key->cert->signature_key), ca_fp,
++ debug2("%s: CA %s%s %s is not listed in %s", __func__,
++ key_type(key->cert->signature_key),
++ key_fingerprint_prefix(), ca_fp,
+ options.trusted_user_ca_keys);
+ goto out;
+ }
+diff -up openssh-5.8p1/auth.c.fingerprint openssh-5.8p1/auth.c
+--- openssh-5.8p1/auth.c.fingerprint 2010-12-01 02:21:51.000000000 +0100
++++ openssh-5.8p1/auth.c 2011-02-25 09:17:18.000000000 +0100
+@@ -639,9 +639,10 @@ auth_key_is_revoked(Key *key)
+ return 1;
+ case 1:
+ /* Key revoked */
+- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
++ key_fp = key_selected_fingerprint(key, SSH_FP_HEX);
+ error("WARNING: authentication attempt with a revoked "
+- "%s key %s ", key_type(key), key_fp);
++ "%s key %s%s ", key_type(key),
++ key_fingerprint_prefix(), key_fp);
+ xfree(key_fp);
+ return 1;
+ }
+diff -up openssh-5.8p1/auth-rsa.c.fingerprint openssh-5.8p1/auth-rsa.c
+--- openssh-5.8p1/auth-rsa.c.fingerprint 2010-12-04 23:01:47.000000000 +0100
++++ openssh-5.8p1/auth-rsa.c 2011-02-25 09:17:18.000000000 +0100
+@@ -318,9 +318,9 @@ auth_rsa(Authctxt *authctxt, BIGNUM *cli
+ * options; this will be reset if the options cause the
+ * authentication to be rejected.
+ */
+- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+- verbose("Found matching %s key: %s",
+- key_type(key), fp);
++ fp = key_selected_fingerprint(key, SSH_FP_HEX);
++ verbose("Found matching %s key: %s%s",
++ key_type(key), key_fingerprint_prefix(), fp);
+ xfree(fp);
+ key_free(key);
+
+diff -up openssh-5.8p1/key.c.fingerprint openssh-5.8p1/key.c
+--- openssh-5.8p1/key.c.fingerprint 2011-02-04 01:48:34.000000000 +0100
++++ openssh-5.8p1/key.c 2011-02-25 09:18:16.000000000 +0100
+@@ -594,6 +594,34 @@ key_fingerprint(Key *k, enum fp_type dgs
+ return retval;
+ }
+
++enum fp_type
++key_fingerprint_selection(void)
++{
++ static enum fp_type rv;
++ static char rv_defined = 0;
++ char *env;
++
++ if (!rv_defined) {
++ env = getenv("SSH_FINGERPRINT_TYPE");
++ rv = (env && !strcmp (env, "sha")) ?
++ SSH_FP_SHA1 : SSH_FP_MD5;
++ rv_defined = 1;
++ }
++ return rv;
++}
++
++char *
++key_selected_fingerprint(Key *k, enum fp_rep dgst_rep)
++{
++ return key_fingerprint(k, key_fingerprint_selection(), dgst_rep);
++}
++
++char *
++key_fingerprint_prefix(void)
++{
++ return key_fingerprint_selection() == SSH_FP_SHA1 ? "sha1:" : "";
++}
++
+ /*
+ * Reads a multiple-precision integer in decimal from the buffer, and advances
+ * the pointer. The integer must already be initialized. This function is
+diff -up openssh-5.8p1/key.h.fingerprint openssh-5.8p1/key.h
+--- openssh-5.8p1/key.h.fingerprint 2010-11-05 00:19:49.000000000 +0100
++++ openssh-5.8p1/key.h 2011-02-25 09:17:18.000000000 +0100
+@@ -96,6 +96,9 @@ int key_equal_public(const Key *, cons
+ int key_equal(const Key *, const Key *);
+ char *key_fingerprint(Key *, enum fp_type, enum fp_rep);
+ u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *);
++enum fp_type key_fingerprint_selection(void);
++char *key_selected_fingerprint(Key *, enum fp_rep);
++char *key_fingerprint_prefix(void);
+ const char *key_type(const Key *);
+ const char *key_cert_type(const Key *);
+ int key_write(const Key *, FILE *);
+diff -up openssh-5.8p1/ssh-add.c.fingerprint openssh-5.8p1/ssh-add.c
+--- openssh-5.8p1/ssh-add.c.fingerprint 2010-11-11 04:17:02.000000000 +0100
++++ openssh-5.8p1/ssh-add.c 2011-02-25 09:17:18.000000000 +0100
+@@ -280,10 +280,10 @@ list_identities(AuthenticationConnection
+ key = ssh_get_next_identity(ac, &comment, version)) {
+ had_identities = 1;
+ if (do_fp) {
+- fp = key_fingerprint(key, SSH_FP_MD5,
+- SSH_FP_HEX);
+- printf("%d %s %s (%s)\n",
+- key_size(key), fp, comment, key_type(key));
++ fp = key_selected_fingerprint(key, SSH_FP_HEX);
++ printf("%d %s%s %s (%s)\n",
++ key_size(key), key_fingerprint_prefix(),
++ fp, comment, key_type(key));
+ xfree(fp);
+ } else {
+ if (!key_write(key, stdout))
+diff -up openssh-5.8p1/ssh-agent.c.fingerprint openssh-5.8p1/ssh-agent.c
+--- openssh-5.8p1/ssh-agent.c.fingerprint 2010-12-01 01:50:35.000000000 +0100
++++ openssh-5.8p1/ssh-agent.c 2011-02-25 09:17:18.000000000 +0100
+@@ -199,9 +199,9 @@ confirm_key(Identity *id)
+ char *p;
+ int ret = -1;
+
+- p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+- if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
+- id->comment, p))
++ p = key_selected_fingerprint(id->key, SSH_FP_HEX);
++ if (ask_permission("Allow use of key %s?\nKey fingerprint %s%s.",
++ id->comment, key_fingerprint_prefix(), p))
+ ret = 0;
+ xfree(p);
+
+diff -up openssh-5.8p1/sshconnect2.c.fingerprint openssh-5.8p1/sshconnect2.c
+--- openssh-5.8p1/sshconnect2.c.fingerprint 2010-12-01 02:21:51.000000000 +0100
++++ openssh-5.8p1/sshconnect2.c 2011-02-25 09:17:18.000000000 +0100
+@@ -590,8 +590,9 @@ input_userauth_pk_ok(int type, u_int32_t
+ key->type, pktype);
+ goto done;
+ }
+- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+- debug2("input_userauth_pk_ok: fp %s", fp);
++ fp = key_selected_fingerprint(key, SSH_FP_HEX);
++ debug2("input_userauth_pk_ok: fp %s%s",
++ key_fingerprint_prefix(), fp);
+ xfree(fp);
+
+ /*
+@@ -1203,8 +1204,9 @@ sign_and_send_pubkey(Authctxt *authctxt,
+ int have_sig = 1;
+ char *fp;
+
+- fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+- debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
++ fp = key_selected_fingerprint(id->key, SSH_FP_HEX);
++ debug3("sign_and_send_pubkey: %s %s%s", key_type(id->key),
++ key_fingerprint_prefix(), fp);
+ xfree(fp);
+
+ if (key_to_blob(id->key, &blob, &bloblen) == 0) {
+diff -up openssh-5.8p1/sshconnect.c.fingerprint openssh-5.8p1/sshconnect.c
+--- openssh-5.8p1/sshconnect.c.fingerprint 2011-01-16 13:17:59.000000000 +0100
++++ openssh-5.8p1/sshconnect.c 2011-02-25 09:17:18.000000000 +0100
+@@ -798,10 +798,10 @@ check_host_key(char *hostname, struct so
+ "key for IP address '%.128s' to the list "
+ "of known hosts.", type, ip);
+ } else if (options.visual_host_key) {
+- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+- ra = key_fingerprint(host_key, SSH_FP_MD5,
+- SSH_FP_RANDOMART);
+- logit("Host key fingerprint is %s\n%s\n", fp, ra);
++ fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
++ ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART);
++ logit("Host key fingerprint is %s%s\n%s\n",
++ key_fingerprint_prefix(), fp, ra);
+ xfree(ra);
+ xfree(fp);
+ }
+@@ -838,9 +838,8 @@ check_host_key(char *hostname, struct so
+ else
+ snprintf(msg1, sizeof(msg1), ".");
+ /* The default */
+- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+- ra = key_fingerprint(host_key, SSH_FP_MD5,
+- SSH_FP_RANDOMART);
++ fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
++ ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART);
+ msg2[0] = '\0';
+ if (options.verify_host_key_dns) {
+ if (matching_host_key_dns)
+@@ -855,10 +854,11 @@ check_host_key(char *hostname, struct so
+ snprintf(msg, sizeof(msg),
+ "The authenticity of host '%.200s (%s)' can't be "
+ "established%s\n"
+- "%s key fingerprint is %s.%s%s\n%s"
++ "%s key fingerprint is %s%s.%s%s\n%s"
+ "Are you sure you want to continue connecting "
+ "(yes/no)? ",
+- host, ip, msg1, type, fp,
++ host, ip, msg1, type,
++ key_fingerprint_prefix(), fp,
+ options.visual_host_key ? "\n" : "",
+ options.visual_host_key ? ra : "",
+ msg2);
+@@ -1104,8 +1104,9 @@ verify_host_key(char *host, struct socka
+ int flags = 0;
+ char *fp;
+
+- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+- debug("Server host key: %s %s", key_type(host_key), fp);
++ fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
++ debug("Server host key: %s %s%s", key_type(host_key),
++ key_fingerprint_prefix(), fp);
+ xfree(fp);
+
+ /* XXX certs are not yet supported for DNS */
+@@ -1214,14 +1215,15 @@ show_other_keys(struct hostkeys *hostkey
+ continue;
+ if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
+ continue;
+- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
+- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
++ fp = key_selected_fingerprint(found->key, SSH_FP_HEX);
++ ra = key_selected_fingerprint(found->key, SSH_FP_RANDOMART);
+ logit("WARNING: %s key found for host %s\n"
+ "in %s:%lu\n"
+- "%s key fingerprint %s.",
++ "%s key fingerprint %s%s.",
+ key_type(found->key),
+ found->host, found->file, found->line,
+- key_type(found->key), fp);
++ key_type(found->key),
++ key_fingerprint_prefix(), fp);
+ if (options.visual_host_key)
+ logit("%s", ra);
+ xfree(ra);
+@@ -1236,7 +1238,7 @@ warn_changed_key(Key *host_key)
+ {
+ char *fp;
+
+- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
++ fp = key_selected_fingerprint(host_key, SSH_FP_HEX);
+
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
+@@ -1244,8 +1246,8 @@ warn_changed_key(Key *host_key)
+ error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
+ error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
+ error("It is also possible that a host key has just been changed.");
+- error("The fingerprint for the %s key sent by the remote host is\n%s.",
+- key_type(host_key), fp);
++ error("The fingerprint for the %s key sent by the remote host is\n%s%s.",
++ key_type(host_key),key_fingerprint_prefix(), fp);
+ error("Please contact your system administrator.");
+
+ xfree(fp);
+diff -up openssh-5.8p1/ssh-keygen.c.fingerprint openssh-5.8p1/ssh-keygen.c
+--- openssh-5.8p1/ssh-keygen.c.fingerprint 2011-01-11 07:20:31.000000000 +0100
++++ openssh-5.8p1/ssh-keygen.c 2011-02-25 09:17:18.000000000 +0100
+@@ -714,13 +714,14 @@ do_fingerprint(struct passwd *pw)
+ {
+ FILE *f;
+ Key *public;
+- char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
++ char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra, *pfx;
+ int i, skip = 0, num = 0, invalid = 1;
+ enum fp_rep rep;
+ enum fp_type fptype;
+ struct stat st;
+
+- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
++ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
++ pfx = print_bubblebabble ? "" : key_fingerprint_prefix();
+ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+
+ if (!have_identity)
+@@ -732,8 +733,8 @@ do_fingerprint(struct passwd *pw)
+ public = key_load_public(identity_file, &comment);
+ if (public != NULL) {
+ fp = key_fingerprint(public, fptype, rep);
+- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+- printf("%u %s %s (%s)\n", key_size(public), fp, comment,
++ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
++ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, comment,
+ key_type(public));
+ if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ printf("%s\n", ra);
+@@ -798,8 +799,8 @@ do_fingerprint(struct passwd *pw)
+ }
+ comment = *cp ? cp : comment;
+ fp = key_fingerprint(public, fptype, rep);
+- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+- printf("%u %s %s (%s)\n", key_size(public), fp,
++ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
++ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp,
+ comment ? comment : "no comment", key_type(public));
+ if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ printf("%s\n", ra);
+@@ -823,13 +824,15 @@ printhost(FILE *f, const char *name, Key
+ if (print_fingerprint) {
+ enum fp_rep rep;
+ enum fp_type fptype;
+- char *fp, *ra;
++ char *fp, *ra, *pfx;
+
+- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
++ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection();
++ pfx = print_bubblebabble ? "" : key_fingerprint_prefix();
+ rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
++
+ fp = key_fingerprint(public, fptype, rep);
+- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+- printf("%u %s %s (%s)\n", key_size(public), fp, name,
++ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
++ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, name,
+ key_type(public));
+ if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ printf("%s\n", ra);
+@@ -1695,16 +1698,17 @@ do_show_cert(struct passwd *pw)
+ fatal("%s is not a certificate", identity_file);
+ v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00;
+
+- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+- ca_fp = key_fingerprint(key->cert->signature_key,
+- SSH_FP_MD5, SSH_FP_HEX);
++ key_fp = key_selected_fingerprint(key, SSH_FP_HEX);
++ ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX);
+
+ printf("%s:\n", identity_file);
+ printf(" Type: %s %s certificate\n", key_ssh_name(key),
+ key_cert_type(key));
+- printf(" Public key: %s %s\n", key_type(key), key_fp);
+- printf(" Signing CA: %s %s\n",
+- key_type(key->cert->signature_key), ca_fp);
++ printf(" Public key: %s %s%s\n", key_type(key),
++ key_fingerprint_prefix(), key_fp);
++ printf(" Signing CA: %s %s%s\n",
++ key_type(key->cert->signature_key),
++ key_fingerprint_prefix(), ca_fp);
+ printf(" Key ID: \"%s\"\n", key->cert->key_id);
+ if (!v00) {
+ printf(" Serial: %llu\n",
+@@ -2249,13 +2253,12 @@ passphrase_again:
+ fclose(f);
+
+ if (!quiet) {
+- char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
+- char *ra = key_fingerprint(public, SSH_FP_MD5,
+- SSH_FP_RANDOMART);
++ char *fp = key_selected_fingerprint(public, SSH_FP_HEX);
++ char *ra = key_selected_fingerprint(public, SSH_FP_RANDOMART);
+ printf("Your public key has been saved in %s.\n",
+ identity_file);
+ printf("The key fingerprint is:\n");
+- printf("%s %s\n", fp, comment);
++ printf("%s%s %s\n", key_fingerprint_prefix(), fp, comment);
+ printf("The key's randomart image is:\n");
+ printf("%s\n", ra);
+ xfree(ra);
--- /dev/null
+diff -up openssh-5.8p1/auth-krb5.c.kuserok openssh-5.8p1/auth-krb5.c
+--- openssh-5.8p1/auth-krb5.c.kuserok 2009-12-21 00:49:22.000000000 +0100
++++ openssh-5.8p1/auth-krb5.c 2011-02-14 09:15:12.000000000 +0100
+@@ -54,6 +54,20 @@
+
+ extern ServerOptions options;
+
++int
++ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client)
++{
++ if (options.use_kuserok)
++ return krb5_kuserok(krb5_ctx, krb5_user, client);
++ else {
++ char kuser[65];
++
++ if (krb5_aname_to_localname(krb5_ctx, krb5_user, sizeof(kuser), kuser))
++ return 0;
++ return strcmp(kuser, client) == 0;
++ }
++}
++
+ static int
+ krb5_init(void *context)
+ {
+@@ -146,7 +160,7 @@ auth_krb5_password(Authctxt *authctxt, c
+ if (problem)
+ goto out;
+
+- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) {
++ if (!ssh_krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) {
+ problem = -1;
+ goto out;
+ }
+diff -up openssh-5.8p1/gss-serv-krb5.c.kuserok openssh-5.8p1/gss-serv-krb5.c
+--- openssh-5.8p1/gss-serv-krb5.c.kuserok 2006-09-01 07:38:36.000000000 +0200
++++ openssh-5.8p1/gss-serv-krb5.c 2011-02-14 09:15:12.000000000 +0100
+@@ -57,6 +57,7 @@ extern ServerOptions options;
+ #endif
+
+ static krb5_context krb_context = NULL;
++extern int ssh_krb5_kuserok(krb5_context, krb5_principal, const char *);
+
+ /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
+
+@@ -97,7 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
+ krb5_get_err_text(krb_context, retval));
+ return 0;
+ }
+- if (krb5_kuserok(krb_context, princ, name)) {
++ if (ssh_krb5_kuserok(krb_context, princ, name)) {
+ retval = 1;
+ logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+ name, (char *)client->displayname.value);
+diff -up openssh-5.8p1/servconf.c.kuserok openssh-5.8p1/servconf.c
+--- openssh-5.8p1/servconf.c.kuserok 2011-02-14 09:15:12.000000000 +0100
++++ openssh-5.8p1/servconf.c 2011-02-14 09:20:22.000000000 +0100
+@@ -142,6 +142,7 @@ initialize_server_options(ServerOptions
+ options->authorized_principals_file = NULL;
+ options->ip_qos_interactive = -1;
+ options->ip_qos_bulk = -1;
++ options->use_kuserok = -1;
+ }
+
+ void
+@@ -291,6 +292,8 @@ fill_default_server_options(ServerOption
+ if (use_privsep == -1)
+ use_privsep = 1;
+
++ if (options->use_kuserok == -1)
++ options->use_kuserok = 1;
+ #ifndef HAVE_MMAP
+ if (use_privsep && options->compression == 1) {
+ error("This platform does not support both privilege "
+@@ -312,7 +315,7 @@ typedef enum {
+ sPermitRootLogin, sLogFacility, sLogLevel,
+ sRhostsRSAAuthentication, sRSAAuthentication,
+ sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
+- sKerberosGetAFSToken,
++ sKerberosGetAFSToken, sKerberosUseKuserok,
+ sKerberosTgtPassing, sChallengeResponseAuthentication,
+ sPasswordAuthentication, sKbdInteractiveAuthentication,
+ sListenAddress, sAddressFamily,
+@@ -381,11 +384,13 @@ static struct {
+ #else
+ { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
+ #endif
++ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL },
+ #else
+ { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
+ { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
+ { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
+ { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
++ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL },
+ #endif
+ { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
+ { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
+@@ -1341,6 +1346,10 @@ process_server_config_line(ServerOptions
+ *activep = value;
+ break;
+
++ case sKerberosUseKuserok:
++ intptr = &options->use_kuserok;
++ goto parse_flag;
++
+ case sPermitOpen:
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+@@ -1544,6 +1553,7 @@ copy_set_server_options(ServerOptions *d
+ M_CP_INTOPT(max_authtries);
+ M_CP_INTOPT(ip_qos_interactive);
+ M_CP_INTOPT(ip_qos_bulk);
++ M_CP_INTOPT(use_kuserok);
+
+ M_CP_STROPT(banner);
+ if (preauth)
+@@ -1764,6 +1774,7 @@ dump_config(ServerOptions *o)
+ dump_cfg_fmtint(sUseDNS, o->use_dns);
+ dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+ dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
++ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
+
+ /* string arguments */
+ dump_cfg_string(sPidFile, o->pid_file);
+diff -up openssh-5.8p1/servconf.h.kuserok openssh-5.8p1/servconf.h
+--- openssh-5.8p1/servconf.h.kuserok 2011-02-14 09:15:12.000000000 +0100
++++ openssh-5.8p1/servconf.h 2011-02-14 09:15:12.000000000 +0100
+@@ -157,6 +157,7 @@ typedef struct {
+
+ int num_permitted_opens;
+
++ int use_kuserok;
+ char *chroot_directory;
+ char *revoked_keys_file;
+ char *trusted_user_ca_keys;
+diff -up openssh-5.8p1/sshd_config.5.kuserok openssh-5.8p1/sshd_config.5
+--- openssh-5.8p1/sshd_config.5.kuserok 2011-02-14 09:15:12.000000000 +0100
++++ openssh-5.8p1/sshd_config.5 2011-02-14 09:17:11.000000000 +0100
+@@ -574,6 +574,10 @@ Specifies whether to automatically destr
+ file on logout.
+ The default is
+ .Dq yes .
++.It Cm KerberosUseKuserok
++Specifies whether to look at .k5login file for user's aliases.
++The default is
++.Dq yes .
+ .It Cm KexAlgorithms
+ Specifies the available KEX (Key Exchange) algorithms.
+ Multiple algorithms must be comma-separated.
+@@ -715,6 +719,7 @@ Available keywords are
+ .Cm HostbasedUsesNameFromPacketOnly ,
+ .Cm KbdInteractiveAuthentication ,
+ .Cm KerberosAuthentication ,
++.Cm KerberosUseKuserok ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
+ .Cm PubkeyAuthentication ,
+diff -up openssh-5.8p1/sshd_config.kuserok openssh-5.8p1/sshd_config
+--- openssh-5.8p1/sshd_config.kuserok 2011-02-14 09:15:12.000000000 +0100
++++ openssh-5.8p1/sshd_config 2011-02-14 09:15:12.000000000 +0100
+@@ -73,6 +73,7 @@ ChallengeResponseAuthentication no
+ #KerberosOrLocalPasswd yes
+ #KerberosTicketCleanup yes
+ #KerberosGetAFSToken no
++#KerberosUseKuserok yes
+
+ # GSSAPI options
+ #GSSAPIAuthentication no
--- /dev/null
+diff -up openssh-5.8p1/misc.c.mls openssh-5.8p1/misc.c
+--- openssh-5.8p1/misc.c.mls 2011-01-13 02:21:36.000000000 +0100
++++ openssh-5.8p1/misc.c 2011-02-12 15:05:06.000000000 +0100
+@@ -427,6 +427,7 @@ char *
+ colon(char *cp)
+ {
+ int flag = 0;
++ int start = 1;
+
+ if (*cp == ':') /* Leading colon is part of file name. */
+ return NULL;
+@@ -442,6 +443,13 @@ colon(char *cp)
+ return (cp);
+ if (*cp == '/')
+ return NULL;
++ if (start) {
++ /* Slash on beginning or after dots only denotes file name. */
++ if (*cp == '/')
++ return (0);
++ if (*cp != '.')
++ start = 0;
++ }
+ }
+ return NULL;
+ }
+diff -up openssh-5.8p1/openbsd-compat/port-linux.c.mls openssh-5.8p1/openbsd-compat/port-linux.c
+--- openssh-5.8p1/openbsd-compat/port-linux.c.mls 2011-02-12 15:05:06.000000000 +0100
++++ openssh-5.8p1/openbsd-compat/port-linux.c 2011-02-12 15:09:23.000000000 +0100
+@@ -40,13 +40,164 @@
+ #ifdef WITH_SELINUX
+ #include <selinux/selinux.h>
+ #include <selinux/flask.h>
++#include <selinux/context.h>
+ #include <selinux/get_context_list.h>
++#include <selinux/get_default_type.h>
++#include <selinux/av_permissions.h>
++
++#ifdef HAVE_LINUX_AUDIT
++#include <libaudit.h>
++#include <unistd.h>
++#endif
+
+ extern ServerOptions options;
+ extern Authctxt *the_authctxt;
+ extern int inetd_flag;
+ extern int rexeced_flag;
+
++/* Send audit message */
++static int
++send_audit_message(int success, security_context_t default_context,
++ security_context_t selected_context)
++{
++ int rc=0;
++#ifdef HAVE_LINUX_AUDIT
++ char *msg = NULL;
++ int audit_fd = audit_open();
++ security_context_t default_raw=NULL;
++ security_context_t selected_raw=NULL;
++ rc = -1;
++ if (audit_fd < 0) {
++ if (errno == EINVAL || errno == EPROTONOSUPPORT ||
++ errno == EAFNOSUPPORT)
++ return 0; /* No audit support in kernel */
++ error("Error connecting to audit system.");
++ return rc;
++ }
++ if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) {
++ error("Error translating default context.");
++ default_raw = NULL;
++ }
++ if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) {
++ error("Error translating selected context.");
++ selected_raw = NULL;
++ }
++ if (asprintf(&msg, "sshd: default-context=%s selected-context=%s",
++ default_raw ? default_raw : (default_context ? default_context: "?"),
++ selected_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) {
++ error("Error allocating memory.");
++ goto out;
++ }
++ if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE,
++ msg, NULL, NULL, NULL, success) <= 0) {
++ error("Error sending audit message.");
++ goto out;
++ }
++ rc = 0;
++ out:
++ free(msg);
++ freecon(default_raw);
++ freecon(selected_raw);
++ close(audit_fd);
++#endif
++ return rc;
++}
++
++static int
++mls_range_allowed(security_context_t src, security_context_t dst)
++{
++ struct av_decision avd;
++ int retval;
++ unsigned int bit = CONTEXT__CONTAINS;
++
++ debug("%s: src:%s dst:%s", __func__, src, dst);
++ retval = security_compute_av(src, dst, SECCLASS_CONTEXT, bit, &avd);
++ if (retval || ((bit & avd.allowed) != bit))
++ return 0;
++
++ return 1;
++}
++
++static int
++get_user_context(const char *sename, const char *role, const char *lvl,
++ security_context_t *sc) {
++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
++ if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 0) {
++ /* User may have requested a level completely outside of his
++ allowed range. We get a context just for auditing as the
++ range check below will certainly fail for default context. */
++#endif
++ if (get_default_context(sename, NULL, sc) != 0) {
++ *sc = NULL;
++ return -1;
++ }
++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
++ }
++#endif
++ if (role != NULL && role[0]) {
++ context_t con;
++ char *type=NULL;
++ if (get_default_type(role, &type) != 0) {
++ error("get_default_type: failed to get default type for '%s'",
++ role);
++ goto out;
++ }
++ con = context_new(*sc);
++ if (!con) {
++ goto out;
++ }
++ context_role_set(con, role);
++ context_type_set(con, type);
++ freecon(*sc);
++ *sc = strdup(context_str(con));
++ context_free(con);
++ if (!*sc)
++ return -1;
++ }
++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
++ if (lvl != NULL && lvl[0]) {
++ /* verify that the requested range is obtained */
++ context_t con;
++ security_context_t obtained_raw;
++ security_context_t requested_raw;
++ con = context_new(*sc);
++ if (!con) {
++ goto out;
++ }
++ context_range_set(con, lvl);
++ if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) {
++ context_free(con);
++ goto out;
++ }
++ if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) {
++ freecon(obtained_raw);
++ context_free(con);
++ goto out;
++ }
++
++ debug("get_user_context: obtained context '%s' requested context '%s'",
++ obtained_raw, requested_raw);
++ if (strcmp(obtained_raw, requested_raw)) {
++ /* set the context to the real requested one but fail */
++ freecon(requested_raw);
++ freecon(obtained_raw);
++ freecon(*sc);
++ *sc = strdup(context_str(con));
++ context_free(con);
++ return -1;
++ }
++ freecon(requested_raw);
++ freecon(obtained_raw);
++ context_free(con);
++ }
++#endif
++ return 0;
++ out:
++ freecon(*sc);
++ *sc = NULL;
++ return -1;
++}
++
+ static void
+ ssh_selinux_get_role_level(char **role, const char **level)
+ {
+@@ -65,14 +216,16 @@ ssh_selinux_get_role_level(char **role,
+ }
+
+ /* Return the default security context for the given username */
+-static security_context_t
+-ssh_selinux_getctxbyname(char *pwname)
++static int
++ssh_selinux_getctxbyname(char *pwname,
++ security_context_t *default_sc, security_context_t *user_sc)
+ {
+ security_context_t sc = NULL;
+ char *sename, *lvl;
+ char *role;
+ const char *reqlvl;
+ int r = 0;
++ context_t con;
+
+ ssh_selinux_get_role_level(&role, &reqlvl);
+ #ifdef HAVE_GETSEUSERBYNAME
+@@ -82,38 +235,63 @@ ssh_selinux_getctxbyname(char *pwname)
+ }
+ #else
+ sename = pwname;
+- lvl = NULL;
++ lvl = "";
+ #endif
+
+ if (r == 0) {
+ #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+- if (role != NULL && role[0])
+- r = get_default_context_with_rolelevel(sename, role, lvl, NULL, &sc);
+- else
+- r = get_default_context_with_level(sename, lvl, NULL, &sc);
++ r = get_default_context_with_level(sename, lvl, NULL, default_sc);
+ #else
+- if (role != NULL && role[0])
+- r = get_default_context_with_role(sename, role, NULL, &sc);
+- else
+- r = get_default_context(sename, NULL, &sc);
++ r = get_default_context(sename, NULL, default_sc);
+ #endif
+ }
+
+- if (r != 0) {
+- switch (security_getenforce()) {
+- case -1:
+- fatal("%s: ssh_selinux_getctxbyname: "
+- "security_getenforce() failed", __func__);
+- case 0:
+- error("%s: Failed to get default SELinux security "
+- "context for %s", __func__, pwname);
+- break;
+- default:
+- fatal("%s: Failed to get default SELinux security "
+- "context for %s (in enforcing mode)",
+- __func__, pwname);
++ if (r == 0) {
++ /* If launched from xinetd, we must use current level */
++ if (inetd_flag && !rexeced_flag) {
++ security_context_t sshdsc=NULL;
++
++ if (getcon_raw(&sshdsc) < 0)
++ fatal("failed to allocate security context");
++
++ if ((con=context_new(sshdsc)) == NULL)
++ fatal("failed to allocate selinux context");
++ reqlvl = context_range_get(con);
++ freecon(sshdsc);
++ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0)
++ /* we actually don't change level */
++ reqlvl = "";
++
++ debug("%s: current connection level '%s'", __func__, reqlvl);
++ }
++
++ if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) {
++ r = get_user_context(sename, role, reqlvl, user_sc);
++
++ if (r == 0 && reqlvl != NULL && reqlvl[0]) {
++ security_context_t default_level_sc = *default_sc;
++ if (role != NULL && role[0]) {
++ if (get_user_context(sename, role, lvl, &default_level_sc) < 0)
++ default_level_sc = *default_sc;
++ }
++ /* verify that the requested range is contained in the user range */
++ if (mls_range_allowed(default_level_sc, *user_sc)) {
++ logit("permit MLS level %s (user range %s)", reqlvl, lvl);
++ } else {
++ r = -1;
++ error("deny MLS level %s (user range %s)", reqlvl, lvl);
++ }
++ if (default_level_sc != *default_sc)
++ freecon(default_level_sc);
++ }
++ } else {
++ *user_sc = *default_sc;
+ }
+ }
++ if (r != 0) {
++ error("%s: Failed to get default SELinux security "
++ "context for %s", __func__, pwname);
++ }
+
+ #ifdef HAVE_GETSEUSERBYNAME
+ if (sename != NULL)
+@@ -121,8 +299,12 @@ ssh_selinux_getctxbyname(char *pwname)
+ if (lvl != NULL)
+ xfree(lvl);
+ #endif
+-
+- return (sc);
++ if (role != NULL)
++ xfree(role);
++ if (con)
++ context_free(con);
++
++ return (r);
+ }
+
+ /* Setup environment variables for pam_selinux */
+@@ -160,6 +342,8 @@ void
+ ssh_selinux_setup_exec_context(char *pwname)
+ {
+ security_context_t user_ctx = NULL;
++ int r = 0;
++ security_context_t default_ctx = NULL;
+
+ if (!ssh_selinux_enabled())
+ return;
+@@ -184,22 +368,45 @@ ssh_selinux_setup_exec_context(char *pwn
+
+ debug3("%s: setting execution context", __func__);
+
+- user_ctx = ssh_selinux_getctxbyname(pwname);
+- if (setexeccon(user_ctx) != 0) {
++ r = ssh_selinux_getctxbyname(pwname, &default_ctx, &user_ctx);
++ if (r >= 0) {
++ r = setexeccon(user_ctx);
++ if (r < 0) {
++ error("%s: Failed to set SELinux execution context %s for %s",
++ __func__, user_ctx, pwname);
++ }
++#ifdef HAVE_SETKEYCREATECON
++ else if (setkeycreatecon(user_ctx) < 0) {
++ error("%s: Failed to set SELinux keyring creation context %s for %s",
++ __func__, user_ctx, pwname);
++ }
++#endif
++ }
++ if (user_ctx == NULL) {
++ user_ctx = default_ctx;
++ }
++ if (r < 0 || user_ctx != default_ctx) {
++ /* audit just the case when user changed a role or there was
++ a failure */
++ send_audit_message(r >= 0, default_ctx, user_ctx);
++ }
++ if (r < 0) {
+ switch (security_getenforce()) {
+ case -1:
+ fatal("%s: security_getenforce() failed", __func__);
+ case 0:
+- error("%s: Failed to set SELinux execution "
+- "context for %s", __func__, pwname);
++ error("%s: SELinux failure. Continuing in permissive mode.",
++ __func__);
+ break;
+ default:
+- fatal("%s: Failed to set SELinux execution context "
+- "for %s (in enforcing mode)", __func__, pwname);
++ fatal("%s: SELinux failure. Aborting connection.",
++ __func__);
+ }
+ }
+- if (user_ctx != NULL)
++ if (user_ctx != NULL && user_ctx != default_ctx)
+ freecon(user_ctx);
++ if (default_ctx != NULL)
++ freecon(default_ctx);
+
+ debug3("%s: done", __func__);
+ }
+@@ -217,7 +424,10 @@ ssh_selinux_setup_pty(char *pwname, cons
+
+ debug3("%s: setting TTY context on %s", __func__, tty);
+
+- user_ctx = ssh_selinux_getctxbyname(pwname);
++ if (getexeccon(&user_ctx) < 0) {
++ error("%s: getexeccon: %s", __func__, strerror(errno));
++ goto out;
++ }
+
+ /* XXX: should these calls fatal() upon failure in enforcing mode? */
+
+diff -up openssh-5.8p1/sshd.c.mls openssh-5.8p1/sshd.c
+--- openssh-5.8p1/sshd.c.mls 2011-02-12 15:05:05.000000000 +0100
++++ openssh-5.8p1/sshd.c 2011-02-12 15:05:06.000000000 +0100
+@@ -2011,6 +2011,9 @@ main(int ac, char **av)
+ restore_uid();
+ }
+ #endif
++#ifdef WITH_SELINUX
++ ssh_selinux_setup_exec_context(authctxt->pw->pw_name);
++#endif
+ #ifdef USE_PAM
+ if (options.use_pam) {
+ do_pam_setcred(1);
--- /dev/null
+diff -up openssh-5.8p1/entropy.c.randclean openssh-5.8p1/entropy.c
+--- openssh-5.8p1/entropy.c.randclean 2011-01-13 11:05:29.000000000 +0100
++++ openssh-5.8p1/entropy.c 2011-02-14 00:26:31.000000000 +0100
+@@ -159,6 +159,9 @@ init_rng(void)
+ fatal("OpenSSL version mismatch. Built against %lx, you "
+ "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
+
++ /* clean the PRNG status when exiting the program */
++ atexit(RAND_cleanup);
++
+ #ifndef OPENSSL_PRNG_ONLY
+ original_uid = getuid();
+ original_euid = geteuid();
--- /dev/null
+diff -up openssh-5.8p1/auth1.c.role openssh-5.8p1/auth1.c
+--- openssh-5.8p1/auth1.c.role 2010-08-31 14:36:39.000000000 +0200
++++ openssh-5.8p1/auth1.c 2011-02-12 14:34:11.000000000 +0100
+@@ -384,6 +384,9 @@ do_authentication(Authctxt *authctxt)
+ {
+ u_int ulen;
+ char *user, *style = NULL;
++#ifdef WITH_SELINUX
++ char *role=NULL;
++#endif
+
+ /* Get the name of the user that we wish to log in as. */
+ packet_read_expect(SSH_CMSG_USER);
+@@ -392,11 +395,24 @@ do_authentication(Authctxt *authctxt)
+ user = packet_get_cstring(&ulen);
+ packet_check_eom();
+
++#ifdef WITH_SELINUX
++ if ((role = strchr(user, '/')) != NULL)
++ *role++ = '\0';
++#endif
++
+ if ((style = strchr(user, ':')) != NULL)
+ *style++ = '\0';
++#ifdef WITH_SELINUX
++ else
++ if (role && (style = strchr(role, ':')) != NULL)
++ *style++ = '\0';
++#endif
+
+ authctxt->user = user;
+ authctxt->style = style;
++#ifdef WITH_SELINUX
++ authctxt->role = role;
++#endif
+
+ /* Verify that the user is a valid user. */
+ if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
+diff -up openssh-5.8p1/auth2.c.role openssh-5.8p1/auth2.c
+--- openssh-5.8p1/auth2.c.role 2010-08-31 14:36:39.000000000 +0200
++++ openssh-5.8p1/auth2.c 2011-02-12 14:34:11.000000000 +0100
+@@ -216,6 +216,9 @@ input_userauth_request(int type, u_int32
+ Authctxt *authctxt = ctxt;
+ Authmethod *m = NULL;
+ char *user, *service, *method, *style = NULL;
++#ifdef WITH_SELINUX
++ char *role = NULL;
++#endif
+ int authenticated = 0;
+
+ if (authctxt == NULL)
+@@ -227,6 +230,11 @@ input_userauth_request(int type, u_int32
+ debug("userauth-request for user %s service %s method %s", user, service, method);
+ debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+
++#ifdef WITH_SELINUX
++ if ((role = strchr(user, '/')) != NULL)
++ *role++ = 0;
++#endif
++
+ if ((style = strchr(user, ':')) != NULL)
+ *style++ = 0;
+
+@@ -252,8 +260,15 @@ input_userauth_request(int type, u_int32
+ use_privsep ? " [net]" : "");
+ authctxt->service = xstrdup(service);
+ authctxt->style = style ? xstrdup(style) : NULL;
+- if (use_privsep)
++#ifdef WITH_SELINUX
++ authctxt->role = role ? xstrdup(role) : NULL;
++#endif
++ if (use_privsep) {
+ mm_inform_authserv(service, style);
++#ifdef WITH_SELINUX
++ mm_inform_authrole(role);
++#endif
++ }
+ userauth_banner();
+ } else if (strcmp(user, authctxt->user) != 0 ||
+ strcmp(service, authctxt->service) != 0) {
+diff -up openssh-5.8p1/auth2-gss.c.role openssh-5.8p1/auth2-gss.c
+--- openssh-5.8p1/auth2-gss.c.role 2007-12-02 12:59:45.000000000 +0100
++++ openssh-5.8p1/auth2-gss.c 2011-02-12 14:34:11.000000000 +0100
+@@ -258,6 +258,7 @@ input_gssapi_mic(int type, u_int32_t ple
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ int authenticated = 0;
++ char *micuser;
+ Buffer b;
+ gss_buffer_desc mic, gssbuf;
+ u_int len;
+@@ -270,7 +271,13 @@ input_gssapi_mic(int type, u_int32_t ple
+ mic.value = packet_get_string(&len);
+ mic.length = len;
+
+- ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
++#ifdef WITH_SELINUX
++ if (authctxt->role && (strlen(authctxt->role) > 0))
++ xasprintf(&micuser, "%s/%s", authctxt->user, authctxt->role);
++ else
++#endif
++ micuser = authctxt->user;
++ ssh_gssapi_buildmic(&b, micuser, authctxt->service,
+ "gssapi-with-mic");
+
+ gssbuf.value = buffer_ptr(&b);
+@@ -282,6 +289,8 @@ input_gssapi_mic(int type, u_int32_t ple
+ logit("GSSAPI MIC check failed");
+
+ buffer_free(&b);
++ if (micuser != authctxt->user)
++ xfree(micuser);
+ xfree(mic.value);
+
+ authctxt->postponed = 0;
+diff -up openssh-5.8p1/auth2-hostbased.c.role openssh-5.8p1/auth2-hostbased.c
+--- openssh-5.8p1/auth2-hostbased.c.role 2011-02-12 14:34:10.000000000 +0100
++++ openssh-5.8p1/auth2-hostbased.c 2011-02-12 14:34:11.000000000 +0100
+@@ -106,7 +106,15 @@ userauth_hostbased(Authctxt *authctxt)
+ buffer_put_string(&b, session_id2, session_id2_len);
+ /* reconstruct packet */
+ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+- buffer_put_cstring(&b, authctxt->user);
++#ifdef WITH_SELINUX
++ if (authctxt->role) {
++ buffer_put_int(&b, strlen(authctxt->user)+strlen(authctxt->role)+1);
++ buffer_append(&b, authctxt->user, strlen(authctxt->user));
++ buffer_put_char(&b, '/');
++ buffer_append(&b, authctxt->role, strlen(authctxt->role));
++ } else
++#endif
++ buffer_put_cstring(&b, authctxt->user);
+ buffer_put_cstring(&b, service);
+ buffer_put_cstring(&b, "hostbased");
+ buffer_put_string(&b, pkalg, alen);
+diff -up openssh-5.8p1/auth2-pubkey.c.role openssh-5.8p1/auth2-pubkey.c
+--- openssh-5.8p1/auth2-pubkey.c.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/auth2-pubkey.c 2011-02-12 14:34:11.000000000 +0100
+@@ -122,7 +122,15 @@ userauth_pubkey(Authctxt *authctxt)
+ }
+ /* reconstruct packet */
+ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+- buffer_put_cstring(&b, authctxt->user);
++#ifdef WITH_SELINUX
++ if (authctxt->role) {
++ buffer_put_int(&b, strlen(authctxt->user)+strlen(authctxt->role)+1);
++ buffer_append(&b, authctxt->user, strlen(authctxt->user));
++ buffer_put_char(&b, '/');
++ buffer_append(&b, authctxt->role, strlen(authctxt->role));
++ } else
++#endif
++ buffer_put_cstring(&b, authctxt->user);
+ buffer_put_cstring(&b,
+ datafellows & SSH_BUG_PKSERVICE ?
+ "ssh-userauth" :
+diff -up openssh-5.8p1/auth.h.role openssh-5.8p1/auth.h
+--- openssh-5.8p1/auth.h.role 2011-02-12 14:34:10.000000000 +0100
++++ openssh-5.8p1/auth.h 2011-02-12 14:34:11.000000000 +0100
+@@ -58,6 +58,9 @@ struct Authctxt {
+ char *service;
+ struct passwd *pw; /* set if 'valid' */
+ char *style;
++#ifdef WITH_SELINUX
++ char *role;
++#endif
+ void *kbdintctxt;
+ void *jpake_ctx;
+ #ifdef BSD_AUTH
+diff -up openssh-5.8p1/auth-pam.c.role openssh-5.8p1/auth-pam.c
+--- openssh-5.8p1/auth-pam.c.role 2009-07-12 14:07:21.000000000 +0200
++++ openssh-5.8p1/auth-pam.c 2011-02-12 14:34:11.000000000 +0100
+@@ -1069,7 +1069,7 @@ is_pam_session_open(void)
+ * during the ssh authentication process.
+ */
+ int
+-do_pam_putenv(char *name, char *value)
++do_pam_putenv(char *name, const char *value)
+ {
+ int ret = 1;
+ #ifdef HAVE_PAM_PUTENV
+diff -up openssh-5.8p1/auth-pam.h.role openssh-5.8p1/auth-pam.h
+--- openssh-5.8p1/auth-pam.h.role 2004-09-11 14:17:26.000000000 +0200
++++ openssh-5.8p1/auth-pam.h 2011-02-12 14:34:11.000000000 +0100
+@@ -38,7 +38,7 @@ void do_pam_session(void);
+ void do_pam_set_tty(const char *);
+ void do_pam_setcred(int );
+ void do_pam_chauthtok(void);
+-int do_pam_putenv(char *, char *);
++int do_pam_putenv(char *, const char *);
+ char ** fetch_pam_environment(void);
+ char ** fetch_pam_child_environment(void);
+ void free_pam_environment(char **);
+diff -up openssh-5.8p1/monitor.c.role openssh-5.8p1/monitor.c
+--- openssh-5.8p1/monitor.c.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/monitor.c 2011-02-12 14:34:11.000000000 +0100
+@@ -138,6 +138,9 @@ int mm_answer_sign(int, Buffer *);
+ int mm_answer_pwnamallow(int, Buffer *);
+ int mm_answer_auth2_read_banner(int, Buffer *);
+ int mm_answer_authserv(int, Buffer *);
++#ifdef WITH_SELINUX
++int mm_answer_authrole(int, Buffer *);
++#endif
+ int mm_answer_authpassword(int, Buffer *);
+ int mm_answer_bsdauthquery(int, Buffer *);
+ int mm_answer_bsdauthrespond(int, Buffer *);
+@@ -218,6 +221,9 @@ struct mon_table mon_dispatch_proto20[]
+ {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
+ {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+ {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
++#ifdef WITH_SELINUX
++ {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
++#endif
+ {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
+ {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+ #ifdef USE_PAM
+@@ -703,6 +709,9 @@ mm_answer_pwnamallow(int sock, Buffer *m
+ else {
+ /* Allow service/style information on the auth context */
+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
++#ifdef WITH_SELINUX
++ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1);
++#endif
+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
+ }
+
+@@ -747,6 +756,25 @@ mm_answer_authserv(int sock, Buffer *m)
+ return (0);
+ }
+
++#ifdef WITH_SELINUX
++int
++mm_answer_authrole(int sock, Buffer *m)
++{
++ monitor_permit_authentications(1);
++
++ authctxt->role = buffer_get_string(m, NULL);
++ debug3("%s: role=%s",
++ __func__, authctxt->role);
++
++ if (strlen(authctxt->role) == 0) {
++ xfree(authctxt->role);
++ authctxt->role = NULL;
++ }
++
++ return (0);
++}
++#endif
++
+ int
+ mm_answer_authpassword(int sock, Buffer *m)
+ {
+@@ -1112,7 +1140,7 @@ static int
+ monitor_valid_userblob(u_char *data, u_int datalen)
+ {
+ Buffer b;
+- char *p;
++ char *p, *r;
+ u_int len;
+ int fail = 0;
+
+@@ -1138,6 +1166,8 @@ monitor_valid_userblob(u_char *data, u_i
+ if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+ fail++;
+ p = buffer_get_string(&b, NULL);
++ if ((r = strchr(p, '/')) != NULL)
++ *r = '\0';
+ if (strcmp(authctxt->user, p) != 0) {
+ logit("wrong user name passed to monitor: expected %s != %.100s",
+ authctxt->user, p);
+@@ -1169,7 +1199,7 @@ monitor_valid_hostbasedblob(u_char *data
+ char *chost)
+ {
+ Buffer b;
+- char *p;
++ char *p, *r;
+ u_int len;
+ int fail = 0;
+
+@@ -1186,6 +1216,8 @@ monitor_valid_hostbasedblob(u_char *data
+ if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+ fail++;
+ p = buffer_get_string(&b, NULL);
++ if ((r = strchr(p, '/')) != NULL)
++ *r = '\0';
+ if (strcmp(authctxt->user, p) != 0) {
+ logit("wrong user name passed to monitor: expected %s != %.100s",
+ authctxt->user, p);
+diff -up openssh-5.8p1/monitor.h.role openssh-5.8p1/monitor.h
+--- openssh-5.8p1/monitor.h.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/monitor.h 2011-02-12 14:34:11.000000000 +0100
+@@ -31,6 +31,9 @@
+ enum monitor_reqtype {
+ MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
+ MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
++#ifdef WITH_SELINUX
++ MONITOR_REQ_AUTHROLE,
++#endif
+ MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
+ MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
+ MONITOR_REQ_AUTH2_READ_BANNER, MONITOR_ANS_AUTH2_READ_BANNER,
+diff -up openssh-5.8p1/monitor_wrap.c.role openssh-5.8p1/monitor_wrap.c
+--- openssh-5.8p1/monitor_wrap.c.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/monitor_wrap.c 2011-02-12 14:34:11.000000000 +0100
+@@ -298,6 +298,25 @@ mm_inform_authserv(char *service, char *
+ buffer_free(&m);
+ }
+
++/* Inform the privileged process about role */
++
++#ifdef WITH_SELINUX
++void
++mm_inform_authrole(char *role)
++{
++ Buffer m;
++
++ debug3("%s entering", __func__);
++
++ buffer_init(&m);
++ buffer_put_cstring(&m, role ? role : "");
++
++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, &m);
++
++ buffer_free(&m);
++}
++#endif
++
+ /* Do the password authentication */
+ int
+ mm_auth_password(Authctxt *authctxt, char *password)
+diff -up openssh-5.8p1/monitor_wrap.h.role openssh-5.8p1/monitor_wrap.h
+--- openssh-5.8p1/monitor_wrap.h.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/monitor_wrap.h 2011-02-12 14:34:11.000000000 +0100
+@@ -41,6 +41,9 @@ int mm_is_monitor(void);
+ DH *mm_choose_dh(int, int, int);
+ int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
+ void mm_inform_authserv(char *, char *);
++#ifdef WITH_SELINUX
++void mm_inform_authrole(char *);
++#endif
+ struct passwd *mm_getpwnamallow(const char *);
+ char *mm_auth2_read_banner(void);
+ int mm_auth_password(struct Authctxt *, char *);
+diff -up openssh-5.8p1/openbsd-compat/Makefile.in.role openssh-5.8p1/openbsd-compat/Makefile.in
+--- openssh-5.8p1/openbsd-compat/Makefile.in.role 2010-10-07 13:19:24.000000000 +0200
++++ openssh-5.8p1/openbsd-compat/Makefile.in 2011-02-12 14:34:11.000000000 +0100
+@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bindresvport
+
+ COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+
+-PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
++PORTS=port-aix.o port-irix.o port-linux.o port-linux_part_2.o port-solaris.o port-tun.o port-uw.o
+
+ .c.o:
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+diff -up openssh-5.8p1/openbsd-compat/port-linux.c.role openssh-5.8p1/openbsd-compat/port-linux.c
+--- openssh-5.8p1/openbsd-compat/port-linux.c.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/openbsd-compat/port-linux.c 2011-02-12 14:37:31.000000000 +0100
+@@ -31,48 +31,73 @@
+
+ #include "log.h"
+ #include "xmalloc.h"
++#include "servconf.h"
+ #include "port-linux.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
+
+ #ifdef WITH_SELINUX
+ #include <selinux/selinux.h>
+ #include <selinux/flask.h>
+ #include <selinux/get_context_list.h>
+
+-/* Wrapper around is_selinux_enabled() to log its return value once only */
+-int
+-ssh_selinux_enabled(void)
+-{
+- static int enabled = -1;
++extern ServerOptions options;
++extern Authctxt *the_authctxt;
++extern int inetd_flag;
++extern int rexeced_flag;
+
+- if (enabled == -1) {
+- enabled = (is_selinux_enabled() == 1);
+- debug("SELinux support %s", enabled ? "enabled" : "disabled");
++static void
++ssh_selinux_get_role_level(char **role, const char **level)
++{
++ *role = NULL;
++ *level = NULL;
++ if (the_authctxt) {
++ if (the_authctxt->role != NULL) {
++ char *slash;
++ *role = xstrdup(the_authctxt->role);
++ if ((slash = strchr(*role, '/')) != NULL) {
++ *slash = '\0';
++ *level = slash + 1;
++ }
++ }
+ }
+-
+- return (enabled);
+ }
+
+ /* Return the default security context for the given username */
+ static security_context_t
+ ssh_selinux_getctxbyname(char *pwname)
+ {
+- security_context_t sc;
+- char *sename = NULL, *lvl = NULL;
+- int r;
++ security_context_t sc = NULL;
++ char *sename, *lvl;
++ char *role;
++ const char *reqlvl;
++ int r = 0;
+
++ ssh_selinux_get_role_level(&role, &reqlvl);
+ #ifdef HAVE_GETSEUSERBYNAME
+- if (getseuserbyname(pwname, &sename, &lvl) != 0)
+- return NULL;
++ if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) {
++ sename = NULL;
++ lvl = NULL;
++ }
+ #else
+ sename = pwname;
+ lvl = NULL;
+ #endif
+
++ if (r == 0) {
+ #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+- r = get_default_context_with_level(sename, lvl, NULL, &sc);
++ if (role != NULL && role[0])
++ r = get_default_context_with_rolelevel(sename, role, lvl, NULL, &sc);
++ else
++ r = get_default_context_with_level(sename, lvl, NULL, &sc);
+ #else
+- r = get_default_context(sename, NULL, &sc);
++ if (role != NULL && role[0])
++ r = get_default_context_with_role(sename, role, NULL, &sc);
++ else
++ r = get_default_context(sename, NULL, &sc);
+ #endif
++ }
+
+ if (r != 0) {
+ switch (security_getenforce()) {
+@@ -100,6 +125,36 @@ ssh_selinux_getctxbyname(char *pwname)
+ return (sc);
+ }
+
++/* Setup environment variables for pam_selinux */
++static int
++ssh_selinux_setup_pam_variables(void)
++{
++ const char *reqlvl;
++ char *role;
++ char *use_current;
++ int rv;
++
++ debug3("%s: setting execution context", __func__);
++
++ ssh_selinux_get_role_level(&role, &reqlvl);
++
++ rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : "");
++
++ if (inetd_flag && !rexeced_flag) {
++ use_current = "1";
++ } else {
++ use_current = "";
++ rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: "");
++ }
++
++ rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current);
++
++ if (role != NULL)
++ xfree(role);
++
++ return rv;
++}
++
+ /* Set the execution context to the default for the specified user */
+ void
+ ssh_selinux_setup_exec_context(char *pwname)
+@@ -109,6 +164,24 @@ ssh_selinux_setup_exec_context(char *pwn
+ if (!ssh_selinux_enabled())
+ return;
+
++ if (options.use_pam) {
++ /* do not compute context, just setup environment for pam_selinux */
++ if (ssh_selinux_setup_pam_variables()) {
++ switch (security_getenforce()) {
++ case -1:
++ fatal("%s: security_getenforce() failed", __func__);
++ case 0:
++ error("%s: SELinux PAM variable setup failure. Continuing in permissive mode.",
++ __func__);
++ break;
++ default:
++ fatal("%s: SELinux PAM variable setup failure. Aborting connection.",
++ __func__);
++ }
++ }
++ return;
++ }
++
+ debug3("%s: setting execution context", __func__);
+
+ user_ctx = ssh_selinux_getctxbyname(pwname);
+@@ -206,21 +279,6 @@ ssh_selinux_change_context(const char *n
+ xfree(newctx);
+ }
+
+-void
+-ssh_selinux_setfscreatecon(const char *path)
+-{
+- security_context_t context;
+-
+- if (!ssh_selinux_enabled())
+- return;
+- if (path == NULL) {
+- setfscreatecon(NULL);
+- return;
+- }
+- if (matchpathcon(path, 0700, &context) == 0)
+- setfscreatecon(context);
+-}
+-
+ #endif /* WITH_SELINUX */
+
+ #ifdef LINUX_OOM_ADJUST
+diff -up openssh-5.8p1/openbsd-compat/port-linux_part_2.c.role openssh-5.8p1/openbsd-compat/port-linux_part_2.c
+--- openssh-5.8p1/openbsd-compat/port-linux_part_2.c.role 2011-02-12 14:34:11.000000000 +0100
++++ openssh-5.8p1/openbsd-compat/port-linux_part_2.c 2011-02-12 14:34:11.000000000 +0100
+@@ -0,0 +1,75 @@
++/* $Id: port-linux.c,v 1.11.4.2 2011/02/04 00:43:08 djm Exp $ */
++
++/*
++ * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com>
++ * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Linux-specific portability code - just SELinux support at present
++ */
++
++#include "includes.h"
++
++#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST)
++#include <errno.h>
++#include <stdarg.h>
++#include <string.h>
++#include <stdio.h>
++
++#include "log.h"
++#include "xmalloc.h"
++#include "port-linux.h"
++#include "key.h"
++#include "hostfile.h"
++#include "auth.h"
++
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#include <selinux/flask.h>
++#include <selinux/get_context_list.h>
++
++/* Wrapper around is_selinux_enabled() to log its return value once only */
++int
++ssh_selinux_enabled(void)
++{
++ static int enabled = -1;
++
++ if (enabled == -1) {
++ enabled = (is_selinux_enabled() == 1);
++ debug("SELinux support %s", enabled ? "enabled" : "disabled");
++ }
++
++ return (enabled);
++}
++
++void
++ssh_selinux_setfscreatecon(const char *path)
++{
++ security_context_t context;
++
++ if (!ssh_selinux_enabled())
++ return;
++ if (path == NULL) {
++ setfscreatecon(NULL);
++ return;
++ }
++ if (matchpathcon(path, 0700, &context) == 0)
++ setfscreatecon(context);
++}
++
++#endif /* WITH_SELINUX */
++
++#endif /* WITH_SELINUX || LINUX_OOM_ADJUST */
--- /dev/null
+diff -up openssh-5.8p1/openbsd-compat/port-linux.c.selinux openssh-5.8p1/openbsd-compat/port-linux.c
+--- openssh-5.8p1/openbsd-compat/port-linux.c.selinux 2011-02-12 09:38:45.000000000 +0100
++++ openssh-5.8p1/openbsd-compat/port-linux.c 2011-02-12 09:39:10.000000000 +0100
+@@ -213,7 +213,7 @@ ssh_selinux_setfscreatecon(const char *p
+
+ if (!ssh_selinux_enabled())
+ return;
+- if (path == NULL)
++ if (path == NULL) {
+ setfscreatecon(NULL);
+ return;
+ }