Home | History | Annotate | Download | only in openssh
      1 /* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "includes.h"
     28 
     29 #ifdef GSSAPI
     30 
     31 #include <sys/types.h>
     32 
     33 #include <stdarg.h>
     34 
     35 #include "xmalloc.h"
     36 #include "key.h"
     37 #include "hostfile.h"
     38 #include "auth.h"
     39 #include "ssh2.h"
     40 #include "log.h"
     41 #include "dispatch.h"
     42 #include "buffer.h"
     43 #include "misc.h"
     44 #include "servconf.h"
     45 #include "packet.h"
     46 #include "ssh-gss.h"
     47 #include "monitor_wrap.h"
     48 
     49 extern ServerOptions options;
     50 
     51 static int input_gssapi_token(int type, u_int32_t plen, void *ctxt);
     52 static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
     53 static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
     54 static int input_gssapi_errtok(int, u_int32_t, void *);
     55 
     56 /*
     57  * We only support those mechanisms that we know about (ie ones that we know
     58  * how to check local user kuserok and the like)
     59  */
     60 static int
     61 userauth_gssapi(Authctxt *authctxt)
     62 {
     63 	gss_OID_desc goid = {0, NULL};
     64 	Gssctxt *ctxt = NULL;
     65 	int mechs;
     66 	int present;
     67 	OM_uint32 ms;
     68 	u_int len;
     69 	u_char *doid = NULL;
     70 
     71 	if (!authctxt->valid || authctxt->user == NULL)
     72 		return (0);
     73 
     74 	mechs = packet_get_int();
     75 	if (mechs == 0) {
     76 		debug("Mechanism negotiation is not supported");
     77 		return (0);
     78 	}
     79 
     80 	do {
     81 		mechs--;
     82 
     83 		free(doid);
     84 
     85 		present = 0;
     86 		doid = packet_get_string(&len);
     87 
     88 		if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
     89 		    doid[1] == len - 2) {
     90 			goid.elements = doid + 2;
     91 			goid.length   = len - 2;
     92 			ssh_gssapi_test_oid_supported(&ms, &goid, &present);
     93 		} else {
     94 			logit("Badly formed OID received");
     95 		}
     96 	} while (mechs > 0 && !present);
     97 
     98 	if (!present) {
     99 		free(doid);
    100 		authctxt->server_caused_failure = 1;
    101 		return (0);
    102 	}
    103 
    104 	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
    105 		if (ctxt != NULL)
    106 			ssh_gssapi_delete_ctx(&ctxt);
    107 		free(doid);
    108 		authctxt->server_caused_failure = 1;
    109 		return (0);
    110 	}
    111 
    112 	authctxt->methoddata = (void *)ctxt;
    113 
    114 	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
    115 
    116 	/* Return the OID that we received */
    117 	packet_put_string(doid, len);
    118 
    119 	packet_send();
    120 	free(doid);
    121 
    122 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
    123 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
    124 	authctxt->postponed = 1;
    125 
    126 	return (0);
    127 }
    128 
    129 static int
    130 input_gssapi_token(int type, u_int32_t plen, void *ctxt)
    131 {
    132 	Authctxt *authctxt = ctxt;
    133 	Gssctxt *gssctxt;
    134 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
    135 	gss_buffer_desc recv_tok;
    136 	OM_uint32 maj_status, min_status, flags;
    137 	u_int len;
    138 
    139 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
    140 		fatal("No authentication or GSSAPI context");
    141 
    142 	gssctxt = authctxt->methoddata;
    143 	recv_tok.value = packet_get_string(&len);
    144 	recv_tok.length = len; /* u_int vs. size_t */
    145 
    146 	packet_check_eom();
    147 
    148 	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
    149 	    &send_tok, &flags));
    150 
    151 	free(recv_tok.value);
    152 
    153 	if (GSS_ERROR(maj_status)) {
    154 		if (send_tok.length != 0) {
    155 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
    156 			packet_put_string(send_tok.value, send_tok.length);
    157 			packet_send();
    158 		}
    159 		authctxt->postponed = 0;
    160 		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
    161 		userauth_finish(authctxt, 0, "gssapi-with-mic", NULL);
    162 	} else {
    163 		if (send_tok.length != 0) {
    164 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
    165 			packet_put_string(send_tok.value, send_tok.length);
    166 			packet_send();
    167 		}
    168 		if (maj_status == GSS_S_COMPLETE) {
    169 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
    170 			if (flags & GSS_C_INTEG_FLAG)
    171 				dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
    172 				    &input_gssapi_mic);
    173 			else
    174 				dispatch_set(
    175 				    SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
    176 				    &input_gssapi_exchange_complete);
    177 		}
    178 	}
    179 
    180 	gss_release_buffer(&min_status, &send_tok);
    181 	return 0;
    182 }
    183 
    184 static int
    185 input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
    186 {
    187 	Authctxt *authctxt = ctxt;
    188 	Gssctxt *gssctxt;
    189 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
    190 	gss_buffer_desc recv_tok;
    191 	OM_uint32 maj_status;
    192 	u_int len;
    193 
    194 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
    195 		fatal("No authentication or GSSAPI context");
    196 
    197 	gssctxt = authctxt->methoddata;
    198 	recv_tok.value = packet_get_string(&len);
    199 	recv_tok.length = len;
    200 
    201 	packet_check_eom();
    202 
    203 	/* Push the error token into GSSAPI to see what it says */
    204 	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
    205 	    &send_tok, NULL));
    206 
    207 	free(recv_tok.value);
    208 
    209 	/* We can't return anything to the client, even if we wanted to */
    210 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
    211 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
    212 
    213 	/* The client will have already moved on to the next auth */
    214 
    215 	gss_release_buffer(&maj_status, &send_tok);
    216 	return 0;
    217 }
    218 
    219 /*
    220  * This is called when the client thinks we've completed authentication.
    221  * It should only be enabled in the dispatch handler by the function above,
    222  * which only enables it once the GSSAPI exchange is complete.
    223  */
    224 
    225 static int
    226 input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
    227 {
    228 	Authctxt *authctxt = ctxt;
    229 	int authenticated;
    230 
    231 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
    232 		fatal("No authentication or GSSAPI context");
    233 
    234 	/*
    235 	 * We don't need to check the status, because we're only enabled in
    236 	 * the dispatcher once the exchange is complete
    237 	 */
    238 
    239 	packet_check_eom();
    240 
    241 	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
    242 
    243 	authctxt->postponed = 0;
    244 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
    245 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
    246 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
    247 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
    248 	userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
    249 	return 0;
    250 }
    251 
    252 static int
    253 input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
    254 {
    255 	Authctxt *authctxt = ctxt;
    256 	Gssctxt *gssctxt;
    257 	int authenticated = 0;
    258 	Buffer b;
    259 	gss_buffer_desc mic, gssbuf;
    260 	u_int len;
    261 
    262 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
    263 		fatal("No authentication or GSSAPI context");
    264 
    265 	gssctxt = authctxt->methoddata;
    266 
    267 	mic.value = packet_get_string(&len);
    268 	mic.length = len;
    269 
    270 	ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
    271 	    "gssapi-with-mic");
    272 
    273 	gssbuf.value = buffer_ptr(&b);
    274 	gssbuf.length = buffer_len(&b);
    275 
    276 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
    277 		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
    278 	else
    279 		logit("GSSAPI MIC check failed");
    280 
    281 	buffer_free(&b);
    282 	free(mic.value);
    283 
    284 	authctxt->postponed = 0;
    285 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
    286 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
    287 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
    288 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
    289 	userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
    290 	return 0;
    291 }
    292 
    293 Authmethod method_gssapi = {
    294 	"gssapi-with-mic",
    295 	userauth_gssapi,
    296 	&options.gss_authentication
    297 };
    298 
    299 #endif /* GSSAPI */
    300