import openssh-9.9p1-2.el10

i10cs changed/i10cs/openssh-9.9p1-2.el10
MSVSphere Packaging Team 3 weeks ago
commit 5c7fe459e0
Signed by: sys_gitsync
GPG Key ID: B2B0B9F29E528FE8

2
.gitignore vendored

@ -0,0 +1,2 @@
SOURCES/gpgkey-736060BA.gpg
SOURCES/openssh-9.9p1.tar.gz

@ -0,0 +1,2 @@
dbb35b4e9ae3f72b930a82c6fd5e83e9dcd7b193 SOURCES/gpgkey-736060BA.gpg
5ded7eb0add0b02b5d1a1c4bf5cb2c89d2117b53 SOURCES/openssh-9.9p1.tar.gz

@ -0,0 +1,18 @@
diff -up openssh-8.6p1/contrib/gnome-ssh-askpass2.c.grab-info openssh-8.6p1/contrib/gnome-ssh-askpass2.c
--- openssh-8.6p1/contrib/gnome-ssh-askpass2.c.grab-info 2021-04-19 13:57:11.720113536 +0200
+++ openssh-8.6p1/contrib/gnome-ssh-askpass2.c 2021-04-19 13:59:29.842163204 +0200
@@ -70,8 +70,12 @@ report_failed_grab (GtkWidget *parent_wi
err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 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_dialog_run(GTK_DIALOG(err));

@ -0,0 +1,83 @@
diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contrib/gnome-ssh-askpass2.c
--- openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress 2016-12-19 05:59:41.000000000 +0100
+++ openssh-7.4p1/contrib/gnome-ssh-askpass2.c 2016-12-23 13:31:16.545211926 +0100
@@ -53,6 +53,7 @@
#include <unistd.h>
#include <X11/Xlib.h>
+#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
@@ -81,14 +82,25 @@ ok_dialog(GtkWidget *entry, gpointer dia
return 1;
}
+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, int prompt_type)
{
const char *failed;
char *passphrase, *local;
int result, grab_tries, grab_server, grab_pointer;
int buttons, default_response;
- GtkWidget *parent_window, *dialog, *entry;
+ GtkWidget *parent_window, *dialog, *entry, *progress, *hbox;
GdkGrabStatus status;
GdkColor fg, bg;
int fg_set = 0, bg_set = 0;
@@ -104,14 +116,19 @@ passphrase_dialog(char *message)
gtk_widget_modify_bg(dialog, GTK_STATE_NORMAL, &bg);
if (prompt_type == PROMPT_ENTRY || prompt_type == PROMPT_NONE) {
+ 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();
if (fg_set)
gtk_widget_modify_fg(entry, GTK_STATE_NORMAL, &fg);
if (bg_set)
gtk_widget_modify_bg(entry, GTK_STATE_NORMAL, &bg);
gtk_box_pack_start(
- GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
- entry, FALSE, FALSE, 0);
+ 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);
if (prompt_type == PROMPT_ENTRY) {
@@ -130,6 +145,22 @@ passphrase_dialog(char *message)
g_signal_connect(G_OBJECT(entry), "key_press_event",
G_CALLBACK(check_none), dialog);
}
+
+ 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);
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK(move_progress), progress);
+
}
/* Grab focus */

@ -0,0 +1,14 @@
diff -up openssh-5.8p2/ssh-keyscan.c.sigpipe openssh-5.8p2/ssh-keyscan.c
--- openssh-5.8p2/ssh-keyscan.c.sigpipe 2011-08-23 18:30:33.873025916 +0200
+++ openssh-5.8p2/ssh-keyscan.c 2011-08-23 18:32:24.574025362 +0200
@@ -715,6 +715,9 @@ main(int argc, char **argv)
if (maxfd > fdlim_get(0))
fdlim_set(maxfd);
fdcon = xcalloc(maxfd, sizeof(con));
+
+ signal(SIGPIPE, SIG_IGN);
+
read_wait = xcalloc(maxfd, sizeof(struct pollfd));
for (j = 0; j < maxfd; j++)
read_wait[j].fd = -1;

@ -0,0 +1,24 @@
diff -up openssh-5.9p0/ssh.1.ipv6man openssh-5.9p0/ssh.1
--- openssh-5.9p0/ssh.1.ipv6man 2011-08-05 22:17:32.000000000 +0200
+++ openssh-5.9p0/ssh.1 2011-08-31 13:08:34.880024485 +0200
@@ -1400,6 +1400,8 @@ manual page for more information.
.Nm
exits with the exit status of the remote command or with 255
if an error occurred.
+.Sh IPV6
+IPv6 address can be used everywhere where IPv4 address. In all entries must be the IPv6 address enclosed in square brackets. Note: The square brackets are metacharacters for the shell and must be escaped in shell.
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,
diff -up openssh-5.9p0/sshd.8.ipv6man openssh-5.9p0/sshd.8
--- openssh-5.9p0/sshd.8.ipv6man 2011-08-05 22:17:32.000000000 +0200
+++ openssh-5.9p0/sshd.8 2011-08-31 13:10:34.129039094 +0200
@@ -940,6 +940,8 @@ concurrently for different ports, this c
started last).
The content of this file is not sensitive; it can be world-readable.
.El
+.Sh IPV6
+IPv6 address can be used everywhere where IPv4 address. In all entries must be the IPv6 address enclosed in square brackets. Note: The square brackets are metacharacters for the shell and must be escaped in shell.
.Sh SEE ALSO
.Xr scp 1 ,
.Xr sftp 1 ,

@ -0,0 +1,16 @@
diff --git a/scp.c b/scp.c
index d98fa67..25d347b 100644
--- a/scp.c
+++ b/scp.c
@@ -638,7 +638,10 @@ toremote(char *targ, int argc, char **argv)
addargs(&alist, "%s", ssh_program);
addargs(&alist, "-x");
addargs(&alist, "-oClearAllForwardings=yes");
- addargs(&alist, "-n");
+ if (isatty(fileno(stdin)))
+ addargs(&alist, "-t");
+ else
+ addargs(&alist, "-n");
for (j = 0; j < remote_remote_args.num; j++) {
addargs(&alist, "%s",
remote_remote_args.list[j]);

@ -0,0 +1,263 @@
diff -up openssh-8.6p1/log.c.log-in-chroot openssh-8.6p1/log.c
--- openssh-8.6p1/log.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/log.c 2021-04-19 14:43:08.544843434 +0200
@@ -194,6 +194,11 @@ void
log_init(const char *av0, LogLevel level, SyslogFacility facility,
int on_stderr)
{
+ log_init_handler(av0, level, facility, on_stderr, 1);
+}
+
+void
+log_init_handler(const char *av0, LogLevel level, SyslogFacility facility, int on_stderr, int reset_handler) {
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
@@ -206,8 +211,10 @@ log_init(const char *av0, LogLevel level
exit(1);
}
- log_handler = NULL;
- log_handler_ctx = NULL;
+ if (reset_handler) {
+ log_handler = NULL;
+ log_handler_ctx = NULL;
+ }
log_on_stderr = on_stderr;
if (on_stderr)
diff -up openssh-8.6p1/log.h.log-in-chroot openssh-8.6p1/log.h
--- openssh-8.6p1/log.h.log-in-chroot 2021-04-19 14:43:08.544843434 +0200
+++ openssh-8.6p1/log.h 2021-04-19 14:56:46.931042176 +0200
@@ -52,6 +52,7 @@ typedef enum {
typedef void (log_handler_fn)(LogLevel, int, const char *, void *);
void log_init(const char *, LogLevel, SyslogFacility, int);
+void log_init_handler(const char *, LogLevel, SyslogFacility, int, int);
LogLevel log_level_get(void);
int log_change_level(LogLevel);
int log_is_on_stderr(void);
diff -up openssh-8.6p1/monitor.c.log-in-chroot openssh-8.6p1/monitor.c
--- openssh-8.6p1/monitor.c.log-in-chroot 2021-04-19 14:43:08.526843298 +0200
+++ openssh-8.6p1/monitor.c 2021-04-19 14:55:25.286424043 +0200
@@ -297,6 +297,8 @@ monitor_child_preauth(struct ssh *ssh, s
close(pmonitor->m_log_sendfd);
pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1;
+ pmonitor->m_state = "preauth";
+
authctxt = (Authctxt *)ssh->authctxt;
memset(authctxt, 0, sizeof(*authctxt));
ssh->authctxt = authctxt;
@@ -408,6 +410,8 @@ monitor_child_postauth(struct ssh *ssh,
close(pmonitor->m_recvfd);
pmonitor->m_recvfd = -1;
+ pmonitor->m_state = "postauth";
+
monitor_set_child_handler(pmonitor->m_pid);
ssh_signal(SIGHUP, &monitor_child_handler);
ssh_signal(SIGTERM, &monitor_child_handler);
@@ -480,7 +484,7 @@ monitor_read_log(struct monitor *pmonito
/* Log it */
if (log_level_name(level) == NULL)
fatal_f("invalid log level %u (corrupted message?)", level);
- sshlogdirect(level, forced, "%s [preauth]", msg);
+ sshlogdirect(level, forced, "%s [%s]", msg, pmonitor->m_state);
sshbuf_free(logmsg);
free(msg);
@@ -1868,13 +1872,28 @@ monitor_init(void)
mon = xcalloc(1, sizeof(*mon));
monitor_openfds(mon, 1);
+ mon->m_state = "";
+
return mon;
}
void
-monitor_reinit(struct monitor *mon)
+monitor_reinit(struct monitor *mon, const char *chroot_dir)
{
- monitor_openfds(mon, 0);
+ struct stat dev_log_stat;
+ char *dev_log_path;
+ int do_logfds = 0;
+
+ if (chroot_dir != NULL) {
+ xasprintf(&dev_log_path, "%s/dev/log", chroot_dir);
+
+ if (stat(dev_log_path, &dev_log_stat) != 0) {
+ debug_f("/dev/log doesn't exist in %s chroot - will try to log via monitor using [postauth] suffix", chroot_dir);
+ do_logfds = 1;
+ }
+ free(dev_log_path);
+ }
+ monitor_openfds(mon, do_logfds);
}
#ifdef GSSAPI
diff -up openssh-8.6p1/monitor.h.log-in-chroot openssh-8.6p1/monitor.h
--- openssh-8.6p1/monitor.h.log-in-chroot 2021-04-19 14:43:08.527843305 +0200
+++ openssh-8.6p1/monitor.h 2021-04-19 14:43:08.545843441 +0200
@@ -80,10 +80,11 @@ struct monitor {
int m_log_sendfd;
struct kex **m_pkex;
pid_t m_pid;
+ char *m_state;
};
struct monitor *monitor_init(void);
-void monitor_reinit(struct monitor *);
+void monitor_reinit(struct monitor *, const char *);
struct Authctxt;
void monitor_child_preauth(struct ssh *, struct monitor *);
diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c
--- openssh-8.6p1/session.c.log-in-chroot 2021-04-19 14:43:08.534843358 +0200
+++ openssh-8.6p1/session.c 2021-04-19 14:43:08.545843441 +0200
@@ -160,6 +160,7 @@ login_cap_t *lc;
static int is_child = 0;
static int in_chroot = 0;
+static int have_dev_log = 1;
/* File containing userauth info, if ExposeAuthInfo set */
static char *auth_info_file = NULL;
@@ -661,6 +662,7 @@ do_exec(struct ssh *ssh, Session *s, con
int ret;
const char *forced = NULL, *tty = NULL;
char session_type[1024];
+ struct stat dev_log_stat;
if (options.adm_forced_command) {
original_command = command;
@@ -720,6 +722,10 @@ do_exec(struct ssh *ssh, Session *s, con
tty += 5;
}
+ if (lstat("/dev/log", &dev_log_stat) != 0) {
+ have_dev_log = 0;
+ }
+
verbose("Starting session: %s%s%s for %s from %.200s port %d id %d",
session_type,
tty == NULL ? "" : " on ",
@@ -1524,14 +1530,6 @@ child_close_fds(struct ssh *ssh)
/* Stop directing logs to a high-numbered fd before we close it */
log_redirect_stderr_to(NULL);
-
- /*
- * Close any extra open file descriptors so that we don't have them
- * hanging around in clients. Note that we want to do this after
- * initgroups, because at least on Solaris 2.3 it leaves file
- * descriptors open.
- */
- closefrom(STDERR_FILENO + 1);
}
/*
@@ -1665,8 +1663,6 @@ do_child(struct ssh *ssh, Session *s, co
exit(1);
}
- closefrom(STDERR_FILENO + 1);
-
do_rc_files(ssh, s, shell);
/* restore SIGPIPE for child */
@@ -1691,9 +1687,17 @@ do_child(struct ssh *ssh, Session *s, co
argv[i] = NULL;
optind = optreset = 1;
__progname = argv[0];
- exit(sftp_server_main(i, argv, s->pw));
+ exit(sftp_server_main(i, argv, s->pw, have_dev_log));
}
+ /*
+ * Close any extra open file descriptors so that we don't have them
+ * hanging around in clients. Note that we want to do this after
+ * initgroups, because at least on Solaris 2.3 it leaves file
+ * descriptors open.
+ */
+ closefrom(STDERR_FILENO + 1);
+
fflush(NULL);
/* Get the last component of the shell name. */
diff -up openssh-8.6p1/sftp.h.log-in-chroot openssh-8.6p1/sftp.h
--- openssh-8.6p1/sftp.h.log-in-chroot 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/sftp.h 2021-04-19 14:43:08.545843441 +0200
@@ -97,5 +97,5 @@
struct passwd;
-int sftp_server_main(int, char **, struct passwd *);
+int sftp_server_main(int, char **, struct passwd *, int);
void sftp_server_cleanup_exit(int) __attribute__((noreturn));
diff -up openssh-8.6p1/sftp-server.c.log-in-chroot openssh-8.6p1/sftp-server.c
--- openssh-8.6p1/sftp-server.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/sftp-server.c 2021-04-19 14:43:08.545843441 +0200
@@ -1644,7 +1644,7 @@ sftp_server_usage(void)
}
int
-sftp_server_main(int argc, char **argv, struct passwd *user_pw)
+sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handler)
{
int i, r, in, out, ch, skipargs = 0, log_stderr = 0;
ssize_t len, olen;
@@ -1657,7 +1657,7 @@ sftp_server_main(int argc, char **argv,
extern char *__progname;
__progname = ssh_get_progname(argv[0]);
- log_init(__progname, log_level, log_facility, log_stderr);
+ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler);
pw = pwcopy(user_pw);
@@ -1730,7 +1730,7 @@ sftp_server_main(int argc, char **argv,
}
}
- log_init(__progname, log_level, log_facility, log_stderr);
+ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler);
/*
* On platforms where we can, avoid making /proc/self/{mem,maps}
diff -up openssh-8.6p1/sftp-server-main.c.log-in-chroot openssh-8.6p1/sftp-server-main.c
--- openssh-8.6p1/sftp-server-main.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/sftp-server-main.c 2021-04-19 14:43:08.545843441 +0200
@@ -50,5 +50,5 @@ main(int argc, char **argv)
return 1;
}
- return (sftp_server_main(argc, argv, user_pw));
+ return (sftp_server_main(argc, argv, user_pw, 0));
}
diff -up openssh-8.6p1/sshd-session.c.log-in-chroot openssh-8.6p1/sshd-session.c
--- openssh-8.6p1/sshd-session.c.log-in-chroot 2021-04-19 14:43:08.543843426 +0200
+++ openssh-8.6p1/sshd-session.c 2021-04-19 14:43:08.545843441 +0200
@@ -559,7 +559,7 @@ privsep_postauth(struct ssh *ssh, Authct
#endif
/* New socket pair */
- monitor_reinit(pmonitor);
+ monitor_reinit(pmonitor, options.chroot_directory);
pmonitor->m_pid = fork();
if (pmonitor->m_pid == -1)
@@ -578,6 +578,11 @@ privsep_postauth(struct ssh *ssh, Authct
close(pmonitor->m_sendfd);
pmonitor->m_sendfd = -1;
+ close(pmonitor->m_log_recvfd);
+ pmonitor->m_log_recvfd = -1;
+
+ if (pmonitor->m_log_sendfd != -1)
+ set_log_handler(mm_log_handler, pmonitor);
/* Demote the private keys to public keys. */
demote_sensitive_data();

@ -0,0 +1,14 @@
--- a/scp.c
+++ a/scp.c
@@ -1084,6 +1084,10 @@ sink(int argc, char **argv)
free(vect[0]);
continue;
}
+ if (buf[0] == 'C' && ! exists && np[strlen(np)-1] == '/') {
+ errno = ENOTDIR;
+ goto bad;
+ }
omode = mode;
mode |= S_IWUSR;
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) {
--

@ -0,0 +1,131 @@
diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c
index 8f32464..18a2ca4 100644
--- a/openbsd-compat/port-linux-sshd.c
+++ b/openbsd-compat/port-linux-sshd.c
@@ -32,6 +32,7 @@
#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
#include "servconf.h"
#include "port-linux.h"
+#include "misc.h"
#include "sshkey.h"
#include "hostfile.h"
#include "auth.h"
@@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname)
void
sshd_selinux_copy_context(void)
{
- security_context_t *ctx;
+ char *ctx;
if (!sshd_selinux_enabled())
return;
@@ -461,6 +462,72 @@ sshd_selinux_copy_context(void)
}
}
+void
+sshd_selinux_change_privsep_preauth_context(void)
+{
+ int len;
+ char line[1024], *preauth_context = NULL, *cp, *arg;
+ const char *contexts_path;
+ FILE *contexts_file;
+ struct stat sb;
+
+ contexts_path = selinux_openssh_contexts_path();
+ if (contexts_path == NULL) {
+ debug3_f("Failed to get the path to SELinux context");
+ return;
+ }
+
+ if ((contexts_file = fopen(contexts_path, "r")) == NULL) {
+ debug_f("Failed to open SELinux context file");
+ return;
+ }
+
+ if (fstat(fileno(contexts_file), &sb) != 0 ||
+ sb.st_uid != 0 || (sb.st_mode & 022) != 0) {
+ logit_f("SELinux context file needs to be owned by root"
+ " and not writable by anyone else");
+ fclose(contexts_file);
+ return;
+ }
+
+ while (fgets(line, sizeof(line), contexts_file)) {
+ /* Strip trailing whitespace */
+ for (len = strlen(line) - 1; len > 0; len--) {
+ if (strchr(" \t\r\n", line[len]) == NULL)
+ break;
+ line[len] = '\0';
+ }
+
+ if (line[0] == '\0')
+ continue;
+
+ cp = line;
+ arg = strdelim(&cp);
+ if (arg && *arg == '\0')
+ arg = strdelim(&cp);
+
+ if (arg && strcmp(arg, "privsep_preauth") == 0) {
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0') {
+ debug_f("privsep_preauth is empty");
+ fclose(contexts_file);
+ return;
+ }
+ preauth_context = xstrdup(arg);
+ }
+ }
+ fclose(contexts_file);
+
+ if (preauth_context == NULL) {
+ debug_f("Unable to find 'privsep_preauth' option in"
+ " SELinux context file");
+ return;
+ }
+
+ ssh_selinux_change_context(preauth_context);
+ free(preauth_context);
+}
+
#endif
#endif
diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c
--- a/openbsd-compat/port-linux.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/openbsd-compat/port-linux.c (date 1703108053912)
@@ -207,7 +207,7 @@
xasprintf(&newctx, "%.*s%s%s", (int)(cx - oldctx + 1), oldctx,
newname, cx2 == NULL ? "" : cx2);
- debug3_f("setting context from '%s' to '%s'", oldctx, newctx);
+ debug_f("setting context from '%s' to '%s'", oldctx, newctx);
if (setcon(newctx) < 0)
do_log2_f(log_level, "setcon %s from %s failed with %s",
newctx, oldctx, strerror(errno));
diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h
index cb51f99..8b7cda2 100644
--- a/openbsd-compat/port-linux.h
+++ b/openbsd-compat/port-linux.h
@@ -29,6 +29,7 @@ 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);
+void sshd_selinux_change_privsep_preauth_context(void);
#endif
#ifdef LINUX_OOM_ADJUST
diff --git a/sshd-session.c b/sshd-session.c
index 2871fe9..39b9c08 100644
--- a/sshd-session.c
+++ b/sshd-session.c
@@ -629,7 +629,7 @@ privsep_preauth_child(void)
demote_sensitive_data();
#ifdef WITH_SELINUX
- ssh_selinux_change_context("sshd_net_t");
+ sshd_selinux_change_privsep_preauth_context();
#endif
/* Demote the child */

@ -0,0 +1,134 @@
diff -up openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-7.4p1/gss-serv-krb5.c
--- openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users 2016-12-23 15:18:40.615216100 +0100
+++ openssh-7.4p1/gss-serv-krb5.c 2016-12-23 15:18:40.628216102 +0100
@@ -279,7 +279,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
FILE *fp;
char file[MAXPATHLEN];
char *line = NULL;
- char kuser[65]; /* match krb5_kuserok() */
struct stat st;
struct passwd *pw = the_authctxt->pw;
int found_principal = 0;
@@ -288,7 +287,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
/* If both .k5login and .k5users DNE, self-login is ok. */
- if (!k5login_exists && (access(file, F_OK) == -1)) {
+ if ( !options.enable_k5users || (!k5login_exists && (access(file, F_OK) == -1))) {
return ssh_krb5_kuserok(krb_context, principal, luser,
k5login_exists);
}
diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c
--- openssh-7.4p1/servconf.c.GSSAPIEnablek5users 2016-12-23 15:18:40.615216100 +0100
+++ openssh-7.4p1/servconf.c 2016-12-23 15:35:36.354401156 +0100
@@ -168,6 +168,7 @@ initialize_server_options(ServerOptions
options->gss_store_rekey = -1;
options->gss_kex_algorithms = NULL;
options->use_kuserok = -1;
+ options->enable_k5users = -1;
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->permit_empty_passwd = -1;
@@ -345,6 +346,8 @@ fill_default_server_options(ServerOption
#endif
if (options->use_kuserok == -1)
options->use_kuserok = 1;
+ if (options->enable_k5users == -1)
+ options->enable_k5users = 0;
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
@@ -578,7 +578,7 @@ typedef enum {
sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize,
sPerSourcePenalties, sPerSourcePenaltyExemptList,
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
- sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
+ sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor,
sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey,
sAcceptEnv, sSetEnv, sPermitTunnel,
sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
@@ -600,14 +600,16 @@ static struct {
{ "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
{ "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
{ "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL },
+ { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL },
#else
{ "gssapiauthentication", sUnsupported, SSHCFG_ALL },
{ "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
{ "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
{ "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
{ "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
{ "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
{ "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL },
+ { "gssapienablek5users", sUnsupported, SSHCFG_ALL },
#endif
{ "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
{ "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
@@ -1653,6 +1658,10 @@ process_server_config_line(ServerOptions
intptr = &options->use_kuserok;
goto parse_flag;
+ case sGssEnablek5users:
+ intptr = &options->enable_k5users;
+ goto parse_flag;
+
case sMatch:
if (cmdline)
fatal("Match directive not supported as a command-line "
@@ -2026,6 +2035,7 @@ copy_set_server_options(ServerOptions *d
M_CP_INTOPT(ip_qos_interactive);
M_CP_INTOPT(ip_qos_bulk);
M_CP_INTOPT(use_kuserok);
+ M_CP_INTOPT(enable_k5users);
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);
M_CP_INTOPT(log_level);
@@ -2320,6 +2330,7 @@ dump_config(ServerOptions *o)
# endif
dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache);
dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
+ dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users);
#endif
#ifdef GSSAPI
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
diff -up openssh-7.4p1/servconf.h.GSSAPIEnablek5users openssh-7.4p1/servconf.h
--- openssh-7.4p1/servconf.h.GSSAPIEnablek5users 2016-12-23 15:18:40.616216100 +0100
+++ openssh-7.4p1/servconf.h 2016-12-23 15:18:40.629216102 +0100
@@ -174,6 +174,7 @@ typedef struct {
int kerberos_unique_ccache; /* If true, the acquired ticket will
* be stored in per-session ccache */
int use_kuserok;
+ int enable_k5users;
int gss_authentication; /* If true, permit GSSAPI authentication */
int gss_keyex; /* If true, permit GSSAPI key exchange */
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
diff -up openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users openssh-7.4p1/sshd_config.5
--- openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users 2016-12-23 15:18:40.630216103 +0100
+++ openssh-7.4p1/sshd_config.5 2016-12-23 15:36:21.607408435 +0100
@@ -628,6 +628,12 @@ Specifies whether to automatically destr
on logout.
The default is
.Cm yes .
+.It Cm GSSAPIEnablek5users
+Specifies whether to look at .k5users file for GSSAPI authentication
+access control. Further details are described in
+.Xr ksu 1 .
+The default is
+.Cm no .
.It Cm GSSAPIKeyExchange
Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
doesn't rely on ssh keys to verify host identity.
diff -up openssh-7.4p1/sshd_config.GSSAPIEnablek5users openssh-7.4p1/sshd_config
--- openssh-7.4p1/sshd_config.GSSAPIEnablek5users 2016-12-23 15:18:40.616216100 +0100
+++ openssh-7.4p1/sshd_config 2016-12-23 15:18:40.631216103 +0100
@@ -80,6 +80,7 @@ GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
+#GSSAPIEnablek5users no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
diff -up openssh-9.8p1/servconf.c.xxx openssh-9.8p1/servconf.c
--- openssh-9.8p1/servconf.c.xxx 2024-07-11 13:51:19.969960781 +0200
+++ openssh-9.8p1/servconf.c 2024-07-11 13:51:30.938231250 +0200

@ -0,0 +1,42 @@
diff -up openssh/sshd.c.ip-opts openssh/sshd.c
--- openssh/sshd-session.c.ip-opts 2016-07-25 13:58:48.998507834 +0200
+++ openssh/sshd-session.c 2016-07-25 14:01:28.346469878 +0200
@@ -1507,12 +1507,32 @@ check_ip_options(struct ssh *ssh)
if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts,
&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", opts[i]);
- fatal("Connection from %.100s port %d with IP opts: %.800s",
- ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text);
+ i = 0;
+ do {
+ switch (opts[i]) {
+ case 0:
+ case 1:
+ ++i;
+ break;
+ case 130:
+ case 133:
+ case 134:
+ if (i + 1 < option_size && opts[i + 1] >= 2) {
+ i += opts[i + 1];
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* Fail, fatally, if we detect either loose or strict
+ * or incorrect source routing options. */
+ text[0] = '\0';
+ for (i = 0; i < option_size; i++)
+ snprintf(text + i*3, sizeof(text) - i*3,
+ " %2.2x", opts[i]);
+ fatal("Connection from %.100s port %d with IP options:%.800s",
+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text);
+ }
+ } while (i < option_size);
}
#endif /* IP_OPTIONS */
}

@ -0,0 +1,280 @@
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 413b845..54dd383 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -32,7 +32,9 @@
#include <sys/types.h>
#include <stdarg.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "xmalloc.h"
#include "sshkey.h"
@@ -45,6 +47,7 @@
#include "ssh-gss.h"
+extern Authctxt *the_authctxt;
extern ServerOptions options;
#ifdef HEIMDAL
@@ -56,6 +59,13 @@ extern ServerOptions options;
# include <gssapi/gssapi_krb5.h>
#endif
+/* all commands are allowed by default */
+char **k5users_allowed_cmds = NULL;
+
+static int ssh_gssapi_k5login_exists();
+static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *,
+ int);
+
static krb5_context krb_context = NULL;
/* Initialise the krb5 library, for the stuff that GSSAPI won't do */
@@ -88,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
krb5_principal princ;
int retval;
const char *errmsg;
+ int k5login_exists;
if (ssh_gssapi_krb5_init() == 0)
return 0;
@@ -99,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
krb5_free_error_message(krb_context, errmsg);
return 0;
}
- if (krb5_kuserok(krb_context, princ, name)) {
+ /* krb5_kuserok() returns 1 if .k5login DNE and this is self-login.
+ * We have to make sure to check .k5users in that case. */
+ k5login_exists = ssh_gssapi_k5login_exists();
+ /* NOTE: .k5login and .k5users must opened as root, not the user,
+ * because if they are on a krb5-protected filesystem, user credentials
+ * to access these files aren't available yet. */
+ if (krb5_kuserok(krb_context, princ, name) && k5login_exists) {
retval = 1;
logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
name, (char *)client->displayname.value);
+ } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value,
+ name, k5login_exists)) {
+ retval = 1;
+ logit("Authorized to %s, krb5 principal %s "
+ "(ssh_gssapi_krb5_cmdok)",
+ name, (char *)client->displayname.value);
} else
retval = 0;
@@ -110,6 +133,137 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
return retval;
}
+/* Test for existence of .k5login.
+ * We need this as part of our .k5users check, because krb5_kuserok()
+ * returns success if .k5login DNE and user is logging in as himself.
+ * With .k5login absent and .k5users present, we don't want absence
+ * of .k5login to authorize self-login. (absence of both is required)
+ * Returns 1 if .k5login is available, 0 otherwise.
+ */
+static int
+ssh_gssapi_k5login_exists()
+{
+ char file[MAXPATHLEN];
+ struct passwd *pw = the_authctxt->pw;
+
+ snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
+ return access(file, F_OK) == 0;
+}
+
+/* check .k5users for login or command authorization
+ * Returns 1 if principal is authorized, 0 otherwise.
+ * If principal is authorized, (global) k5users_allowed_cmds may be populated.
+ */
+static int
+ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
+ const char *luser, int k5login_exists)
+{
+ FILE *fp;
+ char file[MAXPATHLEN];
+ char *line = NULL;
+ char kuser[65]; /* match krb5_kuserok() */
+ struct stat st;
+ struct passwd *pw = the_authctxt->pw;
+ int found_principal = 0;
+ int ncommands = 0, allcommands = 0;
+ u_long linenum = 0;
+ size_t linesize = 0;
+
+ snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
+ /* If both .k5login and .k5users DNE, self-login is ok. */
+ if (!k5login_exists && (access(file, F_OK) == -1)) {
+ return (krb5_aname_to_localname(krb_context, principal,
+ sizeof(kuser), kuser) == 0) &&
+ (strcmp(kuser, luser) == 0);
+ }
+ if ((fp = fopen(file, "r")) == NULL) {
+ int saved_errno = errno;
+ /* 2nd access check to ease debugging if file perms are wrong.
+ * But we don't want to report this if .k5users simply DNE. */
+ if (access(file, F_OK) == 0) {
+ logit("User %s fopen %s failed: %s",
+ pw->pw_name, file, strerror(saved_errno));
+ }
+ return 0;
+ }
+ /* .k5users must be owned either by the user or by root */
+ if (fstat(fileno(fp), &st) == -1) {
+ /* can happen, but very wierd error so report it */
+ logit("User %s fstat %s failed: %s",
+ pw->pw_name, file, strerror(errno));
+ fclose(fp);
+ return 0;
+ }
+ if (!(st.st_uid == pw->pw_uid || st.st_uid == 0)) {
+ logit("User %s %s is not owned by root or user",
+ pw->pw_name, file);
+ fclose(fp);
+ return 0;
+ }
+ /* .k5users must be a regular file. krb5_kuserok() doesn't do this
+ * check, but we don't want to be deficient if they add a check. */
+ if (!S_ISREG(st.st_mode)) {
+ logit("User %s %s is not a regular file", pw->pw_name, file);
+ fclose(fp);
+ return 0;
+ }
+ /* file exists; initialize k5users_allowed_cmds (to none!) */
+ k5users_allowed_cmds = xcalloc(++ncommands,
+ sizeof(*k5users_allowed_cmds));
+
+ /* Check each line. ksu allows unlimited length lines. */
+ while (!allcommands && getline(&line, &linesize, fp) != -1) {
+ linenum++;
+ char *token;
+
+ /* we parse just like ksu, even though we could do better */
+ if ((token = strtok(line, " \t\n")) == NULL)
+ continue;
+ if (strcmp(name, token) == 0) {
+ /* we matched on client principal */
+ found_principal = 1;
+ if ((token = strtok(NULL, " \t\n")) == NULL) {
+ /* only shell is allowed */
+ k5users_allowed_cmds[ncommands-1] =
+ xstrdup(pw->pw_shell);
+ k5users_allowed_cmds =
+ xreallocarray(k5users_allowed_cmds, ++ncommands,
+ sizeof(*k5users_allowed_cmds));
+ break;
+ }
+ /* process the allowed commands */
+ while (token) {
+ if (strcmp(token, "*") == 0) {
+ allcommands = 1;
+ break;
+ }
+ k5users_allowed_cmds[ncommands-1] =
+ xstrdup(token);
+ k5users_allowed_cmds =
+ xreallocarray(k5users_allowed_cmds, ++ncommands,
+ sizeof(*k5users_allowed_cmds));
+ token = strtok(NULL, " \t\n");
+ }
+ }
+ }
+ free(line);
+ if (k5users_allowed_cmds) {
+ /* terminate vector */
+ k5users_allowed_cmds[ncommands-1] = NULL;
+ /* if all commands are allowed, free vector */
+ if (allcommands) {
+ int i;
+ for (i = 0; i < ncommands; i++) {
+ free(k5users_allowed_cmds[i]);
+ }
+ free(k5users_allowed_cmds);
+ k5users_allowed_cmds = NULL;
+ }
+ }
+ fclose(fp);
+ return found_principal;
+}
+
/* This writes out any forwarded credentials from the structure populated
* during userauth. Called after we have setuid to the user */
diff --git a/session.c b/session.c
index 28659ec..9c94d8e 100644
--- a/session.c
+++ b/session.c
@@ -789,6 +789,29 @@ do_exec(Session *s, const char *command)
command = auth_opts->force_command;
forced = "(key-option)";
}
+#ifdef GSSAPI
+#ifdef KRB5 /* k5users_allowed_cmds only available w/ GSSAPI+KRB5 */
+ else if (k5users_allowed_cmds) {
+ const char *match = command;
+ int allowed = 0, i = 0;
+
+ if (!match)
+ match = s->pw->pw_shell;
+ while (k5users_allowed_cmds[i]) {
+ if (strcmp(match, k5users_allowed_cmds[i++]) == 0) {
+ debug("Allowed command '%.900s'", match);
+ allowed = 1;
+ break;
+ }
+ }
+ if (!allowed) {
+ debug("command '%.900s' not allowed", match);
+ return 1;
+ }
+ }
+#endif
+#endif
+
s->forced = 0;
if (forced != NULL) {
s->forced = 1;
diff --git a/ssh-gss.h b/ssh-gss.h
index 0374c88..509109a 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -49,6 +49,10 @@
# endif /* !HAVE_DECL_GSS_C_NT_... */
# endif /* !HEIMDAL */
+
+/* .k5users support */
+extern char **k5users_allowed_cmds;
+
#endif /* KRB5 */
/* draft-ietf-secsh-gsskeyex-06 */
diff --git a/sshd.8 b/sshd.8
index adcaaf9..824163b 100644
--- a/sshd.8
+++ b/sshd.8
@@ -324,6 +324,7 @@ Finally, the server and the client enter an authentication dialog.
The client tries to authenticate itself using
host-based authentication,
public key authentication,
+GSSAPI authentication,
challenge-response authentication,
or password authentication.
.Pp
@@ -800,6 +801,12 @@ This file is used in exactly the same way as
but allows host-based authentication without permitting login with
rlogin/rsh.
.Pp
+.It Pa ~/.k5login
+.It Pa ~/.k5users
+These files enforce GSSAPI/Kerberos authentication access control.
+Further details are described in
+.Xr ksu 1 .
+.Pp
.It Pa ~/.ssh/
This directory is the default location for all user-specific configuration
and authentication information.

@ -0,0 +1,484 @@
diff -up openssh/misc.c.keycat openssh/misc.c
--- openssh/misc.c.keycat 2015-06-24 10:57:50.158849606 +0200
+++ openssh/misc.c 2015-06-24 11:04:23.989868638 +0200
@@ -966,6 +966,13 @@ subprocess(const char *tag, struct passw
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
diff -up openssh/HOWTO.ssh-keycat.keycat openssh/HOWTO.ssh-keycat
--- openssh/HOWTO.ssh-keycat.keycat 2015-06-24 10:57:50.157849608 +0200
+++ openssh/HOWTO.ssh-keycat 2015-06-24 10:57:50.157849608 +0200
@@ -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
+
+
diff -up openssh/Makefile.in.keycat openssh/Makefile.in
--- openssh/Makefile.in.keycat 2015-06-24 10:57:50.152849621 +0200
+++ openssh/Makefile.in 2015-06-24 10:57:50.157849608 +0200
@@ -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
@@ -52,6 +52,7 @@ K5LIBS=@K5LIBS@
K5LIBS=@K5LIBS@
GSSLIBS=@GSSLIBS@
SSHDLIBS=@SSHDLIBS@
+KEYCATLIBS=@KEYCATLIBS@
LIBEDIT=@LIBEDIT@
LIBFIDO2=@LIBFIDO2@
AR=@AR@
@@ -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)
XMSS_OBJS=\
ssh-xmss.o \
@@ -190,6 +191,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)
@@ -321,6 +325,7 @@ install-files:
$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
$(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 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
diff -up openssh/openbsd-compat/port-linux.h.keycat openssh/openbsd-compat/port-linux.h
--- openssh/openbsd-compat/port-linux.h.keycat 2015-06-24 10:57:50.150849626 +0200
+++ openssh/openbsd-compat/port-linux.h 2015-06-24 10:57:50.160849601 +0200
@@ -25,8 +25,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
diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/port-linux-sshd.c
--- openssh/openbsd-compat/port-linux-sshd.c.keycat 2015-06-24 10:57:50.150849626 +0200
+++ openssh/openbsd-compat/port-linux-sshd.c 2015-06-24 10:57:50.159849603 +0200
@@ -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,
@@ -308,7 +322,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);
@@ -336,6 +350,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)
@@ -344,7 +376,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) {
@@ -415,7 +447,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) {
diff -up openssh/platform.c.keycat openssh/platform.c
--- openssh/platform.c.keycat 2015-06-24 10:57:50.147849633 +0200
+++ openssh/platform.c 2015-06-24 10:57:50.160849601 +0200
@@ -103,7 +103,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
diff -up openssh/ssh-keycat.c.keycat openssh/ssh-keycat.c
--- openssh/ssh-keycat.c.keycat 2015-06-24 10:57:50.161849599 +0200
+++ openssh/ssh-keycat.c 2015-06-24 10:57:50.161849599 +0200
@@ -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 <tmraz@redhat.com>
+*/
+
+#define _GNU_SOURCE
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <unistd.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include <security/pam_appl.h>
+
+#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 <user-name>\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;
+}
diff --git a/configure.ac b/configure.ac
index 3bbccfd..6481f1f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2952,6 +2952,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])
@@ -3105,6 +3106,7 @@
;;
*)
SSHDLIBS="$SSHDLIBS -ldl"
+ KEYCATLIBS="$KEYCATLIBS -ldl"
;;
esac
fi
@@ -4042,6 +4044,7 @@ AC_ARG_WITH([selinux],
fi ]
)
AC_SUBST([SSHDLIBS])
+AC_SUBST([KEYCATLIBS])
# Check whether user wants Kerberos 5 support
KRB5_MSG="no"
@@ -5031,6 +5034,9 @@ fi
if test ! -z "${SSHDLIBS}"; then
echo " +for sshd: ${SSHDLIBS}"
fi
+if test ! -z "${KEYCATLIBS}"; then
+echo " +for ssh-keycat: ${KEYCATLIBS}"
+fi
echo ""

@ -0,0 +1,289 @@
diff -up openssh-7.4p1/auth-krb5.c.kuserok openssh-7.4p1/auth-krb5.c
--- openssh-7.4p1/auth-krb5.c.kuserok 2016-12-23 14:36:07.640465939 +0100
+++ openssh-7.4p1/auth-krb5.c 2016-12-23 14:36:07.644465936 +0100
@@ -56,6 +56,21 @@
extern ServerOptions options;
+int
+ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client,
+ int k5login_exists)
+{
+ if (options.use_kuserok || !k5login_exists)
+ 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)
{
@@ -160,8 +175,9 @@ auth_krb5_password(Authctxt *authctxt, c
if (problem)
goto out;
- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
- authctxt->pw->pw_name)) {
+ /* Use !options.use_kuserok here to make ssh_krb5_kuserok() not
+ * depend on the existance of .k5login */
+ if (!ssh_krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name, !options.use_kuserok)) {
problem = -1;
goto out;
}
diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c
--- openssh-7.4p1/gss-serv-krb5.c.kuserok 2016-12-23 14:36:07.640465939 +0100
+++ openssh-7.4p1/gss-serv-krb5.c 2016-12-23 14:36:07.644465936 +0100
@@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_pr
int);
static krb5_context krb_context = NULL;
+extern int ssh_krb5_kuserok(krb5_context, krb5_principal, const char *, int);
/* Initialise the krb5 library, for the stuff that GSSAPI won't do */
@@ -92,6 +93,103 @@ ssh_gssapi_krb5_init(void)
* Returns true if the user is OK to log in, otherwise returns 0
*/
+/* The purpose of the function is to find out if a Kerberos principal is
+ * allowed to log in as the given local user. This is a general problem with
+ * Kerberized services because by design the Kerberos principals are
+ * completely independent from the local user names. This is one of the
+ * reasons why Kerberos is working well on different operating systems like
+ * Windows and UNIX/Linux. Nevertheless a relationship between a Kerberos
+ * principal and a local user name must be established because otherwise every
+ * access would be granted for every principal with a valid ticket.
+ *
+ * Since it is a general issue libkrb5 provides some functions for
+ * applications to find out about the relationship between the Kerberos
+ * principal and a local user name. They are krb5_kuserok() and
+ * krb5_aname_to_localname().
+ *
+ * krb5_kuserok() can be used to "Determine if a principal is authorized to
+ * log in as a local user" (from the MIT Kerberos documentation of this
+ * function). Which is exactly what we are looking for and should be the
+ * preferred choice. It accepts the Kerberos principal and a local user name
+ * and let libkrb5 or its plugins determine if they relate to each other or
+ * not.
+ *
+ * krb5_aname_to_localname() can use used to "Convert a principal name to a
+ * local name" (from the MIT Kerberos documentation of this function). It
+ * accepts a Kerberos principle and returns a local name and it is up to the
+ * application to do any additional checks. There are two issues using
+ * krb5_aname_to_localname(). First, since POSIX user names are case
+ * sensitive, the calling application in general has no other choice than
+ * doing a case-sensitive string comparison between the name returned by
+ * krb5_aname_to_localname() and the name used at the login prompt. When the
+ * users are provided by a case in-sensitive server, e.g. Active Directory,
+ * this might lead to login failures because the user typing the name at the
+ * login prompt might not be aware of the right case. Another issue might be
+ * caused if there are multiple alias names available for a single user. E.g.
+ * the canonical name of a user is user@group.department.example.com but there
+ * exists a shorter login name, e.g. user@example.com, to safe typing at the
+ * login prompt. Here krb5_aname_to_localname() can only return the canonical
+ * name, but if the short alias is used at the login prompt authentication
+ * will fail as well. All this can be avoided by using krb5_kuserok() and
+ * configuring krb5.conf or using a suitable plugin to meet the needs of the
+ * given environment.
+ *
+ * The Fedora and RHEL version of openssh contain two patches which modify the
+ * access control behavior:
+ * - openssh-6.6p1-kuserok.patch
+ * - openssh-6.6p1-force_krb.patch
+ *
+ * openssh-6.6p1-kuserok.patch adds a new option KerberosUseKuserok for
+ * sshd_config which controls if krb5_kuserok() is used to check if the
+ * principle is authorized or if krb5_aname_to_localname() should be used.
+ * The reason to add this patch was that krb5_kuserok() by default checks if
+ * a .k5login file exits in the users home-directory. With this the user can
+ * give access to his account for any given principal which might be
+ * in violation with company policies and it would be useful if this can be
+ * rejected. Nevertheless the patch ignores the fact that krb5_kuserok() does
+ * no only check .k5login but other sources as well and checking .k5login can
+ * be disabled for all applications in krb5.conf as well. With this new
+ * option KerberosUseKuserok set to 'no' (and this is the default for RHEL7
+ * and Fedora 21) openssh can only use krb5_aname_to_localname() with the
+ * restrictions mentioned above.
+ *
+ * openssh-6.6p1-force_krb.patch adds a ksu like behaviour to ssh, i.e. when
+ * using GSSAPI authentication only commands configured in the .k5user can be
+ * executed. Here the wrong assumption that krb5_kuserok() only checks
+ * .k5login is made as well. In contrast ksu checks .k5login directly and
+ * does not use krb5_kuserok() which might be more useful for the given
+ * purpose. Additionally this patch is not synced with
+ * openssh-6.6p1-kuserok.patch.
+ *
+ * The current patch tries to restore the usage of krb5_kuserok() so that e.g.
+ * localauth plugins can be used. It does so by adding a forth parameter to
+ * ssh_krb5_kuserok() which indicates whether .k5login exists or not. If it
+ * does not exists krb5_kuserok() is called even if KerberosUseKuserok is set
+ * to 'no' because the intent of the option is to not check .k5login and if it
+ * does not exists krb5_kuserok() returns a result without checking .k5login.
+ * If .k5login does exists and KerberosUseKuserok is 'no' we fall back to
+ * krb5_aname_to_localname(). This is in my point of view an acceptable
+ * limitation and does not break the current behaviour.
+ *
+ * Additionally with this patch ssh_krb5_kuserok() is called in
+ * ssh_gssapi_krb5_cmdok() instead of only krb5_aname_to_localname() is
+ * neither .k5login nor .k5users exists to allow plugin evaluation via
+ * krb5_kuserok() as well.
+ *
+ * I tried to keep the patch as minimal as possible, nevertheless I see some
+ * areas for improvement which, if they make sense, have to be evaluated
+ * carefully because they might change existing behaviour and cause breaks
+ * during upgrade:
+ * - I wonder if disabling .k5login usage make sense in sshd or if it should
+ * be better disabled globally in krb5.conf
+ * - if really needed openssh-6.6p1-kuserok.patch should be fixed to really
+ * only disable checking .k5login and maybe .k5users
+ * - the ksu behaviour should be configurable and maybe check the .k5login and
+ * .k5users files directly like ksu itself does
+ * - to make krb5_aname_to_localname() more useful an option for sshd to use
+ * the canonical name (the one returned by getpwnam()) instead of the name
+ * given at the login prompt might be useful */
+
static int
ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
{
@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client
/* NOTE: .k5login and .k5users must opened as root, not the user,
* because if they are on a krb5-protected filesystem, user credentials
* to access these files aren't available yet. */
- if (krb5_kuserok(krb_context, princ, name) && k5login_exists) {
+ if (k5login_exists &&
+ ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) {
retval = 1;
logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
name, (char *)client->displayname.value);
@@ -190,9 +289,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir);
/* If both .k5login and .k5users DNE, self-login is ok. */
if (!k5login_exists && (access(file, F_OK) == -1)) {
- return (krb5_aname_to_localname(krb_context, principal,
- sizeof(kuser), kuser) == 0) &&
- (strcmp(kuser, luser) == 0);
+ return ssh_krb5_kuserok(krb_context, principal, luser,
+ k5login_exists);
}
if ((fp = fopen(file, "r")) == NULL) {
int saved_errno = errno;
diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c
--- openssh-7.4p1/servconf.c.kuserok 2016-12-23 14:36:07.630465944 +0100
+++ openssh-7.4p1/servconf.c 2016-12-23 15:11:52.278133344 +0100
@@ -116,6 +116,7 @@ initialize_server_options(ServerOptions
options->gss_strict_acceptor = -1;
options->gss_store_rekey = -1;
options->gss_kex_algorithms = NULL;
+ options->use_kuserok = -1;
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->permit_empty_passwd = -1;
@@ -278,6 +279,8 @@ fill_default_server_options(ServerOption
if (options->gss_kex_algorithms == NULL)
options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX);
#endif
+ if (options->use_kuserok == -1)
+ options->use_kuserok = 1;
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
@@ -399,7 +402,7 @@ typedef enum {
sPort, sHostKeyFile, sLoginGraceTime,
sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
- sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication,
+ sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication,
sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
@@ -478,12 +481,14 @@ static struct {
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
#endif
{ "kerberosuniqueccache", sKerberosUniqueCCache, SSHCFG_GLOBAL },
+ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL },
#else
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosuniqueccache", sUnsupported, SSHCFG_GLOBAL },
+ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL },
#endif
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
@@ -1644,6 +1649,10 @@ process_server_config_line(ServerOptions
}
break;
+ case sKerberosUseKuserok:
+ intptr = &options->use_kuserok;
+ goto parse_flag;
+
case sMatch:
if (cmdline)
fatal("Match directive not supported as a command-line "
@@ -2016,6 +2025,7 @@ copy_set_server_options(ServerOptions *d
M_CP_INTOPT(client_alive_interval);
M_CP_INTOPT(ip_qos_interactive);
M_CP_INTOPT(ip_qos_bulk);
+ M_CP_INTOPT(use_kuserok);
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);
M_CP_INTOPT(log_level);
@@ -2309,6 +2319,7 @@ dump_config(ServerOptions *o)
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
# endif
dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache);
+ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
#endif
#ifdef GSSAPI
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
diff -up openssh-7.4p1/servconf.h.kuserok openssh-7.4p1/servconf.h
--- openssh-7.4p1/servconf.h.kuserok 2016-12-23 14:36:07.630465944 +0100
+++ openssh-7.4p1/servconf.h 2016-12-23 14:36:07.645465936 +0100
@@ -118,6 +118,7 @@ typedef struct {
* authenticated with Kerberos. */
int kerberos_unique_ccache; /* If true, the acquired ticket will
* be stored in per-session ccache */
+ int use_kuserok;
int gss_authentication; /* If true, permit GSSAPI authentication */
int gss_keyex; /* If true, permit GSSAPI key exchange */
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
diff -up openssh-7.4p1/sshd_config.5.kuserok openssh-7.4p1/sshd_config.5
--- openssh-7.4p1/sshd_config.5.kuserok 2016-12-23 14:36:07.637465940 +0100
+++ openssh-7.4p1/sshd_config.5 2016-12-23 15:14:03.117162222 +0100
@@ -850,6 +850,10 @@ Specifies whether to automatically destr
.Cm no
can lead to overwriting previous tickets by subseqent connections to the same
user account.
+.It Cm KerberosUseKuserok
+Specifies whether to look at .k5login file for user's aliases.
+The default is
+.Cm yes .
.It Cm KexAlgorithms
Specifies the permitted KEX (Key Exchange) algorithms that the server will
offer to clients.
@@ -1078,6 +1082,7 @@ Available keywords are
.Cm IPQoS ,
.Cm KbdInteractiveAuthentication ,
.Cm KerberosAuthentication ,
+.Cm KerberosUseKuserok ,
.Cm LogLevel ,
.Cm MaxAuthTries ,
.Cm MaxSessions ,
diff -up openssh-7.4p1/sshd_config.kuserok openssh-7.4p1/sshd_config
--- openssh-7.4p1/sshd_config.kuserok 2016-12-23 14:36:07.631465943 +0100
+++ openssh-7.4p1/sshd_config 2016-12-23 14:36:07.646465935 +0100
@@ -73,6 +73,7 @@ ChallengeResponseAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
+#KerberosUseKuserok yes
# GSSAPI options
#GSSAPIAuthentication no

@ -0,0 +1,120 @@
diff -up openssh-7.4p1/openbsd-compat/port-linux.h.privsep-selinux openssh-7.4p1/openbsd-compat/port-linux.h
--- openssh-7.4p1/openbsd-compat/port-linux.h.privsep-selinux 2016-12-23 18:58:52.972122201 +0100
+++ openssh-7.4p1/openbsd-compat/port-linux.h 2016-12-23 18:58:52.974122201 +0100
@@ -23,6 +23,7 @@ void ssh_selinux_setup_pty(char *, const
void ssh_selinux_change_context(const char *);
void ssh_selinux_setfscreatecon(const char *);
+void sshd_selinux_copy_context(void);
void sshd_selinux_setup_exec_context(char *);
#endif
diff -up openssh-7.4p1/openbsd-compat/port-linux-sshd.c.privsep-selinux openssh-7.4p1/openbsd-compat/port-linux-sshd.c
--- openssh-7.4p1/openbsd-compat/port-linux-sshd.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100
+++ openssh-7.4p1/openbsd-compat/port-linux-sshd.c 2016-12-23 18:58:52.974122201 +0100
@@ -419,6 +419,28 @@ sshd_selinux_setup_exec_context(char *pw
debug3_f("done");
}
+void
+sshd_selinux_copy_context(void)
+{
+ security_context_t *ctx;
+
+ if (!ssh_selinux_enabled())
+ return;
+
+ if (getexeccon((security_context_t *)&ctx) != 0) {
+ logit_f("getexeccon failed with %s", strerror(errno));
+ return;
+ }
+ if (ctx != NULL) {
+ /* unset exec context before we will lose this capabililty */
+ if (setexeccon(NULL) != 0)
+ fatal_f("setexeccon failed with %s", strerror(errno));
+ if (setcon(ctx) != 0)
+ fatal_f("setcon failed with %s", strerror(errno));
+ freecon(ctx);
+ }
+}
+
#endif
#endif
diff -up openssh-7.4p1/session.c.privsep-selinux openssh-7.4p1/session.c
--- openssh-7.4p1/session.c.privsep-selinux 2016-12-19 05:59:41.000000000 +0100
+++ openssh-7.4p1/session.c 2016-12-23 18:58:52.974122201 +0100
@@ -1331,7 +1331,7 @@ do_setusercontext(struct passwd *pw)
platform_setusercontext(pw);
- if (platform_privileged_uidswap()) {
+ if (platform_privileged_uidswap() && !is_child) {
#ifdef HAVE_LOGIN_CAP
if (setusercontext(lc, pw, pw->pw_uid,
(LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
@@ -1361,6 +1361,9 @@ do_setusercontext(struct passwd *pw)
(unsigned long long)pw->pw_uid);
chroot_path = percent_expand(tmp, "h", pw->pw_dir,
"u", pw->pw_name, "U", uidstr, (char *)NULL);
+#ifdef WITH_SELINUX
+ sshd_selinux_copy_context();
+#endif
safely_chroot(chroot_path, pw->pw_uid);
free(tmp);
free(chroot_path);
@@ -1396,6 +1399,11 @@ do_setusercontext(struct passwd *pw)
/* Permanently switch to the desired uid. */
permanently_set_uid(pw);
#endif
+
+#ifdef WITH_SELINUX
+ if (in_chroot == 0)
+ sshd_selinux_copy_context();
+#endif
} else if (options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0) {
fatal("server lacks privileges to chroot to ChrootDirectory");
@@ -1413,9 +1421,6 @@ do_pwchange(Session *s)
if (s->ttyfd != -1) {
fprintf(stderr,
"You must change your password now and login again!\n");
-#ifdef WITH_SELINUX
- setexeccon(NULL);
-#endif
#ifdef PASSWD_NEEDS_USERNAME
execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
(char *)NULL);
@@ -1625,9 +1630,6 @@ do_child(Session *s, const char *command
argv[i] = NULL;
optind = optreset = 1;
__progname = argv[0];
-#ifdef WITH_SELINUX
- ssh_selinux_change_context("sftpd_t");
-#endif
exit(sftp_server_main(i, argv, s->pw));
}
diff -up openssh-7.4p1/sshd.c.privsep-selinux openssh-7.4p1/sshd.c
--- openssh-7.4p1/sshd-session.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100
+++ openssh-7.4p1/sshd-session.c 2016-12-23 18:59:13.808124269 +0100
@@ -540,6 +540,10 @@ privsep_preauth_child(void)
/* Demote the private keys to public keys. */
demote_sensitive_data();
+#ifdef WITH_SELINUX
+ ssh_selinux_change_context("sshd_net_t");
+#endif
+
/* Demote the child */
if (privsep_chroot) {
/* Change our root directory */
@@ -403,7 +403,7 @@ privsep_postauth(struct ssh *ssh, Authct
* fd passing, as AFAIK PTY allocation on this platform doesn't require
* special privileges to begin with.
*/
-#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN)
+#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) && !defined(WITH_SELINUX)
skip_privdrop = 1;
#endif

@ -0,0 +1,248 @@
diff -up openssh-8.5p1/auth-krb5.c.coverity openssh-8.5p1/auth-krb5.c
--- openssh-8.5p1/auth-krb5.c.coverity 2021-03-24 12:03:33.724967756 +0100
+++ openssh-8.5p1/auth-krb5.c 2021-03-24 12:03:33.782968159 +0100
@@ -426,6 +426,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx,
umask(old_umask);
if (tmpfd == -1) {
logit("mkstemp(): %.100s", strerror(oerrno));
+ free(ccname);
return oerrno;
}
@@ -433,6 +434,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx,
oerrno = errno;
logit("fchmod(): %.100s", strerror(oerrno));
close(tmpfd);
+ free(ccname);
return oerrno;
}
/* make sure the KRB5CCNAME is set for non-standard location */
diff -up openssh-8.5p1/gss-genr.c.coverity openssh-8.5p1/gss-genr.c
--- openssh-8.5p1/gss-genr.c.coverity 2021-03-26 11:52:46.613942552 +0100
+++ openssh-8.5p1/gss-genr.c 2021-03-26 11:54:37.881726318 +0100
@@ -167,8 +167,9 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup
enclen = __b64_ntop(digest,
ssh_digest_bytes(SSH_DIGEST_MD5), encoded,
ssh_digest_bytes(SSH_DIGEST_MD5) * 2);
-
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
cp = strncpy(s, kex, strlen(kex));
+#pragma GCC diagnostic pop
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
if (sshbuf_len(buf) != 0 &&
diff -up openssh-8.5p1/krl.c.coverity openssh-8.5p1/krl.c
--- openssh-8.5p1/krl.c.coverity 2021-03-02 11:31:47.000000000 +0100
+++ openssh-8.5p1/krl.c 2021-03-24 12:03:33.783968166 +0100
@@ -1261,6 +1262,7 @@ is_key_revoked(struct ssh_krl *krl, cons
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
free(rb.blob);
+ rb.blob = NULL; /* make coverity happy */
if (erb != NULL) {
KRL_DBG(("revoked by key SHA1"));
return SSH_ERR_KEY_REVOKED;
@@ -1271,6 +1273,7 @@ is_key_revoked(struct ssh_krl *krl, cons
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb);
free(rb.blob);
+ rb.blob = NULL; /* make coverity happy */
if (erb != NULL) {
KRL_DBG(("revoked by key SHA256"));
return SSH_ERR_KEY_REVOKED;
@@ -1282,6 +1285,7 @@ is_key_revoked(struct ssh_krl *krl, cons
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb);
free(rb.blob);
+ rb.blob = NULL; /* make coverity happy */
if (erb != NULL) {
KRL_DBG(("revoked by explicit key"));
return SSH_ERR_KEY_REVOKED;
diff -up openssh-8.5p1/loginrec.c.coverity openssh-8.5p1/loginrec.c
--- openssh-8.5p1/loginrec.c.coverity 2021-03-24 13:18:53.793225885 +0100
+++ openssh-8.5p1/loginrec.c 2021-03-24 13:21:27.948404751 +0100
@@ -690,9 +690,11 @@ construct_utmp(struct logininfo *li,
*/
/* Use strncpy because we don't necessarily want null termination */
+ /* coverity[buffer_size_warning : FALSE] */
strncpy(ut->ut_name, li->username,
MIN_SIZEOF(ut->ut_name, li->username));
# ifdef HAVE_HOST_IN_UTMP
+ /* coverity[buffer_size_warning : FALSE] */
strncpy(ut->ut_host, li->hostname,
MIN_SIZEOF(ut->ut_host, li->hostname));
# endif
diff -up openssh-8.5p1/misc.c.coverity openssh-8.5p1/misc.c
--- openssh-8.5p1/misc.c.coverity 2021-03-24 12:03:33.745967902 +0100
+++ openssh-8.5p1/misc.c 2021-03-24 13:31:47.037079617 +0100
@@ -1425,6 +1425,8 @@ sanitise_stdfd(void)
}
if (nullfd > STDERR_FILENO)
close(nullfd);
+ /* coverity[leaked_handle : FALSE]*/
+ /* coverity[leaked_handle : FALSE]*/
}
char *
@@ -2511,6 +2513,7 @@ stdfd_devnull(int do_stdin, int do_stdou
}
if (devnull > STDERR_FILENO)
close(devnull);
+ /* coverity[leaked_handle : FALSE]*/
return ret;
}
diff -up openssh-7.4p1/monitor.c.coverity openssh-7.4p1/monitor.c
--- openssh-7.4p1/monitor.c.coverity 2016-12-23 16:40:26.888788688 +0100
+++ openssh-7.4p1/monitor.c 2016-12-23 16:40:26.900788691 +0100
@@ -411,7 +411,7 @@ monitor_child_preauth(Authctxt *_authctx
mm_get_keystate(ssh, pmonitor);
/* Drain any buffered messages from the child */
- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0)
+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
;
if (pmonitor->m_recvfd >= 0)
@@ -1678,7 +1678,7 @@ mm_answer_pty(struct ssh *ssh, int sock,
s->ptymaster = s->ptyfd;
debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd);
-
+ /* coverity[leaked_handle : FALSE] */
return (0);
error:
diff -up openssh-7.4p1/openbsd-compat/bindresvport.c.coverity openssh-7.4p1/openbsd-compat/bindresvport.c
--- openssh-7.4p1/openbsd-compat/bindresvport.c.coverity 2016-12-19 05:59:41.000000000 +0100
+++ openssh-7.4p1/openbsd-compat/bindresvport.c 2016-12-23 16:40:26.901788691 +0100
@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr
struct sockaddr_in6 *in6;
u_int16_t *portp;
u_int16_t port;
- socklen_t salen;
+ socklen_t salen = sizeof(struct sockaddr_storage);
int i;
if (sa == NULL) {
diff -up openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity openssh-8.7p1/openbsd-compat/bsd-pselect.c
--- openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity 2021-08-30 16:36:11.357288009 +0200
+++ openssh-8.7p1/openbsd-compat/bsd-pselect.c 2021-08-30 16:37:21.791897976 +0200
@@ -113,13 +113,13 @@ pselect_notify_setup(void)
static void
pselect_notify_parent(void)
{
- if (notify_pipe[1] != -1)
+ if (notify_pipe[1] >= 0)
(void)write(notify_pipe[1], "", 1);
}
static void
pselect_notify_prepare(fd_set *readset)
{
- if (notify_pipe[0] != -1)
+ if (notify_pipe[0] >= 0)
FD_SET(notify_pipe[0], readset);
}
static void
@@ -127,8 +127,8 @@ pselect_notify_done(fd_set *readset)
{
char c;
- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) {
- while (read(notify_pipe[0], &c, 1) != -1)
+ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) {
+ while (read(notify_pipe[0], &c, 1) >= 0)
debug2_f("reading");
FD_CLR(notify_pipe[0], readset);
}
diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c
--- openssh-8.5p1/readconf.c.coverity 2021-03-24 12:03:33.778968131 +0100
+++ openssh-8.5p1/readconf.c 2021-03-24 12:03:33.785968180 +0100
@@ -1847,6 +1847,7 @@ parse_pubkey_algos:
} else if (r != 0) {
error("%.200s line %d: glob failed for %s.",
filename, linenum, arg2);
+ free(arg2);
goto out;
}
free(arg2);
diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c
--- openssh-7.4p1/servconf.c.coverity 2016-12-23 16:40:26.896788690 +0100
+++ openssh-7.4p1/servconf.c 2016-12-23 16:40:26.901788691 +0100
@@ -1638,8 +1638,9 @@ process_server_config_line(ServerOptions
if (*activep && *charptr == NULL) {
*charptr = tilde_expand_filename(arg, getuid());
/* increase optional counter */
- if (intptr != NULL)
- *intptr = *intptr + 1;
+ /* DEAD CODE intptr is still NULL ;)
+ if (intptr != NULL)
+ *intptr = *intptr + 1; */
}
break;
diff -up openssh-8.7p1/serverloop.c.coverity openssh-8.7p1/serverloop.c
--- openssh-8.7p1/serverloop.c.coverity 2021-08-20 06:03:49.000000000 +0200
+++ openssh-8.7p1/serverloop.c 2021-08-30 16:28:22.416226981 +0200
@@ -547,7 +547,7 @@ server_request_tun(struct ssh *ssh)
debug_f("invalid tun");
goto done;
}
- if (auth_opts->force_tun_device != -1) {
+ if (auth_opts->force_tun_device >= 0) {
if (tun != SSH_TUNID_ANY &&
auth_opts->force_tun_device != (int)tun)
goto done;
diff -up openssh-7.4p1/ssh-agent.c.coverity openssh-7.4p1/ssh-agent.c
--- openssh-7.4p1/ssh-agent.c.coverity 2016-12-19 05:59:41.000000000 +0100
+++ openssh-7.4p1/ssh-agent.c 2016-12-23 16:40:26.903788691 +0100
@@ -869,6 +869,7 @@ sanitize_pkcs11_provider(const char *pro
if (pkcs11_uri_parse(provider, uri) != 0) {
error("Failed to parse PKCS#11 URI");
+ pkcs11_uri_cleanup(uri);
return NULL;
}
/* validate also provider from URI */
diff -up openssh-7.4p1/sshd-session.c.coverity openssh-7.4p1/sshd-session.c
--- openssh-7.4p1/sshd-session.c.coverity 2016-12-23 16:40:26.897788690 +0100
+++ openssh-7.4p1/sshd-session.c 2016-12-23 16:40:26.904788692 +0100
@@ -691,8 +691,10 @@ privsep_preauth(Authctxt *authctxt)
privsep_preauth_child(ssh);
setproctitle("%s", "[net]");
- if (box != NULL)
+ if (box != NULL) {
ssh_sandbox_child(box);
+ free(box);
+ }
return 0;
}
@@ -2519,8 +2524,11 @@ do_ssh2_kex(struct ssh *ssh)
if (newstr)
myproposal[PROPOSAL_KEX_ALGS] = newstr;
- else
+ else {
fatal("No supported key exchange algorithms");
+ free(gss);
+ }
+ /* coverity[leaked_storage: FALSE]*/
}
#endif
diff -up openssh-8.5p1/ssh-keygen.c.coverity openssh-8.5p1/ssh-keygen.c
--- openssh-8.5p1/ssh-keygen.c.coverity 2021-03-24 12:03:33.780968145 +0100
+++ openssh-8.5p1/ssh-keygen.c 2021-03-24 12:03:33.787968194 +0100
@@ -2332,6 +2332,9 @@ update_krl_from_file(struct passwd *pw,
r = ssh_krl_revoke_key_sha256(krl, blob, blen);
if (r != 0)
fatal_fr(r, "revoke key failed");
+ freezero(blob, blen);
+ blob = NULL;
+ blen = 0;
} else {
if (strncasecmp(cp, "key:", 4) == 0) {
cp += 4;

@ -0,0 +1,100 @@
diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8
--- openssh-7.2p2/sftp-server.8.sftp-force-mode 2016-03-09 19:04:48.000000000 +0100
+++ openssh-7.2p2/sftp-server.8 2016-06-23 16:18:20.463854117 +0200
@@ -38,6 +38,7 @@
.Op Fl P Ar denied_requests
.Op Fl p Ar allowed_requests
.Op Fl u Ar umask
+.Op Fl m Ar force_file_perms
.Ek
.Nm
.Fl Q Ar protocol_feature
@@ -138,6 +139,12 @@ Sets an explicit
.Xr umask 2
to be applied to newly-created files and directories, instead of the
user's default mask.
+.It Fl m Ar force_file_perms
+Sets explicit file permissions to be applied to newly-created files instead
+of the default or client requested mode. Numeric values include:
+777, 755, 750, 666, 644, 640, etc. Using both -m and -u switches makes the
+umask (-u) effective only for newly created directories and explicit mode (-m)
+for newly created files.
.El
.Pp
On some systems,
diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
--- openssh-7.2p2/sftp-server.c.sftp-force-mode 2016-06-23 16:18:20.446854128 +0200
+++ openssh-7.2p2/sftp-server.c 2016-06-23 16:20:37.950766082 +0200
@@ -69,6 +69,10 @@ struct sshbuf *oqueue;
/* Version of client */
static u_int version;
+/* Force file permissions */
+int permforce = 0;
+long permforcemode;
+
/* SSH2_FXP_INIT received */
static int init_done;
@@ -683,6 +687,7 @@ process_open(u_int32_t id)
Attrib a;
char *name;
int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE;
+ mode_t old_umask = 0;
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
(r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */
@@ -692,6 +697,10 @@ process_open(u_int32_t id)
debug3("request %u: open flags %d", id, pflags);
flags = flags_from_portable(pflags);
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
+ if (permforce == 1) { /* Force perm if -m is set */
+ mode = permforcemode;
+ old_umask = umask(0); /* so umask does not interfere */
+ }
logit("open \"%s\" flags %s mode 0%o",
name, string_from_portable(pflags), mode);
if (readonly &&
@@ -713,6 +722,8 @@ process_open(u_int32_t id)
}
}
}
+ if (permforce == 1)
+ (void) umask(old_umask); /* restore umask to something sane */
if (status != SSH2_FX_OK)
send_status(id, status);
free(name);
@@ -1494,7 +1505,7 @@ sftp_server_usage(void)
fprintf(stderr,
"usage: %s [-ehR] [-d start_directory] [-f log_facility] "
"[-l log_level]\n\t[-P denied_requests] "
- "[-p allowed_requests] [-u umask]\n"
+ "[-p allowed_requests] [-u umask] [-m force_file_perms]\n"
" %s -Q protocol_feature\n",
__progname, __progname);
exit(1);
@@ -1520,7 +1531,7 @@ sftp_server_main(int argc, char **argv,
pw = pwcopy(user_pw);
while (!skipargs && (ch = getopt(argc, argv,
- "d:f:l:P:p:Q:u:cehR")) != -1) {
+ "d:f:l:P:p:Q:u:m:cehR")) != -1) {
switch (ch) {
case 'Q':
if (strcasecmp(optarg, "requests") != 0) {
@@ -1580,6 +1591,15 @@ sftp_server_main(int argc, char **argv,
fatal("Invalid umask \"%s\"", optarg);
(void)umask((mode_t)mask);
break;
+ case 'm':
+ /* Force permissions on file received via sftp */
+ permforce = 1;
+ permforcemode = strtol(optarg, &cp, 8);
+ if (permforcemode < 0 || permforcemode > 0777 ||
+ *cp != '\0' || (permforcemode == 0 &&
+ errno != 0))
+ fatal("Invalid file mode \"%s\"", optarg);
+ break;
case 'h':
default:
sftp_server_usage();

@ -0,0 +1,12 @@
diff -up openssh/servconf.c.sshdt openssh/servconf.c
--- openssh/servconf.c.sshdt 2015-06-24 11:42:29.041078704 +0200
+++ openssh/servconf.c 2015-06-24 11:44:39.734745802 +0200
@@ -2317,7 +2317,7 @@ dump_config(ServerOptions *o)
dump_cfg_string(sXAuthLocation, o->xauth_location);
dump_cfg_string(sCiphers, o->ciphers);
dump_cfg_string(sMacs, o->macs);
- dump_cfg_string(sBanner, o->banner);
+ dump_cfg_string(sBanner, o->banner != NULL ? o->banner : "none");
dump_cfg_string(sForceCommand, o->adm_forced_command);
dump_cfg_string(sChrootDirectory, o->chroot_directory);
dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);

@ -0,0 +1,186 @@
diff -up openssh-7.4p1/monitor_wrap.c.audit-race openssh-7.4p1/monitor_wrap.c
--- openssh-7.4p1/monitor_wrap.c.audit-race 2016-12-23 16:35:52.694685771 +0100
+++ openssh-7.4p1/monitor_wrap.c 2016-12-23 16:35:52.697685772 +0100
@@ -1107,4 +1107,50 @@ mm_audit_destroy_sensitive_data(const ch
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m);
sshbuf_free(m);
}
+
+int mm_forward_audit_messages(int fdin)
+{
+ u_char buf[4];
+ u_int blen, msg_len;
+ struct sshbuf *m;
+ int r, ret = 0;
+
+ debug3_f("entering");
+ if ((m = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ do {
+ blen = atomicio(read, fdin, buf, sizeof(buf));
+ if (blen == 0) /* closed pipe */
+ break;
+ if (blen != sizeof(buf)) {
+ error_f("Failed to read the buffer from child");
+ ret = -1;
+ break;
+ }
+
+ msg_len = get_u32(buf);
+ if (msg_len > 256 * 1024)
+ fatal_f("read: bad msg_len %d", msg_len);
+ sshbuf_reset(m);
+ if ((r = sshbuf_reserve(m, msg_len, NULL)) != 0)
+ fatal_fr(r, "buffer error");
+ if (atomicio(read, fdin, sshbuf_mutable_ptr(m), msg_len) != msg_len) {
+ error_f("Failed to read the the buffer content from the child");
+ ret = -1;
+ break;
+ }
+ if (atomicio(vwrite, pmonitor->m_recvfd, buf, blen) != blen ||
+ atomicio(vwrite, pmonitor->m_recvfd, sshbuf_mutable_ptr(m), msg_len) != msg_len) {
+ error_f("Failed to write the message to the monitor");
+ ret = -1;
+ break;
+ }
+ } while (1);
+ sshbuf_free(m);
+ return ret;
+}
+void mm_set_monitor_pipe(int fd)
+{
+ pmonitor->m_recvfd = fd;
+}
#endif /* SSH_AUDIT_EVENTS */
diff -up openssh-7.4p1/monitor_wrap.h.audit-race openssh-7.4p1/monitor_wrap.h
--- openssh-7.4p1/monitor_wrap.h.audit-race 2016-12-23 16:35:52.694685771 +0100
+++ openssh-7.4p1/monitor_wrap.h 2016-12-23 16:35:52.698685772 +0100
@@ -83,6 +83,8 @@ void mm_audit_unsupported_body(int);
void mm_audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t);
void mm_audit_session_key_free_body(struct ssh *, int, pid_t, uid_t);
void mm_audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t);
+int mm_forward_audit_messages(int);
+void mm_set_monitor_pipe(int);
#endif
struct Session;
diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c
--- openssh-7.4p1/session.c.audit-race 2016-12-23 16:35:52.695685771 +0100
+++ openssh-7.4p1/session.c 2016-12-23 16:37:26.339730596 +0100
@@ -162,6 +162,10 @@ static Session *sessions = NULL;
login_cap_t *lc;
#endif
+#ifdef SSH_AUDIT_EVENTS
+int paudit[2];
+#endif
+
static int is_child = 0;
static int in_chroot = 0;
static int have_dev_log = 1;
@@ -289,6 +293,8 @@ xauth_valid_string(const char *s)
return 1;
}
+void child_destory_sensitive_data(struct ssh *ssh);
+
#define USE_PIPES 1
/*
* This is called to fork and execute a command when we have no tty. This
@@ -424,6 +430,8 @@ do_exec_no_pty(Session *s, const char *c
close(err[0]);
#endif
+ child_destory_sensitive_data(ssh);
+
/* Do processing for the child (exec command etc). */
do_child(ssh, s, command);
/* NOTREACHED */
@@ -547,6 +555,9 @@ do_exec_pty(Session *s, const char *comm
/* Close the extra descriptor for the pseudo tty. */
close(ttyfd);
+ /* Do this early, so we will not block large MOTDs */
+ child_destory_sensitive_data(ssh);
+
/* record login, etc. similar to login(1) */
#ifndef HAVE_OSF_SIA
do_login(ssh, s, command);
@@ -717,6 +728,8 @@ do_exec(Session *s, const char *command)
}
if (s->command != NULL && s->ptyfd == -1)
s->command_handle = mm_audit_run_command(ssh, s->command);
+ if (pipe(paudit) < 0)
+ fatal("pipe: %s", strerror(errno));
#endif
if (s->ttyfd != -1)
ret = do_exec_pty(ssh, s, command);
@@ -732,6 +745,20 @@ do_exec(Session *s, const char *command)
*/
sshbuf_reset(loginmsg);
+#ifdef SSH_AUDIT_EVENTS
+ close(paudit[1]);
+ if (ret == 0) {
+ /*
+ * Read the audit messages from forked child and send them
+ * back to monitor. We don't want to communicate directly,
+ * because the messages might get mixed up.
+ * Continue after the pipe gets closed (all messages sent).
+ */
+ ret = mm_forward_audit_messages(paudit[0]);
+ }
+ close(paudit[0]);
+#endif /* SSH_AUDIT_EVENTS */
+
return ret;
}
@@ -1538,6 +1565,33 @@ child_close_fds(void)
log_redirect_stderr_to(NULL);
}
+void
+child_destory_sensitive_data(struct ssh *ssh)
+{
+#ifdef SSH_AUDIT_EVENTS
+ int pparent = paudit[1];
+ close(paudit[0]);
+ /* Hack the monitor pipe to avoid race condition with parent */
+ mm_set_monitor_pipe(pparent);
+#endif
+
+ /* remove hostkey from the child's memory */
+ destroy_sensitive_data(ssh);
+ /*
+ * We can audit this, because we hacked the pipe to direct the
+ * messages over postauth child. But this message requires answer
+ * which we can't do using one-way pipe.
+ */
+ packet_destroy_all(ssh, 0, 1);
+ /* XXX this will clean the rest but should not audit anymore */
+ /* packet_clear_keys(ssh); */
+
+#ifdef SSH_AUDIT_EVENTS
+ /* Notify parent that we are done */
+ close(pparent);
+#endif
+}
+
/*
* Performs common processing for the child, such as setting up the
* environment, closing extra file descriptors, setting the user and group
@@ -1554,13 +1608,6 @@ do_child(Session *s, const char *command
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
- /* remove hostkey from the child's memory */
- destroy_sensitive_data(ssh);
- ssh_packet_clear_keys(ssh);
- /* Don't audit this - both us and the parent would be talking to the
- monitor over a single socket, with no synchronization. */
- packet_destroy_all(ssh, 0, 1);
-
/* Force a password change */
if (s->authctxt->force_pwchange) {
do_setusercontext(pw);

@ -0,0 +1,87 @@
diff --git a/auth-krb5.c b/auth-krb5.c
index 2b02a04..19b9364 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -375,5 +375,21 @@ cleanup:
return (krb5_cc_resolve(ctx, ccname, ccache));
}
}
+
+/*
+ * Reads k5login_directory option from the krb5.conf
+ */
+krb5_error_code
+ssh_krb5_get_k5login_directory(krb5_context ctx, char **k5login_directory) {
+ profile_t p;
+ int ret = 0;
+
+ ret = krb5_get_profile(ctx, &p);
+ if (ret)
+ return ret;
+
+ return profile_get_string(p, "libdefaults", "k5login_directory", NULL, NULL,
+ k5login_directory);
+}
#endif /* !HEIMDAL */
#endif /* KRB5 */
diff --git a/auth.h b/auth.h
index f9d191c..c432d2f 100644
--- a/auth.h
+++ b/auth.h
@@ -222,6 +222,8 @@ int sys_auth_passwd(Authctxt *, const char *);
#if defined(KRB5) && !defined(HEIMDAL)
krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *);
+krb5_error_code ssh_krb5_get_k5login_directory(krb5_context ctx,
+ char **k5login_directory);
#endif
#endif /* AUTH_H */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index a7c0c5f..df8cc9a 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -244,8 +244,27 @@ ssh_gssapi_k5login_exists()
{
char file[MAXPATHLEN];
struct passwd *pw = the_authctxt->pw;
+ char *k5login_directory = NULL;
+ int ret = 0;
+
+ ret = ssh_krb5_get_k5login_directory(krb_context, &k5login_directory);
+ debug3_f("k5login_directory = %s (rv=%d)", k5login_directory, ret);
+ if (k5login_directory == NULL || ret != 0) {
+ /* If not set, the library will look for k5login
+ * files in the user's home directory, with the filename .k5login.
+ */
+ snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
+ } else {
+ /* If set, the library will look for a local user's k5login file
+ * within the named directory, with a filename corresponding to the
+ * local username.
+ */
+ snprintf(file, sizeof(file), "%s%s%s", k5login_directory,
+ k5login_directory[strlen(k5login_directory)-1] != '/' ? "/" : "",
+ pw->pw_name);
+ }
+ debug_f("Checking existence of file %s", file);
- snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir);
return access(file, F_OK) == 0;
}
diff --git a/sshd.8 b/sshd.8
index 5c4f15b..135e290 100644
--- a/sshd.8
+++ b/sshd.8
@@ -806,6 +806,10 @@ rlogin/rsh.
These files enforce GSSAPI/Kerberos authentication access control.
Further details are described in
.Xr ksu 1 .
+The location of the k5login file depends on the configuration option
+.Cm k5login_directory
+in the
+.Xr krb5.conf 5 .
.Pp
.It Pa ~/.ssh/
This directory is the default location for all user-specific configuration

@ -0,0 +1,52 @@
Zseries only: Leave the hardware filedescriptors open.
All filedescriptors above 2 are getting closed when a new
sshd process to handle a new client connection is
spawned. As the process also chroot into an empty filesystem
without any device nodes, there is no chance to reopen the
files. This patch filters out the reqired fds in the
closefrom function so these are skipped in the close loop.
Author: Harald Freudenberger <freude@de.ibm.com>
---
openbsd-compat/bsd-closefrom.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
--- a/openbsd-compat/bsd-closefrom.c
+++ b/openbsd-compat/bsd-closefrom.c
@@ -82,7 +82,33 @@ closefrom(int lowfd)
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
+#ifdef __s390__
+ {
+ /*
+ * the filedescriptors used to communicate with
+ * the device drivers to provide hardware support
+ * should survive. HF <freude@de.ibm.com>
+ */
+ char fpath[PATH_MAX], lpath[PATH_MAX];
+ len = snprintf(fpath, sizeof(fpath), "%s/%s",
+ fdpath, dent->d_name);
+ if (len > 0 && (size_t)len <= sizeof(fpath)) {
+ len = readlink(fpath, lpath, sizeof(lpath));
+ if (len > 0) {
+ lpath[len] = 0;
+ if (strstr(lpath, "dev/z90crypt")
+ || strstr(lpath, "dev/zcrypt")
+ || strstr(lpath, "dev/prandom")
+ || strstr(lpath, "dev/shm/icastats"))
+ fd = -1;
+ }
+ }
+ if (fd >= 0)
+ (void) close((int) fd);
+ }
+#else
(void) close((int) fd);
+#endif
}
(void) closedir(dirp);
return;

@ -0,0 +1,55 @@
diff --git a/channels.c b/channels.c
--- a/channels.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/channels.c (date 1703026069921)
@@ -5075,11 +5075,13 @@
}
static int
-connect_local_xsocket_path(const char *pathname)
+connect_local_xsocket_path(const char *pathname, int len)
{
int sock;
struct sockaddr_un addr;
+ if (len <= 0)
+ return -1;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1) {
error("socket: %.100s", strerror(errno));
@@ -5087,11 +5089,12 @@
}
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 > 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;
}
@@ -5099,8 +5102,18 @@
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, ret;
+ 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;
}
#ifdef __APPLE__

@ -0,0 +1,213 @@
diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c
--- openssh-7.4p1/channels.c.x11max 2016-12-23 15:46:32.071506625 +0100
+++ openssh-7.4p1/channels.c 2016-12-23 15:46:32.139506636 +0100
@@ -152,8 +152,8 @@ static int all_opens_permitted = 0;
#define NUM_SOCKS 10
/* -- X11 forwarding */
-/* Maximum number of fake X11 displays to try. */
-#define MAX_DISPLAYS 1000
+/* Minimum port number for X11 forwarding */
+#define X11_PORT_MIN 6000
/* Per-channel callback for pre/post IO actions */
typedef void chan_fn(struct ssh *, Channel *c);
@@ -4228,7 +4228,7 @@ channel_send_window_changes(void)
*/
int
x11_create_display_inet(struct ssh *ssh, int x11_display_offset,
- int x11_use_localhost, int single_connection,
+ int x11_use_localhost, int x11_max_displays, int single_connection,
u_int *display_numberp, int **chanids)
{
Channel *nc = NULL;
@@ -4240,10 +4241,15 @@ x11_create_display_inet(int x11_display_
if (chanids == NULL)
return -1;
+ /* Try to bind ports starting at 6000+X11DisplayOffset */
+ x11_max_displays = x11_max_displays + x11_display_offset;
+
for (display_number = x11_display_offset;
- display_number < MAX_DISPLAYS;
+ display_number < x11_max_displays;
display_number++) {
- port = 6000 + display_number;
+ port = X11_PORT_MIN + display_number;
+ if (port < X11_PORT_MIN) /* overflow */
+ break;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE;
@@ -4295,7 +4301,7 @@ x11_create_display_inet(int x11_display_
if (num_socks > 0)
break;
}
- if (display_number >= MAX_DISPLAYS) {
+ if (display_number >= x11_max_displays || port < X11_PORT_MIN ) {
error("Failed to allocate internet-domain X11 display socket.");
return -1;
}
@@ -4441,7 +4447,7 @@ x11_connect_display(void)
memset(&hints, 0, sizeof(hints));
hints.ai_family = ssh->chanctxt->IPv4or6;
hints.ai_socktype = SOCK_STREAM;
- snprintf(strport, sizeof strport, "%u", 6000 + display_number);
+ snprintf(strport, sizeof strport, "%u", X11_PORT_MIN + display_number);
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
error("%.100s: unknown host. (%s)", buf,
ssh_gai_strerror(gaierr));
@@ -4457,7 +4463,7 @@ x11_connect_display(void)
/* Connect it to the display. */
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
debug2("connect %.100s port %u: %.100s", buf,
- 6000 + display_number, strerror(errno));
+ X11_PORT_MIN + display_number, strerror(errno));
close(sock);
continue;
}
@@ -4466,8 +4472,8 @@ x11_connect_display(void)
}
freeaddrinfo(aitop);
if (!ai) {
- error("connect %.100s port %u: %.100s", buf,
- 6000 + display_number, strerror(errno));
+ error("connect %.100s port %u: %.100s", buf,
+ X11_PORT_MIN + display_number, strerror(errno));
return -1;
}
set_nodelay(sock);
diff -up openssh-7.4p1/channels.h.x11max openssh-7.4p1/channels.h
--- openssh-7.4p1/channels.h.x11max 2016-12-19 05:59:41.000000000 +0100
+++ openssh-7.4p1/channels.h 2016-12-23 15:46:32.139506636 +0100
@@ -293,7 +293,7 @@ int permitopen_port(const char *);
void channel_set_x11_refuse_time(struct ssh *, time_t);
int x11_connect_display(struct ssh *);
-int x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **);
+int x11_create_display_inet(struct ssh *, int, int, int, int, u_int *, int **);
void x11_request_forwarding_with_spoofing(struct ssh *, int,
const char *, const char *, const char *, int);
diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c
--- openssh-7.4p1/servconf.c.x11max 2016-12-23 15:46:32.133506635 +0100
+++ openssh-7.4p1/servconf.c 2016-12-23 15:47:27.320519121 +0100
@@ -95,6 +95,7 @@ initialize_server_options(ServerOptions
options->print_lastlog = -1;
options->x11_forwarding = -1;
options->x11_display_offset = -1;
+ options->x11_max_displays = -1;
options->x11_use_localhost = -1;
options->permit_tty = -1;
options->permit_user_rc = -1;
@@ -243,6 +244,8 @@ fill_default_server_options(ServerOption
options->x11_forwarding = 0;
if (options->x11_display_offset == -1)
options->x11_display_offset = 10;
+ if (options->x11_max_displays == -1)
+ options->x11_max_displays = DEFAULT_MAX_DISPLAYS;
if (options->x11_use_localhost == -1)
options->x11_use_localhost = 1;
if (options->xauth_location == NULL)
@@ -419,7 +422,7 @@ typedef enum {
sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication,
sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
- sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
+ sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost,
sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
@@ -540,6 +543,7 @@ static struct {
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
{ "x11forwarding", sX11Forwarding, SSHCFG_ALL },
{ "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
+ { "x11maxdisplays", sX11MaxDisplays, SSHCFG_ALL },
{ "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
{ "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
@@ -1316,6 +1320,10 @@ process_server_config_line(ServerOptions
*intptr = value;
break;
+ case sX11MaxDisplays:
+ intptr = &options->x11_max_displays;
+ goto parse_int;
+
case sX11UseLocalhost:
intptr = &options->x11_use_localhost;
goto parse_flag;
@@ -2063,6 +2071,7 @@ copy_set_server_options(ServerOptions *d
M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
M_CP_INTOPT(x11_display_offset);
M_CP_INTOPT(x11_forwarding);
+ M_CP_INTOPT(x11_max_displays);
M_CP_INTOPT(x11_use_localhost);
M_CP_INTOPT(permit_tty);
M_CP_INTOPT(permit_user_rc);
@@ -2315,6 +2324,7 @@ dump_config(ServerOptions *o)
#endif
dump_cfg_int(sLoginGraceTime, o->login_grace_time);
dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
+ dump_cfg_int(sX11MaxDisplays, o->x11_max_displays);
dump_cfg_int(sMaxAuthTries, o->max_authtries);
dump_cfg_int(sMaxSessions, o->max_sessions);
dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
diff -up openssh-7.4p1/servconf.h.x11max openssh-7.4p1/servconf.h
--- openssh-7.4p1/servconf.h.x11max 2016-12-23 15:46:32.133506635 +0100
+++ openssh-7.4p1/servconf.h 2016-12-23 15:46:32.140506636 +0100
@@ -55,6 +55,7 @@
#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */
#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */
+#define DEFAULT_MAX_DISPLAYS 1000 /* Maximum number of fake X11 displays to try. */
/* Magic name for internal sftp-server */
#define INTERNAL_SFTP_NAME "internal-sftp"
@@ -85,6 +86,7 @@ typedef struct {
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start
* searching at */
+ int x11_max_displays; /* Number of displays to search */
int x11_use_localhost; /* If true, use localhost for fake X11 server. */
char *xauth_location; /* Location of xauth program */
int permit_tty; /* If false, deny pty allocation */
diff -up openssh-7.4p1/session.c.x11max openssh-7.4p1/session.c
--- openssh-7.4p1/session.c.x11max 2016-12-23 15:46:32.136506636 +0100
+++ openssh-7.4p1/session.c 2016-12-23 15:46:32.141506636 +0100
@@ -2518,8 +2518,9 @@ session_setup_x11fwd(Session *s)
return 0;
}
if (x11_create_display_inet(ssh, options.x11_display_offset,
- options.x11_use_localhost, s->single_connection,
- &s->display_number, &s->x11_chanids) == -1) {
+ options.x11_use_localhost, options.x11_max_displays,
+ s->single_connection, &s->display_number,
+ &s->x11_chanids) == -1) {
debug("x11_create_display_inet failed.");
return 0;
}
diff -up openssh-7.4p1/sshd_config.5.x11max openssh-7.4p1/sshd_config.5
--- openssh-7.4p1/sshd_config.5.x11max 2016-12-23 15:46:32.134506635 +0100
+++ openssh-7.4p1/sshd_config.5 2016-12-23 15:46:32.141506636 +0100
@@ -1133,6 +1133,7 @@ Available keywords are
.Cm TrustedUserCAKeys ,
.Cm UnusedConnectionTimeout ,
.Cm X11DisplayOffset ,
+.Cm X11MaxDisplays ,
.Cm X11Forwarding
and
.Cm X11UseLocalhost .
@@ -1566,6 +1567,12 @@ Specifies the first display number avail
X11 forwarding.
This prevents sshd from interfering with real X11 servers.
The default is 10.
+.It Cm X11MaxDisplays
+Specifies the maximum number of displays available for
+.Xr sshd 8 Ns 's
+X11 forwarding.
+This prevents sshd from exhausting local ports.
+The default is 1000.
.It Cm X11Forwarding
Specifies whether X11 forwarding is permitted.
The argument must be

@ -0,0 +1,86 @@
In order to use the OpenSSL-ibmpkcs11 engine it is needed to allow flock
and ipc calls, because this engine calls OpenCryptoki (a PKCS#11
implementation) which calls the libraries that will communicate with the
crypto cards. OpenCryptoki makes use of flock and ipc and, as of now,
this is only need on s390 architecture.
Signed-off-by: Eduardo Barretto <ebarretto@xxxxxxxxxxxxxxxxxx>
---
sandbox-seccomp-filter.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c
index ca75cc7..6e7de31 100644
--- a/sandbox-seccomp-filter.c
+++ b/sandbox-seccomp-filter.c
@@ -166,6 +166,9 @@ static const struct sock_filter preauth_insns[] = {
#ifdef __NR_exit_group
SC_ALLOW(__NR_exit_group),
#endif
+#if defined(__NR_flock) && defined(__s390__)
+ SC_ALLOW(__NR_flock),
+#endif
#ifdef __NR_futex
SC_FUTEX(__NR_futex),
#endif
@@ -178,6 +181,9 @@ static const struct sock_filter preauth_insns[] = {
#ifdef __NR_gettimeofday
SC_ALLOW(__NR_gettimeofday),
#endif
+#if defined(__NR_ipc) && defined(__s390__)
+ SC_ALLOW(__NR_ipc),
+#endif
#ifdef __NR_getuid
SC_ALLOW(__NR_getuid),
#endif
--
1.9.1
getuid and geteuid are needed when using an openssl engine that calls a
crypto card, e.g. ICA (libica).
Those syscalls are also needed by the distros for audit code.
Signed-off-by: Eduardo Barretto <ebarretto@xxxxxxxxxxxxxxxxxx>
---
sandbox-seccomp-filter.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c
index 6e7de31..e86aa2c 100644
--- a/sandbox-seccomp-filter.c
+++ b/sandbox-seccomp-filter.c
@@ -175,6 +175,18 @@ static const struct sock_filter preauth_insns[] = {
#ifdef __NR_getpid
SC_ALLOW(__NR_getpid),
#endif
+#ifdef __NR_getuid
+ SC_ALLOW(__NR_getuid),
+#endif
+#ifdef __NR_getuid32
+ SC_ALLOW(__NR_getuid32),
+#endif
+#ifdef __NR_geteuid
+ SC_ALLOW(__NR_geteuid),
+#endif
+#ifdef __NR_geteuid32
+ SC_ALLOW(__NR_geteuid32),
+#endif
#ifdef __NR_getrandom
SC_ALLOW(__NR_getrandom),
#endif
-- 1.9.1
1.9.1
diff -up openssh-7.6p1/sandbox-seccomp-filter.c.sandbox openssh-7.6p1/sandbox-seccomp-filter.c
--- openssh-7.6p1/sandbox-seccomp-filter.c.sandbox 2017-12-12 13:59:30.563874059 +0100
+++ openssh-7.6p1/sandbox-seccomp-filter.c 2017-12-12 13:59:14.842784083 +0100
@@ -190,6 +190,9 @@ static const struct sock_filter preauth_
#ifdef __NR_geteuid32
SC_ALLOW(__NR_geteuid32),
#endif
+#ifdef __NR_gettid
+ SC_ALLOW(__NR_gettid),
+#endif
#ifdef __NR_getrandom
SC_ALLOW(__NR_getrandom),
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,271 @@
diff -up openssh/auth2-pubkey.c.refactor openssh/auth2-pubkey.c
--- openssh/auth2-pubkey.c.refactor 2019-04-04 13:19:12.188821236 +0200
+++ openssh/auth2-pubkey.c 2019-04-04 13:19:12.276822078 +0200
@@ -72,6 +72,8 @@
/* import */
extern ServerOptions options;
+extern int inetd_flag;
+extern Authctxt *the_authctxt;
extern struct authmethod_cfg methodcfg_pubkey;
static char *
@@ -511,7 +514,8 @@ match_principals_command(struct ssh *ssh
if ((pid = subprocess("AuthorizedPrincipalsCommand", command,
ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD,
- runas_pw, temporarily_use_uid, restore_uid)) == 0)
+ runas_pw, temporarily_use_uid, restore_uid,
+ inetd_flag, the_authctxt)) == 0)
goto out;
uid_swapped = 1;
@@ -981,7 +985,8 @@ user_key_command_allowed2(struct ssh *ss
if ((pid = subprocess("AuthorizedKeysCommand", command,
ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD,
- runas_pw, temporarily_use_uid, restore_uid)) == 0)
+ runas_pw, temporarily_use_uid, restore_uid,
+ inetd_flag, the_authctxt)) == 0)
goto out;
uid_swapped = 1;
diff -up openssh/misc.c.refactor openssh/misc.c
--- openssh/misc.c.refactor 2019-04-04 13:19:12.235821686 +0200
+++ openssh/misc.c 2019-04-04 13:19:12.276822078 +0200
@@ -756,7 +756,8 @@ auth_get_canonical_hostname(struct ssh *
pid_t
subprocess(const char *tag, const char *command,
int ac, char **av, FILE **child, u_int flags,
- struct passwd *pw, privdrop_fn *drop_privs, privrestore_fn *restore_privs)
+ struct passwd *pw, privdrop_fn *drop_privs,
+ privrestore_fn *restore_privs, int inetd, void *the_authctxt)
{
FILE *f = NULL;
struct stat st;
@@ -872,7 +873,7 @@ subprocess(const char *tag, struct passw
_exit(1);
}
#ifdef WITH_SELINUX
- if (sshd_selinux_setup_env_variables() < 0) {
+ if (sshd_selinux_setup_env_variables(inetd, the_authctxt) < 0) {
error ("failed to copy environment: %s",
strerror(errno));
_exit(127);
diff -up openssh/misc.h.refactor openssh/misc.h
--- openssh/misc.h.refactor 2019-04-04 13:19:12.251821839 +0200
+++ openssh/misc.h 2019-04-04 13:19:12.276822078 +0200
@@ -235,7 +235,7 @@ struct passwd *fakepw(void);
#define SSH_SUBPROCESS_UNSAFE_PATH (1<<3) /* Don't check for safe cmd */
#define SSH_SUBPROCESS_PRESERVE_ENV (1<<4) /* Keep parent environment */
pid_t subprocess(const char *, const char *, int, char **, FILE **, u_int,
- struct passwd *, privdrop_fn *, privrestore_fn *);
+ struct passwd *, privdrop_fn *, privrestore_fn *, int, void *);
typedef struct arglist arglist;
struct arglist {
diff -up openssh/openbsd-compat/port-linux.h.refactor openssh/openbsd-compat/port-linux.h
--- openssh/openbsd-compat/port-linux.h.refactor 2019-04-04 13:19:12.256821887 +0200
+++ openssh/openbsd-compat/port-linux.h 2019-04-04 13:19:12.276822078 +0200
@@ -26,8 +26,8 @@ void ssh_selinux_setfscreatecon(const ch
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);
+void sshd_selinux_setup_exec_context(char *, int, int(char *, const char *), void *, int);
+int sshd_selinux_setup_env_variables(int inetd, void *);
void sshd_selinux_change_privsep_preauth_context(void);
#endif
diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compat/port-linux-sshd.c
--- openssh/openbsd-compat/port-linux-sshd.c.refactor 2019-04-04 13:19:12.256821887 +0200
+++ openssh/openbsd-compat/port-linux-sshd.c 2019-04-04 13:19:12.276822078 +0200
@@ -49,10 +49,6 @@
#include <unistd.h>
#endif
-extern ServerOptions options;
-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)
@@ -223,7 +218,8 @@ get_user_context(const char *sename, con
}
static void
-ssh_selinux_get_role_level(char **role, const char **level)
+ssh_selinux_get_role_level(char **role, const char **level,
+ Authctxt *the_authctxt)
{
*role = NULL;
*level = NULL;
@@ -241,8 +237,8 @@ ssh_selinux_get_role_level(char **role,
/* Return the default security context for the given username */
static int
-sshd_selinux_getctxbyname(char *pwname,
- security_context_t *default_sc, security_context_t *user_sc)
+sshd_selinux_getctxbyname(char *pwname, security_context_t *default_sc,
+ security_context_t *user_sc, int inetd, Authctxt *the_authctxt)
{
char *sename, *lvl;
char *role;
@@ -250,7 +246,7 @@ sshd_selinux_getctxbyname(char *pwname,
int r = 0;
context_t con = NULL;
- ssh_selinux_get_role_level(&role, &reqlvl);
+ ssh_selinux_get_role_level(&role, &reqlvl, the_authctxt);
#ifdef HAVE_GETSEUSERBYNAME
if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) {
@@ -272,7 +268,7 @@ sshd_selinux_getctxbyname(char *pwname,
if (r == 0) {
/* If launched from xinetd, we must use current level */
- if (inetd_flag) {
+ if (inetd) {
security_context_t sshdsc=NULL;
if (getcon_raw(&sshdsc) < 0)
@@ -333,7 +329,8 @@ sshd_selinux_getctxbyname(char *pwname,
/* Setup environment variables for pam_selinux */
static int
-sshd_selinux_setup_variables(int(*set_it)(char *, const char *))
+sshd_selinux_setup_variables(int(*set_it)(char *, const char *), int inetd,
+ Authctxt *the_authctxt)
{
const char *reqlvl;
char *role;
@@ -342,11 +339,11 @@ sshd_selinux_setup_variables(int(*set_it
debug3_f("setting execution context");
- ssh_selinux_get_role_level(&role, &reqlvl);
+ ssh_selinux_get_role_level(&role, &reqlvl, the_authctxt);
rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : "");
- if (inetd_flag) {
+ if (inetd) {
use_current = "1";
} else {
use_current = "";
@@ -362,9 +359,10 @@ sshd_selinux_setup_variables(int(*set_it
}
static int
-sshd_selinux_setup_pam_variables(void)
+sshd_selinux_setup_pam_variables(int inetd,
+ int(pam_setenv)(char *, const char *), Authctxt *the_authctxt)
{
- return sshd_selinux_setup_variables(do_pam_putenv);
+ return sshd_selinux_setup_variables(pam_setenv, inetd, the_authctxt);
}
static int
@@ -374,25 +372,28 @@ do_setenv(char *name, const char *value)
}
int
-sshd_selinux_setup_env_variables(void)
+sshd_selinux_setup_env_variables(int inetd, void *the_authctxt)
{
- return sshd_selinux_setup_variables(do_setenv);
+ Authctxt *authctxt = (Authctxt *) the_authctxt;
+ return sshd_selinux_setup_variables(do_setenv, inetd, authctxt);
}
/* Set the execution context to the default for the specified user */
void
-sshd_selinux_setup_exec_context(char *pwname)
+sshd_selinux_setup_exec_context(char *pwname, int inetd,
+ int(pam_setenv)(char *, const char *), void *the_authctxt, int use_pam)
{
security_context_t user_ctx = NULL;
int r = 0;
security_context_t default_ctx = NULL;
+ Authctxt *authctxt = (Authctxt *) the_authctxt;
if (!sshd_selinux_enabled())
return;
- if (options.use_pam) {
+ if (use_pam) {
/* do not compute context, just setup environment for pam_selinux */
- if (sshd_selinux_setup_pam_variables()) {
+ if (sshd_selinux_setup_pam_variables(inetd, pam_setenv, authctxt)) {
switch (security_getenforce()) {
case -1:
fatal_f("security_getenforce() failed");
@@ -410,7 +411,7 @@ sshd_selinux_setup_exec_context(char *pw
debug3_f("setting execution context");
- r = sshd_selinux_getctxbyname(pwname, &default_ctx, &user_ctx);
+ r = sshd_selinux_getctxbyname(pwname, &default_ctx, &user_ctx, inetd, authctxt);
if (r >= 0) {
r = setexeccon(user_ctx);
if (r < 0) {
diff -up openssh/platform.c.refactor openssh/platform.c
--- openssh/platform.c.refactor 2019-04-04 13:19:12.204821389 +0200
+++ openssh/platform.c 2019-04-04 13:19:12.277822088 +0200
@@ -32,6 +32,8 @@
#include "openbsd-compat/openbsd-compat.h"
extern ServerOptions options;
+extern int inetd_flag;
+extern Authctxt *the_authctxt;
/* return 1 if we are running with privilege to swap UIDs, 0 otherwise */
int
@@ -183,7 +186,9 @@ platform_setusercontext_post_groups(stru
}
#endif /* HAVE_SETPCRED */
#ifdef WITH_SELINUX
- sshd_selinux_setup_exec_context(pw->pw_name);
+ sshd_selinux_setup_exec_context(pw->pw_name,
+ inetd_flag, do_pam_putenv, the_authctxt,
+ options.use_pam);
#endif
}
diff -up openssh/sshd-session.c.refactor openssh/sshd-session.c
--- openssh/sshd-session.c.refactor 2019-04-04 13:19:12.275822068 +0200
+++ openssh/sshd-session.c 2019-04-04 13:19:51.270195262 +0200
@@ -158,7 +158,7 @@ int debug_flag = 0;
int debug_flag = 0;
/* Flag indicating that the daemon is being started from inetd. */
-static int inetd_flag = 0;
+int inetd_flag = 0;
/* debug goes to stderr unless inetd_flag is set */
static int log_stderr = 0;
@@ -2192,7 +2192,9 @@ main(int ac, char **av)
}
#endif
#ifdef WITH_SELINUX
- sshd_selinux_setup_exec_context(authctxt->pw->pw_name);
+ sshd_selinux_setup_exec_context(authctxt->pw->pw_name,
+ inetd_flag, do_pam_putenv, the_authctxt,
+ options.use_pam);
#endif
#ifdef USE_PAM
if (options.use_pam) {
diff -up openssh/sshconnect.c.refactor openssh/sshconnect.c
--- openssh/sshconnect.c.refactor 2021-02-24 00:12:03.065325046 +0100
+++ openssh/sshconnect.c 2021-02-24 00:12:12.126449544 +0100
@@ -892,7 +892,7 @@ load_hostkeys_command(struct hostkeys *h
if ((pid = subprocess(tag, command, ac, av, &f,
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH|
- SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL)) == 0)
+ SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL, 0, NULL)) == 0)
goto out;
load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1);

@ -0,0 +1,766 @@
diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/dh.c
--- openssh-8.6p1/dh.c.fips 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/dh.c 2021-05-06 12:12:10.107634472 +0200
@@ -36,6 +36,7 @@
#include <openssl/bn.h>
#include <openssl/dh.h>
+#include <openssl/fips.h>
#include "dh.h"
#include "pathnames.h"
@@ -164,6 +164,12 @@ choose_dh(int min, int wantbits, int max
int best, bestcount, which, linenum;
struct dhgroup dhg;
+ if (FIPS_mode()) {
+ verbose("Using arbitrary primes is not allowed in FIPS mode."
+ " Falling back to known groups.");
+ return (dh_new_group_fallback(max));
+ }
+
if ((f = fopen(get_moduli_filename(), "r")) == NULL) {
logit("WARNING: could not open %s (%s), using fixed modulus",
get_moduli_filename(), strerror(errno));
@@ -502,4 +508,38 @@ dh_estimate(int bits)
return 8192;
}
+/*
+ * Compares the received DH parameters with known-good groups,
+ * which might be either from group14, group16 or group18.
+ */
+int
+dh_is_known_group(const DH *dh)
+{
+ const BIGNUM *p, *g;
+ const BIGNUM *known_p, *known_g;
+ DH *known = NULL;
+ int bits = 0, rv = 0;
+
+ DH_get0_pqg(dh, &p, NULL, &g);
+ bits = BN_num_bits(p);
+
+ if (bits <= 3072) {
+ known = dh_new_group14();
+ } else if (bits <= 6144) {
+ known = dh_new_group16();
+ } else {
+ known = dh_new_group18();
+ }
+
+ DH_get0_pqg(known, &known_p, NULL, &known_g);
+
+ if (BN_cmp(g, known_g) == 0 &&
+ BN_cmp(p, known_p) == 0) {
+ rv = 1;
+ }
+
+ DH_free(known);
+ return rv;
+}
+
#endif /* WITH_OPENSSL */
diff -up openssh-8.6p1/dh.h.fips openssh-8.6p1/dh.h
--- openssh-8.6p1/dh.h.fips 2021-05-06 12:08:36.498926877 +0200
+++ openssh-8.6p1/dh.h 2021-05-06 12:11:28.393298005 +0200
@@ -45,6 +45,7 @@ DH *dh_new_group_fallback(int);
int dh_gen_key(DH *, int);
int dh_pub_is_valid(const DH *, const BIGNUM *);
+int dh_is_known_group(const DH *);
u_int dh_estimate(int);
void dh_set_moduli_file(const char *);
diff -up openssh-8.6p1/kex-names.c.fips openssh-8.6p1/kex-names.c
--- openssh-8.6p1/kex-names.c.fips 2021-05-06 12:08:36.489926807 +0200
+++ openssh-8.6p1/kex-names.c 2021-05-06 12:08:36.498926877 +0200
@@ -39,6 +39,7 @@
#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
+#include <openssl/fips.h>
#include <openssl/evp.h>
#endif
@@ -203,7 +203,10 @@ kex_names_valid(const char *names)
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
if (kex_alg_by_name(p) == NULL) {
- error("Unsupported KEX algorithm \"%.100s\"", p);
+ if (FIPS_mode())
+ error("\"%.100s\" is not allowed in FIPS mode", p);
+ else
+ error("Unsupported KEX algorithm \"%.100s\"", p);
free(s);
return 0;
}
diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c
--- openssh-8.6p1/kexgexc.c.fips 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/kexgexc.c 2021-05-06 12:08:36.498926877 +0200
@@ -28,6 +28,7 @@
#ifdef WITH_OPENSSL
+#include <openssl/fips.h>
#include <sys/types.h>
#include <openssl/dh.h>
@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
+ if (FIPS_mode() && dh_is_known_group(kex->dh) == 0) {
+ r = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
p = g = NULL; /* belong to kex->dh now */
/* generate and send 'e', client DH public key */
diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h
--- openssh-8.6p1/myproposal.h.fips 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/myproposal.h 2021-05-06 12:08:36.498926877 +0200
@@ -57,6 +57,18 @@
"rsa-sha2-512," \
"rsa-sha2-256"
+#define KEX_FIPS_PK_ALG \
+ "ecdsa-sha2-nistp256-cert-v01@openssh.com," \
+ "ecdsa-sha2-nistp384-cert-v01@openssh.com," \
+ "ecdsa-sha2-nistp521-cert-v01@openssh.com," \
+ "rsa-sha2-512-cert-v01@openssh.com," \
+ "rsa-sha2-256-cert-v01@openssh.com," \
+ "ecdsa-sha2-nistp256," \
+ "ecdsa-sha2-nistp384," \
+ "ecdsa-sha2-nistp521," \
+ "rsa-sha2-512," \
+ "rsa-sha2-256"
+
#define KEX_SERVER_ENCRYPT \
"chacha20-poly1305@openssh.com," \
"aes128-ctr,aes192-ctr,aes256-ctr," \
@@ -78,6 +92,27 @@
#define KEX_CLIENT_MAC KEX_SERVER_MAC
+#define KEX_FIPS_ENCRYPT \
+ "aes128-ctr,aes192-ctr,aes256-ctr," \
+ "aes128-cbc,3des-cbc," \
+ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \
+ "aes128-gcm@openssh.com,aes256-gcm@openssh.com"
+#define KEX_DEFAULT_KEX_FIPS \
+ "ecdh-sha2-nistp256," \
+ "ecdh-sha2-nistp384," \
+ "ecdh-sha2-nistp521," \
+ "diffie-hellman-group-exchange-sha256," \
+ "diffie-hellman-group16-sha512," \
+ "diffie-hellman-group18-sha512," \
+ "diffie-hellman-group14-sha256"
+#define KEX_FIPS_MAC \
+ "hmac-sha1," \
+ "hmac-sha2-256," \
+ "hmac-sha2-512," \
+ "hmac-sha1-etm@openssh.com," \
+ "hmac-sha2-256-etm@openssh.com," \
+ "hmac-sha2-512-etm@openssh.com"
+
/* Not a KEX value, but here so all the algorithm defaults are together */
#define SSH_ALLOWED_CA_SIGALGS \
"ssh-ed25519," \
diff -up openssh-8.6p1/readconf.c.fips openssh-8.6p1/readconf.c
--- openssh-8.6p1/readconf.c.fips 2021-05-06 12:08:36.428926336 +0200
+++ openssh-8.6p1/readconf.c 2021-05-06 12:08:36.499926885 +0200
@@ -39,6 +39,7 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
+#include <openssl/fips.h>
#ifdef USE_SYSTEM_GLOB
# include <glob.h>
#else
@@ -2538,11 +2538,16 @@ fill_default_options(Options * options)
all_key = sshkey_alg_list(0, 0, 1, ',');
all_sig = sshkey_alg_list(0, 1, 1, ',');
/* remove unsupported algos from default lists */
- def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher);
- def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac);
- def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex);
- def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
- def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
+ def_cipher = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_ENCRYPT : KEX_CLIENT_ENCRYPT), all_cipher);
+ def_mac = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_MAC : KEX_CLIENT_MAC), all_mac);
+ def_kex = match_filter_allowlist((FIPS_mode() ?
+ KEX_DEFAULT_KEX_FIPS : KEX_CLIENT_KEX), all_kex);
+ def_key = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), all_key);
+ def_sig = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig);
#define ASSEMBLE(what, defaults, all) \
do { \
if ((r = kex_assemble_names(&options->what, \
diff -up openssh-8.6p1/sandbox-seccomp-filter.c.fips openssh-8.6p1/sandbox-seccomp-filter.c
--- openssh-8.6p1/sandbox-seccomp-filter.c.fips 2021-05-06 12:08:36.463926606 +0200
+++ openssh-8.6p1/sandbox-seccomp-filter.c 2021-05-06 12:08:36.499926885 +0200
@@ -160,6 +160,9 @@ static const struct sock_filter preauth_
#ifdef __NR_open
SC_DENY(__NR_open, EACCES),
#endif
+#ifdef __NR_socket
+ SC_DENY(__NR_socket, EACCES),
+#endif
#ifdef __NR_openat
SC_DENY(__NR_openat, EACCES),
#endif
diff -up openssh-8.6p1/servconf.c.fips openssh-8.6p1/servconf.c
--- openssh-8.6p1/servconf.c.fips 2021-05-06 12:08:36.455926545 +0200
+++ openssh-8.6p1/servconf.c 2021-05-06 12:08:36.500926893 +0200
@@ -38,6 +38,7 @@
#include <limits.h>
#include <stdarg.h>
#include <errno.h>
+#include <openssl/fips.h>
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
@@ -226,11 +226,16 @@ assemble_algorithms(ServerOptions *o)
all_key = sshkey_alg_list(0, 0, 1, ',');
all_sig = sshkey_alg_list(0, 1, 1, ',');
/* remove unsupported algos from default lists */
- def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher);
- def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac);
- def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex);
- def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key);
- def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig);
+ def_cipher = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_ENCRYPT : KEX_SERVER_ENCRYPT), all_cipher);
+ def_mac = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_MAC : KEX_SERVER_MAC), all_mac);
+ def_kex = match_filter_allowlist((FIPS_mode() ?
+ KEX_DEFAULT_KEX_FIPS : KEX_SERVER_KEX), all_kex);
+ def_key = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), all_key);
+ def_sig = match_filter_allowlist((FIPS_mode() ?
+ KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig);
#define ASSEMBLE(what, defaults, all) \
do { \
if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \
diff -up openssh-8.6p1/ssh.c.fips openssh-8.6p1/ssh.c
--- openssh-8.6p1/ssh.c.fips 2021-05-06 12:08:36.467926637 +0200
+++ openssh-8.6p1/ssh.c 2021-05-06 12:08:36.500926893 +0200
@@ -77,6 +77,7 @@
#include <openssl/evp.h>
#include <openssl/err.h>
#endif
+#include <openssl/fips.h>
#include "openbsd-compat/openssl-compat.h"
#include "openbsd-compat/sys-queue.h"
@@ -1516,6 +1517,10 @@ main(int ac, char **av)
exit(0);
}
+ if (FIPS_mode()) {
+ debug("FIPS mode initialized");
+ }
+
/* Expand SecurityKeyProvider if it refers to an environment variable */
if (options.sk_provider != NULL && *options.sk_provider == '$' &&
strlen(options.sk_provider) > 1) {
diff -up openssh-8.6p1/sshconnect2.c.fips openssh-8.6p1/sshconnect2.c
--- openssh-8.6p1/sshconnect2.c.fips 2021-05-06 12:08:36.485926777 +0200
+++ openssh-8.6p1/sshconnect2.c 2021-05-06 12:08:36.501926900 +0200
@@ -45,6 +45,8 @@
#include <vis.h>
#endif
+#include <openssl/fips.h>
+
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
@@ -269,36 +271,41 @@ ssh_kex2(struct ssh *ssh, char *host, st
#if defined(GSSAPI) && defined(WITH_OPENSSL)
if (options.gss_keyex) {
- /* Add the GSSAPI mechanisms currently supported on this
- * client to the key exchange algorithm proposal */
- orig = myproposal[PROPOSAL_KEX_ALGS];
-
- if (options.gss_server_identity) {
- gss_host = xstrdup(options.gss_server_identity);
- } else if (options.gss_trust_dns) {
- gss_host = remote_hostname(ssh);
- /* Fall back to specified host if we are using proxy command
- * and can not use DNS on that socket */
- if (strcmp(gss_host, "UNKNOWN") == 0) {
- free(gss_host);
+ if (FIPS_mode()) {
+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode");
+ options.gss_keyex = 0;
+ } else {
+ /* Add the GSSAPI mechanisms currently supported on this
+ * client to the key exchange algorithm proposal */
+ orig = myproposal[PROPOSAL_KEX_ALGS];
+
+ if (options.gss_server_identity) {
+ gss_host = xstrdup(options.gss_server_identity);
+ } else if (options.gss_trust_dns) {
+ gss_host = remote_hostname(ssh);
+ /* Fall back to specified host if we are using proxy command
+ * and can not use DNS on that socket */
+ if (strcmp(gss_host, "UNKNOWN") == 0) {
+ free(gss_host);
+ gss_host = xstrdup(host);
+ }
+ } else {
gss_host = xstrdup(host);
}
- } else {
- gss_host = xstrdup(host);
- }
- gss = ssh_gssapi_client_mechanisms(gss_host,
- options.gss_client_identity, options.gss_kex_algorithms);
- if (gss) {
- debug("Offering GSSAPI proposal: %s", gss);
- xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
- "%s,%s", gss, orig);
-
- /* If we've got GSSAPI algorithms, then we also support the
- * 'null' hostkey, as a last resort */
- orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
- xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
- "%s,null", orig);
+ gss = ssh_gssapi_client_mechanisms(gss_host,
+ options.gss_client_identity, options.gss_kex_algorithms);
+ if (gss) {
+ debug("Offering GSSAPI proposal: %s", gss);
+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
+ "%s,%s", gss, orig);
+
+ /* If we've got GSSAPI algorithms, then we also support the
+ * 'null' hostkey, as a last resort */
+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
+ "%s,null", orig);
+ }
}
}
#endif
diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c
--- openssh-8.6p1/sshd.c.fips 2021-05-06 12:08:36.493926838 +0200
+++ openssh-8.6p1/sshd.c 2021-05-06 12:13:56.501492639 +0200
@@ -66,6 +66,7 @@
#endif
#include <pwd.h>
#include <signal.h>
+#include <syslog.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -77,6 +78,7 @@
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
#include <openssl/rand.h>
+#include <openssl/fips.h>
#include "openbsd-compat/openssl-compat.h"
#endif
@@ -1931,6 +1931,13 @@ main(int ac, char **av)
&key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
do_log2_r(r, ll, "Unable to load host key \"%s\"",
options.host_key_files[i]);
+ if (FIPS_mode() && key != NULL && (sshkey_type_plain(key->type) == KEY_ED25519_SK
+ || sshkey_type_plain(key->type) == KEY_ED25519)) {
+ logit_f("sshd: Ed25519 keys are not allowed in FIPS mode, skipping %s", options.host_key_files[i]);
+ sshkey_free(key);
+ key = NULL;
+ continue;
+ }
if (sshkey_is_sk(key) &&
key->sk_flags & SSH_SK_USER_PRESENCE_REQD) {
debug("host key %s requires user presence, ignoring",
@@ -2110,6 +2113,10 @@ main(int ac, char **av)
/* Reinitialize the log (because of the fork above). */
log_init(__progname, options.log_level, options.log_facility, log_stderr);
+ if (FIPS_mode()) {
+ debug("FIPS mode initialized");
+ }
+
/*
* Chdir to the root directory so that the current disk can be
* unmounted if desired.
diff -up openssh-8.6p1/sshd-session.c.fips openssh-8.6p1/sshd-session.c
--- a/sshd-session.c.fips 2021-05-06 12:08:36.493926838 +0200
+++ b/sshd-session.c 2021-05-06 12:13:56.501492639 +0200
@@ -78,6 +79,7 @@
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
+#include <openssl/fips.h>
#include "openbsd-compat/openssl-compat.h"
#endif
@@ -2506,10 +2513,14 @@ do_ssh2_kex(struct ssh *ssh)
if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
orig = NULL;
- if (options.gss_keyex)
- gss = ssh_gssapi_server_mechanisms();
- else
- gss = NULL;
+ if (options.gss_keyex) {
+ if (FIPS_mode()) {
+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode");
+ options.gss_keyex = 0;
+ } else {
+ gss = ssh_gssapi_server_mechanisms();
+ }
+ }
if (gss && orig)
xasprintf(&newstr, "%s,%s", gss, orig);
diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c
--- openssh-8.6p1/sshkey.c.fips 2021-05-06 12:08:36.493926838 +0200
+++ openssh-8.6p1/sshkey.c 2021-05-06 12:08:36.502926908 +0200
@@ -36,6 +36,7 @@
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/pem.h>
+#include <openssl/fips.h>
#endif
#include "crypto_api.h"
@@ -57,6 +58,7 @@
#define SSHKEY_INTERNAL
#include "sshkey.h"
#include "match.h"
+#include "log.h"
#include "ssh-sk.h"
#ifdef WITH_XMSS
@@ -285,6 +285,18 @@ sshkey_alg_list(int certs_only, int plai
impl = keyimpls[i];
if (impl->name == NULL || impl->type == KEY_NULL)
continue;
+ if (FIPS_mode()) {
+ switch (impl->type) {
+ case KEY_ED25519:
+ case KEY_ED25519_SK:
+ case KEY_ED25519_CERT:
+ case KEY_ED25519_SK_CERT:
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
if (!include_sigonly && impl->sigonly)
continue;
if ((certs_only && !impl->cert) || (plain_only && impl->cert))
@@ -1503,6 +1503,20 @@ sshkey_read(struct sshkey *ret, char **c
return SSH_ERR_EC_CURVE_MISMATCH;
}
+ switch (type) {
+ case KEY_ED25519:
+ case KEY_ED25519_SK:
+ case KEY_ED25519_CERT:
+ case KEY_ED25519_SK_CERT:
+ if (FIPS_mode()) {
+ sshkey_free(k);
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
+ break;
+ default:
+ break;
+ }
/* Fill in ret from parsed key */
sshkey_free_contents(ret);
*ret = *k;
@@ -2916,6 +2916,11 @@ sshkey_sign(struct sshkey *key,
*lenp = 0;
if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
return SSH_ERR_INVALID_ARGUMENT;
+ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
+ /* Fallthrough */
if ((impl = sshkey_impl_from_key(key)) == NULL)
return SSH_ERR_KEY_TYPE_UNKNOWN;
if ((r = sshkey_unshield_private(key)) != 0)
@@ -2973,6 +2978,10 @@ sshkey_verify(const struct sshkey *key,
*detailsp = NULL;
if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
return SSH_ERR_INVALID_ARGUMENT;
+ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
if ((impl = sshkey_impl_from_key(key)) == NULL)
return SSH_ERR_KEY_TYPE_UNKNOWN;
return impl->funcs->verify(key, sig, siglen, data, dlen,
diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c
--- openssh-8.6p1/ssh-keygen.c.fips 2021-05-06 12:08:36.467926637 +0200
+++ openssh-8.6p1/ssh-keygen.c 2021-05-06 12:08:36.503926916 +0200
@@ -20,6 +20,7 @@
#ifdef WITH_OPENSSL
#include <openssl/evp.h>
+#include <openssl/fips.h>
#include <openssl/pem.h>
#include "openbsd-compat/openssl-compat.h"
#endif
@@ -69,6 +69,7 @@
#include "cipher.h"
#define DEFAULT_KEY_TYPE_NAME "ed25519"
+#define FIPS_DEFAULT_KEY_TYPE_NAME "rsa"
/*
* Default number of bits in the RSA, DSA and ECDSA keys. These value can be
@@ -205,6 +205,12 @@ type_bits_valid(int type, const char *na
#endif
}
#ifdef WITH_OPENSSL
+ if (FIPS_mode()) {
+ if (type == KEY_DSA)
+ fatal("DSA keys are not allowed in FIPS mode");
+ if (type == KEY_ED25519 || type == KEY_ED25519_SK)
+ fatal("ED25519 keys are not allowed in FIPS mode");
+ }
switch (type) {
case KEY_DSA:
if (*bitsp != 1024)
@@ -266,7 +267,7 @@ ask_filename(struct passwd *pw, const ch
char *name = NULL;
if (key_type_name == NULL)
- name = _PATH_SSH_CLIENT_ID_ED25519;
+ name = FIPS_mode() ? _PATH_SSH_CLIENT_ID_RSA : _PATH_SSH_CLIENT_ID_ED25519;
else {
switch (sshkey_type_from_shortname(key_type_name)) {
#ifdef WITH_DSA
@@ -1098,9 +1104,17 @@ do_gen_all_hostkeys(struct passwd *pw)
first = 1;
printf("%s: generating new host keys: ", __progname);
}
+ type = sshkey_type_from_shortname(key_types[i].key_type);
+
+ /* Skip the keys that are not supported in FIPS mode */
+ if (FIPS_mode() && (type == KEY_DSA || type == KEY_ED25519)) {
+ logit("Skipping %s key in FIPS mode",
+ key_types[i].key_type_display);
+ goto next;
+ }
+
printf("%s ", key_types[i].key_type_display);
fflush(stdout);
- type = sshkey_type_from_shortname(key_types[i].key_type);
if ((fd = mkstemp(prv_tmp)) == -1) {
error("Could not save your private key in %s: %s",
prv_tmp, strerror(errno));
@@ -3830,7 +3831,7 @@ main(int argc, char **argv)
}
if (key_type_name == NULL)
- key_type_name = DEFAULT_KEY_TYPE_NAME;
+ key_type_name = FIPS_mode() ? FIPS_DEFAULT_KEY_TYPE_NAME : DEFAULT_KEY_TYPE_NAME;
type = sshkey_type_from_shortname(key_type_name);
type_bits_valid(type, key_type_name, &bits);
diff -up openssh-9.3p1/ssh-rsa.c.evpgenrsa openssh-9.3p1/ssh-rsa.c
--- openssh-9.3p1/ssh-rsa.c.evpgenrsa 2022-06-30 15:14:58.200518353 +0200
+++ openssh-9.3p1/ssh-rsa.c 2022-06-30 15:24:31.499641196 +0200
@@ -33,6 +33,7 @@
#include <openssl/evp.h>
#include <openssl/err.h>
+#include <openssl/fips.h>
#include <stdarg.h>
#include <string.h>
@@ -1705,6 +1707,8 @@ ssh_rsa_generate(u_int bits, RSA
goto out;
}
if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) {
+ if (FIPS_mode())
+ logit_f("the key length might be unsupported by FIPS mode approved key generation method");
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
diff -up openssh-9.9p1/kexgen.c.xxx openssh-9.9p1/kexgen.c
--- openssh-9.9p1/kexgen.c.xxx 2024-10-09 10:35:56.285946080 +0200
+++ openssh-9.9p1/kexgen.c 2024-10-09 10:41:52.792597194 +0200
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <string.h>
#include <signal.h>
+#include <openssl/fips.h>
#include "sshkey.h"
#include "kex.h"
@@ -115,13 +116,28 @@ kex_gen_client(struct ssh *ssh)
break;
#endif
case KEX_C25519_SHA256:
- r = kex_c25519_keypair(kex);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type c25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_c25519_keypair(kex);
+ }
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
- r = kex_kem_sntrup761x25519_keypair(kex);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_sntrup761x25519_keypair(kex);
+ }
break;
case KEX_KEM_MLKEM768X25519_SHA256:
- r = kex_kem_mlkem768x25519_keypair(kex);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_mlkem768x25519_keypair(kex);
+ }
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t
break;
#endif
case KEX_C25519_SHA256:
- r = kex_c25519_dec(kex, server_blob, &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type c25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_c25519_dec(kex, server_blob, &shared_secret);
+ }
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
- r = kex_kem_sntrup761x25519_dec(kex, server_blob,
- &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_sntrup761x25519_dec(kex, server_blob,
+ &shared_secret);
+ }
break;
case KEX_KEM_MLKEM768X25519_SHA256:
- r = kex_kem_mlkem768x25519_dec(kex, server_blob,
- &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_mlkem768x25519_dec(kex, server_blob,
+ &shared_secret);
+ }
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t s
break;
#endif
case KEX_C25519_SHA256:
- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
- &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type c25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
+ &shared_secret);
+ }
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
- &server_pubkey, &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
+ &server_pubkey, &shared_secret);
+ }
break;
case KEX_KEM_MLKEM768X25519_SHA256:
- r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
- &server_pubkey, &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
+ &server_pubkey, &shared_secret);
+ }
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
diff -up openssh-8.7p1/ssh-ed25519.c.fips3 openssh-8.7p1/ssh-ed25519.c
--- openssh-8.7p1/ssh-ed25519.c.fips3 2022-07-11 16:53:41.428343304 +0200
+++ openssh-8.7p1/ssh-ed25519.c 2022-07-11 16:56:09.284663661 +0200
@@ -24,6 +24,7 @@
#include <string.h>
#include <stdarg.h>
+#include <openssl/fips.h>
#include "log.h"
#include "sshbuf.h"
@@ -52,6 +53,10 @@ ssh_ed25519_sign(const struct sshkey *ke
key->ed25519_sk == NULL ||
datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
return SSH_ERR_INVALID_ARGUMENT;
+ if (FIPS_mode()) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
smlen = slen = datalen + crypto_sign_ed25519_BYTES;
if ((sig = malloc(slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
@@ -108,6 +113,10 @@ ssh_ed25519_verify(const struct sshkey *
dlen >= INT_MAX - crypto_sign_ed25519_BYTES ||
sig == NULL || siglen == 0)
return SSH_ERR_INVALID_ARGUMENT;
+ if (FIPS_mode()) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
if ((b = sshbuf_from(sig, siglen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
diff -up openssh-9.9p1/kex.c.xxx openssh-9.9p1/kex.c
--- openssh-9.9p1/kex.c.xxx 2024-10-11 12:44:08.087426597 +0200
+++ openssh-9.9p1/kex.c 2024-10-11 14:00:10.404714521 +0200
@@ -40,6 +40,7 @@
#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
#include <openssl/dh.h>
+#include <openssl/fips.h>
# ifdef HAVE_EVP_KDF_CTX_NEW
# include <openssl/kdf.h>
# include <openssl/param_build.h>
@@ -109,7 +110,7 @@ kex_proposal_populate_entries(struct ssh
/* Append EXT_INFO signalling to KexAlgorithms */
if (kexalgos == NULL)
- kexalgos = defprop[PROPOSAL_KEX_ALGS];
+ kexalgos = FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : defprop[PROPOSAL_KEX_ALGS];
if ((cp = kex_names_cat(kexalgos, ssh->kex->server ?
"ext-info-s,kex-strict-s-v00@openssh.com" :
"ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)

@ -0,0 +1,632 @@
diff -up openssh-8.6p1/auth.h.ccache_name openssh-8.6p1/auth.h
--- openssh-8.6p1/auth.h.ccache_name 2021-04-19 14:05:10.820744325 +0200
+++ openssh-8.6p1/auth.h 2021-04-19 14:05:10.853744569 +0200
@@ -83,6 +83,7 @@ struct Authctxt {
krb5_principal krb5_user;
char *krb5_ticket_file;
char *krb5_ccname;
+ int krb5_set_env;
#endif
struct sshbuf *loginmsg;
@@ -231,7 +232,7 @@ struct passwd *fakepw(void);
int sys_auth_passwd(struct ssh *, const char *);
#if defined(KRB5) && !defined(HEIMDAL)
-krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
+krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *);
#endif
#endif /* AUTH_H */
diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c
--- openssh-8.6p1/auth-krb5.c.ccache_name 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/auth-krb5.c 2021-04-19 14:40:55.142832954 +0200
@@ -51,6 +51,7 @@
#include <unistd.h>
#include <string.h>
#include <krb5.h>
+#include <profile.h>
extern ServerOptions options;
@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, c
#endif
krb5_error_code problem;
krb5_ccache ccache = NULL;
- int len;
+ char *ticket_name = NULL;
char *client, *platform_client;
const char *errmsg;
@@ -163,8 +164,8 @@ auth_krb5_password(Authctxt *authctxt, c
goto out;
}
- problem = ssh_krb5_cc_gen(authctxt->krb5_ctx,
- &authctxt->krb5_fwd_ccache);
+ problem = ssh_krb5_cc_new_unique(authctxt->krb5_ctx,
+ &authctxt->krb5_fwd_ccache, &authctxt->krb5_set_env);
if (problem)
goto out;
@@ -179,15 +180,14 @@ auth_krb5_password(Authctxt *authctxt, c
goto out;
#endif
- authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+ problem = krb5_cc_get_full_name(authctxt->krb5_ctx,
+ authctxt->krb5_fwd_ccache, &ticket_name);
- len = strlen(authctxt->krb5_ticket_file) + 6;
- authctxt->krb5_ccname = xmalloc(len);
- snprintf(authctxt->krb5_ccname, len, "FILE:%s",
- authctxt->krb5_ticket_file);
+ authctxt->krb5_ccname = xstrdup(ticket_name);
+ krb5_free_string(authctxt->krb5_ctx, ticket_name);
#ifdef USE_PAM
- if (options.use_pam)
+ if (options.use_pam && authctxt->krb5_set_env)
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
#endif
@@ -223,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, c
void
krb5_cleanup_proc(Authctxt *authctxt)
{
+ struct stat krb5_ccname_stat;
+ char krb5_ccname[128], *krb5_ccname_dir_start, *krb5_ccname_dir_end;
+
debug("krb5_cleanup_proc called");
if (authctxt->krb5_fwd_ccache) {
- krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+ krb5_context ctx = authctxt->krb5_ctx;
+ krb5_cccol_cursor cursor;
+ krb5_ccache ccache;
+ int ret;
+
+ krb5_cc_destroy(ctx, authctxt->krb5_fwd_ccache);
authctxt->krb5_fwd_ccache = NULL;
+
+ ret = krb5_cccol_cursor_new(ctx, &cursor);
+ if (ret)
+ goto out;
+
+ ret = krb5_cccol_cursor_next(ctx, cursor, &ccache);
+ if (ret == 0 && ccache != NULL) {
+ /* There is at least one other ccache in collection
+ * we can switch to */
+ krb5_cc_switch(ctx, ccache);
+ } else if (authctxt->krb5_ccname != NULL) {
+ /* Clean up the collection too */
+ strncpy(krb5_ccname, authctxt->krb5_ccname, sizeof(krb5_ccname) - 10);
+ krb5_ccname_dir_start = strchr(krb5_ccname, ':') + 1;
+ *krb5_ccname_dir_start++ = '\0';
+ if (strcmp(krb5_ccname, "DIR") == 0) {
+
+ strcat(krb5_ccname_dir_start, "/primary");
+
+ if (stat(krb5_ccname_dir_start, &krb5_ccname_stat) == 0) {
+ if (unlink(krb5_ccname_dir_start) == 0) {
+ krb5_ccname_dir_end = strrchr(krb5_ccname_dir_start, '/');
+ *krb5_ccname_dir_end = '\0';
+ if (rmdir(krb5_ccname_dir_start) == -1)
+ debug("cache dir '%s' remove failed: %s",
+ krb5_ccname_dir_start, strerror(errno));
+ }
+ else
+ debug("cache primary file '%s', remove failed: %s",
+ krb5_ccname_dir_start, strerror(errno));
+ }
+ }
+ }
+ krb5_cccol_cursor_free(ctx, &cursor);
}
+out:
if (authctxt->krb5_user) {
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
authctxt->krb5_user = NULL;
@@ -238,36 +281,188 @@ krb5_cleanup_proc(Authctxt *authctxt)
}
}
-#ifndef HEIMDAL
+
+#if !defined(HEIMDAL)
+int
+ssh_asprintf_append(char **dsc, const char *fmt, ...) {
+ char *src, *old;
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ i = vasprintf(&src, fmt, ap);
+ va_end(ap);
+
+ if (i == -1 || src == NULL)
+ return -1;
+
+ old = *dsc;
+
+ i = asprintf(dsc, "%s%s", *dsc, src);
+ if (i == -1 || src == NULL) {
+ free(src);
+ return -1;
+ }
+
+ free(old);
+ free(src);
+
+ return i;
+}
+
+int
+ssh_krb5_expand_template(char **result, const char *template) {
+ char *p_n, *p_o, *r, *tmp_template;
+
+ debug3_f("called, template = %s", template);
+ if (template == NULL)
+ return -1;
+
+ tmp_template = p_n = p_o = xstrdup(template);
+ r = xstrdup("");
+
+ while ((p_n = strstr(p_o, "%{")) != NULL) {
+
+ *p_n++ = '\0';
+ if (ssh_asprintf_append(&r, "%s", p_o) == -1)
+ goto cleanup;
+
+ if (strncmp(p_n, "{uid}", 5) == 0 || strncmp(p_n, "{euid}", 6) == 0 ||
+ strncmp(p_n, "{USERID}", 8) == 0) {
+ p_o = strchr(p_n, '}') + 1;
+ if (ssh_asprintf_append(&r, "%d", geteuid()) == -1)
+ goto cleanup;
+ continue;
+ }
+ else if (strncmp(p_n, "{TEMP}", 6) == 0) {
+ p_o = strchr(p_n, '}') + 1;
+ if (ssh_asprintf_append(&r, "/tmp") == -1)
+ goto cleanup;
+ continue;
+ } else {
+ p_o = strchr(p_n, '}') + 1;
+ *p_o = '\0';
+ debug_f("unsupported token %s in %s", p_n, template);
+ /* unknown token, fallback to the default */
+ goto cleanup;
+ }
+ }
+
+ if (ssh_asprintf_append(&r, "%s", p_o) == -1)
+ goto cleanup;
+
+ *result = r;
+ free(tmp_template);
+ return 0;
+
+cleanup:
+ free(r);
+ free(tmp_template);
+ return -1;
+}
+
+krb5_error_code
+ssh_krb5_get_cctemplate(krb5_context ctx, char **ccname) {
+ profile_t p;
+ int ret = 0;
+ char *value = NULL;
+
+ debug3_f("called");
+ ret = krb5_get_profile(ctx, &p);
+ if (ret)
+ return ret;
+
+ ret = profile_get_string(p, "libdefaults", "default_ccache_name", NULL, NULL, &value);
+ if (ret || !value)
+ return ret;
+
+ ret = ssh_krb5_expand_template(ccname, value);
+
+ debug3_f("returning with ccname = %s", *ccname);
+ return ret;
+}
+
krb5_error_code
-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
- int tmpfd, ret, oerrno;
- char ccname[40];
+ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environment) {
+ int tmpfd, ret, oerrno, type_len;
+ char *ccname = NULL;
mode_t old_umask;
+ char *type = NULL, *colon = NULL;
- ret = snprintf(ccname, sizeof(ccname),
- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
- if (ret < 0 || (size_t)ret >= sizeof(ccname))
- return ENOMEM;
-
- old_umask = umask(0177);
- tmpfd = mkstemp(ccname + strlen("FILE:"));
- oerrno = errno;
- umask(old_umask);
- if (tmpfd == -1) {
- logit("mkstemp(): %.100s", strerror(oerrno));
- return oerrno;
- }
+ debug3_f("called");
+ if (need_environment)
+ *need_environment = 0;
+ ret = ssh_krb5_get_cctemplate(ctx, &ccname);
+ if (ret || !ccname || options.kerberos_unique_ccache) {
+ /* Otherwise, go with the old method */
+ if (ccname)
+ free(ccname);
+ ccname = NULL;
+
+ ret = asprintf(&ccname,
+ "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
+ if (ret < 0)
+ return ENOMEM;
- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
+ old_umask = umask(0177);
+ tmpfd = mkstemp(ccname + strlen("FILE:"));
oerrno = errno;
- logit("fchmod(): %.100s", strerror(oerrno));
+ umask(old_umask);
+ if (tmpfd == -1) {
+ logit("mkstemp(): %.100s", strerror(oerrno));
+ return oerrno;
+ }
+
+ if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
+ oerrno = errno;
+ logit("fchmod(): %.100s", strerror(oerrno));
+ close(tmpfd);
+ return oerrno;
+ }
+ /* make sure the KRB5CCNAME is set for non-standard location */
+ if (need_environment)
+ *need_environment = 1;
close(tmpfd);
- return oerrno;
}
- close(tmpfd);
- return (krb5_cc_resolve(ctx, ccname, ccache));
+ debug3_f("setting default ccname to %s", ccname);
+ /* set the default with already expanded user IDs */
+ ret = krb5_cc_set_default_name(ctx, ccname);
+ if (ret)
+ return ret;
+
+ if ((colon = strstr(ccname, ":")) != NULL) {
+ type_len = colon - ccname;
+ type = malloc((type_len + 1) * sizeof(char));
+ if (type == NULL)
+ return ENOMEM;
+ strncpy(type, ccname, type_len);
+ type[type_len] = 0;
+ } else {
+ type = strdup(ccname);
+ }
+
+ /* If we have a credential cache from krb5.conf, we need to switch
+ * a primary cache for this collection, if it supports that (non-FILE)
+ */
+ if (krb5_cc_support_switch(ctx, type)) {
+ debug3_f("calling cc_new_unique(%s)", ccname);
+ ret = krb5_cc_new_unique(ctx, type, NULL, ccache);
+ free(type);
+ if (ret)
+ return ret;
+
+ debug3_f("calling cc_switch()");
+ return krb5_cc_switch(ctx, *ccache);
+ } else {
+ /* Otherwise, we can not create a unique ccname here (either
+ * it is already unique from above or the type does not support
+ * collections
+ */
+ free(type);
+ debug3_f("calling cc_resolve(%s)", ccname);
+ return (krb5_cc_resolve(ctx, ccname, ccache));
+ }
}
#endif /* !HEIMDAL */
#endif /* KRB5 */
diff -up openssh-8.6p1/gss-serv.c.ccache_name openssh-8.6p1/gss-serv.c
--- openssh-8.6p1/gss-serv.c.ccache_name 2021-04-19 14:05:10.844744503 +0200
+++ openssh-8.6p1/gss-serv.c 2021-04-19 14:05:10.854744577 +0200
@@ -413,13 +413,15 @@ ssh_gssapi_cleanup_creds(void)
}
/* As user */
-void
+int
ssh_gssapi_storecreds(void)
{
if (gssapi_client.mech && gssapi_client.mech->storecreds) {
- (*gssapi_client.mech->storecreds)(&gssapi_client);
+ return (*gssapi_client.mech->storecreds)(&gssapi_client);
} else
debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+
+ return 0;
}
/* This allows GSSAPI methods to do things to the child's environment based
@@ -499,9 +501,7 @@ ssh_gssapi_rekey_creds(void) {
char *envstr;
#endif
- if (gssapi_client.store.filename == NULL &&
- gssapi_client.store.envval == NULL &&
- gssapi_client.store.envvar == NULL)
+ if (gssapi_client.store.envval == NULL)
return;
ok = mm_ssh_gssapi_update_creds(&gssapi_client.store);
diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c
--- openssh-8.6p1/gss-serv-krb5.c.ccache_name 2021-04-19 14:05:10.852744562 +0200
+++ openssh-8.6p1/gss-serv-krb5.c 2021-04-19 14:05:10.854744577 +0200
@@ -267,7 +267,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri
/* This writes out any forwarded credentials from the structure populated
* during userauth. Called after we have setuid to the user */
-static void
+static int
ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
{
krb5_ccache ccache;
@@ -276,14 +276,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
OM_uint32 maj_status, min_status;
const char *new_ccname, *new_cctype;
const char *errmsg;
+ int set_env = 0;
if (client->creds == NULL) {
debug("No credentials stored");
- return;
+ return 0;
}
if (ssh_gssapi_krb5_init() == 0)
- return;
+ return 0;
#ifdef HEIMDAL
# ifdef HAVE_KRB5_CC_NEW_UNIQUE
@@ -297,14 +298,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
krb5_get_err_text(krb_context, problem));
# endif
krb5_free_error_message(krb_context, errmsg);
- return;
+ return 0;
}
#else
- if ((problem = ssh_krb5_cc_gen(krb_context, &ccache))) {
+ if ((problem = ssh_krb5_cc_new_unique(krb_context, &ccache, &set_env)) != 0) {
errmsg = krb5_get_error_message(krb_context, problem);
- logit("ssh_krb5_cc_gen(): %.100s", errmsg);
+ logit("ssh_krb5_cc_new_unique(): %.100s", errmsg);
krb5_free_error_message(krb_context, errmsg);
- return;
+ return 0;
}
#endif /* #ifdef HEIMDAL */
@@ -313,7 +314,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
errmsg = krb5_get_error_message(krb_context, problem);
logit("krb5_parse_name(): %.100s", errmsg);
krb5_free_error_message(krb_context, errmsg);
- return;
+ return 0;
}
if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
@@ -322,7 +323,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
krb5_free_error_message(krb_context, errmsg);
krb5_free_principal(krb_context, princ);
krb5_cc_destroy(krb_context, ccache);
- return;
+ return 0;
}
krb5_free_principal(krb_context, princ);
@@ -331,32 +332,21 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
client->creds, ccache))) {
logit("gss_krb5_copy_ccache() failed");
krb5_cc_destroy(krb_context, ccache);
- return;
+ return 0;
}
new_cctype = krb5_cc_get_type(krb_context, ccache);
new_ccname = krb5_cc_get_name(krb_context, ccache);
-
- client->store.envvar = "KRB5CCNAME";
-#ifdef USE_CCAPI
- xasprintf(&client->store.envval, "API:%s", new_ccname);
- client->store.filename = NULL;
-#else
- if (new_ccname[0] == ':')
- new_ccname++;
xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname);
- if (strcmp(new_cctype, "DIR") == 0) {
- char *p;
- p = strrchr(client->store.envval, '/');
- if (p)
- *p = '\0';
+
+ if (set_env) {
+ client->store.envvar = "KRB5CCNAME";
}
if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0))
client->store.filename = xstrdup(new_ccname);
-#endif
#ifdef USE_PAM
- if (options.use_pam)
+ if (options.use_pam && set_env)
do_pam_putenv(client->store.envvar, client->store.envval);
#endif
@@ -364,7 +354,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
client->store.data = krb_context;
- return;
+ return set_env;
}
int
diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c
--- openssh-8.6p1/servconf.c.ccache_name 2021-04-19 14:05:10.848744532 +0200
+++ openssh-8.6p1/servconf.c 2021-04-19 14:05:10.854744577 +0200
@@ -136,6 +136,7 @@ initialize_server_options(ServerOptions
options->kerberos_or_local_passwd = -1;
options->kerberos_ticket_cleanup = -1;
options->kerberos_get_afs_token = -1;
+ options->kerberos_unique_ccache = -1;
options->gss_authentication=-1;
options->gss_keyex = -1;
options->gss_cleanup_creds = -1;
@@ -359,6 +360,8 @@ fill_default_server_options(ServerOption
options->kerberos_ticket_cleanup = 1;
if (options->kerberos_get_afs_token == -1)
options->kerberos_get_afs_token = 0;
+ if (options->kerberos_unique_ccache == -1)
+ options->kerberos_unique_ccache = 0;
if (options->gss_authentication == -1)
options->gss_authentication = 0;
if (options->gss_keyex == -1)
@@ -506,7 +509,7 @@ typedef enum {
sPort, sHostKeyFile, sLoginGraceTime,
sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose,
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
- sKerberosGetAFSToken, sPasswordAuthentication,
+ sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication,
sKbdInteractiveAuthentication, sListenAddress, sAddressFamily,
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
@@ -593,11 +597,13 @@ static struct {
#else
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
#endif
+ { "kerberosuniqueccache", sKerberosUniqueCCache, SSHCFG_GLOBAL },
#else
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
+ { "kerberosuniqueccache", sUnsupported, SSHCFG_GLOBAL },
#endif
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
@@ -1573,6 +1579,10 @@ process_server_config_line_depth(ServerO
intptr = &options->kerberos_get_afs_token;
goto parse_flag;
+ case sKerberosUniqueCCache:
+ intptr = &options->kerberos_unique_ccache;
+ goto parse_flag;
+
case sGssAuthentication:
intptr = &options->gss_authentication;
goto parse_flag;
@@ -2891,6 +2901,7 @@ dump_config(ServerOptions *o)
# ifdef USE_AFS
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
# endif
+ dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache);
#endif
#ifdef GSSAPI
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h
--- openssh-8.6p1/servconf.h.ccache_name 2021-04-19 14:05:10.848744532 +0200
+++ openssh-8.6p1/servconf.h 2021-04-19 14:05:10.855744584 +0200
@@ -140,6 +140,8 @@ typedef struct {
* file on logout. */
int kerberos_get_afs_token; /* If true, try to get AFS token if
* authenticated with Kerberos. */
+ int kerberos_unique_ccache; /* If true, the acquired ticket will
+ * be stored in per-session ccache */
int gss_authentication; /* If true, permit GSSAPI authentication */
int gss_keyex; /* If true, permit GSSAPI key exchange */
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c
--- openssh-8.6p1/session.c.ccache_name 2021-04-19 14:05:10.852744562 +0200
+++ openssh-8.6p1/session.c 2021-04-19 14:05:10.855744584 +0200
@@ -1038,7 +1038,8 @@ do_setup_env(struct ssh *ssh, Session *s
/* Allow any GSSAPI methods that we've used to alter
* the child's environment as they see fit
*/
- ssh_gssapi_do_child(&env, &envsize);
+ if (s->authctxt->krb5_set_env)
+ ssh_gssapi_do_child(&env, &envsize);
#endif
/* Set basic environment. */
@@ -1114,7 +1115,7 @@ do_setup_env(struct ssh *ssh, Session *s
}
#endif
#ifdef KRB5
- if (s->authctxt->krb5_ccname)
+ if (s->authctxt->krb5_ccname && s->authctxt->krb5_set_env)
child_set_env(&env, &envsize, "KRB5CCNAME",
s->authctxt->krb5_ccname);
#endif
diff -up openssh-8.6p1/sshd-session.c.ccache_name openssh-8.6p1/sshd-session.c
--- openssh-8.6p1/sshd-session.c.ccache_name 2021-04-19 14:05:10.849744540 +0200
+++ openssh-8.6p1/sshd-session.c 2021-04-19 14:05:10.855744584 +0200
@@ -2284,7 +2284,7 @@ main(int ac, char **av)
#ifdef GSSAPI
if (options.gss_authentication) {
temporarily_use_uid(authctxt->pw);
- ssh_gssapi_storecreds();
+ authctxt->krb5_set_env = ssh_gssapi_storecreds();
restore_uid();
}
#endif
diff -up openssh-8.6p1/sshd_config.5.ccache_name openssh-8.6p1/sshd_config.5
--- openssh-8.6p1/sshd_config.5.ccache_name 2021-04-19 14:05:10.849744540 +0200
+++ openssh-8.6p1/sshd_config.5 2021-04-19 14:05:10.856744592 +0200
@@ -939,6 +939,14 @@ Specifies whether to automatically destr
file on logout.
The default is
.Cm yes .
+.It Cm KerberosUniqueCCache
+Specifies whether to store the acquired tickets in the per-session credential
+cache under /tmp/ or whether to use per-user credential cache as configured in
+.Pa /etc/krb5.conf .
+The default value
+.Cm no
+can lead to overwriting previous tickets by subseqent connections to the same
+user account.
.It Cm KexAlgorithms
Specifies the permitted KEX (Key Exchange) algorithms that the server will
offer to clients.
diff -up openssh-8.6p1/ssh-gss.h.ccache_name openssh-8.6p1/ssh-gss.h
--- openssh-8.6p1/ssh-gss.h.ccache_name 2021-04-19 14:05:10.852744562 +0200
+++ openssh-8.6p1/ssh-gss.h 2021-04-19 14:05:10.855744584 +0200
@@ -114,7 +114,7 @@ typedef struct ssh_gssapi_mech_struct {
int (*dochild) (ssh_gssapi_client *);
int (*userok) (ssh_gssapi_client *, char *);
int (*localname) (ssh_gssapi_client *, char **);
- void (*storecreds) (ssh_gssapi_client *);
+ int (*storecreds) (ssh_gssapi_client *);
int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
} ssh_gssapi_mech;
@@ -175,7 +175,7 @@ int ssh_gssapi_userok(char *name, struct
OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
void ssh_gssapi_do_child(char ***, u_int *);
void ssh_gssapi_cleanup_creds(void);
-void ssh_gssapi_storecreds(void);
+int ssh_gssapi_storecreds(void);
const char *ssh_gssapi_displayname(void);
char *ssh_gssapi_server_mechanisms(void);

@ -0,0 +1,109 @@
diff -up openssh/ssh_config.redhat openssh/ssh_config
--- openssh/ssh_config.redhat 2020-02-11 23:28:35.000000000 +0100
+++ openssh/ssh_config 2020-02-13 18:13:39.180641839 +0100
@@ -43,3 +43,10 @@
# ProxyCommand ssh -q -W %h:%p gateway.example.com
# RekeyLimit 1G 1h
# UserKnownHostsFile ~/.ssh/known_hosts.d/%k
+#
+# This system is following system-wide crypto policy.
+# To modify the crypto properties (Ciphers, MACs, ...), create a *.conf
+# file under /etc/ssh/ssh_config.d/ which will be automatically
+# included below. For more information, see manual page for
+# update-crypto-policies(8) and ssh_config(5).
+Include /etc/ssh/ssh_config.d/*.conf
diff -up openssh/ssh_config_redhat.redhat openssh/ssh_config_redhat
--- openssh/ssh_config_redhat.redhat 2020-02-13 18:13:39.180641839 +0100
+++ openssh/ssh_config_redhat 2020-02-13 18:13:39.180641839 +0100
@@ -0,0 +1,15 @@
+# The options here are in the "Match final block" to be applied as the last
+# options and could be potentially overwritten by the user configuration
+Match final all
+ # Follow system-wide Crypto Policy, if defined:
+ Include /etc/crypto-policies/back-ends/openssh.config
+
+ 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
+
+# Uncomment this if you want to use .local domain
+# Host *.local
diff -up openssh/sshd_config.0.redhat openssh/sshd_config.0
--- openssh/sshd_config.0.redhat 2020-02-12 14:30:04.000000000 +0100
+++ openssh/sshd_config.0 2020-02-13 18:13:39.181641855 +0100
@@ -970,9 +970,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/sshd_config.5.redhat openssh/sshd_config.5
--- openssh/sshd_config.5.redhat 2020-02-11 23:28:35.000000000 +0100
+++ openssh/sshd_config.5 2020-02-13 18:13:39.181641855 +0100
@@ -1614,7 +1614,7 @@ By default no subsystems are defined.
.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/sshd_config.redhat openssh/sshd_config
--- openssh/sshd_config.redhat 2020-02-11 23:28:35.000000000 +0100
+++ openssh/sshd_config 2020-02-13 18:20:16.349913681 +0100
@@ -10,6 +10,14 @@
# possible, but leave them commented. Uncommented options override the
# default value.
+# To modify the system-wide sshd configuration, create a *.conf file under
+# /etc/ssh/sshd_config.d/ which will be automatically included below
+Include /etc/ssh/sshd_config.d/*.conf
+
+# If you want to change the port on a SELinux system, you have to tell
+# SELinux about this change.
+# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
+#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
diff -up openssh/sshd_config_redhat.redhat openssh/sshd_config_redhat
--- openssh/sshd_config_redhat.redhat 2020-02-13 18:14:02.268006439 +0100
+++ openssh/sshd_config_redhat 2020-02-13 18:19:20.765035947 +0100
@@ -0,0 +1,15 @@
+SyslogFacility AUTHPRIV
+
+ChallengeResponseAuthentication no
+
+GSSAPIAuthentication yes
+GSSAPICleanupCredentials no
+
+UsePAM yes
+
+X11Forwarding yes
+
+# It is recommended to use pam_motd in /etc/pam.d/sshd instead of PrintMotd,
+# as it is more configurable and versatile than the built-in version.
+PrintMotd no
+
diff -up openssh/sshd_config_redhat.redhat openssh/sshd_config_redhat
--- openssh/sshd_config_redhat_cp.redhat 2020-02-13 18:14:02.268006439 +0100
+++ openssh/sshd_config_redhat_cp 2020-02-13 18:19:20.765035947 +0100
@@ -0,0 +1,7 @@
+# This system is following system-wide crypto policy. The changes to
+# crypto properties (Ciphers, MACs, ...) will not have any effect in
+# this or following included files. To override some configuration option,
+# write it before this block or include it before this file.
+# Please, see manual pages for update-crypto-policies(8) and sshd_config(5).
+Include /etc/crypto-policies/back-ends/opensshserver.config
+

@ -0,0 +1,26 @@
diff -up openssh-8.6p1/sshd.c.log-usepam-no openssh-8.6p1/sshd.c
--- openssh-8.6p1/sshd-session.c.log-usepam-no 2021-04-19 14:00:45.099735129 +0200
+++ openssh-8.6p1/sshd-session.c 2021-04-19 14:03:21.140920974 +0200
@@ -1749,6 +1749,10 @@ main(int ac, char **av)
"enabled authentication methods");
}
+ /* 'UsePAM no' is not supported in our builds */
+ if (! options.use_pam)
+ logit("WARNING: 'UsePAM no' is not supported in this build and may cause several problems.");
+
#ifdef WITH_OPENSSL
if (options.moduli_file != NULL)
dh_set_moduli_file(options.moduli_file);
diff -up openssh-8.6p1/sshd_config.log-usepam-no openssh-8.6p1/sshd_config
--- openssh-8.6p1/sshd_config.log-usepam-no 2021-04-19 14:00:45.098735121 +0200
+++ openssh-8.6p1/sshd_config 2021-04-19 14:00:45.099735129 +0200
@@ -87,6 +87,8 @@ AuthorizedKeysFile .ssh/authorized_keys
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
+# WARNING: 'UsePAM no' is not supported in this build and may cause several
+# problems.
#UsePAM no
#AllowAgentForwarding yes

@ -0,0 +1,863 @@
diff -up openssh/auth2.c.role-mls openssh/auth2.c
--- openssh/auth2.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/auth2.c 2018-08-22 11:14:56.815430916 +0200
@@ -256,6 +256,9 @@ input_userauth_request(int type, u_int32
Authctxt *authctxt = ssh->authctxt;
Authmethod *m = NULL;
char *user = NULL, *service = NULL, *method = NULL, *style = NULL;
+#ifdef WITH_SELINUX
+ char *role = NULL;
+#endif
int r, authenticated = 0;
double tstart = monotime_double();
@@ -268,6 +271,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;
@@ -314,7 +314,13 @@ input_userauth_request(int type, u_int32
setproctitle("%s [net]", authctxt->valid ? user : "unknown");
authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL;
+#ifdef WITH_SELINUX
+ authctxt->role = role ? xstrdup(role) : NULL;
+#endif
mm_inform_authserv(service, style);
+#ifdef WITH_SELINUX
+ mm_inform_authrole(role);
+#endif
userauth_banner(ssh);
if ((r = kex_server_update_ext_info(ssh)) != 0)
fatal_fr(r, "kex_server_update_ext_info failed");
diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c
--- openssh/auth2-gss.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/auth2-gss.c 2018-08-22 11:15:42.459799171 +0200
@@ -281,6 +281,7 @@ input_gssapi_mic(int type, u_int32_t ple
Authctxt *authctxt = ssh->authctxt;
Gssctxt *gssctxt;
int r, authenticated = 0;
+ char *micuser;
struct sshbuf *b;
gss_buffer_desc mic, gssbuf;
u_char *p;
@@ -298,7 +299,13 @@ input_gssapi_mic(int type, u_int32_t ple
fatal_f("sshbuf_new failed");
mic.value = p;
mic.length = len;
- ssh_gssapi_buildmic(b, authctxt->user, authctxt->service,
+#ifdef WITH_SELINUX
+ if (authctxt->role && authctxt->role[0] != 0)
+ xasprintf(&micuser, "%s/%s", authctxt->user, authctxt->role);
+ else
+#endif
+ micuser = authctxt->user;
+ ssh_gssapi_buildmic(b, micuser, authctxt->service,
"gssapi-with-mic", ssh->kex->session_id);
if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
@@ -311,6 +318,8 @@ input_gssapi_mic(int type, u_int32_t ple
logit("GSSAPI MIC check failed");
sshbuf_free(b);
+ if (micuser != authctxt->user)
+ free(micuser);
free(mic.value);
authctxt->postponed = 0;
diff -up openssh/auth2-hostbased.c.role-mls openssh/auth2-hostbased.c
--- openssh/auth2-hostbased.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/auth2-hostbased.c 2018-08-22 11:14:56.816430924 +0200
@@ -123,7 +123,16 @@ userauth_hostbased(struct ssh *ssh)
/* reconstruct packet */
if ((r = sshbuf_put_stringb(b, ssh->kex->session_id)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
+#ifdef WITH_SELINUX
+ (authctxt->role
+ ? ( (r = sshbuf_put_u32(b, strlen(authctxt->user)+strlen(authctxt->role)+1)) != 0 ||
+ (r = sshbuf_put(b, authctxt->user, strlen(authctxt->user))) != 0 ||
+ (r = sshbuf_put_u8(b, '/') != 0) ||
+ (r = sshbuf_put(b, authctxt->role, strlen(authctxt->role))) != 0)
+ : (r = sshbuf_put_cstring(b, authctxt->user)) != 0) ||
+#else
(r = sshbuf_put_cstring(b, authctxt->user)) != 0 ||
+#endif
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
(r = sshbuf_put_cstring(b, method)) != 0 ||
(r = sshbuf_put_string(b, pkalg, alen)) != 0 ||
diff -up openssh/auth2-pubkey.c.role-mls openssh/auth2-pubkey.c
--- openssh/auth2-pubkey.c.role-mls 2018-08-22 11:14:56.816430924 +0200
+++ openssh/auth2-pubkey.c 2018-08-22 11:17:07.331483958 +0200
@@ -169,9 +169,16 @@ userauth_pubkey(struct ssh *ssh)
goto done;
}
/* reconstruct packet */
- xasprintf(&userstyle, "%s%s%s", authctxt->user,
+ xasprintf(&userstyle, "%s%s%s%s%s", authctxt->user,
authctxt->style ? ":" : "",
- authctxt->style ? authctxt->style : "");
+ authctxt->style ? authctxt->style : "",
+#ifdef WITH_SELINUX
+ authctxt->role ? "/" : "",
+ authctxt->role ? authctxt->role : ""
+#else
+ "", ""
+#endif
+ );
if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
(r = sshbuf_put_cstring(b, userstyle)) != 0 ||
(r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
diff -up openssh/auth.h.role-mls openssh/auth.h
--- openssh/auth.h.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/auth.h 2018-08-22 11:14:56.816430924 +0200
@@ -65,6 +65,9 @@ struct Authctxt {
char *service;
struct passwd *pw; /* set if 'valid' */
char *style;
+#ifdef WITH_SELINUX
+ char *role;
+#endif
/* Method lists for multiple authentication */
char **auth_methods; /* modified from server config */
diff -up openssh/auth-pam.c.role-mls openssh/auth-pam.c
--- openssh/auth-pam.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/auth-pam.c 2018-08-22 11:14:56.816430924 +0200
@@ -1172,7 +1172,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;
char *compound;
diff -up openssh/auth-pam.h.role-mls openssh/auth-pam.h
--- openssh/auth-pam.h.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/auth-pam.h 2018-08-22 11:14:56.817430932 +0200
@@ -33,7 +33,7 @@ u_int do_pam_account(void);
void do_pam_session(struct ssh *);
void do_pam_setcred(void);
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/misc.c.role-mls openssh/misc.c
--- openssh/misc.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/misc.c 2018-08-22 11:14:56.817430932 +0200
@@ -542,6 +542,7 @@ char *
colon(char *cp)
{
int flag = 0;
+ int start = 1;
if (*cp == ':') /* Leading colon is part of file name. */
return NULL;
@@ -557,6 +558,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-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c
--- openssh-8.6p1/monitor.c.role-mls 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/monitor.c 2021-05-21 14:21:56.719414087 +0200
@@ -117,6 +117,9 @@ int mm_answer_sign(struct ssh *, int, st
int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *);
int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *);
int mm_answer_authserv(struct ssh *, int, struct sshbuf *);
+#ifdef WITH_SELINUX
+int mm_answer_authrole(struct ssh *, int, struct sshbuf *);
+#endif
int mm_answer_authpassword(struct ssh *, int, struct sshbuf *);
int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *);
int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *);
@@ -195,6 +198,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
@@ -803,6 +809,9 @@ mm_answer_pwnamallow(struct ssh *ssh, in
/* 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);
#ifdef USE_PAM
@@ -877,6 +886,26 @@ key_base_type_match(const char *method,
return found;
}
+#ifdef WITH_SELINUX
+int
+mm_answer_authrole(struct ssh *ssh, int sock, struct sshbuf *m)
+{
+ int r;
+ monitor_permit_authentications(1);
+
+ if ((r = sshbuf_get_cstring(m, &authctxt->role, NULL)) != 0)
+ fatal_f("buffer error: %s", ssh_err(r));
+ debug3_f("role=%s", authctxt->role);
+
+ if (strlen(authctxt->role) == 0) {
+ free(authctxt->role);
+ authctxt->role = NULL;
+ }
+
+ return (0);
+}
+#endif
+
int
mm_answer_authpassword(struct ssh *ssh, int sock, struct sshbuf *m)
{
@@ -1251,7 +1280,7 @@ monitor_valid_userblob(struct ssh *ssh,
struct sshbuf *b;
struct sshkey *hostkey = NULL;
const u_char *p;
- char *userstyle, *cp;
+ char *userstyle, *s, *cp;
size_t len;
u_char type;
int hostbound = 0, r, fail = 0;
@@ -1282,6 +1311,8 @@ monitor_valid_userblob(struct ssh *ssh,
fail++;
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse userstyle");
+ if ((s = strchr(cp, '/')) != NULL)
+ *s = '\0';
xasprintf(&userstyle, "%s%s%s", authctxt->user,
authctxt->style ? ":" : "",
authctxt->style ? authctxt->style : "");
@@ -1317,7 +1348,7 @@ monitor_valid_hostbasedblob(const u_char
{
struct sshbuf *b;
const u_char *p;
- char *cp, *userstyle;
+ char *cp, *s, *userstyle;
size_t len;
int r, fail = 0;
u_char type;
@@ -1338,6 +1370,8 @@ monitor_valid_hostbasedblob(const u_char
fail++;
if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
fatal_fr(r, "parse userstyle");
+ if ((s = strchr(cp, '/')) != NULL)
+ *s = '\0';
xasprintf(&userstyle, "%s%s%s", authctxt->user,
authctxt->style ? ":" : "",
authctxt->style ? authctxt->style : "");
diff -up openssh/monitor.h.role-mls openssh/monitor.h
--- openssh/monitor.h.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/monitor.h 2018-08-22 11:14:56.818430941 +0200
@@ -55,6 +55,10 @@ enum monitor_reqtype {
MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49,
MONITOR_REQ_TERM = 50,
+#ifdef WITH_SELINUX
+ MONITOR_REQ_AUTHROLE = 80,
+#endif
+
MONITOR_REQ_PAM_START = 100,
MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105,
diff -up openssh/monitor_wrap.c.role-mls openssh/monitor_wrap.c
--- openssh/monitor_wrap.c.role-mls 2018-08-22 11:14:56.818430941 +0200
+++ openssh/monitor_wrap.c 2018-08-22 11:21:47.938747968 +0200
@@ -390,6 +390,27 @@ mm_inform_authserv(char *service, char *
sshbuf_free(m);
}
+/* Inform the privileged process about role */
+
+#ifdef WITH_SELINUX
+void
+mm_inform_authrole(char *role)
+{
+ int r;
+ struct sshbuf *m;
+
+ debug3_f("entering");
+
+ if ((m = sshbuf_new()) == NULL)
+ fatal_f("sshbuf_new failed");
+ if ((r = sshbuf_put_cstring(m, role ? role : "")) != 0)
+ fatal_f("buffer error: %s", ssh_err(r));
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, m);
+
+ sshbuf_free(m);
+}
+#endif
+
/* Do the password authentication */
int
mm_auth_password(struct ssh *ssh, char *password)
diff -up openssh/monitor_wrap.h.role-mls openssh/monitor_wrap.h
--- openssh/monitor_wrap.h.role-mls 2018-08-22 11:14:56.818430941 +0200
+++ openssh/monitor_wrap.h 2018-08-22 11:22:10.439929513 +0200
@@ -44,6 +44,9 @@ DH *mm_choose_dh(int, int, int);
const u_char *, size_t, const char *, const char *,
const char *, u_int compat);
void mm_inform_authserv(char *, char *);
+#ifdef WITH_SELINUX
+void mm_inform_authrole(char *);
+#endif
struct passwd *mm_getpwnamallow(struct ssh *, const char *);
char *mm_auth2_read_banner(void);
int mm_auth_password(struct ssh *, char *);
diff -up openssh/openbsd-compat/Makefile.in.role-mls openssh/openbsd-compat/Makefile.in
--- openssh/openbsd-compat/Makefile.in.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/openbsd-compat/Makefile.in 2018-08-22 11:14:56.819430949 +0200
@@ -92,7 +92,8 @@ PORTS= port-aix.o \
port-prngd.o \
port-solaris.o \
port-net.o \
- port-uw.o
+ port-uw.o \
+ port-linux-sshd.o
.c.o:
$(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $<
diff -up openssh/openbsd-compat/port-linux.c.role-mls openssh/openbsd-compat/port-linux.c
--- openssh/openbsd-compat/port-linux.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/openbsd-compat/port-linux.c 2018-08-22 11:14:56.819430949 +0200
@@ -100,37 +100,6 @@ ssh_selinux_getctxbyname(char *pwname)
return sc;
}
-/* Set the execution context to the default for the specified user */
-void
-ssh_selinux_setup_exec_context(char *pwname)
-{
- char *user_ctx = NULL;
-
- if (!ssh_selinux_enabled())
- return;
-
- debug3("%s: setting execution context", __func__);
-
- user_ctx = ssh_selinux_getctxbyname(pwname);
- if (setexeccon(user_ctx) != 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);
- break;
- default:
- fatal("%s: Failed to set SELinux execution context "
- "for %s (in enforcing mode)", __func__, pwname);
- }
- }
- if (user_ctx != NULL)
- freecon(user_ctx);
-
- debug3("%s: done", __func__);
-}
-
/* Set the TTY context for the specified user */
void
ssh_selinux_setup_pty(char *pwname, const char *tty)
@@ -145,7 +114,11 @@ 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_f("getexeccon: %s", strerror(errno));
+ goto out;
+ }
+
/* XXX: should these calls fatal() upon failure in enforcing mode? */
diff -up openssh/openbsd-compat/port-linux.h.role-mls openssh/openbsd-compat/port-linux.h
--- openssh/openbsd-compat/port-linux.h.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/openbsd-compat/port-linux.h 2018-08-22 11:14:56.819430949 +0200
@@ -20,9 +20,10 @@
#ifdef WITH_SELINUX
int ssh_selinux_enabled(void);
void ssh_selinux_setup_pty(char *, const char *);
-void ssh_selinux_setup_exec_context(char *);
void ssh_selinux_change_context(const char *);
void ssh_selinux_setfscreatecon(const char *);
+
+void sshd_selinux_setup_exec_context(char *);
#endif
#ifdef LINUX_OOM_ADJUST
diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compat/port-linux-sshd.c
--- openssh/openbsd-compat/port-linux-sshd.c.role-mls 2018-08-22 11:14:56.819430949 +0200
+++ openssh/openbsd-compat/port-linux-sshd.c 2018-08-22 11:14:56.819430949 +0200
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com>
+ * Copyright (c) 2014 Petr Lautrbach <plautrba@redhat.com>
+ *
+ * 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 for sshd 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 <stdlib.h>
+
+#include "log.h"
+#include "xmalloc.h"
+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
+#include "servconf.h"
+#include "port-linux.h"
+#include "sshkey.h"
+#include "hostfile.h"
+#include "auth.h"
+
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/get_context_list.h>
+#include <selinux/get_default_type.h>
+
+#ifdef HAVE_LINUX_AUDIT
+#include <libaudit.h>
+#include <unistd.h>
+#endif
+
+extern ServerOptions options;
+extern Authctxt *the_authctxt;
+extern int inetd_flag;
+
+/* Send audit message */
+static int
+sshd_selinux_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;
+ access_vector_t bit;
+ security_class_t class;
+
+ debug_f("src:%s dst:%s", src, dst);
+ class = string_to_security_class("context");
+ if (!class) {
+ error("string_to_security_class failed to translate security class context");
+ return 1;
+ }
+ bit = string_to_av_perm(class, "contains");
+ if (!bit) {
+ error("string_to_av_perm failed to translate av perm contains");
+ return 1;
+ }
+ retval = security_compute_av(src, dst, class, 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)
+{
+ *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 the default security context for the given username */
+static int
+sshd_selinux_getctxbyname(char *pwname,
+ security_context_t *default_sc, security_context_t *user_sc)
+{
+ char *sename, *lvl;
+ char *role;
+ const char *reqlvl;
+ int r = 0;
+ context_t con = NULL;
+
+ ssh_selinux_get_role_level(&role, &reqlvl);
+
+#ifdef HAVE_GETSEUSERBYNAME
+ if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) {
+ sename = NULL;
+ lvl = NULL;
+ }
+#else
+ sename = pwname;
+ lvl = "";
+#endif
+
+ if (r == 0) {
+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+ r = get_default_context_with_level(sename, lvl, NULL, default_sc);
+#else
+ r = get_default_context(sename, NULL, default_sc);
+#endif
+ }
+
+ if (r == 0) {
+ /* If launched from xinetd, we must use current level */
+ if (inetd_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_f("current connection level '%s'", 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_f("Failed to get default SELinux security "
+ "context for %s", pwname);
+ }
+
+#ifdef HAVE_GETSEUSERBYNAME
+ free(sename);
+ free(lvl);
+#endif
+
+ if (role != NULL)
+ free(role);
+ if (con)
+ context_free(con);
+
+ return (r);
+}
+
+/* Setup environment variables for pam_selinux */
+static int
+sshd_selinux_setup_pam_variables(void)
+{
+ const char *reqlvl;
+ char *role;
+ char *use_current;
+ int rv;
+
+ debug3_f("setting execution context");
+
+ ssh_selinux_get_role_level(&role, &reqlvl);
+
+ rv = do_pam_putenv("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 || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current);
+
+ if (role != NULL)
+ free(role);
+
+ return rv;
+}
+
+/* Set the execution context to the default for the specified user */
+void
+sshd_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;
+
+ if (options.use_pam) {
+ /* do not compute context, just setup environment for pam_selinux */
+ if (sshd_selinux_setup_pam_variables()) {
+ switch (security_getenforce()) {
+ case -1:
+ fatal_f("security_getenforce() failed");
+ case 0:
+ error_f("SELinux PAM variable setup failure. Continuing in permissive mode.");
+ break;
+ default:
+ fatal_f("SELinux PAM variable setup failure. Aborting connection.");
+ }
+ }
+ return;
+ }
+
+ debug3_f("setting execution context");
+
+ r = sshd_selinux_getctxbyname(pwname, &default_ctx, &user_ctx);
+ if (r >= 0) {
+ r = setexeccon(user_ctx);
+ if (r < 0) {
+ error_f("Failed to set SELinux execution context %s for %s",
+ user_ctx, pwname);
+ }
+#ifdef HAVE_SETKEYCREATECON
+ else if (setkeycreatecon(user_ctx) < 0) {
+ error_f("Failed to set SELinux keyring creation context %s for %s",
+ 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 */
+ sshd_selinux_send_audit_message(r >= 0, default_ctx, user_ctx);
+ }
+ if (r < 0) {
+ switch (security_getenforce()) {
+ case -1:
+ fatal_f("security_getenforce() failed");
+ case 0:
+ error_f("ELinux failure. Continuing in permissive mode.");
+ break;
+ default:
+ fatal_f("SELinux failure. Aborting connection.");
+ }
+ }
+ if (user_ctx != NULL && user_ctx != default_ctx)
+ freecon(user_ctx);
+ if (default_ctx != NULL)
+ freecon(default_ctx);
+
+ debug3_f("done");
+}
+
+#endif
+#endif
+
diff -up openssh/platform.c.role-mls openssh/platform.c
--- openssh/platform.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/platform.c 2018-08-22 11:14:56.819430949 +0200
@@ -183,7 +183,7 @@ platform_setusercontext_post_groups(stru
}
#endif /* HAVE_SETPCRED */
#ifdef WITH_SELINUX
- ssh_selinux_setup_exec_context(pw->pw_name);
+ sshd_selinux_setup_exec_context(pw->pw_name);
#endif
}
diff -up openssh/sshd.c.role-mls openssh/sshd.c
--- openssh/sshd-session.c.role-mls 2018-08-20 07:57:29.000000000 +0200
+++ openssh/sshd-session.c 2018-08-22 11:14:56.820430957 +0200
@@ -2186,6 +2186,9 @@ main(int ac, char **av)
restore_uid();
}
#endif
+#ifdef WITH_SELINUX
+ sshd_selinux_setup_exec_context(authctxt->pw->pw_name);
+#endif
#ifdef USE_PAM
if (options.use_pam) {
do_pam_setcred();

@ -0,0 +1,16 @@
diff --git a/scp.c b/scp.c
index 60682c68..9344806e 100644
--- a/scp.c
+++ b/scp.c
@@ -714,7 +714,9 @@ toremote(int argc, char **argv)
addargs(&alist, "%s", host);
addargs(&alist, "%s", cmd);
addargs(&alist, "%s", src);
- addargs(&alist, "%s%s%s:%s",
+ addargs(&alist,
+ /* IPv6 address needs to be enclosed with sqare brackets */
+ strchr(host, ':') != NULL ? "%s%s[%s]:%s" : "%s%s%s:%s",
tuser ? tuser : "", tuser ? "@" : "",
thost, targ);
if (do_local_cmd(&alist) != 0)

@ -0,0 +1,642 @@
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh_config.5 openssh-9.3p1-patched/ssh_config.5
--- openssh-9.3p1/ssh_config.5 2023-06-07 10:26:48.284590156 +0200
+++ openssh-9.3p1-patched/ssh_config.5 2023-06-07 10:26:00.623052194 +0200
@@ -378,17 +378,13 @@
causes no CNAMEs to be considered for canonicalization.
This is the default behaviour.
.It Cm CASignatureAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies which algorithms are allowed for signing of certificates
by certificate authorities (CAs).
-The default is:
-.Bd -literal -offset indent
-ssh-ed25519,ecdsa-sha2-nistp256,
-ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
-.Pp
If the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
@@ -450,20 +446,25 @@
(the default),
the check will not be executed.
.It Cm Ciphers
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the ciphers allowed and their order of preference.
Multiple ciphers must be comma-separated.
If the specified list begins with a
.Sq +
-character, then the specified ciphers will be appended to the default set
-instead of replacing them.
+character, then the specified ciphers will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified ciphers (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified ciphers will be placed at the head of the
-default set.
+built-in openssh default set.
.Pp
The supported ciphers are:
.Bd -literal -offset indent
@@ -479,13 +480,6 @@
chacha20-poly1305@openssh.com
.Ed
.Pp
-The default is:
-.Bd -literal -offset indent
-chacha20-poly1305@openssh.com,
-aes128-ctr,aes192-ctr,aes256-ctr,
-aes128-gcm@openssh.com,aes256-gcm@openssh.com
-.Ed
-.Pp
The list of available ciphers may also be obtained using
.Qq ssh -Q cipher .
.It Cm ClearAllForwardings
@@ -885,6 +879,11 @@
The default is
.Dq no .
.It Cm GSSAPIKexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
The list of key exchange algorithms that are offered for GSSAPI
key exchange. Possible values are
.Bd -literal -offset 3n
@@ -897,10 +896,8 @@
gss-curve25519-sha256-
.Ed
.Pp
-The default is
-.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-,
-gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- .
This option only applies to connections using GSSAPI.
+.Pp
.It Cm HashKnownHosts
Indicates that
.Xr ssh 1
@@ -919,36 +916,25 @@
but may be manually hashed using
.Xr ssh-keygen 1 .
.It Cm HostbasedAcceptedAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the signature algorithms that will be used for hostbased
authentication as a comma-separated list of patterns.
Alternately if the specified list begins with a
.Sq +
character, then the specified signature algorithms will be appended
-to the default set instead of replacing them.
+to the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified signature algorithms (including wildcards)
-will be removed from the default set instead of replacing them.
+will be removed from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified signature algorithms will be placed
-at the head of the default set.
-The default for this option is:
-.Bd -literal -offset 3n
-ssh-ed25519-cert-v01@openssh.com,
-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-ecdsa-sha2-nistp384-cert-v01@openssh.com,
-ecdsa-sha2-nistp521-cert-v01@openssh.com,
-sk-ssh-ed25519-cert-v01@openssh.com,
-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-rsa-sha2-512-cert-v01@openssh.com,
-rsa-sha2-256-cert-v01@openssh.com,
-ssh-ed25519,
-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
+at the head of the built-in openssh default set.
.Pp
The
.Fl Q
@@ -1001,6 +987,17 @@
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostKeyAlgorithms .
+.Pp
+The proposed
+.Cm HostKeyAlgorithms
+during KEX are limited to the set of algorithms that is defined in
+.Cm PubkeyAcceptedAlgorithms
+and therefore they are indirectly affected by system-wide
+.Xr crypto_policies 7 .
+.Xr crypto_policies 7 can not handle the list of host key algorithms directly as doing so
+would break the order given by the
+.Pa known_hosts
+file.
.It Cm HostKeyAlias
Specifies an alias that should be used instead of the
real host name when looking up or saving the host key
@@ -1330,6 +1330,11 @@ it may be zero or more of:
and
.Cm pam .
.It Cm KexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the permitted KEX (Key Exchange) algorithms that will be used and
their preference order.
The selected algorithm will be the first algorithm in this list that
@@ -1338,29 +1343,17 @@ Multiple algorithms must be comma-separa
.Pp
If the specified list begins with a
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified methods will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
-default set.
-.Pp
-The default is:
-.Bd -literal -offset indent
-sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,
-mlkem768x25519-sha256,
-curve25519-sha256,curve25519-sha256@libssh.org,
-ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
-diffie-hellman-group-exchange-sha256,
-diffie-hellman-group16-sha512,
-diffie-hellman-group18-sha512,
-diffie-hellman-group14-sha256
-.Ed
.Pp
+built-in openssh default set.
The list of supported key exchange algorithms may also be obtained using
.Qq ssh -Q kex .
.It Cm KnownHostsCommand
@@ -1365,37 +1357,33 @@
file.
This option is intended for debugging and no overrides are enabled by default.
.It Cm MACs
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the MAC (message authentication code) algorithms
in order of preference.
The MAC algorithm is used for data integrity protection.
Multiple algorithms must be comma-separated.
If the specified list begins with a
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified algorithms will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
-default set.
+built-in openssh default set.
.Pp
The algorithms that contain
.Qq -etm
calculate the MAC after encryption (encrypt-then-mac).
These are considered safer and their use recommended.
.Pp
-The default is:
-.Bd -literal -offset indent
-umac-64-etm@openssh.com,umac-128-etm@openssh.com,
-hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
-hmac-sha1-etm@openssh.com,
-umac-64@openssh.com,umac-128@openssh.com,
-hmac-sha2-256,hmac-sha2-512,hmac-sha1
-.Ed
-.Pp
The list of available MAC algorithms may also be obtained using
.Qq ssh -Q mac .
.It Cm NoHostAuthenticationForLocalhost
@@ -1567,39 +1555,31 @@
The default is
.Cm no .
.It Cm PubkeyAcceptedAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the signature algorithms that will be used for public key
authentication as a comma-separated list of patterns.
If the specified list begins with a
.Sq +
-character, then the algorithms after it will be appended to the default
-instead of replacing it.
+character, then the algorithms after it will be appended to the built-in
+openssh default instead of replacing it.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
-default set.
-The default for this option is:
-.Bd -literal -offset 3n
-ssh-ed25519-cert-v01@openssh.com,
-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-ecdsa-sha2-nistp384-cert-v01@openssh.com,
-ecdsa-sha2-nistp521-cert-v01@openssh.com,
-sk-ssh-ed25519-cert-v01@openssh.com,
-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-rsa-sha2-512-cert-v01@openssh.com,
-rsa-sha2-256-cert-v01@openssh.com,
-ssh-ed25519,
-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
+built-in openssh default set.
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q PubkeyAcceptedAlgorithms .
+.Pp
+This option affects also
+.Cm HostKeyAlgorithms
.It Cm PubkeyAuthentication
Specifies whether to try public key authentication.
The argument to this keyword must be
@@ -2265,7 +2245,9 @@
This file must be world-readable.
.El
.Sh SEE ALSO
-.Xr ssh 1
+.Xr ssh 1 ,
+.Xr crypto-policies 7 ,
+.Xr update-crypto-policies 8
.Sh AUTHORS
.An -nosplit
OpenSSH is a derivative of the original and free
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshd_config.5 openssh-9.3p1-patched/sshd_config.5
--- openssh-9.3p1/sshd_config.5 2023-06-07 10:26:48.277590077 +0200
+++ openssh-9.3p1-patched/sshd_config.5 2023-06-07 10:26:00.592051845 +0200
@@ -379,17 +379,13 @@
then no banner is displayed.
By default, no banner is displayed.
.It Cm CASignatureAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies which algorithms are allowed for signing of certificates
by certificate authorities (CAs).
-The default is:
-.Bd -literal -offset indent
-ssh-ed25519,ecdsa-sha2-nistp256,
-ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
-.Pp
If the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
@@ -525,20 +521,25 @@
indicating not to
.Xr chroot 2 .
.It Cm Ciphers
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the ciphers allowed.
Multiple ciphers must be comma-separated.
If the specified list begins with a
.Sq +
-character, then the specified ciphers will be appended to the default set
-instead of replacing them.
+character, then the specified ciphers will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified ciphers (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified ciphers will be placed at the head of the
-default set.
+built-in openssh default set.
.Pp
The supported ciphers are:
.Pp
@@ -565,13 +566,6 @@
chacha20-poly1305@openssh.com
.El
.Pp
-The default is:
-.Bd -literal -offset indent
-chacha20-poly1305@openssh.com,
-aes128-ctr,aes192-ctr,aes256-ctr,
-aes128-gcm@openssh.com,aes256-gcm@openssh.com
-.Ed
-.Pp
The list of available ciphers may also be obtained using
.Qq ssh -Q cipher .
.It Cm ClientAliveCountMax
@@ -766,53 +760,43 @@
.Cm GSSAPIKeyExchange
needs to be enabled in the server and also used by the client.
.It Cm GSSAPIKexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
The list of key exchange algorithms that are accepted by GSSAPI
key exchange. Possible values are
.Bd -literal -offset 3n
-gss-gex-sha1-,
-gss-group1-sha1-,
-gss-group14-sha1-,
-gss-group14-sha256-,
-gss-group16-sha512-,
-gss-nistp256-sha256-,
+gss-gex-sha1-
+gss-group1-sha1-
+gss-group14-sha1-
+gss-group14-sha256-
+gss-group16-sha512-
+gss-nistp256-sha256-
gss-curve25519-sha256-
.Ed
-.Pp
-The default is
-.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-,
-gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- .
This option only applies to connections using GSSAPI.
.It Cm HostbasedAcceptedAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the signature algorithms that will be accepted for hostbased
authentication as a list of comma-separated patterns.
Alternately if the specified list begins with a
.Sq +
character, then the specified signature algorithms will be appended to
-the default set instead of replacing them.
+the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified signature algorithms (including wildcards)
-will be removed from the default set instead of replacing them.
+will be removed from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified signature algorithms will be placed at
-the head of the default set.
-The default for this option is:
-.Bd -literal -offset 3n
-ssh-ed25519-cert-v01@openssh.com,
-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-ecdsa-sha2-nistp384-cert-v01@openssh.com,
-ecdsa-sha2-nistp521-cert-v01@openssh.com,
-sk-ssh-ed25519-cert-v01@openssh.com,
-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-rsa-sha2-512-cert-v01@openssh.com,
-rsa-sha2-256-cert-v01@openssh.com,
-ssh-ed25519,
-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
+the head of the built-in openssh default set.
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostbasedAcceptedAlgorithms .
@@ -879,25 +863,14 @@
.Ev SSH_AUTH_SOCK
environment variable.
.It Cm HostKeyAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the host key signature algorithms
that the server offers.
The default for this option is:
-.Bd -literal -offset 3n
-ssh-ed25519-cert-v01@openssh.com,
-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-ecdsa-sha2-nistp384-cert-v01@openssh.com,
-ecdsa-sha2-nistp521-cert-v01@openssh.com,
-sk-ssh-ed25519-cert-v01@openssh.com,
-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-rsa-sha2-512-cert-v01@openssh.com,
-rsa-sha2-256-cert-v01@openssh.com,
-ssh-ed25519,
-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
-.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostKeyAlgorithms .
.It Cm IgnoreRhosts
@@ -1025,6 +1025,11 @@ Specifies whether to look at .k5login fi
The default is
.Cm yes .
.It Cm KexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the permitted KEX (Key Exchange) algorithms that the server will
offer to clients.
The ordering of this list is not important, as the client specifies the
@@ -1033,16 +1038,16 @@ Multiple algorithms must be comma-separa
.Pp
If the specified list begins with a
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified methods will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
-default set.
+built-in openssh default set.
.Pp
The supported algorithms are:
.Pp
@@ -1075,17 +1080,6 @@ ecdh-sha2-nistp521
sntrup761x25519-sha512@openssh.com
.El
.Pp
-The default is:
-.Bd -literal -offset indent
-sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,
-mlkem768x25519-sha256,
-curve25519-sha256,curve25519-sha256@libssh.org,
-ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
-diffie-hellman-group-exchange-sha256,
-diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,
-diffie-hellman-group14-sha256
-.Ed
-.Pp
The list of supported key exchange algorithms may also be obtained using
.Qq ssh -Q KexAlgorithms .
.It Cm ListenAddress
@@ -1184,21 +1152,26 @@
file.
This option is intended for debugging and no overrides are enabled by default.
.It Cm MACs
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the available MAC (message authentication code) algorithms.
The MAC algorithm is used for data integrity protection.
Multiple algorithms must be comma-separated.
If the specified list begins with a
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified algorithms will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
-default set.
+built-in openssh default set.
.Pp
The algorithms that contain
.Qq -etm
@@ -1241,15 +1214,6 @@
umac-128-etm@openssh.com
.El
.Pp
-The default is:
-.Bd -literal -offset indent
-umac-64-etm@openssh.com,umac-128-etm@openssh.com,
-hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,
-hmac-sha1-etm@openssh.com,
-umac-64@openssh.com,umac-128@openssh.com,
-hmac-sha2-256,hmac-sha2-512,hmac-sha1
-.Ed
-.Pp
The list of available MAC algorithms may also be obtained using
.Qq ssh -Q mac .
.It Cm Match
@@ -1633,36 +1597,25 @@
The default is
.Cm yes .
.It Cm PubkeyAcceptedAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the signature algorithms that will be accepted for public key
authentication as a list of comma-separated patterns.
Alternately if the specified list begins with a
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified algorithms will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
character, then the specified algorithms (including wildcards) will be removed
-from the default set instead of replacing them.
+from the built-in openssh default set instead of replacing them.
If the specified list begins with a
.Sq ^
character, then the specified algorithms will be placed at the head of the
-default set.
-The default for this option is:
-.Bd -literal -offset 3n
-ssh-ed25519-cert-v01@openssh.com,
-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-ecdsa-sha2-nistp384-cert-v01@openssh.com,
-ecdsa-sha2-nistp521-cert-v01@openssh.com,
-sk-ssh-ed25519-cert-v01@openssh.com,
-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,
-rsa-sha2-512-cert-v01@openssh.com,
-rsa-sha2-256-cert-v01@openssh.com,
-ssh-ed25519,
-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
-sk-ssh-ed25519@openssh.com,
-sk-ecdsa-sha2-nistp256@openssh.com,
-rsa-sha2-512,rsa-sha2-256
-.Ed
+built-in openssh default set.
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q PubkeyAcceptedAlgorithms .
@@ -2131,7 +2084,9 @@
.El
.Sh SEE ALSO
.Xr sftp-server 8 ,
-.Xr sshd 8
+.Xr sshd 8 ,
+.Xr crypto-policies 7 ,
+.Xr update-crypto-policies 8
.Sh AUTHORS
.An -nosplit
OpenSSH is a derivative of the original and free

@ -0,0 +1,12 @@
diff -up openssh-8.0p1/ssh-keygen.c.strip-doseol openssh-8.0p1/ssh-keygen.c
--- openssh-8.0p1/ssh-keygen.c.strip-doseol 2021-03-18 17:41:34.472404994 +0100
+++ openssh-8.0p1/ssh-keygen.c 2021-03-18 17:41:55.255538761 +0100
@@ -901,7 +901,7 @@ do_fingerprint(struct passwd *pw)
while (getline(&line, &linesize, f) != -1) {
lnum++;
cp = line;
- cp[strcspn(cp, "\n")] = '\0';
+ cp[strcspn(cp, "\r\n")] = '\0';
/* Trim leading space and comments */
cp = line + strspn(line, " \t");
if (*cp == '#' || *cp == '\0')

@ -0,0 +1,151 @@
commit 2c3ef499bfffce3cfd315edeebf202850ba4e00a
Author: Jakub Jelen <jjelen@redhat.com>
Date: Tue Apr 16 15:35:18 2019 +0200
Use the new OpenSSL KDF
diff --git a/configure.ac b/configure.ac
index 2a455e4e..e01c3d43 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2712,6 +2712,7 @@ if test "x$openssl" = "xyes" ; then
HMAC_CTX_init \
RSA_generate_key_ex \
RSA_get_default_method \
+ EVP_KDF_CTX_new \
])
# OpenSSL_add_all_algorithms may be a macro.
diff --git a/kex.c b/kex.c
index b6f041f4..1fbce2bb 100644
--- a/kex.c
+++ b/kex.c
@@ -38,6 +38,11 @@
#ifdef WITH_OPENSSL
#include <openssl/crypto.h>
#include <openssl/dh.h>
+# ifdef HAVE_EVP_KDF_CTX_NEW
+# include <openssl/kdf.h>
+# include <openssl/param_build.h>
+# include <openssl/core_names.h>
+# endif
#endif
#include "ssh.h"
@@ -942,6 +945,107 @@ kex_choose_conf(struct ssh *ssh)
return r;
}
+#ifdef HAVE_EVP_KDF_CTX_NEW
+static const char *
+digest_to_md(int digest_type)
+{
+ switch (digest_type) {
+ case SSH_DIGEST_SHA1:
+ return SN_sha1;
+ case SSH_DIGEST_SHA256:
+ return SN_sha256;
+ case SSH_DIGEST_SHA384:
+ return SN_sha384;
+ case SSH_DIGEST_SHA512:
+ return SN_sha512;
+ }
+ return NULL;
+}
+
+static int
+derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
+ const struct sshbuf *shared_secret, u_char **keyp)
+{
+ struct kex *kex = ssh->kex;
+ u_char *key = NULL;
+ int r, key_len;
+
+ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSHKDF", NULL);
+ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
+ OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new();
+ OSSL_PARAM *params = NULL;
+ const char *md = digest_to_md(kex->hash_alg);
+ char keytype = (char)id;
+
+ EVP_KDF_free(kdf);
+ if (!ctx) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (md == NULL) {
+ r = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ if (param_bld == NULL) {
+ EVP_KDF_CTX_free(ctx);
+ return -1;
+ }
+ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) {
+ r = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ key_len = ROUNDUP(need, key_len);
+ if ((key = calloc(1, key_len)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+
+ r = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_DIGEST,
+ md, strlen(md)) && /* SN */
+ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_KEY,
+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)) &&
+ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_XCGHASH,
+ hash, hashlen) &&
+ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_SESSION_ID,
+ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)) &&
+ OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_SSHKDF_TYPE,
+ &keytype, 1);
+ if (r != 1) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+ params = OSSL_PARAM_BLD_to_param(param_bld);
+ if (params == NULL) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ r = EVP_KDF_derive(ctx, key, key_len, params);
+ if (r != 1) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+#ifdef DEBUG_KEX
+ fprintf(stderr, "key '%c'== ", id);
+ dump_digest("key", key, key_len);
+#endif
+ *keyp = key;
+ key = NULL;
+ r = 0;
+
+out:
+ OSSL_PARAM_BLD_free(param_bld);
+ OSSL_PARAM_free(params);
+ free (key);
+ EVP_KDF_CTX_free(ctx);
+ if (r < 0) {
+ return r;
+ }
+ return 0;
+}
+#else
static int
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
const struct sshbuf *shared_secret, u_char **keyp)
@@ -1004,6 +1096,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
ssh_digest_free(hashctx);
return r;
}
+#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW */
#define NKEYS 6
int

File diff suppressed because it is too large Load Diff

@ -0,0 +1,43 @@
diff -up openssh-8.0p1/auth-pam.c.preserve-pam-errors openssh-8.0p1/auth-pam.c
--- openssh-8.0p1/auth-pam.c.preserve-pam-errors 2021-03-31 17:03:15.618592347 +0200
+++ openssh-8.0p1/auth-pam.c 2021-03-31 17:06:58.115220014 +0200
@@ -511,7 +511,11 @@ sshpam_thread(void *ctxtp)
goto auth_fail;
if (!do_pam_account()) {
- sshpam_err = PAM_ACCT_EXPIRED;
+ /* Preserve PAM_PERM_DENIED and PAM_USER_UNKNOWN.
+ * Backward compatibility for other errors. */
+ if (sshpam_err != PAM_PERM_DENIED
+ && sshpam_err != PAM_USER_UNKNOWN)
+ sshpam_err = PAM_ACCT_EXPIRED;
goto auth_fail;
}
if (sshpam_authctxt->force_pwchange) {
@@ -568,8 +572,10 @@ sshpam_thread(void *ctxtp)
pam_strerror(sshpam_handle, sshpam_err))) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
/* XXX - can't do much about an error here */
- if (sshpam_err == PAM_ACCT_EXPIRED)
- ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer);
+ if (sshpam_err == PAM_PERM_DENIED
+ || sshpam_err == PAM_USER_UNKNOWN
+ || sshpam_err == PAM_ACCT_EXPIRED)
+ ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer);
else if (sshpam_maxtries_reached)
ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer);
else
@@ -856,9 +862,11 @@ sshpam_query(void *ctx, char **name, cha
free(msg);
break;
case PAM_ACCT_EXPIRED:
+ sshpam_account_status = 0;
+ /* FALLTHROUGH */
case PAM_MAXTRIES:
+ case PAM_USER_UNKNOWN:
+ case PAM_PERM_DENIED:
- if (type == PAM_ACCT_EXPIRED)
- sshpam_account_status = 0;
if (type == PAM_MAXTRIES)
sshpam_set_maxtries_reached(1);
/* FALLTHROUGH */

@ -0,0 +1,40 @@
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c
index dca158de..afdcb1d2 100644
--- a/regress/misc/sk-dummy/sk-dummy.c
+++ b/regress/misc/sk-dummy/sk-dummy.c
@@ -71,7 +71,7 @@ skdebug(const char *func, const char *fmt, ...)
#endif
}
-uint32_t
+uint32_t __attribute__((visibility("default")))
sk_api_version(void)
{
return SSH_SK_VERSION_MAJOR;
@@ -220,7 +220,7 @@ check_options(struct sk_option **options)
return 0;
}
-int
+int __attribute__((visibility("default")))
sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
const char *application, uint8_t flags, const char *pin,
struct sk_option **options, struct sk_enroll_response **enroll_response)
@@ -467,7 +467,7 @@ sig_ed25519(const uint8_t *message, size_t message_len,
return ret;
}
-int
+int __attribute__((visibility("default")))
sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
const char *application, const uint8_t *key_handle, size_t key_handle_len,
uint8_t flags, const char *pin, struct sk_option **options,
@@ -518,7 +518,7 @@ sk_sign(uint32_t alg, const uint8_t *message, size_t message_len,
return ret;
}
-int
+int __attribute__((visibility("default")))
sk_load_resident_keys(const char *pin, struct sk_option **options,
struct sk_resident_key ***rks, size_t *nrks)
{

@ -0,0 +1,30 @@
diff --git a/channels.c b/channels.c
--- a/channels.c
+++ b/channels.c
@@ -3933,16 +3933,26 @@ x11_create_display_inet(int x11_display_
if (ai->ai_family == AF_INET6)
sock_set_v6only(sock);
if (x11_use_localhost)
set_reuseaddr(sock);
if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
debug2_f("bind port %d: %.100s", port,
strerror(errno));
close(sock);
+
+ /* do not remove successfully opened
+ * sockets if the request failed because
+ * the protocol IPv4/6 is not available
+ * (e.g. IPv6 may be disabled while being
+ * supported)
+ */
+ if (EADDRNOTAVAIL == errno)
+ continue;
+
for (n = 0; n < num_socks; n++)
close(socks[n]);
num_socks = 0;
break;
}
socks[num_socks++] = sock;
if (num_socks == NUM_SOCKS)
break;

@ -0,0 +1,11 @@
--- openssh-8.7p1/openbsd-compat/bsd-closefrom.c.orig 2022-04-12 15:47:03.815044607 +0200
+++ openssh-8.7p1/openbsd-compat/bsd-closefrom.c 2022-04-12 15:48:12.464963511 +0200
@@ -16,7 +16,7 @@
#include "includes.h"
-#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM)
+#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) || (defined __s390__)
#include <sys/types.h>
#include <unistd.h>

@ -0,0 +1,22 @@
diff --git a/readconf.c b/readconf.c
--- a/readconf.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/readconf.c (date 1703169891147)
@@ -326,6 +326,7 @@
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
{ "requiredrsasize", oRequiredRSASize },
+ { "rsaminsize", oRequiredRSASize }, /* alias */
{ "enableescapecommandline", oEnableEscapeCommandline },
{ "obscurekeystroketiming", oObscureKeystrokeTiming },
{ "channeltimeout", oChannelTimeout },
diff --git a/servconf.c b/servconf.c
--- a/servconf.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/servconf.c (date 1703169891148)
@@ -691,6 +691,7 @@
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
+ { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */
{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
{ "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
{ "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL },

@ -0,0 +1,118 @@
diff -up openssh-9.3p1/regress/hostkey-agent.sh.xxx openssh-9.3p1/regress/hostkey-agent.sh
--- openssh-9.3p1/regress/hostkey-agent.sh.xxx 2023-05-29 18:15:56.311236887 +0200
+++ openssh-9.3p1/regress/hostkey-agent.sh 2023-05-29 18:16:07.598503551 +0200
@@ -17,8 +17,21 @@ trace "make CA key"
${SSHKEYGEN} -qt ed25519 -f $OBJ/agent-ca -N '' || fatal "ssh-keygen CA"
+PUBKEY_ACCEPTED_ALGOS=`$SSH -G "example.com" | \
+ grep -i "PubkeyAcceptedAlgorithms" | cut -d ' ' -f2- | tr "," "|"`
+SSH_ACCEPTED_KEYTYPES=`echo "$SSH_KEYTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"`
+echo $PUBKEY_ACCEPTED_ALGOS | grep "rsa"
+r=$?
+if [ $r == 0 ]; then
+echo $SSH_ACCEPTED_KEYTYPES | grep "rsa"
+r=$?
+if [ $r -ne 0 ]; then
+SSH_ACCEPTED_KEYTYPES="$SSH_ACCEPTED_KEYTYPES ssh-rsa"
+fi
+fi
+
trace "load hostkeys"
-for k in $SSH_KEYTYPES ; do
+for k in $SSH_ACCEPTED_KEYTYPES ; do
${SSHKEYGEN} -qt $k -f $OBJ/agent-key.$k -N '' || fatal "ssh-keygen $k"
${SSHKEYGEN} -s $OBJ/agent-ca -qh -n localhost-with-alias \
-I localhost-with-alias $OBJ/agent-key.$k.pub || \
@@ -32,12 +48,16 @@ rm $OBJ/agent-ca # Don't need CA private
unset SSH_AUTH_SOCK
-for k in $SSH_KEYTYPES ; do
+for k in $SSH_ACCEPTED_KEYTYPES ; do
verbose "key type $k"
+ hka=$k
+ if [ $k = "ssh-rsa" ]; then
+ hka="rsa-sha2-512"
+ fi
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
- echo "HostKeyAlgorithms $k" >> $OBJ/sshd_proxy
+ echo "HostKeyAlgorithms $hka" >> $OBJ/sshd_proxy
echo "Hostkey $OBJ/agent-key.${k}" >> $OBJ/sshd_proxy
- opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy"
+ opts="-oHostKeyAlgorithms=$hka -F $OBJ/ssh_proxy"
( printf 'localhost-with-alias,127.0.0.1,::1 ' ;
cat $OBJ/agent-key.$k.pub) > $OBJ/known_hosts
SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'`
@@ -50,15 +70,16 @@ for k in $SSH_KEYTYPES ; do
done
SSH_CERTTYPES=`ssh -Q key-sig | grep 'cert-v01@openssh.com'`
+SSH_ACCEPTED_CERTTYPES=`echo "$SSH_CERTTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"`
# Prepare sshd_proxy for certificates.
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
HOSTKEYALGS=""
-for k in $SSH_CERTTYPES ; do
+for k in $SSH_ACCEPTED_CERTTYPES ; do
test -z "$HOSTKEYALGS" || HOSTKEYALGS="${HOSTKEYALGS},"
HOSTKEYALGS="${HOSTKEYALGS}${k}"
done
-for k in $SSH_KEYTYPES ; do
+for k in $SSH_ACCEPTED_KEYTYPES ; do
echo "Hostkey $OBJ/agent-key.${k}.pub" >> $OBJ/sshd_proxy
echo "HostCertificate $OBJ/agent-key.${k}-cert.pub" >> $OBJ/sshd_proxy
test -f $OBJ/agent-key.${k}.pub || fatal "no $k key"
@@ -70,7 +93,7 @@ echo "HostKeyAlgorithms $HOSTKEYALGS" >>
( printf '@cert-authority localhost-with-alias ' ;
cat $OBJ/agent-ca.pub) > $OBJ/known_hosts
-for k in $SSH_CERTTYPES ; do
+for k in $SSH_ACCEPTED_CERTTYPES ; do
verbose "cert type $k"
opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy"
SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'`
diff -up openssh-9.3p1/sshconnect2.c.xxx openssh-9.3p1/sshconnect2.c
--- openssh-9.3p1/sshconnect2.c.xxx 2023-04-26 17:37:35.100827792 +0200
+++ openssh-9.3p1/sshconnect2.c 2023-04-26 17:50:31.860748877 +0200
@@ -221,7 +221,7 @@ ssh_kex2(struct ssh *ssh, char *host, st
const struct ssh_conn_info *cinfo)
{
char *myproposal[PROPOSAL_MAX];
- char *all_key, *hkalgs = NULL;
+ char *all_key, *hkalgs = NULL, *filtered_algs = NULL;
int r, use_known_hosts_order = 0;
#if defined(GSSAPI) && defined(WITH_OPENSSL)
@@ -260,10 +260,22 @@ ssh_kex2(struct ssh *ssh, char *host, st
if (use_known_hosts_order)
hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo);
+ filtered_algs = hkalgs ? match_filter_allowlist(hkalgs, options.pubkey_accepted_algos)
+ : match_filter_allowlist(options.hostkeyalgorithms,
+ options.pubkey_accepted_algos);
+ if (filtered_algs == NULL) {
+ if (hkalgs)
+ fatal_f("No match between algorithms for %s (host %s) and pubkey accepted algorithms %s",
+ hkalgs, host, options.pubkey_accepted_algos);
+ else
+ fatal_f("No match between host key algorithms %s and pubkey accepted algorithms %s",
+ options.hostkeyalgorithms, options.pubkey_accepted_algos);
+ }
+
kex_proposal_populate_entries(ssh, myproposal,
options.kex_algorithms, options.ciphers, options.macs,
compression_alg_list(options.compression),
- hkalgs ? hkalgs : options.hostkeyalgorithms);
+ filtered_algs);
#if defined(GSSAPI) && defined(WITH_OPENSSL)
if (options.gss_keyex) {
@@ -303,6 +315,7 @@ ssh_kex2(struct ssh *ssh, char *host, st
#endif
free(hkalgs);
+ free(filtered_algs);
/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)

@ -0,0 +1,297 @@
diff -up openssh-8.7p1/compat.c.sshrsacheck openssh-8.7p1/compat.c
--- openssh-8.7p1/compat.c.sshrsacheck 2023-01-12 13:29:06.338710923 +0100
+++ openssh-8.7p1/compat.c 2023-01-12 13:29:06.357711165 +0100
@@ -43,6 +43,7 @@ void
compat_banner(struct ssh *ssh, const char *version)
{
int i;
+ int forbid_ssh_rsa = 0;
static struct {
char *pat;
int bugs;
@@ -145,16 +146,21 @@ compat_banner(struct ssh *ssh, const cha
};
/* process table, return first match */
+ forbid_ssh_rsa = (ssh->compat & SSH_RH_RSASIGSHA);
ssh->compat = 0;
for (i = 0; check[i].pat; i++) {
if (match_pattern_list(version, check[i].pat, 0) == 1) {
debug_f("match: %s pat %s compat 0x%08x",
version, check[i].pat, check[i].bugs);
ssh->compat = check[i].bugs;
+ if (forbid_ssh_rsa)
+ ssh->compat |= SSH_RH_RSASIGSHA;
return;
}
}
debug_f("no match: %s", version);
+ if (forbid_ssh_rsa)
+ ssh->compat |= SSH_RH_RSASIGSHA;
}
/* Always returns pointer to allocated memory, caller must free. */
diff -up openssh-8.7p1/compat.h.sshrsacheck openssh-8.7p1/compat.h
--- openssh-8.7p1/compat.h.sshrsacheck 2021-08-20 06:03:49.000000000 +0200
+++ openssh-8.7p1/compat.h 2023-01-12 13:29:06.358711178 +0100
@@ -30,7 +30,7 @@
#define SSH_BUG_UTF8TTYMODE 0x00000001
#define SSH_BUG_SIGTYPE 0x00000002
#define SSH_BUG_SIGTYPE74 0x00000004
-/* #define unused 0x00000008 */
+#define SSH_RH_RSASIGSHA 0x00000008
#define SSH_OLD_SESSIONID 0x00000010
/* #define unused 0x00000020 */
#define SSH_BUG_DEBUG 0x00000040
diff -up openssh-8.7p1/monitor.c.sshrsacheck openssh-8.7p1/monitor.c
--- openssh-8.7p1/monitor.c.sshrsacheck 2023-01-20 13:07:54.279676981 +0100
+++ openssh-8.7p1/monitor.c 2023-01-20 15:01:07.007821379 +0100
@@ -660,11 +660,12 @@ mm_answer_sign(struct ssh *ssh, int sock
struct sshkey *key;
struct sshbuf *sigbuf = NULL;
u_char *p = NULL, *signature = NULL;
- char *alg = NULL;
+ char *alg = NULL, *effective_alg;
size_t datlen, siglen, alglen;
int r, is_proof = 0;
u_int keyid, compat;
const char proof_req[] = "hostkeys-prove-00@openssh.com";
+ const char safe_rsa[] = "rsa-sha2-256";
debug3_f("entering");
@@ -719,18 +720,30 @@ mm_answer_sign(struct ssh *ssh, int sock
}
if ((key = get_hostkey_by_index(keyid)) != NULL) {
- if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg,
+ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0
+ && (sshkey_type_plain(key->type) == KEY_RSA)) {
+ effective_alg = safe_rsa;
+ } else {
+ effective_alg = alg;
+ }
+ if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, effective_alg,
options.sk_provider, NULL, compat)) != 0)
fatal_fr(r, "sign");
} else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL &&
auth_sock > 0) {
+ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0
+ && (sshkey_type_plain(key->type) == KEY_RSA)) {
+ effective_alg = safe_rsa;
+ } else {
+ effective_alg = alg;
+ }
if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen,
- p, datlen, alg, compat)) != 0)
+ p, datlen, effective_alg, compat)) != 0)
fatal_fr(r, "agent sign");
} else
fatal_f("no hostkey from index %d", keyid);
- debug3_f("%s %s signature len=%zu", alg,
+ debug3_f("%s (effective: %s) %s signature len=%zu", alg, effective_alg,
is_proof ? "hostkey proof" : "KEX", siglen);
sshbuf_reset(m);
diff -up openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck openssh-8.7p1/regress/unittests/kex/test_kex.c
--- openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck 2023-01-26 13:34:52.645743677 +0100
+++ openssh-8.7p1/regress/unittests/kex/test_kex.c 2023-01-26 13:36:56.220745823 +0100
@@ -97,7 +97,8 @@ do_kex_with_key(char *kex, int keytype,
memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
if (kex != NULL)
kex_params.proposal[PROPOSAL_KEX_ALGS] = kex;
- keyname = strdup(sshkey_ssh_name(private));
+ keyname = (strcmp(sshkey_ssh_name(private), "ssh-rsa")) ?
+ strdup(sshkey_ssh_name(private)) : strdup("rsa-sha2-256");
ASSERT_PTR_NE(keyname, NULL);
kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0);
diff -up openssh-8.7p1/regress/unittests/sshkey/test_file.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_file.c
--- openssh-8.7p1/regress/unittests/sshkey/test_file.c.sshrsacheck 2023-01-26 12:04:55.946343408 +0100
+++ openssh-8.7p1/regress/unittests/sshkey/test_file.c 2023-01-26 12:06:35.235164432 +0100
@@ -110,6 +110,7 @@ sshkey_file_tests(void)
sshkey_free(k2);
TEST_DONE();
+ /* Skip this test, SHA1 signatures are not supported
TEST_START("load RSA cert with SHA1 signature");
ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha1"), &k2), 0);
ASSERT_PTR_NE(k2, NULL);
@@ -117,7 +118,7 @@ sshkey_file_tests(void)
ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
ASSERT_STRING_EQ(k2->cert->signature_type, "ssh-rsa");
sshkey_free(k2);
- TEST_DONE();
+ TEST_DONE(); */
TEST_START("load RSA cert with SHA512 signature");
ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha512"), &k2), 0);
diff -up openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c
--- openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck 2023-01-26 12:10:37.533168013 +0100
+++ openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c 2023-01-26 12:15:35.637631860 +0100
@@ -333,13 +333,14 @@ sshkey_fuzz_tests(void)
TEST_DONE();
#ifdef WITH_OPENSSL
+ /* Skip this test, SHA1 signatures are not supported
TEST_START("fuzz RSA sig");
buf = load_file("rsa_1");
ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
sshbuf_free(buf);
sig_fuzz(k1, "ssh-rsa");
sshkey_free(k1);
- TEST_DONE();
+ TEST_DONE();*/
TEST_START("fuzz RSA SHA256 sig");
buf = load_file("rsa_1");
diff -up openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c
--- openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck 2023-01-26 11:02:52.339413463 +0100
+++ openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c 2023-01-26 11:58:42.324253896 +0100
@@ -60,6 +60,9 @@ build_cert(struct sshbuf *b, struct sshk
u_char *sigblob;
size_t siglen;
+ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */
+ int expected = (sig_alg == NULL || strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0;
+
ca_buf = sshbuf_new();
ASSERT_PTR_NE(ca_buf, NULL);
ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0);
@@ -101,8 +104,9 @@ build_cert(struct sshbuf *b, struct sshk
ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */
ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */
ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen,
- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0);
- ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */
+ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), expected);
+ if (expected == 0)
+ ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */
free(sigblob);
sshbuf_free(ca_buf);
@@ -119,16 +123,22 @@ signature_test(struct sshkey *k, struct
{
size_t len;
u_char *sig;
+ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp in RHEL, permitted in Fedora */
+ int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0) : 0;
+ if (k && (sshkey_type_plain(k->type) == KEY_DSA || sshkey_type_plain(k->type) == KEY_DSA_CERT))
+ expected = sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0);
ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg,
- NULL, NULL, 0), 0);
- ASSERT_SIZE_T_GT(len, 8);
- ASSERT_PTR_NE(sig, NULL);
- ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
- ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0);
- /* Fuzz test is more comprehensive, this is just a smoke test */
- sig[len - 5] ^= 0x10;
- ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
+ NULL, NULL, 0), expected);
+ if (expected == 0) {
+ ASSERT_SIZE_T_GT(len, 8);
+ ASSERT_PTR_NE(sig, NULL);
+ ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
+ ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0);
+ /* Fuzz test is more comprehensive, this is just a smoke test */
+ sig[len - 5] ^= 0x10;
+ ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
+ }
free(sig);
}
@@ -514,7 +524,7 @@ sshkey_tests(void)
ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2,
NULL), 0);
k3 = get_private("rsa_1");
- build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL);
+ build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, "rsa-sha2-256");
ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4),
SSH_ERR_KEY_CERT_INVALID_SIGN_KEY);
ASSERT_PTR_EQ(k4, NULL);
diff -up openssh-8.7p1/serverloop.c.sshrsacheck openssh-8.7p1/serverloop.c
--- openssh-8.7p1/serverloop.c.sshrsacheck 2023-01-12 14:57:08.118400073 +0100
+++ openssh-8.7p1/serverloop.c 2023-01-12 14:59:17.330470518 +0100
@@ -80,6 +80,7 @@
#include "auth-options.h"
#include "serverloop.h"
#include "ssherr.h"
+#include "compat.h"
extern ServerOptions options;
@@ -737,6 +737,10 @@ server_input_hostkeys_prove(struct ssh *
else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED)
sigalg = "rsa-sha2-256";
}
+ if (ssh->compat & SSH_RH_RSASIGSHA && sigalg == NULL) {
+ sigalg = "rsa-sha2-512";
+ debug3_f("SHA1 signature is not supported, falling back to %s", sigalg);
+ }
debug3_f("sign %s key (index %d) using sigalg %s",
sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg);
if ((r = sshbuf_put_cstring(sigbuf,
diff -up openssh-8.7p1/sshconnect2.c.sshrsacheck openssh-8.7p1/sshconnect2.c
--- openssh-8.7p1/sshconnect2.c.sshrsacheck 2023-01-25 15:33:29.140353651 +0100
+++ openssh-8.7p1/sshconnect2.c 2023-01-25 15:59:34.225364883 +0100
@@ -1461,6 +1464,14 @@ identity_sign(struct identity *id, u_cha
retried = 1;
goto retry_pin;
}
+ if ((r == SSH_ERR_LIBCRYPTO_ERROR) && strcmp("ssh-rsa", alg)) {
+ char rsa_safe_alg[] = "rsa-sha2-512";
+ debug3_f("trying to fallback to algorithm %s", rsa_safe_alg);
+
+ if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
+ rsa_safe_alg, options.sk_provider, pin, compat)) != 0)
+ debug_fr(r, "sshkey_sign - RSA fallback");
+ }
goto out;
}
diff -up openssh-8.7p1/ssh-rsa.c.sshrsacheck openssh-8.7p1/ssh-rsa.c
--- openssh-8.7p1/ssh-rsa.c.sshrsacheck 2023-01-20 13:07:54.180676144 +0100
+++ openssh-8.7p1/ssh-rsa.c 2023-01-20 13:07:54.290677074 +0100
@@ -254,7 +254,8 @@ ssh_rsa_verify(const struct sshkey *key,
ret = SSH_ERR_INVALID_ARGUMENT;
goto out;
}
- if (hash_alg != want_alg) {
+ if (hash_alg != want_alg && want_alg != SSH_DIGEST_SHA1) {
+ debug_f("Unexpected digest algorithm: got %d, wanted %d", hash_alg, want_alg);
ret = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
diff -up openssh-9.8p1/sshd-session.c.xxx openssh-9.8p1/sshd-session.c
--- openssh-9.8p1/sshd-session.c.xxx 2024-07-23 15:08:14.794350818 +0200
+++ openssh-9.8p1/sshd-session.c 2024-07-23 15:40:21.658456636 +0200
@@ -1305,6 +1305,27 @@ main(int ac, char **av)
check_ip_options(ssh);
+ {
+ struct sshkey *rsakey = NULL;
+ rsakey = get_hostkey_private_by_type(KEY_RSA, 0, ssh);
+ if (rsakey == NULL)
+ rsakey = get_hostkey_private_by_type(KEY_RSA_CERT, 0, ssh);
+
+ if (rsakey != NULL) {
+ size_t sign_size = 0;
+ u_char *tmp = NULL;
+ u_char data[] = "Test SHA1 vector";
+ int res;
+
+ res = sshkey_sign(rsakey, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0);
+ free(tmp);
+ if (res == SSH_ERR_LIBCRYPTO_ERROR) {
+ verbose_f("SHA1 in signatures is disabled for RSA keys");
+ ssh->compat |= SSH_RH_RSASIGSHA;
+ }
+ }
+ }
+
/* Prepare the channels layer */
channel_init_channels(ssh);
channel_set_af(ssh, options.address_family);

@ -0,0 +1,182 @@
diff --git a/scp.c b/scp.c
--- a/scp.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/scp.c (date 1703111453316)
@@ -1372,7 +1372,7 @@
if (src_is_dir && iamrecursive) {
if (sftp_upload_dir(conn, src, abs_dst, pflag,
- SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
+ SFTP_PROGRESS_ONLY, 0, 0, 1, 1, 1) != 0) {
error("failed to upload directory %s to %s", src, targ);
errs = 1;
}
diff --git a/sftp-client.c b/sftp-client.c
--- a/sftp-client.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/sftp-client.c (date 1703169614263)
@@ -1003,7 +1003,7 @@
/* Implements both the realpath and expand-path operations */
static char *
-sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
+sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir)
{
struct sshbuf *msg;
u_int expected_id, count, id;
@@ -1049,11 +1049,43 @@
if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
(r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
fatal_fr(r, "parse status");
- error("%s %s: %s", expand ? "expand" : "realpath",
- path, *errmsg == '\0' ? fx2txt(status) : errmsg);
- free(errmsg);
- sshbuf_free(msg);
- return NULL;
+ if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir) {
+ memset(&a, '\0', sizeof(a));
+ if ((r = sftp_mkdir(conn, path, &a, 0)) != 0) {
+ sshbuf_free(msg);
+ return NULL;
+ }
+ debug2("Sending SSH2_FXP_REALPATH \"%s\" - create dir", path);
+ send_string_request(conn, id, SSH2_FXP_REALPATH,
+ path, strlen(path));
+
+ get_msg(conn, msg);
+ if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
+ (r = sshbuf_get_u32(msg, &id)) != 0)
+ fatal_fr(r, "parse");
+
+ if (id != expected_id)
+ fatal("ID mismatch (%u != %u)", id, expected_id);
+
+ if (type == SSH2_FXP_STATUS) {
+ free(errmsg);
+
+ if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
+ (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
+ fatal_fr(r, "parse status");
+ error("%s %s: %s", expand ? "expand" : "realpath",
+ path, *errmsg == '\0' ? fx2txt(status) : errmsg);
+ free(errmsg);
+ sshbuf_free(msg);
+ return NULL;
+ }
+ } else {
+ error("%s %s: %s", expand ? "expand" : "realpath",
+ path, *errmsg == '\0' ? fx2txt(status) : errmsg);
+ free(errmsg);
+ sshbuf_free(msg);
+ return NULL;
+ }
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
SSH2_FXP_NAME, type);
@@ -1078,9 +1110,9 @@
}
char *
-sftp_realpath(struct sftp_conn *conn, const char *path)
+sftp_realpath(struct sftp_conn *conn, const char *path, int create_dir)
{
- return sftp_realpath_expand(conn, path, 0);
+ return sftp_realpath_expand(conn, path, 0, create_dir);
}
int
@@ -1094,9 +1126,9 @@
{
if (!sftp_can_expand_path(conn)) {
debug3_f("no server support, fallback to realpath");
- return sftp_realpath_expand(conn, path, 0);
+ return sftp_realpath_expand(conn, path, 0, 0);
}
- return sftp_realpath_expand(conn, path, 1);
+ return sftp_realpath_expand(conn, path, 1, 0);
}
int
@@ -2016,7 +2048,7 @@
char *src_canon;
int ret;
- if ((src_canon = sftp_realpath(conn, src)) == NULL) {
+ if ((src_canon = sftp_realpath(conn, src, 0)) == NULL) {
error("download \"%s\": path canonicalization failed", src);
return -1;
}
@@ -2365,12 +2397,12 @@
int
sftp_upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
int preserve_flag, int print_flag, int resume, int fsync_flag,
- int follow_link_flag, int inplace_flag)
+ int follow_link_flag, int inplace_flag, int create_dir)
{
char *dst_canon;
int ret;
- if ((dst_canon = sftp_realpath(conn, dst)) == NULL) {
+ if ((dst_canon = sftp_realpath(conn, dst, create_dir)) == NULL) {
error("upload \"%s\": path canonicalization failed", dst);
return -1;
}
@@ -2825,7 +2857,7 @@
char *from_path_canon;
int ret;
- if ((from_path_canon = sftp_realpath(from, from_path)) == NULL) {
+ if ((from_path_canon = sftp_realpath(from, from_path, 0)) == NULL) {
error("crossload \"%s\": path canonicalization failed",
from_path);
return -1;
diff --git a/sftp-client.h b/sftp-client.h
--- a/sftp-client.h (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/sftp-client.h (date 1703111691284)
@@ -111,7 +111,7 @@
int sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
/* Canonicalise 'path' - caller must free result */
-char *sftp_realpath(struct sftp_conn *, const char *);
+char *sftp_realpath(struct sftp_conn *, const char *, int);
/* Canonicalisation with tilde expansion (requires server extension) */
char *sftp_expand_path(struct sftp_conn *, const char *);
@@ -163,7 +163,7 @@
* times if 'pflag' is set
*/
int sftp_upload_dir(struct sftp_conn *, const char *, const char *,
- int, int, int, int, int, int);
+ int, int, int, int, int, int, int);
/*
* Download a 'from_path' from the 'from' connection and upload it to
diff --git a/sftp.c b/sftp.c
--- a/sftp.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99)
+++ b/sftp.c (date 1703168795365)
@@ -807,7 +807,7 @@
(rflag || global_rflag)) {
if (sftp_upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
- fflag || global_fflag, 0, 0) == -1)
+ fflag || global_fflag, 0, 0, 0) == -1)
err = -1;
} else {
if (sftp_upload(conn, g.gl_pathv[i], abs_dst,
@@ -1642,7 +1642,7 @@
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir);
path1 = sftp_make_absolute(path1, *pwd);
- if ((tmp = sftp_realpath(conn, path1)) == NULL) {
+ if ((tmp = sftp_realpath(conn, path1, 0)) == NULL) {
err = 1;
break;
}
@@ -2247,7 +2247,7 @@
}
#endif /* USE_LIBEDIT */
- if ((remote_path = sftp_realpath(conn, ".")) == NULL)
+ if ((remote_path = sftp_realpath(conn, ".", 0)) == NULL)
fatal("Need cwd");
startdir = xstrdup(remote_path);

@ -0,0 +1,38 @@
diff -up openssh-8.7p1/ssh.c.xxx openssh-8.7p1/ssh.c
--- openssh-8.7p1/ssh.c.xxx 2024-09-11 14:24:06.711088878 +0200
+++ openssh-8.7p1/ssh.c 2024-09-11 14:35:12.883765718 +0200
@@ -175,6 +175,14 @@ extern int muxserver_sock;
extern u_int muxclient_command;
/* Prints a help message to the user. This function never returns. */
+static void
+redhat_usage(void)
+{
+ fprintf(stderr,
+"\nYou can find some explanations for typical errors at this link:\n"
+" https://red.ht/support_rhel_ssh\n"
+ );
+}
static void
usage(void)
@@ -188,6 +196,7 @@ usage(void)
" destination [command [argument ...]]\n"
" ssh [-Q query_option]\n"
);
+ redhat_usage();
exit(255);
}
@@ -1609,8 +1618,10 @@ main(int ac, char **av)
/* Open a connection to the remote host. */
if (ssh_connect(ssh, host, options.host_arg, addrs, &hostaddr,
options.port, options.connection_attempts,
- &timeout_ms, options.tcp_keep_alive) != 0)
+ &timeout_ms, options.tcp_keep_alive) != 0) {
+ redhat_usage();
exit(255);
+ }
if (addrs != NULL)
freeaddrinfo(addrs);

@ -0,0 +1,46 @@
diff -up openssh-8.7p1/pathnames.h.kill-scp openssh-8.7p1/pathnames.h
--- openssh-8.7p1/pathnames.h.kill-scp 2021-09-16 11:37:57.240171687 +0200
+++ openssh-8.7p1/pathnames.h 2021-09-16 11:42:29.183427917 +0200
@@ -42,6 +42,7 @@
#define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key"
#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
#define _PATH_DH_MODULI SSHDIR "/moduli"
+#define _PATH_SCP_KILL_SWITCH SSHDIR "/disable_scp"
#ifndef _PATH_SSH_PROGRAM
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
diff -up openssh-8.7p1/scp.1.kill-scp openssh-8.7p1/scp.1
--- openssh-8.7p1/scp.1.kill-scp 2021-09-16 12:09:02.646714578 +0200
+++ openssh-8.7p1/scp.1 2021-09-16 12:26:49.978628226 +0200
@@ -278,6 +278,13 @@ to print debugging messages about their
By default a 32KB buffer is used.
.El
.El
+.Pp
+Usage of SCP protocol can be blocked by creating a world-readable
+.Ar /etc/ssh/disable_scp
+file. If this file exists, when SCP protocol is in use (either remotely or
+via the
+.Fl O
+option), the program will exit.
.Sh EXIT STATUS
.Ex -std scp
.Sh SEE ALSO
diff -up openssh-8.7p1/scp.c.kill-scp openssh-8.7p1/scp.c
--- openssh-8.7p1/scp.c.kill-scp 2021-09-16 11:42:56.013650519 +0200
+++ openssh-8.7p1/scp.c 2021-09-16 11:53:03.249713836 +0200
@@ -596,6 +596,14 @@ main(int argc, char **argv)
if (iamremote)
mode = MODE_SCP;
+ if (mode == MODE_SCP) {
+ FILE *f = fopen(_PATH_SCP_KILL_SWITCH, "r");
+ if (f != NULL) {
+ fclose(f);
+ fatal("SCP protocol is forbidden via %s", _PATH_SCP_KILL_SWITCH);
+ }
+ }
+
if ((pwd = getpwuid(userid = getuid())) == NULL)
fatal("unknown user %u", (u_int) userid);

@ -0,0 +1,53 @@
diff --color -ru a/ssh.1 b/ssh.1
--- a/ssh.1 2022-07-12 11:47:51.307295880 +0200
+++ b/ssh.1 2022-07-12 11:50:28.793363263 +0200
@@ -493,6 +493,7 @@
.It AddressFamily
.It BatchMode
.It BindAddress
+.It BindInterface
.It CanonicalDomains
.It CanonicalizeFallbackLocal
.It CanonicalizeHostname
@@ -510,6 +511,7 @@
.It ControlPath
.It ControlPersist
.It DynamicForward
+.It EnableSSHKeysign
.It EnableEscapeCommandline
.It EscapeChar
.It ExitOnForwardFailure
@@ -538,6 +540,8 @@
.It IdentitiesOnly
.It IdentityAgent
.It IdentityFile
+.It IgnoreUnknown
+.It Include
.It IPQoS
.It KbdInteractiveAuthentication
.It KbdInteractiveDevices
@@ -546,6 +550,7 @@
.It LocalCommand
.It LocalForward
.It LogLevel
+.It LogVerbose
.It MACs
.It Match
.It NoHostAuthenticationForLocalhost
@@ -566,6 +571,8 @@
.It RemoteCommand
.It RemoteForward
.It RequestTTY
+.It RevokedHostKeys
+.It SecurityKeyProvider
.It RequiredRSASize
.It SendEnv
.It ServerAliveInterval
@@ -575,6 +582,7 @@
.It StreamLocalBindMask
.It StreamLocalBindUnlink
.It StrictHostKeyChecking
+.It SyslogFacility
.It TCPKeepAlive
.It Tunnel
.It TunnelDevice

@ -0,0 +1,246 @@
diff -up openssh-9.0p1/audit-bsm.c.patch openssh-9.0p1/audit-bsm.c
--- openssh-9.0p1/audit-bsm.c.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit-bsm.c 2022-10-24 14:51:43.685766639 +0200
@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li
}
int
-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
+audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv)
{
/* not implemented */
}
diff -up openssh-9.0p1/audit.c.patch openssh-9.0p1/audit.c
--- openssh-9.0p1/audit.c.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit.c 2022-10-24 15:20:38.854548226 +0200
@@ -116,12 +116,22 @@ audit_event_lookup(ssh_audit_event_t ev)
void
audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key)
{
- char *fp;
+ char *key_fp = NULL;
+ char *issuer_fp = NULL;
+ struct sshkey_cert *cert = NULL;
- fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
- if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0)
+ key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
+ if (sshkey_is_cert(key) && key->cert != NULL && key->cert->signature_key != NULL) {
+ cert = key->cert;
+ issuer_fp = sshkey_fingerprint(cert->signature_key,
+ options.fingerprint_hash, SSH_FP_DEFAULT);
+ }
+ if (audit_keyusage(ssh, host_user, key_fp, cert, issuer_fp, (*rv == 0)) == 0)
*rv = -SSH_ERR_INTERNAL_ERROR;
- free(fp);
+ if (key_fp)
+ free(key_fp);
+ if (issuer_fp)
+ free(issuer_fp);
}
void
diff -up openssh-9.0p1/audit.h.patch openssh-9.0p1/audit.h
--- openssh-9.0p1/audit.h.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit.h 2022-10-24 14:58:20.887565518 +0200
@@ -64,7 +64,7 @@ void audit_session_close(struct logininf
int audit_run_command(struct ssh *, const char *);
void audit_end_command(struct ssh *, int, const char *);
ssh_audit_event_t audit_classify_auth(const char *);
-int audit_keyusage(struct ssh *, int, char *, int);
+int audit_keyusage(struct ssh *, int, const char *, const struct sshkey_cert *, const char *, int);
void audit_key(struct ssh *, int, int *, const struct sshkey *);
void audit_unsupported(struct ssh *, int);
void audit_kex(struct ssh *, int, char *, char *, char *, char *);
diff -up openssh-9.9p1/audit-linux.c.xxx openssh-9.9p1/audit-linux.c
--- openssh-9.9p1/audit-linux.c.xxx 2024-10-15 11:49:48.092151974 +0200
+++ openssh-9.9p1/audit-linux.c 2024-10-15 12:08:17.179158343 +0200
@@ -52,7 +52,7 @@ extern u_int utmp_len;
const char *audit_username(void);
static void
-linux_audit_user_logxxx(int uid, const char *username,
+linux_audit_user_logxxx(int uid, const char *username, const char *hostname,
const char *ip, const char *ttyn, int success, int event)
{
int audit_fd, rc, saved_errno;
@@ -66,7 +66,7 @@ linux_audit_user_logxxx(int uid, const c
}
rc = audit_log_acct_message(audit_fd, event,
NULL, "login", username ? username : "(unknown)",
- username == NULL ? uid : -1, NULL, ip, ttyn, success);
+ username == NULL ? uid : -1, hostname, ip, ttyn, success);
saved_errno = errno;
close(audit_fd);
@@ -137,10 +137,12 @@ fatal_report:
}
int
-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
+audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv)
{
char buf[AUDIT_LOG_SIZE];
int audit_fd, rc, saved_errno;
+ const char *rip;
+ u_int i;
audit_fd = audit_open();
if (audit_fd < 0) {
@@ -150,14 +152,44 @@ audit_keyusage(struct ssh *ssh, int host
else
return 0; /* Must prevent login */
}
+ rip = ssh_remote_ipaddr(ssh);
snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased");
rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv);
+ buf, audit_username(), -1, NULL, rip, NULL, rv);
if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
goto out;
- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp);
+ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp);
rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL,
- ssh_remote_ipaddr(ssh), NULL, rv);
+ rip, NULL, rv);
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
+ goto out;
+
+ if (cert) {
+ char *pbuf;
+
+ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0);
+ if (pbuf == NULL)
+ goto out;
+ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"",
+ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp);
+ free(pbuf);
+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
+ buf, audit_username(), -1, NULL, rip, NULL, rv);
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
+ goto out;
+
+ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) {
+ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0);
+ if (pbuf == NULL)
+ goto out;
+ snprintf(buf, sizeof(buf), "principal %s", pbuf);
+ free(pbuf);
+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
+ buf, audit_username(), -1, NULL, rip, NULL, rv);
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
+ goto out;
+ }
+ }
out:
saved_errno = errno;
audit_close(audit_fd);
@@ -179,26 +211,34 @@ audit_connection_from(const char *host,
int
audit_run_command(struct ssh *ssh, const char *command)
{
+ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL;
if (!user_login_count++)
linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
+ audit_hostname,
ssh_remote_ipaddr(ssh),
"ssh", 1, AUDIT_USER_LOGIN);
linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
+ audit_hostname,
ssh_remote_ipaddr(ssh),
"ssh", 1, AUDIT_USER_START);
+ free(audit_hostname);
return 0;
}
void
audit_end_command(struct ssh *ssh, int handle, const char *command)
{
+ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL;
linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
+ audit_hostname,
ssh_remote_ipaddr(ssh),
"ssh", 1, AUDIT_USER_END);
if (user_login_count && !--user_login_count)
linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
+ audit_hostname,
ssh_remote_ipaddr(ssh),
"ssh", 1, AUDIT_USER_LOGOUT);
+ free(audit_hostname);
}
void
@@ -211,31 +251,41 @@ void
audit_session_open(struct logininfo *li)
{
if (!user_login_count++)
- linux_audit_user_logxxx(li->uid, NULL, li->hostname,
+ linux_audit_user_logxxx(li->uid, NULL,
+ options.use_dns ? li->hostname : NULL,
+ options.use_dns ? NULL : li->hostname,
li->line, 1, AUDIT_USER_LOGIN);
- linux_audit_user_logxxx(li->uid, NULL, li->hostname,
+ linux_audit_user_logxxx(li->uid, NULL,
+ options.use_dns ? li->hostname : NULL,
+ options.use_dns ? NULL : li->hostname,
li->line, 1, AUDIT_USER_START);
}
void
audit_session_close(struct logininfo *li)
{
- linux_audit_user_logxxx(li->uid, NULL, li->hostname,
+ linux_audit_user_logxxx(li->uid, NULL,
+ options.use_dns ? li->hostname : NULL,
+ options.use_dns ? NULL : li->hostname,
li->line, 1, AUDIT_USER_END);
if (user_login_count && !--user_login_count)
- linux_audit_user_logxxx(li->uid, NULL, li->hostname,
+ linux_audit_user_logxxx(li->uid, NULL,
+ options.use_dns ? li->hostname : NULL,
+ options.use_dns ? NULL : li->hostname,
li->line, 1, AUDIT_USER_LOGOUT);
}
void
audit_event(struct ssh *ssh, ssh_audit_event_t event)
{
+ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL;
+
switch(event) {
case SSH_NOLOGIN:
case SSH_LOGIN_ROOT_DENIED:
linux_audit_user_auth(-1, audit_username(),
ssh_remote_ipaddr(ssh), "ssh", 0, event);
- linux_audit_user_logxxx(-1, audit_username(),
+ linux_audit_user_logxxx(-1, audit_username(), audit_hostname,
ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN);
break;
case SSH_AUTH_FAIL_PASSWD:
@@ -255,9 +305,11 @@ audit_event(struct ssh *ssh, ssh_audit_e
if (user_login_count) {
while (user_login_count--)
linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
+ audit_hostname,
ssh_remote_ipaddr(ssh),
"ssh", 1, AUDIT_USER_END);
linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
+ audit_hostname,
ssh_remote_ipaddr(ssh),
"ssh", 1, AUDIT_USER_LOGOUT);
}
@@ -266,12 +318,14 @@ audit_event(struct ssh *ssh, ssh_audit_e
case SSH_CONNECTION_ABANDON:
case SSH_INVALID_USER:
linux_audit_user_logxxx(-1, audit_username(),
+ audit_hostname,
ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN);
break;
default:
debug("%s: unhandled event %d", __func__, event);
break;
}
+ free(audit_hostname);
}
void

@ -0,0 +1,595 @@
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/dh.c openssh-9.0p1-patched/dh.c
--- openssh-9.0p1/dh.c 2023-05-25 09:24:28.730868316 +0200
+++ openssh-9.0p1-patched/dh.c 2023-05-25 09:23:44.841379532 +0200
@@ -37,6 +37,9 @@
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/fips.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
#include "dh.h"
#include "pathnames.h"
@@ -290,10 +293,15 @@
int
dh_gen_key(DH *dh, int need)
{
- int pbits;
- const BIGNUM *dh_p, *pub_key;
+ const BIGNUM *dh_p, *dh_g;
+ BIGNUM *pub_key = NULL, *priv_key = NULL;
+ EVP_PKEY *pkey = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ OSSL_PARAM_BLD *param_bld = NULL;
+ OSSL_PARAM *params = NULL;
+ int pbits, r = 0;
- DH_get0_pqg(dh, &dh_p, NULL, NULL);
+ DH_get0_pqg(dh, &dh_p, NULL, &dh_g);
if (need < 0 || dh_p == NULL ||
(pbits = BN_num_bits(dh_p)) <= 0 ||
@@ -301,19 +309,85 @@
return SSH_ERR_INVALID_ARGUMENT;
if (need < 256)
need = 256;
+
+ if ((param_bld = OSSL_PARAM_BLD_new()) == NULL ||
+ (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) {
+ OSSL_PARAM_BLD_free(param_bld);
+ return SSH_ERR_ALLOC_FAIL;
+ }
+
+ if (OSSL_PARAM_BLD_push_BN(param_bld,
+ OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 ||
+ OSSL_PARAM_BLD_push_BN(param_bld,
+ OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) {
+ error_f("Could not set p,q,g parameters");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
/*
* Pollard Rho, Big step/Little Step attacks are O(sqrt(n)),
* so double requested need here.
*/
- if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1)))
- return SSH_ERR_LIBCRYPTO_ERROR;
-
- if (DH_generate_key(dh) == 0)
- return SSH_ERR_LIBCRYPTO_ERROR;
- DH_get0_key(dh, &pub_key, NULL);
- if (!dh_pub_is_valid(dh, pub_key))
- return SSH_ERR_INVALID_FORMAT;
- return 0;
+ if (OSSL_PARAM_BLD_push_int(param_bld,
+ OSSL_PKEY_PARAM_DH_PRIV_LEN,
+ MINIMUM(need * 2, pbits - 1)) != 1 ||
+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (EVP_PKEY_fromdata_init(ctx) != 1) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (EVP_PKEY_fromdata(ctx, &pkey,
+ EVP_PKEY_KEY_PARAMETERS, params) != 1) {
+ error_f("Failed key generation");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+ /* reuse context for key generation */
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+
+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL ||
+ EVP_PKEY_keygen_init(ctx) != 1) {
+ error_f("Could not create or init context");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (EVP_PKEY_generate(ctx, &pkey) != 1) {
+ error_f("Could not generate keys");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (EVP_PKEY_public_check(ctx) != 1) {
+ error_f("The public key is incorrect");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
+ &pub_key) != 1 ||
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+ &priv_key) != 1 ||
+ DH_set0_key(dh, pub_key, priv_key) != 1) {
+ error_f("Could not set pub/priv keys to DH struct");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+ /* transferred */
+ pub_key = NULL;
+ priv_key = NULL;
+out:
+ OSSL_PARAM_free(params);
+ OSSL_PARAM_BLD_free(param_bld);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ BN_clear_free(pub_key);
+ BN_clear_free(priv_key);
+ return r;
}
DH *
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.c openssh-9.0p1-patched/kex.c
--- openssh-9.0p1/kex.c 2023-05-25 09:24:28.731868327 +0200
+++ openssh-9.0p1-patched/kex.c 2023-05-25 09:23:44.841379532 +0200
@@ -1623,3 +1623,142 @@
return r;
}
+#ifdef WITH_OPENSSL
+/*
+ * Creates an EVP_PKEY from the given parameters and keys.
+ * The private key can be omitted.
+ */
+EVP_PKEY *
+sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx)
+{
+ EVP_PKEY *ret = NULL;
+ OSSL_PARAM *params = NULL;
+ if (param_bld == NULL || ctx == NULL) {
+ debug2_f("param_bld or ctx is NULL");
+ return NULL;
+ }
+ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) {
+ debug2_f("Could not build param list");
+ return NULL;
+ }
+ if (EVP_PKEY_fromdata_init(ctx) != 1 ||
+ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) {
+ debug2_f("EVP_PKEY_fromdata failed");
+ OSSL_PARAM_free(params);
+ return NULL;
+ }
+ return ret;
+}
+
+int
+kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey)
+{
+ OSSL_PARAM_BLD *param_bld = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ BN_CTX *bn_ctx = NULL;
+ uint8_t *pub_ser = NULL;
+ const char *group_name;
+ const EC_POINT *pub = NULL;
+ const BIGNUM *priv = NULL;
+ int ret = 0;
+
+ if (k == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL ||
+ (param_bld = OSSL_PARAM_BLD_new()) == NULL ||
+ (bn_ctx = BN_CTX_new()) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+
+ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL ||
+ OSSL_PARAM_BLD_push_utf8_string(param_bld,
+ OSSL_PKEY_PARAM_GROUP_NAME,
+ group_name,
+ strlen(group_name)) != 1) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if ((pub = EC_KEY_get0_public_key(k)) != NULL) {
+ const EC_GROUP *group;
+ size_t len;
+
+ group = EC_KEY_get0_group(k);
+ len = EC_POINT_point2oct(group, pub,
+ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
+ if ((pub_ser = malloc(len)) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ EC_POINT_point2oct(group,
+ pub,
+ POINT_CONVERSION_UNCOMPRESSED,
+ pub_ser,
+ len,
+ bn_ctx);
+ if (OSSL_PARAM_BLD_push_octet_string(param_bld,
+ OSSL_PKEY_PARAM_PUB_KEY,
+ pub_ser,
+ len) != 1) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ }
+ if ((priv = EC_KEY_get0_private_key(k)) != NULL &&
+ OSSL_PARAM_BLD_push_BN(param_bld,
+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+out:
+ OSSL_PARAM_BLD_free(param_bld);
+ EVP_PKEY_CTX_free(ctx);
+ BN_CTX_free(bn_ctx);
+ free(pub_ser);
+ return ret;
+}
+
+int
+kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q,
+ const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv)
+{
+ OSSL_PARAM_BLD *param_bld = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ int r = 0;
+
+ /* create EVP_PKEY-DH key */
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL ||
+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) {
+ error_f("EVP_PKEY_CTX or PARAM_BLD init failed");
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 ||
+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 ||
+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 ||
+ OSSL_PARAM_BLD_push_BN(param_bld,
+ OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) {
+ error_f("Failed pushing params to OSSL_PARAM_BLD");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (priv != NULL &&
+ OSSL_PARAM_BLD_push_BN(param_bld,
+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) {
+ error_f("Failed pushing private key to OSSL_PARAM_BLD");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL)
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+out:
+ OSSL_PARAM_BLD_free(param_bld);
+ EVP_PKEY_CTX_free(ctx);
+ return r;
+}
+#endif /* WITH_OPENSSL */
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kexdh.c openssh-9.0p1-patched/kexdh.c
--- openssh-9.0p1/kexdh.c 2023-05-25 09:24:28.674867692 +0200
+++ openssh-9.0p1-patched/kexdh.c 2023-05-25 09:25:28.494533889 +0200
@@ -35,6 +35,10 @@
#include "openbsd-compat/openssl-compat.h"
#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
#include "sshkey.h"
#include "kex.h"
@@ -83,9 +87,12 @@
kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out)
{
BIGNUM *shared_secret = NULL;
+ const BIGNUM *pub, *priv, *p, *q, *g;
+ EVP_PKEY *pkey = NULL, *dh_pkey = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
u_char *kbuf = NULL;
size_t klen = 0;
- int kout, r;
+ int r = 0;
#ifdef DEBUG_KEXDH
fprintf(stderr, "dh_pub= ");
@@ -100,24 +107,59 @@
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out;
}
- klen = DH_size(kex->dh);
+
+ DH_get0_key(kex->dh, &pub, &priv);
+ DH_get0_pqg(kex->dh, &p, &q, &g);
+ /* import key */
+ r = kex_create_evp_dh(&pkey, p, q, g, pub, priv);
+ if (r != 0) {
+ error_f("Could not create EVP_PKEY for dh");
+ ERR_print_errors_fp(stderr);
+ goto out;
+ }
+ /* import peer key
+ * the parameters should be the same as with pkey
+ */
+ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL);
+ if (r != 0) {
+ error_f("Could not import peer key for dh");
+ ERR_print_errors_fp(stderr);
+ goto out;
+ }
+
+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) {
+ error_f("Could not init EVP_PKEY_CTX for dh");
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &klen) != 1) {
+ error_f("Could not get key size");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 ||
- BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
+ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 ||
+ BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
+ error_f("Could not derive key");
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXDH
- dump_digest("shared secret", kbuf, kout);
+ dump_digest("shared secret", kbuf, klen);
#endif
r = sshbuf_put_bignum2(out, shared_secret);
out:
freezero(kbuf, klen);
BN_clear_free(shared_secret);
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_free(dh_pkey);
+ EVP_PKEY_CTX_free(ctx);
return r;
}
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.h openssh-9.0p1-patched/kex.h
--- openssh-9.0p1/kex.h 2023-05-25 09:24:28.725868260 +0200
+++ openssh-9.0p1-patched/kex.h 2023-05-25 09:23:44.841379532 +0200
@@ -33,6 +33,9 @@
# include <openssl/bn.h>
# include <openssl/dh.h>
# include <openssl/ecdsa.h>
+# include <openssl/evp.h>
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# else /* OPENSSL_HAS_ECC */
@@ -283,6 +286,9@@
const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int)
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
+int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *,
+ const BIGNUM *, const BIGNUM *, const BIGNUM *);
+int kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey);
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
void dump_digest(const char *, const u_char *, int);
diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../openssh-8.7p1/kexecdh.c ./kexecdh.c
--- ../openssh-8.7p1/kexecdh.c 2021-08-20 06:03:49.000000000 +0200
+++ ./kexecdh.c 2023-04-13 14:30:14.882449593 +0200
@@ -35,17 +35,57 @@
#include <signal.h>
#include <openssl/ecdh.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#include <openssl/err.h>
#include "sshkey.h"
#include "kex.h"
#include "sshbuf.h"
#include "digest.h"
#include "ssherr.h"
+#include "log.h"
static int
kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key,
const EC_GROUP *, struct sshbuf **);
+static EC_KEY *
+generate_ec_keys(int ec_nid)
+{
+ EC_KEY *client_key = NULL;
+ EVP_PKEY *pkey = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ OSSL_PARAM_BLD *param_bld = NULL;
+ OSSL_PARAM *params = NULL;
+ const char *group_name;
+
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL ||
+ (param_bld = OSSL_PARAM_BLD_new()) == NULL)
+ goto out;
+ if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL ||
+ OSSL_PARAM_BLD_push_utf8_string(param_bld,
+ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 ||
+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) {
+ error_f("Could not create OSSL_PARAM");
+ goto out;
+ }
+ if (EVP_PKEY_keygen_init(ctx) != 1 ||
+ EVP_PKEY_CTX_set_params(ctx, params) != 1 ||
+ EVP_PKEY_generate(ctx, &pkey) != 1 ||
+ (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
+ error_f("Could not generate ec keys");
+ goto out;
+ }
+out:
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_CTX_free(ctx);
+ OSSL_PARAM_BLD_free(param_bld);
+ OSSL_PARAM_free(params);
+ return client_key;
+}
+
int
kex_ecdh_keypair(struct kex *kex)
{
@@ -55,11 +95,7 @@
struct sshbuf *buf = NULL;
int r;
- if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if (EC_KEY_generate_key(client_key) != 1) {
+ if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -101,11 +137,7 @@
*server_blobp = NULL;
*shared_secretp = NULL;
- if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if (EC_KEY_generate_key(server_key) != 1) {
+ if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -140,11 +172,21 @@
{
struct sshbuf *buf = NULL;
BIGNUM *shared_secret = NULL;
- EC_POINT *dh_pub = NULL;
- u_char *kbuf = NULL;
- size_t klen = 0;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL, *dh_pkey = NULL;
+ OSSL_PARAM_BLD *param_bld = NULL;
+ OSSL_PARAM *params = NULL;
+ u_char *kbuf = NULL, *pub = NULL;
+ size_t klen = 0, publen;
+ const char *group_name;
int r;
+ /* import EC_KEY to EVP_PKEY */
+ if ((r = kex_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) {
+ error_f("Could not create EVP_PKEY");
+ goto out;
+ }
+
*shared_secretp = NULL;
if ((buf = sshbuf_new()) == NULL) {
@@ -153,45 +195,82 @@
}
if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0)
goto out;
- if ((dh_pub = EC_POINT_new(group)) == NULL) {
+
+ /* the public key is in the buffer in octet string UNCOMPRESSED
+ * format. See sshbuf_put_ec */
+ if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0)
+ goto out;
+ sshbuf_reset(buf);
+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL ||
+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) {
+ if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (OSSL_PARAM_BLD_push_octet_string(param_bld,
+ OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 ||
+ OSSL_PARAM_BLD_push_utf8_string(param_bld,
+ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 ||
+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) {
+ error_f("Failed to set params for dh_pkey");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ if (EVP_PKEY_fromdata_init(ctx) != 1 ||
+ EVP_PKEY_fromdata(ctx, &dh_pkey,
+ EVP_PKEY_PUBLIC_KEY, params) != 1 ||
+ EVP_PKEY_public_check(ctx) != 1) {
+ error_f("Peer public key import failed");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
- sshbuf_reset(buf);
#ifdef DEBUG_KEXECDH
fputs("public key:\n", stderr);
- sshkey_dump_ec_point(group, dh_pub);
+ EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL);
#endif
- if (sshkey_ec_validate_public(group, dh_pub) != 0) {
- r = SSH_ERR_MESSAGE_INCOMPLETE;
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &klen) != 1) {
+ error_f("Failed to get derive information");
+ r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
- klen = (EC_GROUP_get_degree(group) + 7) / 8;
- if ((kbuf = malloc(klen)) == NULL ||
- (shared_secret = BN_new()) == NULL) {
+ if ((kbuf = malloc(klen)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen ||
- BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
+ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
#ifdef DEBUG_KEXECDH
dump_digest("shared secret", kbuf, klen);
#endif
+ if ((shared_secret = BN_new()) == NULL ||
+ (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0)
goto out;
*shared_secretp = buf;
buf = NULL;
out:
- EC_POINT_clear_free(dh_pub);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_free(dh_pkey);
+ OSSL_PARAM_BLD_free(param_bld);
+ OSSL_PARAM_free(params);
BN_clear_free(shared_secret);
freezero(kbuf, klen);
+ freezero(pub, publen);
sshbuf_free(buf);
return r;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,32 @@
From 26f366e263e575c4e1a18e2e64ba418f58878b37 Mon Sep 17 00:00:00 2001
From: Daan De Meyer <daan.j.demeyer@gmail.com>
Date: Mon, 20 Mar 2023 20:22:14 +0100
Subject: [PATCH] Only set PAM_RHOST if the remote host is not "UNKNOWN"
When using sshd's -i option with stdio that is not a AF_INET/AF_INET6
socket, auth_get_canonical_hostname() returns "UNKNOWN" which is then
set as the value of PAM_RHOST, causing pam to try to do a reverse DNS
query of "UNKNOWN", which times out multiple times, causing a
substantial slowdown when logging in.
To fix this, let's only set PAM_RHOST if the hostname is not "UNKNOWN".
---
auth-pam.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/auth-pam.c b/auth-pam.c
index e143304e3..39b4e4563 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -735,7 +735,7 @@ sshpam_init(struct ssh *ssh, Authctxt *authctxt)
sshpam_laddr = get_local_ipaddr(
ssh_packet_get_connection_in(ssh));
}
- if (sshpam_rhost != NULL) {
+ if (sshpam_rhost != NULL && strcmp(sshpam_rhost, "UNKNOWN") != 0) {
debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost);
sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST,
sshpam_rhost);
--
2.44.0

@ -0,0 +1,12 @@
diff -up openssh-9.9p1/ssh_config.5.xxx openssh-9.9p1/ssh_config.5
--- openssh-9.9p1/ssh_config.5.xxx 2024-10-11 12:01:14.260566303 +0200
+++ openssh-9.9p1/ssh_config.5 2024-10-11 12:01:59.725654775 +0200
@@ -759,7 +759,7 @@ or
This option should be placed in the non-hostspecific section.
See
.Xr ssh-keysign 8
-for more information.
+for more information. ssh-keysign should be installed explicitly.
.It Cm EscapeChar
Sets the escape character (default:
.Ql ~ ) .

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEcWi5g4FaXu9ZpK39Kj9BTnNgYLoFAmbspccACgkQKj9BTnNg
YLppxRAAv7eU/Xd2w9MX9vWQdhugiPByEcKg7KuKXUUs9xJGy+HbLqPqUCvn1UW6
qodKoSAdeBuSB7AjzuIQ1lTVX7C67OmZaVPRq25ar5b+Wq4SSlv23KMRq0b4EVyw
pOW6R9tsxqYBwYaiXQ50APcYL8SpepnGU+b/iR15f7q3SU2XMVVtkVb149UdLOqK
smfurbDGwUKFb2Q009MUfEV/d9zq31tdSjphvkqAXCcmxc8siuOYWYcByuysie+m
NpaOpee0047L5JIxNSLsa2yZrJZhClP8LbTCH1Vfwr7l0KE5nvL2qAtPKI2XxGQC
3jXrDLzp10RFxV8sCym+QlY9pZyzGj9d3G7vCHtxWGQ1Y0Qt+xs18OeBpjiehRhl
WM3Y+cjoN35jBaGhOoHdh3ePZQdTUyZ16aSv0h/cUHOohiM7i/4XW+dQtkqsJsw4
a81O0E64WrL8ho3Ju9mwcVZ9A0aEaftJsmJPDB+qYBjF/i7xcnH32LginzP5pel7
/W0aS2C1ZNo3QKHezI6IA9MyENMZiAMy2ybvfmN0HgLBaBY1plJ8a5GvMwJc+Qwh
iCHLCQ6Qgf/1hh+F6liTXnhtedtFHneJdyqvd7XOoardDEipZjxcnGa4HthbDFU+
8XdHKnWWhn4BLA+y7KB3ZGURniQK+qibwkF6J63CuMU+LmG+bvQ=
=Ukrb
-----END PGP SIGNATURE-----

@ -0,0 +1,2 @@
#Type Name ID GECOS Home directory Shell
u sshd 74 "Privilege-separated SSH" /usr/share/empty.sshd -

@ -0,0 +1,14 @@
# just a Makefile parallel_test.sh uses to run stuff in parallel with make
%:
$(MAKE) -j1 -C .t/$* $*
t-exec-%:
$(MAKE) -j1 -C ".t/t-exec-$*" \
TEST_SSH_PORT=10$*0 \
SKIP_LTESTS="$(shell cat .ltests/not-in/$*)" \
BUILDDIR="$(shell pwd)/.t/t-exec-$*" \
TEST_SHELL=sh \
MAKE=make \
TEST_SSH_TRACE=yes \
TEST_SSH_FAIL_FATAL=yes \
t-exec \

@ -0,0 +1,91 @@
#!/usr/bin/bash
set -uexo pipefail
# The custom %check script to run the OpenSSH upstream testsuite in parallel.
#
# The upstream testsuite is serial,
# so the idea here is to split the testsuite into several $PARTS:
# * file-tests
# * interop-tests
# * unit
# * ltests-00
# * ltests-01
# * ...
# * ltests-23
# and run them in parallel, using make, each in its own build subtree.
PARALLEL_MAKEFILE=$1
SPLIT=24
PARTS='file-tests interop-tests unit '
for ((i = 1; i < SPLIT; i++)); do ii=$(printf %02d $i);
PARTS+="t-exec-$ii "
done
# work around a selinux restriction:
#chcon -t unconfined_exec_t ssh-sk-helper || :
# work around something else that only crops up in brew
export TEST_SSH_UNSAFE_PERMISSIONS=1
# create a .test directory to store all our files in:
mkdir -p .t .ltests/{in,not-in}
# patch testsuite: use different ports to avoid port collisions
grep -REi 'port=[2-9][0-9]*' regress
sed -i 's|PORT=4242|PORT=$(expr $TEST_SSH_PORT + 1)|' \
regress/test-exec.sh*
sed -i 's|^P=3301 # test port|P=$(expr $TEST_SSH_PORT + 1)|' \
regress/multiplex.sh*
sed -i 's|^fwdport=3301|fwdport=$(expr $TEST_SSH_PORT + 1)|' \
regress/cfgmatch.sh* regress/cfgmatchlisten.sh*
sed -i 's|^LFWD_PORT=.*|LFWD_PORT=$(expr $TEST_SSH_PORT + 1)|' \
regress/forward-control.sh*
sed -i 's|^RFWD_PORT=.*|RFWD_PORT=$(expr $TEST_SSH_PORT + 2)|' \
regress/forward-control.sh*
( ! grep -REi 'port=[2-9][0-9]*' regress) # try to find more of those
# patch testsuite: speed up
sed -i 's|sleep 1$|sleep .25|' regress/forward-control.sh
# extract LTESTS list to .tests/ltests/all:
grep -Ex 'tests:[[:space:]]*file-tests t-exec interop-tests extra-tests unit' Makefile
echo -ne '\necho-ltests:\n\techo ${LTESTS}' >> regress/Makefile
make -s -C regress echo-ltests | tr ' ' '\n' > .ltests/all
# separate ltests into $SPLIT roughly equal .tests/ltests/in/$ii parts:
grep -qFx connect .ltests/all
( ! grep -qFx nonex .ltests/all )
split -d -a2 --number=l/$SPLIT .ltests/all .ltests/in/
wc -l .ltests/in/*
grep -qFx connect .ltests/in/*
# generate the inverses of them --- .ltests/not-in/$ii:
( ! grep -qFx nonex .ltests/in/* )
for ((i = 0; i < SPLIT; i++)); do ii=$(printf %02d $i);
while read -r tname; do
if ! grep -qFx "$tname" ".ltests/in/$ii"; then
echo -n "$tname " >> ".ltests/not-in/$ii"
fi
done < .ltests/all
done
grep . .ltests/not-in/*
( ! grep -q ^connect .ltests/not-in/0 )
for ((i = 1; i < SPLIT; i++)); do ii=$(printf %02d $i);
grep -q ^connect .ltests/not-in/$ii
done
# prepare several test directories:
for PART in $PARTS; do
mkdir .t/${PART}
cp -ra * .t/${PART}/
sed -i "s|abs_top_srcdir=.*|abs_top_srcdir=$(pwd)/.t/${PART}|" \
.t/${PART}/Makefile
sed -i "s|abs_top_builddir=.*|abs_top_builddir=$(pwd)/.t/${PART}|" \
.t/${PART}/Makefile
sed -i "s|^BUILDDIR=.*|BUILDDIR=$(pwd)/.t/${PART}|" \
.t/${PART}/Makefile
done
# finally, run tests $PARTS in parallel in their own subtrees:
time make -f "$PARALLEL_MAKEFILE" -j$(nproc) $PARTS

@ -0,0 +1,19 @@
# Requires SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
# set in environment, handled for example in plasma via
# /etc/xdg/plasma-workspace/env/ssh-agent.sh
[Unit]
ConditionEnvironment=!SSH_AGENT_PID
Description=OpenSSH key agent
Documentation=man:ssh-agent(1) man:ssh-add(1) man:ssh(1)
Requires=ssh-agent.socket
[Service]
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket
ExecStartPre=/usr/bin/rm -f $SSH_AUTH_SOCK
ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK
PassEnvironment=SSH_AGENT_PID
SuccessExitStatus=2
Type=simple
[Install]
Also=ssh-agent.socket

@ -0,0 +1,14 @@
[Unit]
Description=OpenSSH key agent
Documentation=man:ssh-agent(1) man:ssh-add(1) man:ssh(1)
[Socket]
ListenStream=%t/ssh-agent.socket
Service=ssh-agent.service
Priority=6
Backlog=5
SocketMode=0600
DirectoryMode=0700
[Install]
WantedBy=sockets.target

@ -0,0 +1,15 @@
[Unit]
Description=Update OpenSSH host key permissions
Documentation=https://fedoraproject.org/wiki/Changes/SSHKeySignSuidBit
Before=sshd.service
After=ssh-keygen.target
ConditionPathExists=!/var/lib/.ssh-host-keys-migration
[Service]
Type=oneshot
ExecStart=-/usr/libexec/openssh/ssh-host-keys-migration.sh
ExecStart=touch /var/lib/.ssh-host-keys-migration
RemainAfterExit=yes
[Install]
WantedBy=sshd.service

@ -0,0 +1,36 @@
#!/usr/bin/bash
set -eu -o pipefail
# Detect existing non-conforming host keys and perform the permissions migration
# https://fedoraproject.org/wiki/Changes/SSHKeySignSuidBit
#
# Example output looks like:
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ WARNING: UNPROTECTED PRIVATE KEY FILE! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Permissions 0640 for '/etc/ssh/ssh_host_rsa_key' are too open.
# It is required that your private key files are NOT accessible by others.
# This private key will be ignored.
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ WARNING: UNPROTECTED PRIVATE KEY FILE! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Permissions 0640 for '/etc/ssh/ssh_host_ecdsa_key' are too open.
# It is required that your private key files are NOT accessible by others.
# This private key will be ignored.
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ WARNING: UNPROTECTED PRIVATE KEY FILE! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# Permissions 0640 for '/etc/ssh/ssh_host_ed25519_key' are too open.
# It is required that your private key files are NOT accessible by others.
# This private key will be ignored.
# sshd: no hostkeys available -- exiting.
#
output="$(sshd -T 2>&1 || true)" # expected to fail
while read line; do
if [[ $line =~ ^Permissions\ [0-9]+\ for\ \'(.*)\'\ are\ too\ open. ]]; then
keyfile=${BASH_REMATCH[1]}
echo $line
echo -e "\t-> changing permissions on $keyfile"
chmod --verbose g-r $keyfile
chown --verbose root:root $keyfile
fi
done <<< "$output"

@ -0,0 +1,8 @@
#%PAM-1.0
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session required pam_namespace.so

@ -0,0 +1,45 @@
#!/bin/bash
# Create the host keys for the OpenSSH server.
KEYTYPE=$1
case $KEYTYPE in
"dsa") ;& # disabled in FIPS
"ed25519")
FIPS=/proc/sys/crypto/fips_enabled
if [[ -r "$FIPS" && $(cat $FIPS) == "1" ]]; then
exit 0
fi ;;
"rsa")
if [[ ! -z $SSH_RSA_BITS ]]; then
SSH_KEYGEN_OPTIONS="-b $SSH_RSA_BITS"
fi ;; # always ok
"ecdsa")
if [[ ! -z $SSH_ECDSA_BITS ]]; then
SSH_KEYGEN_OPTIONS="-b $SSH_ECDSA_BITS"
fi ;;
*) # wrong argument
exit 12 ;;
esac
KEY=/etc/ssh/ssh_host_${KEYTYPE}_key
KEYGEN=/usr/bin/ssh-keygen
if [[ ! -x $KEYGEN ]]; then
exit 13
fi
# remove old keys
rm -f $KEY{,.pub}
# create new keys
if ! $KEYGEN -q -t $KEYTYPE $SSH_KEYGEN_OPTIONS -f $KEY -C '' -N '' >&/dev/null; then
exit 1
fi
# sanitize permissions
/usr/bin/chmod 600 $KEY
/usr/bin/chmod 644 $KEY.pub
if [[ -x /usr/sbin/restorecon ]]; then
/usr/sbin/restorecon $KEY{,.pub}
fi
exit 0

@ -0,0 +1,5 @@
[Unit]
Wants=sshd-keygen@rsa.service
Wants=sshd-keygen@ecdsa.service
Wants=sshd-keygen@ed25519.service
PartOf=sshd.service

@ -0,0 +1,11 @@
[Unit]
Description=OpenSSH %i Server Key Generation
ConditionFileNotEmpty=|!/etc/ssh/ssh_host_%i_key
[Service]
Type=oneshot
EnvironmentFile=-/etc/sysconfig/sshd
ExecStart=/usr/libexec/openssh/sshd-keygen %i
[Install]
WantedBy=sshd-keygen.target

@ -0,0 +1,17 @@
#%PAM-1.0
auth substack password-auth
auth include postlogin
account required pam_sepermit.so
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session optional pam_motd.so
session include password-auth
session include postlogin

@ -0,0 +1,20 @@
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.target
Wants=sshd-keygen.target
# Migration for Fedora 38 change to remove group ownership for standard host keys
# See https://fedoraproject.org/wiki/Changes/SSHKeySignSuidBit
Wants=ssh-host-keys-migration.service
[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target

@ -0,0 +1,11 @@
[Unit]
Description=OpenSSH Server Socket
Documentation=man:sshd(8) man:sshd_config(5)
Conflicts=sshd.service
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target

@ -0,0 +1,10 @@
# Configuration file for the sshd service.
# The server keys are automatically generated if they are missing.
# To change the automatic creation, adjust sshd.service options for
# example using systemctl enable sshd-keygen@dsa.service to allow creation
# of DSA key or systemctl mask sshd-keygen@rsa.service to disable RSA key
# creation.
#SSH_RSA_BITS=3072
#SSH_ECDSA_BITS=256

@ -0,0 +1,13 @@
[Unit]
Description=OpenSSH per-connection server daemon
Documentation=man:sshd(8) man:sshd_config(5)
Wants=sshd-keygen.target
After=sshd-keygen.target
# Migration for Fedora 38 change to remove group ownership for standard host keys
# See https://fedoraproject.org/wiki/Changes/SSHKeySignSuidBit
Wants=ssh-host-keys-migration.service
[Service]
EnvironmentFile=-/etc/sysconfig/sshd
ExecStart=-/usr/sbin/sshd -i $OPTIONS
StandardInput=socket

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save