10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
50Sstevel@tonic-gate * modification, are permitted provided that the following conditions
60Sstevel@tonic-gate * are met:
70Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
80Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
90Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
100Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
110Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
140Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
150Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
160Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
170Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
180Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
190Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
200Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
210Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
220Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate /*
25*11044SHuie-Ying.Lee@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
260Sstevel@tonic-gate * Use is subject to license terms.
270Sstevel@tonic-gate */
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include "includes.h"
300Sstevel@tonic-gate
310Sstevel@tonic-gate #ifdef GSSAPI
320Sstevel@tonic-gate #include "auth.h"
330Sstevel@tonic-gate #include "ssh2.h"
340Sstevel@tonic-gate #include "xmalloc.h"
350Sstevel@tonic-gate #include "log.h"
360Sstevel@tonic-gate #include "dispatch.h"
37*11044SHuie-Ying.Lee@Sun.COM #include "buffer.h"
380Sstevel@tonic-gate #include "servconf.h"
390Sstevel@tonic-gate #include "compat.h"
400Sstevel@tonic-gate #include "bufaux.h"
410Sstevel@tonic-gate #include "packet.h"
420Sstevel@tonic-gate
430Sstevel@tonic-gate #include <gssapi/gssapi.h>
440Sstevel@tonic-gate #include "ssh-gss.h"
450Sstevel@tonic-gate
460Sstevel@tonic-gate extern ServerOptions options;
476080Sjp161948 extern uchar_t *session_id2;
480Sstevel@tonic-gate extern int session_id2_len;
490Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt;
500Sstevel@tonic-gate
510Sstevel@tonic-gate static void userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt);
520Sstevel@tonic-gate
530Sstevel@tonic-gate static void
userauth_gssapi_keyex(Authctxt * authctxt)540Sstevel@tonic-gate userauth_gssapi_keyex(Authctxt *authctxt)
550Sstevel@tonic-gate {
566080Sjp161948 gss_buffer_desc g_mic_data, mic_tok;
570Sstevel@tonic-gate Buffer mic_data;
586080Sjp161948 OM_uint32 maj_status, min_status;
590Sstevel@tonic-gate
600Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL)
610Sstevel@tonic-gate fatal("No authentication context during gssapi-keyex userauth");
620Sstevel@tonic-gate
630Sstevel@tonic-gate if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) {
640Sstevel@tonic-gate /* fatal()? or return? */
650Sstevel@tonic-gate debug("No GSS-API context during gssapi-keyex userauth");
660Sstevel@tonic-gate return;
670Sstevel@tonic-gate }
686080Sjp161948
690Sstevel@tonic-gate /* Make data buffer to verify MIC with */
700Sstevel@tonic-gate buffer_init(&mic_data);
710Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len);
720Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
730Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user);
740Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service);
750Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name);
760Sstevel@tonic-gate
770Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data);
780Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data);
790Sstevel@tonic-gate
806080Sjp161948 mic_tok.value = packet_get_string(&mic_tok.length);
810Sstevel@tonic-gate
820Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, xxx_gssctxt->context,
836080Sjp161948 &g_mic_data, &mic_tok, NULL);
840Sstevel@tonic-gate
856080Sjp161948 packet_check_eom();
860Sstevel@tonic-gate buffer_clear(&mic_data);
870Sstevel@tonic-gate
880Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE)
890Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed");
900Sstevel@tonic-gate else
910Sstevel@tonic-gate userauth_gssapi_finish(authctxt, xxx_gssctxt);
920Sstevel@tonic-gate
930Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
940Sstevel@tonic-gate if (xxx_gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
950Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate
980Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
990Sstevel@tonic-gate static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
1000Sstevel@tonic-gate static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
1010Sstevel@tonic-gate static void input_gssapi_errtok(int, u_int32_t, void *);
1026080Sjp161948 static void input_gssapi_exchange_complete(int type, u_int32_t plen,
1036080Sjp161948 void *ctxt);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate static void
userauth_gssapi_abandon(Authctxt * authctxt,Authmethod * method)1060Sstevel@tonic-gate userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data);
1090Sstevel@tonic-gate xxx_gssctxt = NULL;
1100Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
1110Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
1120Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
1136080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate static void
userauth_gssapi(Authctxt * authctxt)1170Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt)
1180Sstevel@tonic-gate {
1196080Sjp161948 gss_OID_set supported_mechs;
1206080Sjp161948 int mechs, present = 0;
1216080Sjp161948 OM_uint32 min_status;
1226080Sjp161948 uint_t len;
1236080Sjp161948 char *doid = NULL;
1246080Sjp161948 gss_OID oid = GSS_C_NULL_OID;
1250Sstevel@tonic-gate
1266080Sjp161948 if (datafellows & SSH_OLD_GSSAPI) {
1276080Sjp161948 debug("Early drafts of GSSAPI userauth not supported");
1286080Sjp161948 return;
1296080Sjp161948 }
1300Sstevel@tonic-gate
1316080Sjp161948 mechs = packet_get_int();
1326080Sjp161948 if (mechs == 0) {
1330Sstevel@tonic-gate packet_check_eom();
1346080Sjp161948 debug("Mechanism negotiation is not supported");
1356080Sjp161948 return;
1366080Sjp161948 }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate ssh_gssapi_server_mechs(&supported_mechs);
1390Sstevel@tonic-gate
1406080Sjp161948 do {
1416080Sjp161948 mechs--;
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate if (oid != GSS_C_NULL_OID)
1440Sstevel@tonic-gate ssh_gssapi_release_oid(&oid);
1450Sstevel@tonic-gate
1466080Sjp161948 doid = packet_get_string(&len);
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate /* ick */
1496080Sjp161948 if (doid[0] != 0x06 || (len > 2 && doid[1] != len - 2)) {
1506080Sjp161948 log("Mechanism OID received using the old "
1516080Sjp161948 "encoding form");
1520Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len, doid);
1536080Sjp161948 } else {
1540Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len - 2, doid + 2);
1556080Sjp161948 }
1566080Sjp161948
1576080Sjp161948 (void) gss_test_oid_set_member(&min_status, oid,
1586080Sjp161948 supported_mechs, &present);
1590Sstevel@tonic-gate
1606080Sjp161948 debug("Client offered gssapi userauth with %s (%s)",
1616080Sjp161948 ssh_gssapi_oid_to_str(oid),
1626080Sjp161948 present ? "supported" : "unsupported");
1636080Sjp161948 } while (!present && (mechs > 0));
1646080Sjp161948
1656080Sjp161948 if (!present) {
1660Sstevel@tonic-gate /* userauth_finish() will send SSH2_MSG_USERAUTH_FAILURE */
1670Sstevel@tonic-gate debug2("No mechanism offered by the client is available");
1686080Sjp161948 ssh_gssapi_release_oid(&oid);
1696080Sjp161948 return;
1706080Sjp161948 }
1710Sstevel@tonic-gate
1726080Sjp161948 ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data,
1736080Sjp161948 0, oid);
1746080Sjp161948 ssh_gssapi_release_oid(&oid);
1756080Sjp161948 /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
1760Sstevel@tonic-gate
1776080Sjp161948 packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* Just return whatever we found -- the matched mech does us no good */
1800Sstevel@tonic-gate packet_put_string(doid, len);
1810Sstevel@tonic-gate xfree(doid);
1820Sstevel@tonic-gate
1836080Sjp161948 packet_send();
1846080Sjp161948 packet_write_wait();
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate /* Setup rest of gssapi userauth conversation */
1876080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
1886080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
1896080Sjp161948 authctxt->method->postponed = 1;
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate static void
input_gssapi_token(int type,u_int32_t plen,void * ctxt)1930Sstevel@tonic-gate input_gssapi_token(int type, u_int32_t plen, void *ctxt)
1940Sstevel@tonic-gate {
1956080Sjp161948 Authctxt *authctxt = ctxt;
1966080Sjp161948 Gssctxt *gssctxt;
1976080Sjp161948 gss_buffer_desc send_tok, recv_tok;
1986080Sjp161948 OM_uint32 maj_status, min_status;
1996080Sjp161948 uint_t len;
2000Sstevel@tonic-gate
2016080Sjp161948 if (authctxt == NULL || authctxt->method == NULL ||
2026080Sjp161948 (authctxt->method->method_data == NULL)) {
2036080Sjp161948 fatal("No authentication or GSSAPI context during "
2046080Sjp161948 "gssapi-with-mic userauth");
2056080Sjp161948 }
2060Sstevel@tonic-gate
2076080Sjp161948 gssctxt = authctxt->method->method_data;
2086080Sjp161948 recv_tok.value = packet_get_string(&len);
2096080Sjp161948 recv_tok.length = len; /* u_int vs. size_t */
2100Sstevel@tonic-gate
2116080Sjp161948 maj_status = ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
2126080Sjp161948 packet_check_eom();
2136080Sjp161948
2146080Sjp161948 if (GSS_ERROR(maj_status)) {
2156080Sjp161948 ssh_gssapi_userauth_error(gssctxt);
2160Sstevel@tonic-gate if (send_tok.length != 0) {
2170Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
2186080Sjp161948 packet_put_string(send_tok.value, send_tok.length);
2196080Sjp161948 packet_send();
2206080Sjp161948 packet_write_wait();
2216080Sjp161948 }
2226080Sjp161948 authctxt->method->postponed = 0;
2236080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2246080Sjp161948 userauth_finish(authctxt, authctxt->method->name);
2256080Sjp161948 } else {
2266080Sjp161948 if (send_tok.length != 0) {
2276080Sjp161948 packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
2286080Sjp161948 packet_put_string(send_tok.value, send_tok.length);
2296080Sjp161948 packet_send();
2306080Sjp161948 packet_write_wait();
2316080Sjp161948 }
2326080Sjp161948 if (maj_status == GSS_S_COMPLETE) {
2336080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2346080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
2356080Sjp161948 &input_gssapi_mic);
2366080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
2376080Sjp161948 &input_gssapi_exchange_complete);
2386080Sjp161948 }
2396080Sjp161948 }
2400Sstevel@tonic-gate
2416080Sjp161948 gss_release_buffer(&min_status, &send_tok);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate static void
input_gssapi_errtok(int type,u_int32_t plen,void * ctxt)2450Sstevel@tonic-gate input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
2460Sstevel@tonic-gate {
2476080Sjp161948 Authctxt *authctxt = ctxt;
2486080Sjp161948 Gssctxt *gssctxt;
2496080Sjp161948 gss_buffer_desc send_tok, recv_tok;
2500Sstevel@tonic-gate
2516080Sjp161948 if (authctxt == NULL || authctxt->method == NULL ||
2526080Sjp161948 (authctxt->method->method_data == NULL)) {
2536080Sjp161948 fatal("No authentication or GSSAPI context during "
2546080Sjp161948 "gssapi-with-mic userauth");
2556080Sjp161948 }
2560Sstevel@tonic-gate
2576080Sjp161948 gssctxt = authctxt->method->method_data;
2586080Sjp161948 recv_tok.value = packet_get_string(&recv_tok.length);
2596080Sjp161948 packet_check_eom();
2600Sstevel@tonic-gate
2616080Sjp161948 /* Push the error token into GSSAPI to see what it says */
2626080Sjp161948 (void) ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate debug("Client sent GSS-API error token during GSS userauth-- %s",
2656080Sjp161948 ssh_gssapi_last_error(gssctxt, NULL, NULL));
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /* We can't return anything to the client, even if we wanted to */
2680Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2696080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * The client will have already moved on to the next auth and
2740Sstevel@tonic-gate * will send a new userauth request. The spec says that the
2750Sstevel@tonic-gate * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in
2760Sstevel@tonic-gate * response to this.
2770Sstevel@tonic-gate *
2780Sstevel@tonic-gate * We leave authctxt->method->postponed == 1 here so that a call
2790Sstevel@tonic-gate * to input_userauth_request() will detect this failure (as
2800Sstevel@tonic-gate * userauth abandonment) and act accordingly.
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate static void
input_gssapi_mic(int type,u_int32_t plen,void * ctxt)2850Sstevel@tonic-gate input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate Authctxt *authctxt = ctxt;
2880Sstevel@tonic-gate Gssctxt *gssctxt;
2896080Sjp161948 gss_buffer_desc g_mic_data, mic_tok;
2900Sstevel@tonic-gate Buffer mic_data;
2916080Sjp161948 OM_uint32 maj_status, min_status;
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL ||
2940Sstevel@tonic-gate (authctxt->method->method_data == NULL)) {
2956080Sjp161948 debug3("No authentication or GSSAPI context during "
2966080Sjp161948 "gssapi-with-mic userauth");
2970Sstevel@tonic-gate return;
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate
3006080Sjp161948 gssctxt = authctxt->method->method_data;
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /* Make data buffer to verify MIC with */
3030Sstevel@tonic-gate buffer_init(&mic_data);
3040Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len);
3050Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
3060Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user);
3070Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service);
3080Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name);
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data);
3110Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data);
3120Sstevel@tonic-gate
3136080Sjp161948 mic_tok.value = packet_get_string(&mic_tok.length);
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, gssctxt->context,
3166080Sjp161948 &g_mic_data, &mic_tok, NULL);
3170Sstevel@tonic-gate
3186080Sjp161948 packet_check_eom();
3190Sstevel@tonic-gate buffer_free(&mic_data);
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE)
3220Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed");
3230Sstevel@tonic-gate else
3240Sstevel@tonic-gate userauth_gssapi_finish(authctxt, gssctxt);
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /* Delete context from keyex */
3270Sstevel@tonic-gate if (xxx_gssctxt != gssctxt)
3280Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt);
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
3310Sstevel@tonic-gate if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
3320Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt);
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate xxx_gssctxt = gssctxt;
3350Sstevel@tonic-gate
3366080Sjp161948 authctxt->method->postponed = 0;
3376080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
3386080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
3396080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
3406080Sjp161948 userauth_finish(authctxt, authctxt->method->name);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3436080Sjp161948 /*
3446080Sjp161948 * This is called when the client thinks we've completed authentication.
3450Sstevel@tonic-gate * It should only be enabled in the dispatch handler by the function above,
3460Sstevel@tonic-gate * which only enables it once the GSSAPI exchange is complete.
3470Sstevel@tonic-gate */
3480Sstevel@tonic-gate static void
input_gssapi_exchange_complete(int type,u_int32_t plen,void * ctxt)3490Sstevel@tonic-gate input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
3500Sstevel@tonic-gate {
3516080Sjp161948 Authctxt *authctxt = ctxt;
3526080Sjp161948 Gssctxt *gssctxt;
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate packet_check_eom();
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL ||
3575562Sjp161948 (authctxt->method->method_data == NULL))
3586080Sjp161948 fatal("No authentication or GSSAPI context");
3590Sstevel@tonic-gate
3606080Sjp161948 gssctxt = authctxt->method->method_data;
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth
3640Sstevel@tonic-gate * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC
3650Sstevel@tonic-gate * instead.
3660Sstevel@tonic-gate *
3670Sstevel@tonic-gate * There's two reasons for this:
3680Sstevel@tonic-gate *
3690Sstevel@tonic-gate * 1) we don't have GSS mechs that don't support integrity
3700Sstevel@tonic-gate * protection, and even if we did we'd not want to use them with
3710Sstevel@tonic-gate * SSHv2, and,
3720Sstevel@tonic-gate *
3730Sstevel@tonic-gate * 2) we currently have no way to dynamically detect whether a
3740Sstevel@tonic-gate * given mechanism does or does not support integrity
3750Sstevel@tonic-gate * protection, so when a context's flags do not indicate
3760Sstevel@tonic-gate * integrity protection we can't know if the client simply
3770Sstevel@tonic-gate * didn't request it, so we assume it didn't and reject the
3780Sstevel@tonic-gate * userauth.
3790Sstevel@tonic-gate *
3800Sstevel@tonic-gate * We could fail partially (i.e., force the use of other
3810Sstevel@tonic-gate * userauth methods without counting this one as failed). But
3820Sstevel@tonic-gate * this will do for now.
3830Sstevel@tonic-gate */
3840Sstevel@tonic-gate #if 0
3856080Sjp161948 authctxt->method->authenticated = ssh_gssapi_userok(gssctxt,
3866080Sjp161948 authctxt->user);
3870Sstevel@tonic-gate #endif
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate if (xxx_gssctxt != gssctxt)
3900Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt);
3910Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt);
3926080Sjp161948 authctxt->method->postponed = 0;
3936080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
3946080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
3956080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
3966080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
3976080Sjp161948 userauth_finish(authctxt, authctxt->method->name);
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate
4006080Sjp161948 static void
ssh_gssapi_userauth_error(Gssctxt * ctxt)4016080Sjp161948 ssh_gssapi_userauth_error(Gssctxt *ctxt)
4026080Sjp161948 {
4030Sstevel@tonic-gate char *errstr;
4046080Sjp161948 OM_uint32 maj, min;
4050Sstevel@tonic-gate
4066080Sjp161948 errstr = ssh_gssapi_last_error(ctxt, &maj, &min);
4070Sstevel@tonic-gate if (errstr) {
4080Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
4090Sstevel@tonic-gate packet_put_int(maj);
4100Sstevel@tonic-gate packet_put_int(min);
4110Sstevel@tonic-gate packet_put_cstring(errstr);
4120Sstevel@tonic-gate packet_put_cstring("");
4130Sstevel@tonic-gate packet_send();
4140Sstevel@tonic-gate packet_write_wait();
4150Sstevel@tonic-gate xfree(errstr);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * Code common to gssapi-keyex and gssapi-with-mic userauth.
4210Sstevel@tonic-gate *
4220Sstevel@tonic-gate * Does authorization, figures out how to store delegated creds.
4230Sstevel@tonic-gate */
4246080Sjp161948 static void
userauth_gssapi_finish(Authctxt * authctxt,Gssctxt * gssctxt)4250Sstevel@tonic-gate userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate char *local_user = NULL;
4284279Sgm149974 gss_buffer_desc dispname;
4294279Sgm149974 OM_uint32 major;
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate if (*authctxt->user != '\0' &&
4325562Sjp161948 ssh_gssapi_userok(gssctxt, authctxt->user)) {
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate * If the client princ did not map to the requested
4360Sstevel@tonic-gate * username then we don't want to clobber existing creds
4370Sstevel@tonic-gate * for the user with the delegated creds.
4380Sstevel@tonic-gate */
4390Sstevel@tonic-gate local_user = ssh_gssapi_localname(gssctxt);
4400Sstevel@tonic-gate if (local_user == NULL ||
4410Sstevel@tonic-gate strcmp(local_user, authctxt->user) == 0)
4420Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */
4430Sstevel@tonic-gate
4446080Sjp161948 authctxt->method->authenticated =
4456080Sjp161948 do_pam_non_initial_userauth(authctxt);
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate } else if (*authctxt->user == '\0') {
4480Sstevel@tonic-gate /* Requested username == ""; derive username from princ name */
4490Sstevel@tonic-gate if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL)
4500Sstevel@tonic-gate return;
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate /* Changed username (from implicit, '') */
4530Sstevel@tonic-gate userauth_user_svc_change(authctxt, local_user, NULL);
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate authctxt->method->authenticated =
4586080Sjp161948 do_pam_non_initial_userauth(authctxt);
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate if (local_user != NULL)
4620Sstevel@tonic-gate xfree(local_user);
4634279Sgm149974
4644279Sgm149974 if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) {
4654279Sgm149974 major = gss_display_name(&gssctxt->minor, gssctxt->src_name,
4666080Sjp161948 &dispname, NULL);
4674279Sgm149974 if (major == GSS_S_COMPLETE) {
4684279Sgm149974 log("Authorized principal %.*s, authenticated with "
4694279Sgm149974 "GSS mechanism %s, to: %s",
4706080Sjp161948 dispname.length, (char *)dispname.value,
4716080Sjp161948 ssh_gssapi_oid_to_name(gssctxt->actual_mech),
4726080Sjp161948 authctxt->user);
4734279Sgm149974 }
4744279Sgm149974 (void) gss_release_buffer(&gssctxt->minor, &dispname);
4754279Sgm149974 }
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate #if 0
4790Sstevel@tonic-gate /* Deprecated userauths -- should not be enabled */
4800Sstevel@tonic-gate Authmethod method_external = {
4810Sstevel@tonic-gate "external-keyx",
4820Sstevel@tonic-gate &options.gss_authentication,
4830Sstevel@tonic-gate userauth_gssapi_keyex,
4840Sstevel@tonic-gate NULL, /* no abandon function */
4850Sstevel@tonic-gate NULL,
4860Sstevel@tonic-gate NULL,
4870Sstevel@tonic-gate /* State counters */
4880Sstevel@tonic-gate 0, 0, 0, 0,
4890Sstevel@tonic-gate /* State flags */
4900Sstevel@tonic-gate 0, 0, 0, 0, 0, 0
4910Sstevel@tonic-gate };
4920Sstevel@tonic-gate
4930Sstevel@tonic-gate Authmethod method_gssapi = {
4946080Sjp161948 "gssapi",
4956080Sjp161948 &options.gss_authentication,
4966080Sjp161948 userauth_gssapi,
4970Sstevel@tonic-gate userauth_gssapi_abandon,
4980Sstevel@tonic-gate NULL,
4990Sstevel@tonic-gate NULL,
5000Sstevel@tonic-gate /* State counters */
5010Sstevel@tonic-gate 0, 0, 0, 0,
5020Sstevel@tonic-gate /* State flags */
5030Sstevel@tonic-gate 0, 0, 0, 0, 0, 0
5040Sstevel@tonic-gate };
5050Sstevel@tonic-gate #endif
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate Authmethod method_external = {
5080Sstevel@tonic-gate "gssapi-keyex",
5090Sstevel@tonic-gate &options.gss_authentication,
5100Sstevel@tonic-gate userauth_gssapi_keyex,
5110Sstevel@tonic-gate NULL, /* no abandon function */
5120Sstevel@tonic-gate NULL,
5130Sstevel@tonic-gate NULL,
5140Sstevel@tonic-gate /* State counters */
5150Sstevel@tonic-gate 0, 0, 0, 0,
5160Sstevel@tonic-gate /* State flags */
5170Sstevel@tonic-gate 0, 0, 0, 0, 0, 0
5180Sstevel@tonic-gate };
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate Authmethod method_gssapi = {
5216080Sjp161948 "gssapi-with-mic",
5226080Sjp161948 &options.gss_authentication,
5236080Sjp161948 userauth_gssapi,
5240Sstevel@tonic-gate userauth_gssapi_abandon,
5250Sstevel@tonic-gate NULL,
5260Sstevel@tonic-gate NULL,
5270Sstevel@tonic-gate /* State counters */
5280Sstevel@tonic-gate 0, 0, 0, 0,
5290Sstevel@tonic-gate /* State flags */
5300Sstevel@tonic-gate 0, 0, 0, 0, 0, 0
5310Sstevel@tonic-gate };
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate #endif /* GSSAPI */
534