xref: /freebsd/crypto/heimdal/appl/ftp/ftpd/gssapi.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1c19800e8SDoug Rabson /*
2*ae771770SStanislav Sedov  * Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34c19800e8SDoug Rabson #ifdef FTP_SERVER
35c19800e8SDoug Rabson #include "ftpd_locl.h"
36c19800e8SDoug Rabson #else
37c19800e8SDoug Rabson #include "ftp_locl.h"
38c19800e8SDoug Rabson #endif
39*ae771770SStanislav Sedov #include <gssapi/gssapi.h>
40*ae771770SStanislav Sedov #include <gssapi/gssapi_krb5.h>
41c19800e8SDoug Rabson #include <krb5_err.h>
42c19800e8SDoug Rabson 
43*ae771770SStanislav Sedov RCSID("$Id$");
44c19800e8SDoug Rabson 
45c19800e8SDoug Rabson int ftp_do_gss_bindings = 0;
46c19800e8SDoug Rabson int ftp_do_gss_delegate = 1;
47c19800e8SDoug Rabson 
48*ae771770SStanislav Sedov struct gssapi_data {
49c19800e8SDoug Rabson     gss_ctx_id_t context_hdl;
50*ae771770SStanislav Sedov     gss_name_t client_name;
51c19800e8SDoug Rabson     gss_cred_id_t delegated_cred_handle;
52c19800e8SDoug Rabson     void *mech_data;
53c19800e8SDoug Rabson };
54c19800e8SDoug Rabson 
55c19800e8SDoug Rabson static int
gss_init(void * app_data)56c19800e8SDoug Rabson gss_init(void *app_data)
57c19800e8SDoug Rabson {
58*ae771770SStanislav Sedov     struct gssapi_data *d = app_data;
59c19800e8SDoug Rabson     d->context_hdl = GSS_C_NO_CONTEXT;
60c19800e8SDoug Rabson     d->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
61c19800e8SDoug Rabson #if defined(FTP_SERVER)
62c19800e8SDoug Rabson     return 0;
63c19800e8SDoug Rabson #else
64c19800e8SDoug Rabson     /* XXX Check the gss mechanism; with  gss_indicate_mechs() ? */
65c19800e8SDoug Rabson #ifdef KRB5
66c19800e8SDoug Rabson     return !use_kerberos;
67c19800e8SDoug Rabson #else
68c19800e8SDoug Rabson     return 0;
69c19800e8SDoug Rabson #endif /* KRB5 */
70c19800e8SDoug Rabson #endif /* FTP_SERVER */
71c19800e8SDoug Rabson }
72c19800e8SDoug Rabson 
73c19800e8SDoug Rabson static int
gss_check_prot(void * app_data,int level)74c19800e8SDoug Rabson gss_check_prot(void *app_data, int level)
75c19800e8SDoug Rabson {
76c19800e8SDoug Rabson     if(level == prot_confidential)
77c19800e8SDoug Rabson 	return -1;
78c19800e8SDoug Rabson     return 0;
79c19800e8SDoug Rabson }
80c19800e8SDoug Rabson 
81c19800e8SDoug Rabson static int
gss_decode(void * app_data,void * buf,int len,int level)82c19800e8SDoug Rabson gss_decode(void *app_data, void *buf, int len, int level)
83c19800e8SDoug Rabson {
84c19800e8SDoug Rabson     OM_uint32 maj_stat, min_stat;
85c19800e8SDoug Rabson     gss_buffer_desc input, output;
86c19800e8SDoug Rabson     gss_qop_t qop_state;
87c19800e8SDoug Rabson     int conf_state;
88*ae771770SStanislav Sedov     struct gssapi_data *d = app_data;
89c19800e8SDoug Rabson     size_t ret_len;
90c19800e8SDoug Rabson 
91c19800e8SDoug Rabson     input.length = len;
92c19800e8SDoug Rabson     input.value = buf;
93c19800e8SDoug Rabson     maj_stat = gss_unwrap (&min_stat,
94c19800e8SDoug Rabson 			   d->context_hdl,
95c19800e8SDoug Rabson 			   &input,
96c19800e8SDoug Rabson 			   &output,
97c19800e8SDoug Rabson 			   &conf_state,
98c19800e8SDoug Rabson 			   &qop_state);
99c19800e8SDoug Rabson     if(GSS_ERROR(maj_stat))
100c19800e8SDoug Rabson 	return -1;
101c19800e8SDoug Rabson     memmove(buf, output.value, output.length);
102c19800e8SDoug Rabson     ret_len = output.length;
103c19800e8SDoug Rabson     gss_release_buffer(&min_stat, &output);
104c19800e8SDoug Rabson     return ret_len;
105c19800e8SDoug Rabson }
106c19800e8SDoug Rabson 
107c19800e8SDoug Rabson static int
gss_overhead(void * app_data,int level,int len)108c19800e8SDoug Rabson gss_overhead(void *app_data, int level, int len)
109c19800e8SDoug Rabson {
110c19800e8SDoug Rabson     return 100; /* dunno? */
111c19800e8SDoug Rabson }
112c19800e8SDoug Rabson 
113c19800e8SDoug Rabson 
114c19800e8SDoug Rabson static int
gss_encode(void * app_data,void * from,int length,int level,void ** to)115c19800e8SDoug Rabson gss_encode(void *app_data, void *from, int length, int level, void **to)
116c19800e8SDoug Rabson {
117c19800e8SDoug Rabson     OM_uint32 maj_stat, min_stat;
118c19800e8SDoug Rabson     gss_buffer_desc input, output;
119c19800e8SDoug Rabson     int conf_state;
120*ae771770SStanislav Sedov     struct gssapi_data *d = app_data;
121c19800e8SDoug Rabson 
122c19800e8SDoug Rabson     input.length = length;
123c19800e8SDoug Rabson     input.value = from;
124c19800e8SDoug Rabson     maj_stat = gss_wrap (&min_stat,
125c19800e8SDoug Rabson 			 d->context_hdl,
126c19800e8SDoug Rabson 			 level == prot_private,
127c19800e8SDoug Rabson 			 GSS_C_QOP_DEFAULT,
128c19800e8SDoug Rabson 			 &input,
129c19800e8SDoug Rabson 			 &conf_state,
130c19800e8SDoug Rabson 			 &output);
131c19800e8SDoug Rabson     *to = output.value;
132c19800e8SDoug Rabson     return output.length;
133c19800e8SDoug Rabson }
134c19800e8SDoug Rabson 
135c19800e8SDoug Rabson static void
sockaddr_to_gss_address(struct sockaddr * sa,OM_uint32 * addr_type,gss_buffer_desc * gss_addr)136c19800e8SDoug Rabson sockaddr_to_gss_address (struct sockaddr *sa,
137c19800e8SDoug Rabson 			 OM_uint32 *addr_type,
138c19800e8SDoug Rabson 			 gss_buffer_desc *gss_addr)
139c19800e8SDoug Rabson {
140c19800e8SDoug Rabson     switch (sa->sa_family) {
141c19800e8SDoug Rabson #ifdef HAVE_IPV6
142c19800e8SDoug Rabson     case AF_INET6 : {
143c19800e8SDoug Rabson 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
144c19800e8SDoug Rabson 
145c19800e8SDoug Rabson 	gss_addr->length = 16;
146c19800e8SDoug Rabson 	gss_addr->value  = &sin6->sin6_addr;
147c19800e8SDoug Rabson 	*addr_type       = GSS_C_AF_INET6;
148c19800e8SDoug Rabson 	break;
149c19800e8SDoug Rabson     }
150c19800e8SDoug Rabson #endif
151c19800e8SDoug Rabson     case AF_INET : {
152c19800e8SDoug Rabson 	struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
153c19800e8SDoug Rabson 
154c19800e8SDoug Rabson 	gss_addr->length = 4;
155c19800e8SDoug Rabson 	gss_addr->value  = &sin4->sin_addr;
156c19800e8SDoug Rabson 	*addr_type       = GSS_C_AF_INET;
157c19800e8SDoug Rabson 	break;
158c19800e8SDoug Rabson     }
159c19800e8SDoug Rabson     default :
160c19800e8SDoug Rabson 	errx (1, "unknown address family %d", sa->sa_family);
161c19800e8SDoug Rabson 
162c19800e8SDoug Rabson     }
163c19800e8SDoug Rabson }
164c19800e8SDoug Rabson 
165c19800e8SDoug Rabson /* end common stuff */
166c19800e8SDoug Rabson 
167c19800e8SDoug Rabson #ifdef FTP_SERVER
168c19800e8SDoug Rabson 
169c19800e8SDoug Rabson static int
gss_adat(void * app_data,void * buf,size_t len)170c19800e8SDoug Rabson gss_adat(void *app_data, void *buf, size_t len)
171c19800e8SDoug Rabson {
172c19800e8SDoug Rabson     char *p = NULL;
173c19800e8SDoug Rabson     gss_buffer_desc input_token, output_token;
174c19800e8SDoug Rabson     OM_uint32 maj_stat, min_stat;
175c19800e8SDoug Rabson     gss_name_t client_name;
176*ae771770SStanislav Sedov     struct gssapi_data *d = app_data;
177c19800e8SDoug Rabson     gss_channel_bindings_t bindings;
178c19800e8SDoug Rabson 
179c19800e8SDoug Rabson     if (ftp_do_gss_bindings) {
180c19800e8SDoug Rabson 	bindings = malloc(sizeof(*bindings));
181c19800e8SDoug Rabson 	if (bindings == NULL)
182c19800e8SDoug Rabson 	    errx(1, "out of memory");
183c19800e8SDoug Rabson 
184c19800e8SDoug Rabson 	sockaddr_to_gss_address (his_addr,
185c19800e8SDoug Rabson 				 &bindings->initiator_addrtype,
186c19800e8SDoug Rabson 				 &bindings->initiator_address);
187c19800e8SDoug Rabson 	sockaddr_to_gss_address (ctrl_addr,
188c19800e8SDoug Rabson 				 &bindings->acceptor_addrtype,
189c19800e8SDoug Rabson 				 &bindings->acceptor_address);
190c19800e8SDoug Rabson 
191c19800e8SDoug Rabson 	bindings->application_data.length = 0;
192c19800e8SDoug Rabson 	bindings->application_data.value = NULL;
193c19800e8SDoug Rabson     } else
194c19800e8SDoug Rabson 	bindings = GSS_C_NO_CHANNEL_BINDINGS;
195c19800e8SDoug Rabson 
196c19800e8SDoug Rabson     input_token.value = buf;
197c19800e8SDoug Rabson     input_token.length = len;
198c19800e8SDoug Rabson 
199c19800e8SDoug Rabson     maj_stat = gss_accept_sec_context (&min_stat,
200c19800e8SDoug Rabson 				       &d->context_hdl,
201c19800e8SDoug Rabson 				       GSS_C_NO_CREDENTIAL,
202c19800e8SDoug Rabson 				       &input_token,
203c19800e8SDoug Rabson 				       bindings,
204c19800e8SDoug Rabson 				       &client_name,
205c19800e8SDoug Rabson 				       NULL,
206c19800e8SDoug Rabson 				       &output_token,
207c19800e8SDoug Rabson 				       NULL,
208c19800e8SDoug Rabson 				       NULL,
209c19800e8SDoug Rabson 				       &d->delegated_cred_handle);
210c19800e8SDoug Rabson 
211c19800e8SDoug Rabson     if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
212c19800e8SDoug Rabson 	free(bindings);
213c19800e8SDoug Rabson 
214c19800e8SDoug Rabson     if(output_token.length) {
215c19800e8SDoug Rabson 	if(base64_encode(output_token.value, output_token.length, &p) < 0) {
216c19800e8SDoug Rabson 	    reply(535, "Out of memory base64-encoding.");
217c19800e8SDoug Rabson 	    return -1;
218c19800e8SDoug Rabson 	}
219c19800e8SDoug Rabson 	gss_release_buffer(&min_stat, &output_token);
220c19800e8SDoug Rabson     }
221c19800e8SDoug Rabson     if(maj_stat == GSS_S_COMPLETE){
222*ae771770SStanislav Sedov 	d->client_name = client_name;
223*ae771770SStanislav Sedov 	client_name = GSS_C_NO_NAME;
224c19800e8SDoug Rabson 	if(p)
225c19800e8SDoug Rabson 	    reply(235, "ADAT=%s", p);
226c19800e8SDoug Rabson 	else
227c19800e8SDoug Rabson 	    reply(235, "ADAT Complete");
228c19800e8SDoug Rabson 	sec_complete = 1;
229c19800e8SDoug Rabson 
230c19800e8SDoug Rabson     } else if(maj_stat == GSS_S_CONTINUE_NEEDED) {
231c19800e8SDoug Rabson 	if(p)
232c19800e8SDoug Rabson 	    reply(335, "ADAT=%s", p);
233c19800e8SDoug Rabson 	else
234c19800e8SDoug Rabson 	    reply(335, "OK, need more data");
235c19800e8SDoug Rabson     } else {
236c19800e8SDoug Rabson 	OM_uint32 new_stat;
237c19800e8SDoug Rabson 	OM_uint32 msg_ctx = 0;
238c19800e8SDoug Rabson 	gss_buffer_desc status_string;
239c19800e8SDoug Rabson 	gss_display_status(&new_stat,
240c19800e8SDoug Rabson 			   min_stat,
241c19800e8SDoug Rabson 			   GSS_C_MECH_CODE,
242c19800e8SDoug Rabson 			   GSS_C_NO_OID,
243c19800e8SDoug Rabson 			   &msg_ctx,
244c19800e8SDoug Rabson 			   &status_string);
245*ae771770SStanislav Sedov 	syslog(LOG_ERR, "gss_accept_sec_context: %.*s",
246*ae771770SStanislav Sedov 	       (int)status_string.length,
247c19800e8SDoug Rabson 	       (char*)status_string.value);
248c19800e8SDoug Rabson 	gss_release_buffer(&new_stat, &status_string);
249c19800e8SDoug Rabson 	reply(431, "Security resource unavailable");
250c19800e8SDoug Rabson     }
251*ae771770SStanislav Sedov 
252c19800e8SDoug Rabson     if (client_name)
253c19800e8SDoug Rabson 	gss_release_name(&min_stat, &client_name);
254c19800e8SDoug Rabson     free(p);
255c19800e8SDoug Rabson     return 0;
256c19800e8SDoug Rabson }
257c19800e8SDoug Rabson 
258*ae771770SStanislav Sedov int gssapi_userok(void*, char*);
259*ae771770SStanislav Sedov int gssapi_session(void*, char*);
260c19800e8SDoug Rabson 
261c19800e8SDoug Rabson struct sec_server_mech gss_server_mech = {
262c19800e8SDoug Rabson     "GSSAPI",
263*ae771770SStanislav Sedov     sizeof(struct gssapi_data),
264c19800e8SDoug Rabson     gss_init, /* init */
265c19800e8SDoug Rabson     NULL, /* end */
266c19800e8SDoug Rabson     gss_check_prot,
267c19800e8SDoug Rabson     gss_overhead,
268c19800e8SDoug Rabson     gss_encode,
269c19800e8SDoug Rabson     gss_decode,
270c19800e8SDoug Rabson     /* */
271c19800e8SDoug Rabson     NULL,
272c19800e8SDoug Rabson     gss_adat,
273c19800e8SDoug Rabson     NULL, /* pbsz */
274c19800e8SDoug Rabson     NULL, /* ccc */
275*ae771770SStanislav Sedov     gssapi_userok,
276*ae771770SStanislav Sedov     gssapi_session
277c19800e8SDoug Rabson };
278c19800e8SDoug Rabson 
279c19800e8SDoug Rabson #else /* FTP_SERVER */
280c19800e8SDoug Rabson 
281c19800e8SDoug Rabson extern struct sockaddr *hisctladdr, *myctladdr;
282c19800e8SDoug Rabson 
283c19800e8SDoug Rabson static int
import_name(const char * kname,const char * host,gss_name_t * target_name)284c19800e8SDoug Rabson import_name(const char *kname, const char *host, gss_name_t *target_name)
285c19800e8SDoug Rabson {
286c19800e8SDoug Rabson     OM_uint32 maj_stat, min_stat;
287c19800e8SDoug Rabson     gss_buffer_desc name;
288c19800e8SDoug Rabson     char *str;
289c19800e8SDoug Rabson 
290c19800e8SDoug Rabson     name.length = asprintf(&str, "%s@%s", kname, host);
291c19800e8SDoug Rabson     if (str == NULL) {
292c19800e8SDoug Rabson 	printf("Out of memory\n");
293c19800e8SDoug Rabson 	return AUTH_ERROR;
294c19800e8SDoug Rabson     }
295c19800e8SDoug Rabson     name.value = str;
296c19800e8SDoug Rabson 
297c19800e8SDoug Rabson     maj_stat = gss_import_name(&min_stat,
298c19800e8SDoug Rabson 			       &name,
299c19800e8SDoug Rabson 			       GSS_C_NT_HOSTBASED_SERVICE,
300c19800e8SDoug Rabson 			       target_name);
301c19800e8SDoug Rabson     if (GSS_ERROR(maj_stat)) {
302c19800e8SDoug Rabson 	OM_uint32 new_stat;
303c19800e8SDoug Rabson 	OM_uint32 msg_ctx = 0;
304c19800e8SDoug Rabson 	gss_buffer_desc status_string;
305c19800e8SDoug Rabson 
306c19800e8SDoug Rabson 	gss_display_status(&new_stat,
307c19800e8SDoug Rabson 			   min_stat,
308c19800e8SDoug Rabson 			   GSS_C_MECH_CODE,
309c19800e8SDoug Rabson 			   GSS_C_NO_OID,
310c19800e8SDoug Rabson 			   &msg_ctx,
311c19800e8SDoug Rabson 			   &status_string);
312*ae771770SStanislav Sedov 	printf("Error importing name %.*s: %.*s\n",
313*ae771770SStanislav Sedov 	       (int)name.length,
314c19800e8SDoug Rabson 	       (char *)name.value,
315*ae771770SStanislav Sedov 	       (int)status_string.length,
316c19800e8SDoug Rabson 	       (char *)status_string.value);
317c19800e8SDoug Rabson 	free(name.value);
318c19800e8SDoug Rabson 	gss_release_buffer(&new_stat, &status_string);
319c19800e8SDoug Rabson 	return AUTH_ERROR;
320c19800e8SDoug Rabson     }
321c19800e8SDoug Rabson     free(name.value);
322c19800e8SDoug Rabson     return 0;
323c19800e8SDoug Rabson }
324c19800e8SDoug Rabson 
325c19800e8SDoug Rabson static int
gss_auth(void * app_data,char * host)326c19800e8SDoug Rabson gss_auth(void *app_data, char *host)
327c19800e8SDoug Rabson {
328c19800e8SDoug Rabson 
329c19800e8SDoug Rabson     OM_uint32 maj_stat, min_stat;
330c19800e8SDoug Rabson     gss_name_t target_name;
331c19800e8SDoug Rabson     gss_buffer_desc input, output_token;
332c19800e8SDoug Rabson     int context_established = 0;
333c19800e8SDoug Rabson     char *p;
334c19800e8SDoug Rabson     int n;
335c19800e8SDoug Rabson     gss_channel_bindings_t bindings;
336*ae771770SStanislav Sedov     struct gssapi_data *d = app_data;
337c19800e8SDoug Rabson     OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;
338c19800e8SDoug Rabson 
339c19800e8SDoug Rabson     const char *knames[] = { "ftp", "host", NULL }, **kname = knames;
340c19800e8SDoug Rabson 
341c19800e8SDoug Rabson 
342c19800e8SDoug Rabson     if(import_name(*kname++, host, &target_name))
343c19800e8SDoug Rabson 	return AUTH_ERROR;
344c19800e8SDoug Rabson 
345c19800e8SDoug Rabson     input.length = 0;
346c19800e8SDoug Rabson     input.value = NULL;
347c19800e8SDoug Rabson 
348c19800e8SDoug Rabson     if (ftp_do_gss_bindings) {
349c19800e8SDoug Rabson 	bindings = malloc(sizeof(*bindings));
350c19800e8SDoug Rabson 	if (bindings == NULL)
351c19800e8SDoug Rabson 	    errx(1, "out of memory");
352c19800e8SDoug Rabson 
353c19800e8SDoug Rabson 	sockaddr_to_gss_address (myctladdr,
354c19800e8SDoug Rabson 				 &bindings->initiator_addrtype,
355c19800e8SDoug Rabson 				 &bindings->initiator_address);
356c19800e8SDoug Rabson 	sockaddr_to_gss_address (hisctladdr,
357c19800e8SDoug Rabson 				 &bindings->acceptor_addrtype,
358c19800e8SDoug Rabson 				 &bindings->acceptor_address);
359c19800e8SDoug Rabson 
360c19800e8SDoug Rabson 	bindings->application_data.length = 0;
361c19800e8SDoug Rabson 	bindings->application_data.value = NULL;
362c19800e8SDoug Rabson     } else
363c19800e8SDoug Rabson 	bindings = GSS_C_NO_CHANNEL_BINDINGS;
364c19800e8SDoug Rabson 
365c19800e8SDoug Rabson     if (ftp_do_gss_delegate)
366c19800e8SDoug Rabson 	mech_flags |= GSS_C_DELEG_FLAG;
367c19800e8SDoug Rabson 
368c19800e8SDoug Rabson     while(!context_established) {
369c19800e8SDoug Rabson 	maj_stat = gss_init_sec_context(&min_stat,
370c19800e8SDoug Rabson 					GSS_C_NO_CREDENTIAL,
371c19800e8SDoug Rabson 					&d->context_hdl,
372c19800e8SDoug Rabson 					target_name,
373c19800e8SDoug Rabson 					GSS_C_NO_OID,
374c19800e8SDoug Rabson                                         mech_flags,
375c19800e8SDoug Rabson 					0,
376c19800e8SDoug Rabson 					bindings,
377c19800e8SDoug Rabson 					&input,
378c19800e8SDoug Rabson 					NULL,
379c19800e8SDoug Rabson 					&output_token,
380c19800e8SDoug Rabson 					NULL,
381c19800e8SDoug Rabson 					NULL);
382c19800e8SDoug Rabson 	if (GSS_ERROR(maj_stat)) {
383c19800e8SDoug Rabson 	    OM_uint32 new_stat;
384c19800e8SDoug Rabson 	    OM_uint32 msg_ctx = 0;
385c19800e8SDoug Rabson 	    gss_buffer_desc status_string;
386c19800e8SDoug Rabson 
387c19800e8SDoug Rabson 	    d->context_hdl = GSS_C_NO_CONTEXT;
388c19800e8SDoug Rabson 
389c19800e8SDoug Rabson 	    gss_release_name(&min_stat, &target_name);
390c19800e8SDoug Rabson 
391c19800e8SDoug Rabson 	    if(*kname != NULL) {
392c19800e8SDoug Rabson 
393c19800e8SDoug Rabson 		if(import_name(*kname++, host, &target_name)) {
394c19800e8SDoug Rabson 		    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
395c19800e8SDoug Rabson 			free(bindings);
396c19800e8SDoug Rabson 		    return AUTH_ERROR;
397c19800e8SDoug Rabson 		}
398c19800e8SDoug Rabson 		continue;
399c19800e8SDoug Rabson 	    }
400c19800e8SDoug Rabson 
401c19800e8SDoug Rabson 	    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
402c19800e8SDoug Rabson 		free(bindings);
403c19800e8SDoug Rabson 
404c19800e8SDoug Rabson 	    gss_display_status(&new_stat,
405c19800e8SDoug Rabson 			       min_stat,
406c19800e8SDoug Rabson 			       GSS_C_MECH_CODE,
407c19800e8SDoug Rabson 			       GSS_C_NO_OID,
408c19800e8SDoug Rabson 			       &msg_ctx,
409c19800e8SDoug Rabson 			       &status_string);
410*ae771770SStanislav Sedov 	    printf("Error initializing security context: %.*s\n",
411*ae771770SStanislav Sedov 		   (int)status_string.length,
412c19800e8SDoug Rabson 		   (char*)status_string.value);
413c19800e8SDoug Rabson 	    gss_release_buffer(&new_stat, &status_string);
414c19800e8SDoug Rabson 	    return AUTH_CONTINUE;
415c19800e8SDoug Rabson 	}
416c19800e8SDoug Rabson 
417c19800e8SDoug Rabson 	if (input.value) {
418c19800e8SDoug Rabson 	    free(input.value);
419c19800e8SDoug Rabson 	    input.value = NULL;
420c19800e8SDoug Rabson 	    input.length = 0;
421c19800e8SDoug Rabson 	}
422c19800e8SDoug Rabson 	if (output_token.length != 0) {
423c19800e8SDoug Rabson 	    base64_encode(output_token.value, output_token.length, &p);
424c19800e8SDoug Rabson 	    gss_release_buffer(&min_stat, &output_token);
425c19800e8SDoug Rabson 	    n = command("ADAT %s", p);
426c19800e8SDoug Rabson 	    free(p);
427c19800e8SDoug Rabson 	}
428c19800e8SDoug Rabson 	if (GSS_ERROR(maj_stat)) {
429c19800e8SDoug Rabson 	    if (d->context_hdl != GSS_C_NO_CONTEXT)
430c19800e8SDoug Rabson 		gss_delete_sec_context (&min_stat,
431c19800e8SDoug Rabson 					&d->context_hdl,
432c19800e8SDoug Rabson 					GSS_C_NO_BUFFER);
433c19800e8SDoug Rabson 	    break;
434c19800e8SDoug Rabson 	}
435c19800e8SDoug Rabson 	if (maj_stat & GSS_S_CONTINUE_NEEDED) {
436c19800e8SDoug Rabson 	    p = strstr(reply_string, "ADAT=");
437c19800e8SDoug Rabson 	    if(p == NULL){
438c19800e8SDoug Rabson 		printf("Error: expected ADAT in reply. got: %s\n",
439c19800e8SDoug Rabson 		       reply_string);
440c19800e8SDoug Rabson 		if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
441c19800e8SDoug Rabson 		    free(bindings);
442c19800e8SDoug Rabson 		return AUTH_ERROR;
443c19800e8SDoug Rabson 	    } else {
444c19800e8SDoug Rabson 		p+=5;
445c19800e8SDoug Rabson 		input.value = malloc(strlen(p));
446c19800e8SDoug Rabson 		input.length = base64_decode(p, input.value);
447c19800e8SDoug Rabson 	    }
448c19800e8SDoug Rabson 	} else {
449c19800e8SDoug Rabson 	    if(code != 235) {
450c19800e8SDoug Rabson 		printf("Unrecognized response code: %d\n", code);
451c19800e8SDoug Rabson 		if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
452c19800e8SDoug Rabson 		    free(bindings);
453c19800e8SDoug Rabson 		return AUTH_ERROR;
454c19800e8SDoug Rabson 	    }
455c19800e8SDoug Rabson 	    context_established = 1;
456c19800e8SDoug Rabson 	}
457c19800e8SDoug Rabson     }
458c19800e8SDoug Rabson 
459c19800e8SDoug Rabson     gss_release_name(&min_stat, &target_name);
460c19800e8SDoug Rabson 
461c19800e8SDoug Rabson     if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
462c19800e8SDoug Rabson 	free(bindings);
463c19800e8SDoug Rabson     if (input.value)
464c19800e8SDoug Rabson 	free(input.value);
465c19800e8SDoug Rabson 
466c19800e8SDoug Rabson     {
467c19800e8SDoug Rabson 	gss_name_t targ_name;
468c19800e8SDoug Rabson 
469c19800e8SDoug Rabson 	maj_stat = gss_inquire_context(&min_stat,
470c19800e8SDoug Rabson 				       d->context_hdl,
471c19800e8SDoug Rabson 				       NULL,
472c19800e8SDoug Rabson 				       &targ_name,
473c19800e8SDoug Rabson 				       NULL,
474c19800e8SDoug Rabson 				       NULL,
475c19800e8SDoug Rabson 				       NULL,
476c19800e8SDoug Rabson 				       NULL,
477c19800e8SDoug Rabson 				       NULL);
478c19800e8SDoug Rabson 	if (GSS_ERROR(maj_stat) == 0) {
479c19800e8SDoug Rabson 	    gss_buffer_desc name;
480c19800e8SDoug Rabson 	    maj_stat = gss_display_name (&min_stat,
481c19800e8SDoug Rabson 					 targ_name,
482c19800e8SDoug Rabson 					 &name,
483c19800e8SDoug Rabson 					 NULL);
484c19800e8SDoug Rabson 	    if (GSS_ERROR(maj_stat) == 0) {
485*ae771770SStanislav Sedov 		printf("Authenticated to <%.*s>\n",
486*ae771770SStanislav Sedov 			(int)name.length,
487*ae771770SStanislav Sedov 			(char *)name.value);
488c19800e8SDoug Rabson 		gss_release_buffer(&min_stat, &name);
489c19800e8SDoug Rabson 	    }
490c19800e8SDoug Rabson 	    gss_release_name(&min_stat, &targ_name);
491c19800e8SDoug Rabson 	} else
492c19800e8SDoug Rabson 	    printf("Failed to get gss name of peer.\n");
493c19800e8SDoug Rabson     }
494c19800e8SDoug Rabson 
495c19800e8SDoug Rabson 
496c19800e8SDoug Rabson     return AUTH_OK;
497c19800e8SDoug Rabson }
498c19800e8SDoug Rabson 
499c19800e8SDoug Rabson struct sec_client_mech gss_client_mech = {
500c19800e8SDoug Rabson     "GSSAPI",
501*ae771770SStanislav Sedov     sizeof(struct gssapi_data),
502c19800e8SDoug Rabson     gss_init,
503c19800e8SDoug Rabson     gss_auth,
504c19800e8SDoug Rabson     NULL, /* end */
505c19800e8SDoug Rabson     gss_check_prot,
506c19800e8SDoug Rabson     gss_overhead,
507c19800e8SDoug Rabson     gss_encode,
508c19800e8SDoug Rabson     gss_decode,
509c19800e8SDoug Rabson };
510c19800e8SDoug Rabson 
511c19800e8SDoug Rabson #endif /* FTP_SERVER */
512