+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+
+ mech++; /* Move along to next candidate */
+
+ return 1;
+}
+
+void
+input_gssapi_response(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ OM_uint32 status, ms;
+ int oidlen;
+ char *oidv;
+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+
+ if (authctxt == NULL)
+ fatal("input_gssapi_response: no authentication context");
+ gssctxt = authctxt->methoddata;
+
+ /* Setup our OID */
+ oidv = packet_get_string(&oidlen);
+
+ if (datafellows & SSH_BUG_GSSAPI_BER) {
+ if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen))
+ fatal("Server returned different OID than expected");
+ } else {
+ if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) {
+ debug("Badly encoded mechanism OID received");
+ userauth(authctxt, NULL);
+ xfree(oidv);
+ return;
+ }
+ if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2))
+ fatal("Server returned different OID than expected");
+ }
+
+ packet_check_eom();
+
+ xfree(oidv);
+
+ status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+ GSS_C_NO_BUFFER, &send_tok, NULL);
+ if (GSS_ERROR(status)) {
+ if (send_tok.length > 0) {
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ packet_put_string(send_tok.value, send_tok.length);
+ packet_send();
+ gss_release_buffer(&ms, &send_tok);
+ }
+ /* Start again with next method on list */
+ debug("Trying to start again");
+ userauth(authctxt, NULL);
+ return;
+ }
+
+ /* We must have data to send */
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+ packet_put_string(send_tok.value, send_tok.length);
+ packet_send();
+ gss_release_buffer(&ms, &send_tok);
+}
+
+void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc recv_tok;
+ OM_uint32 status, ms;
+ u_int slen;
+
+ if (authctxt == NULL)
+ fatal("input_gssapi_response: no authentication context");
+ gssctxt = authctxt->methoddata;
+
+ recv_tok.value = packet_get_string(&slen);
+ recv_tok.length = slen; /* safe typecast */
+
+ packet_check_eom();
+
+ status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+ &recv_tok, &send_tok, NULL);
+
+ xfree(recv_tok.value);
+
+ if (GSS_ERROR(status)) {
+ if (send_tok.length > 0) {
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ packet_put_string(send_tok.value, send_tok.length);
+ packet_send();
+ gss_release_buffer(&ms, &send_tok);
+ }
+ /* Start again with the next method in the list */
+ userauth(authctxt, NULL);
+ return;
+ }
+
+ if (send_tok.length > 0) {
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+ packet_put_string(send_tok.value, send_tok.length);
+ packet_send();
+ gss_release_buffer(&ms, &send_tok);
+ }
+
+ if (status == GSS_S_COMPLETE) {
+ /* If that succeeded, send a exchange complete message */
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
+ packet_send();
+ }
+}
+
+void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc recv_tok;
+ OM_uint32 status, ms;
+ u_int len;
+
+ if (authctxt == NULL)
+ fatal("input_gssapi_response: no authentication context");
+ gssctxt = authctxt->methoddata;
+
+ recv_tok.value = packet_get_string(&len);
+ recv_tok.length = len;
+
+ packet_check_eom();
+
+ /* Stick it into GSSAPI and see what it says */
+ status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+ &recv_tok, &send_tok, NULL);
+
+ xfree(recv_tok.value);
+ gss_release_buffer(&ms, &send_tok);
+
+ /* Server will be returning a failed packet after this one */