/*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "servconf.h"
#include "compat.h"
#include "misc.h"
-#include "monitor_wrap.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;
char *envvar;
} 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
NULL
};
-static void gssapi_unsetenv(const char *var);
-
#ifdef KRB5
#ifdef HEIMDAL
krb5_free_principal(krb_context, princ);
return retval;
}
-
-int
-ssh_gssapi_krb5_localname(char **user)
-{
- krb5_principal princ;
-
- if (krb5_parse_name(krb_context, gssapi_client_name.value, &princ)) {
- return(0);
- }
- *user = (char *)xmalloc(256);
- if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
- xfree(*user);
- *user = NULL;
- return(0);
- }
- return(1);
-}
/* Make sure that this is called _after_ we've setuid to the user */
#endif /* KRB5 */
#ifdef GSI
-#include <globus_gss_assist.h>
+#include "globus_gss_assist_gsi.h"
/*
* Check if this user is OK to login under GSI. User has been authenticated
return authorized;
}
-/*
- * Return the local username associated with the GSI credentials.
- */
-int
-ssh_gssapi_gsi_localname(char **user)
-{
- return(globus_gss_assist_gridmap(gssapi_client_name.value, user) == 0);
-}
-
/*
* Handle setting up child environment for GSI.
*
ssh_gssapi_storecreds()
{
switch (gssapi_client_type) {
-#ifdef KRB5
- case GSS_KERBEROS:
- ssh_gssapi_krb5_storecreds();
- break;
-#endif
#ifdef GSI
case GSS_GSI:
ssh_gssapi_gsi_storecreds();
break;
#endif /* GSI */
+#ifdef KRB5
+ case GSS_KERBEROS:
+ ssh_gssapi_krb5_storecreds();
+ break;
+#endif
case GSS_LAST_ENTRY:
/* GSSAPI not used in this authentication */
debug("No GSSAPI credentials stored");
}
int
-ssh_gssapi_localname(char **user)
+userauth_external(Authctxt *authctxt)
{
- *user = NULL;
- if (gssapi_client_name.length==0 ||
- gssapi_client_name.value==NULL) {
- debug("No suitable client data");
- return(0);;
+ packet_check_eom();
+
+ return(ssh_gssapi_userok(authctxt->user));
+}
+
+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
+ */
+int
+userauth_gssapi(Authctxt *authctxt)
+{
+ gss_OID_desc oid= {0,NULL};
+ Gssctxt *ctxt;
+ int mechs;
+ 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;
}
- switch (gssapi_client_type) {
-#ifdef KRB5
- case GSS_KERBEROS:
- return(ssh_gssapi_krb5_localname(user));
- break; /* Not reached */
-#endif
-#ifdef GSI
- case GSS_GSI:
- return(ssh_gssapi_gsi_localname(user));
- break; /* Not reached */
-#endif /* GSI */
- case GSS_LAST_ENTRY:
- debug("Client not GSSAPI");
- break;
- default:
- debug("Unknown client authentication type");
+
+ mechs=packet_get_int();
+ if (mechs==0) {
+ debug("Mechanism negotiation is not supported");
+ return 0;
}
- return(0);
+
+ ssh_gssapi_supported_oids(&supported);
+ do {
+ if (oid.elements)
+ xfree(oid.elements);
+ oid.elements = packet_get_string(&len);
+ oid.length = len;
+ gss_test_oid_set_member(&ms, &oid, supported, &present);
+ mechs--;
+ } while (mechs>0 && !present);
+
+ if (!present) {
+ xfree(oid.elements);
+ return(0);
+ }
+
+ ctxt=xmalloc(sizeof(Gssctxt));
+ authctxt->methoddata=(void *)ctxt;
+
+ ssh_gssapi_build_ctx(ctxt);
+ ssh_gssapi_set_oid(ctxt,&oid);
+
+ if (ssh_gssapi_acquire_cred(ctxt))
+ return 0;
+
+ /* 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;
+
+ return 0;
+}
+
+void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ gss_buffer_desc send_tok,recv_tok;
+ OM_uint32 maj_status, min_status;
+
+ if (authctxt == NULL || authctxt->methoddata == NULL)
+ fatal("No authentication or GSSAPI context");
+
+ gssctxt=authctxt->methoddata;
+
+ recv_tok.value=packet_get_string(&recv_tok.length);
+
+ maj_status=ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok, NULL);
+ packet_check_eom();
+
+ if (GSS_ERROR(maj_status)) {
+ /* Failure <sniff> */
+ ssh_gssapi_send_error(maj_status,min_status);
+ 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);
+ }
+
+ if (maj_status == GSS_S_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);
+ }
+}
+
+/* This is called when the client thinks we've completed authentication.
+ * It should only be enabled in the dispatch handler by the function above,
+ * which only enables it once the GSSAPI exchange is complete.
+ */
+
+void
+input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ int authenticated;
+
+ if(strcmp(authctxt->user,"") == 0) {
+ char *user;
+ char *gridmapped_name = NULL;
+ struct passwd *pw = NULL;
+ if(globus_gss_assist_gridmap(gssapi_client_name.value,
+ &gridmapped_name) == 0) {
+ user = gridmapped_name;
+ debug("I gridmapped and got %s", user);
+ pw = getpwnam(user);
+ if (pw && allowed_user(pw)) {
+ authctxt->user = user;
+ authctxt->pw = pwcopy(pw);
+ authctxt->valid = 1;
+ }
+ }
+ }
+
+
+ if (authctxt == NULL || authctxt->methoddata == NULL)
+ fatal("No authentication or GSSAPI context");
+
+ gssctxt=authctxt->methoddata;
+
+ /* This should never happen, but better safe than sorry. */
+ if (gssctxt->status != GSS_S_COMPLETE) {
+ packet_disconnect("Context negotiation is not complete");
+ }
+
+ if (ssh_gssapi_getclient(gssctxt,&gssapi_client_type,
+ &gssapi_client_name,
+ &gssapi_client_creds)) {
+ fatal("Couldn't convert client name");
+ }
+
+ 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);
+ } else {
+ packet_start(SSH_MSG_AUTH_GSSAPI_ABORT);
+ packet_send();
+ packet_write_wait();
+ }
+ }
+
+ 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");
}
/*
/*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _SSH_GSS_H
-#define _SSH_GSS_H
-
#ifdef GSSAPI
#include "kex.h"
#include "buffer.h"
-#include <gssapi.h>
+#include "gssapi_krb.h"
#ifdef KRB5
#ifndef HEIMDAL
-#include <gssapi_generic.h>
/* MIT Kerberos doesn't seem to define GSS_NT_HOSTBASED_SERVICE */
#endif /* !HEIMDAL */
#endif /* KRB5 */
-/* draft-ietf-secsh-gsskeyex-03 */
-#define SSH2_MSG_KEXGSS_INIT 30
-#define SSH2_MSG_KEXGSS_CONTINUE 31
-#define SSH2_MSG_KEXGSS_COMPLETE 32
-#define SSH2_MSG_KEXGSS_HOSTKEY 33
-#define SSH2_MSG_KEXGSS_ERROR 34
-#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60
-#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61
+/* draft-ietf-secsh-gsskeyex-01 */
+#define SSH2_MSG_KEXGSS_INIT 30
+#define SSH2_MSG_KEXGSS_CONTINUE 31
+#define SSH2_MSG_KEXGSS_COMPLETE 32
+#define SSH2_MSG_KEXGSS_HOSTKEY 33
+#define KEX_GSS_SHA1 "gss-group1-sha1-"
+
+/* draft-galb-secsh-gssapi-01 */
+#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60
+#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61
+#define SSH2_MSG_USERAUTH_GSSAPI_HASH 62
#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63
-#define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64
-
-#define KEX_GSS_SHA1 "gss-group1-sha1-"
enum ssh_gss_id {
-#ifdef KRB5
- GSS_KERBEROS,
-#endif
#ifdef GSI
GSS_GSI,
#endif /* GSI */
+#ifdef KRB5
+ GSS_KERBEROS,
+#endif
GSS_LAST_ENTRY
};
extern enum ssh_gss_id gssapi_client_type;
char *ssh_gssapi_mechanisms(int server, char *host);
-gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
+int ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len);
void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid);
void ssh_gssapi_supported_oids(gss_OID_set *oidset);
gss_cred_id_t *creds);
void ssh_gssapi_error(OM_uint32 major_status,OM_uint32 minor_status);
void ssh_gssapi_send_error(OM_uint32 major_status,OM_uint32 minor_status);
-void ssh_gssapi_build_ctx(Gssctxt **ctx);
-void ssh_gssapi_delete_ctx(Gssctxt **ctx);
-OM_uint32 ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid,char *host);
-OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid);
+void ssh_gssapi_build_ctx(Gssctxt *ctx);
+void ssh_gssapi_delete_ctx(Gssctxt *ctx);
/* In the client */
void ssh_gssapi_client(Kex *kex, char *host, struct sockaddr *hostaddr,
Buffer *client_kexinit, Buffer *server_kexinit);
/* In the server */
-int ssh_gssapi_userok(char *name);
-int ssh_gssapi_localname(char **lname);
void ssh_gssapi_server(Kex *kex, Buffer *client_kexinit,
Buffer *server_kexinit);
-
-OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer,
- gss_buffer_desc *hash);
-
void ssh_gssapi_do_child(char ***envp, u_int *envsizep);
void ssh_gssapi_cleanup_creds(void *ignored);
void ssh_gssapi_storecreds();
void ssh_gssapi_clean_env();
-
-#ifdef GSI
-int gsi_gridmap(char *subject_name, char **mapped_name);
-#endif
#endif /* GSSAPI */
-
-#endif /* _SSH_GSS_H */