Improve kerberos credential cache handling (#1566494)
This commit is contained in:
parent
4ef6823ff4
commit
1176788778
@ -1,247 +0,0 @@
|
||||
diff -up openssh-6.3p1/auth-krb5.c.ccache_name openssh-6.3p1/auth-krb5.c
|
||||
--- openssh-6.3p1/auth-krb5.c.ccache_name 2013-10-23 22:03:52.322950759 +0200
|
||||
+++ openssh-6.3p1/auth-krb5.c 2013-10-23 22:04:24.295799873 +0200
|
||||
@@ -50,7 +50,9 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
+#include <sys/stat.h>
|
||||
#include <krb5.h>
|
||||
+#include <profile.h>
|
||||
|
||||
extern ServerOptions options;
|
||||
|
||||
@@ -91,6 +93,7 @@ auth_krb5_password(Authctxt *authctxt, c
|
||||
#endif
|
||||
krb5_error_code problem;
|
||||
krb5_ccache ccache = NULL;
|
||||
+ const char *ccache_type;
|
||||
int len;
|
||||
char *client, *platform_client;
|
||||
const char *errmsg;
|
||||
@@ -191,12 +194,30 @@ auth_krb5_password(Authctxt *authctxt, c
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
+ ccache_type = krb5_cc_get_type(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
|
||||
authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
|
||||
|
||||
- len = strlen(authctxt->krb5_ticket_file) + 6;
|
||||
+ if (authctxt->krb5_ticket_file[0] == ':')
|
||||
+ authctxt->krb5_ticket_file++;
|
||||
+
|
||||
+ len = strlen(authctxt->krb5_ticket_file) + strlen(ccache_type) + 2;
|
||||
authctxt->krb5_ccname = xmalloc(len);
|
||||
- snprintf(authctxt->krb5_ccname, len, "FILE:%s",
|
||||
+
|
||||
+#ifdef USE_CCAPI
|
||||
+ snprintf(authctxt->krb5_ccname, len, "API:%s",
|
||||
authctxt->krb5_ticket_file);
|
||||
+#else
|
||||
+ snprintf(authctxt->krb5_ccname, len, "%s:%s",
|
||||
+ ccache_type, authctxt->krb5_ticket_file);
|
||||
+#endif
|
||||
+
|
||||
+ if (strcmp(ccache_type, "DIR") == 0) {
|
||||
+ char *p;
|
||||
+ p = strrchr(authctxt->krb5_ccname, '/');
|
||||
+ if (p)
|
||||
+ *p = '\0';
|
||||
+ }
|
||||
+
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (options.use_pam)
|
||||
@@ -235,10 +256,34 @@ 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);
|
||||
authctxt->krb5_fwd_ccache = NULL;
|
||||
+
|
||||
+ 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)
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
if (authctxt->krb5_user) {
|
||||
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
|
||||
@@ -250,34 +295,139 @@ krb5_cleanup_proc(Authctxt *authctxt)
|
||||
}
|
||||
}
|
||||
|
||||
+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;
|
||||
+
|
||||
+ 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("%s: unsupported token %s in %s", __func__, 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;
|
||||
+
|
||||
+ ret = krb5_get_profile(ctx, &p);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = profile_get_string(p, "libdefaults", "default_ccache_name", NULL, NULL, &value);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = ssh_krb5_expand_template(ccname, value);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
#ifndef HEIMDAL
|
||||
krb5_error_code
|
||||
ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
|
||||
int tmpfd, ret, oerrno;
|
||||
- char ccname[40];
|
||||
+ char *ccname;
|
||||
+#ifdef USE_CCAPI
|
||||
+ char cctemplate[] = "API:krb5cc_%d";
|
||||
+#else
|
||||
mode_t old_umask;
|
||||
+ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
|
||||
|
||||
- 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;
|
||||
- }
|
||||
+#endif
|
||||
+
|
||||
+ ret = ssh_krb5_get_cctemplate(ctx, &ccname);
|
||||
|
||||
- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
|
||||
+ if (ret) {
|
||||
+ ret = asprintf(&ccname, cctemplate, geteuid());
|
||||
+ if (ret == -1)
|
||||
+ return ENOMEM;
|
||||
+ 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;
|
||||
+ }
|
||||
close(tmpfd);
|
||||
- return oerrno;
|
||||
}
|
||||
- close(tmpfd);
|
||||
+ debug("%s: Setting ccname to %s", __func__, ccname);
|
||||
|
||||
return (krb5_cc_resolve(ctx, ccname, ccache));
|
||||
}
|
@ -82,8 +82,8 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c
|
||||
M_CP_INTOPT(rekey_interval);
|
||||
M_CP_INTOPT(log_level);
|
||||
@@ -2320,6 +2330,7 @@ dump_config(ServerOptions *o)
|
||||
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
|
||||
# endif
|
||||
dump_cfg_fmtint(sKerberosUniqueTicket, o->kerberos_unique_ticket);
|
||||
dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
|
||||
+ dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users);
|
||||
#endif
|
||||
@ -93,8 +93,8 @@ 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_get_afs_token; /* If true, try to get AFS token if
|
||||
* authenticated with Kerberos. */
|
||||
int kerberos_unique_ticket; /* If true, the aquired ticket will
|
||||
* be stored in per-session ccache */
|
||||
int use_kuserok;
|
||||
+ int enable_k5users;
|
||||
int gss_authentication; /* If true, permit GSSAPI authentication */
|
||||
|
@ -192,26 +192,26 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
if (options->kbd_interactive_authentication == -1)
|
||||
@@ -399,7 +402,8 @@ typedef enum {
|
||||
@@ -399,7 +402,7 @@ typedef enum {
|
||||
sPermitRootLogin, sLogFacility, sLogLevel,
|
||||
sRhostsRSAAuthentication, sRSAAuthentication,
|
||||
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
|
||||
- sKerberosGetAFSToken, sChallengeResponseAuthentication,
|
||||
+ sKerberosGetAFSToken, sKerberosUseKuserok,
|
||||
+ sChallengeResponseAuthentication,
|
||||
- sKerberosGetAFSToken, sKerberosUniqueTicket,
|
||||
+ sKerberosGetAFSToken, sKerberosUniqueTicket, sKerberosUseKuserok,
|
||||
sChallengeResponseAuthentication,
|
||||
sPasswordAuthentication, sKbdInteractiveAuthentication,
|
||||
sListenAddress, sAddressFamily,
|
||||
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
|
||||
@@ -478,11 +481,13 @@ static struct {
|
||||
#else
|
||||
@@ -478,12 +481,14 @@ static struct {
|
||||
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
|
||||
#endif
|
||||
{ "kerberosuniqueticket", sKerberosUniqueTicket, SSHCFG_GLOBAL },
|
||||
+ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL },
|
||||
#else
|
||||
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
|
||||
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
|
||||
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
|
||||
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
|
||||
{ "kerberosuniqueticket", sUnsupported, SSHCFG_GLOBAL },
|
||||
+ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL },
|
||||
#endif
|
||||
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
|
||||
@ -236,9 +236,9 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c
|
||||
M_CP_INTOPT(rekey_interval);
|
||||
M_CP_INTOPT(log_level);
|
||||
@@ -2309,6 +2319,7 @@ dump_config(ServerOptions *o)
|
||||
# ifdef USE_AFS
|
||||
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
|
||||
# endif
|
||||
dump_cfg_fmtint(sKerberosUniqueTicket, o->kerberos_unique_ticket);
|
||||
+ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok);
|
||||
#endif
|
||||
#ifdef GSSAPI
|
||||
@ -247,9 +247,9 @@ 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 {
|
||||
* file on logout. */
|
||||
int kerberos_get_afs_token; /* If true, try to get AFS token if
|
||||
* authenticated with Kerberos. */
|
||||
int kerberos_unique_ticket; /* If true, the aquired 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 */
|
||||
@ -258,9 +258,9 @@ 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
|
||||
file on logout.
|
||||
tickets aquired in different sessions of the same user.
|
||||
The default is
|
||||
.Cm yes .
|
||||
.Cm no .
|
||||
+.It Cm KerberosUseKuserok
|
||||
+Specifies whether to look at .k5login file for user's aliases.
|
||||
+The default is
|
||||
|
@ -401,8 +401,8 @@ diff -up openssh-7.0p1/ssh-gss.h.gsskexalg openssh-7.0p1/ssh-gss.h
|
||||
+ KEX_GSS_GRP14_SHA1_ID
|
||||
+
|
||||
typedef struct {
|
||||
char *filename;
|
||||
char *envvar;
|
||||
char *envval;
|
||||
@@ -147,9 +151,9 @@ int ssh_gssapi_credentials_updated(Gssct
|
||||
/* In the server */
|
||||
typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
|
||||
|
@ -540,7 +540,7 @@ diff -up openssh/gss-serv.c.gsskex openssh/gss-serv.c
|
||||
- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
|
||||
- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
|
||||
+ { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
|
||||
+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0};
|
||||
+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL}, 0, 0};
|
||||
|
||||
ssh_gssapi_mech gssapi_null_mech =
|
||||
- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
|
||||
@ -710,7 +710,7 @@ diff -up openssh/gss-serv.c.gsskex openssh/gss-serv.c
|
||||
/* Destroy delegated credentials if userok fails */
|
||||
gss_release_buffer(&lmin, &gssapi_client.displayname);
|
||||
gss_release_buffer(&lmin, &gssapi_client.exportedname);
|
||||
@@ -383,14 +469,90 @@ ssh_gssapi_userok(char *user)
|
||||
@@ -383,14 +469,89 @@ ssh_gssapi_userok(char *user)
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -748,8 +748,7 @@ diff -up openssh/gss-serv.c.gsskex openssh/gss-serv.c
|
||||
+ char *envstr;
|
||||
+#endif
|
||||
+
|
||||
+ if (gssapi_client.store.filename == NULL &&
|
||||
+ gssapi_client.store.envval == NULL &&
|
||||
+ if (gssapi_client.store.envval == NULL &&
|
||||
+ gssapi_client.store.envvar == NULL)
|
||||
+ return;
|
||||
+
|
||||
@ -819,7 +818,7 @@ diff -up openssh/gss-serv-krb5.c.gsskex openssh/gss-serv-krb5.c
|
||||
const char *errmsg;
|
||||
|
||||
if (client->creds == NULL) {
|
||||
@@ -181,11 +181,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
|
||||
@@ -181,11 +181,23 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl
|
||||
return;
|
||||
}
|
||||
|
||||
@ -833,7 +832,6 @@ diff -up openssh/gss-serv-krb5.c.gsskex openssh/gss-serv-krb5.c
|
||||
- snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
|
||||
+#ifdef USE_CCAPI
|
||||
+ xasprintf(&client->store.envval, "API:%s", new_ccname);
|
||||
+ client->store.filename = NULL;
|
||||
+#else
|
||||
+ if (new_ccname[0] == ':')
|
||||
+ new_ccname++;
|
||||
@ -844,8 +842,6 @@ diff -up openssh/gss-serv-krb5.c.gsskex openssh/gss-serv-krb5.c
|
||||
+ if (p)
|
||||
+ *p = '\0';
|
||||
+ }
|
||||
+ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0))
|
||||
+ client->store.filename = xstrdup(new_ccname);
|
||||
+#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
@ -1794,7 +1790,7 @@ diff -up openssh/monitor.c.gsskex openssh/monitor.c
|
||||
|
||||
buffer_clear(m);
|
||||
buffer_put_int(m, authenticated);
|
||||
@@ -1854,5 +1880,73 @@ mm_answer_gss_userok(int sock, Buffer *m
|
||||
@@ -1854,5 +1880,71 @@ mm_answer_gss_userok(int sock, Buffer *m
|
||||
/* Monitor loop will terminate if authenticated */
|
||||
return (authenticated);
|
||||
}
|
||||
@ -1848,13 +1844,11 @@ diff -up openssh/monitor.c.gsskex openssh/monitor.c
|
||||
+ ssh_gssapi_ccache store;
|
||||
+ int ok;
|
||||
+
|
||||
+ store.filename = buffer_get_string(m, NULL);
|
||||
+ store.envvar = buffer_get_string(m, NULL);
|
||||
+ store.envval = buffer_get_string(m, NULL);
|
||||
+
|
||||
+ ok = ssh_gssapi_update_creds(&store);
|
||||
+
|
||||
+ free(store.filename);
|
||||
+ free(store.envvar);
|
||||
+ free(store.envval);
|
||||
+
|
||||
@ -1892,7 +1886,7 @@ diff -up openssh/monitor_wrap.c.gsskex openssh/monitor_wrap.c
|
||||
{
|
||||
Buffer m;
|
||||
int authenticated = 0;
|
||||
@@ -967,5 +967,50 @@ mm_ssh_gssapi_userok(char *user)
|
||||
@@ -967,5 +967,49 @@ mm_ssh_gssapi_userok(char *user)
|
||||
debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
|
||||
return (authenticated);
|
||||
}
|
||||
@ -1927,7 +1921,6 @@ diff -up openssh/monitor_wrap.c.gsskex openssh/monitor_wrap.c
|
||||
+
|
||||
+ buffer_init(&m);
|
||||
+
|
||||
+ buffer_put_cstring(&m, store->filename ? store->filename : "");
|
||||
+ buffer_put_cstring(&m, store->envvar ? store->envvar : "");
|
||||
+ buffer_put_cstring(&m, store->envval ? store->envval : "");
|
||||
+
|
||||
|
@ -32,7 +32,7 @@ index f9d191c..c432d2f 100644
|
||||
@@ -222,5 +222,7 @@ int sys_auth_passwd(Authctxt *, const char *);
|
||||
#if defined(KRB5) && !defined(HEIMDAL)
|
||||
#include <krb5.h>
|
||||
krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
|
||||
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
|
||||
|
@ -1,259 +0,0 @@
|
||||
diff --git a/auth-krb5.c b/auth-krb5.c
|
||||
index 09ed151..282fcca 100644
|
||||
--- a/auth-krb5.c
|
||||
+++ b/auth-krb5.c
|
||||
@@ -182,7 +182,8 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache);
|
||||
+ problem = ssh_krb5_cc_gen(authctxt->krb5_ctx,
|
||||
+ &authctxt->krb5_fwd_ccache, &authctxt->krb5_set_env);
|
||||
if (problem)
|
||||
goto out;
|
||||
|
||||
@@ -192,7 +192,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
||||
|
||||
|
||||
#ifdef USE_PAM
|
||||
- if (options.use_pam)
|
||||
+ if (options.use_pam && authctxt->krb5_set_env)
|
||||
do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
|
||||
#endif
|
||||
|
||||
@@ -412,7 +413,7 @@ ssh_krb5_get_cctemplate(krb5_context ctx, char **ccname) {
|
||||
|
||||
#ifndef HEIMDAL
|
||||
krb5_error_code
|
||||
-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
|
||||
+ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache, int *need_environment) {
|
||||
int tmpfd, ret, oerrno;
|
||||
char *ccname;
|
||||
#ifdef USE_CCAPI
|
||||
@@ -423,8 +424,10 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
|
||||
|
||||
#endif
|
||||
|
||||
+ if (need_environment)
|
||||
+ *need_environment = 0;
|
||||
ret = ssh_krb5_get_cctemplate(ctx, &ccname);
|
||||
-
|
||||
+ /* fallback to the ccache in /tmp */
|
||||
if (ret) {
|
||||
ret = asprintf(&ccname, cctemplate, geteuid());
|
||||
if (ret == -1)
|
||||
@@ -444,6 +447,9 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
|
||||
close(tmpfd);
|
||||
return oerrno;
|
||||
}
|
||||
+ /* make sure the KRBCCNAME is set for non-standard location */
|
||||
+ if (need_environment)
|
||||
+ *need_environment = 1;
|
||||
close(tmpfd);
|
||||
}
|
||||
debug("%s: Setting ccname to %s", __func__, ccname);
|
||||
diff --git a/auth.h b/auth.h
|
||||
index 954a0dd..0819483 100644
|
||||
--- a/auth.h
|
||||
+++ b/auth.h
|
||||
@@ -78,6 +78,7 @@ struct Authctxt {
|
||||
krb5_principal krb5_user;
|
||||
char *krb5_ticket_file;
|
||||
char *krb5_ccname;
|
||||
+ int krb5_set_env;
|
||||
#endif
|
||||
struct sshbuf *loginmsg;
|
||||
|
||||
@@ -220,7 +221,7 @@ int sys_auth_passwd(Authctxt *, const char *);
|
||||
|
||||
#if defined(KRB5) && !defined(HEIMDAL)
|
||||
#include <krb5.h>
|
||||
-krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
|
||||
+krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *, int *);
|
||||
krb5_error_code ssh_krb5_get_k5login_directory(krb5_context ctx,
|
||||
char **k5login_directory);
|
||||
#endif
|
||||
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
|
||||
index 0fa3838..4127245 100644
|
||||
--- a/gss-serv-krb5.c
|
||||
+++ b/gss-serv-krb5.c
|
||||
@@ -382,7 +382,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name,
|
||||
/* 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;
|
||||
@@ -391,14 +391,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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
|
||||
@@ -412,14 +413,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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_gen(krb_context, &ccache, &set_env))) {
|
||||
errmsg = krb5_get_error_message(krb_context, problem);
|
||||
logit("ssh_krb5_cc_gen(): %.100s", errmsg);
|
||||
krb5_free_error_message(krb_context, errmsg);
|
||||
- return;
|
||||
+ return 0;
|
||||
}
|
||||
#endif /* #ifdef HEIMDAL */
|
||||
|
||||
@@ -428,7 +429,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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))) {
|
||||
@@ -437,7 +438,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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);
|
||||
@@ -446,7 +447,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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);
|
||||
@@ -471,7 +478,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAM
|
||||
- if (options.use_pam)
|
||||
+ if (options.use_pam && set_env)
|
||||
do_pam_putenv(client->store.envvar, client->store.envval);
|
||||
#endif
|
||||
|
||||
@@ -479,7 +486,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
|
||||
client->store.data = krb_context;
|
||||
|
||||
- return;
|
||||
+ return set_env;
|
||||
}
|
||||
|
||||
int
|
||||
diff --git a/gss-serv.c b/gss-serv.c
|
||||
index 681847a..2a02dae 100644
|
||||
--- a/gss-serv.c
|
||||
+++ b/gss-serv.c
|
||||
@@ -404,7 +404,7 @@ ssh_gssapi_cleanup_creds(void)
|
||||
debug("%s: krb5_cc_resolve(): %.100s", __func__,
|
||||
krb5_get_err_text(gssapi_client.store.data, problem));
|
||||
} else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) {
|
||||
- debug("%s: krb5_cc_resolve(): %.100s", __func__,
|
||||
+ debug("%s: krb5_cc_destroy(): %.100s", __func__,
|
||||
krb5_get_err_text(gssapi_client.store.data, problem));
|
||||
} else {
|
||||
krb5_free_context(gssapi_client.store.data);
|
||||
@@ -414,13 +414,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 childs environment based
|
||||
diff --git a/session.c b/session.c
|
||||
index df4985a..b7a6a57 100644
|
||||
--- a/session.c
|
||||
+++ b/session.c
|
||||
@@ -1084,7 +1084,8 @@ do_setup_env(Session *s, const char *shell)
|
||||
/* Allow any GSSAPI methods that we've used to alter
|
||||
* the childs 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. */
|
||||
@@ -1196,7 +1197,7 @@ do_setup_env(Session *s, const char *shell)
|
||||
}
|
||||
#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 --git a/ssh-gss.h b/ssh-gss.h
|
||||
index 6f2b0ac..73ef2c2 100644
|
||||
--- a/ssh-gss.h
|
||||
+++ b/ssh-gss.h
|
||||
@@ -106,7 +106,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;
|
||||
|
||||
@@ -163,7 +163,7 @@ char* ssh_gssapi_get_displayname(void);
|
||||
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);
|
||||
diff --git a/sshd.c b/sshd.c
|
||||
index ce2e374..3c4e13e 100644
|
||||
--- a/sshd.c
|
||||
+++ b/sshd.c
|
||||
@@ -2221,7 +2221,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
|
||||
|
651
openssh-7.7p1-gssapi-new-unique.patch
Normal file
651
openssh-7.7p1-gssapi-new-unique.patch
Normal file
@ -0,0 +1,651 @@
|
||||
diff --git a/auth-krb5.c b/auth-krb5.c
|
||||
index a5a81ed2..63f877f2 100644
|
||||
--- a/auth-krb5.c
|
||||
+++ b/auth-krb5.c
|
||||
@@ -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, const char *password)
|
||||
#endif
|
||||
krb5_error_code problem;
|
||||
krb5_ccache ccache = NULL;
|
||||
- int len;
|
||||
+ char *ticket_name = NULL;
|
||||
char *client, *platform_client;
|
||||
const char *errmsg;
|
||||
|
||||
@@ -163,7 +164,8 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
||||
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;
|
||||
|
||||
@@ -172,21 +174,20 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
||||
if (problem)
|
||||
goto out;
|
||||
|
||||
- problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
|
||||
+ problem = krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
|
||||
&creds);
|
||||
if (problem)
|
||||
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
|
||||
|
||||
@@ -222,10 +223,59 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
|
||||
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;
|
||||
+
|
||||
+ /* Avoid race conditions with other processes touching the same collection */
|
||||
+ //krb5_cccol_lock(ctx);
|
||||
+
|
||||
+ krb5_cc_destroy(ctx, authctxt->krb5_fwd_ccache);
|
||||
authctxt->krb5_fwd_ccache = NULL;
|
||||
+
|
||||
+ ret = krb5_cccol_cursor_new(ctx, &cursor);
|
||||
+ if (ret)
|
||||
+ goto unlock;
|
||||
+
|
||||
+ 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 {
|
||||
+ /* 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));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+unlock:
|
||||
+ krb5_cccol_cursor_free(ctx, &cursor);
|
||||
+
|
||||
+ /* Release lock */
|
||||
+ //krb5_cccol_unlock(ctx);
|
||||
}
|
||||
if (authctxt->krb5_user) {
|
||||
krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
|
||||
@@ -237,36 +287,186 @@ krb5_cleanup_proc(Authctxt *authctxt)
|
||||
}
|
||||
}
|
||||
|
||||
-#ifndef HEIMDAL
|
||||
-krb5_error_code
|
||||
-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
|
||||
- int tmpfd, ret, oerrno;
|
||||
- char ccname[40];
|
||||
- mode_t old_umask;
|
||||
|
||||
- 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;
|
||||
+#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("%s: called, template = %s", __func__, 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("%s: unsupported token %s in %s", __func__, p_n, template);
|
||||
+ /* unknown token, fallback to the default */
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
|
||||
+ 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("%s: called", __func__);
|
||||
+ 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("%s: returning with ccname = %s", __func__, *ccname);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+krb5_error_code
|
||||
+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;
|
||||
+
|
||||
+ debug3("%s: called", __func__);
|
||||
+ if (need_environment)
|
||||
+ *need_environment = 0;
|
||||
+ ret = ssh_krb5_get_cctemplate(ctx, &ccname);
|
||||
+ if (ret || !ccname || options.kerberos_unique_ticket) {
|
||||
+ /* 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;
|
||||
+
|
||||
+ 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("%s: setting default ccname to %s", __func__, 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("%s: calling cc_new_unique(%s)", __func__, ccname);
|
||||
+ ret = krb5_cc_new_unique(ctx, type, NULL, ccache);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ debug3("%s: calling cc_switch()", __func__);
|
||||
+ 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
|
||||
+ */
|
||||
+ debug3("%s: calling cc_resolve(%s)", __func__, ccname);
|
||||
+ return (krb5_cc_resolve(ctx, ccname, ccache));
|
||||
+ }
|
||||
}
|
||||
#endif /* !HEIMDAL */
|
||||
#endif /* KRB5 */
|
||||
diff --git a/auth.h b/auth.h
|
||||
index 29491df9..fdab5040 100644
|
||||
--- a/auth.h
|
||||
+++ b/auth.h
|
||||
@@ -82,6 +82,7 @@ struct Authctxt {
|
||||
krb5_principal krb5_user;
|
||||
char *krb5_ticket_file;
|
||||
char *krb5_ccname;
|
||||
+ int krb5_set_env;
|
||||
#endif
|
||||
struct sshbuf *loginmsg;
|
||||
|
||||
@@ -243,6 +244,6 @@ int sys_auth_passwd(struct ssh *, const char *);
|
||||
|
||||
#if defined(KRB5) && !defined(HEIMDAL)
|
||||
#include <krb5.h>
|
||||
-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
|
||||
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
|
||||
index 795992d9..0623a107 100644
|
||||
--- a/gss-serv-krb5.c
|
||||
+++ b/gss-serv-krb5.c
|
||||
@@ -114,7 +114,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
|
||||
/* 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;
|
||||
@@ -121,16 +121,17 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
krb5_error_code problem;
|
||||
krb5_principal princ;
|
||||
OM_uint32 maj_status, min_status;
|
||||
- const char *new_ccname, *new_cctype;
|
||||
+ int len;
|
||||
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
|
||||
@@ -144,14 +145,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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 */
|
||||
|
||||
@@ -160,7 +161,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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))) {
|
||||
@@ -169,7 +170,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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);
|
||||
@@ -178,37 +179,27 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
|
||||
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);
|
||||
-#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';
|
||||
- }
|
||||
-#endif
|
||||
+ if (set_env) {
|
||||
+ const char *filename = krb5_cc_get_name(krb_context, ccache);
|
||||
+ client->store.envvar = "KRB5CCNAME";
|
||||
+ len = strlen(filename) + 6;
|
||||
+ client->store.envval = xmalloc(len);
|
||||
+ snprintf(client->store.envval, len, "FILE:%s", filename);
|
||||
+ }
|
||||
|
||||
#ifdef USE_PAM
|
||||
- if (options.use_pam)
|
||||
+ if (options.use_pam && set_env)
|
||||
do_pam_putenv(client->store.envvar, client->store.envval);
|
||||
#endif
|
||||
|
||||
krb5_cc_close(krb_context, ccache);
|
||||
|
||||
client->store.data = krb_context;
|
||||
|
||||
- return;
|
||||
+ return set_env;
|
||||
}
|
||||
|
||||
int
|
||||
diff --git a/gss-serv.c b/gss-serv.c
|
||||
index 6cae720e..16e55cbc 100644
|
||||
--- a/gss-serv.c
|
||||
+++ b/gss-serv.c
|
||||
@@ -320,13 +320,15 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
|
||||
}
|
||||
|
||||
/* 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 childs environment based
|
||||
diff --git a/servconf.c b/servconf.c
|
||||
index cb578658..a6e01df2 100644
|
||||
--- a/servconf.c
|
||||
+++ b/servconf.c
|
||||
@@ -122,6 +122,7 @@ initialize_server_options(ServerOptions *options)
|
||||
options->kerberos_or_local_passwd = -1;
|
||||
options->kerberos_ticket_cleanup = -1;
|
||||
options->kerberos_get_afs_token = -1;
|
||||
+ options->kerberos_unique_ticket = -1;
|
||||
options->gss_authentication=-1;
|
||||
options->gss_keyex = -1;
|
||||
options->gss_cleanup_creds = -1;
|
||||
@@ -315,6 +316,8 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->kerberos_ticket_cleanup = 1;
|
||||
if (options->kerberos_get_afs_token == -1)
|
||||
options->kerberos_get_afs_token = 0;
|
||||
+ if (options->kerberos_unique_ticket == -1)
|
||||
+ options->kerberos_unique_ticket = 0;
|
||||
if (options->gss_authentication == -1)
|
||||
options->gss_authentication = 0;
|
||||
if (options->gss_keyex == -1)
|
||||
@@ -447,7 +450,8 @@ typedef enum {
|
||||
sPermitRootLogin, sLogFacility, sLogLevel,
|
||||
sRhostsRSAAuthentication, sRSAAuthentication,
|
||||
sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
|
||||
- sKerberosGetAFSToken, sChallengeResponseAuthentication,
|
||||
+ sKerberosGetAFSToken, sKerberosUniqueTicket,
|
||||
+ sChallengeResponseAuthentication,
|
||||
sPasswordAuthentication, sKbdInteractiveAuthentication,
|
||||
sListenAddress, sAddressFamily,
|
||||
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
|
||||
@@ -526,11 +530,13 @@ static struct {
|
||||
#else
|
||||
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
|
||||
#endif
|
||||
+ { "kerberosuniqueticket", sKerberosUniqueTicket, SSHCFG_GLOBAL },
|
||||
#else
|
||||
{ "kerberosauthentication", sUnsupported, SSHCFG_ALL },
|
||||
{ "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
|
||||
{ "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
|
||||
{ "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
|
||||
+ { "kerberosuniqueticket", sUnsupported, SSHCFG_GLOBAL },
|
||||
#endif
|
||||
{ "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
|
||||
{ "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
|
||||
@@ -1437,6 +1443,10 @@ process_server_config_line(ServerOptions *options, char *line,
|
||||
intptr = &options->kerberos_get_afs_token;
|
||||
goto parse_flag;
|
||||
|
||||
+ case sKerberosUniqueTicket:
|
||||
+ intptr = &options->kerberos_unique_ticket;
|
||||
+ goto parse_flag;
|
||||
+
|
||||
case sGssAuthentication:
|
||||
intptr = &options->gss_authentication;
|
||||
goto parse_flag;
|
||||
@@ -2507,6 +2517,7 @@ dump_config(ServerOptions *o)
|
||||
# ifdef USE_AFS
|
||||
dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
|
||||
# endif
|
||||
+ dump_cfg_fmtint(sKerberosUniqueTicket, o->kerberos_unique_ticket);
|
||||
#endif
|
||||
#ifdef GSSAPI
|
||||
dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
|
||||
diff --git a/servconf.h b/servconf.h
|
||||
index db8362c6..4fa42d64 100644
|
||||
--- a/servconf.h
|
||||
+++ b/servconf.h
|
||||
@@ -123,6 +123,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_ticket; /* If true, the aquired 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 --git a/session.c b/session.c
|
||||
index 85df6a27..480a5ead 100644
|
||||
--- a/session.c
|
||||
+++ b/session.c
|
||||
@@ -1033,7 +1033,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
||||
/* Allow any GSSAPI methods that we've used to alter
|
||||
* the childs 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. */
|
||||
@@ -1105,7 +1106,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
|
||||
}
|
||||
#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 --git a/ssh-gss.h b/ssh-gss.h
|
||||
index 6593e422..245178af 100644
|
||||
--- a/ssh-gss.h
|
||||
+++ b/ssh-gss.h
|
||||
@@ -62,7 +62,6 @@
|
||||
#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
|
||||
|
||||
typedef struct {
|
||||
- char *filename;
|
||||
char *envvar;
|
||||
char *envval;
|
||||
struct passwd *owner;
|
||||
@@ -83,7 +82,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;
|
||||
|
||||
@@ -127,7 +126,7 @@ int ssh_gssapi_userok(char *name);
|
||||
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);
|
||||
diff --git a/sshd.c b/sshd.c
|
||||
index edbe815c..89514e8a 100644
|
||||
--- a/sshd.c
|
||||
+++ b/sshd.c
|
||||
@@ -2162,7 +2162,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 --git a/sshd_config.5 b/sshd_config.5
|
||||
index c0683d4a..2349f477 100644
|
||||
--- a/sshd_config.5
|
||||
+++ b/sshd_config.5
|
||||
@@ -860,6 +860,12 @@ Specifies whether to automatically destroy the user's ticket cache
|
||||
file on logout.
|
||||
The default is
|
||||
.Cm yes .
|
||||
+.It Cm KerberosUniqueTicket
|
||||
+Specifies whether to store the aquired tickets in the per-session credential
|
||||
+cache or whether to use per-user credential cache, which might overwrite
|
||||
+tickets aquired in different sessions of the same user.
|
||||
+The default is
|
||||
+.Cm no .
|
||||
.It Cm KexAlgorithms
|
||||
Specifies the available KEX (Key Exchange) algorithms.
|
||||
Multiple algorithms must be comma-separated.
|
11
openssh.spec
11
openssh.spec
@ -182,12 +182,11 @@ Patch802: openssh-6.6p1-GSSAPIEnablek5users.patch
|
||||
# Documentation about GSSAPI
|
||||
# from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=765655
|
||||
Patch803: openssh-7.1p1-gssapi-documentation.patch
|
||||
# use default_ccache_name from /etc/krb5.conf (#991186)
|
||||
Patch804: openssh-6.3p1-krb5-use-default_ccache_name.patch
|
||||
# Improve ccache handling in openssh (#991186, #1199363, #1566494)
|
||||
# https://bugzilla.mindrot.org/show_bug.cgi?id=2775
|
||||
Patch804: openssh-7.7p1-gssapi-new-unique.patch
|
||||
# Respect k5login_directory option in krk5.conf (#1328243)
|
||||
Patch805: openssh-7.2p2-k5login_directory.patch
|
||||
# Do not export KRBCCNAME if the default path is used (#1199363)
|
||||
Patch806: openssh-7.5p1-gss-environment.patch
|
||||
# Support SHA2 in GSS key exchanges from draft-ssorce-gss-keyex-sha2-02
|
||||
Patch807: openssh-7.5p1-gssapi-kex-with-ec.patch
|
||||
|
||||
@ -233,7 +232,6 @@ Patch952: openssh-7.6p1-pkcs11-ecdsa.patch
|
||||
# Opening tun devices fails + other regressions in OpenSSH v7.7 (#2855, #1567775)
|
||||
Patch953: openssh-7.7p1-tun-devices.patch
|
||||
|
||||
|
||||
License: BSD
|
||||
Group: Applications/Internet
|
||||
Requires: /sbin/nologin
|
||||
@ -435,7 +433,6 @@ popd
|
||||
%patch803 -p1 -b .gss-docs
|
||||
%patch804 -p1 -b .ccache_name
|
||||
%patch805 -p1 -b .k5login
|
||||
%patch806 -p1 -b .gss-env
|
||||
#
|
||||
%patch900 -p1 -b .canohost
|
||||
%patch901 -p1 -b .kuserok
|
||||
@ -813,7 +810,7 @@ getent passwd sshd >/dev/null || \
|
||||
- Drop support for ExposeAuthenticationMethods option
|
||||
|
||||
* Mon Sep 11 2017 Jakub Jelen <jjelen@redhat.com> - 7.5p1-6 + 0.10.3-2
|
||||
- Do not export KRBCCNAME if the default path is used (#1199363)
|
||||
- Do not export KRB5CCNAME if the default path is used (#1199363)
|
||||
- Add enablement for openssl-ibmca and openssl-ibmpkcs11 (#1477636)
|
||||
- Add new GSSAPI kex algorithms with SHA-2, but leave them disabled for now
|
||||
- Enforce pam_sepermit for all logins in SSH (#1492313)
|
||||
|
Loading…
Reference in New Issue
Block a user