auth2-gss.c revision 149749
190075Sobrien/* $OpenBSD: auth2-gss.c,v 1.10 2005/07/17 07:17:54 djm Exp $ */ 290075Sobrien 390075Sobrien/* 490075Sobrien * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 590075Sobrien * 690075Sobrien * Redistribution and use in source and binary forms, with or without 790075Sobrien * modification, are permitted provided that the following conditions 890075Sobrien * are met: 990075Sobrien * 1. Redistributions of source code must retain the above copyright 1090075Sobrien * notice, this list of conditions and the following disclaimer. 1190075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1290075Sobrien * notice, this list of conditions and the following disclaimer in the 1390075Sobrien * documentation and/or other materials provided with the distribution. 1490075Sobrien * 1590075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR 1690075Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1790075Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1890075Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1990075Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2090075Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2190075Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2290075Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2390075Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2490075Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2590075Sobrien */ 2690075Sobrien 2790075Sobrien#include "includes.h" 2890075Sobrien 2990075Sobrien#ifdef GSSAPI 3090075Sobrien 3190075Sobrien#include "auth.h" 3290075Sobrien#include "ssh2.h" 3390075Sobrien#include "xmalloc.h" 3490075Sobrien#include "log.h" 3590075Sobrien#include "dispatch.h" 3690075Sobrien#include "servconf.h" 3790075Sobrien#include "compat.h" 3890075Sobrien#include "packet.h" 3990075Sobrien#include "monitor_wrap.h" 4090075Sobrien 4190075Sobrien#include "ssh-gss.h" 4290075Sobrien 4390075Sobrienextern ServerOptions options; 4490075Sobrien 4590075Sobrienstatic void input_gssapi_token(int type, u_int32_t plen, void *ctxt); 4690075Sobrienstatic void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); 4790075Sobrienstatic void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 4890075Sobrienstatic void input_gssapi_errtok(int, u_int32_t, void *); 4990075Sobrien 5090075Sobrien/* 5190075Sobrien * We only support those mechanisms that we know about (ie ones that we know 5290075Sobrien * how to check local user kuserok and the like 5390075Sobrien */ 5490075Sobrienstatic int 5590075Sobrienuserauth_gssapi(Authctxt *authctxt) 5690075Sobrien{ 5790075Sobrien gss_OID_desc goid = {0, NULL}; 5890075Sobrien Gssctxt *ctxt = NULL; 5990075Sobrien int mechs; 6090075Sobrien gss_OID_set supported; 6190075Sobrien int present; 6290075Sobrien OM_uint32 ms; 6390075Sobrien u_int len; 6490075Sobrien u_char *doid = NULL; 6590075Sobrien 6690075Sobrien if (!authctxt->valid || authctxt->user == NULL) 6790075Sobrien return (0); 6890075Sobrien 6990075Sobrien mechs = packet_get_int(); 7090075Sobrien if (mechs == 0) { 7190075Sobrien debug("Mechanism negotiation is not supported"); 7290075Sobrien return (0); 7390075Sobrien } 7490075Sobrien 7590075Sobrien ssh_gssapi_supported_oids(&supported); 7690075Sobrien do { 7790075Sobrien mechs--; 7890075Sobrien 7990075Sobrien if (doid) 8090075Sobrien xfree(doid); 8190075Sobrien 8290075Sobrien present = 0; 8390075Sobrien doid = packet_get_string(&len); 8490075Sobrien 8590075Sobrien if (len > 2 && doid[0] == SSH_GSS_OIDTYPE && 8690075Sobrien doid[1] == len - 2) { 8790075Sobrien goid.elements = doid + 2; 8890075Sobrien goid.length = len - 2; 8990075Sobrien gss_test_oid_set_member(&ms, &goid, supported, 9090075Sobrien &present); 9190075Sobrien } else { 9290075Sobrien logit("Badly formed OID received"); 9390075Sobrien } 9490075Sobrien } while (mechs > 0 && !present); 9590075Sobrien 9690075Sobrien gss_release_oid_set(&ms, &supported); 9790075Sobrien 9890075Sobrien if (!present) { 9990075Sobrien xfree(doid); 10090075Sobrien return (0); 10190075Sobrien } 10290075Sobrien 10390075Sobrien if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { 10490075Sobrien xfree(doid); 10590075Sobrien return (0); 10690075Sobrien } 10790075Sobrien 10890075Sobrien authctxt->methoddata=(void *)ctxt; 10990075Sobrien 11090075Sobrien packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE); 11190075Sobrien 11290075Sobrien /* Return the OID that we received */ 11390075Sobrien packet_put_string(doid, len); 11490075Sobrien 11590075Sobrien packet_send(); 11690075Sobrien xfree(doid); 11790075Sobrien 11890075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 11990075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 12090075Sobrien authctxt->postponed = 1; 12190075Sobrien 12290075Sobrien return (0); 12390075Sobrien} 12490075Sobrien 12590075Sobrienstatic void 12690075Sobrieninput_gssapi_token(int type, u_int32_t plen, void *ctxt) 12790075Sobrien{ 12890075Sobrien Authctxt *authctxt = ctxt; 12990075Sobrien Gssctxt *gssctxt; 13090075Sobrien gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 13190075Sobrien gss_buffer_desc recv_tok; 13290075Sobrien OM_uint32 maj_status, min_status, flags; 13390075Sobrien u_int len; 13490075Sobrien 13590075Sobrien if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 13690075Sobrien fatal("No authentication or GSSAPI context"); 13790075Sobrien 13890075Sobrien gssctxt = authctxt->methoddata; 13990075Sobrien recv_tok.value = packet_get_string(&len); 14090075Sobrien recv_tok.length = len; /* u_int vs. size_t */ 14190075Sobrien 14290075Sobrien packet_check_eom(); 14390075Sobrien 14490075Sobrien maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 14590075Sobrien &send_tok, &flags)); 14690075Sobrien 14790075Sobrien xfree(recv_tok.value); 14890075Sobrien 14990075Sobrien if (GSS_ERROR(maj_status)) { 15090075Sobrien if (send_tok.length != 0) { 15190075Sobrien packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 15290075Sobrien packet_put_string(send_tok.value, send_tok.length); 15390075Sobrien packet_send(); 15490075Sobrien } 15590075Sobrien authctxt->postponed = 0; 15690075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 15790075Sobrien userauth_finish(authctxt, 0, "gssapi-with-mic"); 15890075Sobrien } else { 15990075Sobrien if (send_tok.length != 0) { 16090075Sobrien packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 16190075Sobrien packet_put_string(send_tok.value, send_tok.length); 16290075Sobrien packet_send(); 16390075Sobrien } 16490075Sobrien if (maj_status == GSS_S_COMPLETE) { 16590075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 16690075Sobrien if (flags & GSS_C_INTEG_FLAG) 16790075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, 16890075Sobrien &input_gssapi_mic); 16990075Sobrien else 17090075Sobrien dispatch_set( 17190075Sobrien SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, 17290075Sobrien &input_gssapi_exchange_complete); 17390075Sobrien } 17490075Sobrien } 17590075Sobrien 17690075Sobrien gss_release_buffer(&min_status, &send_tok); 17790075Sobrien} 17890075Sobrien 17990075Sobrienstatic void 18090075Sobrieninput_gssapi_errtok(int type, u_int32_t plen, void *ctxt) 18190075Sobrien{ 18290075Sobrien Authctxt *authctxt = ctxt; 18390075Sobrien Gssctxt *gssctxt; 18490075Sobrien gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 18590075Sobrien gss_buffer_desc recv_tok; 18690075Sobrien OM_uint32 maj_status; 18790075Sobrien u_int len; 18890075Sobrien 18990075Sobrien if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 19090075Sobrien fatal("No authentication or GSSAPI context"); 19190075Sobrien 19290075Sobrien gssctxt = authctxt->methoddata; 19390075Sobrien recv_tok.value = packet_get_string(&len); 19490075Sobrien recv_tok.length = len; 19590075Sobrien 19690075Sobrien packet_check_eom(); 19790075Sobrien 19890075Sobrien /* Push the error token into GSSAPI to see what it says */ 19990075Sobrien maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 20090075Sobrien &send_tok, NULL)); 20190075Sobrien 20290075Sobrien xfree(recv_tok.value); 20390075Sobrien 20490075Sobrien /* We can't return anything to the client, even if we wanted to */ 20590075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 20690075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 20790075Sobrien 20890075Sobrien /* The client will have already moved on to the next auth */ 20990075Sobrien 21090075Sobrien gss_release_buffer(&maj_status, &send_tok); 21190075Sobrien} 21290075Sobrien 21390075Sobrien/* 21490075Sobrien * This is called when the client thinks we've completed authentication. 21590075Sobrien * It should only be enabled in the dispatch handler by the function above, 21690075Sobrien * which only enables it once the GSSAPI exchange is complete. 21790075Sobrien */ 21890075Sobrien 21990075Sobrienstatic void 22090075Sobrieninput_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) 22190075Sobrien{ 22290075Sobrien Authctxt *authctxt = ctxt; 22390075Sobrien Gssctxt *gssctxt; 22490075Sobrien int authenticated; 22590075Sobrien 22690075Sobrien if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 22790075Sobrien fatal("No authentication or GSSAPI context"); 22890075Sobrien 22990075Sobrien gssctxt = authctxt->methoddata; 23090075Sobrien 23190075Sobrien /* 23290075Sobrien * We don't need to check the status, because we're only enabled in 23390075Sobrien * the dispatcher once the exchange is complete 23490075Sobrien */ 23590075Sobrien 23690075Sobrien packet_check_eom(); 23790075Sobrien 23890075Sobrien authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 23990075Sobrien 24090075Sobrien authctxt->postponed = 0; 24190075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 24290075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 24390075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 24490075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 24590075Sobrien userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 24690075Sobrien} 24790075Sobrien 24890075Sobrienstatic void 24990075Sobrieninput_gssapi_mic(int type, u_int32_t plen, void *ctxt) 25090075Sobrien{ 25190075Sobrien Authctxt *authctxt = ctxt; 25290075Sobrien Gssctxt *gssctxt; 25390075Sobrien int authenticated = 0; 25490075Sobrien Buffer b; 25590075Sobrien gss_buffer_desc mic, gssbuf; 25690075Sobrien u_int len; 25790075Sobrien 25890075Sobrien if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 25990075Sobrien fatal("No authentication or GSSAPI context"); 26090075Sobrien 26190075Sobrien gssctxt = authctxt->methoddata; 26290075Sobrien 26390075Sobrien mic.value = packet_get_string(&len); 26490075Sobrien mic.length = len; 26590075Sobrien 26690075Sobrien ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, 26790075Sobrien "gssapi-with-mic"); 26890075Sobrien 26990075Sobrien gssbuf.value = buffer_ptr(&b); 27090075Sobrien gssbuf.length = buffer_len(&b); 27190075Sobrien 27290075Sobrien if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 27390075Sobrien authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 27490075Sobrien else 27590075Sobrien logit("GSSAPI MIC check failed"); 27690075Sobrien 27790075Sobrien buffer_free(&b); 27890075Sobrien xfree(mic.value); 27990075Sobrien 28090075Sobrien authctxt->postponed = 0; 28190075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 28290075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 28390075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 28490075Sobrien dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 28590075Sobrien userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 28690075Sobrien} 28790075Sobrien 28890075SobrienAuthmethod method_gssapi = { 28990075Sobrien "gssapi-with-mic", 29090075Sobrien userauth_gssapi, 29190075Sobrien &options.gss_authentication 29290075Sobrien}; 29390075Sobrien 29490075Sobrien#endif /* GSSAPI */ 29590075Sobrien