From 46201ce0f8708c098cb4bcd3d42d7a6f7b5eb3e6 Mon Sep 17 00:00:00 2001 From: basney Date: Mon, 31 Aug 2009 19:22:32 +0000 Subject: [PATCH] merged OPENSSH_5_2P1_GSSAPI_20090831 to GPT-branch --- openssh/ChangeLog.gssapi | 26 +++ openssh/Makefile.in | 11 +- openssh/auth-pam.c | 71 ++++++- openssh/auth-pam.h | 1 + openssh/auth.c | 4 + openssh/auth2-gss.c | 15 +- openssh/auth2.c | 2 +- openssh/channels.c | 8 +- openssh/cipher-ctr-mt.c | 401 --------------------------------------- openssh/cipher.c | 7 +- openssh/clientloop.c | 13 ++ openssh/compat.h | 2 +- openssh/configure.ac | 14 +- openssh/gss-genr.c | 129 +++++++++++-- openssh/gss-serv-gsi.c | 3 +- openssh/gss-serv-krb5.c | 70 ++++++- openssh/gss-serv.c | 209 ++++++++++++++++---- openssh/kex.h | 1 + openssh/kexgssc.c | 27 ++- openssh/kexgsss.c | 28 ++- openssh/misc.c | 14 ++ openssh/misc.h | 1 + openssh/monitor.c | 130 +++++++++---- openssh/monitor.h | 1 + openssh/monitor_wrap.c | 68 ++++--- openssh/monitor_wrap.h | 3 +- openssh/readconf.c | 45 +++-- openssh/readconf.h | 4 +- openssh/servconf.c | 47 +++-- openssh/servconf.h | 8 +- openssh/ssh-gss.h | 33 +++- openssh/ssh_config.5 | 20 +- openssh/sshconnect2.c | 72 ++++--- openssh/sshd.c | 15 +- openssh/sshd_config | 4 + openssh/sshd_config.5 | 41 ++-- openssh/version.h | 4 +- 37 files changed, 895 insertions(+), 657 deletions(-) delete mode 100644 openssh/cipher-ctr-mt.c diff --git a/openssh/ChangeLog.gssapi b/openssh/ChangeLog.gssapi index 010612c..927b98b 100644 --- a/openssh/ChangeLog.gssapi +++ b/openssh/ChangeLog.gssapi @@ -1,3 +1,29 @@ +20090615 + - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c + sshd.c ] + Fix issues identified by Greg Hudson following a code review + Check return value of gss_indicate_mechs + Protect GSSAPI calls in monitor, so they can only be used if enabled + Check return values of bignum functions in key exchange + Use BN_clear_free to clear other side's DH value + Make ssh_gssapi_id_kex more robust + Only configure kex table pointers if GSSAPI is enabled + Don't leak mechanism list, or gss mechanism list + Cast data.length before printing + If serverkey isn't provided, use an empty string, rather than NULL + +20090201 + - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h + ssh_config.5 sshconnet2.c ] + Add support for the GSSAPIClientIdentity option, which allows the user + to specify which GSSAPI identity to use to contact a given server + +20080404 + - [ gss-serv.c ] + Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow + been omitted from a previous version of this patch. Reported by Borislav + Stoichkov + 20070317 - [ gss-serv-krb5.c ] Remove C99ism, where new_ccname was being declared in the middle of a diff --git a/openssh/Makefile.in b/openssh/Makefile.in index df44542..28acc71 100644 --- a/openssh/Makefile.in +++ b/openssh/Makefile.in @@ -42,7 +42,7 @@ CC=@CC@ LD=@LD@ CFLAGS=@CFLAGS@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -LIBS=@LIBS@ -lpthread +LIBS=@LIBS@ SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ AR=@AR@ @@ -68,7 +68,7 @@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keys LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \ - cipher-bf1.o cipher-ctr.o cipher-ctr-mt.o cipher-3des1.o cleanup.o \ + cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \ log.o match.o md-sha256.o moduli.o nchan.o packet.o \ readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \ @@ -76,8 +76,8 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ pathnames.o \ - kexgssc.o \ - entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o + entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o \ + kexgssc.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ sshconnect.o sshconnect1.o sshconnect2.o mux.o @@ -90,8 +90,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \ monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ auth-krb5.o \ - auth2-gss.o gss-serv.o gss-serv-krb5.o \ - kexgsss.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\ gss-serv-gsi.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o diff --git a/openssh/auth-pam.c b/openssh/auth-pam.c index ccdb993..582c463 100644 --- a/openssh/auth-pam.c +++ b/openssh/auth-pam.c @@ -30,7 +30,7 @@ */ /* * Copyright (c) 2003,2004 Damien Miller - * Copyright (c) 2003,2004 Darren Tucker + * Copyright (c) 2003,2004,2006 Darren Tucker * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -272,6 +272,49 @@ sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags) # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) #endif +struct passwd * +sshpam_getpw(const char *user) +{ + struct passwd *pw; + + if ((pw = getpwnam(user)) != NULL) + return(pw); + + debug("PAM: faking passwd struct for user '%.100s'", user); + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + return NULL; + pw->pw_name = xstrdup(user); /* XXX leak */ + pw->pw_shell = "/bin/true"; + pw->pw_gecos = "sshd fake PAM user"; + return (pw); +} + +void +sshpam_check_userchanged(void) +{ + int sshpam_err; + struct passwd *pw; + const char *user; + + debug("sshpam_check_userchanged"); + sshpam_err = pam_get_item(sshpam_handle, PAM_USER, &user); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: could not get PAM_USER: %s", + pam_strerror(sshpam_handle, sshpam_err)); + if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) { + debug("PAM: user mapped from '%.100s' to '%.100s'", + sshpam_authctxt->pw->pw_name, user); + if ((pw = getpwnam(user)) == NULL) + fatal("PAM: could not get passwd entry for user " + "'%.100s' provided by PAM_USER", user); + pwfree(sshpam_authctxt->pw); + sshpam_authctxt->pw = pw; + sshpam_authctxt->valid = allowed_user(pw); + debug("PAM: user '%.100s' now %svalid", user, + sshpam_authctxt->valid ? "" : "in"); + } +} + void sshpam_password_change_required(int reqd) { @@ -294,7 +337,7 @@ sshpam_password_change_required(int reqd) static void import_environments(Buffer *b) { - char *env; + char *env, *user; u_int i, num_env; int err; @@ -304,6 +347,15 @@ import_environments(Buffer *b) /* Import variables set by do_pam_account */ sshpam_account_status = buffer_get_int(b); sshpam_password_change_required(buffer_get_int(b)); + if (options.permit_pam_user_change) { + user = buffer_get_string(b, NULL); + debug("PAM: got username '%.100s' from thread", user); + if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS) + fatal("PAM: failed to set PAM_USER: %s", + pam_strerror(sshpam_handle, err)); + pwfree(sshpam_authctxt->pw); + sshpam_authctxt->pw = pwcopy(sshpam_getpw(user)); + } /* Import environment from subprocess */ num_env = buffer_get_int(b); @@ -469,6 +521,9 @@ sshpam_thread(void *ctxtp) if (sshpam_err != PAM_SUCCESS) goto auth_fail; + if (options.permit_pam_user_change) { + sshpam_check_userchanged(); + } if (compat20) { if (!do_pam_account()) { sshpam_err = PAM_ACCT_EXPIRED; @@ -489,6 +544,9 @@ sshpam_thread(void *ctxtp) /* Export variables set by do_pam_account */ buffer_put_int(&buffer, sshpam_account_status); buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); + if (options.permit_pam_user_change) { + buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name); + } /* Export any environment strings set in child */ for(i = 0; environ[i] != NULL; i++) @@ -907,6 +965,12 @@ do_pam_account(void) debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, pam_strerror(sshpam_handle, sshpam_err)); + if (options.permit_pam_user_change) { + sshpam_check_userchanged(); + if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL) + fatal("PAM: completed authentication but PAM account invalid"); + } + if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { sshpam_account_status = 0; return (sshpam_account_status); @@ -1206,6 +1270,9 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) pam_strerror(sshpam_handle, sshpam_err)); sshpam_err = pam_authenticate(sshpam_handle, flags); + if (options.permit_pam_user_change) { + sshpam_check_userchanged(); + } sshpam_password = NULL; if (sshpam_err == PAM_SUCCESS && authctxt->valid) { debug("PAM: password authentication accepted for %.100s", diff --git a/openssh/auth-pam.h b/openssh/auth-pam.h index 93a1eca..c2cb6dc 100644 --- a/openssh/auth-pam.h +++ b/openssh/auth-pam.h @@ -46,5 +46,6 @@ void sshpam_thread_cleanup(void); void sshpam_cleanup(void); int sshpam_auth_passwd(Authctxt *, const char *); int is_pam_session_open(void); +struct passwd *sshpam_getpw(const char *); #endif /* USE_PAM */ diff --git a/openssh/auth.c b/openssh/auth.c index 2106dfc..010e550 100644 --- a/openssh/auth.c +++ b/openssh/auth.c @@ -527,6 +527,10 @@ getpwnamallow(const char *user) get_canonical_hostname(options.use_dns), get_remote_ipaddr()); pw = getpwnam(user); +#ifdef USE_PAM + if (options.use_pam && options.permit_pam_user_change && pw == NULL) + pw = sshpam_getpw(user); +#endif if (pw == NULL) { logit("Invalid user %.100s from %.100s", (user && user[0]) ? user : "unknown", diff --git a/openssh/auth2-gss.c b/openssh/auth2-gss.c index 2cf6929..1db62c4 100644 --- a/openssh/auth2-gss.c +++ b/openssh/auth2-gss.c @@ -1,7 +1,7 @@ /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,7 +62,7 @@ userauth_external(Authctxt *authctxt) packet_check_eom(); if (authctxt->valid && authctxt->user && authctxt->user[0]) { - return(PRIVSEP(ssh_gssapi_userok(authctxt->user))); + return(PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw))); } return 0; } @@ -102,7 +102,8 @@ userauth_gsskeyex(Authctxt *authctxt) !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, &gssbuf2, &mic)))) { if (authctxt->valid && authctxt->user && authctxt->user[0]) { - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, + authctxt->pw)); } } @@ -341,7 +342,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) /* user should be set if valid but we double-check here */ if (authctxt->valid && authctxt->user && authctxt->user[0]) { - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, + authctxt->pw)); } else { authenticated = 0; } @@ -397,9 +399,10 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) if (authctxt->valid && authctxt->user && authctxt->user[0]) { - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + authenticated = + PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); } else { - authenticated = 0; + authenticated = 0; } else logit("GSSAPI MIC check failed"); diff --git a/openssh/auth2.c b/openssh/auth2.c index 2e46638..1cd3e10 100644 --- a/openssh/auth2.c +++ b/openssh/auth2.c @@ -411,7 +411,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method) /* Dont count server configuration issues against the client */ /* Allow initial try of "none" auth without failure penalty */ if (!authctxt->server_caused_failure && - (authctxt->attempt > 1 || strcmp(method, "none") != 0)) + (authctxt->attempt > 1 || strcmp(method, "none") != 0)) authctxt->failures++; if (authctxt->failures >= options.max_authtries) { #ifdef SSH_AUDIT_EVENTS diff --git a/openssh/channels.c b/openssh/channels.c index 6996bde..79c7696 100644 --- a/openssh/channels.c +++ b/openssh/channels.c @@ -2662,10 +2662,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr, c = channel_new("port listener", type, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "port listener", 1); - else - c = channel_new("port listener", type, sock, sock, -1, - hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, - 0, "port listener", 1); + else + c = channel_new("port listener", type, sock, sock, -1, + hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); c->path = xstrdup(host); c->host_port = port_to_connect; c->listening_port = listen_port; diff --git a/openssh/cipher-ctr-mt.c b/openssh/cipher-ctr-mt.c deleted file mode 100644 index fd30499..0000000 --- a/openssh/cipher-ctr-mt.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * OpenSSH Multi-threaded AES-CTR Cipher - * - * Author: Benjamin Bennett - * Copyright (c) 2008 Pittsburgh Supercomputing Center. All rights reserved. - * - * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged, - * Copyright (c) 2003 Markus Friedl - * - * 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. - */ -#include "includes.h" - -#include - -#include -#include - -#include - -#include "xmalloc.h" -#include "log.h" - -/* compatibility with old or broken OpenSSL versions */ -#include "openbsd-compat/openssl-compat.h" - -#ifndef USE_BUILTIN_RIJNDAEL -#include -#endif - -#include - -/*-------------------- TUNABLES --------------------*/ -/* Number of pregen threads to use */ -#define CIPHER_THREADS 2 - -/* Number of keystream queues */ -#define NUMKQ (CIPHER_THREADS + 2) - -/* Length of a keystream queue */ -#define KQLEN 4096 - -/* Processor cacheline length */ -#define CACHELINE_LEN 64 -/*-------------------- END TUNABLES --------------------*/ - - -const EVP_CIPHER *evp_aes_ctr_mt(void); - -/* Keystream Queue state */ -enum { - KQINIT, - KQEMPTY, - KQFILLING, - KQFULL, - KQDRAINING -}; - -/* Keystream Queue struct */ -struct kq { - u_char keys[KQLEN][AES_BLOCK_SIZE]; - u_char ctr[AES_BLOCK_SIZE]; - u_char pad0[CACHELINE_LEN]; - volatile int qstate; - pthread_mutex_t lock; - pthread_cond_t cond; - u_char pad1[CACHELINE_LEN]; -}; - -/* Context struct */ -struct ssh_aes_ctr_ctx -{ - struct kq q[NUMKQ]; - AES_KEY aes_ctx; - u_char aes_counter[AES_BLOCK_SIZE]; - pthread_t tid[CIPHER_THREADS]; - int state; - int qidx; - int ridx; -}; - -/* - * increment counter 'ctr', - * the counter is of size 'len' bytes and stored in network-byte-order. - * (LSB at ctr[len-1], MSB at ctr[0]) - */ -static void -ssh_ctr_inc(u_char *ctr, u_int len) -{ - int i; - - for (i = len - 1; i >= 0; i--) - if (++ctr[i]) /* continue on overflow */ - return; -} - -/* - * Add num to counter 'ctr' - */ -static void -ssh_ctr_add(u_char *ctr, uint32_t num, u_int len) -{ - int i; - uint16_t n; - - for (n = 0, i = len - 1; i >= 0 && (num || n); i--) { - n = ctr[i] + (num & 0xff) + n; - num >>= 8; - ctr[i] = n & 0xff; - n >>= 8; - } -} - -/* - * Threads may be cancelled in a pthread_cond_wait, we must free the mutex - */ -static void -thread_loop_cleanup(void *x) -{ - pthread_mutex_unlock((pthread_mutex_t *)x); -} - -/* - * The life of a pregen thread: - * Find empty keystream queues and fill them using their counter. - * When done, update counter for the next fill. - */ -static void * -thread_loop(void *x) -{ - AES_KEY key; - struct ssh_aes_ctr_ctx *c = x; - struct kq *q; - int i; - int qidx; - - /* Thread local copy of AES key */ - memcpy(&key, &c->aes_ctx, sizeof(key)); - - /* - * Handle the special case of startup, one thread must fill - * the first KQ then mark it as draining. Lock held throughout. - */ - if (pthread_equal(pthread_self(), c->tid[0])) { - q = &c->q[0]; - pthread_mutex_lock(&q->lock); - if (q->qstate == KQINIT) { - for (i = 0; i < KQLEN; i++) { - AES_encrypt(q->ctr, q->keys[i], &key); - ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); - } - ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE); - q->qstate = KQDRAINING; - pthread_cond_broadcast(&q->cond); - } - pthread_mutex_unlock(&q->lock); - } - - /* - * Normal case is to find empty queues and fill them, skipping over - * queues already filled by other threads and stopping to wait for - * a draining queue to become empty. - * - * Multiple threads may be waiting on a draining queue and awoken - * when empty. The first thread to wake will mark it as filling, - * others will move on to fill, skip, or wait on the next queue. - */ - for (qidx = 1;; qidx = (qidx + 1) % NUMKQ) { - /* Check if I was cancelled, also checked in cond_wait */ - pthread_testcancel(); - - /* Lock queue and block if its draining */ - q = &c->q[qidx]; - pthread_mutex_lock(&q->lock); - pthread_cleanup_push(thread_loop_cleanup, &q->lock); - while (q->qstate == KQDRAINING || q->qstate == KQINIT) { - pthread_cond_wait(&q->cond, &q->lock); - } - pthread_cleanup_pop(0); - - /* If filling or full, somebody else got it, skip */ - if (q->qstate != KQEMPTY) { - pthread_mutex_unlock(&q->lock); - continue; - } - - /* - * Empty, let's fill it. - * Queue lock is relinquished while we do this so others - * can see that it's being filled. - */ - q->qstate = KQFILLING; - pthread_mutex_unlock(&q->lock); - for (i = 0; i < KQLEN; i++) { - AES_encrypt(q->ctr, q->keys[i], &key); - ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); - } - - /* Re-lock, mark full and signal consumer */ - pthread_mutex_lock(&q->lock); - ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE); - q->qstate = KQFULL; - pthread_cond_signal(&q->cond); - pthread_mutex_unlock(&q->lock); - } - - return NULL; -} - -static int -ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, - u_int len) -{ - struct ssh_aes_ctr_ctx *c; - struct kq *q, *oldq; - int ridx; - u_char *buf; - - if (len == 0) - return (1); - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) - return (0); - - q = &c->q[c->qidx]; - ridx = c->ridx; - - /* src already padded to block multiple */ - while (len > 0) { - buf = q->keys[ridx]; - -#ifdef CIPHER_BYTE_XOR - dest[0] = src[0] ^ buf[0]; - dest[1] = src[1] ^ buf[1]; - dest[2] = src[2] ^ buf[2]; - dest[3] = src[3] ^ buf[3]; - dest[4] = src[4] ^ buf[4]; - dest[5] = src[5] ^ buf[5]; - dest[6] = src[6] ^ buf[6]; - dest[7] = src[7] ^ buf[7]; - dest[8] = src[8] ^ buf[8]; - dest[9] = src[9] ^ buf[9]; - dest[10] = src[10] ^ buf[10]; - dest[11] = src[11] ^ buf[11]; - dest[12] = src[12] ^ buf[12]; - dest[13] = src[13] ^ buf[13]; - dest[14] = src[14] ^ buf[14]; - dest[15] = src[15] ^ buf[15]; -#else - *(uint64_t *)dest = *(uint64_t *)src ^ *(uint64_t *)buf; - *(uint64_t *)(dest + 8) = *(uint64_t *)(src + 8) ^ - *(uint64_t *)(buf + 8); -#endif - - dest += 16; - src += 16; - len -= 16; - ssh_ctr_inc(ctx->iv, AES_BLOCK_SIZE); - - /* Increment read index, switch queues on rollover */ - if ((ridx = (ridx + 1) % KQLEN) == 0) { - oldq = q; - - /* Mark next queue draining, may need to wait */ - c->qidx = (c->qidx + 1) % NUMKQ; - q = &c->q[c->qidx]; - pthread_mutex_lock(&q->lock); - while (q->qstate != KQFULL) { - pthread_cond_wait(&q->cond, &q->lock); - } - q->qstate = KQDRAINING; - pthread_mutex_unlock(&q->lock); - - /* Mark consumed queue empty and signal producers */ - pthread_mutex_lock(&oldq->lock); - oldq->qstate = KQEMPTY; - pthread_cond_broadcast(&oldq->cond); - pthread_mutex_unlock(&oldq->lock); - } - } - c->ridx = ridx; - return (1); -} - -#define HAVE_NONE 0 -#define HAVE_KEY 1 -#define HAVE_IV 2 -static int -ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, - int enc) -{ - struct ssh_aes_ctr_ctx *c; - int i; - - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { - c = xmalloc(sizeof(*c)); - - c->state = HAVE_NONE; - for (i = 0; i < NUMKQ; i++) { - pthread_mutex_init(&c->q[i].lock, NULL); - pthread_cond_init(&c->q[i].cond, NULL); - } - - EVP_CIPHER_CTX_set_app_data(ctx, c); - } - - if (c->state == (HAVE_KEY | HAVE_IV)) { - /* Cancel pregen threads */ - for (i = 0; i < CIPHER_THREADS; i++) - pthread_cancel(c->tid[i]); - for (i = 0; i < CIPHER_THREADS; i++) - pthread_join(c->tid[i], NULL); - /* Start over getting key & iv */ - c->state = HAVE_NONE; - } - - if (key != NULL) { - AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, - &c->aes_ctx); - c->state |= HAVE_KEY; - } - - if (iv != NULL) { - memcpy(ctx->iv, iv, AES_BLOCK_SIZE); - c->state |= HAVE_IV; - } - - if (c->state == (HAVE_KEY | HAVE_IV)) { - /* Clear queues */ - memcpy(c->q[0].ctr, ctx->iv, AES_BLOCK_SIZE); - c->q[0].qstate = KQINIT; - for (i = 1; i < NUMKQ; i++) { - memcpy(c->q[i].ctr, ctx->iv, AES_BLOCK_SIZE); - ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE); - c->q[i].qstate = KQEMPTY; - } - c->qidx = 0; - c->ridx = 0; - - /* Start threads */ - for (i = 0; i < CIPHER_THREADS; i++) { - pthread_create(&c->tid[i], NULL, thread_loop, c); - } - pthread_mutex_lock(&c->q[0].lock); - while (c->q[0].qstate != KQDRAINING) - pthread_cond_wait(&c->q[0].cond, &c->q[0].lock); - pthread_mutex_unlock(&c->q[0].lock); - - } - return (1); -} - -static int -ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) -{ - struct ssh_aes_ctr_ctx *c; - int i; - - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { - /* Cancel pregen threads */ - for (i = 0; i < CIPHER_THREADS; i++) - pthread_cancel(c->tid[i]); - for (i = 0; i < CIPHER_THREADS; i++) - pthread_join(c->tid[i], NULL); - - memset(c, 0, sizeof(*c)); - xfree(c); - EVP_CIPHER_CTX_set_app_data(ctx, NULL); - } - return (1); -} - -/* */ -const EVP_CIPHER * -evp_aes_ctr_mt(void) -{ - static EVP_CIPHER aes_ctr; - - memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); - aes_ctr.nid = NID_undef; - aes_ctr.block_size = AES_BLOCK_SIZE; - aes_ctr.iv_len = AES_BLOCK_SIZE; - aes_ctr.key_len = 16; - aes_ctr.init = ssh_aes_ctr_init; - aes_ctr.cleanup = ssh_aes_ctr_cleanup; - aes_ctr.do_cipher = ssh_aes_ctr; -#ifndef SSH_OLD_EVP - aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | - EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; -#endif - return (&aes_ctr); -} diff --git a/openssh/cipher.c b/openssh/cipher.c index bbb2805..d18e0fb 100644 --- a/openssh/cipher.c +++ b/openssh/cipher.c @@ -55,7 +55,6 @@ extern const EVP_CIPHER *evp_ssh1_bf(void); extern const EVP_CIPHER *evp_ssh1_3des(void); extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); extern const EVP_CIPHER *evp_aes_128_ctr(void); -extern const EVP_CIPHER *evp_aes_ctr_mt(void); extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); struct Cipher { @@ -83,9 +82,9 @@ struct Cipher { { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, { "rijndael-cbc@lysator.liu.se", SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, - { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_ctr_mt }, - { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_ctr_mt }, - { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_ctr_mt }, + { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_128_ctr }, + { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_128_ctr }, + { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_128_ctr }, #ifdef USE_CIPHER_ACSS { "acss@openssh.org", SSH_CIPHER_SSH2, 16, 5, 0, 0, EVP_acss }, #endif diff --git a/openssh/clientloop.c b/openssh/clientloop.c index 38028d5..afd91c1 100644 --- a/openssh/clientloop.c +++ b/openssh/clientloop.c @@ -110,6 +110,10 @@ #include "match.h" #include "msg.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + /* import options */ extern Options options; @@ -1429,6 +1433,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) /* Do channel operations unless rekeying in progress. */ if (!rekeying) { channel_after_select(readset, writeset); + +#ifdef GSSAPI + if (options.gss_renewal_rekey && + ssh_gssapi_credentials_updated((Gssctxt *)GSS_C_NO_CONTEXT)) { + debug("credentials updated - forcing rekey"); + need_rekeying = 1; + } +#endif + if (need_rekeying || packet_need_rekeying()) { debug("need rekeying"); xxx_kex->done = 0; diff --git a/openssh/compat.h b/openssh/compat.h index e303d33..6feaa6b 100644 --- a/openssh/compat.h +++ b/openssh/compat.h @@ -58,7 +58,7 @@ #define SSH_OLD_FORWARD_ADDR 0x01000000 #define SSH_BUG_RFWD_ADDR 0x02000000 #define SSH_NEW_OPENSSH 0x04000000 -#define SSH_BUG_LARGEWINDOW 0x08000000 +#define SSH_BUG_LARGEWINDOW 0x08000000 void enable_compat13(void); void enable_compat20(void); diff --git a/openssh/configure.ac b/openssh/configure.ac index 0b7526e..c93f865 100644 --- a/openssh/configure.ac +++ b/openssh/configure.ac @@ -466,13 +466,6 @@ int main(void) { exit(0); } [Use tunnel device compatibility to OpenBSD]) AC_DEFINE(SSH_TUN_PREPEND_AF, 1, [Prepend the address family to IP tunnel traffic]) - m4_pattern_allow(AU_IPv) - AC_CHECK_DECL(AU_IPv4, [], - AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records]) - [#include ] - AC_DEFINE(LASTLOG_WRITE_PUTUTXLINE, 1, - [Define if pututxline updates lastlog too]) - ) AC_MSG_CHECKING(if we have the Security Authorization Session API) AC_TRY_COMPILE([#include ], [SessionCreate(0, 0);], @@ -497,6 +490,13 @@ int main(void) { exit(0); } fi], [AC_MSG_RESULT(no)] ) + m4_pattern_allow(AU_IPv) + AC_CHECK_DECL(AU_IPv4, [], + AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records]) + [#include ] + AC_DEFINE(LASTLOG_WRITE_PUTUTXLINE, 1, + [Define if pututxline updates lastlog too]) + ) ;; *-*-dragonfly*) SSHDLIBS="$SSHDLIBS -lcrypt" diff --git a/openssh/gss-genr.c b/openssh/gss-genr.c index 92cd09a..81b85ba 100644 --- a/openssh/gss-genr.c +++ b/openssh/gss-genr.c @@ -1,7 +1,7 @@ /* $OpenBSD: gss-genr.c,v 1.19 2007/06/12 11:56:15 dtucker Exp $ */ /* - * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -77,19 +77,20 @@ ssh_gssapi_oid_table_ok() { */ char * -ssh_gssapi_client_mechanisms(const char *host) { +ssh_gssapi_client_mechanisms(const char *host, const char *client) { gss_OID_set gss_supported; OM_uint32 min_status; - gss_indicate_mechs(&min_status, &gss_supported); + if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) + return NULL; return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, - host)); + host, client)); } char * ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, - const char *data) { + const char *host, const char *client) { Buffer buf; size_t i; int oidpos, enclen; @@ -113,7 +114,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, oidpos = 0; for (i = 0; i < gss_supported->count; i++) { if (gss_supported->elements[i].length < 128 && - (*check)(NULL, &(gss_supported->elements[i]), data)) { + (*check)(NULL, &(gss_supported->elements[i]), host, client)) { deroid[0] = SSH_GSS_OIDTYPE; deroid[1] = gss_supported->elements[i].length; @@ -172,12 +173,18 @@ ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { switch (kex_type) { case KEX_GSS_GRP1_SHA1: + if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) + return GSS_C_NO_OID; name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; break; case KEX_GSS_GRP14_SHA1: + if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) + return GSS_C_NO_OID; name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; break; case KEX_GSS_GEX_SHA1: + if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) + return GSS_C_NO_OID; name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; break; default: @@ -350,7 +357,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, } ctx->major = gss_init_sec_context(&ctx->minor, - GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, + ctx->client_creds, &ctx->context, ctx->name, ctx->oid, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); @@ -389,9 +396,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) return (ctx->major); } +OM_uint32 +ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) +{ + gss_buffer_desc gssbuf; + gss_name_t gssname; + OM_uint32 status; + gss_OID_set oidset; + + gssbuf.value = (void *) name; + gssbuf.length = strlen(gssbuf.value); + + gss_create_empty_oid_set(&status, &oidset); + gss_add_oid_set_member(&status, ctx->oid, &oidset); + + ctx->major = gss_import_name(&ctx->minor, &gssbuf, + GSS_C_NT_USER_NAME, &gssname); + + if (!ctx->major) + ctx->major = gss_acquire_cred(&ctx->minor, + gssname, 0, oidset, GSS_C_INITIATE, + &ctx->client_creds, NULL, NULL); + + gss_release_name(&status, &gssname); + gss_release_oid_set(&status, &oidset); + + if (ctx->major) + ssh_gssapi_error(ctx); + + return(ctx->major); +} + OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) { + if (ctx == NULL) + return -1; + if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); @@ -400,17 +441,16 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) } /* Priviledged when used by server */ -/* Moved here from gss-serv.c because called by kexgss_client(). */ OM_uint32 ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) { - if (ctx == NULL) - return -1; + if (ctx == NULL) + return -1; - ctx->major = gss_verify_mic(&ctx->minor, ctx->context, - gssbuf, gssmic, NULL); + ctx->major = gss_verify_mic(&ctx->minor, ctx->context, + gssbuf, gssmic, NULL); - return (ctx->major); + return (ctx->major); } void @@ -426,7 +466,8 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, } int -ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) +ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, + const char *client) { gss_buffer_desc token = GSS_C_EMPTY_BUFFER; OM_uint32 major, minor; @@ -444,6 +485,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) ssh_gssapi_build_ctx(ctx); ssh_gssapi_set_oid(*ctx, oid); major = ssh_gssapi_import_name(*ctx, host); + + if (!GSS_ERROR(major) && client) + major = ssh_gssapi_client_identity(*ctx, client); + if (!GSS_ERROR(major)) { major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); @@ -459,4 +504,60 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) return (!GSS_ERROR(major)); } +int +ssh_gssapi_credentials_updated(Gssctxt *ctxt) { + static gss_name_t saved_name = GSS_C_NO_NAME; + static OM_uint32 saved_lifetime = 0; + static gss_OID saved_mech = GSS_C_NO_OID; + static gss_name_t name; + static OM_uint32 last_call = 0; + OM_uint32 lifetime, now, major, minor; + int equal; + + now = time(NULL); + + if (ctxt) { + debug("Rekey has happened - updating saved versions"); + + if (saved_name != GSS_C_NO_NAME) + gss_release_name(&minor, &saved_name); + + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, + &saved_name, &saved_lifetime, NULL, NULL); + + if (!GSS_ERROR(major)) { + saved_mech = ctxt->oid; + saved_lifetime+= now; + } else { + /* Handle the error */ + } + return 0; + } + + if (now - last_call < 10) + return 0; + + last_call = now; + + if (saved_mech == GSS_C_NO_OID) + return 0; + + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, + &name, &lifetime, NULL, NULL); + if (major == GSS_S_CREDENTIALS_EXPIRED) + return 0; + else if (GSS_ERROR(major)) + return 0; + + major = gss_compare_name(&minor, saved_name, name, &equal); + gss_release_name(&minor, &name); + if (GSS_ERROR(major)) + return 0; + + if (equal && (saved_lifetime < lifetime + now - 10)) + return 1; + + return 0; +} + #endif /* GSSAPI */ diff --git a/openssh/gss-serv-gsi.c b/openssh/gss-serv-gsi.c index e31d70c..e77db62 100644 --- a/openssh/gss-serv-gsi.c +++ b/openssh/gss-serv-gsi.c @@ -57,7 +57,8 @@ ssh_gssapi_mech gssapi_gsi_mech = { NULL, &ssh_gssapi_gsi_userok, &ssh_gssapi_gsi_localname, - &ssh_gssapi_gsi_storecreds + &ssh_gssapi_gsi_storecreds, + NULL }; /* diff --git a/openssh/gss-serv-krb5.c b/openssh/gss-serv-krb5.c index bea0eae..a439393 100644 --- a/openssh/gss-serv-krb5.c +++ b/openssh/gss-serv-krb5.c @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,7 +69,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { NULL, &ssh_gssapi_krb5_userok, &ssh_gssapi_krb5_localname, - &ssh_gssapi_krb5_storecreds + &ssh_gssapi_krb5_storecreds, + &ssh_gssapi_krb5_updatecreds }; /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ @@ -242,6 +243,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) return; } +int +ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, + ssh_gssapi_client *client) +{ + krb5_ccache ccache = NULL; + krb5_principal principal = NULL; + char *name = NULL; + krb5_error_code problem; + OM_uint32 maj_status, min_status; + + if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { + logit("krb5_cc_resolve(): %.100s", + krb5_get_err_text(krb_context, problem)); + return 0; + } + + /* Find out who the principal in this cache is */ + if ((problem = krb5_cc_get_principal(krb_context, ccache, + &principal))) { + logit("krb5_cc_get_principal(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_cc_close(krb_context, ccache); + return 0; + } + + if ((problem = krb5_unparse_name(krb_context, principal, &name))) { + logit("krb5_unparse_name(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + return 0; + } + + + if (strcmp(name,client->exportedname.value)!=0) { + debug("Name in local credentials cache differs. Not storing"); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + krb5_free_unparsed_name(krb_context, name); + return 0; + } + krb5_free_unparsed_name(krb_context, name); + + /* Name matches, so lets get on with it! */ + + if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { + logit("krb5_cc_initialize(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + return 0; + } + + krb5_free_principal(krb_context, principal); + + if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, + ccache))) { + logit("gss_krb5_copy_ccache() failed. Sorry!"); + krb5_cc_close(krb_context, ccache); + return 0; + } + + return 1; +} + #endif /* KRB5 */ #endif /* GSSAPI */ diff --git a/openssh/gss-serv.c b/openssh/gss-serv.c index bf88d71..de0f7d5 100644 --- a/openssh/gss-serv.c +++ b/openssh/gss-serv.c @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ /* - * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,6 +46,7 @@ #include "session.h" #include "misc.h" #include "servconf.h" +#include "uidswap.h" #include "xmalloc.h" #include "ssh-gss.h" @@ -56,10 +57,10 @@ extern Authctxt *the_authctxt; static ssh_gssapi_client gssapi_client = { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, - GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; + GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0}; ssh_gssapi_mech gssapi_null_mech = - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; @@ -82,28 +83,6 @@ ssh_gssapi_mech* supported_mechs[]= { static int limited = 0; #endif -/* Unprivileged */ -char * -ssh_gssapi_server_mechanisms() { - gss_OID_set supported; - - ssh_gssapi_supported_oids(&supported); - return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, - NULL)); -} - -/* Unprivileged */ -int -ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) { - Gssctxt *ctx = NULL; - int res; - - res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); - ssh_gssapi_delete_ctx(&ctx); - - return (res); -} - /* * Acquire credentials for a server running on the current host. * Requires that the context structure contains a valid OID @@ -146,7 +125,6 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) return GSS_S_COMPLETE; } - /* Privileged */ OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) @@ -158,6 +136,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) return (ssh_gssapi_acquire_cred(*ctx)); } +/* Unprivileged */ +char * +ssh_gssapi_server_mechanisms() { + gss_OID_set supported; + + ssh_gssapi_supported_oids(&supported); + return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, + NULL, NULL)); +} + +/* Unprivileged */ +int +ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, + const char *dummy) { + Gssctxt *ctx = NULL; + int res; + + res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); + ssh_gssapi_delete_ctx(&ctx); + + return (res); +} + /* Unprivileged */ void ssh_gssapi_supported_oids(gss_OID_set *oidset) @@ -168,8 +169,10 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) gss_OID_set supported; gss_create_empty_oid_set(&min_status, oidset); - /* Ask priviledged process what mechanisms it supports. */ - PRIVSEP(gss_indicate_mechs(&min_status, &supported)); + + /* Ask privileged process what mechanisms it supports. */ + if (GSS_ERROR(PRIVSEP(gss_indicate_mechs(&min_status, &supported)))) + return; while (supported_mechs[i]->name != NULL) { if (GSS_ERROR(gss_test_oid_set_member(&min_status, @@ -308,8 +311,51 @@ OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; + int equal = 0; + gss_name_t new_name = GSS_C_NO_NAME; + gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; + + if (options.gss_store_rekey && client->used && ctx->client_creds) { + if (client->mech->oid.length != ctx->oid->length || + (memcmp(client->mech->oid.elements, + ctx->oid->elements, ctx->oid->length) !=0)) { + debug("Rekeyed credentials have different mechanism"); + return GSS_S_COMPLETE; + } + + /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech + because GSI doesn't support the latter. -jbasney */ + + if ((ctx->major = gss_inquire_cred(&ctx->minor, + ctx->client_creds, &new_name, + NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } - gss_buffer_desc ename; + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); + + if (GSS_ERROR(ctx->major)) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + if (!equal) { + debug("Rekeyed credentials have different name"); + return GSS_S_COMPLETE; + } + + debug("Marking rekeyed credentials for export"); + + gss_release_name(&ctx->minor, &client->name); + gss_release_cred(&ctx->minor, &client->creds); + client->name = new_name; + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; + client->updated = 1; + return GSS_S_COMPLETE; + } client->mech = NULL; @@ -324,6 +370,16 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) if (client->mech == NULL) return GSS_S_FAILURE; + /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech + because GSI doesn't support the latter. -jbasney */ + + if (ctx->client_creds && + (ctx->major = gss_inquire_cred(&ctx->minor, + ctx->client_creds, &client->name, NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); @@ -341,6 +397,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) return (ctx->major); } + gss_release_buffer(&ctx->minor, &ename); + /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; @@ -397,7 +455,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) /* Privileged */ int -ssh_gssapi_userok(char *user) +ssh_gssapi_userok(char *user, struct passwd *pw) { OM_uint32 lmin; @@ -413,9 +471,11 @@ ssh_gssapi_userok(char *user) } #endif if (gssapi_client.mech && gssapi_client.mech->userok) - if ((*gssapi_client.mech->userok)(&gssapi_client, user)) + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { + gssapi_client.used = 1; + gssapi_client.store.owner = pw; return 1; - else { + } else { /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); @@ -449,4 +509,89 @@ ssh_gssapi_localname(char **user) return(0); } +/* These bits are only used for rekeying. The unpriviledged child is running + * as the user, the monitor is root. + * + * In the child, we want to : + * *) Ask the monitor to store our credentials into the store we specify + * *) If it succeeds, maybe do a PAM update + */ + +/* Stuff for PAM */ + +#ifdef USE_PAM +static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + return (PAM_CONV_ERR); +} +#endif + +void +ssh_gssapi_rekey_creds() { + int ok; +#ifdef USE_PAM + pam_handle_t *pamh = NULL; + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; + char *envstr; +#endif + + if (gssapi_client.store.filename == NULL && + gssapi_client.store.envval == NULL && + gssapi_client.store.envvar == NULL) + return; + + ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); + + if (!ok) + return; + + debug("Rekeyed credentials stored successfully"); + + /* Actually managing to play with the ssh pam stack from here will + * be next to impossible. In any case, we may want different options + * for rekeying. So, use our own :) + */ +#ifdef USE_PAM + if (!use_privsep) { + debug("Not even going to try and do PAM with privsep disabled"); + return; + } + + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, + &pamconv, &pamh); + if (ret) + return; + + xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, + gssapi_client.store.envval); + + ret = pam_putenv(pamh, envstr); + if (!ret) + pam_setcred(pamh, PAM_REINITIALIZE_CRED); + pam_end(pamh, PAM_SUCCESS); +#endif +} + +int +ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { + int ok = 0; + + /* Check we've got credentials to store */ + if (!gssapi_client.updated) + return 0; + + gssapi_client.updated = 0; + + temporarily_use_uid(gssapi_client.store.owner); + if (gssapi_client.mech && gssapi_client.mech->updatecreds) + ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); + else + debug("No update function for this mechanism"); + + restore_uid(); + + return ok; +} + #endif diff --git a/openssh/kex.h b/openssh/kex.h index 39c28c8..6100df8 100644 --- a/openssh/kex.h +++ b/openssh/kex.h @@ -127,6 +127,7 @@ struct Kex { int gss_deleg_creds; int gss_trust_dns; char *gss_host; + char *gss_client; #endif char *client_version_string; char *server_version_string; diff --git a/openssh/kexgssc.c b/openssh/kexgssc.c index 1cadb2a..39be405 100644 --- a/openssh/kexgssc.c +++ b/openssh/kexgssc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,6 +26,8 @@ #ifdef GSSAPI +#include "includes.h" + #include #include @@ -57,6 +59,7 @@ kexgss_client(Kex *kex) { BIGNUM *g = NULL; u_char *kbuf, *hash; u_char *serverhostkey = NULL; + u_char *empty = ""; char *msg; char *lang; int type = 0; @@ -71,7 +74,11 @@ kexgss_client(Kex *kex) { if (ssh_gssapi_import_name(ctxt, kex->gss_host)) fatal("Couldn't import hostname"); - + + if (kex->gss_client && + ssh_gssapi_client_identity(ctxt, kex->gss_client)) + fatal("Couldn't acquire client credentials"); + switch (kex->kex_type) { case KEX_GSS_GRP1_SHA1: dh = dh_new_group1(); @@ -243,9 +250,16 @@ kexgss_client(Kex *kex) { klen = DH_size(dh); kbuf = xmalloc(klen); kout = DH_compute_key(kbuf, dh_server_pub, dh); + if (kout < 0) + fatal("DH_compute_key: failed"); shared_secret = BN_new(); - BN_bin2bn(kbuf,kout, shared_secret); + if (shared_secret == NULL) + fatal("kexgss_client: BN_new failed"); + + if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) + fatal("kexdh_client: BN_bin2bn failed"); + memset(kbuf, 0, klen); xfree(kbuf); @@ -256,7 +270,7 @@ kexgss_client(Kex *kex) { kex->server_version_string, buffer_ptr(&kex->my), buffer_len(&kex->my), buffer_ptr(&kex->peer), buffer_len(&kex->peer), - serverhostkey, slen, /* server host key */ + (serverhostkey ? serverhostkey : empty), slen, dh->pub_key, /* e */ dh_server_pub, /* f */ shared_secret, /* K */ @@ -270,7 +284,7 @@ kexgss_client(Kex *kex) { kex->server_version_string, buffer_ptr(&kex->my), buffer_len(&kex->my), buffer_ptr(&kex->peer), buffer_len(&kex->peer), - serverhostkey, slen, + (serverhostkey ? serverhostkey : empty), slen, min, nbits, max, dh->p, dh->g, dh->pub_key, @@ -304,6 +318,9 @@ kexgss_client(Kex *kex) { memcpy(kex->session_id, hash, kex->session_id_len); } + if (kex->gss_deleg_creds) + ssh_gssapi_credentials_updated(ctxt); + if (gss_kex_context == NULL) gss_kex_context = ctxt; else diff --git a/openssh/kexgsss.c b/openssh/kexgsss.c index ae58cac..3e5205c 100644 --- a/openssh/kexgsss.c +++ b/openssh/kexgsss.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,8 +42,10 @@ #include "dh.h" #include "ssh-gss.h" #include "monitor_wrap.h" +#include "servconf.h" static void kex_gss_send_error(Gssctxt *ctxt); +extern ServerOptions options; void kexgss_server(Kex *kex) @@ -69,6 +71,7 @@ kexgss_server(Kex *kex) BIGNUM *dh_client_pub = NULL; int type = 0; gss_OID oid; + char *mechs; /* Initialise GSSAPI */ @@ -77,7 +80,8 @@ kexgss_server(Kex *kex) * into life */ if (!ssh_gssapi_oid_table_ok()) - ssh_gssapi_server_mechanisms(); + if ((mechs = ssh_gssapi_server_mechanisms())) + xfree(mechs); debug2("%s: Identifying %s", __func__, kex->name); oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); @@ -168,7 +172,7 @@ kexgss_server(Kex *kex) if (maj_status & GSS_S_CONTINUE_NEEDED) { debug("Sending GSSAPI_CONTINUE"); packet_start(SSH2_MSG_KEXGSS_CONTINUE); - packet_put_string(send_tok.value, send_tok.length); + packet_put_string((char *)send_tok.value, send_tok.length); packet_send(); gss_release_buffer(&min_status, &send_tok); } @@ -178,7 +182,7 @@ kexgss_server(Kex *kex) kex_gss_send_error(ctxt); if (send_tok.length > 0) { packet_start(SSH2_MSG_KEXGSS_CONTINUE); - packet_put_string(send_tok.value, send_tok.length); + packet_put_string((char *)send_tok.value, send_tok.length); packet_send(); } packet_disconnect("GSSAPI Key Exchange handshake failed"); @@ -196,9 +200,16 @@ kexgss_server(Kex *kex) klen = DH_size(dh); kbuf = xmalloc(klen); kout = DH_compute_key(kbuf, dh_client_pub, dh); + if (kout < 0) + fatal("DH_compute_key: failed"); shared_secret = BN_new(); - BN_bin2bn(kbuf, kout, shared_secret); + if (shared_secret == NULL) + fatal("kexgss_server: BN_new failed"); + + if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) + fatal("kexgss_server: BN_bin2bn failed"); + memset(kbuf, 0, klen); xfree(kbuf); @@ -233,7 +244,7 @@ kexgss_server(Kex *kex) fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); } - BN_free(dh_client_pub); + BN_clear_free(dh_client_pub); if (kex->session_id == NULL) { kex->session_id_len = hashlen; @@ -272,6 +283,11 @@ kexgss_server(Kex *kex) kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); + + /* If this was a rekey, then save out any delegated credentials we + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); } static void diff --git a/openssh/misc.c b/openssh/misc.c index 83efded..c447d23 100644 --- a/openssh/misc.c +++ b/openssh/misc.c @@ -237,6 +237,20 @@ pwcopy(struct passwd *pw) return copy; } +void +pwfree(struct passwd *pw) +{ + xfree(pw->pw_name); + xfree(pw->pw_passwd); + xfree(pw->pw_gecos); +#ifdef HAVE_PW_CLASS_IN_PASSWD + xfree(pw->pw_class); +#endif + xfree(pw->pw_dir); + xfree(pw->pw_shell); + xfree(pw); +} + /* * Convert ASCII string to TCP/IP port number. * Port must be >=0 and <=65535. diff --git a/openssh/misc.h b/openssh/misc.h index 5da170d..b7299e3 100644 --- a/openssh/misc.h +++ b/openssh/misc.h @@ -37,6 +37,7 @@ void ms_subtract_diff(struct timeval *, int *); void ms_to_timeval(struct timeval *, int); struct passwd *pwcopy(struct passwd *); +void pwfree(struct passwd *); const char *ssh_gai_strerror(int); typedef struct arglist arglist; diff --git a/openssh/monitor.c b/openssh/monitor.c index bc018a4..e0434d5 100644 --- a/openssh/monitor.c +++ b/openssh/monitor.c @@ -174,6 +174,7 @@ int mm_answer_gss_sign(int, Buffer *); int mm_answer_gss_error(int, Buffer *); int mm_answer_gss_indicate_mechs(int, Buffer *); int mm_answer_gss_localname(int, Buffer *); +int mm_answer_gss_updatecreds(int, Buffer *); #endif #ifdef SSH_AUDIT_EVENTS @@ -265,6 +266,7 @@ struct mon_table mon_dispatch_postauth20[] = { {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error}, {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, #endif {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, {MONITOR_REQ_SIGN, 0, mm_answer_sign}, @@ -1737,9 +1739,11 @@ mm_get_kex(Buffer *m) kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; #ifdef GSSAPI - kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; - kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; - kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; + } #endif kex->server = 1; kex->hostkey_type = buffer_get_int(m); @@ -1940,6 +1944,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m) OM_uint32 major; u_int len; + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + goid.elements = buffer_get_string(m, &len); goid.length = len; @@ -1967,6 +1974,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) OM_uint32 flags = 0; /* GSI needs this */ u_int len; + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + in.value = buffer_get_string(m, &len); in.length = len; major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); @@ -1997,6 +2007,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m) OM_uint32 ret; u_int len; + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + gssbuf.value = buffer_get_string(m, &len); gssbuf.length = len; mic.value = buffer_get_string(m, &len); @@ -2023,7 +2036,11 @@ mm_answer_gss_userok(int sock, Buffer *m) { int authenticated; - authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + + authenticated = authctxt->valid && + ssh_gssapi_userok(authctxt->user, authctxt->pw); buffer_clear(m); buffer_put_int(m, authenticated); @@ -2037,43 +2054,6 @@ mm_answer_gss_userok(int sock, Buffer *m) return (authenticated); } -int -mm_answer_gss_sign(int socket, Buffer *m) -{ - gss_buffer_desc data; - gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; - OM_uint32 major, minor; - u_int len; - - data.value = buffer_get_string(m, &len); - data.length = len; - if (data.length != 20) - fatal("%s: data length incorrect: %d", __func__, (int)data.length); - - /* Save the session ID on the first time around */ - if (session_id2_len == 0) { - session_id2_len = data.length; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, data.value, session_id2_len); - } - major = ssh_gssapi_sign(gsscontext, &data, &hash); - - xfree(data.value); - - buffer_clear(m); - buffer_put_int(m, major); - buffer_put_string(m, hash.value, hash.length); - - mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); - - gss_release_buffer(&minor, &hash); - - /* Turn on getpwnam permissions */ - monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); - - return (0); -} - int mm_answer_gss_error(int socket, Buffer *m) { OM_uint32 major,minor; @@ -2137,6 +2117,74 @@ mm_answer_gss_localname(int socket, Buffer *m) { return(0); } + +int +mm_answer_gss_sign(int socket, Buffer *m) +{ + gss_buffer_desc data; + gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; + OM_uint32 major, minor; + u_int len; + + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + + data.value = buffer_get_string(m, &len); + data.length = len; + if (data.length != 20) + fatal("%s: data length incorrect: %d", __func__, + (int) data.length); + + /* Save the session ID on the first time around */ + if (session_id2_len == 0) { + session_id2_len = data.length; + session_id2 = xmalloc(session_id2_len); + memcpy(session_id2, data.value, session_id2_len); + } + major = ssh_gssapi_sign(gsscontext, &data, &hash); + + xfree(data.value); + + buffer_clear(m); + buffer_put_int(m, major); + buffer_put_string(m, hash.value, hash.length); + + mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); + + gss_release_buffer(&minor, &hash); + + /* Turn on getpwnam permissions */ + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + /* And credential updating, for when rekeying */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); + + return (0); +} + +int +mm_answer_gss_updatecreds(int socket, Buffer *m) { + 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); + + xfree(store.filename); + xfree(store.envvar); + xfree(store.envval); + + buffer_clear(m); + buffer_put_int(m, ok); + + mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); + + return(0); +} + #endif /* GSSAPI */ #ifdef JPAKE diff --git a/openssh/monitor.h b/openssh/monitor.h index 3b40f13..9219f4a 100644 --- a/openssh/monitor.h +++ b/openssh/monitor.h @@ -57,6 +57,7 @@ enum monitor_reqtype { MONITOR_REQ_GSSERR, MONITOR_ANS_GSSERR, MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, + MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS, MONITOR_REQ_PAM_START, MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, diff --git a/openssh/monitor_wrap.c b/openssh/monitor_wrap.c index 368738f..a2bc3a6 100644 --- a/openssh/monitor_wrap.c +++ b/openssh/monitor_wrap.c @@ -1239,7 +1239,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) } int -mm_ssh_gssapi_userok(char *user) +mm_ssh_gssapi_userok(char *user, struct passwd *pw) { Buffer m; int authenticated = 0; @@ -1257,28 +1257,6 @@ mm_ssh_gssapi_userok(char *user) return (authenticated); } -OM_uint32 -mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) -{ - Buffer m; - OM_uint32 major; - u_int len; - - buffer_init(&m); - buffer_put_string(&m, data->value, data->length); - - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); - mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); - - major = buffer_get_int(&m); - hash->value = buffer_get_string(&m, &len); - hash->length = len; - - buffer_free(&m); - - return(major); -} - char * mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) { Buffer m; @@ -1356,6 +1334,50 @@ mm_ssh_gssapi_localname(char **lname) return(0); } +OM_uint32 +mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) +{ + Buffer m; + OM_uint32 major; + u_int len; + + buffer_init(&m); + buffer_put_string(&m, data->value, data->length); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); + + major = buffer_get_int(&m); + hash->value = buffer_get_string(&m, &len); + hash->length = len; + + buffer_free(&m); + + return(major); +} + +int +mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) +{ + Buffer m; + int ok; + + 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 : ""); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); + + ok = buffer_get_int(&m); + + buffer_free(&m); + + return (ok); +} + #endif /* GSSAPI */ #ifdef JPAKE diff --git a/openssh/monitor_wrap.h b/openssh/monitor_wrap.h index a190a26..e4a3d48 100644 --- a/openssh/monitor_wrap.h +++ b/openssh/monitor_wrap.h @@ -57,13 +57,14 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *); OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); -int mm_ssh_gssapi_userok(char *user); +int mm_ssh_gssapi_userok(char *user, struct passwd *); OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); int mm_ssh_gssapi_localname(char **user); OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set); char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); +int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); #endif #ifdef USE_PAM diff --git a/openssh/readconf.c b/openssh/readconf.c index 6d05b4e..0f29417 100644 --- a/openssh/readconf.c +++ b/openssh/readconf.c @@ -127,8 +127,7 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, - oGssKeyEx, - oGssTrustDns, + oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, @@ -171,11 +170,15 @@ static struct { { "gssapikeyexchange", oGssKeyEx }, { "gssapidelegatecredentials", oGssDelegateCreds }, { "gssapitrustdns", oGssTrustDns }, + { "gssapiclientidentity", oGssClientIdentity }, + { "gssapirenewalforcesrekey", oGssRenewalRekey }, #else { "gssapiauthentication", oUnsupported }, { "gssapikeyexchange", oUnsupported }, { "gssapidelegatecredentials", oUnsupported }, { "gssapitrustdns", oUnsupported }, + { "gssapiclientidentity", oUnsupported }, + { "gssapirenewalforcesrekey", oUnsupported }, #endif { "fallbacktorsh", oDeprecated }, { "usersh", oDeprecated }, @@ -235,25 +238,19 @@ static struct { { "tunneldevice", oTunnelDevice }, { "localcommand", oLocalCommand }, { "permitlocalcommand", oPermitLocalCommand }, - { "noneenabled", oNoneEnabled }, - { "tcprcvbufpoll", oTcpRcvBufPoll }, - { "tcprcvbuf", oTcpRcvBuf }, - { "noneswitch", oNoneSwitch }, - { "hpndisabled", oHPNDisabled }, - { "hpnbuffersize", oHPNBufferSize }, { "visualhostkey", oVisualHostKey }, - { "noneenabled", oNoneEnabled }, - { "tcprcvbufpoll", oTcpRcvBufPoll }, - { "tcprcvbuf", oTcpRcvBuf }, - { "noneswitch", oNoneSwitch }, - { "hpndisabled", oHPNDisabled }, - { "hpnbuffersize", oHPNBufferSize }, #ifdef JPAKE { "zeroknowledgepasswordauthentication", oZeroKnowledgePasswordAuthentication }, #else { "zeroknowledgepasswordauthentication", oUnsupported }, #endif + { "noneenabled", oNoneEnabled }, + { "tcprcvbufpoll", oTcpRcvBufPoll }, + { "tcprcvbuf", oTcpRcvBuf }, + { "noneswitch", oNoneSwitch }, + { "hpndisabled", oHPNDisabled }, + { "hpnbuffersize", oHPNBufferSize }, { NULL, oBadOption } }; @@ -473,7 +470,7 @@ parse_flag: goto parse_flag; case oGssKeyEx: - intptr = &options->gss_keyex; + intptr = &options->gss_keyex; goto parse_flag; case oGssDelegateCreds: @@ -484,6 +481,14 @@ parse_flag: intptr = &options->gss_trust_dns; goto parse_flag; + case oGssClientIdentity: + charptr = &options->gss_client_identity; + goto parse_string; + + case oGssRenewalRekey: + intptr = &options->gss_renewal_rekey; + goto parse_flag; + case oBatchMode: intptr = &options->batch_mode; goto parse_flag; @@ -1073,6 +1078,8 @@ initialize_options(Options * options) options->gss_keyex = -1; options->gss_deleg_creds = -1; options->gss_trust_dns = -1; + options->gss_renewal_rekey = -1; + options->gss_client_identity = NULL; options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; @@ -1141,6 +1148,12 @@ initialize_options(Options * options) options->tcp_rcv_buf_poll = -1; options->tcp_rcv_buf = -1; options->zero_knowledge_password_authentication = -1; + options->none_switch = -1; + options->none_enabled = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; + options->tcp_rcv_buf_poll = -1; + options->tcp_rcv_buf = -1; } /* @@ -1181,6 +1194,8 @@ fill_default_options(Options * options) options->gss_deleg_creds = 1; if (options->gss_trust_dns == -1) options->gss_trust_dns = 1; + if (options->gss_renewal_rekey == -1) + options->gss_renewal_rekey = 0; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) diff --git a/openssh/readconf.h b/openssh/readconf.h index 9396f17..12477c0 100644 --- a/openssh/readconf.h +++ b/openssh/readconf.h @@ -44,9 +44,11 @@ typedef struct { int challenge_response_authentication; /* Try S/Key or TIS, authentication. */ int gss_authentication; /* Try GSS authentication */ - int gss_keyex; /* Try GSS key exchange */ + int gss_keyex; /* Try GSS key exchange */ int gss_deleg_creds; /* Delegate GSS credentials */ int gss_trust_dns; /* Trust DNS for GSS canonicalization */ + int gss_renewal_rekey; /* Credential renewal forces rekey */ + char *gss_client_identity; /* Principal to initiate GSSAPI with */ int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ diff --git a/openssh/servconf.c b/openssh/servconf.c index a693e05..96a27f3 100644 --- a/openssh/servconf.c +++ b/openssh/servconf.c @@ -58,6 +58,7 @@ initialize_server_options(ServerOptions *options) /* Portable-specific options */ options->use_pam = -1; + options->permit_pam_user_change = -1; /* Standard Options */ options->num_ports = 0; @@ -102,6 +103,7 @@ initialize_server_options(ServerOptions *options) options->gss_cleanup_creds = -1; options->gss_strict_acceptor = -1; options->gsi_allow_limited_proxy = -1; + options->gss_store_rekey = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->challenge_response_authentication = -1; @@ -136,11 +138,11 @@ initialize_server_options(ServerOptions *options) options->num_permitted_opens = -1; options->adm_forced_command = NULL; options->chroot_directory = NULL; + options->zero_knowledge_password_authentication = -1; options->none_enabled = -1; options->tcp_rcv_buf_poll = -1; options->hpn_disabled = -1; options->hpn_buffer_size = -1; - options->zero_knowledge_password_authentication = -1; } void @@ -154,6 +156,8 @@ fill_default_server_options(ServerOptions *options) /* Portable-specific options */ if (options->use_pam == -1) options->use_pam = 0; + if (options->permit_pam_user_change == -1) + options->permit_pam_user_change = 0; /* Standard Options */ if (options->protocol == SSH_PROTO_UNKNOWN) @@ -238,6 +242,8 @@ fill_default_server_options(ServerOptions *options) options->gss_strict_acceptor = 1; if (options->gsi_allow_limited_proxy == -1) options->gsi_allow_limited_proxy = 0; + if (options->gss_store_rekey == -1) + options->gss_store_rekey = 0; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -343,7 +349,7 @@ fill_default_server_options(ServerOptions *options) typedef enum { sBadOption, /* == unknown option */ /* Portable-specific options */ - sUsePAM, + sUsePAM, sPermitPAMUserChange, /* Standard Options */ sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, @@ -367,17 +373,16 @@ typedef enum { sBanner, sUseDNS, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, - sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds, - sGssStrictAcceptor, - sGssKeyEx, sGssCredsPath, sGsiAllowLimitedProxy, - sAcceptEnv, sPermitTunnel, + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssKeyEx, sGssStoreRekey, + sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, - sNoneEnabled, sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, sZeroKnowledgePasswordAuthentication, + sNoneEnabled, sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, sDeprecated, sUnsupported } ServerOpCodes; @@ -394,8 +399,10 @@ static struct { /* Portable-specific options */ #ifdef USE_PAM { "usepam", sUsePAM, SSHCFG_GLOBAL }, + { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL } #else { "usepam", sUnsupported, SSHCFG_GLOBAL }, + { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL }, #endif { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, /* Standard Options */ @@ -437,22 +444,24 @@ static struct { { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, #ifdef GSI { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL }, #endif + { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, #ifdef GSI { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, #endif + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, #endif #ifdef SESSION_HOOKS { "allowsessionhooks", sAllowSessionHooks, SSHCFG_GLOBAL }, @@ -777,6 +786,10 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->use_pam; goto parse_flag; + case sPermitPAMUserChange: + intptr = &options->permit_pam_user_change; + goto parse_flag; + /* Standard Options */ case sBadOption: return -1; @@ -1015,17 +1028,23 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->gss_cleanup_creds; goto parse_flag; + case sGssCredsPath: + charptr = &options->gss_creds_path; + goto parse_filename; + case sGssStrictAcceptor: intptr = &options->gss_strict_acceptor; goto parse_flag; - case sGssCredsPath: - charptr = &options->gss_creds_path; - goto parse_filename; + case sGssStoreRekey: + intptr = &options->gss_store_rekey; + goto parse_flag; +#ifdef GSI case sGsiAllowLimitedProxy: intptr = &options->gsi_allow_limited_proxy; goto parse_flag; +#endif #ifdef SESSION_HOOKS case sAllowSessionHooks: diff --git a/openssh/servconf.h b/openssh/servconf.h index 6ca0980..2c9f00e 100644 --- a/openssh/servconf.h +++ b/openssh/servconf.h @@ -95,13 +95,14 @@ typedef struct { #endif int kerberos_get_afs_token; /* If true, try to get AFS token if * authenticated with Kerberos. */ + int gsi_allow_limited_proxy; /* If true, accept limited proxies */ int gss_authentication; /* If true, permit GSSAPI authentication */ int gss_deleg_creds; /* If true, store delegated GSSAPI credentials*/ - int gss_keyex; /* If true, permit GSSAPI key exchange */ + int gss_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ char* gss_creds_path; /* If true, destroy cred cache on logout */ - int gsi_allow_limited_proxy; /* If true, accept limited proxies */ + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; int password_authentication; /* If true, permit password * authentication. */ int kbd_interactive_authentication; /* If true, permit */ @@ -155,6 +156,7 @@ typedef struct { char *adm_forced_command; int use_pam; /* Enable auth via PAM */ + int permit_pam_user_change; /* Allow PAM to change user name */ int none_enabled; /* enable NONE cipher switch */ int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ int hpn_disabled; /* disable hpn functionality. false by default */ diff --git a/openssh/ssh-gss.h b/openssh/ssh-gss.h index d751c63..9d39d3f 100644 --- a/openssh/ssh-gss.h +++ b/openssh/ssh-gss.h @@ -1,6 +1,6 @@ /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -80,6 +80,7 @@ typedef struct { char *filename; char *envvar; char *envval; + struct passwd *owner; void *data; } ssh_gssapi_ccache; @@ -87,9 +88,12 @@ typedef struct { gss_buffer_desc displayname; gss_buffer_desc exportedname; gss_cred_id_t creds; + gss_name_t name; struct ssh_gssapi_mech_struct *mech; ssh_gssapi_ccache store; gss_ctx_id_t context; + int used; + int updated; } ssh_gssapi_client; typedef struct ssh_gssapi_mech_struct { @@ -100,6 +104,7 @@ typedef struct ssh_gssapi_mech_struct { int (*userok) (ssh_gssapi_client *, char *); int (*localname) (ssh_gssapi_client *, char **); void (*storecreds) (ssh_gssapi_client *); + int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); } ssh_gssapi_mech; typedef struct { @@ -110,7 +115,7 @@ typedef struct { gss_OID oid; /* both */ gss_cred_id_t creds; /* server */ gss_name_t client; /* server */ - gss_cred_id_t client_creds; /* server */ + gss_cred_id_t client_creds; /* both */ } Gssctxt; extern ssh_gssapi_mech *supported_mechs[]; @@ -134,24 +139,28 @@ void ssh_gssapi_build_ctx(Gssctxt **); void ssh_gssapi_delete_ctx(Gssctxt **); OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); -int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); +int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); +OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); +int ssh_gssapi_credentials_updated(Gssctxt *); int ssh_gssapi_localname(char **name); +void ssh_gssapi_rekey_creds(); /* In the server */ -typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *); -char *ssh_gssapi_client_mechanisms(const char *host); -char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *); +typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, + const char *); +char *ssh_gssapi_client_mechanisms(const char *, const char *); +char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, + const char *); gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); -int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *); +int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, + const char *); OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); -int ssh_gssapi_userok(char *name); +int ssh_gssapi_userok(char *name, struct passwd *); 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); -char * ssh_gssapi_server_mechanisms(void); -int ssh_gssapi_oid_table_ok(); #ifdef MECHGLUE gss_cred_id_t __gss_get_mechanism_cred @@ -160,6 +169,10 @@ gss_cred_id_t __gss_get_mechanism_cred ); #endif +char *ssh_gssapi_server_mechanisms(void); +int ssh_gssapi_oid_table_ok(); + +int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); #endif /* GSSAPI */ #endif /* _SSH_GSS_H */ diff --git a/openssh/ssh_config.5 b/openssh/ssh_config.5 index 073d038..a72a35b 100644 --- a/openssh/ssh_config.5 +++ b/openssh/ssh_config.5 @@ -490,18 +490,28 @@ GSSAPI key exchange the server need not have a host key. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm GSSAPIClientIdentity +If set, specifies the GSSAPI client identity that ssh should use when +connecting to the server. The default is unset, which means that the default +identity will be used. .It Cm GSSAPIDelegateCredentials Forward (delegate) credentials to the server. The default is .Dq yes . -Note that this option applies to protocol version 2 only. +Note that this option applies to protocol version 2 connections using GSSAPI. +.It Cm GSSAPIRenewalForcesRekey +If set to +.Dq yes +then renewal of the client's GSSAPI credentials will force the rekeying of the +ssh connection. With a compatible server, this can delegate the renewed +credentials to a session on the server. +The default is +.Dq yes . .It Cm GSSAPITrustDns Set to -.Dq yes -to indicate that the DNS is trusted to securely canonicalize +.Dq yes to indicate that the DNS is trusted to securely canonicalize the name of the host being connected to. If -.Dq no , -the hostname entered on the +.Dq no, the hostname entered on the command line will be passed untouched to the GSSAPI library. The default is .Dq yes . diff --git a/openssh/sshconnect2.c b/openssh/sshconnect2.c index 4696f34..c7aadb4 100644 --- a/openssh/sshconnect2.c +++ b/openssh/sshconnect2.c @@ -78,6 +78,12 @@ extern char *client_version_string; extern char *server_version_string; extern Options options; +extern Kex *xxx_kex; + +/* tty_flag is set in ssh.c. use this in ssh_userauth2 */ +/* if it is set then prevent the switch to the null cipher */ + +extern int tty_flag; /* tty_flag is set in ssh.c. use this in ssh_userauth2 */ /* if it is set then prevent the switch to the null cipher */ @@ -133,7 +139,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) else gss_host = host; - gss = ssh_gssapi_client_mechanisms(gss_host); + gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); if (gss) { debug("Offering GSSAPI proposal: %s", gss); xasprintf(&myproposal[PROPOSAL_KEX_ALGS], @@ -176,6 +182,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], "%s,null", orig); + xfree(gss); } #endif @@ -189,18 +196,23 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; #ifdef GSSAPI - kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; - kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; - kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; + } #endif kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; #ifdef GSSAPI - kex->gss_deleg_creds = options.gss_deleg_creds; - kex->gss_trust_dns = options.gss_trust_dns; - kex->gss_host = gss_host; + if (options.gss_keyex) { + kex->gss_deleg_creds = options.gss_deleg_creds; + kex->gss_trust_dns = options.gss_trust_dns; + kex->gss_client = options.gss_client_identity; + kex->gss_host = gss_host; + } #endif xxx_kex = kex; @@ -654,14 +666,18 @@ userauth_gssapi(Authctxt *authctxt) * once. */ if (gss_supported == NULL) - gss_indicate_mechs(&min, &gss_supported); + if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { + gss_supported = NULL; + return 0; + } /* Check to see if the mechanism is usable before we offer it */ while (mech < gss_supported->count && !ok) { /* My DER encoding requires length<128 */ if (gss_supported->elements[mech].length < 128 && ssh_gssapi_check_mechanism(&gssctxt, - &gss_supported->elements[mech], gss_host)) { + &gss_supported->elements[mech], gss_host, + options.gss_client_identity)) { ok = 1; /* Mechanism works */ } else { mech++; @@ -883,10 +899,10 @@ const gss_OID_desc * const gss_mech_globus_gssapi_openssl; int userauth_external(Authctxt *authctxt) { - static int attempt = 0; + static int attempt = 0; - if (attempt++ >= 1) - return 0; + if (attempt++ >= 1) + return 0; /* The client MUST NOT try this method if initial key exchange was not performed using a GSSAPI-based key exchange @@ -896,22 +912,22 @@ userauth_external(Authctxt *authctxt) return 0; } - debug2("userauth_external"); - packet_start(SSH2_MSG_USERAUTH_REQUEST); + debug2("userauth_external"); + packet_start(SSH2_MSG_USERAUTH_REQUEST); #ifdef GSI - if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { - packet_put_cstring(""); + if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { + packet_put_cstring(""); } else { #endif - packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->server_user); #ifdef GSI } #endif - packet_put_cstring(authctxt->service); - packet_put_cstring(authctxt->method->name); - packet_send(); - packet_write_wait(); - return 1; + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_send(); + packet_write_wait(); + return 1; } int userauth_gsskeyex(Authctxt *authctxt) @@ -931,12 +947,12 @@ userauth_gsskeyex(Authctxt *authctxt) } #ifdef GSI - if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { - ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex"); + if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { + ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex"); } else { #endif - ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, - "gssapi-keyex"); + ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, + "gssapi-keyex"); #ifdef GSI } #endif @@ -951,8 +967,8 @@ userauth_gsskeyex(Authctxt *authctxt) packet_start(SSH2_MSG_USERAUTH_REQUEST); #ifdef GSI - if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { - packet_put_cstring(""); + if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { + packet_put_cstring(""); } else { #endif packet_put_cstring(authctxt->server_user); diff --git a/openssh/sshd.c b/openssh/sshd.c index 04eeb8b..b52ec48 100644 --- a/openssh/sshd.c +++ b/openssh/sshd.c @@ -1802,6 +1802,9 @@ main(int ac, char **av) cleanup_exit(255); } + /* set the HPN options for the child */ + channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); + /* * We use get_canonical_hostname with usedns = 0 instead of * get_remote_ipaddr here so IP options will be checked. @@ -1893,9 +1896,6 @@ main(int ac, char **av) } #endif - /* set the HPN options for the child */ - channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); - /* * We don't want to listen forever unless the other side * successfully authenticates itself. So we set up an alarm which is @@ -2328,7 +2328,6 @@ do_ssh2_kex(void) } #endif - /* start key exchange */ /* start key exchange */ kex = kex_setup(myproposal); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; @@ -2336,9 +2335,11 @@ do_ssh2_kex(void) kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; #ifdef GSSAPI - kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; - kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; - kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; + } #endif kex->server = 1; kex->client_version_string=client_version_string; diff --git a/openssh/sshd_config b/openssh/sshd_config index badf4af..309170d 100644 --- a/openssh/sshd_config +++ b/openssh/sshd_config @@ -93,6 +93,10 @@ Protocol 2 # and ChallengeResponseAuthentication to 'no'. #UsePAM yes +# Set to 'yes' to allow the PAM stack to change the user name during +# calls to authentication +#PermitPAMUserChange no + #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no diff --git a/openssh/sshd_config.5 b/openssh/sshd_config.5 index 6649d32..0602495 100644 --- a/openssh/sshd_config.5 +++ b/openssh/sshd_config.5 @@ -390,6 +390,22 @@ on logout. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm GSSAPICredentialsPath +If specified, the delegated GSSAPI credential is stored in the +given path, overwriting any existing credentials. +Paths can be specified with syntax similar to the AuthorizedKeysFile +option (i.e., accepting %h and %u tokens). +When using this option, +setting 'GssapiCleanupCredentials no' is recommended, +so logging out of one session +doesn't remove the credentials in use by another session of +the same user. +Currently only implemented for the GSI mechanism. +.It Cm GSIAllowLimitedProxy +Specifies whether to accept limited proxy credentials for +authentication. +The default is +.Dq no . .It Cm GSSAPIStrictAcceptorCheck Determines whether to be strict about the identity of the GSSAPI acceptor a client authenticates against. If @@ -407,21 +423,10 @@ Note that this option applies only to protocol version 2 GSSAPI connections, and setting it to .Dq no may only work with recent Kerberos GSSAPI libraries. -.It Cm GSSAPICredentialsPath -If specified, the delegated GSSAPI credential is stored in the -given path, overwriting any existing credentials. -Paths can be specified with syntax similar to the AuthorizedKeysFile -option (i.e., accepting %h and %u tokens). -When using this option, -setting 'GssapiCleanupCredentials no' is recommended, -so logging out of one session -doesn't remove the credentials in use by another session of -the same user. -Currently only implemented for the GSI mechanism. -.It Cm GSIAllowLimitedProxy -Specifies whether to accept limited proxy credentials for -authentication. -The default is +.It Cm GSSAPIStoreCredentialsOnRekey +Controls whether the user's GSSAPI credentials should be updated following a +successful connection rekeying. This option can be used to accepted renewed +or updated credentials from a compatible client. The default is .Dq no . .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together @@ -966,6 +971,12 @@ is enabled, you will not be able to run as a non-root user. The default is .Dq no . +.It Cm PermitPAMUserChange +If set to +.Dq yes +this will enable PAM authentication to change the name of the user being +authenticated. The default is +.Dq no . .It Cm UsePrivilegeSeparation Specifies whether .Xr sshd 8 diff --git a/openssh/version.h b/openssh/version.h index 74ae653..fc7e5c3 100644 --- a/openssh/version.h +++ b/openssh/version.h @@ -18,11 +18,11 @@ #define MGLUE_VERSION "" #endif -#define NCSA_VERSION " GLOBUS_GSSAPI_GPT_4.6" +#define NCSA_VERSION " GLOBUS_GSSAPI_GPT_4.7" #define SSH_VERSION "OpenSSH_5.2" #define SSH_PORTABLE "p1" -#define SSH_HPN "-hpn13v5" +#define SSH_HPN "-hpn13v6" #define SSH_RELEASE SSH_VERSION SSH_PORTABLE SSH_HPN \ NCSA_VERSION GSI_VERSION KRB5_VERSION MGLUE_VERSION -- 2.45.2