-#ifdef GSSAPI
-#ifdef GSI
-static gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"};
-char * get_gsi_name()
-{
- gss_name_t pname = GSS_C_NO_NAME;
- gss_buffer_desc tmpname;
- gss_buffer_t tmpnamed = &tmpname;
- char *retname=NULL;
- gss_OID_set oidset;
- gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
- Gssctxt *ctx = NULL;
-
- ssh_gssapi_build_ctx(&ctx);
-
- gss_create_empty_oid_set(&ctx->minor,&oidset);
- gss_add_oid_set_member(&ctx->minor,&gsioid,&oidset);
- ssh_gssapi_set_oid(ctx,&gsioid);
- ctx->major = gss_acquire_cred(&ctx->minor,
- GSS_C_NO_NAME,
- GSS_C_INDEFINITE,
- oidset,
- GSS_C_INITIATE,
- &gss_cred,
- NULL,
- NULL);
-
- if (ctx->major != GSS_S_COMPLETE) {
- goto cleanup;
- }
-
- debug("calling gss_inquire_cred");
- ctx->major = gss_inquire_cred(&ctx->minor,
- gss_cred,
- &pname,
- NULL,
- NULL,
- NULL);
- if (ctx->major != GSS_S_COMPLETE) {
- goto cleanup;
- }
-
- ctx->major = gss_display_name(&ctx->minor,
- pname,
- tmpnamed,
- NULL);
- if (ctx->major != GSS_S_COMPLETE) {
- goto cleanup;
- }
- debug("gss_display_name finsished");
- retname = xmalloc(tmpname.length + 1);
- memcpy(retname, tmpname.value, tmpname.length);
- retname[tmpname.length] = '\0';
-
- gss_release_name(&ctx->minor, &pname);
- gss_release_buffer(&ctx->minor, tmpnamed);
-
- cleanup:
- if (!retname) {
- debug("Failed to set GSI username from credentials");
- ssh_gssapi_error(ctx);
- }
- if (ctx) ssh_gssapi_delete_ctx(&ctx);
- return retname;
-}
-#endif /* GSI */
-
-int try_gssapi_authentication(char *host, Options *options)
-{
- char *service_name = NULL;
- gss_buffer_desc name_tok;
- gss_buffer_desc send_tok;
- gss_buffer_desc recv_tok;
- gss_buffer_desc *token_ptr;
- gss_name_t target_name = NULL;
- gss_ctx_id_t gss_context;
- gss_OID_desc mech_oid;
- gss_OID name_type;
- gss_OID_set gss_mechs, my_mechs;
- int my_mech_num, i;
- int ret_stat = 0; /* 1 == success */
- OM_uint32 req_flags = 0;
- OM_uint32 ret_flags;
- int type;
- char *xhost;
- unsigned int slen;
- Gssctxt *ctx = NULL;
-
- ssh_gssapi_build_ctx(&ctx);
-
- xhost = xstrdup(get_canonical_hostname(1));
- resolve_localhost(&xhost);
-
- /*
- * Default flags
- */
- req_flags |= GSS_C_REPLAY_FLAG;
-
- /* Do mutual authentication */
- req_flags |= GSS_C_MUTUAL_FLAG;
-
- service_name = (char *) xmalloc(strlen("host") +
- strlen(xhost) +
- 2 /* 1 for '@', 1 for NUL */);
-
- sprintf(service_name, "host@%s", xhost);
-
- xfree(xhost);
- xhost = NULL;
-
- name_type = GSS_C_NT_HOSTBASED_SERVICE;
-
- debug("Service name is %s", service_name);
-
- /* Forward credentials? */
- if(options->gss_deleg_creds) {
- debug("Delegating GSSAPI credentials");
- req_flags |= GSS_C_DELEG_FLAG;
- }
-
- debug("req_flags = %u", (unsigned int)req_flags);
-
- name_tok.value = service_name;
- name_tok.length = strlen(service_name) + 1;
- ctx->major = gss_import_name(&ctx->minor, &name_tok,
- name_type, &target_name);
-
- free(service_name);
- service_name = NULL;
-
- if (ctx->major != GSS_S_COMPLETE) {
- ssh_gssapi_error(ctx);
- goto cleanup;
- }
-
- ctx->major = gss_indicate_mechs(&ctx->minor, &gss_mechs);
-
- if (ctx->major != GSS_S_COMPLETE) {
- ssh_gssapi_error(ctx);
- goto cleanup;
- }
-
- /* The GSSAPI supports the mechs in gss_mechs, but which ones do
- we have credentials for? We only get one try, so we don't want
- to propose a mechanism we know is going to fail. */
- ctx->major = gss_create_empty_oid_set(&ctx->minor, &my_mechs);
- for (i=0; i<gss_mechs->count; i++) {
- if (ssh_gssapi_check_mechanism(&(gss_mechs->elements[i]), host)) {
- ctx->major = gss_add_oid_set_member(&ctx->minor,
- &(gss_mechs->elements[i]),
- &my_mechs);
- }
- }
-
- if (my_mechs->count == 0) {
- debug("No GSSAPI mechanisms.");
- goto cleanup;
- }
-
- /*
- * Send over a packet to the daemon, letting it know we're doing
- * GSSAPI and our mech_oid(s).
- */
- debug("Sending mech oid(s) to server");
- packet_start(SSH_CMSG_AUTH_GSSAPI);
- packet_put_int(my_mechs->count); /* Number of mechs we're sending */
-#ifdef GSI
- {
- int present;
- /* Send GSI before Kerberos, because if GSI fails, we can always
- fall back and try regular Kerberos authentication with our
- Kerberos cred. */
- ctx->major = gss_test_oid_set_member(&ctx->minor, &gsioid,
- my_mechs, &present);
- if (present) {
- packet_put_string(gsioid.elements,gsioid.length);
- }
- }
-#endif
- for (my_mech_num = 0; my_mech_num < my_mechs->count; my_mech_num++) {
-#ifdef GSI
- /* Skip GSI. We already sent it above. */
- if ((my_mechs->elements[my_mech_num].length ==
- gsioid.length) &&
- memcmp(my_mechs->elements[my_mech_num].elements,
- gsioid.elements,
- my_mechs->elements[my_mech_num].length) == 0) {
- continue;
- }
-#endif
- packet_put_string(my_mechs->elements[my_mech_num].elements,
- my_mechs->elements[my_mech_num].length);
- }
- packet_send();
- packet_write_wait();
-
- /*
- * Get reply from the daemon to see if our mech was acceptable
- */
- type = packet_read();
-
- switch (type) {
- case SSH_SMSG_AUTH_GSSAPI_RESPONSE:
- debug("Server accepted mechanism");
- /* Successful negotiation */
- break;
-
- case SSH_MSG_AUTH_GSSAPI_ABORT:
- case SSH_SMSG_FAILURE:
- debug("Unable to negotiate GSSAPI mechanism type with server");
- packet_get_all();
- goto cleanup;
-
- default:
- packet_disconnect("Protocol error during GSSAPI authentication:"
- " packet type %d received",
- type);
- /* Does not return */
- }
-
- /* Read the mechanism the server returned */
- mech_oid.elements = packet_get_string(&slen);
- mech_oid.length = slen; /* safe typecast */
- packet_get_all();
-
- ssh_gssapi_set_oid(ctx, &mech_oid);
-
- /*
- * Perform the context-establishement loop.
- *
- * On each pass through the loop, token_ptr points to the token
- * to send to the server (or GSS_C_NO_BUFFER on the first pass).
- * Every generated token is stored in send_tok which is then
- * transmitted to the server; every received token is stored in
- * recv_tok, which token_ptr is then set to, to be processed by
- * the next call to gss_init_sec_context.
- *
- * GSS-API guarantees that send_tok's length will be non-zero
- * if and only if the server is expecting another token from us,
- * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
- * and only if the server has another token to send us.
- */
-
- token_ptr = GSS_C_NO_BUFFER;
- gss_context = GSS_C_NO_CONTEXT;
-
- do {
- ctx->major =
- gss_init_sec_context(&ctx->minor,
- GSS_C_NO_CREDENTIAL,
- &gss_context,
- target_name,
- ctx->oid,
- req_flags,
- 0,
- NULL, /* no channel bindings */
- token_ptr,
- NULL, /* ignore mech type */
- &send_tok,
- &ret_flags,
- NULL); /* ignore time_rec */
-
- if (token_ptr != GSS_C_NO_BUFFER)
- (void) gss_release_buffer(&ctx->minor, &recv_tok);
-
- if (ctx->major != GSS_S_COMPLETE && ctx->major != GSS_S_CONTINUE_NEEDED) {
- ssh_gssapi_error(ctx);
-
- /* Send an abort message */
- packet_start(SSH_MSG_AUTH_GSSAPI_ABORT);
- packet_send();
- packet_write_wait();
-
- goto cleanup;
- }
-
- if (send_tok.length != 0) {
- debug("Sending authenticaton token...");
- packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
- packet_put_string((char *) send_tok.value, send_tok.length);
- packet_send();
- packet_write_wait();
-
- (void) gss_release_buffer(&ctx->minor, &send_tok);
- }
-
- if (ctx->major == GSS_S_CONTINUE_NEEDED) {
-
- debug("Continue needed. Reading response...");
-
- type = packet_read();
-
- switch(type) {
-
- case SSH_MSG_AUTH_GSSAPI_TOKEN:
- /* This is what we expected */
- break;
-
- case SSH_MSG_AUTH_GSSAPI_ABORT:
- case SSH_SMSG_FAILURE:
- debug("Server aborted GSSAPI authentication.");
- packet_get_all();
- goto cleanup;
-
- default:
- packet_disconnect("Protocol error during GSSAPI authentication:"
- " packet type %d received",
- type);
- /* Does not return */
- }
-
- recv_tok.value = packet_get_string(&slen);
- recv_tok.length=slen; /* safe typecast */
- packet_get_all();
- token_ptr = &recv_tok;
- }
- } while (ctx->major == GSS_S_CONTINUE_NEEDED);
-
- /* Success */
- ret_stat = 1;
-
- debug("GSSAPI authentication successful");
-
- /*
- * Read hash of host and server keys and make sure it
- * matches what we got earlier.
- */
- debug("Reading hash of server and host keys...");
- type = packet_read();
-
- if (type == SSH_MSG_AUTH_GSSAPI_ABORT || type == SSH_SMSG_FAILURE) {
- debug("Server aborted GSSAPI authentication.");
- packet_get_all();
- ret_stat = 0;
- goto cleanup;
-
- } else if (type == SSH_SMSG_AUTH_GSSAPI_HASH) {
- gss_buffer_desc wrapped_buf;
- gss_buffer_desc unwrapped_buf;
- int conf_state;
- gss_qop_t qop_state;
-
-
- wrapped_buf.value = packet_get_string(&slen);
- wrapped_buf.length=slen; /* safe typecast */
- packet_get_all();
-
- ctx->major = gss_unwrap(&ctx->minor,
- gss_context,
- &wrapped_buf,
- &unwrapped_buf,
- &conf_state,
- &qop_state);
-
- if (ctx->major != GSS_S_COMPLETE) {
- ssh_gssapi_error(ctx);
- packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
- "Unwrapping of hash failed.");
- }
-
- if (unwrapped_buf.length != sizeof(ssh_key_digest)) {
- packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
- "Size of key hashes do not match (%d != %d)!",
- (int)unwrapped_buf.length,
- (int)sizeof(ssh_key_digest));
- }
-
- if (memcmp(ssh_key_digest, unwrapped_buf.value, sizeof(ssh_key_digest)) != 0) {
- packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
- "Hashes don't match!");
- }
-
- debug("Verified SSHD keys through GSSAPI-secured channel.");
-
- gss_release_buffer(&ctx->minor, &unwrapped_buf);
-
- } else {
- packet_disconnect("Protocol error during GSSAPI authentication:"
- "packet type %d received", type);
- /* Does not return */
- }
-
-
- cleanup:
- if (target_name != NULL)
- (void) gss_release_name(&ctx->minor, &target_name);
- if (ctx)
- ssh_gssapi_delete_ctx(&ctx);
-
- return ret_stat;
-}
-
-#endif /* GSSAPI */
-
-