Path: blob/main/crypto/heimdal/appl/gssmask/gssmask.c
34889 views
/*1* Copyright (c) 2006 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 KTH nor the names of its contributors may be17* used to endorse or promote products derived from this software without18* specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY21* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR23* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR27* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,28* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR29* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF30* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31*/3233#include "common.h"34RCSID("$Id$");3536/*37*38*/3940enum handle_type { handle_context, handle_cred };4142struct handle {43int32_t idx;44enum handle_type type;45void *ptr;46struct handle *next;47};4849struct client {50krb5_storage *sock;51krb5_storage *logging;52char *moniker;53int32_t nHandle;54struct handle *handles;55struct sockaddr_storage sa;56socklen_t salen;57char servername[MAXHOSTNAMELEN];58};5960FILE *logfile;61static char *targetname;62krb5_context context;6364/*65*66*/6768static void69logmessage(struct client *c, const char *file, unsigned int lineno,70int level, const char *fmt, ...)71{72char *message;73va_list ap;74int32_t ackid;7576va_start(ap, fmt);77vasprintf(&message, fmt, ap);78va_end(ap);7980if (logfile)81fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message);8283if (c->logging) {84if (krb5_store_int32(c->logging, eLogInfo) != 0)85errx(1, "krb5_store_int32: log level");86if (krb5_store_string(c->logging, file) != 0)87errx(1, "krb5_store_string: filename");88if (krb5_store_int32(c->logging, lineno) != 0)89errx(1, "krb5_store_string: filename");90if (krb5_store_string(c->logging, message) != 0)91errx(1, "krb5_store_string: message");92if (krb5_ret_int32(c->logging, &ackid) != 0)93errx(1, "krb5_ret_int32: ackid");94}95free(message);96}9798/*99*100*/101102static int32_t103add_handle(struct client *c, enum handle_type type, void *data)104{105struct handle *h;106107h = ecalloc(1, sizeof(*h));108109h->idx = ++c->nHandle;110h->type = type;111h->ptr = data;112h->next = c->handles;113c->handles = h;114115return h->idx;116}117118static void119del_handle(struct handle **h, int32_t idx)120{121OM_uint32 min_stat;122123if (idx == 0)124return;125126while (*h) {127if ((*h)->idx == idx) {128struct handle *p = *h;129*h = (*h)->next;130switch(p->type) {131case handle_context: {132gss_ctx_id_t c = p->ptr;133gss_delete_sec_context(&min_stat, &c, NULL);134break; }135case handle_cred: {136gss_cred_id_t c = p->ptr;137gss_release_cred(&min_stat, &c);138break; }139}140free(p);141return;142}143h = &((*h)->next);144}145errx(1, "tried to delete an unexisting handle");146}147148static void *149find_handle(struct handle *h, int32_t idx, enum handle_type type)150{151if (idx == 0)152return NULL;153154while (h) {155if (h->idx == idx) {156if (type == h->type)157return h->ptr;158errx(1, "monger switched type on handle!");159}160h = h->next;161}162return NULL;163}164165166static int32_t167convert_gss_to_gsm(OM_uint32 maj_stat)168{169switch(maj_stat) {170case 0:171return GSMERR_OK;172case GSS_S_CONTINUE_NEEDED:173return GSMERR_CONTINUE_NEEDED;174case GSS_S_DEFECTIVE_TOKEN:175return GSMERR_INVALID_TOKEN;176case GSS_S_BAD_MIC:177return GSMERR_AP_MODIFIED;178default:179return GSMERR_ERROR;180}181}182183static int32_t184convert_krb5_to_gsm(krb5_error_code ret)185{186switch(ret) {187case 0:188return GSMERR_OK;189default:190return GSMERR_ERROR;191}192}193194/*195*196*/197198static int32_t199acquire_cred(struct client *c,200krb5_principal principal,201krb5_get_init_creds_opt *opt,202int32_t *handle)203{204krb5_error_code ret;205krb5_creds cred;206krb5_ccache id;207gss_cred_id_t gcred;208OM_uint32 maj_stat, min_stat;209210*handle = 0;211212krb5_get_init_creds_opt_set_forwardable (opt, 1);213krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30);214215memset(&cred, 0, sizeof(cred));216217ret = krb5_get_init_creds_password (context,218&cred,219principal,220NULL,221NULL,222NULL,2230,224NULL,225opt);226if (ret) {227logmessage(c, __FILE__, __LINE__, 0,228"krb5_get_init_creds failed: %d", ret);229return convert_krb5_to_gsm(ret);230}231232ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);233if (ret)234krb5_err (context, 1, ret, "krb5_cc_initialize");235236ret = krb5_cc_initialize (context, id, cred.client);237if (ret)238krb5_err (context, 1, ret, "krb5_cc_initialize");239240ret = krb5_cc_store_cred (context, id, &cred);241if (ret)242krb5_err (context, 1, ret, "krb5_cc_store_cred");243244krb5_free_cred_contents (context, &cred);245246maj_stat = gss_krb5_import_cred(&min_stat,247id,248NULL,249NULL,250&gcred);251krb5_cc_close(context, id);252if (maj_stat) {253logmessage(c, __FILE__, __LINE__, 0,254"krb5 import creds failed with: %d", maj_stat);255return convert_gss_to_gsm(maj_stat);256}257258*handle = add_handle(c, handle_cred, gcred);259260return 0;261}262263264/*265*266*/267268#define HandleOP(h) \269handle##h(enum gssMaggotOp op, struct client *c)270271/*272*273*/274275static int276HandleOP(GetVersionInfo)277{278put32(c, GSSMAGGOTPROTOCOL);279errx(1, "GetVersionInfo");280}281282static int283HandleOP(GoodBye)284{285struct handle *h = c->handles;286unsigned int i = 0;287288while (h) {289h = h->next;290i++;291}292293if (i)294logmessage(c, __FILE__, __LINE__, 0,295"Did not toast all resources: %d", i);296return 1;297}298299static int300HandleOP(InitContext)301{302OM_uint32 maj_stat, min_stat, ret_flags;303int32_t hContext, hCred, flags;304krb5_data target_name, in_token;305int32_t new_context_id = 0, gsm_error = 0;306krb5_data out_token = { 0 , NULL };307308gss_ctx_id_t ctx;309gss_cred_id_t creds;310gss_name_t gss_target_name;311gss_buffer_desc input_token, output_token;312gss_OID oid = GSS_C_NO_OID;313gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;314315ret32(c, hContext);316ret32(c, hCred);317ret32(c, flags);318retdata(c, target_name);319retdata(c, in_token);320321logmessage(c, __FILE__, __LINE__, 0,322"targetname: <%.*s>", (int)target_name.length,323(char *)target_name.data);324325ctx = find_handle(c->handles, hContext, handle_context);326if (ctx == NULL)327hContext = 0;328creds = find_handle(c->handles, hCred, handle_cred);329if (creds == NULL)330abort();331332input_token.length = target_name.length;333input_token.value = target_name.data;334335maj_stat = gss_import_name(&min_stat,336&input_token,337GSS_KRB5_NT_PRINCIPAL_NAME,338&gss_target_name);339if (GSS_ERROR(maj_stat)) {340logmessage(c, __FILE__, __LINE__, 0,341"import name creds failed with: %d", maj_stat);342gsm_error = convert_gss_to_gsm(maj_stat);343goto out;344}345346/* oid from flags */347348if (in_token.length) {349input_token.length = in_token.length;350input_token.value = in_token.data;351input_token_ptr = &input_token;352if (ctx == NULL)353krb5_errx(context, 1, "initcreds, context NULL, but not first req");354} else {355input_token.length = 0;356input_token.value = NULL;357if (ctx)358krb5_errx(context, 1, "initcreds, context not NULL, but first req");359}360361if ((flags & GSS_C_DELEG_FLAG) != 0)362logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating");363if ((flags & GSS_C_DCE_STYLE) != 0)364logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style");365366maj_stat = gss_init_sec_context(&min_stat,367creds,368&ctx,369gss_target_name,370oid,371flags & 0x7f,3720,373NULL,374input_token_ptr,375NULL,376&output_token,377&ret_flags,378NULL);379if (GSS_ERROR(maj_stat)) {380if (hContext != 0)381del_handle(&c->handles, hContext);382new_context_id = 0;383logmessage(c, __FILE__, __LINE__, 0,384"gss_init_sec_context returns code: %d/%d",385maj_stat, min_stat);386} else {387if (input_token.length == 0)388new_context_id = add_handle(c, handle_context, ctx);389else390new_context_id = hContext;391}392393gsm_error = convert_gss_to_gsm(maj_stat);394395if (output_token.length) {396out_token.data = output_token.value;397out_token.length = output_token.length;398}399400out:401logmessage(c, __FILE__, __LINE__, 0,402"InitContext return code: %d", gsm_error);403404put32(c, new_context_id);405put32(c, gsm_error);406putdata(c, out_token);407408gss_release_name(&min_stat, &gss_target_name);409if (output_token.length)410gss_release_buffer(&min_stat, &output_token);411krb5_data_free(&in_token);412krb5_data_free(&target_name);413414return 0;415}416417static int418HandleOP(AcceptContext)419{420OM_uint32 maj_stat, min_stat, ret_flags;421int32_t hContext, deleg_hcred, flags;422krb5_data in_token;423int32_t new_context_id = 0, gsm_error = 0;424krb5_data out_token = { 0 , NULL };425426gss_ctx_id_t ctx;427gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL;428gss_buffer_desc input_token, output_token;429gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER;430431ret32(c, hContext);432ret32(c, flags);433retdata(c, in_token);434435ctx = find_handle(c->handles, hContext, handle_context);436if (ctx == NULL)437hContext = 0;438439if (in_token.length) {440input_token.length = in_token.length;441input_token.value = in_token.data;442input_token_ptr = &input_token;443} else {444input_token.length = 0;445input_token.value = NULL;446}447448maj_stat = gss_accept_sec_context(&min_stat,449&ctx,450GSS_C_NO_CREDENTIAL,451&input_token,452GSS_C_NO_CHANNEL_BINDINGS,453NULL,454NULL,455&output_token,456&ret_flags,457NULL,458&deleg_cred);459if (GSS_ERROR(maj_stat)) {460if (hContext != 0)461del_handle(&c->handles, hContext);462logmessage(c, __FILE__, __LINE__, 0,463"gss_accept_sec_context returns code: %d/%d",464maj_stat, min_stat);465new_context_id = 0;466} else {467if (hContext == 0)468new_context_id = add_handle(c, handle_context, ctx);469else470new_context_id = hContext;471}472if (output_token.length) {473out_token.data = output_token.value;474out_token.length = output_token.length;475}476if ((ret_flags & GSS_C_DCE_STYLE) != 0)477logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style");478if ((ret_flags & GSS_C_DELEG_FLAG) != 0) {479deleg_hcred = add_handle(c, handle_cred, deleg_cred);480logmessage(c, __FILE__, __LINE__, 0,481"accept_context delegated handle: %d", deleg_hcred);482} else {483gss_release_cred(&min_stat, &deleg_cred);484deleg_hcred = 0;485}486487488gsm_error = convert_gss_to_gsm(maj_stat);489490put32(c, new_context_id);491put32(c, gsm_error);492putdata(c, out_token);493put32(c, deleg_hcred);494495if (output_token.length)496gss_release_buffer(&min_stat, &output_token);497krb5_data_free(&in_token);498499return 0;500}501502static int503HandleOP(ToastResource)504{505int32_t handle;506507ret32(c, handle);508logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle);509del_handle(&c->handles, handle);510put32(c, GSMERR_OK);511512return 0;513}514515static int516HandleOP(AcquireCreds)517{518char *name, *password;519int32_t gsm_error, flags, handle = 0;520krb5_principal principal = NULL;521krb5_get_init_creds_opt *opt = NULL;522krb5_error_code ret;523524retstring(c, name);525retstring(c, password);526ret32(c, flags);527528logmessage(c, __FILE__, __LINE__, 0,529"username: %s password: %s", name, password);530531ret = krb5_parse_name(context, name, &principal);532if (ret) {533gsm_error = convert_krb5_to_gsm(ret);534goto out;535}536537ret = krb5_get_init_creds_opt_alloc (context, &opt);538if (ret)539krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");540541krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL);542543gsm_error = acquire_cred(c, principal, opt, &handle);544545out:546logmessage(c, __FILE__, __LINE__, 0,547"AcquireCreds handle: %d return code: %d", handle, gsm_error);548549if (opt)550krb5_get_init_creds_opt_free (context, opt);551if (principal)552krb5_free_principal(context, principal);553free(name);554free(password);555556put32(c, gsm_error);557put32(c, handle);558559return 0;560}561562static int563HandleOP(Sign)564{565OM_uint32 maj_stat, min_stat;566int32_t hContext, flags, seqno;567krb5_data token;568gss_ctx_id_t ctx;569gss_buffer_desc input_token, output_token;570571ret32(c, hContext);572ret32(c, flags);573ret32(c, seqno);574retdata(c, token);575576ctx = find_handle(c->handles, hContext, handle_context);577if (ctx == NULL)578errx(1, "sign: reference to unknown context");579580input_token.length = token.length;581input_token.value = token.data;582583maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token,584&output_token);585if (maj_stat != GSS_S_COMPLETE)586errx(1, "gss_get_mic failed");587588krb5_data_free(&token);589590token.data = output_token.value;591token.length = output_token.length;592593put32(c, 0); /* XXX fix gsm_error */594putdata(c, token);595596gss_release_buffer(&min_stat, &output_token);597598return 0;599}600601static int602HandleOP(Verify)603{604OM_uint32 maj_stat, min_stat;605int32_t hContext, flags, seqno;606krb5_data msg, mic;607gss_ctx_id_t ctx;608gss_buffer_desc msg_token, mic_token;609gss_qop_t qop;610611ret32(c, hContext);612613ctx = find_handle(c->handles, hContext, handle_context);614if (ctx == NULL)615errx(1, "verify: reference to unknown context");616617ret32(c, flags);618ret32(c, seqno);619retdata(c, msg);620621msg_token.length = msg.length;622msg_token.value = msg.data;623624retdata(c, mic);625626mic_token.length = mic.length;627mic_token.value = mic.data;628629maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token,630&mic_token, &qop);631if (maj_stat != GSS_S_COMPLETE)632errx(1, "gss_verify_mic failed");633634krb5_data_free(&mic);635krb5_data_free(&msg);636637put32(c, 0); /* XXX fix gsm_error */638639return 0;640}641642static int643HandleOP(GetVersionAndCapabilities)644{645int32_t cap = HAS_MONIKER;646char name[256] = "unknown", *str;647648if (targetname)649cap |= ISSERVER; /* is server */650651#ifdef HAVE_UNAME652{653struct utsname ut;654if (uname(&ut) == 0) {655snprintf(name, sizeof(name), "%s-%s-%s",656ut.sysname, ut.version, ut.machine);657}658}659#endif660661asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name);662663put32(c, GSSMAGGOTPROTOCOL);664put32(c, cap);665putstring(c, str);666free(str);667668return 0;669}670671static int672HandleOP(GetTargetName)673{674if (targetname)675putstring(c, targetname);676else677putstring(c, "");678return 0;679}680681static int682HandleOP(SetLoggingSocket)683{684int32_t portnum;685int fd, ret;686687ret32(c, portnum);688689logmessage(c, __FILE__, __LINE__, 0,690"logging port on peer is: %d", (int)portnum);691692socket_set_port((struct sockaddr *)(&c->sa), htons(portnum));693694fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0);695if (fd < 0)696return 0;697698ret = connect(fd, (struct sockaddr *)&c->sa, c->salen);699if (ret < 0) {700logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s",701strerror(errno));702close(fd);703return 0;704}705706if (c->logging)707krb5_storage_free(c->logging);708c->logging = krb5_storage_from_fd(fd);709close(fd);710711krb5_store_int32(c->logging, eLogSetMoniker);712store_string(c->logging, c->moniker);713714logmessage(c, __FILE__, __LINE__, 0, "logging turned on");715716return 0;717}718719720static int721HandleOP(ChangePassword)722{723errx(1, "ChangePassword");724}725726static int727HandleOP(SetPasswordSelf)728{729errx(1, "SetPasswordSelf");730}731732static int733HandleOP(Wrap)734{735OM_uint32 maj_stat, min_stat;736int32_t hContext, flags, seqno;737krb5_data token;738gss_ctx_id_t ctx;739gss_buffer_desc input_token, output_token;740int conf_state;741742ret32(c, hContext);743ret32(c, flags);744ret32(c, seqno);745retdata(c, token);746747ctx = find_handle(c->handles, hContext, handle_context);748if (ctx == NULL)749errx(1, "wrap: reference to unknown context");750751input_token.length = token.length;752input_token.value = token.data;753754maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token,755&conf_state, &output_token);756if (maj_stat != GSS_S_COMPLETE)757errx(1, "gss_wrap failed");758759krb5_data_free(&token);760761token.data = output_token.value;762token.length = output_token.length;763764put32(c, 0); /* XXX fix gsm_error */765putdata(c, token);766767gss_release_buffer(&min_stat, &output_token);768769return 0;770}771772773static int774HandleOP(Unwrap)775{776OM_uint32 maj_stat, min_stat;777int32_t hContext, flags, seqno;778krb5_data token;779gss_ctx_id_t ctx;780gss_buffer_desc input_token, output_token;781int conf_state;782gss_qop_t qop_state;783784ret32(c, hContext);785ret32(c, flags);786ret32(c, seqno);787retdata(c, token);788789ctx = find_handle(c->handles, hContext, handle_context);790if (ctx == NULL)791errx(1, "unwrap: reference to unknown context");792793input_token.length = token.length;794input_token.value = token.data;795796maj_stat = gss_unwrap(&min_stat, ctx, &input_token,797&output_token, &conf_state, &qop_state);798799if (maj_stat != GSS_S_COMPLETE)800errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);801802krb5_data_free(&token);803if (maj_stat == GSS_S_COMPLETE) {804token.data = output_token.value;805token.length = output_token.length;806} else {807token.data = NULL;808token.length = 0;809}810put32(c, 0); /* XXX fix gsm_error */811putdata(c, token);812813if (maj_stat == GSS_S_COMPLETE)814gss_release_buffer(&min_stat, &output_token);815816return 0;817}818819static int820HandleOP(Encrypt)821{822return handleWrap(op, c);823}824825static int826HandleOP(Decrypt)827{828return handleUnwrap(op, c);829}830831static int832HandleOP(ConnectLoggingService2)833{834errx(1, "ConnectLoggingService2");835}836837static int838HandleOP(GetMoniker)839{840putstring(c, c->moniker);841return 0;842}843844static int845HandleOP(CallExtension)846{847errx(1, "CallExtension");848}849850static int851HandleOP(AcquirePKInitCreds)852{853int32_t flags;854krb5_data pfxdata;855char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX";856krb5_principal principal = NULL;857int fd;858859ret32(c, flags);860retdata(c, pfxdata);861862fd = mkstemp(fn + 5);863if (fd < 0)864errx(1, "mkstemp");865866net_write(fd, pfxdata.data, pfxdata.length);867krb5_data_free(&pfxdata);868close(fd);869870if (principal)871krb5_free_principal(context, principal);872873put32(c, -1); /* hResource */874put32(c, GSMERR_NOT_SUPPORTED);875return 0;876}877878static int879HandleOP(WrapExt)880{881OM_uint32 maj_stat, min_stat;882int32_t hContext, flags, bflags;883krb5_data token, header, trailer;884gss_ctx_id_t ctx;885unsigned char *p;886int conf_state, iov_len;887gss_iov_buffer_desc iov[6];888889ret32(c, hContext);890ret32(c, flags);891ret32(c, bflags);892retdata(c, header);893retdata(c, token);894retdata(c, trailer);895896ctx = find_handle(c->handles, hContext, handle_context);897if (ctx == NULL)898errx(1, "wrap: reference to unknown context");899900memset(&iov, 0, sizeof(iov));901902iov_len = sizeof(iov)/sizeof(iov[0]);903904if (bflags & WRAP_EXP_ONLY_HEADER)905iov_len -= 2; /* skip trailer and padding, aka dce-style */906907iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;908if (header.length != 0) {909iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;910iov[1].buffer.length = header.length;911iov[1].buffer.value = header.data;912} else {913iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;914}915iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;916iov[2].buffer.length = token.length;917iov[2].buffer.value = token.data;918if (trailer.length != 0) {919iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;920iov[3].buffer.length = trailer.length;921iov[3].buffer.value = trailer.data;922} else {923iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;924}925iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;926iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;927928maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state,929iov, iov_len);930if (maj_stat != GSS_S_COMPLETE)931errx(1, "gss_wrap_iov_length failed");932933maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state,934iov, iov_len);935if (maj_stat != GSS_S_COMPLETE)936errx(1, "gss_wrap_iov failed");937938krb5_data_free(&token);939940token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length;941token.data = malloc(token.length);942943p = token.data;944memcpy(p, iov[0].buffer.value, iov[0].buffer.length);945p += iov[0].buffer.length;946memcpy(p, iov[2].buffer.value, iov[2].buffer.length);947p += iov[2].buffer.length;948memcpy(p, iov[4].buffer.value, iov[4].buffer.length);949p += iov[4].buffer.length;950memcpy(p, iov[5].buffer.value, iov[5].buffer.length);951#ifndef __clang_analyzer__952p += iov[5].buffer.length;953#endif954955gss_release_iov_buffer(NULL, iov, iov_len);956957put32(c, 0); /* XXX fix gsm_error */958putdata(c, token);959960free(token.data);961962return 0;963}964965966static int967HandleOP(UnwrapExt)968{969OM_uint32 maj_stat, min_stat;970int32_t hContext, flags, bflags;971krb5_data token, header, trailer;972gss_ctx_id_t ctx;973gss_iov_buffer_desc iov[3];974int conf_state, iov_len;975gss_qop_t qop_state;976977ret32(c, hContext);978ret32(c, flags);979ret32(c, bflags);980retdata(c, header);981retdata(c, token);982retdata(c, trailer);983984iov_len = sizeof(iov)/sizeof(iov[0]);985986if (bflags & WRAP_EXP_ONLY_HEADER)987iov_len -= 1; /* skip trailer and padding, aka dce-style */988989ctx = find_handle(c->handles, hContext, handle_context);990if (ctx == NULL)991errx(1, "unwrap: reference to unknown context");992993if (header.length != 0) {994iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;995iov[0].buffer.length = header.length;996iov[0].buffer.value = header.data;997} else {998iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY;999}1000iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;1001iov[1].buffer.length = token.length;1002iov[1].buffer.value = token.data;10031004if (trailer.length != 0) {1005iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;1006iov[2].buffer.length = trailer.length;1007iov[2].buffer.value = trailer.data;1008} else {1009iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY;1010}10111012maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state,1013iov, iov_len);10141015if (maj_stat != GSS_S_COMPLETE)1016errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat);10171018if (maj_stat == GSS_S_COMPLETE) {1019token.data = iov[1].buffer.value;1020token.length = iov[1].buffer.length;1021} else {1022token.data = NULL;1023token.length = 0;1024}1025put32(c, 0); /* XXX fix gsm_error */1026putdata(c, token);10271028return 0;1029}10301031/*1032*1033*/10341035struct handler {1036enum gssMaggotOp op;1037const char *name;1038int (*func)(enum gssMaggotOp, struct client *);1039};10401041#define S(a) { e##a, #a, handle##a }10421043struct handler handlers[] = {1044S(GetVersionInfo),1045S(GoodBye),1046S(InitContext),1047S(AcceptContext),1048S(ToastResource),1049S(AcquireCreds),1050S(Encrypt),1051S(Decrypt),1052S(Sign),1053S(Verify),1054S(GetVersionAndCapabilities),1055S(GetTargetName),1056S(SetLoggingSocket),1057S(ChangePassword),1058S(SetPasswordSelf),1059S(Wrap),1060S(Unwrap),1061S(ConnectLoggingService2),1062S(GetMoniker),1063S(CallExtension),1064S(AcquirePKInitCreds),1065S(WrapExt),1066S(UnwrapExt),1067};10681069#undef S10701071/*1072*1073*/10741075static struct handler *1076find_op(int32_t op)1077{1078int i;10791080for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)1081if (handlers[i].op == op)1082return &handlers[i];1083return NULL;1084}10851086static struct client *1087create_client(int fd, int port, const char *moniker)1088{1089struct client *c;10901091c = ecalloc(1, sizeof(*c));10921093if (moniker) {1094c->moniker = estrdup(moniker);1095} else {1096char hostname[MAXHOSTNAMELEN];1097gethostname(hostname, sizeof(hostname));1098asprintf(&c->moniker, "gssmask: %s:%d", hostname, port);1099}11001101{1102c->salen = sizeof(c->sa);1103getpeername(fd, (struct sockaddr *)&c->sa, &c->salen);11041105getnameinfo((struct sockaddr *)&c->sa, c->salen,1106c->servername, sizeof(c->servername),1107NULL, 0, NI_NUMERICHOST);1108}11091110c->sock = krb5_storage_from_fd(fd);1111if (c->sock == NULL)1112errx(1, "krb5_storage_from_fd");11131114close(fd);11151116return c;1117}11181119static void1120free_client(struct client *c)1121{1122while(c->handles)1123del_handle(&c->handles, c->handles->idx);11241125free(c->moniker);1126krb5_storage_free(c->sock);1127if (c->logging)1128krb5_storage_free(c->logging);1129free(c);1130}113111321133static void *1134handleServer(void *ptr)1135{1136struct handler *handler;1137struct client *c;1138int32_t op;11391140c = (struct client *)ptr;114111421143while(1) {1144ret32(c, op);11451146handler = find_op(op);1147if (handler == NULL) {1148logmessage(c, __FILE__, __LINE__, 0,1149"op %d not supported", (int)op);1150exit(1);1151}11521153logmessage(c, __FILE__, __LINE__, 0,1154"---> Got op %s from server %s",1155handler->name, c->servername);11561157if ((handler->func)(handler->op, c))1158break;1159}11601161return NULL;1162}116311641165static char *port_str;1166static int version_flag;1167static int help_flag;1168static char *logfile_str;1169static char *moniker_str;11701171static int port = 4711;11721173struct getargs args[] = {1174{ "spn", 0, arg_string, &targetname, "This host's SPN",1175"service/host@REALM" },1176{ "port", 'p', arg_string, &port_str, "Use this port",1177"number-of-service" },1178{ "logfile", 0, arg_string, &logfile_str, "logfile",1179"number-of-service" },1180{ "moniker", 0, arg_string, &moniker_str, "nickname",1181"name" },1182{ "version", 0, arg_flag, &version_flag, "Print version",1183NULL },1184{ "help", 0, arg_flag, &help_flag, NULL,1185NULL }1186};11871188static void1189usage(int ret)1190{1191arg_printusage (args,1192sizeof(args) / sizeof(args[0]),1193NULL,1194"");1195exit (ret);1196}11971198int1199main(int argc, char **argv)1200{1201int optidx = 0;12021203setprogname (argv[0]);12041205if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))1206usage (1);12071208if (help_flag)1209usage (0);12101211if (version_flag) {1212print_version (NULL);1213return 0;1214}12151216if (optidx != argc)1217usage (1);12181219if (port_str) {1220char *ptr;12211222port = strtol (port_str, &ptr, 10);1223if (port == 0 && ptr == port_str)1224errx (1, "Bad port `%s'", port_str);1225}12261227krb5_init_context(&context);12281229{1230const char *lf = logfile_str;1231if (lf == NULL)1232lf = "/dev/tty";12331234logfile = fopen(lf, "w");1235if (logfile == NULL)1236err(1, "error opening %s", lf);1237}12381239mini_inetd(htons(port), NULL);1240fprintf(logfile, "connected\n");12411242{1243struct client *c;12441245c = create_client(0, port, moniker_str);1246/* close(0); */12471248handleServer(c);12491250free_client(c);1251}12521253krb5_free_context(context);12541255return 0;1256}125712581259