#include "cipher.h"
#include "key.h"
#include "kex.h"
+#include "misc.h"
+#include "ssh.h"
+#include "readconf.h"
#include <openssl/evp.h>
#include "ssh-gss.h"
extern u_char *session_id2;
extern u_int session_id2_len;
+extern Options options;
typedef struct {
char *encoded;
static ssh_gss_kex_mapping *gss_enc2oid = NULL;
+static char *gss_password = NULL;
+
+static void
+ssh_gssapi_cleanup_password(void)
+{
+ if (gss_password) {
+ memset(gss_password, 0, strlen(gss_password));
+ xfree(gss_password);
+ }
+}
+
int
ssh_gssapi_oid_table_ok() {
return (gss_enc2oid != NULL);
char *
ssh_gssapi_client_mechanisms(const char *host, const char *client) {
gss_OID_set gss_supported;
- OM_uint32 min_status;
+ OM_uint32 maj_status, min_status;
+
+ if (options.gss_mechanism_oid) {
+ maj_status = gss_create_empty_oid_set(&min_status,
+ &gss_supported);
+ if (!GSS_ERROR(maj_status))
+ maj_status = gss_add_oid_set_member(&min_status,
+ options.gss_mechanism_oid,
+ &gss_supported);
+ } else {
+ maj_status = gss_indicate_mechs(&min_status, &gss_supported);
+ }
- if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
+ if (GSS_ERROR(maj_status))
return NULL;
return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
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);
+ if (GSS_ERROR(ctx->major)) {
+ ssh_gssapi_error(ctx);
+ return ctx->major;
+ }
+
+ if (options.gss_password_prompt) {
+ char prompt[150];
+
+ if (!gss_password) {
+ snprintf(prompt, sizeof(prompt), "%.30s's password: ", name);
+ gss_password = read_passphrase(prompt, 0);
+
+ atexit(ssh_gssapi_cleanup_password);
+ }
+
+ gssbuf.value = gss_password;
+ gssbuf.length = strlen(gss_password);
+
+ ctx->major = gss_acquire_cred_with_password(&ctx->minor,
+ gssname,
+ &gssbuf,
+ GSS_C_INDEFINITE,
+ oidset,
+ GSS_C_INITIATE,
+ &ctx->client_creds,
+ NULL,
+ NULL);
+ } else {
+ ctx->major = gss_acquire_cred(&ctx->minor,
+ gssname,
+ GSS_C_INDEFINITE,
+ oidset,
+ GSS_C_INITIATE,
+ &ctx->client_creds,
+ NULL,
+ NULL);
+ }
gss_release_name(&status, &gssname);
gss_release_oid_set(&status, &oidset);
- if (ctx->major)
+ if (GSS_ERROR(ctx->major))
ssh_gssapi_error(ctx);
- return(ctx->major);
+ return ctx->major;
}
OM_uint32
if (ctx == NULL)
ctx = &intctx;
- /* RFC 4462 says we MUST NOT do SPNEGO */
- if (oid->length == spnego_oid.length &&
+ /*
+ * RFC 4462 says we MUST NOT do SPNEGO, but we relax that if
+ * the SPNEGO mechanism was explicitly specified by the user.
+ */
+ if (options.gss_mechanism_oid == GSS_C_NO_OID &&
+ oid->length == spnego_oid.length &&
(memcmp(oid->elements, spnego_oid.elements, oid->length) == 0))
return 0; /* false */
return 0;
}
-
#endif /* GSSAPI */
#include "buffer.h"
#include "kex.h"
#include "mac.h"
+#if defined(GSSAPI)
+#include "ssh-gss.h"
+#endif
/* Format of the configuration file:
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
- oGssServerIdentity,
+ oGssServerIdentity, oGssPasswordPrompt, oGssMechanismOid,
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
oSendEnv, oControlPath, oControlMaster, oControlPersist,
oHashKnownHosts,
{ "gssapiclientidentity", oGssClientIdentity },
{ "gssapiserveridentity", oGssServerIdentity },
{ "gssapirenewalforcesrekey", oGssRenewalRekey },
+ { "gssapipasswordprompt", oGssPasswordPrompt },
+ { "gssapimechanismoid", oGssMechanismOid },
#else
{ "gssapiauthentication", oUnsupported },
{ "gssapikeyexchange", oUnsupported },
{ "gssapitrustdns", oUnsupported },
{ "gssapiclientidentity", oUnsupported },
{ "gssapirenewalforcesrekey", oUnsupported },
+ { "gssapipasswordprompt", oUnsupported },
+ { "gssapimechanismoid", oUnsupported },
#endif
{ "fallbacktorsh", oDeprecated },
{ "usersh", oDeprecated },
{ NULL, oBadOption }
};
+#ifdef GSSAPI
+static gss_OID
+mechanism_oid(const char *arg);
+#endif
+
/*
* Adds a local TCP/IP port forward to options. Never returns if there is an
* error.
intptr = &options->gss_renewal_rekey;
goto parse_flag;
+ case oGssPasswordPrompt:
+ intptr = &options->gss_password_prompt;
+ goto parse_flag;
+
+#ifdef GSSAPI
+ case oGssMechanismOid: {
+ OM_uint32 minor;
+ gss_OID oid;
+
+ arg = strdelim(&s);
+ if (!arg || *arg == '\0')
+ fatal("%.200s line %d: Missing argument.", filename, linenum);
+ oid = mechanism_oid(arg);
+ if (oid == GSS_C_NO_OID)
+ fatal("%.200s line %d: Bad GSS mechanism OID '%s'.",
+ filename, linenum, arg ? arg : "<NONE>");
+ if (*activep && options->gss_mechanism_oid == GSS_C_NO_OID)
+ options->gss_mechanism_oid = oid;
+ else
+ gss_release_oid(&minor, &oid);
+ break;
+ }
+#endif
+
case oBatchMode:
intptr = &options->batch_mode;
goto parse_flag;
options->gss_renewal_rekey = -1;
options->gss_client_identity = NULL;
options->gss_server_identity = NULL;
+ options->gss_password_prompt = -1;
+ options->gss_mechanism_oid = NULL;
options->password_authentication = -1;
options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL;
options->gss_trust_dns = 0;
if (options->gss_renewal_rekey == -1)
options->gss_renewal_rekey = 0;
+ if (options->gss_password_prompt == -1)
+ options->gss_password_prompt = 0;
if (options->password_authentication == -1)
options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1)
}
return (0);
}
+
+#ifdef GSSAPI
+static gss_OID
+mechanism_oid(const char *oidstr)
+{
+ OM_uint32 minor;
+ gss_buffer_desc oidBuf;
+ size_t oidstrLen, i;
+ char *p;
+ gss_OID ret = GSS_C_NO_OID;
+
+ oidstrLen = strlen(oidstr);
+
+ oidBuf.length = 2 + oidstrLen + 2;
+ oidBuf.value = xmalloc(oidBuf.length + 1);
+ if (oidBuf.value == NULL)
+ return NULL;
+
+ p = (char *)oidBuf.value;
+ *p++ = '{';
+ *p++ = ' ';
+ for (i = 0; i < oidstrLen; i++)
+ *p++ = oidstr[i] == '.' ? ' ' : oidstr[i];
+ *p++ = ' ';
+ *p++ = '}';
+ *p = '\0';
+
+ gss_str_to_oid(&minor, &oidBuf, &ret);
+
+ xfree(oidBuf.value);
+
+ return ret;
+}
+#endif