Path: blob/main/crypto/heimdal/appl/ftp/ftpd/gssapi.c
34889 views
/*1* Copyright (c) 1998 - 2005 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#ifdef FTP_SERVER34#include "ftpd_locl.h"35#else36#include "ftp_locl.h"37#endif38#include <gssapi/gssapi.h>39#include <gssapi/gssapi_krb5.h>40#include <krb5_err.h>4142RCSID("$Id$");4344int ftp_do_gss_bindings = 0;45int ftp_do_gss_delegate = 1;4647struct gssapi_data {48gss_ctx_id_t context_hdl;49gss_name_t client_name;50gss_cred_id_t delegated_cred_handle;51void *mech_data;52};5354static int55gss_init(void *app_data)56{57struct gssapi_data *d = app_data;58d->context_hdl = GSS_C_NO_CONTEXT;59d->delegated_cred_handle = GSS_C_NO_CREDENTIAL;60#if defined(FTP_SERVER)61return 0;62#else63/* XXX Check the gss mechanism; with gss_indicate_mechs() ? */64#ifdef KRB565return !use_kerberos;66#else67return 0;68#endif /* KRB5 */69#endif /* FTP_SERVER */70}7172static int73gss_check_prot(void *app_data, int level)74{75if(level == prot_confidential)76return -1;77return 0;78}7980static int81gss_decode(void *app_data, void *buf, int len, int level)82{83OM_uint32 maj_stat, min_stat;84gss_buffer_desc input, output;85gss_qop_t qop_state;86int conf_state;87struct gssapi_data *d = app_data;88size_t ret_len;8990input.length = len;91input.value = buf;92maj_stat = gss_unwrap (&min_stat,93d->context_hdl,94&input,95&output,96&conf_state,97&qop_state);98if(GSS_ERROR(maj_stat))99return -1;100memmove(buf, output.value, output.length);101ret_len = output.length;102gss_release_buffer(&min_stat, &output);103return ret_len;104}105106static int107gss_overhead(void *app_data, int level, int len)108{109return 100; /* dunno? */110}111112113static int114gss_encode(void *app_data, void *from, int length, int level, void **to)115{116OM_uint32 maj_stat, min_stat;117gss_buffer_desc input, output;118int conf_state;119struct gssapi_data *d = app_data;120121input.length = length;122input.value = from;123maj_stat = gss_wrap (&min_stat,124d->context_hdl,125level == prot_private,126GSS_C_QOP_DEFAULT,127&input,128&conf_state,129&output);130*to = output.value;131return output.length;132}133134static void135sockaddr_to_gss_address (struct sockaddr *sa,136OM_uint32 *addr_type,137gss_buffer_desc *gss_addr)138{139switch (sa->sa_family) {140#ifdef HAVE_IPV6141case AF_INET6 : {142struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;143144gss_addr->length = 16;145gss_addr->value = &sin6->sin6_addr;146*addr_type = GSS_C_AF_INET6;147break;148}149#endif150case AF_INET : {151struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;152153gss_addr->length = 4;154gss_addr->value = &sin4->sin_addr;155*addr_type = GSS_C_AF_INET;156break;157}158default :159errx (1, "unknown address family %d", sa->sa_family);160161}162}163164/* end common stuff */165166#ifdef FTP_SERVER167168static int169gss_adat(void *app_data, void *buf, size_t len)170{171char *p = NULL;172gss_buffer_desc input_token, output_token;173OM_uint32 maj_stat, min_stat;174gss_name_t client_name;175struct gssapi_data *d = app_data;176gss_channel_bindings_t bindings;177178if (ftp_do_gss_bindings) {179bindings = malloc(sizeof(*bindings));180if (bindings == NULL)181errx(1, "out of memory");182183sockaddr_to_gss_address (his_addr,184&bindings->initiator_addrtype,185&bindings->initiator_address);186sockaddr_to_gss_address (ctrl_addr,187&bindings->acceptor_addrtype,188&bindings->acceptor_address);189190bindings->application_data.length = 0;191bindings->application_data.value = NULL;192} else193bindings = GSS_C_NO_CHANNEL_BINDINGS;194195input_token.value = buf;196input_token.length = len;197198maj_stat = gss_accept_sec_context (&min_stat,199&d->context_hdl,200GSS_C_NO_CREDENTIAL,201&input_token,202bindings,203&client_name,204NULL,205&output_token,206NULL,207NULL,208&d->delegated_cred_handle);209210if (bindings != GSS_C_NO_CHANNEL_BINDINGS)211free(bindings);212213if(output_token.length) {214if(base64_encode(output_token.value, output_token.length, &p) < 0) {215reply(535, "Out of memory base64-encoding.");216return -1;217}218gss_release_buffer(&min_stat, &output_token);219}220if(maj_stat == GSS_S_COMPLETE){221d->client_name = client_name;222client_name = GSS_C_NO_NAME;223if(p)224reply(235, "ADAT=%s", p);225else226reply(235, "ADAT Complete");227sec_complete = 1;228229} else if(maj_stat == GSS_S_CONTINUE_NEEDED) {230if(p)231reply(335, "ADAT=%s", p);232else233reply(335, "OK, need more data");234} else {235OM_uint32 new_stat;236OM_uint32 msg_ctx = 0;237gss_buffer_desc status_string;238gss_display_status(&new_stat,239min_stat,240GSS_C_MECH_CODE,241GSS_C_NO_OID,242&msg_ctx,243&status_string);244syslog(LOG_ERR, "gss_accept_sec_context: %.*s",245(int)status_string.length,246(char*)status_string.value);247gss_release_buffer(&new_stat, &status_string);248reply(431, "Security resource unavailable");249}250251if (client_name)252gss_release_name(&min_stat, &client_name);253free(p);254return 0;255}256257int gssapi_userok(void*, char*);258int gssapi_session(void*, char*);259260struct sec_server_mech gss_server_mech = {261"GSSAPI",262sizeof(struct gssapi_data),263gss_init, /* init */264NULL, /* end */265gss_check_prot,266gss_overhead,267gss_encode,268gss_decode,269/* */270NULL,271gss_adat,272NULL, /* pbsz */273NULL, /* ccc */274gssapi_userok,275gssapi_session276};277278#else /* FTP_SERVER */279280extern struct sockaddr *hisctladdr, *myctladdr;281282static int283import_name(const char *kname, const char *host, gss_name_t *target_name)284{285OM_uint32 maj_stat, min_stat;286gss_buffer_desc name;287char *str;288289name.length = asprintf(&str, "%s@%s", kname, host);290if (str == NULL) {291printf("Out of memory\n");292return AUTH_ERROR;293}294name.value = str;295296maj_stat = gss_import_name(&min_stat,297&name,298GSS_C_NT_HOSTBASED_SERVICE,299target_name);300if (GSS_ERROR(maj_stat)) {301OM_uint32 new_stat;302OM_uint32 msg_ctx = 0;303gss_buffer_desc status_string;304305gss_display_status(&new_stat,306min_stat,307GSS_C_MECH_CODE,308GSS_C_NO_OID,309&msg_ctx,310&status_string);311printf("Error importing name %.*s: %.*s\n",312(int)name.length,313(char *)name.value,314(int)status_string.length,315(char *)status_string.value);316free(name.value);317gss_release_buffer(&new_stat, &status_string);318return AUTH_ERROR;319}320free(name.value);321return 0;322}323324static int325gss_auth(void *app_data, char *host)326{327328OM_uint32 maj_stat, min_stat;329gss_name_t target_name;330gss_buffer_desc input, output_token;331int context_established = 0;332char *p;333int n;334gss_channel_bindings_t bindings;335struct gssapi_data *d = app_data;336OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;337338const char *knames[] = { "ftp", "host", NULL }, **kname = knames;339340341if(import_name(*kname++, host, &target_name))342return AUTH_ERROR;343344input.length = 0;345input.value = NULL;346347if (ftp_do_gss_bindings) {348bindings = malloc(sizeof(*bindings));349if (bindings == NULL)350errx(1, "out of memory");351352sockaddr_to_gss_address (myctladdr,353&bindings->initiator_addrtype,354&bindings->initiator_address);355sockaddr_to_gss_address (hisctladdr,356&bindings->acceptor_addrtype,357&bindings->acceptor_address);358359bindings->application_data.length = 0;360bindings->application_data.value = NULL;361} else362bindings = GSS_C_NO_CHANNEL_BINDINGS;363364if (ftp_do_gss_delegate)365mech_flags |= GSS_C_DELEG_FLAG;366367while(!context_established) {368maj_stat = gss_init_sec_context(&min_stat,369GSS_C_NO_CREDENTIAL,370&d->context_hdl,371target_name,372GSS_C_NO_OID,373mech_flags,3740,375bindings,376&input,377NULL,378&output_token,379NULL,380NULL);381if (GSS_ERROR(maj_stat)) {382OM_uint32 new_stat;383OM_uint32 msg_ctx = 0;384gss_buffer_desc status_string;385386d->context_hdl = GSS_C_NO_CONTEXT;387388gss_release_name(&min_stat, &target_name);389390if(*kname != NULL) {391392if(import_name(*kname++, host, &target_name)) {393if (bindings != GSS_C_NO_CHANNEL_BINDINGS)394free(bindings);395return AUTH_ERROR;396}397continue;398}399400if (bindings != GSS_C_NO_CHANNEL_BINDINGS)401free(bindings);402403gss_display_status(&new_stat,404min_stat,405GSS_C_MECH_CODE,406GSS_C_NO_OID,407&msg_ctx,408&status_string);409printf("Error initializing security context: %.*s\n",410(int)status_string.length,411(char*)status_string.value);412gss_release_buffer(&new_stat, &status_string);413return AUTH_CONTINUE;414}415416if (input.value) {417free(input.value);418input.value = NULL;419input.length = 0;420}421if (output_token.length != 0) {422base64_encode(output_token.value, output_token.length, &p);423gss_release_buffer(&min_stat, &output_token);424n = command("ADAT %s", p);425free(p);426}427if (GSS_ERROR(maj_stat)) {428if (d->context_hdl != GSS_C_NO_CONTEXT)429gss_delete_sec_context (&min_stat,430&d->context_hdl,431GSS_C_NO_BUFFER);432break;433}434if (maj_stat & GSS_S_CONTINUE_NEEDED) {435p = strstr(reply_string, "ADAT=");436if(p == NULL){437printf("Error: expected ADAT in reply. got: %s\n",438reply_string);439if (bindings != GSS_C_NO_CHANNEL_BINDINGS)440free(bindings);441return AUTH_ERROR;442} else {443p+=5;444input.value = malloc(strlen(p));445input.length = base64_decode(p, input.value);446}447} else {448if(code != 235) {449printf("Unrecognized response code: %d\n", code);450if (bindings != GSS_C_NO_CHANNEL_BINDINGS)451free(bindings);452return AUTH_ERROR;453}454context_established = 1;455}456}457458gss_release_name(&min_stat, &target_name);459460if (bindings != GSS_C_NO_CHANNEL_BINDINGS)461free(bindings);462if (input.value)463free(input.value);464465{466gss_name_t targ_name;467468maj_stat = gss_inquire_context(&min_stat,469d->context_hdl,470NULL,471&targ_name,472NULL,473NULL,474NULL,475NULL,476NULL);477if (GSS_ERROR(maj_stat) == 0) {478gss_buffer_desc name;479maj_stat = gss_display_name (&min_stat,480targ_name,481&name,482NULL);483if (GSS_ERROR(maj_stat) == 0) {484printf("Authenticated to <%.*s>\n",485(int)name.length,486(char *)name.value);487gss_release_buffer(&min_stat, &name);488}489gss_release_name(&min_stat, &targ_name);490} else491printf("Failed to get gss name of peer.\n");492}493494495return AUTH_OK;496}497498struct sec_client_mech gss_client_mech = {499"GSSAPI",500sizeof(struct gssapi_data),501gss_init,502gss_auth,503NULL, /* end */504gss_check_prot,505gss_overhead,506gss_encode,507gss_decode,508};509510#endif /* FTP_SERVER */511512513