#ifdef GSSAPI
#include "ssh.h"
+#include "ssh1.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "buffer.h"
#include "kex.h"
#include "auth.h"
#include "log.h"
+#include "channels.h"
#include "session.h"
#include "dispatch.h"
#include "servconf.h"
+#include "compat.h"
#include "ssh-gss.h"
extern u_char *session_id2;
extern int session_id2_len;
+void userauth_reply(Authctxt *authctxt, int authenticated);
+static void gssapi_unsetenv(const char *var);
typedef struct ssh_gssapi_cred_cache {
char *filename;
} ssh_gssapi_cred_cache;
static struct ssh_gssapi_cred_cache gssapi_cred_store = {NULL,NULL,NULL};
+unsigned char ssh1_key_digest[16]; /* used for ssh1 gssapi */
+
+/*
+ * Environment variables pointing to delegated credentials
+ */
+static char *delegation_env[] = {
+ "X509_USER_PROXY", /* GSSAPI/SSLeay */
+ "KRB5CCNAME", /* Krb5 and possibly SSLeay */
+ NULL
+};
#ifdef KRB5
#endif
case GSS_LAST_ENTRY:
debug("No GSSAPI credentials stored");
-
+ break;
default:
log("ssh_gssapi_do_child: Unknown mechanism");
}
int
userauth_external(Authctxt *authctxt)
{
- packet_done();
+ packet_check_eom();
return(ssh_gssapi_userok(authctxt->user));
}
-void input_gssapi_token(int type, int plen, void *ctxt);
-void input_gssapi_exchange_complete(int type, int plen, void *ctxt);
+void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
/* We only support those mechanisms that we know about (ie ones that we know
* how to check local user kuserok and the like
gss_OID_set supported;
int present;
OM_uint32 ms;
+ u_int len;
if (!authctxt->valid || authctxt->user == NULL)
return 0;
+
+ if (datafellows & SSH_OLD_GSSAPI) {
+ debug("Early drafts of GSSAPI userauth not supported");
+ return 0;
+ }
+
mechs=packet_get_int();
if (mechs==0) {
debug("Mechanism negotiation is not supported");
do {
if (oid.elements)
xfree(oid.elements);
- oid.elements = packet_get_string(&oid.length);
+ oid.elements = packet_get_string(&len);
+ oid.length = len;
gss_test_oid_set_member(&ms, &oid, supported, &present);
mechs--;
} while (mechs>0 && !present);
/* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
+ if (!compat20)
+ packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
+ else
packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
packet_put_string(oid.elements,oid.length);
packet_send();
packet_write_wait();
xfree(oid.elements);
+ if (!compat20)
+ dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN,
+ &input_gssapi_token);
+ else
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,
&input_gssapi_token);
authctxt->postponed = 1;
}
void
-input_gssapi_token(int type, int plen, void *ctxt)
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
recv_tok.value=packet_get_string(&recv_tok.length);
maj_status=ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok, NULL);
- packet_done();
+ packet_check_eom();
if (GSS_ERROR(maj_status)) {
/* Failure <sniff> */
authctxt->postponed = 0;
+ dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
userauth_finish(authctxt, 0, "gssapi");
}
if (send_tok.length != 0) {
/* Send a packet back to the client */
+ if (!compat20)
+ packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+ else
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
packet_put_string(send_tok.value,send_tok.length);
packet_send();
packet_write_wait();
- gss_release_buffer(&min_status, &send_tok);
+ gss_release_buffer(&min_status, &send_tok);
}
if (maj_status == GSS_S_COMPLETE) {
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
- &input_gssapi_exchange_complete);
+ dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
+ /* ssh1 does not have an extra message here */
+ if (!compat20)
+ input_gssapi_exchange_complete(0, 0, ctxt);
+ else
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+ &input_gssapi_exchange_complete);
}
}
*/
void
-input_gssapi_exchange_complete(int type, int plen, void *ctxt)
+input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
authenticated = ssh_gssapi_userok(authctxt->user);
+ /* ssh1 needs to exchange the hash of the keys */
+ if (!compat20) {
+ if (authenticated) {
+
+ OM_uint32 maj_status, min_status;
+ gss_buffer_desc gssbuf,msg_tok;
+
+ /* ssh1 uses wrap */
+ gssbuf.value=ssh1_key_digest;
+ gssbuf.length=sizeof(ssh1_key_digest);
+ if ((maj_status=gss_wrap(&min_status,
+ gssctxt->context,
+ 0,
+ GSS_C_QOP_DEFAULT,
+ &gssbuf,
+ NULL,
+ &msg_tok))) {
+ ssh_gssapi_error(maj_status,min_status);
+ fatal("Couldn't wrap keys");
+ }
+ packet_start(SSH_SMSG_AUTH_GSSAPI_HASH);
+ packet_put_string((char *)msg_tok.value,msg_tok.length);
+ packet_send();
+ packet_write_wait();
+ gss_release_buffer(&min_status,&msg_tok);
+ }
+ }
+
authctxt->postponed = 0;
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
userauth_finish(authctxt, authenticated, "gssapi");
}
+/*
+ * Clean our environment on startup. This means removing any environment
+ * strings that might inadvertantly been in root's environment and
+ * could cause serious security problems if we think we set them.
+ */
+void
+ssh_gssapi_clean_env(void)
+{
+ char *envstr;
+ int envstr_index;
+
+
+ for (envstr_index = 0;
+ (envstr = delegation_env[envstr_index]) != NULL;
+ envstr_index++) {
+
+ if (getenv(envstr)) {
+ debug("Clearing environment variable %s", envstr);
+ gssapi_unsetenv(envstr);
+ }
+ }
+}
+
+/*
+ * Wrapper around unsetenv.
+ */
+static void
+gssapi_unsetenv(const char *var)
+{
+#ifdef HAVE_UNSETENV
+ unsetenv(var);
+
+#else /* !HAVE_UNSETENV */
+ extern char **environ;
+ char **p1 = environ; /* New array list */
+ char **p2 = environ; /* Current array list */
+ int len = strlen(var);
+
+ /*
+ * Walk through current environ array (p2) copying each pointer
+ * to new environ array (p1) unless the pointer is to the item
+ * we want to delete. Copy happens in place.
+ */
+ while (*p2) {
+ if ((strncmp(*p2, var, len) == 0) &&
+ ((*p2)[len] == '=')) {
+ /*
+ * *p2 points at item to be deleted, just skip over it
+ */
+ p2++;
+ } else {
+ /*
+ * *p2 points at item we want to save, so copy it
+ */
+ *p1 = *p2;
+ p1++;
+ p2++;
+ }
+ }
+
+ /* And make sure new array is NULL terminated */
+ *p1 = NULL;
+#endif /* HAVE_UNSETENV */
+}
+
#endif /* GSSAPI */