From 03240ce159e2454b70e7a636e92580a283de72fa Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Thu, 26 Mar 1998 02:58:22 +0000 Subject: [PATCH] GSS-API backend for the unified security framework. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@4673 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/ftp/ftp/gssapi.c | 305 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 appl/ftp/ftp/gssapi.c diff --git a/appl/ftp/ftp/gssapi.c b/appl/ftp/ftp/gssapi.c new file mode 100644 index 000000000..7e480c419 --- /dev/null +++ b/appl/ftp/ftp/gssapi.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef FTP_SERVER +#include "ftpd_locl.h" +#else +#include "ftp_locl.h" +#endif +#include + +RCSID("$Id$"); + +struct gss_data { + gss_ctx_id_t context_hdl; +}; + +static int +gss_init(void *app_data) +{ + struct gss_data *d = app_data; + d->context_hdl = GSS_C_NO_CONTEXT; + return 0; +} + +static int +gss_check_prot(void *app_data, int level) +{ + if(level == prot_confidential) + return -1; + return 0; +} + +static int +gss_decode(void *app_data, void *buf, int len, int level) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input, output; + gss_qop_t qop_state; + int conf_state; + struct gss_data *d = app_data; + + input.length = len; + input.value = buf; + maj_stat = gss_unwrap (&min_stat, + d->context_hdl, + &input, + &output, + &conf_state, + &qop_state); + if(GSS_ERROR(maj_stat)) { + printf("Error unwrapping GSS packet: %x, %d, len = %d.\n", + maj_stat, min_stat, len); + abort(); + } + memmove(buf, output.value, output.length); + return output.length; +} + +static int +gss_overhead(void *app_data, int level, int len) +{ + return 100; /* dunno? */ +} + + +static int +gss_encode(void *app_data, void *from, int length, int level, void **to) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input, output; + int conf_state; + struct gss_data *d = app_data; + + input.length = length; + input.value = from; + maj_stat = gss_wrap (&min_stat, + d->context_hdl, + level == prot_private, + GSS_C_QOP_DEFAULT, + &input, + &conf_state, + &output); + *to = output.value; + return output.length; +} + +/* end common stuff */ + +#ifdef FTP_SERVER + +static int +gss_adat(void *app_data, void *buf, size_t len) +{ + char *p = NULL; + gss_buffer_desc input_token, output_token; + OM_uint32 maj_stat, min_stat; + gss_name_t client_name; + struct gss_data *d = app_data; + + gss_channel_bindings_t bindings = malloc(sizeof(*bindings)); + bindings->initiator_addrtype = GSS_C_AF_INET; + bindings->initiator_address.length = 4; + bindings->initiator_address.value = &his_addr.sin_addr; + bindings->acceptor_addrtype = GSS_C_AF_INET; + bindings->acceptor_address.length = 4; + bindings->acceptor_address.value = &ctrl_addr.sin_addr; + bindings->application_data.length = 0; + bindings->application_data.value = NULL; + + input_token.value = buf; + input_token.length = len; + + maj_stat = gss_accept_sec_context (&min_stat, + &d->context_hdl, + GSS_C_NO_CREDENTIAL, + &input_token, + bindings, + &client_name, + NULL, + &output_token, + NULL, + NULL, + NULL); + + if(output_token.length) { + if(base64_encode(output_token.value, output_token.length, &p) < 0) { + reply(535, "Out of memory base64-encoding."); + return -1; + } + } + if(maj_stat == GSS_S_COMPLETE){ + if(p) + reply(235, "ADAT=%s", p); + else + reply(235, "ADAT Complete"); + sec_complete = 1; + } else if(maj_stat == GSS_S_CONTINUE_NEEDED) + if(p) + reply(335, "ADAT=%s", p); + else + reply(335, "OK, need more data"); + else + reply(535, "foo?"); + free(p); + return 0; +} + +static int +gss_userok() +{ + return 0; +} + +struct sec_server_mech gss_server_mech = { + "GSSAPI", + sizeof(struct gss_data), + gss_init, /* init */ + NULL, /* end */ + gss_check_prot, + gss_overhead, + gss_encode, + gss_decode, + /* */ + NULL, + gss_adat, + NULL, /* pbsz */ + NULL, /* ccc */ + gss_userok +}; + +#else + +extern struct sockaddr_in hisctladdr, myctladdr; + +static int +gss_auth(void *app_data, char *host) +{ + + OM_uint32 maj_stat, min_stat; + gss_buffer_desc name; + gss_name_t target_name; + gss_buffer_desc input, output_token; + int context_established = 0; + char *p; + int n; + gss_channel_bindings_t bindings; + struct gss_data *d = app_data; + + name.length = asprintf((char**)&name.value, "ftp@%s", host); + maj_stat = gss_import_name(&min_stat, + &name, + GSS_C_NT_HOSTBASED_SERVICE, + &target_name); + free(name.value); + + + input.length = 0; + input.value = NULL; + + bindings = malloc(sizeof(*bindings)); + bindings->initiator_addrtype = GSS_C_AF_INET; + bindings->initiator_address.length = 4; + bindings->initiator_address.value = &hisctladdr.sin_addr; + bindings->acceptor_addrtype = GSS_C_AF_INET; + bindings->acceptor_address.length = 4; + bindings->acceptor_address.value = &myctladdr.sin_addr; + bindings->application_data.length = 0; + bindings->application_data.value = NULL; + + while(!context_established) { + maj_stat = gss_init_sec_context(&min_stat, + GSS_C_NO_CREDENTIAL, + &d->context_hdl, + target_name, + GSS_C_NO_OID, + GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, + 0, + bindings, + &input, + NULL, + &output_token, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) + abort (); + gss_release_buffer(&min_stat, &input); + if (output_token.length != 0) { + base64_encode(output_token.value, output_token.length, &p); + gss_release_buffer(&min_stat, &output_token); + n = command("ADAT %s", p); + free(p); + } + if (GSS_ERROR(maj_stat)) { + if (d->context_hdl != GSS_C_NO_CONTEXT) + gss_delete_sec_context (&min_stat, + &d->context_hdl, + GSS_C_NO_BUFFER); + break; + } + if (maj_stat & GSS_S_CONTINUE_NEEDED) { + p = strstr(reply_string, "ADAT="); + if(p == NULL){ + abort(); + } else { + p+=5; + input.value = malloc(strlen(p)); + input.length = base64_decode(p, input.value); + } + } else { + if(code != 235) + abort(); + context_established = 1; + } + } + return 0; +} + +struct sec_client_mech gss_client_mech = { + "GSSAPI", + sizeof(struct gss_data), + gss_init, + gss_auth, + NULL, /* end */ + gss_check_prot, + gss_overhead, + gss_encode, + gss_decode, +}; + +#endif