Toshaan Bharvani
2 years ago
commit
b05ac21e02
79 changed files with 23582 additions and 0 deletions
Binary file not shown.
@ -0,0 +1,18 @@
@@ -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 @@
@@ -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,12 @@
@@ -0,0 +1,12 @@
|
||||
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,8 @@ main(int argc, char **argv) |
||||
fdlim_set(maxfd); |
||||
fdcon = xcalloc(maxfd, sizeof(con)); |
||||
|
||||
+ signal(SIGPIPE, SIG_IGN); |
||||
+ |
||||
read_wait_nfdset = howmany(maxfd, NFDBITS); |
||||
read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask)); |
||||
|
@ -0,0 +1,24 @@
@@ -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,101 @@
@@ -0,0 +1,101 @@
|
||||
diff -up openssh-5.9p1/cipher-ctr.c.ctr-evp openssh-5.9p1/cipher-ctr.c |
||||
--- openssh-5.9p1/cipher-ctr.c.ctr-evp 2012-01-11 09:24:06.000000000 +0100 |
||||
+++ openssh-5.9p1/cipher-ctr.c 2012-01-11 15:54:04.675956600 +0100 |
||||
@@ -38,7 +38,7 @@ void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, in |
||||
|
||||
struct ssh_aes_ctr_ctx |
||||
{ |
||||
- AES_KEY aes_ctx; |
||||
+ EVP_CIPHER_CTX ecbctx; |
||||
u_char aes_counter[AES_BLOCK_SIZE]; |
||||
}; |
||||
|
||||
@@ -63,21 +63,42 @@ ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char |
||||
{ |
||||
struct ssh_aes_ctr_ctx *c; |
||||
size_t n = 0; |
||||
- u_char buf[AES_BLOCK_SIZE]; |
||||
+ u_char ctrbuf[AES_BLOCK_SIZE*256]; |
||||
+ u_char buf[AES_BLOCK_SIZE*256]; |
||||
|
||||
if (len == 0) |
||||
return (1); |
||||
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) |
||||
return (0); |
||||
|
||||
- while ((len--) > 0) { |
||||
+ for (; len > 0; len -= sizeof(u_int)) { |
||||
+ u_int r,a,b; |
||||
+ |
||||
if (n == 0) { |
||||
- AES_encrypt(c->aes_counter, buf, &c->aes_ctx); |
||||
- ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); |
||||
+ int outl, i, buflen; |
||||
+ |
||||
+ buflen = MIN(len, sizeof(ctrbuf)); |
||||
+ |
||||
+ for(i = 0; i < buflen; i += AES_BLOCK_SIZE) { |
||||
+ memcpy(&ctrbuf[i], c->aes_counter, AES_BLOCK_SIZE); |
||||
+ ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); |
||||
+ } |
||||
+ |
||||
+ EVP_EncryptUpdate(&c->ecbctx, buf, &outl, |
||||
+ ctrbuf, buflen); |
||||
} |
||||
- *(dest++) = *(src++) ^ buf[n]; |
||||
- n = (n + 1) % AES_BLOCK_SIZE; |
||||
+ |
||||
+ memcpy(&a, src, sizeof(a)); |
||||
+ memcpy(&b, &buf[n], sizeof(b)); |
||||
+ r = a ^ b; |
||||
+ memcpy(dest, &r, sizeof(r)); |
||||
+ src += sizeof(a); |
||||
+ dest += sizeof(r); |
||||
+ |
||||
+ n = (n + sizeof(b)) % sizeof(buf); |
||||
} |
||||
+ memset(ctrbuf, '\0', sizeof(ctrbuf)); |
||||
+ memset(buf, '\0', sizeof(buf)); |
||||
return (1); |
||||
} |
||||
|
||||
@@ -91,9 +112,28 @@ ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, co |
||||
c = xmalloc(sizeof(*c)); |
||||
EVP_CIPHER_CTX_set_app_data(ctx, c); |
||||
} |
||||
- if (key != NULL) |
||||
- AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, |
||||
- &c->aes_ctx); |
||||
+ |
||||
+ EVP_CIPHER_CTX_init(&c->ecbctx); |
||||
+ |
||||
+ if (key != NULL) { |
||||
+ const EVP_CIPHER *cipher; |
||||
+ switch(EVP_CIPHER_CTX_key_length(ctx)*8) { |
||||
+ case 128: |
||||
+ cipher = EVP_aes_128_ecb(); |
||||
+ break; |
||||
+ case 192: |
||||
+ cipher = EVP_aes_192_ecb(); |
||||
+ break; |
||||
+ case 256: |
||||
+ cipher = EVP_aes_256_ecb(); |
||||
+ break; |
||||
+ default: |
||||
+ fatal("ssh_aes_ctr_init: wrong aes key length"); |
||||
+ } |
||||
+ if(!EVP_EncryptInit_ex(&c->ecbctx, cipher, NULL, key, NULL)) |
||||
+ fatal("ssh_aes_ctr_init: cannot initialize aes encryption"); |
||||
+ EVP_CIPHER_CTX_set_padding(&c->ecbctx, 0); |
||||
+ } |
||||
if (iv != NULL) |
||||
memcpy(c->aes_counter, iv, AES_BLOCK_SIZE); |
||||
return (1); |
||||
@@ -105,6 +145,7 @@ ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) |
||||
struct ssh_aes_ctr_ctx *c; |
||||
|
||||
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { |
||||
+ EVP_CIPHER_CTX_cleanup(&c->ecbctx); |
||||
memset(c, 0, sizeof(*c)); |
||||
free(c); |
||||
EVP_CIPHER_CTX_set_app_data(ctx, NULL); |
@ -0,0 +1,16 @@
@@ -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 @@
@@ -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-05-06 11:32:25.179006811 +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-05-06 11:32:25.179006811 +0200 |
||||
+++ openssh-8.6p1/log.h 2021-05-06 11:34:22.349925757 +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-05-06 11:32:25.153006607 +0200 |
||||
+++ openssh-8.6p1/monitor.c 2021-05-06 11:33:37.671575348 +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-05-06 11:32:25.153006607 +0200 |
||||
+++ openssh-8.6p1/monitor.h 2021-05-06 11:32:25.180006819 +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-05-06 11:32:25.166006709 +0200 |
||||
+++ openssh-8.6p1/session.c 2021-05-06 11:32:25.181006827 +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-05-06 11:32:25.181006827 +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-05-06 11:32:25.181006827 +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) |
||||
{ |
||||
fd_set *rset, *wset; |
||||
int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0; |
||||
@@ -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-05-06 11:32:25.181006827 +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.c.log-in-chroot openssh-8.6p1/sshd.c |
||||
--- openssh-8.6p1/sshd.c.log-in-chroot 2021-05-06 11:32:25.177006795 +0200 |
||||
+++ openssh-8.6p1/sshd.c 2021-05-06 11:32:25.182006834 +0200 |
||||
@@ -559,7 +559,7 @@ privsep_postauth(struct ssh *ssh, Authct |
||||
} |
||||
|
||||
/* 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 @@
@@ -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,133 @@
@@ -0,0 +1,133 @@
|
||||
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 |
||||
index 22ea8ef..1fc963d 100644 |
||||
--- a/openbsd-compat/port-linux.c |
||||
+++ b/openbsd-compat/port-linux.c |
||||
@@ -179,7 +179,7 @@ ssh_selinux_change_context(const char *newname) |
||||
strlcpy(newctx + len, newname, newlen - len); |
||||
if ((cx = index(cx + 1, ':'))) |
||||
strlcat(newctx, cx, newlen); |
||||
- debug3("%s: setting context from '%s' to '%s'", __func__, |
||||
+ debug_f("setting context from '%s' to '%s'", |
||||
oldctx, newctx); |
||||
if (setcon(newctx) < 0) |
||||
do_log2(log_level, "%s: setcon %s from %s failed with %s", |
||||
__func__, 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.c b/sshd.c |
||||
index 2871fe9..39b9c08 100644 |
||||
--- a/sshd.c |
||||
+++ b/sshd.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,131 @@
@@ -0,0 +1,131 @@
|
||||
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) |
||||
@@ -418,7 +421,7 @@ typedef enum { |
||||
sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, |
||||
sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, |
||||
sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, |
||||
- sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, |
||||
+ sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, |
||||
sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, |
||||
sAcceptEnv, sSetEnv, sPermitTunnel, |
||||
sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, |
||||
@@ -497,14 +500,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 |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
diff -up openssh/sshd.c.ip-opts openssh/sshd.c |
||||
--- openssh/sshd.c.ip-opts 2016-07-25 13:58:48.998507834 +0200 |
||||
+++ openssh/sshd.c 2016-07-25 14:01:28.346469878 +0200 |
||||
@@ -1507,12 +1507,29 @@ 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: |
||||
+ i += opts[i + 1]; |
||||
+ break; |
||||
+ default: |
||||
+ /* Fail, fatally, if we detect either loose or strict |
||||
+ * source routing options. */ |
||||
+ text[0] = '\0'; |
||||
+ for (i = 0; i < option_size; i++) |
||||
+ snprintf(text + i*3, sizeof(text) - i*3, |
||||
+ " %2.2x", 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); |
||||
} |
||||
return; |
||||
#endif /* IP_OPTIONS */ |
@ -0,0 +1,280 @@
@@ -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 @@
@@ -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 |
||||
SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper |
||||
SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper |
||||
PRIVSEP_PATH=@PRIVSEP_PATH@ |
||||
@@ -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) 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) 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) |
||||
|
||||
+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) |
||||
|
||||
@@ -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 int inetd_flag; |
||||
extern int rexeced_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 && !rexeced_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,31 @@
@@ -0,0 +1,31 @@
|
||||
diff -up openssh-8.2p1/authfile.c.keyperm openssh-8.2p1/authfile.c |
||||
--- openssh-8.2p1/authfile.c.keyperm 2020-02-14 01:40:54.000000000 +0100 |
||||
+++ openssh-8.2p1/authfile.c 2020-02-17 11:55:12.841729758 +0100 |
||||
@@ -31,6 +31,7 @@ |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
+#include <grp.h> |
||||
#include <stdio.h> |
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
@@ -101,7 +102,19 @@ sshkey_perm_ok(int fd, const char *filen |
||||
#ifdef HAVE_CYGWIN |
||||
if (check_ntsec(filename)) |
||||
#endif |
||||
+ |
||||
if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { |
||||
+ if (st.st_mode & 040) { |
||||
+ struct group *gr; |
||||
+ |
||||
+ if ((gr = getgrnam("ssh_keys")) && (st.st_gid == gr->gr_gid)) { |
||||
+ /* The only additional bit is read |
||||
+ * for ssh_keys group, which is fine */ |
||||
+ if ((st.st_mode & 077) == 040 ) { |
||||
+ return 0; |
||||
+ } |
||||
+ } |
||||
+ } |
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
||||
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); |
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
@ -0,0 +1,289 @@
@@ -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 (ssh_krb5_kuserok(krb_context, princ, name, k5login_exists) |
||||
+ && 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, |
||||
+ sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, |
||||
sChallengeResponseAuthentication, |
||||
sPasswordAuthentication, sKbdInteractiveAuthentication, |
||||
sListenAddress, sAddressFamily, |
||||
@@ -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 available KEX (Key Exchange) algorithms. |
||||
Multiple algorithms must be comma-separated. |
||||
@@ -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,121 @@
@@ -0,0 +1,121 @@
|
||||
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 || !use_privsep)) { |
||||
#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.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 |
||||
+++ openssh-7.4p1/sshd.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 */ |
||||
@@ -633,6 +637,9 @@ privsep_postauth(Authctxt *authctxt) |
||||
{ |
||||
#ifdef DISABLE_FD_PASSING |
||||
if (1) { |
||||
+#elif defined(WITH_SELINUX) |
||||
+ if (0) { |
||||
+ /* even root user can be confined by SELinux */ |
||||
#else |
||||
if (authctxt->pw->pw_uid == 0) { |
||||
#endif |
@ -0,0 +1,554 @@
@@ -0,0 +1,554 @@
|
||||
diff -up openssh-8.5p1/addr.c.coverity openssh-8.5p1/addr.c |
||||
--- openssh-8.5p1/addr.c.coverity 2021-03-02 11:31:47.000000000 +0100 |
||||
+++ openssh-8.5p1/addr.c 2021-03-24 12:03:33.782968159 +0100 |
||||
@@ -312,8 +312,10 @@ addr_pton(const char *p, struct xaddr *n |
||||
if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0) |
||||
return -1; |
||||
|
||||
- if (ai == NULL || ai->ai_addr == NULL) |
||||
+ if (ai == NULL || ai->ai_addr == NULL) { |
||||
+ freeaddrinfo(ai); |
||||
return -1; |
||||
+ } |
||||
|
||||
if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, |
||||
n) == -1) { |
||||
@@ -336,12 +338,16 @@ addr_sa_pton(const char *h, const char * |
||||
if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0) |
||||
return -1; |
||||
|
||||
- if (ai == NULL || ai->ai_addr == NULL) |
||||
+ if (ai == NULL || ai->ai_addr == NULL) { |
||||
+ freeaddrinfo(ai); |
||||
return -1; |
||||
+ } |
||||
|
||||
if (sa != NULL) { |
||||
- if (slen < ai->ai_addrlen) |
||||
+ if (slen < ai->ai_addrlen) { |
||||
+ freeaddrinfo(ai); |
||||
return -1; |
||||
+ } |
||||
memcpy(sa, &ai->ai_addr, ai->ai_addrlen); |
||||
} |
||||
|
||||
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/auth-options.c.coverity openssh-8.5p1/auth-options.c |
||||
--- openssh-8.5p1/auth-options.c.coverity 2021-03-02 11:31:47.000000000 +0100 |
||||
+++ openssh-8.5p1/auth-options.c 2021-03-24 12:03:33.782968159 +0100 |
||||
@@ -706,6 +708,7 @@ serialise_array(struct sshbuf *m, char * |
||||
return r; |
||||
} |
||||
/* success */ |
||||
+ sshbuf_free(b); |
||||
return 0; |
||||
} |
||||
|
||||
diff -up openssh-7.4p1/channels.c.coverity openssh-7.4p1/channels.c |
||||
--- openssh-7.4p1/channels.c.coverity 2016-12-23 16:40:26.881788686 +0100 |
||||
+++ openssh-7.4p1/channels.c 2016-12-23 16:42:36.244818763 +0100 |
||||
@@ -1875,7 +1875,7 @@ channel_post_connecting(struct ssh *ssh, |
||||
debug("channel %d: connection failed: %s", |
||||
c->self, strerror(err)); |
||||
/* Try next address, if any */ |
||||
- if ((sock = connect_next(&c->connect_ctx)) > 0) { |
||||
+ if ((sock = connect_next(&c->connect_ctx)) >= 0) { |
||||
close(c->sock); |
||||
c->sock = c->rfd = c->wfd = sock; |
||||
channel_find_maxfd(ssh->chanctxt); |
||||
@@ -3804,7 +3804,7 @@ int |
||||
channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd) |
||||
{ |
||||
int r, success = 0, idx = -1; |
||||
- char *host_to_connect, *listen_host, *listen_path; |
||||
+ char *host_to_connect = NULL, *listen_host = NULL, *listen_path = NULL; |
||||
int port_to_connect, listen_port; |
||||
|
||||
/* Send the forward request to the remote side. */ |
||||
@@ -3832,7 +3832,6 @@ channel_request_remote_forwarding(struct |
||||
success = 1; |
||||
if (success) { |
||||
/* Record that connection to this host/port is permitted. */ |
||||
- host_to_connect = listen_host = listen_path = NULL; |
||||
port_to_connect = listen_port = 0; |
||||
if (fwd->connect_path != NULL) { |
||||
host_to_connect = xstrdup(fwd->connect_path); |
||||
@@ -3853,6 +3852,9 @@ channel_request_remote_forwarding(struct |
||||
host_to_connect, port_to_connect, |
||||
listen_host, listen_path, listen_port, NULL); |
||||
} |
||||
+ free(host_to_connect); |
||||
+ free(listen_host); |
||||
+ free(listen_path); |
||||
return idx; |
||||
} |
||||
|
||||
diff -up openssh-8.5p1/dns.c.coverity openssh-8.5p1/dns.c |
||||
--- openssh-8.5p1/dns.c.coverity 2021-03-02 11:31:47.000000000 +0100 |
||||
+++ openssh-8.5p1/dns.c 2021-03-24 12:03:33.783968166 +0100 |
||||
@@ -282,6 +282,7 @@ verify_host_key_dns(const char *hostname |
||||
&hostkey_digest, &hostkey_digest_len, hostkey)) { |
||||
error("Error calculating key fingerprint."); |
||||
freerrset(fingerprints); |
||||
+ free(dnskey_digest); |
||||
return -1; |
||||
} |
||||
|
||||
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 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 |
||||
@@ -1209,6 +1209,7 @@ ssh_krl_from_blob(struct sshbuf *buf, st |
||||
sshkey_free(key); |
||||
sshbuf_free(copy); |
||||
sshbuf_free(sect); |
||||
+ /* coverity[leaked_storage : FALSE] */ |
||||
return r; |
||||
} |
||||
|
||||
@@ -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 |
||||
@@ -1690,6 +1692,7 @@ record_failed_login(struct ssh *ssh, con |
||||
|
||||
memset(&ut, 0, sizeof(ut)); |
||||
/* strncpy because we don't necessarily want nul termination */ |
||||
+ /* coverity[buffer_size_warning : FALSE] */ |
||||
strncpy(ut.ut_user, username, sizeof(ut.ut_user)); |
||||
strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); |
||||
|
||||
@@ -1699,6 +1702,7 @@ record_failed_login(struct ssh *ssh, con |
||||
ut.ut_pid = getpid(); |
||||
|
||||
/* strncpy because we don't necessarily want nul termination */ |
||||
+ /* coverity[buffer_size_warning : FALSE] */ |
||||
strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); |
||||
|
||||
if (ssh_packet_connection_is_on_socket(ssh) && |
||||
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-8.5p1/moduli.c.coverity openssh-8.5p1/moduli.c |
||||
--- openssh-8.5p1/moduli.c.coverity 2021-03-02 11:31:47.000000000 +0100 |
||||
+++ openssh-8.5p1/moduli.c 2021-03-24 12:03:33.784968173 +0100 |
||||
@@ -476,6 +476,7 @@ write_checkpoint(char *cpfile, u_int32_t |
||||
else |
||||
logit("failed to write to checkpoint file '%s': %s", cpfile, |
||||
strerror(errno)); |
||||
+ /* coverity[leaked_storage : FALSE] */ |
||||
} |
||||
|
||||
static unsigned long |
||||
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/monitor_wrap.c.coverity openssh-7.4p1/monitor_wrap.c |
||||
--- openssh-7.4p1/monitor_wrap.c.coverity 2016-12-23 16:40:26.892788689 +0100 |
||||
+++ openssh-7.4p1/monitor_wrap.c 2016-12-23 16:40:26.900788691 +0100 |
||||
@@ -525,10 +525,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, |
||||
if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || |
||||
(tmp2 = dup(pmonitor->m_recvfd)) == -1) { |
||||
error_f("cannot allocate fds for pty"); |
||||
- if (tmp1 > 0) |
||||
+ if (tmp1 >= 0) |
||||
close(tmp1); |
||||
- if (tmp2 > 0) |
||||
- close(tmp2); |
||||
+ /*DEAD CODE if (tmp2 >= 0) |
||||
+ close(tmp2);*/ |
||||
return 0; |
||||
} |
||||
close(tmp1); |
||||
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-8.7p1/scp.c.coverity openssh-8.7p1/scp.c |
||||
--- openssh-8.7p1/scp.c.coverity 2021-08-30 16:23:35.389741329 +0200 |
||||
+++ openssh-8.7p1/scp.c 2021-08-30 16:27:04.854555296 +0200 |
||||
@@ -186,11 +186,11 @@ killchild(int signo) |
||||
{ |
||||
if (do_cmd_pid > 1) { |
||||
kill(do_cmd_pid, signo ? signo : SIGTERM); |
||||
- waitpid(do_cmd_pid, NULL, 0); |
||||
+ (void) waitpid(do_cmd_pid, NULL, 0); |
||||
} |
||||
if (do_cmd_pid2 > 1) { |
||||
kill(do_cmd_pid2, signo ? signo : SIGTERM); |
||||
- waitpid(do_cmd_pid2, NULL, 0); |
||||
+ (void) waitpid(do_cmd_pid2, NULL, 0); |
||||
} |
||||
|
||||
if (signo) |
||||
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-8.5p1/session.c.coverity openssh-8.5p1/session.c |
||||
--- openssh-8.5p1/session.c.coverity 2021-03-24 12:03:33.777968124 +0100 |
||||
+++ openssh-8.5p1/session.c 2021-03-24 12:03:33.786968187 +0100 |
||||
@@ -1223,12 +1223,14 @@ do_setup_env(struct ssh *ssh, Session *s |
||||
/* Environment specified by admin */ |
||||
for (i = 0; i < options.num_setenv; i++) { |
||||
cp = xstrdup(options.setenv[i]); |
||||
+ /* coverity[overwrite_var : FALSE] */ |
||||
if ((value = strchr(cp, '=')) == NULL) { |
||||
/* shouldn't happen; vars are checked in servconf.c */ |
||||
fatal("Invalid config SetEnv: %s", options.setenv[i]); |
||||
} |
||||
*value++ = '\0'; |
||||
child_set_env(&env, &envsize, cp, value); |
||||
+ free(cp); |
||||
} |
||||
|
||||
/* SSH_CLIENT deprecated */ |
||||
--- a/sftp.c 2022-06-30 10:43:13.914058913 +0200 |
||||
+++ b/sftp.c 2022-06-30 10:48:17.243997888 +0200 |
||||
@@ -222,7 +222,7 @@ killchild(int signo) |
||||
pid = sshpid; |
||||
if (pid > 1) { |
||||
kill(pid, SIGTERM); |
||||
- waitpid(pid, NULL, 0); |
||||
+ (void) waitpid(pid, NULL, 0); |
||||
} |
||||
|
||||
_exit(1); |
||||
@@ -768,6 +768,8 @@ process_put(struct sftp_conn *conn, cons |
||||
fflag || global_fflag, 0) == -1) |
||||
err = -1; |
||||
} |
||||
+ free(abs_dst); |
||||
+ abs_dst = NULL; |
||||
} |
||||
|
||||
out: |
||||
@@ -991,6 +993,7 @@ do_globbed_ls(struct sftp_conn *conn, co |
||||
if (lflag & LS_LONG_VIEW) { |
||||
if (g.gl_statv[i] == NULL) { |
||||
error("no stat information for %s", fname); |
||||
+ free(fname); |
||||
continue; |
||||
} |
||||
lname = ls_file(fname, g.gl_statv[i], 1, |
||||
diff --git a/sftp-client.c b/sftp-client.c |
||||
index 9de9afa20f..ea98d9f8d0 100644 |
||||
--- a/sftp-client.c |
||||
+++ b/sftp-client.c |
||||
@@ -2195,6 +2195,7 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous, |
||||
(*nreqsp)--; |
||||
} |
||||
debug3_f("done: %u outstanding replies", *nreqsp); |
||||
+ sshbuf_free(msg); |
||||
} |
||||
|
||||
int |
||||
diff --git a/sftp-server.c b/sftp-server.c |
||||
index 18d1949112..6380c4dd23 100644 |
||||
--- a/sftp-server.c |
||||
+++ b/sftp-server.c |
||||
@@ -1553,6 +1553,7 @@ process_extended_expand(u_int32_t id) |
||||
npath = xstrdup(path + 2); |
||||
free(path); |
||||
xasprintf(&path, "%s/%s", cwd, npath); |
||||
+ free(npath); |
||||
} else { |
||||
/* ~user expansions */ |
||||
if (tilde_expand(path, pw->pw_uid, &npath) != 0) { |
||||
diff -up openssh-8.5p1/sk-usbhid.c.coverity openssh-8.5p1/sk-usbhid.c |
||||
--- openssh-8.5p1/sk-usbhid.c.coverity 2021-03-02 11:31:47.000000000 +0100 |
||||
+++ openssh-8.5p1/sk-usbhid.c 2021-03-24 12:03:33.786968187 +0100 |
||||
@@ -1256,6 +1256,7 @@ sk_load_resident_keys(const char *pin, s |
||||
freezero(rks[i], sizeof(*rks[i])); |
||||
} |
||||
free(rks); |
||||
+ free(device); |
||||
return ret; |
||||
} |
||||
|
||||
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 */ |
||||
@@ -1220,8 +1220,8 @@ main(int ac, char **av) |
||||
sanitise_stdfd(); |
||||
|
||||
/* drop */ |
||||
- setegid(getgid()); |
||||
- setgid(getgid()); |
||||
+ (void) setegid(getgid()); |
||||
+ (void) setgid(getgid()); |
||||
|
||||
platform_disable_tracing(0); /* strict=no */ |
||||
|
||||
diff -up openssh-8.5p1/ssh.c.coverity openssh-8.5p1/ssh.c |
||||
--- openssh-8.5p1/ssh.c.coverity 2021-03-24 12:03:33.779968138 +0100 |
||||
+++ openssh-8.5p1/ssh.c 2021-03-24 12:03:33.786968187 +0100 |
||||
@@ -1746,6 +1746,7 @@ control_persist_detach(void) |
||||
close(muxserver_sock); |
||||
muxserver_sock = -1; |
||||
options.control_master = SSHCTL_MASTER_NO; |
||||
+ /* coverity[leaked_handle: FALSE]*/ |
||||
muxclient(options.control_path); |
||||
/* muxclient() doesn't return on success. */ |
||||
fatal("Failed to connect to new control master"); |
||||
diff -up openssh-7.4p1/sshd.c.coverity openssh-7.4p1/sshd.c |
||||
--- openssh-7.4p1/sshd.c.coverity 2016-12-23 16:40:26.897788690 +0100 |
||||
+++ openssh-7.4p1/sshd.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; |
||||
} |
||||
@@ -1386,6 +1388,9 @@ server_accept_loop(int *sock_in, int *so |
||||
explicit_bzero(rnd, sizeof(rnd)); |
||||
} |
||||
} |
||||
+ |
||||
+ if (fdset != NULL) |
||||
+ free(fdset); |
||||
} |
||||
|
||||
/* |
||||
@@ -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; |
||||
@@ -2879,6 +2882,7 @@ do_moduli_screen(const char *out_file, c |
||||
} else if (strncmp(opts[i], "start-line=", 11) == 0) { |
||||
start_lineno = strtoul(opts[i]+11, NULL, 10); |
||||
} else if (strncmp(opts[i], "checkpoint=", 11) == 0) { |
||||
+ free(checkpoint); |
||||
checkpoint = xstrdup(opts[i]+11); |
||||
} else if (strncmp(opts[i], "generator=", 10) == 0) { |
||||
generator_wanted = (u_int32_t)strtonum( |
||||
@@ -2920,6 +2924,9 @@ do_moduli_screen(const char *out_file, c |
||||
#else /* WITH_OPENSSL */ |
||||
fatal("Moduli screening is not supported"); |
||||
#endif /* WITH_OPENSSL */ |
||||
+ free(checkpoint); |
||||
+ if (in != stdin) |
||||
+ fclose(in); |
||||
} |
||||
|
||||
static char * |
||||
diff -up openssh-8.5p1/sshsig.c.coverity openssh-8.5p1/sshsig.c |
||||
--- openssh-8.5p1/sshsig.c.coverity 2021-03-02 11:31:47.000000000 +0100 |
||||
+++ openssh-8.5p1/sshsig.c 2021-03-24 12:03:33.787968194 +0100 |
||||
@@ -515,6 +515,7 @@ hash_file(int fd, const char *hashalg, s |
||||
oerrno = errno; |
||||
error_f("read: %s", strerror(errno)); |
||||
ssh_digest_free(ctx); |
||||
+ ctx = NULL; |
||||
errno = oerrno; |
||||
r = SSH_ERR_SYSTEM_ERROR; |
||||
goto out; |
@ -0,0 +1,100 @@
@@ -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 @@
@@ -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,187 @@
@@ -0,0 +1,187 @@
|
||||
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 = PRIVSEP(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 (use_privsep && 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,34 @@ 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 */ |
||||
+ if (use_privsep) |
||||
+ mm_set_monitor_pipe(pparent); |
||||
+#endif |
||||
+ |
||||
+ /* remove hostkey from the child's memory */ |
||||
+ destroy_sensitive_data(ssh, use_privsep); |
||||
+ /* |
||||
+ * 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, 1); |
||||
- 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 @@
@@ -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 @@
@@ -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,53 @@
@@ -0,0 +1,53 @@
|
||||
diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c |
||||
--- openssh-7.2p2/channels.c.x11 2016-03-09 19:04:48.000000000 +0100 |
||||
+++ openssh-7.2p2/channels.c 2016-06-03 10:42:04.775164520 +0200 |
||||
@@ -3990,21 +3990,24 @@ x11_create_display_inet(int x11_display_ |
||||
} |
||||
|
||||
static int |
||||
-connect_local_xsocket_path(const char *pathname) |
||||
+connect_local_xsocket_path(const char *pathname, int len) |
||||
{ |
||||
int sock; |
||||
struct sockaddr_un addr; |
||||
|
||||
+ if (len <= 0) |
||||
+ return -1; |
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0); |
||||
if (sock == -1) |
||||
error("socket: %.100s", strerror(errno)); |
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sun_family = AF_UNIX; |
||||
- strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); |
||||
- if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) |
||||
+ if (len > 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; |
||||
} |
||||
|
||||
@@ -4012,8 +4015,18 @@ static int |
||||
connect_local_xsocket(u_int dnr) |
||||
{ |
||||
char buf[1024]; |
||||
- snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr); |
||||
- return connect_local_xsocket_path(buf); |
||||
+ int len, 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 @@
@@ -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 FWD_PERMIT_ANY_HOST "*" |
||||
|
||||
/* -- 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 select() 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 *, u_int); |
||||
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 { |
||||
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 StreamLocalBindUnlink , |
||||
.Cm TrustedUserCAKeys , |
||||
.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,98 @@
@@ -0,0 +1,98 @@
|
||||
commit 0e22b79bfde45a7cf7a2e51a68ec11c4285f3b31 |
||||
Author: Jakub Jelen <jjelen@redhat.com> |
||||
Date: Mon Nov 21 15:04:06 2016 +0100 |
||||
|
||||
systemd stuff |
||||
|
||||
diff --git a/configure.ac b/configure.ac |
||||
index 2ffc369..162ce92 100644 |
||||
--- a/configure.ac |
||||
+++ b/configure.ac |
||||
@@ -4265,6 +4265,30 @@ AC_ARG_WITH([kerberos5], |
||||
AC_SUBST([GSSLIBS]) |
||||
AC_SUBST([K5LIBS]) |
||||
|
||||
+# Check whether user wants systemd support |
||||
+SYSTEMD_MSG="no" |
||||
+AC_ARG_WITH(systemd, |
||||
+ [ --with-systemd Enable systemd support], |
||||
+ [ if test "x$withval" != "xno" ; then |
||||
+ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) |
||||
+ if test "$PKGCONFIG" != "no"; then |
||||
+ AC_MSG_CHECKING([for libsystemd]) |
||||
+ if $PKGCONFIG --exists libsystemd; then |
||||
+ SYSTEMD_CFLAGS=`$PKGCONFIG --cflags libsystemd` |
||||
+ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` |
||||
+ CPPFLAGS="$CPPFLAGS $SYSTEMD_CFLAGS" |
||||
+ SSHDLIBS="$SSHDLIBS $SYSTEMD_LIBS" |
||||
+ AC_MSG_RESULT([yes]) |
||||
+ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if you want systemd support.]) |
||||
+ SYSTEMD_MSG="yes" |
||||
+ else |
||||
+ AC_MSG_RESULT([no]) |
||||
+ fi |
||||
+ fi |
||||
+ fi ] |
||||
+) |
||||
+ |
||||
+ |
||||
# Looking for programs, paths and files |
||||
|
||||
PRIVSEP_PATH=/var/empty |
||||
@@ -5097,6 +5121,7 @@ echo " libedit support: $LIBEDIT_MSG" |
||||
echo " Solaris process contract support: $SPC_MSG" |
||||
echo " Solaris project support: $SP_MSG" |
||||
echo " Solaris privilege support: $SPP_MSG" |
||||
+echo " systemd support: $SYSTEMD_MSG" |
||||
echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" |
||||
echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" |
||||
echo " BSD Auth support: $BSD_AUTH_MSG" |
||||
diff --git a/contrib/sshd.service b/contrib/sshd.service |
||||
new file mode 100644 |
||||
index 0000000..e0d4923 |
||||
--- /dev/null |
||||
+++ b/contrib/sshd.service |
||||
@@ -0,0 +1,16 @@ |
||||
+[Unit] |
||||
+Description=OpenSSH server daemon |
||||
+Documentation=man:sshd(8) man:sshd_config(5) |
||||
+After=network.target |
||||
+ |
||||
+[Service] |
||||
+Type=notify |
||||
+ExecStart=/usr/sbin/sshd -D $OPTIONS |
||||
+ExecReload=/bin/kill -HUP $MAINPID |
||||
+KillMode=process |
||||
+Restart=on-failure |
||||
+RestartPreventExitStatus=255 |
||||
+ |
||||
+[Install] |
||||
+WantedBy=multi-user.target |
||||
+ |
||||
diff --git a/sshd.c b/sshd.c |
||||
index 816611c..b8b9d13 100644 |
||||
--- a/sshd.c |
||||
+++ b/sshd.c |
||||
@@ -85,6 +85,10 @@ |
||||
#include <prot.h> |
||||
#endif |
||||
|
||||
+#ifdef HAVE_SYSTEMD |
||||
+#include <systemd/sd-daemon.h> |
||||
+#endif |
||||
+ |
||||
#include "xmalloc.h" |
||||
#include "ssh.h" |
||||
#include "ssh2.h" |
||||
@@ -1888,6 +1892,11 @@ main(int ac, char **av) |
||||
} |
||||
} |
||||
|
||||
+#ifdef HAVE_SYSTEMD |
||||
+ /* Signal systemd that we are ready to accept connections */ |
||||
+ sd_notify(0, "READY=1"); |
||||
+#endif |
||||
+ |
||||
/* Accept a connection and return in a forked child */ |
||||
server_accept_loop(&sock_in, &sock_out, |
||||
&newsock, config_s); |
@ -0,0 +1,86 @@
@@ -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_ALLOW(__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,283 @@
@@ -0,0 +1,283 @@
|
||||
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,9 @@ |
||||
|
||||
/* import */ |
||||
extern ServerOptions options; |
||||
+extern int inetd_flag; |
||||
+extern int rexeced_flag; |
||||
+extern Authctxt *the_authctxt; |
||||
|
||||
static char * |
||||
format_key(const struct sshkey *key) |
||||
@@ -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 && !rexeced_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 && !rexeced_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,11 +49,6 @@ |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
-extern ServerOptions options; |
||||
-extern Authctxt *the_authctxt; |
||||
-extern int inetd_flag; |
||||
-extern int rexeced_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 && !rexeced_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 && !rexeced_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,9 @@ |
||||
|
||||
extern int use_privsep; |
||||
extern ServerOptions options; |
||||
+extern int inetd_flag; |
||||
+extern int rexeced_flag; |
||||
+extern Authctxt *the_authctxt; |
||||
|
||||
void |
||||
platform_pre_listen(void) |
||||
@@ -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 && !rexeced_flag), do_pam_putenv, the_authctxt, |
||||
+ options.use_pam); |
||||
#endif |
||||
} |
||||
|
||||
diff -up openssh/sshd.c.refactor openssh/sshd.c |
||||
--- openssh/sshd.c.refactor 2019-04-04 13:19:12.275822068 +0200 |
||||
+++ openssh/sshd.c 2019-04-04 13:19:51.270195262 +0200 |
||||
@@ -158,7 +158,7 @@ int debug_flag = 0; |
||||
static int test_flag = 0; |
||||
|
||||
/* Flag indicating that the daemon is being started from inetd. */ |
||||
-static int inetd_flag = 0; |
||||
+int inetd_flag = 0; |
||||
|
||||
/* Flag indicating that sshd should not detach and become a daemon. */ |
||||
static int no_daemon_flag = 0; |
||||
@@ -171,7 +171,7 @@ static char **saved_argv; |
||||
static int saved_argc; |
||||
|
||||
/* re-exec */ |
||||
-static int rexeced_flag = 0; |
||||
+int rexeced_flag = 0; |
||||
static int rexec_flag = 1; |
||||
static int rexec_argc = 0; |
||||
static char **rexec_argv; |
||||
@@ -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 && !rexeced_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,635 @@
@@ -0,0 +1,635 @@
|
||||
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 |
||||
@@ -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.c.fips openssh-8.6p1/kex.c |
||||
--- openssh-8.6p1/kex.c.fips 2021-05-06 12:08:36.489926807 +0200 |
||||
+++ openssh-8.6p1/kex.c 2021-05-06 12:08:36.498926877 +0200 |
||||
@@ -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/crypto.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-256," \ |
||||
"ssh-rsa" |
||||
|
||||
+#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 |
||||
@@ -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 |
||||
@@ -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/crypto.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/crypto.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 @@ |
||||
#include <grp.h> |
||||
#include <pwd.h> |
||||
#include <signal.h> |
||||
+#include <syslog.h> |
||||
#include <stdarg.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
@@ -77,6 +78,7 @@ |
||||
#include <openssl/dh.h> |
||||
#include <openssl/bn.h> |
||||
#include <openssl/rand.h> |
||||
+#include <openssl/crypto.h> |
||||
#include "openbsd-compat/openssl-compat.h" |
||||
#endif |
||||
|
||||
@@ -1619,6 +1621,7 @@ main(int ac, char **av) |
||||
#endif |
||||
__progname = ssh_get_progname(av[0]); |
||||
|
||||
+ OpenSSL_add_all_algorithms(); |
||||
/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ |
||||
saved_argc = ac; |
||||
rexec_argc = ac; |
||||
@@ -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. |
||||
@@ -2494,10 +2501,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 |
||||
@@ -34,6 +34,7 @@ |
||||
#include <openssl/evp.h> |
||||
#include <openssl/err.h> |
||||
#include <openssl/pem.h> |
||||
+#include <openssl/crypto.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 |
||||
for (kt = keytypes; kt->type != -1; kt++) { |
||||
if (kt->name == NULL || kt->type == KEY_NULL) |
||||
continue; |
||||
+ if (FIPS_mode()) { |
||||
+ switch (kt->type) { |
||||
+ case KEY_ED25519: |
||||
+ case KEY_ED25519_SK: |
||||
+ case KEY_ED25519_CERT: |
||||
+ case KEY_ED25519_SK_CERT: |
||||
+ continue; |
||||
+ break; |
||||
+ default: |
||||
+ break; |
||||
+ } |
||||
+ } |
||||
if (!include_sigonly && kt->sigonly) |
||||
continue; |
||||
if ((certs_only && !kt->cert) || (plain_only && kt->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 */ |
||||
ret->type = type; |
||||
if (sshkey_is_cert(ret)) { |
||||
@@ -1705,6 +1707,8 @@ rsa_generate_private_key(u_int bits, RSA |
||||
goto out; |
||||
|
||||
if (EVP_PKEY_keygen(ctx, &res) <= 0) { |
||||
+ 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; |
||||
} |
||||
@@ -2916,6 +2916,11 @@ sshkey_sign(struct sshkey *key, |
||||
break; |
||||
case KEY_ED25519_SK: |
||||
case KEY_ED25519_SK_CERT: |
||||
+ if (FIPS_mode()) { |
||||
+ logit_f("Ed25519 keys are not allowed in FIPS mode"); |
||||
+ return SSH_ERR_INVALID_ARGUMENT; |
||||
+ } |
||||
+ /* Fallthrough */ |
||||
case KEY_ECDSA_SK_CERT: |
||||
case KEY_ECDSA_SK: |
||||
r = sshsk_sign(sk_provider, key, sigp, lenp, data, |
||||
@@ -2973,6 +2978,10 @@ sshkey_verify(const struct sshkey *key, |
||||
return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); |
||||
case KEY_ED25519_SK: |
||||
case KEY_ED25519_SK_CERT: |
||||
+ if (FIPS_mode()) { |
||||
+ logit_f("Ed25519 keys are not allowed in FIPS mode"); |
||||
+ return SSH_ERR_INVALID_ARGUMENT; |
||||
+ } |
||||
return ssh_ed25519_sk_verify(key, sig, siglen, data, dlen, |
||||
compat, detailsp); |
||||
#ifdef WITH_XMSS |
||||
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 |
||||
@@ -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) |
||||
@@ -1098,9 +1104,17 @@ do_gen_all_hostkeys(struct passwd *pw) |
||||
first = 1; |
||||
printf("%s: generating new host keys: ", __progname); |
||||
} |
||||
+ type = sshkey_type_from_name(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_name(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)); |
||||
diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c |
||||
--- openssh-8.7p1/kexgen.c.fips3 2022-07-11 16:11:21.973519913 +0200 |
||||
+++ openssh-8.7p1/kexgen.c 2022-07-11 16:25:31.172187365 +0200 |
||||
@@ -31,6 +31,7 @@ |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <signal.h> |
||||
+#include <openssl/crypto.h> |
||||
|
||||
#include "sshkey.h" |
||||
#include "kex.h" |
||||
@@ -115,10 +116,20 @@ 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; |
||||
default: |
||||
r = SSH_ERR_INVALID_ARGUMENT; |
||||
@@ -186,11 +197,21 @@ 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; |
||||
default: |
||||
r = SSH_ERR_INVALID_ARGUMENT; |
||||
@@ -285,12 +306,22 @@ 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; |
||||
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/crypto.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 * |
||||
datalen >= INT_MAX - crypto_sign_ed25519_BYTES || |
||||
signature == NULL || signaturelen == 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(signature, signaturelen)) == NULL) |
||||
return SSH_ERR_ALLOC_FAIL; |
@ -0,0 +1,633 @@
@@ -0,0 +1,633 @@
|
||||
diff -up openssh-8.6p1/auth.h.ccache_name openssh-8.6p1/auth.h |
||||
--- openssh-8.6p1/auth.h.ccache_name 2021-05-06 11:15:36.345143341 +0200 |
||||
+++ openssh-8.6p1/auth.h 2021-05-06 11:15:36.387143654 +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-05-06 11:28:40.195242317 +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-05-06 11:15:36.374143558 +0200 |
||||
+++ openssh-8.6p1/gss-serv.c 2021-05-06 11:15:36.387143654 +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 = PRIVSEP(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-05-06 11:15:36.384143632 +0200 |
||||
+++ openssh-8.6p1/gss-serv-krb5.c 2021-05-06 11:15:36.387143654 +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-05-06 11:15:36.377143580 +0200 |
||||
+++ openssh-8.6p1/servconf.c 2021-05-06 11:15:36.388143662 +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,8 @@ typedef enum { |
||||
sPort, sHostKeyFile, sLoginGraceTime, |
||||
sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, |
||||
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, |
||||
- sKerberosGetAFSToken, sChallengeResponseAuthentication, |
||||
+ sKerberosGetAFSToken, sKerberosUniqueCCache, |
||||
+ sChallengeResponseAuthentication, |
||||
sPasswordAuthentication, sKbdInteractiveAuthentication, |
||||
sListenAddress, sAddressFamily, |
||||
sPrintMotd, sPrintLastLog, sIgnoreRhosts, |
||||
@@ -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-05-06 11:15:36.377143580 +0200 |
||||
+++ openssh-8.6p1/servconf.h 2021-05-06 11:15:36.397143729 +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-05-06 11:15:36.384143632 +0200 |
||||
+++ openssh-8.6p1/session.c 2021-05-06 11:15:36.397143729 +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.c.ccache_name openssh-8.6p1/sshd.c |
||||
--- openssh-8.6p1/sshd.c.ccache_name 2021-05-06 11:15:36.380143602 +0200 |
||||
+++ openssh-8.6p1/sshd.c 2021-05-06 11:15:36.398143736 +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-05-06 11:15:36.380143602 +0200 |
||||
+++ openssh-8.6p1/sshd_config.5 2021-05-06 11:15:36.398143736 +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 available KEX (Key Exchange) algorithms. |
||||
Multiple algorithms must be comma-separated. |
||||
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-05-06 11:15:36.384143632 +0200 |
||||
+++ openssh-8.6p1/ssh-gss.h 2021-05-06 11:15:36.398143736 +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,105 @@
@@ -0,0 +1,105 @@
|
||||
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,22 @@ |
||||
+# 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 |
||||
+ |
||||
+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 |
||||
+ |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
diff -up openssh-8.6p1/sshd.c.log-usepam-no openssh-8.6p1/sshd.c |
||||
--- openssh-8.6p1/sshd.c.log-usepam-no 2021-04-19 14:00:45.099735129 +0200 |
||||
+++ openssh-8.6p1/sshd.c 2021-04-19 14:03:21.140920974 +0200 |
||||
@@ -1749,6 +1749,10 @@ main(int ac, char **av) |
||||
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, |
||||
cfg, &includes, NULL); |
||||
|
||||
+ /* 'UsePAM no' is not supported in RHEL */ |
||||
+ if (! options.use_pam) |
||||
+ logit("WARNING: 'UsePAM no' is not supported in RHEL 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 RHEL and may cause several |
||||
+# problems. |
||||
#UsePAM no |
||||
|
||||
#AllowAgentForwarding yes |
@ -0,0 +1,867 @@
@@ -0,0 +1,867 @@
|
||||
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; |
||||
|
||||
@@ -296,8 +304,15 @@ input_userauth_request(int type, u_int32 |
||||
use_privsep ? " [net]" : ""); |
||||
authctxt->service = xstrdup(service); |
||||
authctxt->style = style ? xstrdup(style) : NULL; |
||||
- if (use_privsep) |
||||
+#ifdef WITH_SELINUX |
||||
+ authctxt->role = role ? xstrdup(role) : NULL; |
||||
+#endif |
||||
+ if (use_privsep) { |
||||
mm_inform_authserv(service, style); |
||||
+#ifdef WITH_SELINUX |
||||
+ mm_inform_authrole(role); |
||||
+#endif |
||||
+ } |
||||
userauth_banner(ssh); |
||||
if (auth2_setup_methods_lists(authctxt) != 0) |
||||
ssh_packet_disconnect(ssh, |
||||
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; |
||||
const char *displayname; |
||||
@@ -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); |
||||
|
||||
if ((!use_privsep || mm_is_monitor()) && |
||||
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, "hostbased")) != 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(int ); |
||||
void do_pam_chauthtok(void); |
||||
-int do_pam_putenv(char *, char *); |
||||
+int do_pam_putenv(char *, const char *); |
||||
char ** fetch_pam_environment(void); |
||||
char ** fetch_pam_child_environment(void); |
||||
void free_pam_environment(char **); |
||||
diff -up openssh/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; |
||||
const u_char *p; |
||||
- char *userstyle, *cp; |
||||
+ char *userstyle, *s, *cp; |
||||
size_t len; |
||||
u_char type; |
||||
int 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,421 @@ |
||||
+/* |
||||
+ * 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; |
||||
+extern int rexeced_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 && !rexeced_flag) { |
||||
+ security_context_t sshdsc=NULL; |
||||
+ |
||||
+ if (getcon_raw(&sshdsc) < 0) |
||||
+ fatal("failed to allocate security context"); |
||||
+ |
||||
+ if ((con=context_new(sshdsc)) == NULL) |
||||
+ fatal("failed to allocate selinux context"); |
||||
+ reqlvl = context_range_get(con); |
||||
+ freecon(sshdsc); |
||||
+ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0) |
||||
+ /* we actually don't change level */ |
||||
+ reqlvl = ""; |
||||
+ |
||||
+ debug_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 && !rexeced_flag) { |
||||
+ use_current = "1"; |
||||
+ } else { |
||||
+ use_current = ""; |
||||
+ rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: ""); |
||||
+ } |
||||
+ |
||||
+ rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current); |
||||
+ |
||||
+ if (role != NULL) |
||||
+ 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.c.role-mls 2018-08-20 07:57:29.000000000 +0200 |
||||
+++ openssh/sshd.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(1); |
@ -0,0 +1,16 @@
@@ -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,502 @@
@@ -0,0 +1,502 @@
|
||||
diff --color -ru a/ssh_config.5 b/ssh_config.5 |
||||
--- a/ssh_config.5 2022-07-12 15:05:22.550013071 +0200 |
||||
+++ b/ssh_config.5 2022-07-12 15:17:20.016704545 +0200 |
||||
@@ -373,17 +373,13 @@ |
||||
.Qq *.c.example.com |
||||
domains. |
||||
.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 |
||||
@@ -445,20 +441,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 |
||||
@@ -474,13 +475,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 |
||||
@@ -874,6 +868,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 |
||||
@@ -886,10 +885,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 |
||||
@@ -1219,29 +1216,25 @@ |
||||
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 available KEX (Key Exchange) algorithms. |
||||
Multiple algorithms must be comma-separated. |
||||
If the specified list begins with a |
||||
.Sq + |
||||
-character, then the specified methods 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 methods (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 methods will be placed at the head of the |
||||
-default set. |
||||
-The default is: |
||||
-.Bd -literal -offset indent |
||||
-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 |
||||
+built-in openssh default set. |
||||
.Pp |
||||
The list of available key exchange algorithms may also be obtained using |
||||
.Qq ssh -Q kex . |
||||
@@ -1351,37 +1344,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 |
||||
@@ -1553,37 +1542,25 @@ |
||||
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-rsa-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,ssh-rsa |
||||
-.Ed |
||||
+built-in openssh default set. |
||||
.Pp |
||||
The list of available signature algorithms may also be obtained using |
||||
.Qq ssh -Q PubkeyAcceptedAlgorithms . |
||||
diff --color -ru a/sshd_config.5 b/sshd_config.5 |
||||
--- a/sshd_config.5 2022-07-12 15:05:22.535012771 +0200 |
||||
+++ b/sshd_config.5 2022-07-12 15:15:33.394809258 +0200 |
||||
@@ -373,17 +373,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 |
||||
@@ -450,20 +446,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 |
||||
@@ -490,13 +491,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 |
||||
@@ -685,21 +679,22 @@ |
||||
.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 |
||||
Specifies the signature algorithms that will be accepted for hostbased |
||||
@@ -799,26 +794,13 @@ |
||||
.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-rsa-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,ssh-rsa |
||||
-.Ed |
||||
-.Pp |
||||
The list of available signature algorithms may also be obtained using |
||||
.Qq ssh -Q HostKeyAlgorithms . |
||||
.It Cm IgnoreRhosts |
||||
@@ -965,20 +947,25 @@ |
||||
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 available KEX (Key Exchange) algorithms. |
||||
Multiple algorithms must be comma-separated. |
||||
Alternately if the specified list begins with a |
||||
.Sq + |
||||
-character, then the specified methods 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 methods (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 methods will be placed at the head of the |
||||
-default set. |
||||
+built-in openssh default set. |
||||
The supported algorithms are: |
||||
.Pp |
||||
.Bl -item -compact -offset indent |
||||
@@ -1010,15 +997,6 @@ |
||||
sntrup761x25519-sha512@openssh.com |
||||
.El |
||||
.Pp |
||||
-The default is: |
||||
-.Bd -literal -offset indent |
||||
-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 available key exchange algorithms may also be obtained using |
||||
.Qq ssh -Q KexAlgorithms . |
||||
.It Cm ListenAddress |
||||
@@ -1104,21 +1082,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 |
||||
@@ -1161,15 +1144,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 |
||||
@@ -1548,37 +1522,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-rsa-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,ssh-rsa |
||||
-.Ed |
||||
+built-in openssh default set. |
||||
.Pp |
||||
The list of available signature algorithms may also be obtained using |
||||
.Qq ssh -Q PubkeyAcceptedAlgorithms . |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
@@ -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,720 @@
@@ -0,0 +1,720 @@
|
||||
From ed7ec0cdf577ffbb0b15145340cf51596ca3eb89 Mon Sep 17 00:00:00 2001 |
||||
From: Jakub Jelen <jjelen@redhat.com> |
||||
Date: Tue, 14 May 2019 10:45:45 +0200 |
||||
Subject: [PATCH] Use high-level OpenSSL API for signatures |
||||
|
||||
--- |
||||
digest-openssl.c | 16 ++++ |
||||
digest.h | 6 ++ |
||||
ssh-dss.c | 65 ++++++++++------ |
||||
ssh-ecdsa.c | 69 ++++++++++------- |
||||
ssh-rsa.c | 193 +++++++++-------------------------------------- |
||||
sshkey.c | 77 +++++++++++++++++++ |
||||
sshkey.h | 4 + |
||||
7 files changed, 221 insertions(+), 209 deletions(-) |
||||
|
||||
diff --git a/digest-openssl.c b/digest-openssl.c |
||||
index da7ed72bc..6a21d8adb 100644 |
||||
--- a/digest-openssl.c |
||||
+++ b/digest-openssl.c |
||||
@@ -63,6 +63,22 @@ const struct ssh_digest digests[] = { |
||||
{ -1, NULL, 0, NULL }, |
||||
}; |
||||
|
||||
+const EVP_MD * |
||||
+ssh_digest_to_md(int digest_type) |
||||
+{ |
||||
+ switch (digest_type) { |
||||
+ case SSH_DIGEST_SHA1: |
||||
+ return EVP_sha1(); |
||||
+ case SSH_DIGEST_SHA256: |
||||
+ return EVP_sha256(); |
||||
+ case SSH_DIGEST_SHA384: |
||||
+ return EVP_sha384(); |
||||
+ case SSH_DIGEST_SHA512: |
||||
+ return EVP_sha512(); |
||||
+ } |
||||
+ return NULL; |
||||
+} |
||||
+ |
||||
static const struct ssh_digest * |
||||
ssh_digest_by_alg(int alg) |
||||
{ |
||||
diff --git a/digest.h b/digest.h |
||||
index 274574d0e..c7ceeb36f 100644 |
||||
--- a/digest.h |
||||
+++ b/digest.h |
||||
@@ -32,6 +32,12 @@ |
||||
struct sshbuf; |
||||
struct ssh_digest_ctx; |
||||
|
||||
+#ifdef WITH_OPENSSL |
||||
+#include <openssl/evp.h> |
||||
+/* Converts internal digest representation to the OpenSSL one */ |
||||
+const EVP_MD *ssh_digest_to_md(int digest_type); |
||||
+#endif |
||||
+ |
||||
/* Looks up a digest algorithm by name */ |
||||
int ssh_digest_alg_by_name(const char *name); |
||||
|
||||
diff --git a/ssh-dss.c b/ssh-dss.c |
||||
index a23c383dc..ea45e7275 100644 |
||||
--- a/ssh-dss.c |
||||
+++ b/ssh-dss.c |
||||
@@ -52,11 +52,15 @@ int |
||||
ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
const u_char *data, size_t datalen, u_int compat) |
||||
{ |
||||
+ EVP_PKEY *pkey = NULL; |
||||
DSA_SIG *sig = NULL; |
||||
const BIGNUM *sig_r, *sig_s; |
||||
- u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; |
||||
- size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); |
||||
+ u_char sigblob[SIGBLOB_LEN]; |
||||
+ size_t rlen, slen; |
||||
+ int len; |
||||
struct sshbuf *b = NULL; |
||||
+ u_char *sigb = NULL; |
||||
+ const u_char *psig = NULL; |
||||
int ret = SSH_ERR_INVALID_ARGUMENT; |
||||
|
||||
if (lenp != NULL) |
||||
@@ -67,17 +71,24 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
if (key == NULL || key->dsa == NULL || |
||||
sshkey_type_plain(key->type) != KEY_DSA) |
||||
return SSH_ERR_INVALID_ARGUMENT; |
||||
- if (dlen == 0) |
||||
- return SSH_ERR_INTERNAL_ERROR; |
||||
|
||||
- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, |
||||
- digest, sizeof(digest))) != 0) |
||||
+ if ((pkey = EVP_PKEY_new()) == NULL || |
||||
+ EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) |
||||
+ return SSH_ERR_ALLOC_FAIL; |
||||
+ ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len, |
||||
+ data, datalen); |
||||
+ EVP_PKEY_free(pkey); |
||||
+ if (ret < 0) { |
||||
goto out; |
||||
+ } |
||||
|
||||
- if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { |
||||
+ psig = sigb; |
||||
+ if ((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL) { |
||||
ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
} |
||||
+ free(sigb); |
||||
+ sigb = NULL; |
||||
|
||||
DSA_SIG_get0(sig, &sig_r, &sig_s); |
||||
rlen = BN_num_bytes(sig_r); |
||||
@@ -110,7 +121,7 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
*lenp = len; |
||||
ret = 0; |
||||
out: |
||||
- explicit_bzero(digest, sizeof(digest)); |
||||
+ free(sigb); |
||||
DSA_SIG_free(sig); |
||||
sshbuf_free(b); |
||||
return ret; |
||||
@@ -121,20 +132,20 @@ ssh_dss_verify(const struct sshkey *key, |
||||
const u_char *signature, size_t signaturelen, |
||||
const u_char *data, size_t datalen, u_int compat) |
||||
{ |
||||
+ EVP_PKEY *pkey = NULL; |
||||
DSA_SIG *sig = NULL; |
||||
BIGNUM *sig_r = NULL, *sig_s = NULL; |
||||
- u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; |
||||
- size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); |
||||
+ u_char *sigblob = NULL; |
||||
+ size_t len, slen; |
||||
int ret = SSH_ERR_INTERNAL_ERROR; |
||||
struct sshbuf *b = NULL; |
||||
char *ktype = NULL; |
||||
+ u_char *sigb = NULL, *psig = NULL; |
||||
|
||||
if (key == NULL || key->dsa == NULL || |
||||
sshkey_type_plain(key->type) != KEY_DSA || |
||||
signature == NULL || signaturelen == 0) |
||||
return SSH_ERR_INVALID_ARGUMENT; |
||||
- if (dlen == 0) |
||||
- return SSH_ERR_INTERNAL_ERROR; |
||||
|
||||
/* fetch signature */ |
||||
if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
||||
@@ -176,25 +187,31 @@ ssh_dss_verify(const struct sshkey *key, |
||||
} |
||||
sig_r = sig_s = NULL; /* transferred */ |
||||
|
||||
- /* sha1 the data */ |
||||
- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, |
||||
- digest, sizeof(digest))) != 0) |
||||
+ if ((slen = i2d_DSA_SIG(sig, NULL)) == 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
- |
||||
- switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { |
||||
- case 1: |
||||
- ret = 0; |
||||
- break; |
||||
- case 0: |
||||
- ret = SSH_ERR_SIGNATURE_INVALID; |
||||
+ } |
||||
+ if ((sigb = malloc(slen)) == NULL) { |
||||
+ ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
- default: |
||||
+ } |
||||
+ psig = sigb; |
||||
+ if ((slen = i2d_DSA_SIG(sig, &psig)) == 0) { |
||||
ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
} |
||||
|
||||
+ if ((pkey = EVP_PKEY_new()) == NULL || |
||||
+ EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) { |
||||
+ ret = SSH_ERR_ALLOC_FAIL; |
||||
+ goto out; |
||||
+ } |
||||
+ ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, datalen, |
||||
+ sigb, slen); |
||||
+ EVP_PKEY_free(pkey); |
||||
+ |
||||
out: |
||||
- explicit_bzero(digest, sizeof(digest)); |
||||
+ free(sigb); |
||||
DSA_SIG_free(sig); |
||||
BN_clear_free(sig_r); |
||||
BN_clear_free(sig_s); |
||||
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c |
||||
index 599c7199d..b036796e8 100644 |
||||
--- a/ssh-ecdsa.c |
||||
+++ b/ssh-ecdsa.c |
||||
@@ -50,11 +50,13 @@ int |
||||
ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
const u_char *data, size_t datalen, u_int compat) |
||||
{ |
||||
+ EVP_PKEY *pkey = NULL; |
||||
ECDSA_SIG *sig = NULL; |
||||
+ unsigned char *sigb = NULL; |
||||
+ const unsigned char *psig; |
||||
const BIGNUM *sig_r, *sig_s; |
||||
int hash_alg; |
||||
- u_char digest[SSH_DIGEST_MAX_LENGTH]; |
||||
- size_t len, dlen; |
||||
+ int len; |
||||
struct sshbuf *b = NULL, *bb = NULL; |
||||
int ret = SSH_ERR_INTERNAL_ERROR; |
||||
|
||||
@@ -67,18 +69,24 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
sshkey_type_plain(key->type) != KEY_ECDSA) |
||||
return SSH_ERR_INVALID_ARGUMENT; |
||||
|
||||
- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || |
||||
- (dlen = ssh_digest_bytes(hash_alg)) == 0) |
||||
+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) |
||||
return SSH_ERR_INTERNAL_ERROR; |
||||
- if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
||||
- digest, sizeof(digest))) != 0) |
||||
+ |
||||
+ if ((pkey = EVP_PKEY_new()) == NULL || |
||||
+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) |
||||
+ return SSH_ERR_ALLOC_FAIL; |
||||
+ ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, |
||||
+ datalen); |
||||
+ EVP_PKEY_free(pkey); |
||||
+ if (ret < 0) { |
||||
goto out; |
||||
+ } |
||||
|
||||
- if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) { |
||||
+ psig = sigb; |
||||
+ if ((sig = d2i_ECDSA_SIG(NULL, &psig, len)) == NULL) { |
||||
ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
} |
||||
- |
||||
if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { |
||||
ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
@@ -102,7 +110,7 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
*lenp = len; |
||||
ret = 0; |
||||
out: |
||||
- explicit_bzero(digest, sizeof(digest)); |
||||
+ free(sigb); |
||||
sshbuf_free(b); |
||||
sshbuf_free(bb); |
||||
ECDSA_SIG_free(sig); |
||||
@@ -115,22 +123,21 @@ ssh_ecdsa_verify(const struct sshkey *key, |
||||
const u_char *signature, size_t signaturelen, |
||||
const u_char *data, size_t datalen, u_int compat) |
||||
{ |
||||
+ EVP_PKEY *pkey = NULL; |
||||
ECDSA_SIG *sig = NULL; |
||||
BIGNUM *sig_r = NULL, *sig_s = NULL; |
||||
- int hash_alg; |
||||
- u_char digest[SSH_DIGEST_MAX_LENGTH]; |
||||
- size_t dlen; |
||||
+ int hash_alg, len; |
||||
int ret = SSH_ERR_INTERNAL_ERROR; |
||||
struct sshbuf *b = NULL, *sigbuf = NULL; |
||||
char *ktype = NULL; |
||||
+ unsigned char *sigb = NULL, *psig = NULL; |
||||
|
||||
if (key == NULL || key->ecdsa == NULL || |
||||
sshkey_type_plain(key->type) != KEY_ECDSA || |
||||
signature == NULL || signaturelen == 0) |
||||
return SSH_ERR_INVALID_ARGUMENT; |
||||
|
||||
- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || |
||||
- (dlen = ssh_digest_bytes(hash_alg)) == 0) |
||||
+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) |
||||
return SSH_ERR_INTERNAL_ERROR; |
||||
|
||||
/* fetch signature */ |
||||
@@ -166,28 +173,36 @@ ssh_ecdsa_verify(const struct sshkey *key, |
||||
} |
||||
sig_r = sig_s = NULL; /* transferred */ |
||||
|
||||
- if (sshbuf_len(sigbuf) != 0) { |
||||
- ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
||||
+ /* Figure out the length */ |
||||
+ if ((len = i2d_ECDSA_SIG(sig, NULL)) == 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ if ((sigb = malloc(len)) == NULL) { |
||||
+ ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
} |
||||
- if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
||||
- digest, sizeof(digest))) != 0) |
||||
+ psig = sigb; |
||||
+ if ((len = i2d_ECDSA_SIG(sig, &psig)) == 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
+ } |
||||
|
||||
- switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) { |
||||
- case 1: |
||||
- ret = 0; |
||||
- break; |
||||
- case 0: |
||||
- ret = SSH_ERR_SIGNATURE_INVALID; |
||||
+ if (sshbuf_len(sigbuf) != 0) { |
||||
+ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
||||
goto out; |
||||
- default: |
||||
- ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ } |
||||
+ |
||||
+ if ((pkey = EVP_PKEY_new()) == NULL || |
||||
+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) { |
||||
+ ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
} |
||||
+ ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, sigb, len); |
||||
+ EVP_PKEY_free(pkey); |
||||
|
||||
out: |
||||
- explicit_bzero(digest, sizeof(digest)); |
||||
+ free(sigb); |
||||
sshbuf_free(sigbuf); |
||||
sshbuf_free(b); |
||||
ECDSA_SIG_free(sig); |
||||
diff --git a/ssh-rsa.c b/ssh-rsa.c |
||||
index 9b14f9a9a..8ef3a6aca 100644 |
||||
--- a/ssh-rsa.c |
||||
+++ b/ssh-rsa.c |
||||
@@ -37,7 +37,7 @@ |
||||
|
||||
#include "openbsd-compat/openssl-compat.h" |
||||
|
||||
-static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); |
||||
+static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP_PKEY *); |
||||
|
||||
static const char * |
||||
rsa_hash_alg_ident(int hash_alg) |
||||
@@ -90,21 +90,6 @@ rsa_hash_id_from_keyname(const char *alg) |
||||
return -1; |
||||
} |
||||
|
||||
-static int |
||||
-rsa_hash_alg_nid(int type) |
||||
-{ |
||||
- switch (type) { |
||||
- case SSH_DIGEST_SHA1: |
||||
- return NID_sha1; |
||||
- case SSH_DIGEST_SHA256: |
||||
- return NID_sha256; |
||||
- case SSH_DIGEST_SHA512: |
||||
- return NID_sha512; |
||||
- default: |
||||
- return -1; |
||||
- } |
||||
-} |
||||
- |
||||
int |
||||
ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) |
||||
{ |
||||
@@ -164,11 +149,10 @@ int |
||||
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
const u_char *data, size_t datalen, const char *alg_ident) |
||||
{ |
||||
- const BIGNUM *rsa_n; |
||||
- u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; |
||||
- size_t slen = 0; |
||||
- u_int dlen, len; |
||||
- int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
||||
+ EVP_PKEY *pkey = NULL; |
||||
+ u_char *sig = NULL; |
||||
+ int len, slen = 0; |
||||
+ int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
||||
struct sshbuf *b = NULL; |
||||
|
||||
if (lenp != NULL) |
||||
@@ -180,33 +164,24 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
hash_alg = SSH_DIGEST_SHA1; |
||||
else |
||||
hash_alg = rsa_hash_id_from_keyname(alg_ident); |
||||
+ |
||||
if (key == NULL || key->rsa == NULL || hash_alg == -1 || |
||||
sshkey_type_plain(key->type) != KEY_RSA) |
||||
return SSH_ERR_INVALID_ARGUMENT; |
||||
- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); |
||||
- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
||||
- return SSH_ERR_KEY_LENGTH; |
||||
slen = RSA_size(key->rsa); |
||||
- if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) |
||||
- return SSH_ERR_INVALID_ARGUMENT; |
||||
- |
||||
- /* hash the data */ |
||||
- nid = rsa_hash_alg_nid(hash_alg); |
||||
- if ((dlen = ssh_digest_bytes(hash_alg)) == 0) |
||||
- return SSH_ERR_INTERNAL_ERROR; |
||||
- if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
||||
- digest, sizeof(digest))) != 0) |
||||
- goto out; |
||||
+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
||||
+ return SSH_ERR_KEY_LENGTH; |
||||
|
||||
- if ((sig = malloc(slen)) == NULL) { |
||||
- ret = SSH_ERR_ALLOC_FAIL; |
||||
+ if ((pkey = EVP_PKEY_new()) == NULL || |
||||
+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) |
||||
+ return SSH_ERR_ALLOC_FAIL; |
||||
+ ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, |
||||
+ datalen); |
||||
+ EVP_PKEY_free(pkey); |
||||
+ if (ret < 0) { |
||||
goto out; |
||||
} |
||||
|
||||
- if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { |
||||
- ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
- goto out; |
||||
- } |
||||
if (len < slen) { |
||||
size_t diff = slen - len; |
||||
memmove(sig + diff, sig, len); |
||||
@@ -215,6 +190,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
ret = SSH_ERR_INTERNAL_ERROR; |
||||
goto out; |
||||
} |
||||
+ |
||||
/* encode signature */ |
||||
if ((b = sshbuf_new()) == NULL) { |
||||
ret = SSH_ERR_ALLOC_FAIL; |
||||
@@ -235,7 +211,6 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
||||
*lenp = len; |
||||
ret = 0; |
||||
out: |
||||
- explicit_bzero(digest, sizeof(digest)); |
||||
freezero(sig, slen); |
||||
sshbuf_free(b); |
||||
return ret; |
||||
@@ -246,10 +221,10 @@ ssh_rsa_verify(const struct sshkey *key, |
||||
const u_char *sig, size_t siglen, const u_char *data, size_t datalen, |
||||
const char *alg) |
||||
{ |
||||
- const BIGNUM *rsa_n; |
||||
+ EVP_PKEY *pkey = NULL; |
||||
char *sigtype = NULL; |
||||
int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; |
||||
- size_t len = 0, diff, modlen, dlen; |
||||
+ size_t len = 0, diff, modlen; |
||||
struct sshbuf *b = NULL; |
||||
u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; |
||||
|
||||
@@ -257,8 +232,7 @@ ssh_rsa_verify(const struct sshkey *key, |
||||
sshkey_type_plain(key->type) != KEY_RSA || |
||||
sig == NULL || siglen == 0) |
||||
return SSH_ERR_INVALID_ARGUMENT; |
||||
- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); |
||||
- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
||||
+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
||||
return SSH_ERR_KEY_LENGTH; |
||||
|
||||
if ((b = sshbuf_from(sig, siglen)) == NULL) |
||||
@@ -310,16 +284,15 @@ ssh_rsa_verify(const struct sshkey *key, |
||||
explicit_bzero(sigblob, diff); |
||||
len = modlen; |
||||
} |
||||
- if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { |
||||
- ret = SSH_ERR_INTERNAL_ERROR; |
||||
+ |
||||
+ if ((pkey = EVP_PKEY_new()) == NULL || |
||||
+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) { |
||||
+ ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
} |
||||
- if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
||||
- digest, sizeof(digest))) != 0) |
||||
- goto out; |
||||
+ ret = openssh_RSA_verify(hash_alg, data, datalen, sigblob, len, pkey); |
||||
+ EVP_PKEY_free(pkey); |
||||
|
||||
- ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, |
||||
- key->rsa); |
||||
out: |
||||
freezero(sigblob, len); |
||||
free(sigtype); |
||||
@@ -328,122 +301,26 @@ ssh_rsa_verify(const struct sshkey *key, |
||||
return ret; |
||||
} |
||||
|
||||
-/* |
||||
- * See: |
||||
- * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ |
||||
- * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn |
||||
- */ |
||||
- |
||||
-/* |
||||
- * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) |
||||
- * oiw(14) secsig(3) algorithms(2) 26 } |
||||
- */ |
||||
-static const u_char id_sha1[] = { |
||||
- 0x30, 0x21, /* type Sequence, length 0x21 (33) */ |
||||
- 0x30, 0x09, /* type Sequence, length 0x09 */ |
||||
- 0x06, 0x05, /* type OID, length 0x05 */ |
||||
- 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ |
||||
- 0x05, 0x00, /* NULL */ |
||||
- 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ |
||||
-}; |
||||
- |
||||
-/* |
||||
- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html |
||||
- * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) |
||||
- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) |
||||
- * id-sha256(1) } |
||||
- */ |
||||
-static const u_char id_sha256[] = { |
||||
- 0x30, 0x31, /* type Sequence, length 0x31 (49) */ |
||||
- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ |
||||
- 0x06, 0x09, /* type OID, length 0x09 */ |
||||
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ |
||||
- 0x05, 0x00, /* NULL */ |
||||
- 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ |
||||
-}; |
||||
- |
||||
-/* |
||||
- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html |
||||
- * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) |
||||
- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) |
||||
- * id-sha256(3) } |
||||
- */ |
||||
-static const u_char id_sha512[] = { |
||||
- 0x30, 0x51, /* type Sequence, length 0x51 (81) */ |
||||
- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ |
||||
- 0x06, 0x09, /* type OID, length 0x09 */ |
||||
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ |
||||
- 0x05, 0x00, /* NULL */ |
||||
- 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ |
||||
-}; |
||||
- |
||||
static int |
||||
-rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) |
||||
+openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, |
||||
+ u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) |
||||
{ |
||||
- switch (hash_alg) { |
||||
- case SSH_DIGEST_SHA1: |
||||
- *oidp = id_sha1; |
||||
- *oidlenp = sizeof(id_sha1); |
||||
- break; |
||||
- case SSH_DIGEST_SHA256: |
||||
- *oidp = id_sha256; |
||||
- *oidlenp = sizeof(id_sha256); |
||||
- break; |
||||
- case SSH_DIGEST_SHA512: |
||||
- *oidp = id_sha512; |
||||
- *oidlenp = sizeof(id_sha512); |
||||
- break; |
||||
- default: |
||||
- return SSH_ERR_INVALID_ARGUMENT; |
||||
- } |
||||
- return 0; |
||||
-} |
||||
+ size_t rsasize = 0; |
||||
+ const RSA *rsa; |
||||
+ int ret; |
||||
|
||||
-static int |
||||
-openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, |
||||
- u_char *sigbuf, size_t siglen, RSA *rsa) |
||||
-{ |
||||
- size_t rsasize = 0, oidlen = 0, hlen = 0; |
||||
- int ret, len, oidmatch, hashmatch; |
||||
- const u_char *oid = NULL; |
||||
- u_char *decrypted = NULL; |
||||
- |
||||
- if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) |
||||
- return ret; |
||||
- ret = SSH_ERR_INTERNAL_ERROR; |
||||
- hlen = ssh_digest_bytes(hash_alg); |
||||
- if (hashlen != hlen) { |
||||
- ret = SSH_ERR_INVALID_ARGUMENT; |
||||
- goto done; |
||||
- } |
||||
+ rsa = EVP_PKEY_get0_RSA(pkey); |
||||
rsasize = RSA_size(rsa); |
||||
if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || |
||||
siglen == 0 || siglen > rsasize) { |
||||
ret = SSH_ERR_INVALID_ARGUMENT; |
||||
goto done; |
||||
} |
||||
- if ((decrypted = malloc(rsasize)) == NULL) { |
||||
- ret = SSH_ERR_ALLOC_FAIL; |
||||
- goto done; |
||||
- } |
||||
- if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, |
||||
- RSA_PKCS1_PADDING)) < 0) { |
||||
- ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
- goto done; |
||||
- } |
||||
- if (len < 0 || (size_t)len != hlen + oidlen) { |
||||
- ret = SSH_ERR_INVALID_FORMAT; |
||||
- goto done; |
||||
- } |
||||
- oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; |
||||
- hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; |
||||
- if (!oidmatch || !hashmatch) { |
||||
- ret = SSH_ERR_SIGNATURE_INVALID; |
||||
- goto done; |
||||
- } |
||||
- ret = 0; |
||||
+ |
||||
+ ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, |
||||
+ sigbuf, siglen); |
||||
+ |
||||
done: |
||||
- freezero(decrypted, rsasize); |
||||
return ret; |
||||
} |
||||
#endif /* WITH_OPENSSL */ |
||||
diff --git a/sshkey.c b/sshkey.c |
||||
index ad1957762..b95ed0b10 100644 |
||||
--- a/sshkey.c |
||||
+++ b/sshkey.c |
||||
@@ -358,6 +358,83 @@ sshkey_type_plain(int type) |
||||
} |
||||
|
||||
#ifdef WITH_OPENSSL |
||||
+int |
||||
+sshkey_calculate_signature(EVP_PKEY *pkey, int hash_alg, u_char **sigp, |
||||
+ int *lenp, const u_char *data, size_t datalen) |
||||
+{ |
||||
+ EVP_MD_CTX *ctx = NULL; |
||||
+ u_char *sig = NULL; |
||||
+ int ret, slen, len; |
||||
+ |
||||
+ if (sigp == NULL || lenp == NULL) { |
||||
+ return SSH_ERR_INVALID_ARGUMENT; |
||||
+ } |
||||
+ |
||||
+ slen = EVP_PKEY_size(pkey); |
||||
+ if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) |
||||
+ return SSH_ERR_INVALID_ARGUMENT; |
||||
+ |
||||
+ len = slen; |
||||
+ if ((sig = malloc(slen)) == NULL) { |
||||
+ return SSH_ERR_ALLOC_FAIL; |
||||
+ } |
||||
+ |
||||
+ if ((ctx = EVP_MD_CTX_new()) == NULL) { |
||||
+ ret = SSH_ERR_ALLOC_FAIL; |
||||
+ goto error; |
||||
+ } |
||||
+ if (EVP_SignInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 || |
||||
+ EVP_SignUpdate(ctx, data, datalen) <= 0 || |
||||
+ EVP_SignFinal(ctx, sig, &len, pkey) <= 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto error; |
||||
+ } |
||||
+ |
||||
+ *sigp = sig; |
||||
+ *lenp = len; |
||||
+ /* Now owned by the caller */ |
||||
+ sig = NULL; |
||||
+ ret = 0; |
||||
+ |
||||
+error: |
||||
+ EVP_MD_CTX_free(ctx); |
||||
+ free(sig); |
||||
+ return ret; |
||||
+} |
||||
+ |
||||
+int |
||||
+sshkey_verify_signature(EVP_PKEY *pkey, int hash_alg, const u_char *data, |
||||
+ size_t datalen, u_char *sigbuf, int siglen) |
||||
+{ |
||||
+ EVP_MD_CTX *ctx = NULL; |
||||
+ int ret; |
||||
+ |
||||
+ if ((ctx = EVP_MD_CTX_new()) == NULL) { |
||||
+ return SSH_ERR_ALLOC_FAIL; |
||||
+ } |
||||
+ if (EVP_VerifyInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 || |
||||
+ EVP_VerifyUpdate(ctx, data, datalen) <= 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto done; |
||||
+ } |
||||
+ ret = EVP_VerifyFinal(ctx, sigbuf, siglen, pkey); |
||||
+ switch (ret) { |
||||
+ case 1: |
||||
+ ret = 0; |
||||
+ break; |
||||
+ case 0: |
||||
+ ret = SSH_ERR_SIGNATURE_INVALID; |
||||
+ break; |
||||
+ default: |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ break; |
||||
+ } |
||||
+ |
||||
+done: |
||||
+ EVP_MD_CTX_free(ctx); |
||||
+ return ret; |
||||
+} |
||||
+ |
||||
/* XXX: these are really begging for a table-driven approach */ |
||||
int |
||||
sshkey_curve_name_to_nid(const char *name) |
||||
diff --git a/sshkey.h b/sshkey.h |
||||
index a91e60436..270901a87 100644 |
||||
--- a/sshkey.h |
||||
+++ b/sshkey.h |
||||
@@ -179,6 +179,10 @@ const char *sshkey_ssh_name(const struct sshkey *); |
||||
const char *sshkey_ssh_name_plain(const struct sshkey *); |
||||
int sshkey_names_valid2(const char *, int); |
||||
char *sshkey_alg_list(int, int, int, char); |
||||
+int sshkey_calculate_signature(EVP_PKEY*, int, u_char **, |
||||
+ int *, const u_char *, size_t); |
||||
+int sshkey_verify_signature(EVP_PKEY *, int, const u_char *, |
||||
+ size_t, u_char *, int); |
||||
|
||||
int sshkey_from_blob(const u_char *, size_t, struct sshkey **); |
||||
int sshkey_fromb(struct sshbuf *, struct sshkey **); |
||||
|
@ -0,0 +1,137 @@
@@ -0,0 +1,137 @@
|
||||
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_id \ |
||||
]) |
||||
|
||||
# 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,9 @@ |
||||
#ifdef WITH_OPENSSL |
||||
#include <openssl/crypto.h> |
||||
#include <openssl/dh.h> |
||||
+# ifdef HAVE_EVP_KDF_CTX_NEW_ID |
||||
+# include <openssl/kdf.h> |
||||
+# endif |
||||
#endif |
||||
|
||||
#include "ssh.h" |
||||
@@ -942,6 +945,95 @@ kex_choose_conf(struct ssh *ssh) |
||||
return r; |
||||
} |
||||
|
||||
+#ifdef HAVE_EVP_KDF_CTX_NEW_ID |
||||
+static const EVP_MD * |
||||
+digest_to_md(int digest_type) |
||||
+{ |
||||
+ switch (digest_type) { |
||||
+ case SSH_DIGEST_SHA1: |
||||
+ return EVP_sha1(); |
||||
+ case SSH_DIGEST_SHA256: |
||||
+ return EVP_sha256(); |
||||
+ case SSH_DIGEST_SHA384: |
||||
+ return EVP_sha384(); |
||||
+ case SSH_DIGEST_SHA512: |
||||
+ return EVP_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; |
||||
+ EVP_KDF_CTX *ctx = NULL; |
||||
+ u_char *key = NULL; |
||||
+ int r, key_len; |
||||
+ |
||||
+ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) |
||||
+ return SSH_ERR_INVALID_ARGUMENT; |
||||
+ key_len = ROUNDUP(need, key_len); |
||||
+ if ((key = calloc(1, key_len)) == NULL) { |
||||
+ r = SSH_ERR_ALLOC_FAIL; |
||||
+ goto out; |
||||
+ } |
||||
+ |
||||
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF); |
||||
+ if (!ctx) { |
||||
+ r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ |
||||
+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest_to_md(kex->hash_alg)); |
||||
+ if (r != 1) { |
||||
+ r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, |
||||
+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)); |
||||
+ if (r != 1) { |
||||
+ r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, hash, hashlen); |
||||
+ if (r != 1) { |
||||
+ r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, id); |
||||
+ if (r != 1) { |
||||
+ r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, |
||||
+ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)); |
||||
+ if (r != 1) { |
||||
+ r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ r = EVP_KDF_derive(ctx, key, key_len); |
||||
+ 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: |
||||
+ 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_ID */ |
||||
|
||||
#define NKEYS 6 |
||||
int |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
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,10 +862,12 @@ sshpam_query(void *ctx, char **name, cha |
||||
plen++; |
||||
free(msg); |
||||
break; |
||||
+ case PAM_USER_UNKNOWN: |
||||
+ case PAM_PERM_DENIED: |
||||
case PAM_ACCT_EXPIRED: |
||||
+ sshpam_account_status = 0; |
||||
+ /* FALLTHROUGH */ |
||||
case PAM_MAXTRIES: |
||||
- if (type == PAM_ACCT_EXPIRED) |
||||
- sshpam_account_status = 0; |
||||
if (type == PAM_MAXTRIES) |
||||
sshpam_set_maxtries_reached(1); |
||||
/* FALLTHROUGH */ |
@ -0,0 +1,40 @@
@@ -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 @@
@@ -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,110 @@
@@ -0,0 +1,110 @@
|
||||
diff -up openssh-8.7p1/sshkey.c.evpgenrsa openssh-8.7p1/sshkey.c |
||||
--- openssh-8.7p1/sshkey.c.evpgenrsa 2022-06-30 15:14:58.200518353 +0200 |
||||
+++ openssh-8.7p1/sshkey.c 2022-06-30 15:24:31.499641196 +0200 |
||||
@@ -1657,7 +1657,8 @@ sshkey_cert_type(const struct sshkey *k) |
||||
static int |
||||
rsa_generate_private_key(u_int bits, RSA **rsap) |
||||
{ |
||||
- RSA *private = NULL; |
||||
+ EVP_PKEY_CTX *ctx = NULL; |
||||
+ EVP_PKEY *res = NULL; |
||||
BIGNUM *f4 = NULL; |
||||
int ret = SSH_ERR_INTERNAL_ERROR; |
||||
|
||||
@@ -1667,20 +1668,42 @@ rsa_generate_private_key(u_int bits, RSA |
||||
bits > SSHBUF_MAX_BIGNUM * 8) |
||||
return SSH_ERR_KEY_LENGTH; |
||||
*rsap = NULL; |
||||
- if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { |
||||
+ |
||||
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL |
||||
+ || (f4 = BN_new()) == NULL || !BN_set_word(f4, RSA_F4)) { |
||||
ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
} |
||||
- if (!BN_set_word(f4, RSA_F4) || |
||||
- !RSA_generate_key_ex(private, bits, f4, NULL)) { |
||||
+ |
||||
+ if (EVP_PKEY_keygen_init(ctx) <= 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ |
||||
+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) { |
||||
+ ret = SSH_ERR_KEY_LENGTH; |
||||
+ goto out; |
||||
+ } |
||||
+ |
||||
+ if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, f4) <= 0) |
||||
+ goto out; |
||||
+ |
||||
+ if (EVP_PKEY_keygen(ctx, &res) <= 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ |
||||
+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ |
||||
+ *rsap = EVP_PKEY_get1_RSA(res); |
||||
+ if (*rsap) { |
||||
+ ret = 0; |
||||
+ } else { |
||||
ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
} |
||||
- *rsap = private; |
||||
- private = NULL; |
||||
- ret = 0; |
||||
out: |
||||
- RSA_free(private); |
||||
+ EVP_PKEY_CTX_free(ctx); |
||||
+ EVP_PKEY_free(res); |
||||
BN_free(f4); |
||||
return ret; |
||||
} |
||||
@@ -1820,7 +1820,8 @@ sshkey_ecdsa_key_to_nid(EC_KEY *k) |
||||
static int |
||||
ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap) |
||||
{ |
||||
- EC_KEY *private; |
||||
+ EVP_PKEY_CTX *ctx = NULL; |
||||
+ EVP_PKEY *res = NULL; |
||||
int ret = SSH_ERR_INTERNAL_ERROR; |
||||
|
||||
if (nid == NULL || ecdsap == NULL) |
||||
@@ -1828,20 +1829,29 @@ ecdsa_generate_private_key(u_int bits, i |
||||
if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) |
||||
return SSH_ERR_KEY_LENGTH; |
||||
*ecdsap = NULL; |
||||
- if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) { |
||||
+ |
||||
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) { |
||||
ret = SSH_ERR_ALLOC_FAIL; |
||||
goto out; |
||||
} |
||||
- if (EC_KEY_generate_key(private) != 1) { |
||||
+ |
||||
+ if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_group_name(ctx, OBJ_nid2sn(*nid)) <= 0 |
||||
+ || EVP_PKEY_keygen(ctx, &res) <= 0) { |
||||
+ ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
+ goto out; |
||||
+ } |
||||
+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ |
||||
+ *ecdsap = EVP_PKEY_get1_EC_KEY(res); |
||||
+ if (*ecdsap) { |
||||
+ EC_KEY_set_asn1_flag(*ecdsap, OPENSSL_EC_NAMED_CURVE); |
||||
+ ret = 0; |
||||
+ } else { |
||||
ret = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
} |
||||
- EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); |
||||
- *ecdsap = private; |
||||
- private = NULL; |
||||
- ret = 0; |
||||
out: |
||||
- EC_KEY_free(private); |
||||
+ EVP_PKEY_CTX_free(ctx); |
||||
+ EVP_PKEY_free(res); |
||||
return ret; |
||||
} |
||||
# endif /* OPENSSL_HAS_ECC */ |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
diff -up openssh-8.7p1/ssh-keygen.c.find-princ openssh-8.7p1/ssh-keygen.c |
||||
--- openssh-8.7p1/ssh-keygen.c.find-princ 2021-11-29 15:27:03.032070863 +0100 |
||||
+++ openssh-8.7p1/ssh-keygen.c 2021-11-29 15:27:34.736342968 +0100 |
||||
@@ -2700,7 +2700,8 @@ sig_process_opts(char * const *opts, siz |
||||
time_t now; |
||||
|
||||
*verify_timep = 0; |
||||
- *print_pubkey = 0; |
||||
+ if (print_pubkey) |
||||
+ *print_pubkey = 0; |
||||
for (i = 0; i < nopts; i++) { |
||||
if (strncasecmp(opts[i], "verify-time=", 12) == 0) { |
||||
if (parse_absolute_time(opts[i] + 12, |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
diff --color -rup a/monitor.c b/monitor.c |
||||
--- a/monitor.c 2022-07-11 15:11:28.146863144 +0200 |
||||
+++ b/monitor.c 2022-07-11 15:15:35.726655877 +0200 |
||||
@@ -376,8 +376,15 @@ monitor_child_preauth(struct ssh *ssh, s |
||||
if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) { |
||||
auth_log(ssh, authenticated, partial, |
||||
auth_method, auth_submethod); |
||||
- if (!partial && !authenticated) |
||||
+ if (!partial && !authenticated) { |
||||
+#ifdef GSSAPI |
||||
+ /* If gssapi-with-mic failed, MONITOR_REQ_GSSCHECKMIC is disabled. |
||||
+ * We have to reenable it to try again for gssapi-keyex */ |
||||
+ if (strcmp(auth_method, "gssapi-with-mic") == 0 && options.gss_keyex) |
||||
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); |
||||
+#endif |
||||
authctxt->failures++; |
||||
+ } |
||||
if (authenticated || partial) { |
||||
auth2_update_session_info(authctxt, |
||||
auth_method, auth_submethod); |
@ -0,0 +1,151 @@
@@ -0,0 +1,151 @@
|
||||
diff --color -rup a/sshconnect2.c b/sshconnect2.c |
||||
--- a/sshconnect2.c 2022-07-11 17:00:02.618575727 +0200 |
||||
+++ b/sshconnect2.c 2022-07-11 17:03:05.096085690 +0200 |
||||
@@ -2288,9 +2288,9 @@ userauth_hostbased(struct ssh *ssh) |
||||
if (authctxt->sensitive->keys[i] == NULL || |
||||
authctxt->sensitive->keys[i]->type == KEY_UNSPEC) |
||||
continue; |
||||
- if (match_pattern_list( |
||||
+ if (!sshkey_match_keyname_to_sigalgs( |
||||
sshkey_ssh_name(authctxt->sensitive->keys[i]), |
||||
- authctxt->active_ktype, 0) != 1) |
||||
+ authctxt->active_ktype)) |
||||
continue; |
||||
/* we take and free the key */ |
||||
private = authctxt->sensitive->keys[i]; |
||||
@@ -2316,7 +2316,8 @@ userauth_hostbased(struct ssh *ssh) |
||||
error_f("sshkey_fingerprint failed"); |
||||
goto out; |
||||
} |
||||
- debug_f("trying hostkey %s %s", sshkey_ssh_name(private), fp); |
||||
+ debug_f("trying hostkey %s %s using sigalg %s", |
||||
+ sshkey_ssh_name(private), fp, authctxt->active_ktype); |
||||
|
||||
/* figure out a name for the client host */ |
||||
lname = get_local_name(ssh_packet_get_connection_in(ssh)); |
||||
diff --color -rup a/sshkey.c b/sshkey.c |
||||
--- a/sshkey.c 2022-07-11 17:00:02.609575554 +0200 |
||||
+++ b/sshkey.c 2022-07-11 17:12:30.905976443 +0200 |
||||
@@ -252,6 +252,29 @@ sshkey_ecdsa_nid_from_name(const char *n |
||||
return -1; |
||||
} |
||||
|
||||
+int |
||||
+sshkey_match_keyname_to_sigalgs(const char *keyname, const char *sigalgs) |
||||
+{ |
||||
+ int ktype; |
||||
+ |
||||
+ if (sigalgs == NULL || *sigalgs == '\0' || |
||||
+ (ktype = sshkey_type_from_name(keyname)) == KEY_UNSPEC) |
||||
+ return 0; |
||||
+ else if (ktype == KEY_RSA) { |
||||
+ return match_pattern_list("ssh-rsa", sigalgs, 0) == 1 || |
||||
+ match_pattern_list("rsa-sha2-256", sigalgs, 0) == 1 || |
||||
+ match_pattern_list("rsa-sha2-512", sigalgs, 0) == 1; |
||||
+ } else if (ktype == KEY_RSA_CERT) { |
||||
+ return match_pattern_list("ssh-rsa-cert-v01@openssh.com", |
||||
+ sigalgs, 0) == 1 || |
||||
+ match_pattern_list("rsa-sha2-256-cert-v01@openssh.com", |
||||
+ sigalgs, 0) == 1 || |
||||
+ match_pattern_list("rsa-sha2-512-cert-v01@openssh.com", |
||||
+ sigalgs, 0) == 1; |
||||
+ } else |
||||
+ return match_pattern_list(keyname, sigalgs, 0) == 1; |
||||
+} |
||||
+ |
||||
char * |
||||
sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) |
||||
{ |
||||
diff --color -rup a/sshkey.h b/sshkey.h |
||||
--- a/sshkey.h 2022-07-11 17:00:02.603575438 +0200 |
||||
+++ b/sshkey.h 2022-07-11 17:13:01.052556879 +0200 |
||||
@@ -194,6 +194,10 @@ int sshkey_is_cert(const struct sshkey |
||||
int sshkey_is_sk(const struct sshkey *); |
||||
int sshkey_type_is_cert(int); |
||||
int sshkey_type_plain(int); |
||||
+ |
||||
+/* Returns non-zero if key name match sigalgs pattern list. (handles RSA) */ |
||||
+int sshkey_match_keyname_to_sigalgs(const char *, const char *); |
||||
+ |
||||
int sshkey_to_certified(struct sshkey *); |
||||
int sshkey_drop_cert(struct sshkey *); |
||||
int sshkey_cert_copy(const struct sshkey *, struct sshkey *); |
||||
diff --color -rup a/ssh-keysign.c b/ssh-keysign.c |
||||
--- a/ssh-keysign.c 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ b/ssh-keysign.c 2022-07-11 17:00:23.306973667 +0200 |
||||
@@ -62,7 +62,7 @@ |
||||
extern char *__progname; |
||||
|
||||
static int |
||||
-valid_request(struct passwd *pw, char *host, struct sshkey **ret, |
||||
+valid_request(struct passwd *pw, char *host, struct sshkey **ret, char **pkalgp, |
||||
u_char *data, size_t datalen) |
||||
{ |
||||
struct sshbuf *b; |
||||
@@ -75,6 +75,8 @@ valid_request(struct passwd *pw, char *h |
||||
|
||||
if (ret != NULL) |
||||
*ret = NULL; |
||||
+ if (pkalgp != NULL) |
||||
+ *pkalgp = NULL; |
||||
fail = 0; |
||||
|
||||
if ((b = sshbuf_from(data, datalen)) == NULL) |
||||
@@ -122,8 +124,6 @@ valid_request(struct passwd *pw, char *h |
||||
fail++; |
||||
} else if (key->type != pktype) |
||||
fail++; |
||||
- free(pkalg); |
||||
- free(pkblob); |
||||
|
||||
/* client host name, handle trailing dot */ |
||||
if ((r = sshbuf_get_cstring(b, &p, &len)) != 0) |
||||
@@ -154,8 +154,19 @@ valid_request(struct passwd *pw, char *h |
||||
|
||||
if (fail) |
||||
sshkey_free(key); |
||||
- else if (ret != NULL) |
||||
- *ret = key; |
||||
+ else { |
||||
+ if (ret != NULL) { |
||||
+ *ret = key; |
||||
+ key = NULL; |
||||
+ } |
||||
+ if (pkalgp != NULL) { |
||||
+ *pkalgp = pkalg; |
||||
+ pkalg = NULL; |
||||
+ } |
||||
+ } |
||||
+ sshkey_free(key); |
||||
+ free(pkalg); |
||||
+ free(pkblob); |
||||
|
||||
return (fail ? -1 : 0); |
||||
} |
||||
@@ -170,7 +181,7 @@ main(int argc, char **argv) |
||||
struct passwd *pw; |
||||
int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd; |
||||
u_char *signature, *data, rver; |
||||
- char *host, *fp; |
||||
+ char *host, *fp, *pkalg; |
||||
size_t slen, dlen; |
||||
|
||||
if (pledge("stdio rpath getpw dns id", NULL) != 0) |
||||
@@ -258,7 +269,7 @@ main(int argc, char **argv) |
||||
|
||||
if ((r = sshbuf_get_string(b, &data, &dlen)) != 0) |
||||
fatal_r(r, "%s: buffer error", __progname); |
||||
- if (valid_request(pw, host, &key, data, dlen) < 0) |
||||
+ if (valid_request(pw, host, &key, &pkalg, data, dlen) < 0) |
||||
fatal("%s: not a valid request", __progname); |
||||
free(host); |
||||
|
||||
@@ -279,7 +290,7 @@ main(int argc, char **argv) |
||||
} |
||||
|
||||
if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen, |
||||
- NULL, NULL, NULL, 0)) != 0) |
||||
+ pkalg, NULL, NULL, 0)) != 0) |
||||
fatal_r(r, "%s: sshkey_sign failed", __progname); |
||||
free(data); |
||||
|
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
--- 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" |
||||
|
||||
-#ifndef HAVE_CLOSEFROM |
||||
+#if (!defined HAVE_CLOSEFROM) || (defined __s390__) |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/param.h> |
||||
|
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
diff --color -rup a/compat.c b/compat.c |
||||
--- a/compat.c 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ b/compat.c 2022-07-14 17:39:23.770268440 +0200 |
||||
@@ -157,11 +157,12 @@ compat_banner(struct ssh *ssh, const cha |
||||
debug_f("no match: %s", version); |
||||
} |
||||
|
||||
+/* Always returns pointer to allocated memory, caller must free. */ |
||||
char * |
||||
compat_cipher_proposal(struct ssh *ssh, char *cipher_prop) |
||||
{ |
||||
if (!(ssh->compat & SSH_BUG_BIGENDIANAES)) |
||||
- return cipher_prop; |
||||
+ return xstrdup(cipher_prop); |
||||
debug2_f("original cipher proposal: %s", cipher_prop); |
||||
if ((cipher_prop = match_filter_denylist(cipher_prop, "aes*")) == NULL) |
||||
fatal("match_filter_denylist failed"); |
||||
@@ -171,11 +172,12 @@ compat_cipher_proposal(struct ssh *ssh, |
||||
return cipher_prop; |
||||
} |
||||
|
||||
+/* Always returns pointer to allocated memory, caller must free. */ |
||||
char * |
||||
compat_pkalg_proposal(struct ssh *ssh, char *pkalg_prop) |
||||
{ |
||||
if (!(ssh->compat & SSH_BUG_RSASIGMD5)) |
||||
- return pkalg_prop; |
||||
+ return xstrdup(pkalg_prop); |
||||
debug2_f("original public key proposal: %s", pkalg_prop); |
||||
if ((pkalg_prop = match_filter_denylist(pkalg_prop, "ssh-rsa")) == NULL) |
||||
fatal("match_filter_denylist failed"); |
||||
@@ -185,21 +187,26 @@ compat_pkalg_proposal(struct ssh *ssh, c |
||||
return pkalg_prop; |
||||
} |
||||
|
||||
+/* Always returns pointer to allocated memory, caller must free. */ |
||||
char * |
||||
compat_kex_proposal(struct ssh *ssh, char *p) |
||||
{ |
||||
+ char *cp = NULL; |
||||
+ |
||||
if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0) |
||||
- return p; |
||||
+ return xstrdup(p); |
||||
debug2_f("original KEX proposal: %s", p); |
||||
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0) |
||||
if ((p = match_filter_denylist(p, |
||||
"curve25519-sha256@libssh.org")) == NULL) |
||||
fatal("match_filter_denylist failed"); |
||||
if ((ssh->compat & SSH_OLD_DHGEX) != 0) { |
||||
+ cp = p; |
||||
if ((p = match_filter_denylist(p, |
||||
"diffie-hellman-group-exchange-sha256," |
||||
"diffie-hellman-group-exchange-sha1")) == NULL) |
||||
fatal("match_filter_denylist failed"); |
||||
+ free(cp); |
||||
} |
||||
debug2_f("compat KEX proposal: %s", p); |
||||
if (*p == '\0') |
||||
diff --color -rup a/sshconnect2.c b/sshconnect2.c |
||||
--- a/sshconnect2.c 2022-07-14 17:38:43.241496549 +0200 |
||||
+++ b/sshconnect2.c 2022-07-14 17:39:23.772268479 +0200 |
||||
@@ -222,6 +222,7 @@ ssh_kex2(struct ssh *ssh, char *host, st |
||||
{ |
||||
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
||||
char *s, *all_key; |
||||
+ char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL; |
||||
int r, use_known_hosts_order = 0; |
||||
|
||||
#if defined(GSSAPI) && defined(WITH_OPENSSL) |
||||
@@ -252,10 +253,9 @@ ssh_kex2(struct ssh *ssh, char *host, st |
||||
|
||||
if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) |
||||
fatal_f("kex_names_cat"); |
||||
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s); |
||||
+ myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, s); |
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
||||
- compat_cipher_proposal(ssh, options.ciphers); |
||||
- myproposal[PROPOSAL_ENC_ALGS_STOC] = |
||||
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc = |
||||
compat_cipher_proposal(ssh, options.ciphers); |
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = |
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = |
||||
@@ -264,12 +264,12 @@ ssh_kex2(struct ssh *ssh, char *host, st |
||||
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
||||
if (use_known_hosts_order) { |
||||
/* Query known_hosts and prefer algorithms that appear there */ |
||||
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
||||
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey = |
||||
compat_pkalg_proposal(ssh, |
||||
order_hostkeyalgs(host, hostaddr, port, cinfo)); |
||||
} else { |
||||
/* Use specified HostkeyAlgorithms exactly */ |
||||
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
||||
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey = |
||||
compat_pkalg_proposal(ssh, options.hostkeyalgorithms); |
||||
} |
||||
|
||||
@@ -383,6 +383,10 @@ ssh_kex2(struct ssh *ssh, char *host, st |
||||
(r = ssh_packet_write_wait(ssh)) != 0) |
||||
fatal_fr(r, "send packet"); |
||||
#endif |
||||
+ /* Free only parts of proposal that were dynamically allocated here. */ |
||||
+ free(prop_kex); |
||||
+ free(prop_enc); |
||||
+ free(prop_hostkey); |
||||
} |
||||
|
||||
/* |
||||
diff --color -rup a/sshd.c b/sshd.c |
||||
--- a/sshd.c 2022-07-14 17:38:43.242496568 +0200 |
||||
+++ b/sshd.c 2022-07-14 17:42:07.616388978 +0200 |
||||
@@ -2493,14 +2493,15 @@ do_ssh2_kex(struct ssh *ssh) |
||||
{ |
||||
char *myproposal[PROPOSAL_MAX] = { KEX_SERVER }; |
||||
struct kex *kex; |
||||
+ char *hostkey_types = NULL; |
||||
+ char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL; |
||||
int r; |
||||
|
||||
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, |
||||
+ myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, |
||||
options.kex_algorithms); |
||||
- myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh, |
||||
- options.ciphers); |
||||
- myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(ssh, |
||||
- options.ciphers); |
||||
+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
||||
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc = |
||||
+ compat_cipher_proposal(ssh, options.ciphers); |
||||
myproposal[PROPOSAL_MAC_ALGS_CTOS] = |
||||
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
||||
|
||||
@@ -2513,8 +2514,10 @@ do_ssh2_kex(struct ssh *ssh) |
||||
ssh_packet_set_rekey_limits(ssh, options.rekey_limit, |
||||
options.rekey_interval); |
||||
|
||||
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( |
||||
- ssh, list_hostkey_types()); |
||||
+ hostkey_types = list_hostkey_types(); |
||||
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey = |
||||
+ compat_pkalg_proposal(ssh, hostkey_types); |
||||
+ free(hostkey_types); |
||||
|
||||
#if defined(GSSAPI) && defined(WITH_OPENSSL) |
||||
{ |
||||
@@ -2606,6 +2609,9 @@ do_ssh2_kex(struct ssh *ssh) |
||||
(r = ssh_packet_write_wait(ssh)) != 0) |
||||
fatal_fr(r, "send test"); |
||||
#endif |
||||
+ free(prop_kex); |
||||
+ free(prop_enc); |
||||
+ free(prop_hostkey); |
||||
debug("KEX done"); |
||||
} |
||||
|
@ -0,0 +1,207 @@
@@ -0,0 +1,207 @@
|
||||
diff --color -ru a/clientloop.c b/clientloop.c |
||||
--- a/clientloop.c 2022-06-29 16:35:06.677597259 +0200 |
||||
+++ b/clientloop.c 2022-06-29 16:40:29.737926205 +0200 |
||||
@@ -116,6 +116,9 @@ |
||||
#include "ssh-gss.h" |
||||
#endif |
||||
|
||||
+/* Permitted RSA signature algorithms for UpdateHostkeys proofs */ |
||||
+#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" |
||||
+ |
||||
/* import options */ |
||||
extern Options options; |
||||
|
||||
@@ -2110,8 +2113,10 @@ |
||||
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; |
||||
size_t i, ndone; |
||||
struct sshbuf *signdata; |
||||
- int r, kexsigtype, use_kexsigtype; |
||||
+ int r, plaintype; |
||||
const u_char *sig; |
||||
+ const char *rsa_kexalg = NULL; |
||||
+ char *alg = NULL; |
||||
size_t siglen; |
||||
|
||||
if (ctx->nnew == 0) |
||||
@@ -2122,9 +2127,9 @@ |
||||
hostkeys_update_ctx_free(ctx); |
||||
return; |
||||
} |
||||
- kexsigtype = sshkey_type_plain( |
||||
- sshkey_type_from_name(ssh->kex->hostkey_alg)); |
||||
- |
||||
+ if (sshkey_type_plain(sshkey_type_from_name( |
||||
+ ssh->kex->hostkey_alg)) == KEY_RSA) |
||||
+ rsa_kexalg = ssh->kex->hostkey_alg; |
||||
if ((signdata = sshbuf_new()) == NULL) |
||||
fatal_f("sshbuf_new failed"); |
||||
/* |
||||
@@ -2135,6 +2140,7 @@ |
||||
for (ndone = i = 0; i < ctx->nkeys; i++) { |
||||
if (ctx->keys_match[i]) |
||||
continue; |
||||
+ plaintype = sshkey_type_plain(ctx->keys[i]->type); |
||||
/* Prepare data to be signed: session ID, unique string, key */ |
||||
sshbuf_reset(signdata); |
||||
if ( (r = sshbuf_put_cstring(signdata, |
||||
@@ -2148,19 +2154,33 @@ |
||||
error_fr(r, "parse sig"); |
||||
goto out; |
||||
} |
||||
+ if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) { |
||||
+ error_fr(r, "server gave unintelligible signature " |
||||
+ "for %s key %zu", sshkey_type(ctx->keys[i]), i); |
||||
+ goto out; |
||||
+ } |
||||
/* |
||||
- * For RSA keys, prefer to use the signature type negotiated |
||||
- * during KEX to the default (SHA1). |
||||
+ * Special case for RSA keys: if a RSA hostkey was negotiated, |
||||
+ * then use its signature type for verification of RSA hostkey |
||||
+ * proofs. Otherwise, accept only RSA-SHA256/512 signatures. |
||||
*/ |
||||
- use_kexsigtype = kexsigtype == KEY_RSA && |
||||
- sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; |
||||
- debug3_f("verify %s key %zu using %s sigalg", |
||||
- sshkey_type(ctx->keys[i]), i, |
||||
- use_kexsigtype ? ssh->kex->hostkey_alg : "default"); |
||||
+ if (plaintype == KEY_RSA && rsa_kexalg == NULL && |
||||
+ match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) { |
||||
+ debug_f("server used untrusted RSA signature algorithm " |
||||
+ "%s for key %zu, disregarding", alg, i); |
||||
+ free(alg); |
||||
+ /* zap the key from the list */ |
||||
+ sshkey_free(ctx->keys[i]); |
||||
+ ctx->keys[i] = NULL; |
||||
+ ndone++; |
||||
+ continue; |
||||
+ } |
||||
+ debug3_f("verify %s key %zu using sigalg %s", |
||||
+ sshkey_type(ctx->keys[i]), i, alg); |
||||
+ free(alg); |
||||
if ((r = sshkey_verify(ctx->keys[i], sig, siglen, |
||||
sshbuf_ptr(signdata), sshbuf_len(signdata), |
||||
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, |
||||
- NULL)) != 0) { |
||||
+ plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) { |
||||
error_fr(r, "server gave bad signature for %s key %zu", |
||||
sshkey_type(ctx->keys[i]), i); |
||||
goto out; |
||||
diff --git a/hostfile.c b/hostfile.c |
||||
index a035b381..bd49e3ac 100644 |
||||
--- a/hostfile.c |
||||
+++ b/hostfile.c |
||||
@@ -642,7 +642,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip, |
||||
/* Re-add the requested keys */ |
||||
want = HKF_MATCH_HOST | (ip == NULL ? 0 : HKF_MATCH_IP); |
||||
for (i = 0; i < nkeys; i++) { |
||||
- if ((want & ctx.match_keys[i]) == want) |
||||
+ if (keys[i] == NULL || (want & ctx.match_keys[i]) == want) |
||||
continue; |
||||
if ((fp = sshkey_fingerprint(keys[i], hash_alg, |
||||
SSH_FP_DEFAULT)) == NULL) { |
||||
diff --color -ru a/kex.c b/kex.c |
||||
--- a/kex.c 2022-06-29 16:35:06.775599179 +0200 |
||||
+++ b/kex.c 2022-06-29 16:42:00.839710940 +0200 |
||||
@@ -959,6 +959,18 @@ |
||||
return (1); |
||||
} |
||||
|
||||
+/* returns non-zero if proposal contains any algorithm from algs */ |
||||
+static int |
||||
+has_any_alg(const char *proposal, const char *algs) |
||||
+{ |
||||
+ char *cp; |
||||
+ |
||||
+ if ((cp = match_list(proposal, algs, NULL)) == NULL) |
||||
+ return 0; |
||||
+ free(cp); |
||||
+ return 1; |
||||
+} |
||||
+ |
||||
static int |
||||
kex_choose_conf(struct ssh *ssh) |
||||
{ |
||||
@@ -994,6 +1006,16 @@ |
||||
free(ext); |
||||
} |
||||
|
||||
+ /* Check whether client supports rsa-sha2 algorithms */ |
||||
+ if (kex->server && (kex->flags & KEX_INITIAL)) { |
||||
+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], |
||||
+ "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com")) |
||||
+ kex->flags |= KEX_RSA_SHA2_256_SUPPORTED; |
||||
+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], |
||||
+ "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com")) |
||||
+ kex->flags |= KEX_RSA_SHA2_512_SUPPORTED; |
||||
+ } |
||||
+ |
||||
/* Algorithm Negotiation */ |
||||
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], |
||||
sprop[PROPOSAL_KEX_ALGS])) != 0) { |
||||
diff --color -ru a/kex.h b/kex.h |
||||
--- a/kex.h 2022-06-29 16:35:06.766599003 +0200 |
||||
+++ b/kex.h 2022-06-29 16:42:24.199168567 +0200 |
||||
@@ -116,6 +116,8 @@ |
||||
|
||||
#define KEX_INIT_SENT 0x0001 |
||||
#define KEX_INITIAL 0x0002 |
||||
+#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */ |
||||
+#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */ |
||||
|
||||
struct sshenc { |
||||
char *name; |
||||
diff --color -ru a/serverloop.c b/serverloop.c |
||||
--- a/serverloop.c 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ b/serverloop.c 2022-06-29 16:45:05.902336428 +0200 |
||||
@@ -684,16 +684,18 @@ |
||||
struct sshbuf *resp = NULL; |
||||
struct sshbuf *sigbuf = NULL; |
||||
struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL; |
||||
- int r, ndx, kexsigtype, use_kexsigtype, success = 0; |
||||
+ int r, ndx, success = 0; |
||||
const u_char *blob; |
||||
+ const char *sigalg, *kex_rsa_sigalg = NULL; |
||||
u_char *sig = 0; |
||||
size_t blen, slen; |
||||
|
||||
if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL) |
||||
fatal_f("sshbuf_new"); |
||||
|
||||
- kexsigtype = sshkey_type_plain( |
||||
- sshkey_type_from_name(ssh->kex->hostkey_alg)); |
||||
+ if (sshkey_type_plain(sshkey_type_from_name( |
||||
+ ssh->kex->hostkey_alg)) == KEY_RSA) |
||||
+ kex_rsa_sigalg = ssh->kex->hostkey_alg; |
||||
while (ssh_packet_remaining(ssh) > 0) { |
||||
sshkey_free(key); |
||||
key = NULL; |
||||
@@ -726,16 +728,24 @@ |
||||
* For RSA keys, prefer to use the signature type negotiated |
||||
* during KEX to the default (SHA1). |
||||
*/ |
||||
- use_kexsigtype = kexsigtype == KEY_RSA && |
||||
- sshkey_type_plain(key->type) == KEY_RSA; |
||||
+ sigalg = NULL; |
||||
+ if (sshkey_type_plain(key->type) == KEY_RSA) { |
||||
+ if (kex_rsa_sigalg != NULL) |
||||
+ sigalg = kex_rsa_sigalg; |
||||
+ else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED) |
||||
+ sigalg = "rsa-sha2-512"; |
||||
+ else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) |
||||
+ sigalg = "rsa-sha2-256"; |
||||
+ } |
||||
+ debug3_f("sign %s key (index %d) using sigalg %s", |
||||
+ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); |
||||
if ((r = sshbuf_put_cstring(sigbuf, |
||||
"hostkeys-prove-00@openssh.com")) != 0 || |
||||
(r = sshbuf_put_stringb(sigbuf, |
||||
ssh->kex->session_id)) != 0 || |
||||
(r = sshkey_puts(key, sigbuf)) != 0 || |
||||
(r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen, |
||||
- sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), |
||||
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 || |
||||
+ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), sigalg)) != 0 || |
||||
(r = sshbuf_put_string(resp, sig, slen)) != 0) { |
||||
error_fr(r, "assemble signature"); |
||||
goto out; |
@ -0,0 +1,446 @@
@@ -0,0 +1,446 @@
|
||||
diff --git a/auth2-hostbased.c b/auth2-hostbased.c |
||||
index 36b9d2f5..6b517db4 100644 |
||||
--- a/auth2-hostbased.c |
||||
+++ b/auth2-hostbased.c |
||||
@@ -119,6 +119,11 @@ userauth_hostbased(struct ssh *ssh, const char *method) |
||||
"(null)" : key->cert->signature_type); |
||||
goto done; |
||||
} |
||||
+ if ((r = sshkey_check_rsa_length(key, |
||||
+ options.required_rsa_size)) != 0) { |
||||
+ logit_r(r, "refusing %s key", sshkey_type(key)); |
||||
+ goto done; |
||||
+ } |
||||
|
||||
if (!authctxt->valid || authctxt->user == NULL) { |
||||
debug2_f("disabled because of invalid user"); |
||||
diff --git a/auth2-pubkey.c b/auth2-pubkey.c |
||||
index 962fd342..5d59febc 100644 |
||||
--- a/auth2-pubkey.c |
||||
+++ b/auth2-pubkey.c |
||||
@@ -175,6 +175,11 @@ userauth_pubkey(struct ssh *ssh, const char *method) |
||||
"(null)" : key->cert->signature_type); |
||||
goto done; |
||||
} |
||||
+ if ((r = sshkey_check_rsa_length(key, |
||||
+ options.required_rsa_size)) != 0) { |
||||
+ logit_r(r, "refusing %s key", sshkey_type(key)); |
||||
+ goto done; |
||||
+ } |
||||
key_s = format_key(key); |
||||
if (sshkey_is_cert(key)) |
||||
ca_s = format_key(key->cert->signature_key); |
||||
diff --git a/readconf.c b/readconf.c |
||||
index 7f26c680..42be690b 100644 |
||||
--- a/readconf.c |
||||
+++ b/readconf.c |
||||
@@ -174,7 +174,7 @@ typedef enum { |
||||
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, |
||||
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms, |
||||
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, |
||||
- oSecurityKeyProvider, oKnownHostsCommand, |
||||
+ oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, |
||||
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported |
||||
} OpCodes; |
||||
|
||||
@@ -320,6 +320,8 @@ static struct { |
||||
{ "proxyjump", oProxyJump }, |
||||
{ "securitykeyprovider", oSecurityKeyProvider }, |
||||
{ "knownhostscommand", oKnownHostsCommand }, |
||||
+ { "requiredrsasize", oRequiredRSASize }, |
||||
+ { "rsaminsize", oRequiredRSASize }, /* alias */ |
||||
|
||||
{ NULL, oBadOption } |
||||
}; |
||||
@@ -2176,6 +2177,10 @@ parse_pubkey_algos: |
||||
*charptr = xstrdup(arg); |
||||
break; |
||||
|
||||
+ case oRequiredRSASize: |
||||
+ intptr = &options->required_rsa_size; |
||||
+ goto parse_int; |
||||
+ |
||||
case oDeprecated: |
||||
debug("%s line %d: Deprecated option \"%s\"", |
||||
filename, linenum, keyword); |
||||
@@ -2423,6 +2428,7 @@ initialize_options(Options * options) |
||||
options->hostbased_accepted_algos = NULL; |
||||
options->pubkey_accepted_algos = NULL; |
||||
options->known_hosts_command = NULL; |
||||
+ options->required_rsa_size = -1; |
||||
} |
||||
|
||||
/* |
||||
@@ -2619,6 +2625,8 @@ fill_default_options(Options * options) |
||||
if (options->sk_provider == NULL) |
||||
options->sk_provider = xstrdup("$SSH_SK_PROVIDER"); |
||||
#endif |
||||
+ if (options->required_rsa_size == -1) |
||||
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; |
||||
|
||||
/* Expand KEX name lists */ |
||||
all_cipher = cipher_alg_list(',', 0); |
||||
@@ -3308,6 +3316,7 @@ dump_client_config(Options *o, const char *host) |
||||
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); |
||||
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); |
||||
dump_cfg_int(oServerAliveInterval, o->server_alive_interval); |
||||
+ dump_cfg_int(oRequiredRSASize, o->required_rsa_size); |
||||
|
||||
/* String options */ |
||||
dump_cfg_string(oBindAddress, o->bind_address); |
||||
diff --git a/readconf.h b/readconf.h |
||||
index f647bd42..ffb5ec4f 100644 |
||||
--- a/readconf.h |
||||
+++ b/readconf.h |
||||
@@ -176,6 +176,8 @@ typedef struct { |
||||
|
||||
char *known_hosts_command; |
||||
|
||||
+ int required_rsa_size; /* minimum size of RSA keys */ |
||||
+ |
||||
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ |
||||
} Options; |
||||
|
||||
diff --git a/servconf.c b/servconf.c |
||||
index 29df0463..423772b1 100644 |
||||
--- a/servconf.c |
||||
+++ b/servconf.c |
||||
@@ -195,6 +195,7 @@ initialize_server_options(ServerOptions *options) |
||||
options->fingerprint_hash = -1; |
||||
options->disable_forwarding = -1; |
||||
options->expose_userauth_info = -1; |
||||
+ options->required_rsa_size = -1; |
||||
} |
||||
|
||||
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ |
||||
@@ -441,6 +442,8 @@ fill_default_server_options(ServerOptions *options) |
||||
options->expose_userauth_info = 0; |
||||
if (options->sk_provider == NULL) |
||||
options->sk_provider = xstrdup("internal"); |
||||
+ if (options->required_rsa_size == -1) |
||||
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; |
||||
|
||||
assemble_algorithms(options); |
||||
|
||||
@@ -517,6 +520,7 @@ typedef enum { |
||||
sStreamLocalBindMask, sStreamLocalBindUnlink, |
||||
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, |
||||
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, |
||||
+ sRequiredRSASize, |
||||
sDeprecated, sIgnore, sUnsupported |
||||
} ServerOpCodes; |
||||
|
||||
@@ -676,6 +680,8 @@ static struct { |
||||
{ "rdomain", sRDomain, SSHCFG_ALL }, |
||||
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, |
||||
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, |
||||
+ { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, |
||||
+ { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */ |
||||
{ NULL, sBadOption, 0 } |
||||
}; |
||||
|
||||
@@ -2438,6 +2443,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, |
||||
*charptr = xstrdup(arg); |
||||
break; |
||||
|
||||
+ case sRequiredRSASize: |
||||
+ intptr = &options->required_rsa_size; |
||||
+ goto parse_int; |
||||
+ |
||||
case sDeprecated: |
||||
case sIgnore: |
||||
case sUnsupported: |
||||
@@ -2610,6 +2619,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) |
||||
M_CP_INTOPT(rekey_limit); |
||||
M_CP_INTOPT(rekey_interval); |
||||
M_CP_INTOPT(log_level); |
||||
+ M_CP_INTOPT(required_rsa_size); |
||||
|
||||
/* |
||||
* The bind_mask is a mode_t that may be unsigned, so we can't use |
||||
@@ -2874,6 +2884,7 @@ dump_config(ServerOptions *o) |
||||
dump_cfg_int(sMaxSessions, o->max_sessions); |
||||
dump_cfg_int(sClientAliveInterval, o->client_alive_interval); |
||||
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); |
||||
+ dump_cfg_int(sRequiredRSASize, o->required_rsa_size); |
||||
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask); |
||||
|
||||
/* formatted integer arguments */ |
||||
diff --git a/servconf.h b/servconf.h |
||||
index 8a04463e..9346155c 100644 |
||||
--- a/servconf.h |
||||
+++ b/servconf.h |
||||
@@ -229,6 +229,7 @@ typedef struct { |
||||
int expose_userauth_info; |
||||
u_int64_t timing_secret; |
||||
char *sk_provider; |
||||
+ int required_rsa_size; /* minimum size of RSA keys */ |
||||
} ServerOptions; |
||||
|
||||
/* Information about the incoming connection as used by Match */ |
||||
diff --git a/ssh.c b/ssh.c |
||||
index 559bf2af..25be53d5 100644 |
||||
--- a/ssh.c |
||||
+++ b/ssh.c |
||||
@@ -516,14 +516,22 @@ resolve_canonicalize(char **hostp, int port) |
||||
} |
||||
|
||||
/* |
||||
- * Check the result of hostkey loading, ignoring some errors and |
||||
- * fatal()ing for others. |
||||
+ * Check the result of hostkey loading, ignoring some errors and either |
||||
+ * discarding the key or fatal()ing for others. |
||||
*/ |
||||
static void |
||||
-check_load(int r, const char *path, const char *message) |
||||
+check_load(int r, struct sshkey **k, const char *path, const char *message) |
||||
{ |
||||
switch (r) { |
||||
case 0: |
||||
+ /* Check RSA keys size and discard if undersized */ |
||||
+ if (k != NULL && *k != NULL && |
||||
+ (r = sshkey_check_rsa_length(*k, |
||||
+ options.required_rsa_size)) != 0) { |
||||
+ error_r(r, "load %s \"%s\"", message, path); |
||||
+ free(*k); |
||||
+ *k = NULL; |
||||
+ } |
||||
break; |
||||
case SSH_ERR_INTERNAL_ERROR: |
||||
case SSH_ERR_ALLOC_FAIL: |
||||
@@ -1578,7 +1586,7 @@ main(int ac, char **av) |
||||
if ((o) >= sensitive_data.nkeys) \ |
||||
fatal_f("pubkey out of array bounds"); \ |
||||
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \ |
||||
- p, "pubkey"); \ |
||||
+ &(sensitive_data.keys[o]), p, "pubkey"); \ |
||||
} while (0) |
||||
#define L_CERT(p,o) do { \ |
||||
if ((o) >= sensitive_data.nkeys) \ |
||||
@@ -1586,7 +1594,8 @@ main(int ac, char **av) |
||||
#define L_CERT(p,o) do { \ |
||||
if ((o) >= sensitive_data.nkeys) \ |
||||
fatal_f("cert out of array bounds"); \ |
||||
- check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \ |
||||
+ check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \ |
||||
+ &(sensitive_data.keys[o]), p, "cert"); \ |
||||
} while (0) |
||||
|
||||
if (options.hostbased_authentication == 1) { |
||||
@@ -2244,7 +2253,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) |
||||
filename = default_client_percent_dollar_expand(cp, cinfo); |
||||
free(cp); |
||||
check_load(sshkey_load_public(filename, &public, NULL), |
||||
- filename, "pubkey"); |
||||
+ &public, filename, "pubkey"); |
||||
debug("identity file %s type %d", filename, |
||||
public ? public->type : -1); |
||||
free(options.identity_files[i]); |
||||
@@ -2284,7 +2293,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) |
||||
continue; |
||||
xasprintf(&cp, "%s-cert", filename); |
||||
check_load(sshkey_load_public(cp, &public, NULL), |
||||
- filename, "pubkey"); |
||||
+ &public, filename, "pubkey"); |
||||
debug("identity file %s type %d", cp, |
||||
public ? public->type : -1); |
||||
if (public == NULL) { |
||||
@@ -2315,7 +2324,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) |
||||
free(cp); |
||||
|
||||
check_load(sshkey_load_public(filename, &public, NULL), |
||||
- filename, "certificate"); |
||||
+ &public, filename, "certificate"); |
||||
debug("certificate file %s type %d", filename, |
||||
public ? public->type : -1); |
||||
free(options.certificate_files[i]); |
||||
diff --git a/sshconnect2.c b/sshconnect2.c |
||||
index f9bd19ea..58fe98db 100644 |
||||
--- a/sshconnect2.c |
||||
+++ b/sshconnect2.c |
||||
@@ -96,6 +96,11 @@ static const struct ssh_conn_info *xxx_conn_info; |
||||
static int |
||||
verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh) |
||||
{ |
||||
+ int r; |
||||
+ |
||||
+ if ((r = sshkey_check_rsa_length(hostkey, |
||||
+ options.required_rsa_size)) != 0) |
||||
+ fatal_r(r, "Bad server host key"); |
||||
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, |
||||
xxx_conn_info) == -1) |
||||
fatal("Host key verification failed."); |
||||
@@ -1606,6 +1611,13 @@ load_identity_file(Identity *id) |
||||
private = NULL; |
||||
quit = 1; |
||||
} |
||||
+ if (!quit && (r = sshkey_check_rsa_length(private, |
||||
+ options.required_rsa_size)) != 0) { |
||||
+ debug_fr(r, "Skipping key %s", id->filename); |
||||
+ sshkey_free(private); |
||||
+ private = NULL; |
||||
+ quit = 1; |
||||
+ } |
||||
if (!quit && private != NULL && id->agent_fd == -1 && |
||||
!(id->key && id->isprivate)) |
||||
maybe_add_key_to_agent(id->filename, private, comment, |
||||
@@ -1752,6 +1764,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt) |
||||
close(agent_fd); |
||||
} else { |
||||
for (j = 0; j < idlist->nkeys; j++) { |
||||
+ if ((r = sshkey_check_rsa_length(idlist->keys[j], |
||||
+ options.required_rsa_size)) != 0) { |
||||
+ debug_fr(r, "ignoring %s agent key", |
||||
+ sshkey_ssh_name(idlist->keys[j])); |
||||
+ continue; |
||||
+ } |
||||
found = 0; |
||||
TAILQ_FOREACH(id, &files, next) { |
||||
/* |
||||
diff --git a/sshd.c b/sshd.c |
||||
index 17eee9d8..395ef493 100644 |
||||
--- a/sshd.c |
||||
+++ b/sshd.c |
||||
@@ -1870,6 +1870,13 @@ main(int ac, char **av) |
||||
fatal_r(r, "Could not demote key: \"%s\"", |
||||
options.host_key_files[i]); |
||||
} |
||||
+ if (pubkey != NULL && (r = sshkey_check_rsa_length(pubkey, |
||||
+ options.required_rsa_size)) != 0) { |
||||
+ error_fr(r, "Host key %s", options.host_key_files[i]); |
||||
+ sshkey_free(pubkey); |
||||
+ sshkey_free(key); |
||||
+ continue; |
||||
+ } |
||||
sensitive_data.host_keys[i] = key; |
||||
sensitive_data.host_pubkeys[i] = pubkey; |
||||
|
||||
diff --git a/sshkey.c b/sshkey.c |
||||
index ed2b5dff..77093235 100644 |
||||
--- a/sshkey.c |
||||
+++ b/sshkey.c |
||||
@@ -2365,18 +2365,24 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) |
||||
return ret; |
||||
} |
||||
|
||||
-#ifdef WITH_OPENSSL |
||||
-static int |
||||
-check_rsa_length(const RSA *rsa) |
||||
+int |
||||
+sshkey_check_rsa_length(const struct sshkey *k, int min_size) |
||||
{ |
||||
+#ifdef WITH_OPENSSL |
||||
const BIGNUM *rsa_n; |
||||
+ int nbits; |
||||
|
||||
- RSA_get0_key(rsa, &rsa_n, NULL, NULL); |
||||
- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
||||
+ if (k == NULL || k->rsa == NULL || |
||||
+ (k->type != KEY_RSA && k->type != KEY_RSA_CERT)) |
||||
+ return 0; |
||||
+ RSA_get0_key(k->rsa, &rsa_n, NULL, NULL); |
||||
+ nbits = BN_num_bits(rsa_n); |
||||
+ if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE || |
||||
+ (min_size > 0 && nbits < min_size)) |
||||
return SSH_ERR_KEY_LENGTH; |
||||
+#endif /* WITH_OPENSSL */ |
||||
return 0; |
||||
} |
||||
-#endif |
||||
|
||||
static int |
||||
sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, |
||||
@@ -2439,7 +2445,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, |
||||
goto out; |
||||
} |
||||
rsa_n = rsa_e = NULL; /* transferred */ |
||||
- if ((ret = check_rsa_length(key->rsa)) != 0) |
||||
+ if ((ret = sshkey_check_rsa_length(key, 0)) != 0) |
||||
goto out; |
||||
#ifdef DEBUG_PK |
||||
RSA_print_fp(stderr, key->rsa, 8); |
||||
@@ -3642,7 +3648,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) |
||||
goto out; |
||||
} |
||||
rsa_p = rsa_q = NULL; /* transferred */ |
||||
- if ((r = check_rsa_length(k->rsa)) != 0) |
||||
+ if ((r = sshkey_check_rsa_length(k, 0)) != 0) |
||||
goto out; |
||||
if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0) |
||||
goto out; |
||||
@@ -4644,7 +4650,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, |
||||
r = SSH_ERR_LIBCRYPTO_ERROR; |
||||
goto out; |
||||
} |
||||
- if ((r = check_rsa_length(prv->rsa)) != 0) |
||||
+ if ((r = sshkey_check_rsa_length(prv, 0)) != 0) |
||||
goto out; |
||||
} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA && |
||||
(type == KEY_UNSPEC || type == KEY_DSA)) { |
||||
diff --git a/sshkey.h b/sshkey.h |
||||
index 094815e0..be254e6b 100644 |
||||
--- a/sshkey.h |
||||
+++ b/sshkey.h |
||||
@@ -273,6 +273,7 @@ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, |
||||
int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, |
||||
int type, struct sshkey **pubkeyp); |
||||
|
||||
+int sshkey_check_rsa_length(const struct sshkey *, int); |
||||
/* XXX should be internal, but used by ssh-keygen */ |
||||
int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *); |
||||
|
||||
diff --git a/ssh.1 b/ssh.1 |
||||
index b4956aec..e255b9b9 100644 |
||||
--- a/ssh.1 |
||||
+++ b/ssh.1 |
||||
@@ -571,6 +571,7 @@ For full details of the options listed below, and their possible values, see |
||||
.It RemoteCommand |
||||
.It RemoteForward |
||||
.It RequestTTY |
||||
+.It RequiredRSASize |
||||
.It SendEnv |
||||
.It ServerAliveInterval |
||||
.It ServerAliveCountMax |
||||
diff --git a/ssh_config.5 b/ssh_config.5 |
||||
index 24a46460..d1ede18e 100644 |
||||
--- a/ssh_config.5 |
||||
+++ b/ssh_config.5 |
||||
@@ -1634,6 +1634,17 @@ and |
||||
.Fl T |
||||
flags for |
||||
.Xr ssh 1 . |
||||
+.It Cm RequiredRSASize |
||||
+Specifies the minimum RSA key size (in bits) that |
||||
+.Xr ssh 1 |
||||
+will accept. |
||||
+User authentication keys smaller than this limit will be ignored. |
||||
+Servers that present host keys smaller than this limit will cause the |
||||
+connection to be terminated. |
||||
+The default is |
||||
+.Cm 1024 |
||||
+bits. |
||||
+Note that this limit may only be raised from the default. |
||||
.It Cm RevokedHostKeys |
||||
Specifies revoked host public keys. |
||||
Keys listed in this file will be refused for host authentication. |
||||
diff --git a/sshd_config.5 b/sshd_config.5 |
||||
index 867a747d..f5a06637 100644 |
||||
--- a/sshd_config.5 |
||||
+++ b/sshd_config.5 |
||||
@@ -1596,6 +1596,16 @@ is |
||||
.Cm default none , |
||||
which means that rekeying is performed after the cipher's default amount |
||||
of data has been sent or received and no time based rekeying is done. |
||||
+.It Cm RequiredRSASize |
||||
+Specifies the minimum RSA key size (in bits) that |
||||
+.Xr sshd 8 |
||||
+will accept. |
||||
+User and host-based authentication keys smaller than this limit will be |
||||
+refused. |
||||
+The default is |
||||
+.Cm 1024 |
||||
+bits. |
||||
+Note that this limit may only be raised from the default. |
||||
.It Cm RevokedKeys |
||||
Specifies revoked public keys file, or |
||||
.Cm none |
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
diff --color -rup a/regress/hostkey-agent.sh b/regress/hostkey-agent.sh |
||||
--- a/regress/hostkey-agent.sh 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ b/regress/hostkey-agent.sh 2022-07-14 11:58:12.172786060 +0200 |
||||
@@ -13,8 +13,12 @@ r=$? |
||||
grep -vi 'hostkey' $OBJ/sshd_proxy > $OBJ/sshd_proxy.orig |
||||
echo "HostKeyAgent $SSH_AUTH_SOCK" >> $OBJ/sshd_proxy.orig |
||||
|
||||
+PUBKEY_ACCEPTED_ALGOS=`$SSH -G "example.com" | \ |
||||
+ grep -i "PubkeyAcceptedAlgorithms" | cut -d ' ' -f2- | tr "," "|"` |
||||
+SSH_ACCEPTED_KEYTYPES=`echo "$SSH_KEYTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"` |
||||
+ |
||||
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" |
||||
( |
||||
printf 'localhost-with-alias,127.0.0.1,::1 ' |
||||
@@ -31,7 +35,7 @@ cp $OBJ/known_hosts.orig $OBJ/known_host |
||||
unset SSH_AUTH_SOCK |
||||
|
||||
for ps in yes; do |
||||
- for k in $SSH_KEYTYPES ; do |
||||
+ for k in $SSH_ACCEPTED_KEYTYPES ; do |
||||
verbose "key type $k privsep=$ps" |
||||
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy |
||||
echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy |
||||
diff --color -rup a/sshconnect2.c b/sshconnect2.c |
||||
--- a/sshconnect2.c 2022-07-14 10:10:07.262975710 +0200 |
||||
+++ b/sshconnect2.c 2022-07-14 10:10:32.068452067 +0200 |
||||
@@ -222,6 +222,7 @@ ssh_kex2(struct ssh *ssh, char *host, st |
||||
{ |
||||
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
||||
char *s, *all_key; |
||||
+ char *hostkeyalgs = NULL, *pkalg = NULL; |
||||
char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL; |
||||
int r, use_known_hosts_order = 0; |
||||
|
||||
@@ -264,14 +265,19 @@ ssh_kex2(struct ssh *ssh, char *host, st |
||||
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
||||
if (use_known_hosts_order) { |
||||
/* Query known_hosts and prefer algorithms that appear there */ |
||||
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey = |
||||
- compat_pkalg_proposal(ssh, |
||||
- order_hostkeyalgs(host, hostaddr, port, cinfo)); |
||||
+ if ((hostkeyalgs = order_hostkeyalgs(host, hostaddr, port, cinfo)) == NULL) |
||||
+ fatal_f("order_hostkeyalgs"); |
||||
+ pkalg = match_filter_allowlist(hostkeyalgs, options.pubkey_accepted_algos); |
||||
+ free(hostkeyalgs); |
||||
} else { |
||||
- /* Use specified HostkeyAlgorithms exactly */ |
||||
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey = |
||||
- compat_pkalg_proposal(ssh, options.hostkeyalgorithms); |
||||
+ /* Use specified HostkeyAlgorithms */ |
||||
+ pkalg = match_filter_allowlist(options.hostkeyalgorithms, options.pubkey_accepted_algos); |
||||
} |
||||
+ if (pkalg == NULL) |
||||
+ fatal_f("match_filter_allowlist"); |
||||
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey = |
||||
+ compat_pkalg_proposal(ssh, pkalg); |
||||
+ free(pkalg); |
||||
|
||||
#if defined(GSSAPI) && defined(WITH_OPENSSL) |
||||
if (options.gss_keyex) { |
@ -0,0 +1,174 @@
@@ -0,0 +1,174 @@
|
||||
diff -up openssh-8.7p1/scp.c.scp-sftpdirs openssh-8.7p1/scp.c |
||||
--- openssh-8.7p1/scp.c.scp-sftpdirs 2022-02-07 12:31:07.407740407 +0100 |
||||
+++ openssh-8.7p1/scp.c 2022-02-07 12:31:07.409740424 +0100 |
||||
@@ -1324,7 +1324,7 @@ source_sftp(int argc, char *src, char *t |
||||
|
||||
if (src_is_dir && iamrecursive) { |
||||
if (upload_dir(conn, src, abs_dst, pflag, |
||||
- SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) { |
||||
+ SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { |
||||
error("failed to upload directory %s to %s", |
||||
src, abs_dst); |
||||
errs = 1; |
||||
diff -up openssh-8.7p1/sftp-client.c.scp-sftpdirs openssh-8.7p1/sftp-client.c |
||||
--- openssh-8.7p1/sftp-client.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ openssh-8.7p1/sftp-client.c 2022-02-07 12:47:59.117516131 +0100 |
||||
@@ -971,7 +971,7 @@ do_fsetstat(struct sftp_conn *conn, cons |
||||
|
||||
/* Implements both the realpath and expand-path operations */ |
||||
static char * |
||||
-do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) |
||||
+do_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir) |
||||
{ |
||||
struct sshbuf *msg; |
||||
u_int expected_id, count, id; |
||||
@@ -1012,9 +1012,38 @@ do_realpath_expand(struct sftp_conn *con |
||||
|
||||
if ((r = sshbuf_get_u32(msg, &status)) != 0) |
||||
fatal_fr(r, "parse status"); |
||||
- error("Couldn't canonicalize: %s", fx2txt(status)); |
||||
- sshbuf_free(msg); |
||||
- return NULL; |
||||
+ if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir) { |
||||
+ memset(&a, '\0', sizeof(a)); |
||||
+ if ((r = do_mkdir(conn, path, &a, 0)) != 0) { |
||||
+ sshbuf_free(msg); |
||||
+ return NULL; |
||||
+ } |
||||
+ |
||||
+ 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) { |
||||
+ u_int status; |
||||
+ |
||||
+ if ((r = sshbuf_get_u32(msg, &status)) != 0) |
||||
+ fatal_fr(r, "parse status"); |
||||
+ error("Couldn't canonicalize: %s", fx2txt(status)); |
||||
+ sshbuf_free(msg); |
||||
+ return NULL; |
||||
+ } |
||||
+ } else { |
||||
+ error("Couldn't canonicalize: %s", fx2txt(status)); |
||||
+ sshbuf_free(msg); |
||||
+ return NULL; |
||||
+ } |
||||
} else if (type != SSH2_FXP_NAME) |
||||
fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", |
||||
SSH2_FXP_NAME, type); |
||||
@@ -1039,9 +1067,9 @@ do_realpath_expand(struct sftp_conn *con |
||||
} |
||||
|
||||
char * |
||||
-do_realpath(struct sftp_conn *conn, const char *path) |
||||
+do_realpath(struct sftp_conn *conn, const char *path, int create_dir) |
||||
{ |
||||
- return do_realpath_expand(conn, path, 0); |
||||
+ return do_realpath_expand(conn, path, 0, create_dir); |
||||
} |
||||
|
||||
int |
||||
@@ -1055,9 +1083,9 @@ do_expand_path(struct sftp_conn *conn, c |
||||
{ |
||||
if (!can_expand_path(conn)) { |
||||
debug3_f("no server support, fallback to realpath"); |
||||
- return do_realpath_expand(conn, path, 0); |
||||
+ return do_realpath_expand(conn, path, 0, 0); |
||||
} |
||||
- return do_realpath_expand(conn, path, 1); |
||||
+ return do_realpath_expand(conn, path, 1, 0); |
||||
} |
||||
|
||||
int |
||||
@@ -1807,7 +1835,7 @@ download_dir(struct sftp_conn *conn, con |
||||
char *src_canon; |
||||
int ret; |
||||
|
||||
- if ((src_canon = do_realpath(conn, src)) == NULL) { |
||||
+ if ((src_canon = do_realpath(conn, src, 0)) == NULL) { |
||||
error("Unable to canonicalize path \"%s\"", src); |
||||
return -1; |
||||
} |
||||
@@ -2115,12 +2143,12 @@ upload_dir_internal(struct sftp_conn *co |
||||
int |
||||
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 follow_link_flag, int create_dir) |
||||
{ |
||||
char *dst_canon; |
||||
int ret; |
||||
|
||||
- if ((dst_canon = do_realpath(conn, dst)) == NULL) { |
||||
+ if ((dst_canon = do_realpath(conn, dst, create_dir)) == NULL) { |
||||
error("Unable to canonicalize path \"%s\"", dst); |
||||
return -1; |
||||
} |
||||
@@ -2557,7 +2585,7 @@ crossload_dir(struct sftp_conn *from, st |
||||
char *from_path_canon; |
||||
int ret; |
||||
|
||||
- if ((from_path_canon = do_realpath(from, from_path)) == NULL) { |
||||
+ if ((from_path_canon = do_realpath(from, from_path, 0)) == NULL) { |
||||
error("Unable to canonicalize path \"%s\"", from_path); |
||||
return -1; |
||||
} |
||||
diff -up openssh-8.7p1/sftp-client.h.scp-sftpdirs openssh-8.7p1/sftp-client.h |
||||
--- openssh-8.7p1/sftp-client.h.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ openssh-8.7p1/sftp-client.h 2022-02-07 12:31:07.410740433 +0100 |
||||
@@ -111,7 +111,7 @@ int do_fsetstat(struct sftp_conn *, cons |
||||
int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); |
||||
|
||||
/* Canonicalise 'path' - caller must free result */ |
||||
-char *do_realpath(struct sftp_conn *, const char *); |
||||
+char *do_realpath(struct sftp_conn *, const char *, int); |
||||
|
||||
/* Canonicalisation with tilde expansion (requires server extension) */ |
||||
char *do_expand_path(struct sftp_conn *, const char *); |
||||
@@ -159,7 +159,7 @@ int do_upload(struct sftp_conn *, const |
||||
* times if 'pflag' is set |
||||
*/ |
||||
int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, |
||||
- int, int); |
||||
+ int, int, int); |
||||
|
||||
/* |
||||
* Download a 'from_path' from the 'from' connection and upload it to |
||||
diff -up openssh-8.7p1/sftp.c.scp-sftpdirs openssh-8.7p1/sftp.c |
||||
--- openssh-8.7p1/sftp.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 |
||||
+++ openssh-8.7p1/sftp.c 2022-02-07 12:31:07.411740442 +0100 |
||||
@@ -760,7 +760,7 @@ process_put(struct sftp_conn *conn, cons |
||||
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
||||
if (upload_dir(conn, g.gl_pathv[i], abs_dst, |
||||
pflag || global_pflag, 1, resume, |
||||
- fflag || global_fflag, 0) == -1) |
||||
+ fflag || global_fflag, 0, 0) == -1) |
||||
err = -1; |
||||
} else { |
||||
if (do_upload(conn, g.gl_pathv[i], abs_dst, |
||||
@@ -1577,7 +1577,7 @@ parse_dispatch_command(struct sftp_conn |
||||
if (path1 == NULL || *path1 == '\0') |
||||
path1 = xstrdup(startdir); |
||||
path1 = make_absolute(path1, *pwd); |
||||
- if ((tmp = do_realpath(conn, path1)) == NULL) { |
||||
+ if ((tmp = do_realpath(conn, path1, 0)) == NULL) { |
||||
err = 1; |
||||
break; |
||||
} |
||||
@@ -2160,7 +2160,7 @@ interactive_loop(struct sftp_conn *conn, |
||||
} |
||||
#endif /* USE_LIBEDIT */ |
||||
|
||||
- remote_path = do_realpath(conn, "."); |
||||
+ remote_path = do_realpath(conn, ".", 0); |
||||
if (remote_path == NULL) |
||||
fatal("Need cwd"); |
||||
startdir = xstrdup(remote_path); |
@ -0,0 +1,304 @@
@@ -0,0 +1,304 @@
|
||||
diff --color -rup a/scp.c b/scp.c |
||||
--- a/scp.c 2022-07-26 14:51:40.560120817 +0200 |
||||
+++ b/scp.c 2022-07-26 14:52:37.118213004 +0200 |
||||
@@ -1324,12 +1324,12 @@ source_sftp(int argc, char *src, char *t |
||||
|
||||
if (src_is_dir && iamrecursive) { |
||||
if (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, abs_dst); |
||||
errs = 1; |
||||
} |
||||
- } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) { |
||||
+ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) { |
||||
error("failed to upload file %s to %s", src, abs_dst); |
||||
errs = 1; |
||||
} |
||||
@@ -1566,11 +1566,11 @@ sink_sftp(int argc, char *dst, const cha |
||||
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); |
||||
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { |
||||
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, |
||||
- pflag, SFTP_PROGRESS_ONLY, 0, 0, 1) == -1) |
||||
+ pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1) |
||||
err = -1; |
||||
} else { |
||||
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, |
||||
- pflag, 0, 0) == -1) |
||||
+ pflag, 0, 0, 1) == -1) |
||||
err = -1; |
||||
} |
||||
free(abs_dst); |
||||
diff --color -rup a/sftp.c b/sftp.c |
||||
--- a/sftp.c 2022-07-26 14:51:40.561120836 +0200 |
||||
+++ b/sftp.c 2022-07-26 14:52:37.119213023 +0200 |
||||
@@ -666,12 +666,12 @@ process_get(struct sftp_conn *conn, cons |
||||
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
||||
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, |
||||
pflag || global_pflag, 1, resume, |
||||
- fflag || global_fflag, 0) == -1) |
||||
+ fflag || global_fflag, 0, 0) == -1) |
||||
err = -1; |
||||
} else { |
||||
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, |
||||
pflag || global_pflag, resume, |
||||
- fflag || global_fflag) == -1) |
||||
+ fflag || global_fflag, 0) == -1) |
||||
err = -1; |
||||
} |
||||
free(abs_dst); |
||||
@@ -760,12 +760,12 @@ process_put(struct sftp_conn *conn, cons |
||||
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
||||
if (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 (do_upload(conn, g.gl_pathv[i], abs_dst, |
||||
pflag || global_pflag, resume, |
||||
- fflag || global_fflag) == -1) |
||||
+ fflag || global_fflag, 0) == -1) |
||||
err = -1; |
||||
} |
||||
} |
||||
diff --color -rup a/sftp-client.c b/sftp-client.c |
||||
--- a/sftp-client.c 2022-07-26 14:51:40.561120836 +0200 |
||||
+++ b/sftp-client.c 2022-07-26 15:09:54.825295533 +0200 |
||||
@@ -1454,7 +1454,7 @@ progress_meter_path(const char *path) |
||||
int |
||||
do_download(struct sftp_conn *conn, const char *remote_path, |
||||
const char *local_path, Attrib *a, int preserve_flag, int resume_flag, |
||||
- int fsync_flag) |
||||
+ int fsync_flag, int inplace_flag) |
||||
{ |
||||
struct sshbuf *msg; |
||||
u_char *handle; |
||||
@@ -1498,8 +1498,8 @@ do_download(struct sftp_conn *conn, cons |
||||
&handle, &handle_len) != 0) |
||||
return -1; |
||||
|
||||
- local_fd = open(local_path, |
||||
- O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); |
||||
+ local_fd = open(local_path, O_WRONLY | O_CREAT | |
||||
+ ((resume_flag || inplace_flag) ? 0 : O_TRUNC), mode | S_IWUSR); |
||||
if (local_fd == -1) { |
||||
error("Couldn't open local file \"%s\" for writing: %s", |
||||
local_path, strerror(errno)); |
||||
@@ -1661,8 +1661,11 @@ do_download(struct sftp_conn *conn, cons |
||||
/* Sanity check */ |
||||
if (TAILQ_FIRST(&requests) != NULL) |
||||
fatal("Transfer complete, but requests still in queue"); |
||||
- /* Truncate at highest contiguous point to avoid holes on interrupt */ |
||||
- if (read_error || write_error || interrupted) { |
||||
+ /* |
||||
+ * Truncate at highest contiguous point to avoid holes on interrupt, |
||||
+ * or unconditionally if writing in place. |
||||
+ */ |
||||
+ if (inplace_flag || read_error || write_error || interrupted) { |
||||
if (reordered && resume_flag) { |
||||
error("Unable to resume download of \"%s\": " |
||||
"server reordered requests", local_path); |
||||
@@ -1724,7 +1727,7 @@ do_download(struct sftp_conn *conn, cons |
||||
static int |
||||
download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, |
||||
int depth, Attrib *dirattrib, int preserve_flag, int print_flag, |
||||
- int resume_flag, int fsync_flag, int follow_link_flag) |
||||
+ int resume_flag, int fsync_flag, int follow_link_flag, int inplace_flag) |
||||
{ |
||||
int i, ret = 0; |
||||
SFTP_DIRENT **dir_entries; |
||||
@@ -1781,7 +1784,7 @@ download_dir_internal(struct sftp_conn * |
||||
if (download_dir_internal(conn, new_src, new_dst, |
||||
depth + 1, &(dir_entries[i]->a), preserve_flag, |
||||
print_flag, resume_flag, |
||||
- fsync_flag, follow_link_flag) == -1) |
||||
+ fsync_flag, follow_link_flag, inplace_flag) == -1) |
||||
ret = -1; |
||||
} else if (S_ISREG(dir_entries[i]->a.perm) || |
||||
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { |
||||
@@ -1793,7 +1796,8 @@ download_dir_internal(struct sftp_conn * |
||||
if (do_download(conn, new_src, new_dst, |
||||
S_ISLNK(dir_entries[i]->a.perm) ? NULL : |
||||
&(dir_entries[i]->a), |
||||
- preserve_flag, resume_flag, fsync_flag) == -1) { |
||||
+ preserve_flag, resume_flag, fsync_flag, |
||||
+ inplace_flag) == -1) { |
||||
error("Download of file %s to %s failed", |
||||
new_src, new_dst); |
||||
ret = -1; |
||||
@@ -1831,7 +1835,7 @@ download_dir_internal(struct sftp_conn * |
||||
int |
||||
download_dir(struct sftp_conn *conn, const char *src, const char *dst, |
||||
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, |
||||
- int fsync_flag, int follow_link_flag) |
||||
+ int fsync_flag, int follow_link_flag, int inplace_flag) |
||||
{ |
||||
char *src_canon; |
||||
int ret; |
||||
@@ -1843,26 +1847,25 @@ download_dir(struct sftp_conn *conn, con |
||||
|
||||
ret = download_dir_internal(conn, src_canon, dst, 0, |
||||
dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, |
||||
- follow_link_flag); |
||||
+ follow_link_flag, inplace_flag); |
||||
free(src_canon); |
||||
return ret; |
||||
} |
||||
|
||||
int |
||||
do_upload(struct sftp_conn *conn, const char *local_path, |
||||
- const char *remote_path, int preserve_flag, int resume, int fsync_flag) |
||||
+ const char *remote_path, int preserve_flag, int resume, |
||||
+ int fsync_flag, int inplace_flag) |
||||
{ |
||||
int r, local_fd; |
||||
- u_int status = SSH2_FX_OK; |
||||
- u_int id; |
||||
- u_char type; |
||||
+ u_int openmode, id, status = SSH2_FX_OK, reordered = 0; |
||||
off_t offset, progress_counter; |
||||
- u_char *handle, *data; |
||||
+ u_char type, *handle, *data; |
||||
struct sshbuf *msg; |
||||
struct stat sb; |
||||
- Attrib a, *c = NULL; |
||||
- u_int32_t startid; |
||||
- u_int32_t ackid; |
||||
+ Attrib a, t, *c = NULL; |
||||
+ u_int32_t startid, ackid; |
||||
+ u_int64_t highwater = 0; |
||||
struct request *ack = NULL; |
||||
struct requests acks; |
||||
size_t handle_len; |
||||
@@ -1913,10 +1916,15 @@ do_upload(struct sftp_conn *conn, const |
||||
} |
||||
} |
||||
|
||||
+ openmode = SSH2_FXF_WRITE|SSH2_FXF_CREAT; |
||||
+ if (resume) |
||||
+ openmode |= SSH2_FXF_APPEND; |
||||
+ else if (!inplace_flag) |
||||
+ openmode |= SSH2_FXF_TRUNC; |
||||
+ |
||||
/* Send open request */ |
||||
- if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT| |
||||
- (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC), |
||||
- &a, &handle, &handle_len) != 0) { |
||||
+ if (send_open(conn, remote_path, "dest", openmode, &a, |
||||
+ &handle, &handle_len) != 0) { |
||||
close(local_fd); |
||||
return -1; |
||||
} |
||||
@@ -1999,6 +2007,12 @@ do_upload(struct sftp_conn *conn, const |
||||
ack->id, ack->len, (unsigned long long)ack->offset); |
||||
++ackid; |
||||
progress_counter += ack->len; |
||||
+ if (!reordered && ack->offset <= highwater) |
||||
+ highwater = ack->offset + ack->len; |
||||
+ else if (!reordered && ack->offset > highwater) { |
||||
+ debug3_f("server reordered ACKs"); |
||||
+ reordered = 1; |
||||
+ } |
||||
free(ack); |
||||
} |
||||
offset += len; |
||||
@@ -2017,6 +2031,14 @@ do_upload(struct sftp_conn *conn, const |
||||
status = SSH2_FX_FAILURE; |
||||
} |
||||
|
||||
+ if (inplace_flag || (resume && (status != SSH2_FX_OK || interrupted))) { |
||||
+ debug("truncating at %llu", (unsigned long long)highwater); |
||||
+ attrib_clear(&t); |
||||
+ t.flags = SSH2_FILEXFER_ATTR_SIZE; |
||||
+ t.size = highwater; |
||||
+ do_fsetstat(conn, handle, handle_len, &t); |
||||
+ } |
||||
+ |
||||
if (close(local_fd) == -1) { |
||||
error("Couldn't close local file \"%s\": %s", local_path, |
||||
strerror(errno)); |
||||
@@ -2041,7 +2063,7 @@ do_upload(struct sftp_conn *conn, const |
||||
static int |
||||
upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, |
||||
int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, |
||||
- int follow_link_flag) |
||||
+ int follow_link_flag, int inplace_flag) |
||||
{ |
||||
int ret = 0; |
||||
DIR *dirp; |
||||
@@ -2119,12 +2141,13 @@ upload_dir_internal(struct sftp_conn *co |
||||
|
||||
if (upload_dir_internal(conn, new_src, new_dst, |
||||
depth + 1, preserve_flag, print_flag, resume, |
||||
- fsync_flag, follow_link_flag) == -1) |
||||
+ fsync_flag, follow_link_flag, inplace_flag) == -1) |
||||
ret = -1; |
||||
} else if (S_ISREG(sb.st_mode) || |
||||
(follow_link_flag && S_ISLNK(sb.st_mode))) { |
||||
if (do_upload(conn, new_src, new_dst, |
||||
- preserve_flag, resume, fsync_flag) == -1) { |
||||
+ preserve_flag, resume, fsync_flag, |
||||
+ inplace_flag) == -1) { |
||||
error("Uploading of file %s to %s failed!", |
||||
new_src, new_dst); |
||||
ret = -1; |
||||
@@ -2144,7 +2167,7 @@ upload_dir_internal(struct sftp_conn *co |
||||
int |
||||
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 create_dir) |
||||
+ int follow_link_flag, int create_dir, int inplace_flag) |
||||
{ |
||||
char *dst_canon; |
||||
int ret; |
||||
@@ -2155,7 +2178,7 @@ upload_dir(struct sftp_conn *conn, const |
||||
} |
||||
|
||||
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, |
||||
- print_flag, resume, fsync_flag, follow_link_flag); |
||||
+ print_flag, resume, fsync_flag, follow_link_flag, inplace_flag); |
||||
|
||||
free(dst_canon); |
||||
return ret; |
||||
diff --color -rup a/sftp-client.h b/sftp-client.h |
||||
--- a/sftp-client.h 2022-07-26 14:51:40.561120836 +0200 |
||||
+++ b/sftp-client.h 2022-07-26 14:52:37.120213042 +0200 |
||||
@@ -138,28 +138,29 @@ int do_fsync(struct sftp_conn *conn, u_c |
||||
* Download 'remote_path' to 'local_path'. Preserve permissions and times |
||||
* if 'pflag' is set |
||||
*/ |
||||
-int do_download(struct sftp_conn *, const char *, const char *, |
||||
- Attrib *, int, int, int); |
||||
+int do_download(struct sftp_conn *, const char *, const char *, Attrib *, |
||||
+ int, int, int, int); |
||||
|
||||
/* |
||||
* Recursively download 'remote_directory' to 'local_directory'. Preserve |
||||
* times if 'pflag' is set |
||||
*/ |
||||
-int download_dir(struct sftp_conn *, const char *, const char *, |
||||
- Attrib *, int, int, int, int, int); |
||||
+int download_dir(struct sftp_conn *, const char *, const char *, Attrib *, |
||||
+ int, int, int, int, int, int); |
||||
|
||||
/* |
||||
* Upload 'local_path' to 'remote_path'. Preserve permissions and times |
||||
* if 'pflag' is set |
||||
*/ |
||||
-int do_upload(struct sftp_conn *, const char *, const char *, int, int, int); |
||||
+int do_upload(struct sftp_conn *, const char *, const char *, |
||||
+ int, int, int, int); |
||||
|
||||
/* |
||||
* Recursively upload 'local_directory' to 'remote_directory'. Preserve |
||||
* times if 'pflag' is set |
||||
*/ |
||||
-int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, |
||||
- int, int, int); |
||||
+int upload_dir(struct sftp_conn *, const char *, const char *, |
||||
+ int, int, int, int, int, int, int); |
||||
|
||||
/* |
||||
* Download a 'from_path' from the 'from' connection and upload it to |
@ -0,0 +1,46 @@
@@ -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 |
||||
This is helpful in |
||||
debugging connection, authentication, and configuration problems. |
||||
.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,129 @@
@@ -0,0 +1,129 @@
|
||||
diff --git a/scp.1 b/scp.1 |
||||
index 68aac04b..a96e95ad 100644 |
||||
--- a/scp.1 |
||||
+++ b/scp.1 |
||||
@@ -8,9 +8,9 @@ |
||||
.\" |
||||
.\" Created: Sun May 7 00:14:37 1995 ylo |
||||
.\" |
||||
-.\" $OpenBSD: scp.1,v 1.100 2021/08/11 14:07:54 naddy Exp $ |
||||
+.\" $OpenBSD: scp.1,v 1.101 2021/09/08 23:31:39 djm Exp $ |
||||
.\" |
||||
-.Dd $Mdocdate: August 11 2021 $ |
||||
+.Dd $Mdocdate: September 8 2021 $ |
||||
.Dt SCP 1 |
||||
.Os |
||||
.Sh NAME |
||||
@@ -18,7 +18,7 @@ |
||||
.Nd OpenSSH secure file copy |
||||
.Sh SYNOPSIS |
||||
.Nm scp |
||||
-.Op Fl 346ABCOpqRrsTv |
||||
+.Op Fl 346ABCOpqRrTv |
||||
.Op Fl c Ar cipher |
||||
.Op Fl D Ar sftp_server_path |
||||
.Op Fl F Ar ssh_config |
||||
@@ -37,9 +37,6 @@ It uses |
||||
.Xr ssh 1 |
||||
for data transfer, and uses the same authentication and provides the |
||||
same security as a login session. |
||||
-The scp protocol requires execution of the remote user's shell to perform |
||||
-.Xr glob 3 |
||||
-pattern matching. |
||||
.Pp |
||||
.Nm |
||||
will ask for passwords or passphrases if they are needed for |
||||
@@ -79,7 +76,9 @@ The options are as follows: |
||||
Copies between two remote hosts are transferred through the local host. |
||||
Without this option the data is copied directly between the two remote |
||||
hosts. |
||||
-Note that, when using the legacy SCP protocol (the default), this option |
||||
+Note that, when using the legacy SCP protocol (via the |
||||
+.Fl O |
||||
+flag), this option |
||||
selects batch mode for the second host as |
||||
.Nm |
||||
cannot ask for passwords or passphrases for both hosts. |
||||
@@ -146,9 +145,10 @@ Limits the used bandwidth, specified in Kbit/s. |
||||
.It Fl O |
||||
Use the legacy SCP protocol for file transfers instead of the SFTP protocol. |
||||
Forcing the use of the SCP protocol may be necessary for servers that do |
||||
-not implement SFTP or for backwards-compatibility for particular filename |
||||
-wildcard patterns. |
||||
-This mode is the default. |
||||
+not implement SFTP, for backwards-compatibility for particular filename |
||||
+wildcard patterns and for expanding paths with a |
||||
+.Sq ~ |
||||
+prefix for older SFTP servers. |
||||
.It Fl o Ar ssh_option |
||||
Can be used to pass options to |
||||
.Nm ssh |
||||
@@ -258,16 +258,6 @@ to use for the encrypted connection. |
||||
The program must understand |
||||
.Xr ssh 1 |
||||
options. |
||||
-.It Fl s |
||||
-Use the SFTP protocol for file transfers instead of the legacy SCP protocol. |
||||
-Using SFTP avoids invoking a shell on the remote side and provides |
||||
-more predictable filename handling, as the SCP protocol |
||||
-relied on the remote shell for expanding |
||||
-.Xr glob 3 |
||||
-wildcards. |
||||
-.Pp |
||||
-A near-future release of OpenSSH will make the SFTP protocol the default. |
||||
-This option will be deleted before the end of 2022. |
||||
.It Fl T |
||||
Disable strict filename checking. |
||||
By default when copying files from a remote host to a local directory |
||||
@@ -299,11 +289,23 @@ debugging connection, authentication, and configuration problems. |
||||
.Xr ssh_config 5 , |
||||
.Xr sftp-server 8 , |
||||
.Xr sshd 8 |
||||
+.Sh CAVEATS |
||||
+The original scp protocol (selected by the |
||||
+.Fl O |
||||
+flag) requires execution of the remote user's shell to perform |
||||
+.Xr glob 3 |
||||
+pattern matching. |
||||
+This requires careful quoting of any characters that have special meaning to |
||||
+the remote shell, such as quote characters. |
||||
.Sh HISTORY |
||||
.Nm |
||||
is based on the rcp program in |
||||
.Bx |
||||
source code from the Regents of the University of California. |
||||
+.Pp |
||||
+Since OpenSSH 8.8 (8.7 in Red Hat/Fedora builds), |
||||
+.Nm |
||||
+has use the SFTP protocol for transfers by default. |
||||
.Sh AUTHORS |
||||
.An Timo Rinne Aq Mt tri@iki.fi |
||||
.An Tatu Ylonen Aq Mt ylo@cs.hut.fi |
||||
diff --git a/scp.c b/scp.c |
||||
index e039350c..c7cf7529 100644 |
||||
--- a/scp.c |
||||
+++ b/scp.c |
||||
@@ -1,4 +1,4 @@ |
||||
-/* $OpenBSD: scp.c,v 1.232 2021/08/11 14:07:54 naddy Exp $ */ |
||||
+/* $OpenBSD: scp.c,v 1.233 2021/09/08 23:31:39 djm Exp $ */ |
||||
/* |
||||
* scp - secure remote copy. This is basically patched BSD rcp which |
||||
* uses ssh to do the data transfer (instead of using rcmd). |
||||
@@ -448,7 +448,7 @@ main(int argc, char **argv) |
||||
const char *errstr; |
||||
extern char *optarg; |
||||
extern int optind; |
||||
- enum scp_mode_e mode = MODE_SCP; |
||||
+ enum scp_mode_e mode = MODE_SFTP; |
||||
char *sftp_direct = NULL; |
||||
|
||||
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
||||
@@ -1983,7 +1983,7 @@ void |
||||
usage(void) |
||||
{ |
||||
(void) fprintf(stderr, |
||||
- "usage: scp [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n" |
||||
+ "usage: scp [-346ABCOpqRrTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n" |
||||
" [-i identity_file] [-J destination] [-l limit]\n" |
||||
" [-o ssh_option] [-P port] [-S program] source ... target\n"); |
||||
exit(1); |
@ -0,0 +1,167 @@
@@ -0,0 +1,167 @@
|
||||
diff -up openssh-8.7p1/scp.c.sftpdirs openssh-8.7p1/scp.c |
||||
--- openssh-8.7p1/scp.c.sftpdirs 2022-02-02 14:11:12.553447509 +0100 |
||||
+++ openssh-8.7p1/scp.c 2022-02-02 14:12:56.081316414 +0100 |
||||
@@ -130,6 +130,7 @@ |
||||
#include "misc.h" |
||||
#include "progressmeter.h" |
||||
#include "utf8.h" |
||||
+#include "sftp.h" |
||||
|
||||
#include "sftp-common.h" |
||||
#include "sftp-client.h" |
||||
@@ -660,7 +661,7 @@ main(int argc, char **argv) |
||||
* Finally check the exit status of the ssh process, if one was forked |
||||
* and no error has occurred yet |
||||
*/ |
||||
- if (do_cmd_pid != -1 && errs == 0) { |
||||
+ if (do_cmd_pid != -1 && (mode == MODE_SFTP || errs == 0)) { |
||||
if (remin != -1) |
||||
(void) close(remin); |
||||
if (remout != -1) |
||||
@@ -1264,13 +1265,18 @@ tolocal(int argc, char **argv, enum scp_ |
||||
static char * |
||||
prepare_remote_path(struct sftp_conn *conn, const char *path) |
||||
{ |
||||
+ size_t nslash; |
||||
+ |
||||
/* Handle ~ prefixed paths */ |
||||
- if (*path != '~') |
||||
- return xstrdup(path); |
||||
if (*path == '\0' || strcmp(path, "~") == 0) |
||||
return xstrdup("."); |
||||
- if (strncmp(path, "~/", 2) == 0) |
||||
- return xstrdup(path + 2); |
||||
+ if (*path != '~') |
||||
+ return xstrdup(path); |
||||
+ if (strncmp(path, "~/", 2) == 0) { |
||||
+ if ((nslash = strspn(path + 2, "/")) == strlen(path + 2)) |
||||
+ return xstrdup("."); |
||||
+ return xstrdup(path + 2 + nslash); |
||||
+ } |
||||
if (can_expand_path(conn)) |
||||
return do_expand_path(conn, path); |
||||
/* No protocol extension */ |
||||
@@ -1282,10 +1288,16 @@ void |
||||
source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) |
||||
{ |
||||
char *target = NULL, *filename = NULL, *abs_dst = NULL; |
||||
- int target_is_dir; |
||||
- |
||||
+ int src_is_dir, target_is_dir; |
||||
+ Attrib a; |
||||
+ struct stat st; |
||||
+ |
||||
+ memset(&a, '\0', sizeof(a)); |
||||
+ if (stat(src, &st) != 0) |
||||
+ fatal("stat local \"%s\": %s", src, strerror(errno)); |
||||
+ src_is_dir = S_ISDIR(st.st_mode); |
||||
if ((filename = basename(src)) == NULL) |
||||
- fatal("basename %s: %s", src, strerror(errno)); |
||||
+ fatal("basename \"%s\": %s", src, strerror(errno)); |
||||
|
||||
/* |
||||
* No need to glob here - the local shell already took care of |
||||
@@ -1295,8 +1307,12 @@ source_sftp(int argc, char *src, char *t |
||||
cleanup_exit(255); |
||||
target_is_dir = remote_is_dir(conn, target); |
||||
if (targetshouldbedirectory && !target_is_dir) { |
||||
- fatal("Target is not a directory, but more files selected " |
||||
- "for upload"); |
||||
+ debug("target directory \"%s\" does not exist", target); |
||||
+ a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS; |
||||
+ a.perm = st.st_mode | 0700; /* ensure writable */ |
||||
+ if (do_mkdir(conn, target, &a, 1) != 0) |
||||
+ cleanup_exit(255); /* error already logged */ |
||||
+ target_is_dir = 1; |
||||
} |
||||
if (target_is_dir) |
||||
abs_dst = path_append(target, filename); |
||||
@@ -1306,14 +1322,17 @@ source_sftp(int argc, char *src, char *t |
||||
} |
||||
debug3_f("copying local %s to remote %s", src, abs_dst); |
||||
|
||||
- if (local_is_dir(src) && iamrecursive) { |
||||
+ if (src_is_dir && iamrecursive) { |
||||
if (upload_dir(conn, src, abs_dst, pflag, |
||||
SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) { |
||||
- fatal("failed to upload directory %s to %s", |
||||
+ error("failed to upload directory %s to %s", |
||||
src, abs_dst); |
||||
+ errs = 1; |
||||
} |
||||
- } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) |
||||
- fatal("failed to upload file %s to %s", src, abs_dst); |
||||
+ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) { |
||||
+ error("failed to upload file %s to %s", src, abs_dst); |
||||
+ errs = 1; |
||||
+ } |
||||
|
||||
free(abs_dst); |
||||
free(target); |
||||
@@ -1487,14 +1506,15 @@ sink_sftp(int argc, char *dst, const cha |
||||
char *abs_dst = NULL; |
||||
glob_t g; |
||||
char *filename, *tmp = NULL; |
||||
- int i, r, err = 0; |
||||
+ int i, r, err = 0, dst_is_dir; |
||||
+ struct stat st; |
||||
|
||||
memset(&g, 0, sizeof(g)); |
||||
+ |
||||
/* |
||||
* Here, we need remote glob as SFTP can not depend on remote shell |
||||
* expansions |
||||
*/ |
||||
- |
||||
if ((abs_src = prepare_remote_path(conn, src)) == NULL) { |
||||
err = -1; |
||||
goto out; |
||||
@@ -1510,11 +1530,24 @@ sink_sftp(int argc, char *dst, const cha |
||||
goto out; |
||||
} |
||||
|
||||
- if (g.gl_matchc > 1 && !local_is_dir(dst)) { |
||||
- error("Multiple files match pattern, but destination " |
||||
- "\"%s\" is not a directory", dst); |
||||
- err = -1; |
||||
- goto out; |
||||
+ if ((r = stat(dst, &st)) != 0) |
||||
+ debug2_f("stat local \"%s\": %s", dst, strerror(errno)); |
||||
+ dst_is_dir = r == 0 && S_ISDIR(st.st_mode); |
||||
+ |
||||
+ if (g.gl_matchc > 1 && !dst_is_dir) { |
||||
+ if (r == 0) { |
||||
+ error("Multiple files match pattern, but destination " |
||||
+ "\"%s\" is not a directory", dst); |
||||
+ err = -1; |
||||
+ goto out; |
||||
+ } |
||||
+ debug2_f("creating destination \"%s\"", dst); |
||||
+ if (mkdir(dst, 0777) != 0) { |
||||
+ error("local mkdir \"%s\": %s", dst, strerror(errno)); |
||||
+ err = -1; |
||||
+ goto out; |
||||
+ } |
||||
+ dst_is_dir = 1; |
||||
} |
||||
|
||||
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
||||
@@ -1525,7 +1558,7 @@ sink_sftp(int argc, char *dst, const cha |
||||
goto out; |
||||
} |
||||
|
||||
- if (local_is_dir(dst)) |
||||
+ if (dst_is_dir) |
||||
abs_dst = path_append(dst, filename); |
||||
else |
||||
abs_dst = xstrdup(dst); |
||||
@@ -1551,7 +1584,8 @@ out: |
||||
free(tmp); |
||||
globfree(&g); |
||||
if (err == -1) { |
||||
- fatal("Failed to download file '%s'", src); |
||||
+ error("Failed to download '%s'", src); |
||||
+ errs = 1; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,53 @@
@@ -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 EscapeChar |
||||
.It ExitOnForwardFailure |
||||
.It FingerprintHash |
||||
@@ -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,25 @@
@@ -0,0 +1,25 @@
|
||||
diff --git a/misc.c b/misc.c |
||||
index b8d1040d..0134d694 100644 |
||||
--- a/misc.c |
||||
+++ b/misc.c |
||||
@@ -56,6 +56,7 @@ |
||||
#ifdef HAVE_PATHS_H |
||||
# include <paths.h> |
||||
#include <pwd.h> |
||||
+#include <grp.h> |
||||
#endif |
||||
#ifdef SSH_TUN_OPENBSD |
||||
#include <net/if.h> |
||||
@@ -2695,6 +2696,12 @@ subprocess(const char *tag, const char *command, |
||||
} |
||||
closefrom(STDERR_FILENO + 1); |
||||
|
||||
+ if (geteuid() == 0 && |
||||
+ initgroups(pw->pw_name, pw->pw_gid) == -1) { |
||||
+ error("%s: initgroups(%s, %u): %s", tag, |
||||
+ pw->pw_name, (u_int)pw->pw_gid, strerror(errno)); |
||||
+ _exit(1); |
||||
+ } |
||||
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) { |
||||
error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, |
||||
strerror(errno)); |
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
authfd.c |
||||
authfd.h |
||||
atomicio.c |
||||
atomicio.h |
||||
bufaux.c |
||||
bufbn.c |
||||
buffer.h |
||||
buffer.c |
||||
cleanup.c |
||||
cipher.h |
||||
compat.h |
||||
entropy.c |
||||
entropy.h |
||||
fatal.c |
||||
includes.h |
||||
kex.h |
||||
key.c |
||||
key.h |
||||
log.c |
||||
log.h |
||||
match.h |
||||
misc.c |
||||
misc.h |
||||
pathnames.h |
||||
platform.h |
||||
rsa.h |
||||
ssh-dss.c |
||||
ssh-rsa.c |
||||
ssh.h |
||||
ssh2.h |
||||
uidswap.c |
||||
uidswap.h |
||||
uuencode.c |
||||
uuencode.h |
||||
xmalloc.c |
||||
xmalloc.h |
@ -0,0 +1,992 @@
@@ -0,0 +1,992 @@
|
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -27,6 +27,7 @@ |
||||
* or implied, of Jamie Beverly. |
||||
*/ |
||||
|
||||
+#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
@@ -66,8 +67,8 @@ proc_pid_cmdline(char *** inargv) |
||||
case EOF: |
||||
case '\0': |
||||
if (len > 0) { |
||||
- argv = pamsshagentauth_xrealloc(argv, count + 1, sizeof(*argv)); |
||||
- argv[count] = pamsshagentauth_xcalloc(len + 1, sizeof(*argv[count])); |
||||
+ argv = xreallocarray(argv, count + 1, sizeof(*argv)); |
||||
+ argv[count] = xcalloc(len + 1, sizeof(*argv[count])); |
||||
strncpy(argv[count++], argbuf, len); |
||||
memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1); |
||||
len = 0; |
||||
@@ -106,9 +107,9 @@ pamsshagentauth_free_command_line(char * |
||||
{ |
||||
size_t i; |
||||
for (i = 0; i < n_args; i++) |
||||
- pamsshagentauth_xfree(argv[i]); |
||||
+ free(argv[i]); |
||||
|
||||
- pamsshagentauth_xfree(argv); |
||||
+ free(argv); |
||||
return; |
||||
} |
||||
|
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -30,8 +30,8 @@ |
||||
#include "openbsd-compat/sys-queue.h" |
||||
#include "xmalloc.h" |
||||
#include "log.h" |
||||
-#include "buffer.h" |
||||
-#include "key.h" |
||||
+#include "sshbuf.h" |
||||
+#include "sshkey.h" |
||||
#include "authfd.h" |
||||
#include <stdio.h> |
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct idlist Idlist; |
||||
struct identity { |
||||
TAILQ_ENTRY(identity) next; |
||||
AuthenticationConnection *ac; /* set if agent supports key */ |
||||
- Key *key; /* public/private key */ |
||||
+ struct sshkey *key; /* public/private key */ |
||||
char *filename; /* comment for agent-only keys */ |
||||
int tried; |
||||
int isprivate; /* key points to the private key */ |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c.psaa-compat 2020-09-23 10:52:16.421001434 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -36,8 +36,8 @@ |
||||
#include "openbsd-compat/sys-queue.h" |
||||
#include "xmalloc.h" |
||||
#include "log.h" |
||||
-#include "buffer.h" |
||||
-#include "key.h" |
||||
+#include "sshbuf.h" |
||||
+#include "sshkey.h" |
||||
#include "authfd.h" |
||||
#include <stdio.h> |
||||
#include <openssl/evp.h> |
||||
@@ -58,6 +58,8 @@ |
||||
#include "get_command_line.h" |
||||
extern char **environ; |
||||
|
||||
+#define PAM_SSH_AGENT_AUTH_REQUESTv1 101 |
||||
+ |
||||
/* |
||||
* Added by Jamie Beverly, ensure socket fd points to a socket owned by the user |
||||
* A cursory check is done, but to avoid race conditions, it is necessary |
||||
@@ -77,7 +79,7 @@ log_action(char ** action, size_t count) |
||||
if (count == 0) |
||||
return NULL; |
||||
|
||||
- buf = pamsshagentauth_xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); |
||||
+ buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); |
||||
for (i = 0; i < count; i++) { |
||||
strcat(buf, (i > 0) ? " '" : "'"); |
||||
strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG); |
||||
@@ -87,21 +89,25 @@ log_action(char ** action, size_t count) |
||||
} |
||||
|
||||
void |
||||
-agent_action(Buffer *buf, char ** action, size_t count) |
||||
+agent_action(struct sshbuf **buf, char ** action, size_t count) |
||||
{ |
||||
size_t i; |
||||
- pamsshagentauth_buffer_init(buf); |
||||
+ int r; |
||||
|
||||
- pamsshagentauth_buffer_put_int(buf, count); |
||||
+ if ((*buf = sshbuf_new()) == NULL) |
||||
+ fatal("%s: sshbuf_new failed", __func__); |
||||
+ if ((r = sshbuf_put_u32(*buf, count)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
|
||||
for (i = 0; i < count; i++) { |
||||
- pamsshagentauth_buffer_put_cstring(buf, action[i]); |
||||
+ if ((r = sshbuf_put_cstring(*buf, action[i])) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
} |
||||
} |
||||
|
||||
|
||||
-void |
||||
-pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, |
||||
+static void |
||||
+pamsshagentauth_session_id2_gen(struct sshbuf ** session_id2, const char * user, |
||||
const char * ruser, const char * servicename) |
||||
{ |
||||
u_char *cookie = NULL; |
||||
@@ -114,22 +120,23 @@ pamsshagentauth_session_id2_gen(Buffer * |
||||
char ** reported_argv = NULL; |
||||
size_t count = 0; |
||||
char * action_logbuf = NULL; |
||||
- Buffer action_agentbuf; |
||||
+ struct sshbuf *action_agentbuf = NULL; |
||||
uint8_t free_logbuf = 0; |
||||
char * retc; |
||||
int32_t reti; |
||||
+ int r; |
||||
|
||||
- rnd = pamsshagentauth_arc4random(); |
||||
+ rnd = arc4random(); |
||||
cookie_len = ((uint8_t) rnd); |
||||
while (cookie_len < 16) { |
||||
cookie_len += 16; /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */ |
||||
} |
||||
|
||||
- cookie = pamsshagentauth_xcalloc(1,cookie_len); |
||||
+ cookie = xcalloc(1, cookie_len); |
||||
|
||||
for (i = 0; i < cookie_len; i++) { |
||||
if (i % 4 == 0) { |
||||
- rnd = pamsshagentauth_arc4random(); |
||||
+ rnd = arc4random(); |
||||
} |
||||
cookie[i] = (u_char) rnd; |
||||
rnd >>= 8; |
||||
@@ -144,7 +151,8 @@ pamsshagentauth_session_id2_gen(Buffer * |
||||
} |
||||
else { |
||||
action_logbuf = "unknown on this platform"; |
||||
- pamsshagentauth_buffer_init(&action_agentbuf); /* stays empty, means unavailable */ |
||||
+ if ((action_agentbuf = sshbuf_new()) == NULL) /* stays empty, means unavailable */ |
||||
+ fatal("%s: sshbuf_new failed", __func__); |
||||
} |
||||
|
||||
/* |
||||
@@ -161,35 +169,39 @@ pamsshagentauth_session_id2_gen(Buffer * |
||||
retc = getcwd(pwd, sizeof(pwd) - 1); |
||||
time(&ts); |
||||
|
||||
- pamsshagentauth_buffer_init(session_id2); |
||||
+ if ((*session_id2 = sshbuf_new()) == NULL) |
||||
+ fatal("%s: sshbuf_new failed", __func__); |
||||
|
||||
- pamsshagentauth_buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1); |
||||
- /* pamsshagentauth_debug3("cookie: %s", pamsshagentauth_tohex(cookie, cookie_len)); */ |
||||
- pamsshagentauth_buffer_put_string(session_id2, cookie, cookie_len); |
||||
- /* pamsshagentauth_debug3("user: %s", user); */ |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, user); |
||||
- /* pamsshagentauth_debug3("ruser: %s", ruser); */ |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, ruser); |
||||
- /* pamsshagentauth_debug3("servicename: %s", servicename); */ |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, servicename); |
||||
- /* pamsshagentauth_debug3("pwd: %s", pwd); */ |
||||
- if(retc) |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, pwd); |
||||
- else |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, ""); |
||||
- /* pamsshagentauth_debug3("action: %s", action_logbuf); */ |
||||
- pamsshagentauth_buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset); |
||||
+ if ((r = sshbuf_put_u32(*session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1)) != 0 || |
||||
+ (r = sshbuf_put_string(*session_id2, cookie, cookie_len)) != 0 || |
||||
+ (r = sshbuf_put_cstring(*session_id2, user)) != 0 || |
||||
+ (r = sshbuf_put_cstring(*session_id2, ruser)) != 0 || |
||||
+ (r = sshbuf_put_cstring(*session_id2, servicename)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
+ if (retc) { |
||||
+ if ((r = sshbuf_put_cstring(*session_id2, pwd)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
+ } else { |
||||
+ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
+ } |
||||
+ if ((r = sshbuf_put_stringb(*session_id2, action_agentbuf)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
if (free_logbuf) { |
||||
- pamsshagentauth_xfree(action_logbuf); |
||||
- pamsshagentauth_buffer_free(&action_agentbuf); |
||||
+ free(action_logbuf); |
||||
+ sshbuf_free(action_agentbuf); |
||||
+ } |
||||
+ /* debug3("hostname: %s", hostname); */ |
||||
+ if (reti >= 0) { |
||||
+ if ((r = sshbuf_put_cstring(*session_id2, hostname)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
+ } else { |
||||
+ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
} |
||||
- /* pamsshagentauth_debug3("hostname: %s", hostname); */ |
||||
- if(reti >= 0) |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, hostname); |
||||
- else |
||||
- pamsshagentauth_buffer_put_cstring(session_id2, ""); |
||||
- /* pamsshagentauth_debug3("ts: %ld", ts); */ |
||||
- pamsshagentauth_buffer_put_int64(session_id2, (uint64_t) ts); |
||||
+ /* debug3("ts: %ld", ts); */ |
||||
+ if ((r = sshbuf_put_u64(*session_id2, (uint64_t) ts)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
|
||||
free(cookie); |
||||
return; |
||||
@@ -278,7 +290,8 @@ ssh_get_authentication_connection_for_ui |
||||
|
||||
auth = xmalloc(sizeof(*auth)); |
||||
auth->fd = sock; |
||||
- buffer_init(&auth->identities); |
||||
+ if ((auth->identities = sshbuf_new()) == NULL) |
||||
+ fatal("%s: sshbuf_new failed", __func__); |
||||
auth->howmany = 0; |
||||
|
||||
return auth; |
||||
@@ -287,9 +300,9 @@ ssh_get_authentication_connection_for_ui |
||||
int |
||||
pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) |
||||
{ |
||||
- Buffer session_id2 = { 0 }; |
||||
+ struct sshbuf *session_id2 = NULL; |
||||
Identity *id; |
||||
- Key *key; |
||||
+ struct sshkey *key; |
||||
AuthenticationConnection *ac; |
||||
char *comment; |
||||
uint8_t retval = 0; |
||||
@@ -299,31 +312,30 @@ pamsshagentauth_find_authorized_keys(con |
||||
pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); |
||||
|
||||
if ((ac = ssh_get_authentication_connection_for_uid(uid))) { |
||||
- pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); |
||||
+ verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); |
||||
for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) |
||||
{ |
||||
if(key != NULL) { |
||||
- id = pamsshagentauth_xcalloc(1, sizeof(*id)); |
||||
+ id = xcalloc(1, sizeof(*id)); |
||||
id->key = key; |
||||
id->filename = comment; |
||||
id->ac = ac; |
||||
- if(userauth_pubkey_from_id(ruser, id, &session_id2)) { |
||||
+ if(userauth_pubkey_from_id(ruser, id, session_id2)) { |
||||
retval = 1; |
||||
} |
||||
- pamsshagentauth_xfree(id->filename); |
||||
- pamsshagentauth_key_free(id->key); |
||||
- pamsshagentauth_xfree(id); |
||||
+ free(id->filename); |
||||
+ key_free(id->key); |
||||
+ free(id); |
||||
if(retval == 1) |
||||
break; |
||||
} |
||||
} |
||||
- pamsshagentauth_buffer_free(&session_id2); |
||||
+ sshbuf_free(session_id2); |
||||
ssh_close_authentication_connection(ac); |
||||
} |
||||
else { |
||||
- pamsshagentauth_verbose("No ssh-agent could be contacted"); |
||||
+ verbose("No ssh-agent could be contacted"); |
||||
} |
||||
- /* pamsshagentauth_xfree(session_id2); */ |
||||
EVP_cleanup(); |
||||
return retval; |
||||
} |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c.psaa-compat 2020-09-23 10:52:16.423001461 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c 2020-09-23 10:53:10.631727657 +0200 |
||||
@@ -106,7 +106,7 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
* a patch 8-) |
||||
*/ |
||||
#if ! HAVE___PROGNAME || HAVE_BUNDLE |
||||
- __progname = pamsshagentauth_xstrdup(servicename); |
||||
+ __progname = xstrdup(servicename); |
||||
#endif |
||||
|
||||
for(i = argc, argv_ptr = (char **) argv; i > 0; ++argv_ptr, i--) { |
||||
@@ -132,11 +132,11 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
#endif |
||||
} |
||||
|
||||
- pamsshagentauth_log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); |
||||
+ log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); |
||||
pam_get_item(pamh, PAM_USER, (void *) &user); |
||||
pam_get_item(pamh, PAM_RUSER, (void *) &ruser_ptr); |
||||
|
||||
- pamsshagentauth_verbose("Beginning pam_ssh_agent_auth for user %s", user); |
||||
+ verbose("Beginning pam_ssh_agent_auth for user %s", user); |
||||
|
||||
if(ruser_ptr) { |
||||
strncpy(ruser, ruser_ptr, sizeof(ruser) - 1); |
||||
@@ -151,12 +151,12 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
#ifdef ENABLE_SUDO_HACK |
||||
if( (strlen(sudo_service_name) > 0) && strncasecmp(servicename, sudo_service_name, sizeof(sudo_service_name) - 1) == 0 && getenv("SUDO_USER") ) { |
||||
strncpy(ruser, getenv("SUDO_USER"), sizeof(ruser) - 1 ); |
||||
- pamsshagentauth_verbose( "Using environment variable SUDO_USER (%s)", ruser ); |
||||
+ verbose( "Using environment variable SUDO_USER (%s)", ruser ); |
||||
} else |
||||
#endif |
||||
{ |
||||
if( ! getpwuid(getuid()) ) { |
||||
- pamsshagentauth_verbose("Unable to getpwuid(getuid())"); |
||||
+ verbose("Unable to getpwuid(getuid())"); |
||||
goto cleanexit; |
||||
} |
||||
strncpy(ruser, getpwuid(getuid())->pw_name, sizeof(ruser) - 1); |
||||
@@ -165,11 +165,11 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
|
||||
/* Might as well explicitely confirm the user exists here */ |
||||
if(! getpwnam(ruser) ) { |
||||
- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", ruser); |
||||
+ verbose("getpwnam(%s) failed, bailing out", ruser); |
||||
goto cleanexit; |
||||
} |
||||
if( ! getpwnam(user) ) { |
||||
- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", user); |
||||
+ verbose("getpwnam(%s) failed, bailing out", user); |
||||
goto cleanexit; |
||||
} |
||||
|
||||
@@ -179,8 +179,8 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
*/ |
||||
parse_authorized_key_file(user, authorized_keys_file_input); |
||||
} else { |
||||
- pamsshagentauth_verbose("Using default file=/etc/security/authorized_keys"); |
||||
- authorized_keys_file = pamsshagentauth_xstrdup("/etc/security/authorized_keys"); |
||||
+ verbose("Using default file=/etc/security/authorized_keys"); |
||||
+ authorized_keys_file = xstrdup("/etc/security/authorized_keys"); |
||||
} |
||||
|
||||
/* |
||||
@@ -189,7 +189,7 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
*/ |
||||
|
||||
if(user && strlen(ruser) > 0) { |
||||
- pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
+ verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
|
||||
/* |
||||
* Attempt to read data from the sshd if we're being called as an auth agent. |
||||
@@ -197,10 +197,10 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
const char* ssh_user_auth = pam_getenv(pamh, "SSH_AUTH_INFO_0"); |
||||
int sshd_service = strncasecmp(servicename, sshd_service_name, sizeof(sshd_service_name) - 1); |
||||
if (sshd_service == 0 && ssh_user_auth != NULL) { |
||||
- pamsshagentauth_verbose("Got SSH_AUTH_INFO_0: `%.20s...'", ssh_user_auth); |
||||
+ verbose("Got SSH_AUTH_INFO_0: `%.20s...'", ssh_user_auth); |
||||
if (userauth_pubkey_from_pam(ruser, ssh_user_auth) > 0) { |
||||
retval = PAM_SUCCESS; |
||||
- pamsshagentauth_logit("Authenticated (sshd): `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
+ logit("Authenticated (sshd): `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
goto cleanexit; |
||||
} |
||||
} |
||||
@@ -208,13 +208,13 @@ pam_sm_authenticate(pam_handle_t * pamh, |
||||
* this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user |
||||
*/ |
||||
if(pamsshagentauth_find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */ |
||||
- pamsshagentauth_logit("Authenticated (agent): `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
+ logit("Authenticated (agent): `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
retval = PAM_SUCCESS; |
||||
} else { |
||||
- pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
+ logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); |
||||
} |
||||
} else { |
||||
- pamsshagentauth_logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); |
||||
+ logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); |
||||
} |
||||
|
||||
cleanexit: |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -66,8 +66,8 @@ |
||||
#include "xmalloc.h" |
||||
#include "match.h" |
||||
#include "log.h" |
||||
-#include "buffer.h" |
||||
-#include "key.h" |
||||
+#include "sshbuf.h" |
||||
+#include "sshkey.h" |
||||
#include "misc.h" |
||||
|
||||
#include "xmalloc.h" |
||||
@@ -77,7 +77,6 @@ |
||||
#include "pathnames.h" |
||||
#include "secure_filename.h" |
||||
|
||||
-#include "identity.h" |
||||
#include "pam_user_key_allowed2.h" |
||||
|
||||
extern char *authorized_keys_file; |
||||
@@ -117,12 +116,12 @@ parse_authorized_key_file(const char *us |
||||
} else { |
||||
slash_ptr = strchr(auth_keys_file_buf, '/'); |
||||
if(!slash_ptr) |
||||
- pamsshagentauth_fatal |
||||
+ fatal |
||||
("cannot expand tilde in path without a `/'"); |
||||
|
||||
owner_uname_len = slash_ptr - auth_keys_file_buf - 1; |
||||
if(owner_uname_len > (sizeof(owner_uname) - 1)) |
||||
- pamsshagentauth_fatal("Username too long"); |
||||
+ fatal("Username too long"); |
||||
|
||||
strncat(owner_uname, auth_keys_file_buf + 1, owner_uname_len); |
||||
if(!authorized_keys_file_allowed_owner_uid) |
||||
@@ -130,11 +129,11 @@ parse_authorized_key_file(const char *us |
||||
getpwnam(owner_uname)->pw_uid; |
||||
} |
||||
authorized_keys_file = |
||||
- pamsshagentauth_tilde_expand_filename(auth_keys_file_buf, |
||||
+ tilde_expand_filename(auth_keys_file_buf, |
||||
authorized_keys_file_allowed_owner_uid); |
||||
strncpy(auth_keys_file_buf, authorized_keys_file, |
||||
sizeof(auth_keys_file_buf) - 1); |
||||
- pamsshagentauth_xfree(authorized_keys_file) /* when we |
||||
+ free(authorized_keys_file) /* when we |
||||
percent_expand |
||||
later, we'd step |
||||
on this, so free |
||||
@@ -150,13 +149,13 @@ parse_authorized_key_file(const char *us |
||||
strncat(hostname, fqdn, strcspn(fqdn, ".")); |
||||
#endif |
||||
authorized_keys_file = |
||||
- pamsshagentauth_percent_expand(auth_keys_file_buf, "h", |
||||
+ percent_expand(auth_keys_file_buf, "h", |
||||
getpwnam(user)->pw_dir, "H", hostname, |
||||
"f", fqdn, "u", user, NULL); |
||||
} |
||||
|
||||
int |
||||
-pam_user_key_allowed(const char *ruser, Key * key) |
||||
+pam_user_key_allowed(const char *ruser, struct sshkey * key) |
||||
{ |
||||
return |
||||
pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -32,7 +32,7 @@ |
||||
#define _PAM_USER_KEY_ALLOWED_H |
||||
|
||||
#include "identity.h" |
||||
-int pam_user_key_allowed(const char *, Key *); |
||||
+int pam_user_key_allowed(const char *, struct sshkey *); |
||||
void parse_authorized_key_file(const char *, const char *); |
||||
|
||||
#endif |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -45,44 +45,46 @@ |
||||
#include "xmalloc.h" |
||||
#include "ssh.h" |
||||
#include "ssh2.h" |
||||
-#include "buffer.h" |
||||
+#include "sshbuf.h" |
||||
#include "log.h" |
||||
#include "compat.h" |
||||
-#include "key.h" |
||||
+#include "digest.h" |
||||
+#include "sshkey.h" |
||||
#include "pathnames.h" |
||||
#include "misc.h" |
||||
#include "secure_filename.h" |
||||
#include "uidswap.h" |
||||
- |
||||
-#include "identity.h" |
||||
+#include <unistd.h> |
||||
|
||||
/* return 1 if user allows given key */ |
||||
/* Modified slightly from original found in auth2-pubkey.c */ |
||||
static int |
||||
-pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key) |
||||
+pamsshagentauth_check_authkeys_file(FILE * f, char *file, struct sshkey * key) |
||||
{ |
||||
- char line[SSH_MAX_PUBKEY_BYTES]; |
||||
+ char *line = NULL; |
||||
int found_key = 0; |
||||
u_long linenum = 0; |
||||
- Key *found; |
||||
+ struct sshkey *found; |
||||
char *fp; |
||||
+ size_t linesize = 0; |
||||
|
||||
found_key = 0; |
||||
- found = pamsshagentauth_key_new(key->type); |
||||
+ found = sshkey_new(key->type); |
||||
|
||||
- while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { |
||||
+ while ((getline(&line, &linesize, f)) != -1) { |
||||
char *cp = NULL; /* *key_options = NULL; */ |
||||
|
||||
+ linenum++; |
||||
/* Skip leading whitespace, empty and comment lines. */ |
||||
for(cp = line; *cp == ' ' || *cp == '\t'; cp++); |
||||
if(!*cp || *cp == '\n' || *cp == '#') |
||||
continue; |
||||
|
||||
- if(pamsshagentauth_key_read(found, &cp) != 1) { |
||||
+ if (sshkey_read(found, &cp) != 0) { |
||||
/* no key? check if there are options for this key */ |
||||
int quoted = 0; |
||||
|
||||
- pamsshagentauth_verbose("user_key_allowed: check options: '%s'", cp); |
||||
+ verbose("user_key_allowed: check options: '%s'", cp); |
||||
/* key_options = cp; */ |
||||
for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { |
||||
if(*cp == '\\' && cp[1] == '"') |
||||
@@ -92,26 +94,27 @@ pamsshagentauth_check_authkeys_file(FILE |
||||
} |
||||
/* Skip remaining whitespace. */ |
||||
for(; *cp == ' ' || *cp == '\t'; cp++); |
||||
- if(pamsshagentauth_key_read(found, &cp) != 1) { |
||||
- pamsshagentauth_verbose("user_key_allowed: advance: '%s'", cp); |
||||
+ if(sshkey_read(found, &cp) != 0) { |
||||
+ verbose("user_key_allowed: advance: '%s'", cp); |
||||
/* still no key? advance to next line */ |
||||
continue; |
||||
} |
||||
} |
||||
- if(pamsshagentauth_key_equal(found, key)) { |
||||
+ if(sshkey_equal(found, key)) { |
||||
found_key = 1; |
||||
- pamsshagentauth_logit("matching key found: file/command %s, line %lu", file, |
||||
+ logit("matching key found: file/command %s, line %lu", file, |
||||
linenum); |
||||
- fp = pamsshagentauth_key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); |
||||
- pamsshagentauth_logit("Found matching %s key: %s", |
||||
- pamsshagentauth_key_type(found), fp); |
||||
- pamsshagentauth_xfree(fp); |
||||
+ fp = sshkey_fingerprint(found, SSH_DIGEST_SHA256, SSH_FP_BASE64); |
||||
+ logit("Found matching %s key: %s", |
||||
+ sshkey_type(found), fp); |
||||
+ free(fp); |
||||
break; |
||||
} |
||||
} |
||||
- pamsshagentauth_key_free(found); |
||||
+ free(line); |
||||
+ sshkey_free(found); |
||||
if(!found_key) |
||||
- pamsshagentauth_verbose("key not found"); |
||||
+ verbose("key not found"); |
||||
return found_key; |
||||
} |
||||
|
||||
@@ -120,19 +123,19 @@ pamsshagentauth_check_authkeys_file(FILE |
||||
* returns 1 if the key is allowed or 0 otherwise. |
||||
*/ |
||||
int |
||||
-pamsshagentauth_user_key_allowed2(struct passwd *pw, Key * key, char *file) |
||||
+pamsshagentauth_user_key_allowed2(struct passwd *pw, struct sshkey * key, char *file) |
||||
{ |
||||
FILE *f; |
||||
int found_key = 0; |
||||
struct stat st; |
||||
- char buf[SSH_MAX_PUBKEY_BYTES]; |
||||
+ char buf[256]; |
||||
|
||||
/* Temporarily use the user's uid. */ |
||||
- pamsshagentauth_verbose("trying public key file %s", file); |
||||
+ verbose("trying public key file %s", file); |
||||
|
||||
/* Fail not so quietly if file does not exist */ |
||||
if(stat(file, &st) < 0) { |
||||
- pamsshagentauth_verbose("File not found: %s", file); |
||||
+ verbose("File not found: %s", file); |
||||
return 0; |
||||
} |
||||
|
||||
@@ -144,7 +147,7 @@ pamsshagentauth_user_key_allowed2(struct |
||||
|
||||
if(pamsshagentauth_secure_filename(f, file, pw, buf, sizeof(buf)) != 0) { |
||||
fclose(f); |
||||
- pamsshagentauth_logit("Authentication refused: %s", buf); |
||||
+ logit("Authentication refused: %s", buf); |
||||
return 0; |
||||
} |
||||
|
||||
@@ -160,7 +163,7 @@ pamsshagentauth_user_key_allowed2(struct |
||||
int |
||||
pamsshagentauth_user_key_command_allowed2(char *authorized_keys_command, |
||||
char *authorized_keys_command_user, |
||||
- struct passwd *user_pw, Key * key) |
||||
+ struct passwd *user_pw, struct sshkey * key) |
||||
{ |
||||
FILE *f; |
||||
int ok, found_key = 0; |
||||
@@ -187,44 +190,44 @@ pamsshagentauth_user_key_command_allowed |
||||
else { |
||||
pw = getpwnam(authorized_keys_command_user); |
||||
if(pw == NULL) { |
||||
- pamsshagentauth_logerror("authorized_keys_command_user \"%s\" not found: %s", |
||||
+ error("authorized_keys_command_user \"%s\" not found: %s", |
||||
authorized_keys_command_user, strerror(errno)); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
- pamsshagentauth_temporarily_use_uid(pw); |
||||
+ temporarily_use_uid(pw); |
||||
|
||||
if(stat(authorized_keys_command, &st) < 0) { |
||||
- pamsshagentauth_logerror |
||||
+ error |
||||
("Could not stat AuthorizedKeysCommand \"%s\": %s", |
||||
authorized_keys_command, strerror(errno)); |
||||
goto out; |
||||
} |
||||
if(pamsshagentauth_auth_secure_path |
||||
(authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { |
||||
- pamsshagentauth_logerror("Unsafe AuthorizedKeysCommand: %s", errmsg); |
||||
+ error("Unsafe AuthorizedKeysCommand: %s", errmsg); |
||||
goto out; |
||||
} |
||||
|
||||
/* open the pipe and read the keys */ |
||||
if(pipe(p) != 0) { |
||||
- pamsshagentauth_logerror("%s: pipe: %s", __func__, strerror(errno)); |
||||
+ error("%s: pipe: %s", __func__, strerror(errno)); |
||||
goto out; |
||||
} |
||||
|
||||
- pamsshagentauth_debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", |
||||
+ debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", |
||||
authorized_keys_command, pw->pw_name, username); |
||||
|
||||
/* |
||||
* Don't want to call this in the child, where it can fatal() and |
||||
* run cleanup_exit() code. |
||||
*/ |
||||
- pamsshagentauth_restore_uid(); |
||||
+ restore_uid(); |
||||
|
||||
switch ((pid = fork())) { |
||||
case -1: /* error */ |
||||
- pamsshagentauth_logerror("%s: fork: %s", __func__, strerror(errno)); |
||||
+ error("%s: fork: %s", __func__, strerror(errno)); |
||||
close(p[0]); |
||||
close(p[1]); |
||||
return 0; |
||||
@@ -234,13 +237,13 @@ pamsshagentauth_user_key_command_allowed |
||||
|
||||
/* do this before the setresuid so thta they can be logged */ |
||||
if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { |
||||
- pamsshagentauth_logerror("%s: open %s: %s", __func__, _PATH_DEVNULL, |
||||
+ error("%s: open %s: %s", __func__, _PATH_DEVNULL, |
||||
strerror(errno)); |
||||
_exit(1); |
||||
} |
||||
if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1 |
||||
|| dup2(devnull, STDERR_FILENO) == -1) { |
||||
- pamsshagentauth_logerror("%s: dup2: %s", __func__, strerror(errno)); |
||||
+ error("%s: dup2: %s", __func__, strerror(errno)); |
||||
_exit(1); |
||||
} |
||||
#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) |
||||
@@ -248,7 +251,7 @@ pamsshagentauth_user_key_command_allowed |
||||
#else |
||||
if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) { |
||||
#endif |
||||
- pamsshagentauth_logerror("setresgid %u: %s", (u_int) pw->pw_gid, |
||||
+ error("setresgid %u: %s", (u_int) pw->pw_gid, |
||||
strerror(errno)); |
||||
_exit(1); |
||||
} |
||||
@@ -258,7 +261,7 @@ pamsshagentauth_user_key_command_allowed |
||||
#else |
||||
if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) { |
||||
#endif |
||||
- pamsshagentauth_logerror("setresuid %u: %s", (u_int) pw->pw_uid, |
||||
+ error("setresuid %u: %s", (u_int) pw->pw_uid, |
||||
strerror(errno)); |
||||
_exit(1); |
||||
} |
||||
@@ -270,18 +273,18 @@ pamsshagentauth_user_key_command_allowed |
||||
|
||||
/* pretty sure this will barf because we are now suid, but since we |
||||
should't reach this anyway, I'll leave it here */ |
||||
- pamsshagentauth_logerror("AuthorizedKeysCommand %s exec failed: %s", |
||||
+ error("AuthorizedKeysCommand %s exec failed: %s", |
||||
authorized_keys_command, strerror(errno)); |
||||
_exit(127); |
||||
default: /* parent */ |
||||
break; |
||||
} |
||||
|
||||
- pamsshagentauth_temporarily_use_uid(pw); |
||||
+ temporarily_use_uid(pw); |
||||
|
||||
close(p[1]); |
||||
if((f = fdopen(p[0], "r")) == NULL) { |
||||
- pamsshagentauth_logerror("%s: fdopen: %s", __func__, strerror(errno)); |
||||
+ error("%s: fdopen: %s", __func__, strerror(errno)); |
||||
close(p[0]); |
||||
/* Don't leave zombie child */ |
||||
while(waitpid(pid, NULL, 0) == -1 && errno == EINTR); |
||||
@@ -292,22 +295,22 @@ pamsshagentauth_user_key_command_allowed |
||||
|
||||
while(waitpid(pid, &status, 0) == -1) { |
||||
if(errno != EINTR) { |
||||
- pamsshagentauth_logerror("%s: waitpid: %s", __func__, |
||||
+ error("%s: waitpid: %s", __func__, |
||||
strerror(errno)); |
||||
goto out; |
||||
} |
||||
} |
||||
if(WIFSIGNALED(status)) { |
||||
- pamsshagentauth_logerror("AuthorizedKeysCommand %s exited on signal %d", |
||||
+ error("AuthorizedKeysCommand %s exited on signal %d", |
||||
authorized_keys_command, WTERMSIG(status)); |
||||
goto out; |
||||
} else if(WEXITSTATUS(status) != 0) { |
||||
- pamsshagentauth_logerror("AuthorizedKeysCommand %s returned status %d", |
||||
+ error("AuthorizedKeysCommand %s returned status %d", |
||||
authorized_keys_command, WEXITSTATUS(status)); |
||||
goto out; |
||||
} |
||||
found_key = ok; |
||||
out: |
||||
- pamsshagentauth_restore_uid(); |
||||
+ restore_uid(); |
||||
return found_key; |
||||
} |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -32,7 +32,7 @@ |
||||
#define _PAM_USER_KEY_ALLOWED_H |
||||
|
||||
#include "identity.h" |
||||
-int pamsshagentauth_user_key_allowed2(struct passwd *, Key *, char *); |
||||
-int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, Key *); |
||||
+int pamsshagentauth_user_key_allowed2(struct passwd *, struct sshkey *, char *); |
||||
+int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, struct sshkey *); |
||||
|
||||
#endif |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -53,8 +53,8 @@ |
||||
#include "xmalloc.h" |
||||
#include "match.h" |
||||
#include "log.h" |
||||
-#include "buffer.h" |
||||
-#include "key.h" |
||||
+#include "sshbuf.h" |
||||
+#include "sshkey.h" |
||||
#include "misc.h" |
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ pamsshagentauth_auth_secure_path(const c |
||||
int comparehome = 0; |
||||
struct stat st; |
||||
|
||||
- pamsshagentauth_verbose("auth_secure_filename: checking for uid: %u", uid); |
||||
+ verbose("auth_secure_filename: checking for uid: %u", uid); |
||||
|
||||
if (realpath(name, buf) == NULL) { |
||||
snprintf(err, errlen, "realpath %s failed: %s", name, |
||||
@@ -115,9 +115,9 @@ pamsshagentauth_auth_secure_path(const c |
||||
snprintf(err, errlen, "dirname() failed"); |
||||
return -1; |
||||
} |
||||
- pamsshagentauth_strlcpy(buf, cp, sizeof(buf)); |
||||
+ strlcpy(buf, cp, sizeof(buf)); |
||||
|
||||
- pamsshagentauth_verbose("secure_filename: checking '%s'", buf); |
||||
+ verbose("secure_filename: checking '%s'", buf); |
||||
if (stat(buf, &st) < 0 || |
||||
(st.st_uid != 0 && st.st_uid != uid) || |
||||
(st.st_mode & 022) != 0) { |
||||
@@ -128,7 +128,7 @@ pamsshagentauth_auth_secure_path(const c |
||||
|
||||
/* If are passed the homedir then we can stop */ |
||||
if (comparehome && strcmp(homedir, buf) == 0) { |
||||
- pamsshagentauth_verbose("secure_filename: terminating check at '%s'", |
||||
+ verbose("secure_filename: terminating check at '%s'", |
||||
buf); |
||||
break; |
||||
} |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -37,10 +37,11 @@ |
||||
#include "xmalloc.h" |
||||
#include "ssh.h" |
||||
#include "ssh2.h" |
||||
-#include "buffer.h" |
||||
+#include "sshbuf.h" |
||||
#include "log.h" |
||||
#include "compat.h" |
||||
-#include "key.h" |
||||
+#include "sshkey.h" |
||||
+#include "ssherr.h" |
||||
#include "pathnames.h" |
||||
#include "misc.h" |
||||
#include "secure_filename.h" |
||||
@@ -48,54 +49,59 @@ |
||||
#include "identity.h" |
||||
#include "pam_user_authorized_keys.h" |
||||
|
||||
+#define SSH2_MSG_USERAUTH_TRUST_REQUEST 54 |
||||
+ |
||||
/* extern u_char *session_id2; |
||||
extern uint8_t session_id_len; |
||||
*/ |
||||
|
||||
int |
||||
-userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2) |
||||
+userauth_pubkey_from_id(const char *ruser, Identity * id, struct sshbuf * session_id2) |
||||
{ |
||||
- Buffer b = { 0 }; |
||||
+ struct sshbuf *b = NULL; |
||||
char *pkalg = NULL; |
||||
u_char *pkblob = NULL, *sig = NULL; |
||||
- u_int blen = 0, slen = 0; |
||||
- int authenticated = 0; |
||||
+ size_t blen = 0, slen = 0; |
||||
+ int r, authenticated = 0; |
||||
|
||||
- pkalg = (char *) key_ssh_name(id->key); |
||||
+ pkalg = (char *) sshkey_ssh_name(id->key); |
||||
|
||||
/* first test if this key is even allowed */ |
||||
if(! pam_user_key_allowed(ruser, id->key)) |
||||
- goto user_auth_clean_exit; |
||||
+ goto user_auth_clean_exit_without_buffer; |
||||
|
||||
- if(pamsshagentauth_key_to_blob(id->key, &pkblob, &blen) == 0) |
||||
- goto user_auth_clean_exit; |
||||
+ if(sshkey_to_blob(id->key, &pkblob, &blen) != 0) |
||||
+ goto user_auth_clean_exit_without_buffer; |
||||
|
||||
/* construct packet to sign and test */ |
||||
- pamsshagentauth_buffer_init(&b); |
||||
+ if ((b = sshbuf_new()) == NULL) |
||||
+ fatal("%s: sshbuf_new failed", __func__); |
||||
|
||||
- pamsshagentauth_buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset); |
||||
- pamsshagentauth_buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST); |
||||
- pamsshagentauth_buffer_put_cstring(&b, ruser); |
||||
- pamsshagentauth_buffer_put_cstring(&b, "pam_ssh_agent_auth"); |
||||
- pamsshagentauth_buffer_put_cstring(&b, "publickey"); |
||||
- pamsshagentauth_buffer_put_char(&b, 1); |
||||
- pamsshagentauth_buffer_put_cstring(&b, pkalg); |
||||
- pamsshagentauth_buffer_put_string(&b, pkblob, blen); |
||||
+ if ((r = sshbuf_put_string(b, sshbuf_ptr(session_id2), sshbuf_len(session_id2))) != 0 || |
||||
+ (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_TRUST_REQUEST)) != 0 || |
||||
+ (r = sshbuf_put_cstring(b, ruser)) != 0 || |
||||
+ (r = sshbuf_put_cstring(b, "pam_ssh_agent_auth")) != 0 || |
||||
+ (r = sshbuf_put_cstring(b, "publickey")) != 0 || |
||||
+ (r = sshbuf_put_u8(b, 1)) != 0 || |
||||
+ (r = sshbuf_put_cstring(b, pkalg)) != 0 || |
||||
+ (r = sshbuf_put_string(b, pkblob, blen)) != 0) |
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
|
||||
- if(ssh_agent_sign(id->ac, id->key, &sig, &slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) != 0) |
||||
+ if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) |
||||
goto user_auth_clean_exit; |
||||
|
||||
/* test for correct signature */ |
||||
- if(pamsshagentauth_key_verify(id->key, sig, slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) == 1) |
||||
+ if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0) |
||||
authenticated = 1; |
||||
|
||||
user_auth_clean_exit: |
||||
/* if(&b != NULL) */ |
||||
- pamsshagentauth_buffer_free(&b); |
||||
+ sshbuf_free(b); |
||||
+ user_auth_clean_exit_without_buffer: |
||||
if(sig != NULL) |
||||
- pamsshagentauth_xfree(sig); |
||||
+ free(sig); |
||||
if(pkblob != NULL) |
||||
- pamsshagentauth_xfree(pkblob); |
||||
+ free(pkblob); |
||||
CRYPTO_cleanup_all_ex_data(); |
||||
return authenticated; |
||||
} |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -31,7 +31,7 @@ |
||||
#ifndef _USERAUTH_PUBKEY_FROM_ID_H |
||||
#define _USERAUTH_PUBKEY_FROM_ID_H |
||||
|
||||
-#include <identity.h> |
||||
-int userauth_pubkey_from_id(const char *, Identity *, Buffer *); |
||||
+#include "identity.h" |
||||
+int userauth_pubkey_from_id(const char *, Identity *, struct sshbuf *); |
||||
|
||||
#endif |
||||
diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c 2020-09-23 10:52:16.424001475 +0200 |
||||
@@ -56,7 +56,7 @@ pamsshagentauth_uudecode(const char *src |
||||
/* and remove trailing whitespace because __b64_pton needs this */ |
||||
*p = '\0'; |
||||
len = pamsshagentauth___b64_pton(encoded, target, targsize); |
||||
- pamsshagentauth_xfree(encoded); |
||||
+ xfree(encoded); |
||||
return len; |
||||
} |
||||
|
||||
@@ -70,7 +70,7 @@ pamsshagentauth_dump_base64(FILE *fp, co |
||||
fprintf(fp, "dump_base64: len > 65536\n"); |
||||
return; |
||||
} |
||||
- buf = pamsshagentauth_xmalloc(2*len); |
||||
+ buf = malloc(2*len); |
||||
n = pamsshagentauth_uuencode(data, len, buf, 2*len); |
||||
for (i = 0; i < n; i++) { |
||||
fprintf(fp, "%c", buf[i]); |
||||
@@ -79,5 +79,5 @@ pamsshagentauth_dump_base64(FILE *fp, co |
||||
} |
||||
if (i % 70 != 69) |
||||
fprintf(fp, "\n"); |
||||
- pamsshagentauth_xfree(buf); |
||||
+ free(buf); |
||||
} |
||||
--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_pam.c.compat 2020-09-23 11:32:30.783695267 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_pam.c 2020-09-23 11:33:21.383389036 +0200 |
||||
@@ -33,7 +33,8 @@ |
||||
#include <string.h> |
||||
|
||||
#include "defines.h" |
||||
-#include "key.h" |
||||
+#include <includes.h> |
||||
+#include "sshkey.h" |
||||
#include "log.h" |
||||
|
||||
#include "pam_user_authorized_keys.h" |
||||
@@ -42,28 +42,28 @@ |
||||
int authenticated = 0; |
||||
const char method[] = "publickey "; |
||||
|
||||
- char* ai = pamsshagentauth_xstrdup(ssh_auth_info); |
||||
+ char* ai = xstrdup(ssh_auth_info); |
||||
char* saveptr; |
||||
|
||||
char* auth_line = strtok_r(ai, "\n", &saveptr); |
||||
while (auth_line != NULL) { |
||||
if (strncmp(auth_line, method, sizeof(method) - 1) == 0) { |
||||
char* key_str = auth_line + sizeof(method) - 1; |
||||
- Key* key = pamsshagentauth_key_new(KEY_UNSPEC); |
||||
+ struct sshkey* key = sshkey_new(KEY_UNSPEC); |
||||
if (key == NULL) { |
||||
continue; |
||||
} |
||||
- int r = pamsshagentauth_key_read(key, &key_str); |
||||
+ int r = sshkey_read(key, &key_str); |
||||
if (r == 1) { |
||||
if (pam_user_key_allowed(ruser, key)) { |
||||
authenticated = 1; |
||||
- pamsshagentauth_key_free(key); |
||||
+ sshkey_free(key); |
||||
break; |
||||
} |
||||
} else { |
||||
- pamsshagentauth_verbose("Failed to create key for %s: %d", auth_line, r); |
||||
+ verbose("Failed to create key for %s: %d", auth_line, r); |
||||
} |
||||
- pamsshagentauth_key_free(key); |
||||
+ sshkey_free(key); |
||||
} |
||||
auth_line = strtok_r(NULL, "\n", &saveptr); |
||||
} |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
diff --git a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c |
||||
--- a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c |
||||
+++ b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c |
||||
@@ -158,11 +158,12 @@ parse_authorized_key_file(const char *user, |
||||
int |
||||
pam_user_key_allowed(const char *ruser, struct sshkey * key) |
||||
{ |
||||
+ struct passwd *pw; |
||||
return |
||||
- pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), |
||||
- key, authorized_keys_file) |
||||
- || pamsshagentauth_user_key_allowed2(getpwuid(0), key, |
||||
- authorized_keys_file) |
||||
+ ( (pw = getpwuid(authorized_keys_file_allowed_owner_uid)) && |
||||
+ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) |
||||
+ || ((pw = getpwuid(0)) && |
||||
+ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) |
||||
|| pamsshagentauth_user_key_command_allowed2(authorized_keys_command, |
||||
authorized_keys_command_user, |
||||
getpwnam(ruser), key); |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c |
||||
--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid 2017-02-07 15:41:53.172334151 +0100 |
||||
+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 15:41:53.174334149 +0100 |
||||
@@ -238,17 +238,26 @@ ssh_get_authentication_socket_for_uid(ui |
||||
} |
||||
|
||||
errno = 0; |
||||
- seteuid(uid); /* To ensure a race condition is not used to circumvent the stat |
||||
- above, we will temporarily drop UID to the caller */ |
||||
- if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { |
||||
+ /* To ensure a race condition is not used to circumvent the stat |
||||
+ above, we will temporarily drop UID to the caller */ |
||||
+ if (seteuid(uid) == -1) { |
||||
close(sock); |
||||
- if(errno == EACCES) |
||||
- fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); |
||||
+ error("seteuid(%lu) failed with error: %s", |
||||
+ (unsigned long) uid, strerror(errno)); |
||||
return -1; |
||||
} |
||||
+ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { |
||||
+ close(sock); |
||||
+ sock = -1; |
||||
+ if(errno == EACCES) |
||||
+ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); |
||||
+ } |
||||
|
||||
- seteuid(0); /* we now continue the regularly scheduled programming */ |
||||
- |
||||
+ /* we now continue the regularly scheduled programming */ |
||||
+ if (0 != seteuid(0)) { |
||||
+ fatal("setuid(0) failed with error: %s", strerror(errno)); |
||||
+ return -1; |
||||
+ } |
||||
return sock; |
||||
} |
||||
|
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
diff -up openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c |
||||
--- openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 2022-07-15 15:08:12.865585410 +0200 |
||||
+++ openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2022-07-15 15:16:25.164282372 +0200 |
||||
@@ -87,8 +87,13 @@ userauth_pubkey_from_id(const char *ruse |
||||
(r = sshbuf_put_string(b, pkblob, blen)) != 0) |
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
|
||||
- if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) |
||||
- goto user_auth_clean_exit; |
||||
+ if (sshkey_type_plain(id->key->type) == KEY_RSA |
||||
+ && ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), "rsa-sha2-256", 0) == 0) { |
||||
+ /* Do nothing */ |
||||
+ } else { |
||||
+ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) |
||||
+ goto user_auth_clean_exit; |
||||
+ } |
||||
|
||||
/* test for correct signature */ |
||||
if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0) |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
diff -up openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c.psaa-visibility openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c |
||||
--- openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c.psaa-visibility 2014-03-31 19:35:17.000000000 +0200 |
||||
+++ openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c 2016-01-22 15:22:40.984469774 +0100 |
||||
@@ -72,7 +72,7 @@ char *__progname; |
||||
extern char *__progname; |
||||
#endif |
||||
|
||||
-PAM_EXTERN int |
||||
+PAM_EXTERN int __attribute__ ((visibility ("default"))) |
||||
pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) |
||||
{ |
||||
char **argv_ptr; |
||||
@@ -214,7 +214,7 @@ cleanexit: |
||||
} |
||||
|
||||
|
||||
-PAM_EXTERN int |
||||
+PAM_EXTERN int __attribute__ ((visibility ("default"))) |
||||
pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) |
||||
{ |
||||
UNUSED(pamh); |
@ -0,0 +1,96 @@
@@ -0,0 +1,96 @@
|
||||
diff -up openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/identity.h |
||||
--- openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent 2016-11-13 04:24:32.000000000 +0100 |
||||
+++ openssh/pam_ssh_agent_auth-0.10.3/identity.h 2017-09-27 14:25:49.421739027 +0200 |
||||
@@ -38,6 +38,12 @@ |
||||
typedef struct identity Identity; |
||||
typedef struct idlist Idlist; |
||||
|
||||
+typedef struct { |
||||
+ int fd; |
||||
+ struct sshbuf *identities; |
||||
+ int howmany; |
||||
+} AuthenticationConnection; |
||||
+ |
||||
struct identity { |
||||
TAILQ_ENTRY(identity) next; |
||||
AuthenticationConnection *ac; /* set if agent supports key */ |
||||
diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c |
||||
--- openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-09-27 14:25:49.421739027 +0200 |
||||
@@ -39,6 +39,7 @@ |
||||
#include "sshbuf.h" |
||||
#include "sshkey.h" |
||||
#include "authfd.h" |
||||
+#include "ssherr.h" |
||||
#include <stdio.h> |
||||
#include <openssl/evp.h> |
||||
#include "ssh2.h" |
||||
@@ -291,36 +292,43 @@ pamsshagentauth_find_authorized_keys(con |
||||
{ |
||||
struct sshbuf *session_id2 = NULL; |
||||
Identity *id; |
||||
- struct sshkey *key; |
||||
AuthenticationConnection *ac; |
||||
- char *comment; |
||||
uint8_t retval = 0; |
||||
uid_t uid = getpwnam(ruser)->pw_uid; |
||||
+ struct ssh_identitylist *idlist; |
||||
+ int r; |
||||
+ unsigned int i; |
||||
|
||||
OpenSSL_add_all_digests(); |
||||
pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); |
||||
|
||||
if ((ac = ssh_get_authentication_connection_for_uid(uid))) { |
||||
verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); |
||||
- for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) |
||||
- { |
||||
- if(key != NULL) { |
||||
+ if ((r = ssh_fetch_identitylist(ac->fd, &idlist)) != 0) { |
||||
+ if (r != SSH_ERR_AGENT_NO_IDENTITIES) |
||||
+ fprintf(stderr, "error fetching identities for " |
||||
+ "protocol %d: %s\n", 2, ssh_err(r)); |
||||
+ } else { |
||||
+ for (i = 0; i < idlist->nkeys; i++) |
||||
+ { |
||||
+ if (idlist->keys[i] != NULL) { |
||||
id = xcalloc(1, sizeof(*id)); |
||||
- id->key = key; |
||||
- id->filename = comment; |
||||
+ id->key = idlist->keys[i]; |
||||
+ id->filename = idlist->comments[i]; |
||||
id->ac = ac; |
||||
if(userauth_pubkey_from_id(ruser, id, session_id2)) { |
||||
retval = 1; |
||||
} |
||||
- free(id->filename); |
||||
- key_free(id->key); |
||||
free(id); |
||||
if(retval == 1) |
||||
break; |
||||
- } |
||||
- } |
||||
+ } |
||||
+ } |
||||
- sshbuf_free(session_id2); |
||||
- ssh_close_authentication_connection(ac); |
||||
+ sshbuf_free(session_id2); |
||||
+ ssh_free_identitylist(idlist); |
||||
+ } |
||||
+ ssh_close_authentication_socket(ac->fd); |
||||
+ free(ac); |
||||
} |
||||
else { |
||||
verbose("No ssh-agent could be contacted"); |
||||
diff -up openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c |
||||
--- openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 |
||||
+++ openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-09-27 14:25:49.422739032 +0200 |
||||
@@ -84,7 +85,7 @@ userauth_pubkey_from_id(const char *ruse |
||||
(r = sshbuf_put_string(b, pkblob, blen)) != 0) |
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
||||
|
||||
- if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) |
||||
+ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) |
||||
goto user_auth_clean_exit; |
||||
|
||||
/* test for correct signature */ |
@ -0,0 +1,198 @@
@@ -0,0 +1,198 @@
|
||||
diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c |
||||
--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build 2016-11-13 04:24:32.000000000 +0100 |
||||
+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 14:29:41.626116675 +0100 |
||||
@@ -43,12 +43,31 @@ |
||||
#include <openssl/evp.h> |
||||
#include "ssh2.h" |
||||
#include "misc.h" |
||||
+#include "ssh.h" |
||||
+#include <sys/types.h> |
||||
+#include <sys/stat.h> |
||||
+#include <sys/socket.h> |
||||
+#include <sys/un.h> |
||||
+#include <unistd.h> |
||||
+#include <stdlib.h> |
||||
+#include <errno.h> |
||||
+#include <fcntl.h> |
||||
|
||||
#include "userauth_pubkey_from_id.h" |
||||
#include "identity.h" |
||||
#include "get_command_line.h" |
||||
extern char **environ; |
||||
|
||||
+/* |
||||
+ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user |
||||
+ * A cursory check is done, but to avoid race conditions, it is necessary |
||||
+ * to drop effective UID when connecting to the socket. |
||||
+ * |
||||
+ * If the cause of error is EACCES, because we verified we would not have that |
||||
+ * problem initially, we can safely assume that somebody is attempting to find a |
||||
+ * race condition; so a more "direct" log message is generated. |
||||
+ */ |
||||
+ |
||||
static char * |
||||
log_action(char ** action, size_t count) |
||||
{ |
||||
@@ -85,7 +104,7 @@ void |
||||
pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, |
||||
const char * ruser, const char * servicename) |
||||
{ |
||||
- char *cookie = NULL; |
||||
+ u_char *cookie = NULL; |
||||
uint8_t i = 0; |
||||
uint32_t rnd = 0; |
||||
uint8_t cookie_len; |
||||
@@ -112,7 +131,7 @@ pamsshagentauth_session_id2_gen(Buffer * |
||||
if (i % 4 == 0) { |
||||
rnd = pamsshagentauth_arc4random(); |
||||
} |
||||
- cookie[i] = (char) rnd; |
||||
+ cookie[i] = (u_char) rnd; |
||||
rnd >>= 8; |
||||
} |
||||
|
||||
@@ -177,6 +196,86 @@ pamsshagentauth_session_id2_gen(Buffer * |
||||
} |
||||
|
||||
int |
||||
+ssh_get_authentication_socket_for_uid(uid_t uid) |
||||
+{ |
||||
+ const char *authsocket; |
||||
+ int sock; |
||||
+ struct sockaddr_un sunaddr; |
||||
+ struct stat sock_st; |
||||
+ |
||||
+ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); |
||||
+ if (!authsocket) |
||||
+ return -1; |
||||
+ |
||||
+ /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ |
||||
+ if( stat(authsocket,&sock_st) == 0) { |
||||
+ if(uid != 0 && sock_st.st_uid != uid) { |
||||
+ fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); |
||||
+ return -1; |
||||
+ } |
||||
+ } |
||||
+ |
||||
+ /* |
||||
+ * Ensures that the EACCES tested for below can _only_ happen if somebody |
||||
+ * is attempting to race the stat above to bypass authentication. |
||||
+ */ |
||||
+ if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { |
||||
+ error("ssh-agent socket has incorrect permissions for owner"); |
||||
+ return -1; |
||||
+ } |
||||
+ |
||||
+ sunaddr.sun_family = AF_UNIX; |
||||
+ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); |
||||
+ |
||||
+ sock = socket(AF_UNIX, SOCK_STREAM, 0); |
||||
+ if (sock < 0) |
||||
+ return -1; |
||||
+ |
||||
+ /* close on exec */ |
||||
+ if (fcntl(sock, F_SETFD, 1) == -1) { |
||||
+ close(sock); |
||||
+ return -1; |
||||
+ } |
||||
+ |
||||
+ errno = 0; |
||||
+ seteuid(uid); /* To ensure a race condition is not used to circumvent the stat |
||||
+ above, we will temporarily drop UID to the caller */ |
||||
+ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { |
||||
+ close(sock); |
||||
+ if(errno == EACCES) |
||||
+ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); |
||||
+ return -1; |
||||
+ } |
||||
+ |
||||
+ seteuid(0); /* we now continue the regularly scheduled programming */ |
||||
+ |
||||
+ return sock; |
||||
+} |
||||
+ |
||||
+AuthenticationConnection * |
||||
+ssh_get_authentication_connection_for_uid(uid_t uid) |
||||
+{ |
||||
+ AuthenticationConnection *auth; |
||||
+ int sock; |
||||
+ |
||||
+ sock = ssh_get_authentication_socket_for_uid(uid); |
||||
+ |
||||
+ /* |
||||
+ * Fail if we couldn't obtain a connection. This happens if we |
||||
+ * exited due to a timeout. |
||||
+ */ |
||||
+ if (sock < 0) |
||||
+ return NULL; |
||||
+ |
||||
+ auth = xmalloc(sizeof(*auth)); |
||||
+ auth->fd = sock; |
||||
+ buffer_init(&auth->identities); |
||||
+ auth->howmany = 0; |
||||
+ |
||||
+ return auth; |
||||
+} |
||||
+ |
||||
+int |
||||
pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) |
||||
{ |
||||
Buffer session_id2 = { 0 }; |
||||
@@ -190,7 +289,7 @@ pamsshagentauth_find_authorized_keys(con |
||||
OpenSSL_add_all_digests(); |
||||
pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); |
||||
|
||||
- if ((ac = ssh_get_authentication_connection(uid))) { |
||||
+ if ((ac = ssh_get_authentication_connection_for_uid(uid))) { |
||||
pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); |
||||
for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) |
||||
{ |
||||
diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in |
||||
--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build 2016-11-13 04:24:32.000000000 +0100 |
||||
+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in 2017-02-07 14:40:14.407566921 +0100 |
||||
@@ -52,7 +52,7 @@ PATHS= |
||||
CC=@CC@ |
||||
LD=@LD@ |
||||
CFLAGS=@CFLAGS@ |
||||
-CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ |
||||
+CPPFLAGS=-I.. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ |
||||
LIBS=@LIBS@ |
||||
AR=@AR@ |
||||
AWK=@AWK@ |
||||
@@ -61,8 +61,8 @@ INSTALL=@INSTALL@ |
||||
PERL=@PERL@ |
||||
SED=@SED@ |
||||
ENT=@ENT@ |
||||
-LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ |
||||
-LDFLAGS_SHARED = @LDFLAGS_SHARED@ |
||||
+LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ |
||||
+LDFLAGS_SHARED =-Wl,-z,defs @LDFLAGS_SHARED@ |
||||
EXEEXT=@EXEEXT@ |
||||
|
||||
INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ |
||||
@@ -74,7 +74,7 @@ SSHOBJS=xmalloc.o atomicio.o authfd.o bu |
||||
|
||||
ED25519OBJS=ed25519-donna/ed25519.o |
||||
|
||||
-PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o userauth_pubkey_from_pam.o |
||||
+PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o userauth_pubkey_from_pam.o secure_filename.o |
||||
|
||||
|
||||
MANPAGES_IN = pam_ssh_agent_auth.pod |
||||
@@ -94,13 +94,13 @@ $(PAM_MODULES): Makefile.in config.h |
||||
.c.o: |
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ |
||||
|
||||
-LIBCOMPAT=openbsd-compat/libopenbsd-compat.a |
||||
+LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a |
||||
$(LIBCOMPAT): always |
||||
(cd openbsd-compat && $(MAKE)) |
||||
always: |
||||
|
||||
-pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o |
||||
- $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat pam_ssh_agent_auth.o $(LIBS) -lpam |
||||
+pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o ../uidswap.o ../ssh-sk-client.o |
||||
+ $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) ../ssh-sk-client.o $(LDFLAGS) -lssh -lopenbsd-compat pam_ssh_agent_auth.o ../uidswap.o $(LIBS) -lpam |
||||
|
||||
$(MANPAGES): $(MANPAGES_IN) |
||||
pod2man --section=8 --release=v0.10.3 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 |
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
# 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) |
||||
|
||||
[Service] |
||||
Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket |
||||
ExecStart=/usr/bin/ssh-agent -a $SSH_AUTH_SOCK |
||||
PassEnvironment=SSH_AGENT_PID |
||||
SuccessExitStatus=2 |
||||
Type=forking |
@ -0,0 +1,8 @@
@@ -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,40 @@
@@ -0,0 +1,40 @@
|
||||
#!/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") ;; # always ok |
||||
"ecdsa") ;; |
||||
*) # 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 -f $KEY -C '' -N '' >&/dev/null; then |
||||
exit 1 |
||||
fi |
||||
|
||||
# sanitize permissions |
||||
/usr/bin/chgrp ssh_keys $KEY |
||||
/usr/bin/chmod 640 $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 @@
@@ -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 @@
@@ -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 @@
@@ -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,17 @@
@@ -0,0 +1,17 @@
|
||||
[Unit] |
||||
Description=OpenSSH server daemon |
||||
Documentation=man:sshd(8) man:sshd_config(5) |
||||
After=network.target sshd-keygen.target |
||||
Wants=sshd-keygen.target |
||||
|
||||
[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 @@
@@ -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,7 @@
@@ -0,0 +1,7 @@
|
||||
# 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. |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
[Unit] |
||||
Description=OpenSSH per-connection server daemon |
||||
Documentation=man:sshd(8) man:sshd_config(5) |
||||
Wants=sshd-keygen.target |
||||
After=sshd-keygen.target |
||||
|
||||
[Service] |
||||
EnvironmentFile=-/etc/sysconfig/sshd |
||||
ExecStart=-/usr/sbin/sshd -i $OPTIONS |
||||
StandardInput=socket |
Loading…
Reference in new issue