auth2-gss.c revision 126274
1141104Sharti/*	$OpenBSD: auth2-gss.c,v 1.7 2003/11/21 11:57:03 djm Exp $	*/
21590Srgrimes
31590Srgrimes/*
41590Srgrimes * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
51590Srgrimes *
61590Srgrimes * Redistribution and use in source and binary forms, with or without
71590Srgrimes * modification, are permitted provided that the following conditions
81590Srgrimes * are met:
91590Srgrimes * 1. Redistributions of source code must retain the above copyright
101590Srgrimes *    notice, this list of conditions and the following disclaimer.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes *
151590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
161590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include "includes.h"
281590Srgrimes
291590Srgrimes#ifdef GSSAPI
301590Srgrimes
311590Srgrimes#include "auth.h"
321590Srgrimes#include "ssh2.h"
331590Srgrimes#include "xmalloc.h"
341590Srgrimes#include "log.h"
351590Srgrimes#include "dispatch.h"
361590Srgrimes#include "servconf.h"
3762833Swsanchez#include "compat.h"
3862833Swsanchez#include "packet.h"
391590Srgrimes#include "monitor_wrap.h"
401590Srgrimes
4162833Swsanchez#include "ssh-gss.h"
4294587Sobrien
431590Srgrimesextern ServerOptions options;
441590Srgrimes
451590Srgrimesstatic void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
461590Srgrimesstatic void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
471590Srgrimesstatic void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
481590Srgrimesstatic void input_gssapi_errtok(int, u_int32_t, void *);
491590Srgrimes
501590Srgrimes/*
511590Srgrimes * We only support those mechanisms that we know about (ie ones that we know
521590Srgrimes * how to check local user kuserok and the like
531590Srgrimes */
541590Srgrimesstatic int
55141270Shartiuserauth_gssapi(Authctxt *authctxt)
56141270Sharti{
57146338Sharti	gss_OID_desc oid = {0, NULL};
58141270Sharti	Gssctxt *ctxt = NULL;
591590Srgrimes	int mechs;
60141270Sharti	gss_OID_set supported;
61141270Sharti	int present;
62141270Sharti	OM_uint32 ms;
631590Srgrimes	u_int len;
64141270Sharti	char *doid = NULL;
65141270Sharti
66141270Sharti	if (!authctxt->valid || authctxt->user == NULL)
67141270Sharti		return (0);
681590Srgrimes
69141270Sharti	mechs = packet_get_int();
70141270Sharti	if (mechs == 0) {
71141270Sharti		debug("Mechanism negotiation is not supported");
72141270Sharti		return (0);
731590Srgrimes	}
74141270Sharti
75141270Sharti	ssh_gssapi_supported_oids(&supported);
76141270Sharti	do {
77141270Sharti		mechs--;
78141270Sharti
791590Srgrimes		if (doid)
80141270Sharti			xfree(doid);
81141270Sharti
82141270Sharti		present = 0;
831590Srgrimes		doid = packet_get_string(&len);
84141270Sharti
85141270Sharti		if (len > 2 &&
861590Srgrimes		   doid[0] == SSH_GSS_OIDTYPE &&
87141270Sharti		   doid[1] == len - 2) {
881590Srgrimes			oid.elements = doid + 2;
891590Srgrimes			oid.length   = len - 2;
90141104Sharti			gss_test_oid_set_member(&ms, &oid, supported,
91144387Sharti			    &present);
92141104Sharti		} else {
93141104Sharti			logit("Badly formed OID received");
94141104Sharti		}
95144387Sharti	} while (mechs > 0 && !present);
96144387Sharti
97176799Simp	gss_release_oid_set(&ms, &supported);
98141104Sharti
99141104Sharti	if (!present) {
100141104Sharti		xfree(doid);
101141104Sharti		return (0);
102141104Sharti	}
1031590Srgrimes
104141104Sharti	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &oid)))) {
105142457Sharti		xfree(doid);
106200630Sstas		return (0);
107141104Sharti	}
108141104Sharti
109141104Sharti	authctxt->methoddata=(void *)ctxt;
110141104Sharti
111141104Sharti	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
112146066Sharti
113141104Sharti	/* Return the OID that we received */
114141104Sharti	packet_put_string(doid, len);
115141104Sharti
116141104Sharti	packet_send();
1171590Srgrimes	xfree(doid);
118142173Sharti
119142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
120142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
121142173Sharti	authctxt->postponed = 1;
122142173Sharti
123142173Sharti	return (0);
124142173Sharti}
125143657Sharti
126144387Shartistatic void
1271590Srgrimesinput_gssapi_token(int type, u_int32_t plen, void *ctxt)
1281590Srgrimes{
129144387Sharti	Authctxt *authctxt = ctxt;
130144387Sharti	Gssctxt *gssctxt;
1311590Srgrimes	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
132144387Sharti	gss_buffer_desc recv_tok;
133144387Sharti	OM_uint32 maj_status, min_status, flags;
134144387Sharti	u_int len;
135144387Sharti
136144387Sharti	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
137144387Sharti		fatal("No authentication or GSSAPI context");
138144387Sharti
139144387Sharti	gssctxt = authctxt->methoddata;
140144387Sharti	recv_tok.value = packet_get_string(&len);
141144387Sharti	recv_tok.length = len; /* u_int vs. size_t */
142144387Sharti
143144387Sharti	packet_check_eom();
144144387Sharti
145144387Sharti	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
146144387Sharti	    &send_tok, &flags));
147144387Sharti
148144387Sharti	xfree(recv_tok.value);
149144387Sharti
150144387Sharti	if (GSS_ERROR(maj_status)) {
151144387Sharti		if (send_tok.length != 0) {
152144387Sharti			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
153144387Sharti			packet_put_string(send_tok.value, send_tok.length);
154144387Sharti			packet_send();
155144387Sharti		}
156144387Sharti		authctxt->postponed = 0;
157144387Sharti		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
158144387Sharti		userauth_finish(authctxt, 0, "gssapi-with-mic");
159144387Sharti	} else {
160144387Sharti		if (send_tok.length != 0) {
161144387Sharti			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
162144387Sharti			packet_put_string(send_tok.value, send_tok.length);
163144387Sharti			packet_send();
164144387Sharti		}
165144387Sharti		if (maj_status == GSS_S_COMPLETE) {
166144387Sharti			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
167144387Sharti			if (flags & GSS_C_INTEG_FLAG)
168144387Sharti				dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
169144387Sharti				    &input_gssapi_mic);
170144387Sharti			else
171144387Sharti				dispatch_set(
172144387Sharti				    SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
173144387Sharti				    &input_gssapi_exchange_complete);
174144387Sharti		}
175144387Sharti	}
176144387Sharti
177144387Sharti	gss_release_buffer(&min_status, &send_tok);
178144387Sharti}
179144387Sharti
180144387Shartistatic void
181144387Shartiinput_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
182144387Sharti{
183144387Sharti	Authctxt *authctxt = ctxt;
184144387Sharti	Gssctxt *gssctxt;
185144387Sharti	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
186144387Sharti	gss_buffer_desc recv_tok;
187144387Sharti	OM_uint32 maj_status;
188144387Sharti	u_int len;
189144387Sharti
190144387Sharti	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
191144387Sharti		fatal("No authentication or GSSAPI context");
192144387Sharti
193144387Sharti	gssctxt = authctxt->methoddata;
1941590Srgrimes	recv_tok.value = packet_get_string(&len);
1951590Srgrimes	recv_tok.length = len;
1961590Srgrimes
1971590Srgrimes	packet_check_eom();
1981590Srgrimes
199104696Sjmallett	/* Push the error token into GSSAPI to see what it says */
200104696Sjmallett	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
201104696Sjmallett	    &send_tok, NULL));
2021590Srgrimes
2031590Srgrimes	xfree(recv_tok.value);
204146338Sharti
2051590Srgrimes	/* We can't return anything to the client, even if we wanted to */
2061590Srgrimes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2071590Srgrimes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
2081590Srgrimes
2091590Srgrimes	/* The client will have already moved on to the next auth */
2101590Srgrimes
2111590Srgrimes	gss_release_buffer(&maj_status, &send_tok);
2121590Srgrimes}
213146338Sharti
214138512Sharti/*
2151590Srgrimes * This is called when the client thinks we've completed authentication.
216142173Sharti * It should only be enabled in the dispatch handler by the function above,
217142173Sharti * which only enables it once the GSSAPI exchange is complete.
218142173Sharti */
219142173Sharti
220142173Shartistatic void
221142173Shartiinput_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
222142173Sharti{
223141270Sharti	Authctxt *authctxt = ctxt;
2241590Srgrimes	Gssctxt *gssctxt;
225142173Sharti	int authenticated;
2268874Srgrimes
227142173Sharti	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
2281590Srgrimes		fatal("No authentication or GSSAPI context");
229142173Sharti
230142173Sharti	gssctxt = authctxt->methoddata;
231142173Sharti
232142173Sharti	/*
233142173Sharti	 * We don't need to check the status, because we're only enabled in
234142173Sharti	 * the dispatcher once the exchange is complete
235142937Sharti	 */
236142173Sharti
237142173Sharti	packet_check_eom();
2388874Srgrimes
239142173Sharti	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
240142173Sharti
241146338Sharti	authctxt->postponed = 0;
242142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
243142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
2448874Srgrimes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
245142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
246142173Sharti	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
247142173Sharti}
248142173Sharti
249142173Shartistatic void
2501590Srgrimesinput_gssapi_mic(int type, u_int32_t plen, void *ctxt)
2511590Srgrimes{
252142173Sharti	Authctxt *authctxt = ctxt;
253142173Sharti	Gssctxt *gssctxt;
254146027Sharti	int authenticated = 0;
255142173Sharti	Buffer b;
2561590Srgrimes	gss_buffer_desc mic, gssbuf;
257142173Sharti	u_int len;
258142173Sharti
259142173Sharti	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
260142173Sharti		fatal("No authentication or GSSAPI context");
261142173Sharti
262142173Sharti	gssctxt = authctxt->methoddata;
2631590Srgrimes
2641590Srgrimes	mic.value = packet_get_string(&len);
265142173Sharti	mic.length = len;
2661590Srgrimes
267142173Sharti	ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
2681590Srgrimes	    "gssapi-with-mic");
269142173Sharti
270142173Sharti	gssbuf.value = buffer_ptr(&b);
271143105Sharti	gssbuf.length = buffer_len(&b);
2721590Srgrimes
2731590Srgrimes	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
274142173Sharti		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
275142173Sharti	else
276142173Sharti		logit("GSSAPI MIC check failed");
277142173Sharti
278142173Sharti	buffer_free(&b);
279142173Sharti	xfree(mic.value);
280142173Sharti
281142173Sharti	authctxt->postponed = 0;
282142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
283142937Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
284142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
285142173Sharti	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
286142173Sharti	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
287142173Sharti}
288142173Sharti
289142173ShartiAuthmethod method_gssapi = {
290146338Sharti	"gssapi-with-mic",
291142173Sharti	userauth_gssapi,
292142173Sharti	&options.gss_authentication
293142173Sharti};
294142173Sharti
295142173Sharti#endif /* GSSAPI */
296142173Sharti