protocol.c revision 233294
133965Sjdp/* 278836Sobrien * Copyright (c) 2005, PADL Software Pty Ltd. 378836Sobrien * All rights reserved. 460514Sobrien * 533965Sjdp * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 633965Sjdp * 733965Sjdp * Redistribution and use in source and binary forms, with or without 833965Sjdp * modification, are permitted provided that the following conditions 933965Sjdp * are met: 1033965Sjdp * 1133965Sjdp * 1. Redistributions of source code must retain the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer. 1333965Sjdp * 1433965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1533965Sjdp * notice, this list of conditions and the following disclaimer in the 1633965Sjdp * documentation and/or other materials provided with the distribution. 1733965Sjdp * 1833965Sjdp * 3. Neither the name of PADL Software nor the names of its contributors 1933965Sjdp * may be used to endorse or promote products derived from this software 2060514Sobrien * without specific prior written permission. 2160514Sobrien * 2233965Sjdp * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 2359431Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2459431Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2533965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 2633965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2733965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2833965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2933965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3033965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3133965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3233965Sjdp * SUCH DAMAGE. 3333965Sjdp */ 3433965Sjdp 3533965Sjdp#include "kcm_locl.h" 3633965Sjdp#include <heimntlm.h> 3733965Sjdp 3833965Sjdpstatic void 3933965Sjdpkcm_drop_default_cache(krb5_context context, kcm_client *client, char *name); 4033965Sjdp 4133965Sjdp 4233965Sjdpint 4333965Sjdpkcm_is_same_session(kcm_client *client, uid_t uid, pid_t session) 4433965Sjdp{ 4533965Sjdp#if 0 /* XXX pppd is running in diffrent session the user */ 4633965Sjdp if (session != -1) 4733965Sjdp return (client->session == session); 4833965Sjdp else 4933965Sjdp#endif 5033965Sjdp return (client->uid == uid); 5133965Sjdp} 5233965Sjdp 5333965Sjdpstatic krb5_error_code 5433965Sjdpkcm_op_noop(krb5_context context, 5533965Sjdp kcm_client *client, 5633965Sjdp kcm_operation opcode, 5733965Sjdp krb5_storage *request, 5833965Sjdp krb5_storage *response) 5933965Sjdp{ 6033965Sjdp KCM_LOG_REQUEST(context, client, opcode); 6133965Sjdp 6233965Sjdp return 0; 6333965Sjdp} 6433965Sjdp 6533965Sjdp/* 6633965Sjdp * Request: 6733965Sjdp * NameZ 6833965Sjdp * Response: 6933965Sjdp * NameZ 7033965Sjdp * 7133965Sjdp */ 7233965Sjdpstatic krb5_error_code 7333965Sjdpkcm_op_get_name(krb5_context context, 7433965Sjdp kcm_client *client, 7533965Sjdp kcm_operation opcode, 7633965Sjdp krb5_storage *request, 7733965Sjdp krb5_storage *response) 7833965Sjdp 7933965Sjdp{ 8033965Sjdp krb5_error_code ret; 8133965Sjdp char *name = NULL; 8233965Sjdp kcm_ccache ccache; 8333965Sjdp 8433965Sjdp ret = krb5_ret_stringz(request, &name); 8533965Sjdp if (ret) 8633965Sjdp return ret; 8733965Sjdp 8833965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 8933965Sjdp 9033965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 9133965Sjdp name, &ccache); 9233965Sjdp if (ret) { 9333965Sjdp free(name); 9433965Sjdp return ret; 9533965Sjdp } 9633965Sjdp 9733965Sjdp ret = krb5_store_stringz(response, ccache->name); 9833965Sjdp if (ret) { 9933965Sjdp kcm_release_ccache(context, ccache); 10033965Sjdp free(name); 10133965Sjdp return ret; 10233965Sjdp } 10333965Sjdp 10433965Sjdp free(name); 10533965Sjdp kcm_release_ccache(context, ccache); 10633965Sjdp return 0; 10733965Sjdp} 10833965Sjdp 10933965Sjdp/* 11033965Sjdp * Request: 11133965Sjdp * 11233965Sjdp * Response: 11333965Sjdp * NameZ 11433965Sjdp */ 11533965Sjdpstatic krb5_error_code 11633965Sjdpkcm_op_gen_new(krb5_context context, 11733965Sjdp kcm_client *client, 11833965Sjdp kcm_operation opcode, 11933965Sjdp krb5_storage *request, 12033965Sjdp krb5_storage *response) 12133965Sjdp{ 12233965Sjdp krb5_error_code ret; 12333965Sjdp char *name; 12433965Sjdp 12533965Sjdp KCM_LOG_REQUEST(context, client, opcode); 12633965Sjdp 12733965Sjdp name = kcm_ccache_nextid(client->pid, client->uid, client->gid); 12833965Sjdp if (name == NULL) { 12933965Sjdp return KRB5_CC_NOMEM; 13033965Sjdp } 13133965Sjdp 13233965Sjdp ret = krb5_store_stringz(response, name); 13333965Sjdp free(name); 13433965Sjdp 13533965Sjdp return ret; 13633965Sjdp} 13733965Sjdp 13833965Sjdp/* 13933965Sjdp * Request: 14033965Sjdp * NameZ 14133965Sjdp * Principal 14233965Sjdp * 14333965Sjdp * Response: 14433965Sjdp * 14533965Sjdp */ 14633965Sjdpstatic krb5_error_code 14733965Sjdpkcm_op_initialize(krb5_context context, 14833965Sjdp kcm_client *client, 14933965Sjdp kcm_operation opcode, 15033965Sjdp krb5_storage *request, 15133965Sjdp krb5_storage *response) 15233965Sjdp{ 15333965Sjdp kcm_ccache ccache; 15433965Sjdp krb5_principal principal; 15533965Sjdp krb5_error_code ret; 15633965Sjdp char *name; 15789864Sobrien#if 0 15833965Sjdp kcm_event event; 15933965Sjdp#endif 16033965Sjdp 16133965Sjdp KCM_LOG_REQUEST(context, client, opcode); 16233965Sjdp 16333965Sjdp ret = krb5_ret_stringz(request, &name); 16433965Sjdp if (ret) 16533965Sjdp return ret; 16633965Sjdp 16733965Sjdp ret = krb5_ret_principal(request, &principal); 16833965Sjdp if (ret) { 16933965Sjdp free(name); 17033965Sjdp return ret; 17133965Sjdp } 17233965Sjdp 17333965Sjdp ret = kcm_ccache_new_client(context, client, name, &ccache); 17433965Sjdp if (ret) { 17533965Sjdp free(name); 17633965Sjdp krb5_free_principal(context, principal); 17733965Sjdp return ret; 17833965Sjdp } 17933965Sjdp 18033965Sjdp ccache->client = principal; 18133965Sjdp 18233965Sjdp free(name); 18333965Sjdp 18433965Sjdp#if 0 18533965Sjdp /* 18633965Sjdp * Create a new credentials cache. To mitigate DoS attacks we will 18733965Sjdp * expire it in 30 minutes unless it has some credentials added 18833965Sjdp * to it 18933965Sjdp */ 19033965Sjdp 19133965Sjdp event.fire_time = 30 * 60; 19233965Sjdp event.expire_time = 0; 19333965Sjdp event.backoff_time = 0; 19433965Sjdp event.action = KCM_EVENT_DESTROY_EMPTY_CACHE; 19533965Sjdp event.ccache = ccache; 19633965Sjdp 19733965Sjdp ret = kcm_enqueue_event_relative(context, &event); 19833965Sjdp#endif 19933965Sjdp 20033965Sjdp kcm_release_ccache(context, ccache); 20133965Sjdp 20233965Sjdp return ret; 20333965Sjdp} 20433965Sjdp 20533965Sjdp/* 20633965Sjdp * Request: 20733965Sjdp * NameZ 20833965Sjdp * 20933965Sjdp * Response: 21033965Sjdp * 21133965Sjdp */ 21233965Sjdpstatic krb5_error_code 21333965Sjdpkcm_op_destroy(krb5_context context, 21433965Sjdp kcm_client *client, 21533965Sjdp kcm_operation opcode, 21633965Sjdp krb5_storage *request, 21733965Sjdp krb5_storage *response) 21833965Sjdp{ 21933965Sjdp krb5_error_code ret; 22033965Sjdp char *name; 22133965Sjdp 22233965Sjdp ret = krb5_ret_stringz(request, &name); 22333965Sjdp if (ret) 22433965Sjdp return ret; 22533965Sjdp 22633965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 22733965Sjdp 22833965Sjdp ret = kcm_ccache_destroy_client(context, client, name); 22933965Sjdp if (ret == 0) 23033965Sjdp kcm_drop_default_cache(context, client, name); 23133965Sjdp 23233965Sjdp free(name); 23333965Sjdp 23433965Sjdp return ret; 23533965Sjdp} 23633965Sjdp 23733965Sjdp/* 23833965Sjdp * Request: 23933965Sjdp * NameZ 24033965Sjdp * Creds 24133965Sjdp * 24233965Sjdp * Response: 24333965Sjdp * 24433965Sjdp */ 24533965Sjdpstatic krb5_error_code 24633965Sjdpkcm_op_store(krb5_context context, 24733965Sjdp kcm_client *client, 24833965Sjdp kcm_operation opcode, 24933965Sjdp krb5_storage *request, 25089864Sobrien krb5_storage *response) 25189864Sobrien{ 25289864Sobrien krb5_creds creds; 25389864Sobrien krb5_error_code ret; 25489864Sobrien kcm_ccache ccache; 25533965Sjdp char *name; 25633965Sjdp 25733965Sjdp ret = krb5_ret_stringz(request, &name); 25833965Sjdp if (ret) 25933965Sjdp return ret; 26038891Sjdp 26133965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 26238891Sjdp 26338891Sjdp ret = krb5_ret_creds(request, &creds); 26438891Sjdp if (ret) { 26538891Sjdp free(name); 26660514Sobrien return ret; 26760514Sobrien } 26833965Sjdp 26933965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 27033965Sjdp name, &ccache); 27177307Sobrien if (ret) { 27233965Sjdp free(name); 27333965Sjdp krb5_free_cred_contents(context, &creds); 27433965Sjdp return ret; 27533965Sjdp } 27633965Sjdp 27733965Sjdp ret = kcm_ccache_store_cred(context, ccache, &creds, 0); 27833965Sjdp if (ret) { 27933965Sjdp free(name); 28033965Sjdp krb5_free_cred_contents(context, &creds); 28133965Sjdp kcm_release_ccache(context, ccache); 28233965Sjdp return ret; 28333965Sjdp } 28433965Sjdp 28533965Sjdp kcm_ccache_enqueue_default(context, ccache, &creds); 28633965Sjdp 28733965Sjdp free(name); 28860514Sobrien kcm_release_ccache(context, ccache); 28933965Sjdp 29033965Sjdp return 0; 29133965Sjdp} 29233965Sjdp 29333965Sjdp/* 29433965Sjdp * Request: 29533965Sjdp * NameZ 29633965Sjdp * WhichFields 29733965Sjdp * MatchCreds 29833965Sjdp * 29933965Sjdp * Response: 30033965Sjdp * Creds 30133965Sjdp * 30289864Sobrien */ 30389864Sobrienstatic krb5_error_code 30489864Sobrienkcm_op_retrieve(krb5_context context, 30568773Sobrien kcm_client *client, 30668773Sobrien kcm_operation opcode, 30768773Sobrien krb5_storage *request, 30877307Sobrien krb5_storage *response) 30977307Sobrien{ 31077307Sobrien uint32_t flags; 31168773Sobrien krb5_creds mcreds; 31268773Sobrien krb5_error_code ret; 31368773Sobrien kcm_ccache ccache; 31468773Sobrien char *name; 31568773Sobrien krb5_creds *credp; 31668773Sobrien int free_creds = 0; 31768773Sobrien 31868773Sobrien ret = krb5_ret_stringz(request, &name); 31968773Sobrien if (ret) 32068773Sobrien return ret; 32168773Sobrien 32268773Sobrien KCM_LOG_REQUEST_NAME(context, client, opcode, name); 32368773Sobrien 32468773Sobrien ret = krb5_ret_uint32(request, &flags); 32568773Sobrien if (ret) { 32668773Sobrien free(name); 32768773Sobrien return ret; 32868773Sobrien } 32968773Sobrien 33089864Sobrien ret = krb5_ret_creds_tag(request, &mcreds); 33189864Sobrien if (ret) { 33268773Sobrien free(name); 33368773Sobrien return ret; 33433965Sjdp } 33533965Sjdp 33668773Sobrien if (disallow_getting_krbtgt && 33733965Sjdp mcreds.server->name.name_string.len == 2 && 33833965Sjdp strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0) 33933965Sjdp { 34033965Sjdp free(name); 34133965Sjdp krb5_free_cred_contents(context, &mcreds); 34233965Sjdp return KRB5_FCC_PERM; 34333965Sjdp } 34433965Sjdp 34533965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 34633965Sjdp name, &ccache); 34733965Sjdp if (ret) { 34833965Sjdp free(name); 34933965Sjdp krb5_free_cred_contents(context, &mcreds); 35033965Sjdp return ret; 35133965Sjdp } 35233965Sjdp 35333965Sjdp ret = kcm_ccache_retrieve_cred(context, ccache, flags, 35433965Sjdp &mcreds, &credp); 35533965Sjdp if (ret && ((flags & KRB5_GC_CACHED) == 0) && 35633965Sjdp !krb5_is_config_principal(context, mcreds.server)) { 35733965Sjdp krb5_ccache_data ccdata; 35833965Sjdp 35933965Sjdp /* try and acquire */ 36033965Sjdp HEIMDAL_MUTEX_lock(&ccache->mutex); 36133965Sjdp 36233965Sjdp /* Fake up an internal ccache */ 36333965Sjdp kcm_internal_ccache(context, ccache, &ccdata); 36433965Sjdp 36533965Sjdp /* glue cc layer will store creds */ 36633965Sjdp ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp); 36733965Sjdp if (ret == 0) 36833965Sjdp free_creds = 1; 36960514Sobrien 37033965Sjdp HEIMDAL_MUTEX_unlock(&ccache->mutex); 37133965Sjdp } 37233965Sjdp 37333965Sjdp if (ret == 0) { 37433965Sjdp ret = krb5_store_creds(response, credp); 37533965Sjdp } 37633965Sjdp 37733965Sjdp free(name); 37833965Sjdp krb5_free_cred_contents(context, &mcreds); 37933965Sjdp kcm_release_ccache(context, ccache); 38033965Sjdp 38133965Sjdp if (free_creds) 38233965Sjdp krb5_free_cred_contents(context, credp); 38333965Sjdp 38433965Sjdp return ret; 38533965Sjdp} 38633965Sjdp 38733965Sjdp/* 38833965Sjdp * Request: 38933965Sjdp * NameZ 39033965Sjdp * 39133965Sjdp * Response: 39233965Sjdp * Principal 39333965Sjdp */ 39460514Sobrienstatic krb5_error_code 39533965Sjdpkcm_op_get_principal(krb5_context context, 39633965Sjdp kcm_client *client, 39733965Sjdp kcm_operation opcode, 39833965Sjdp krb5_storage *request, 39989864Sobrien krb5_storage *response) 40089864Sobrien{ 40133965Sjdp krb5_error_code ret; 40233965Sjdp kcm_ccache ccache; 40333965Sjdp char *name; 40433965Sjdp 40533965Sjdp ret = krb5_ret_stringz(request, &name); 40633965Sjdp if (ret) 40733965Sjdp return ret; 40833965Sjdp 40960514Sobrien KCM_LOG_REQUEST_NAME(context, client, opcode, name); 41060514Sobrien 41160514Sobrien ret = kcm_ccache_resolve_client(context, client, opcode, 41289864Sobrien name, &ccache); 41389864Sobrien if (ret) { 41489864Sobrien free(name); 41560514Sobrien return ret; 41660514Sobrien } 41760514Sobrien 41833965Sjdp if (ccache->client == NULL) 41933965Sjdp ret = KRB5_CC_NOTFOUND; 42033965Sjdp else 42133965Sjdp ret = krb5_store_principal(response, ccache->client); 42233965Sjdp 42333965Sjdp free(name); 42433965Sjdp kcm_release_ccache(context, ccache); 42533965Sjdp 42689864Sobrien return 0; 42777307Sobrien} 42833965Sjdp 42933965Sjdp/* 43033965Sjdp * Request: 43133965Sjdp * NameZ 43233965Sjdp * 43333965Sjdp * Response: 43433965Sjdp * UUIDs 43533965Sjdp * 43633965Sjdp */ 43733965Sjdpstatic krb5_error_code 43833965Sjdpkcm_op_get_cred_uuid_list(krb5_context context, 43933965Sjdp kcm_client *client, 44033965Sjdp kcm_operation opcode, 44133965Sjdp krb5_storage *request, 44233965Sjdp krb5_storage *response) 44377307Sobrien{ 44477307Sobrien struct kcm_creds *creds; 44577307Sobrien krb5_error_code ret; 44677307Sobrien kcm_ccache ccache; 44777307Sobrien char *name; 44877307Sobrien 44977307Sobrien ret = krb5_ret_stringz(request, &name); 45077307Sobrien if (ret) 45177307Sobrien return ret; 45277307Sobrien 45377307Sobrien KCM_LOG_REQUEST_NAME(context, client, opcode, name); 45433965Sjdp 45533965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 45633965Sjdp name, &ccache); 45733965Sjdp free(name); 45833965Sjdp if (ret) 45933965Sjdp return ret; 46033965Sjdp 46133965Sjdp for (creds = ccache->creds ; creds ; creds = creds->next) { 46233965Sjdp ssize_t sret; 46333965Sjdp sret = krb5_storage_write(response, &creds->uuid, sizeof(creds->uuid)); 46433965Sjdp if (sret != sizeof(creds->uuid)) { 46533965Sjdp ret = ENOMEM; 46633965Sjdp break; 46789864Sobrien } 46833965Sjdp } 46933965Sjdp 47033965Sjdp kcm_release_ccache(context, ccache); 47133965Sjdp 47233965Sjdp return ret; 47333965Sjdp} 47433965Sjdp 47533965Sjdp/* 47633965Sjdp * Request: 47733965Sjdp * NameZ 47833965Sjdp * Cursor 47933965Sjdp * 48033965Sjdp * Response: 48133965Sjdp * Creds 48233965Sjdp */ 48333965Sjdpstatic krb5_error_code 48433965Sjdpkcm_op_get_cred_by_uuid(krb5_context context, 48533965Sjdp kcm_client *client, 48633965Sjdp kcm_operation opcode, 48733965Sjdp krb5_storage *request, 48833965Sjdp krb5_storage *response) 48933965Sjdp{ 49033965Sjdp krb5_error_code ret; 49133965Sjdp kcm_ccache ccache; 49233965Sjdp char *name; 49333965Sjdp struct kcm_creds *c; 49433965Sjdp kcmuuid_t uuid; 49533965Sjdp ssize_t sret; 49633965Sjdp 49733965Sjdp ret = krb5_ret_stringz(request, &name); 49877307Sobrien if (ret) 49977307Sobrien return ret; 50077307Sobrien 50177307Sobrien KCM_LOG_REQUEST_NAME(context, client, opcode, name); 50277307Sobrien 50377307Sobrien ret = kcm_ccache_resolve_client(context, client, opcode, 50477307Sobrien name, &ccache); 50577307Sobrien free(name); 50677307Sobrien if (ret) 50777307Sobrien return ret; 50877307Sobrien 50933965Sjdp sret = krb5_storage_read(request, &uuid, sizeof(uuid)); 51060514Sobrien if (sret != sizeof(uuid)) { 51133965Sjdp kcm_release_ccache(context, ccache); 51233965Sjdp krb5_clear_error_message(context); 51333965Sjdp return KRB5_CC_IO; 51433965Sjdp } 51533965Sjdp 51633965Sjdp c = kcm_ccache_find_cred_uuid(context, ccache, uuid); 51733965Sjdp if (c == NULL) { 51833965Sjdp kcm_release_ccache(context, ccache); 51933965Sjdp return KRB5_CC_END; 52033965Sjdp } 52133965Sjdp 52233965Sjdp HEIMDAL_MUTEX_lock(&ccache->mutex); 52333965Sjdp ret = krb5_store_creds(response, &c->cred); 52433965Sjdp HEIMDAL_MUTEX_unlock(&ccache->mutex); 52533965Sjdp 52633965Sjdp kcm_release_ccache(context, ccache); 52733965Sjdp 52833965Sjdp return ret; 52933965Sjdp} 53033965Sjdp 53133965Sjdp/* 53233965Sjdp * Request: 53333965Sjdp * NameZ 53433965Sjdp * WhichFields 53533965Sjdp * MatchCreds 53633965Sjdp * 53733965Sjdp * Response: 53833965Sjdp * 53933965Sjdp */ 54033965Sjdpstatic krb5_error_code 54133965Sjdpkcm_op_remove_cred(krb5_context context, 54233965Sjdp kcm_client *client, 54333965Sjdp kcm_operation opcode, 54433965Sjdp krb5_storage *request, 54533965Sjdp krb5_storage *response) 54633965Sjdp{ 54733965Sjdp uint32_t whichfields; 54833965Sjdp krb5_creds mcreds; 54960514Sobrien krb5_error_code ret; 55033965Sjdp kcm_ccache ccache; 55133965Sjdp char *name; 55233965Sjdp 55333965Sjdp ret = krb5_ret_stringz(request, &name); 55433965Sjdp if (ret) 55533965Sjdp return ret; 55633965Sjdp 55733965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 55833965Sjdp 55933965Sjdp ret = krb5_ret_uint32(request, &whichfields); 56033965Sjdp if (ret) { 56133965Sjdp free(name); 56233965Sjdp return ret; 56333965Sjdp } 56433965Sjdp 56533965Sjdp ret = krb5_ret_creds_tag(request, &mcreds); 56633965Sjdp if (ret) { 56733965Sjdp free(name); 56833965Sjdp return ret; 56933965Sjdp } 57033965Sjdp 57133965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 57233965Sjdp name, &ccache); 57333965Sjdp if (ret) { 57433965Sjdp free(name); 57533965Sjdp krb5_free_cred_contents(context, &mcreds); 57633965Sjdp return ret; 57733965Sjdp } 57833965Sjdp 57933965Sjdp ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds); 58033965Sjdp 58133965Sjdp /* XXX need to remove any events that match */ 58233965Sjdp 58333965Sjdp free(name); 58433965Sjdp krb5_free_cred_contents(context, &mcreds); 58533965Sjdp kcm_release_ccache(context, ccache); 58633965Sjdp 58733965Sjdp return ret; 58833965Sjdp} 58933965Sjdp 59033965Sjdp/* 59133965Sjdp * Request: 59233965Sjdp * NameZ 59333965Sjdp * Flags 59433965Sjdp * 59533965Sjdp * Response: 59633965Sjdp * 59733965Sjdp */ 59833965Sjdpstatic krb5_error_code 59933965Sjdpkcm_op_set_flags(krb5_context context, 60038891Sjdp kcm_client *client, 60138891Sjdp kcm_operation opcode, 60238891Sjdp krb5_storage *request, 60338891Sjdp krb5_storage *response) 60438891Sjdp{ 60533965Sjdp uint32_t flags; 60633965Sjdp krb5_error_code ret; 60733965Sjdp kcm_ccache ccache; 60833965Sjdp char *name; 60938891Sjdp 61038891Sjdp ret = krb5_ret_stringz(request, &name); 61138891Sjdp if (ret) 61238891Sjdp return ret; 61338891Sjdp 61433965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 61533965Sjdp 61633965Sjdp ret = krb5_ret_uint32(request, &flags); 61733965Sjdp if (ret) { 61833965Sjdp free(name); 61933965Sjdp return ret; 62033965Sjdp } 62133965Sjdp 62233965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 62333965Sjdp name, &ccache); 62433965Sjdp if (ret) { 62533965Sjdp free(name); 62633965Sjdp return ret; 62733965Sjdp } 62833965Sjdp 62933965Sjdp /* we don't really support any flags yet */ 63033965Sjdp free(name); 63133965Sjdp kcm_release_ccache(context, ccache); 63233965Sjdp 63333965Sjdp return 0; 63433965Sjdp} 63533965Sjdp 63633965Sjdp/* 63733965Sjdp * Request: 63833965Sjdp * NameZ 63933965Sjdp * UID 64033965Sjdp * GID 64133965Sjdp * 64233965Sjdp * Response: 64333965Sjdp * 64433965Sjdp */ 64533965Sjdpstatic krb5_error_code 64633965Sjdpkcm_op_chown(krb5_context context, 64733965Sjdp kcm_client *client, 64833965Sjdp kcm_operation opcode, 64933965Sjdp krb5_storage *request, 65033965Sjdp krb5_storage *response) 65133965Sjdp{ 65233965Sjdp uint32_t uid; 65333965Sjdp uint32_t gid; 65438891Sjdp krb5_error_code ret; 65538891Sjdp kcm_ccache ccache; 65638891Sjdp char *name; 65733965Sjdp 65833965Sjdp ret = krb5_ret_stringz(request, &name); 65933965Sjdp if (ret) 66033965Sjdp return ret; 66133965Sjdp 66233965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 66333965Sjdp 66433965Sjdp ret = krb5_ret_uint32(request, &uid); 66533965Sjdp if (ret) { 66633965Sjdp free(name); 66733965Sjdp return ret; 66833965Sjdp } 66933965Sjdp 67033965Sjdp ret = krb5_ret_uint32(request, &gid); 67133965Sjdp if (ret) { 67233965Sjdp free(name); 67333965Sjdp return ret; 67433965Sjdp } 67533965Sjdp 67633965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 67733965Sjdp name, &ccache); 67833965Sjdp if (ret) { 67933965Sjdp free(name); 68033965Sjdp return ret; 68133965Sjdp } 68233965Sjdp 68333965Sjdp ret = kcm_chown(context, client, ccache, uid, gid); 68433965Sjdp 68533965Sjdp free(name); 68633965Sjdp kcm_release_ccache(context, ccache); 68733965Sjdp 68833965Sjdp return ret; 68933965Sjdp} 69033965Sjdp 69133965Sjdp/* 69233965Sjdp * Request: 69333965Sjdp * NameZ 69433965Sjdp * Mode 69533965Sjdp * 69633965Sjdp * Response: 69733965Sjdp * 69833965Sjdp */ 69933965Sjdpstatic krb5_error_code 70033965Sjdpkcm_op_chmod(krb5_context context, 70133965Sjdp kcm_client *client, 70233965Sjdp kcm_operation opcode, 70333965Sjdp krb5_storage *request, 70433965Sjdp krb5_storage *response) 70533965Sjdp{ 70633965Sjdp uint16_t mode; 70733965Sjdp krb5_error_code ret; 70833965Sjdp kcm_ccache ccache; 70933965Sjdp char *name; 71033965Sjdp 71133965Sjdp ret = krb5_ret_stringz(request, &name); 71233965Sjdp if (ret) 71333965Sjdp return ret; 71433965Sjdp 71533965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 71633965Sjdp 71733965Sjdp ret = krb5_ret_uint16(request, &mode); 71833965Sjdp if (ret) { 71933965Sjdp free(name); 72033965Sjdp return ret; 72133965Sjdp } 72233965Sjdp 72333965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 72433965Sjdp name, &ccache); 72533965Sjdp if (ret) { 72633965Sjdp free(name); 72733965Sjdp return ret; 72833965Sjdp } 72933965Sjdp 73033965Sjdp ret = kcm_chmod(context, client, ccache, mode); 73133965Sjdp 73233965Sjdp free(name); 73333965Sjdp kcm_release_ccache(context, ccache); 73433965Sjdp 73533965Sjdp return ret; 73633965Sjdp} 73733965Sjdp 73833965Sjdp/* 73933965Sjdp * Protocol extensions for moving ticket acquisition responsibility 74033965Sjdp * from client to KCM follow. 74133965Sjdp */ 74233965Sjdp 74333965Sjdp/* 74433965Sjdp * Request: 74533965Sjdp * NameZ 74633965Sjdp * ServerPrincipalPresent 74733965Sjdp * ServerPrincipal OPTIONAL 74833965Sjdp * Key 74933965Sjdp * 75033965Sjdp * Repsonse: 75133965Sjdp * 75233965Sjdp */ 75333965Sjdpstatic krb5_error_code 75433965Sjdpkcm_op_get_initial_ticket(krb5_context context, 75533965Sjdp kcm_client *client, 75633965Sjdp kcm_operation opcode, 75733965Sjdp krb5_storage *request, 75833965Sjdp krb5_storage *response) 75933965Sjdp{ 76033965Sjdp krb5_error_code ret; 76133965Sjdp kcm_ccache ccache; 76233965Sjdp char *name; 76333965Sjdp int8_t not_tgt = 0; 76433965Sjdp krb5_principal server = NULL; 76533965Sjdp krb5_keyblock key; 76633965Sjdp 76733965Sjdp krb5_keyblock_zero(&key); 76833965Sjdp 76933965Sjdp ret = krb5_ret_stringz(request, &name); 77033965Sjdp if (ret) 77133965Sjdp return ret; 77233965Sjdp 77333965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 77433965Sjdp 77533965Sjdp ret = krb5_ret_int8(request, ¬_tgt); 77633965Sjdp if (ret) { 77733965Sjdp free(name); 77833965Sjdp return ret; 77933965Sjdp } 78033965Sjdp 78133965Sjdp if (not_tgt) { 78233965Sjdp ret = krb5_ret_principal(request, &server); 78333965Sjdp if (ret) { 78433965Sjdp free(name); 78533965Sjdp return ret; 78633965Sjdp } 78733965Sjdp } 78833965Sjdp 78933965Sjdp ret = krb5_ret_keyblock(request, &key); 79033965Sjdp if (ret) { 79133965Sjdp free(name); 79233965Sjdp if (server != NULL) 79333965Sjdp krb5_free_principal(context, server); 79433965Sjdp return ret; 79533965Sjdp } 79633965Sjdp 79733965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 79833965Sjdp name, &ccache); 79933965Sjdp if (ret == 0) { 80033965Sjdp HEIMDAL_MUTEX_lock(&ccache->mutex); 80133965Sjdp 80233965Sjdp if (ccache->server != NULL) { 80333965Sjdp krb5_free_principal(context, ccache->server); 80433965Sjdp ccache->server = NULL; 80533965Sjdp } 80633965Sjdp 80733965Sjdp krb5_free_keyblock(context, &ccache->key.keyblock); 80833965Sjdp 80933965Sjdp ccache->server = server; 81033965Sjdp ccache->key.keyblock = key; 81133965Sjdp ccache->flags |= KCM_FLAGS_USE_CACHED_KEY; 81233965Sjdp 81333965Sjdp ret = kcm_ccache_enqueue_default(context, ccache, NULL); 81433965Sjdp if (ret) { 81533965Sjdp ccache->server = NULL; 81633965Sjdp krb5_keyblock_zero(&ccache->key.keyblock); 81733965Sjdp ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY); 81833965Sjdp } 81933965Sjdp 82033965Sjdp HEIMDAL_MUTEX_unlock(&ccache->mutex); 82133965Sjdp } 82233965Sjdp 82333965Sjdp free(name); 82433965Sjdp 82533965Sjdp if (ret != 0) { 82633965Sjdp krb5_free_principal(context, server); 82733965Sjdp krb5_free_keyblock(context, &key); 82833965Sjdp } 82933965Sjdp 83033965Sjdp kcm_release_ccache(context, ccache); 83133965Sjdp 83233965Sjdp return ret; 83333965Sjdp} 83433965Sjdp 83533965Sjdp/* 83633965Sjdp * Request: 83733965Sjdp * NameZ 83833965Sjdp * ServerPrincipal 83933965Sjdp * KDCFlags 84033965Sjdp * EncryptionType 84133965Sjdp * 84233965Sjdp * Repsonse: 84333965Sjdp * 84433965Sjdp */ 84533965Sjdpstatic krb5_error_code 84633965Sjdpkcm_op_get_ticket(krb5_context context, 84733965Sjdp kcm_client *client, 84833965Sjdp kcm_operation opcode, 84933965Sjdp krb5_storage *request, 85033965Sjdp krb5_storage *response) 85133965Sjdp{ 85233965Sjdp krb5_error_code ret; 85333965Sjdp kcm_ccache ccache; 85433965Sjdp char *name; 85533965Sjdp krb5_principal server = NULL; 85633965Sjdp krb5_ccache_data ccdata; 85733965Sjdp krb5_creds in, *out; 85833965Sjdp krb5_kdc_flags flags; 85933965Sjdp 86038891Sjdp memset(&in, 0, sizeof(in)); 86133965Sjdp 86233965Sjdp ret = krb5_ret_stringz(request, &name); 86333965Sjdp if (ret) 86433965Sjdp return ret; 86533965Sjdp 86633965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 86733965Sjdp 86833965Sjdp ret = krb5_ret_uint32(request, &flags.i); 86933965Sjdp if (ret) { 87033965Sjdp free(name); 87133965Sjdp return ret; 87233965Sjdp } 87333965Sjdp 87433965Sjdp ret = krb5_ret_int32(request, &in.session.keytype); 87533965Sjdp if (ret) { 87633965Sjdp free(name); 87733965Sjdp return ret; 87833965Sjdp } 87933965Sjdp 88033965Sjdp ret = krb5_ret_principal(request, &server); 88133965Sjdp if (ret) { 88233965Sjdp free(name); 88333965Sjdp return ret; 88433965Sjdp } 88533965Sjdp 88633965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, 88733965Sjdp name, &ccache); 88833965Sjdp if (ret) { 88933965Sjdp krb5_free_principal(context, server); 89033965Sjdp free(name); 89133965Sjdp return ret; 89233965Sjdp } 89333965Sjdp 89433965Sjdp HEIMDAL_MUTEX_lock(&ccache->mutex); 89533965Sjdp 89633965Sjdp /* Fake up an internal ccache */ 89733965Sjdp kcm_internal_ccache(context, ccache, &ccdata); 89833965Sjdp 89933965Sjdp in.client = ccache->client; 90033965Sjdp in.server = server; 90133965Sjdp in.times.endtime = 0; 90233965Sjdp 90333965Sjdp /* glue cc layer will store creds */ 90433965Sjdp ret = krb5_get_credentials_with_flags(context, 0, flags, 90533965Sjdp &ccdata, &in, &out); 90633965Sjdp 90733965Sjdp HEIMDAL_MUTEX_unlock(&ccache->mutex); 90833965Sjdp 90933965Sjdp krb5_free_principal(context, server); 91033965Sjdp 91133965Sjdp if (ret == 0) 91233965Sjdp krb5_free_cred_contents(context, out); 91333965Sjdp 91433965Sjdp kcm_release_ccache(context, ccache); 91533965Sjdp free(name); 91633965Sjdp 91733965Sjdp return ret; 91833965Sjdp} 91933965Sjdp 92033965Sjdp/* 92133965Sjdp * Request: 92233965Sjdp * OldNameZ 92333965Sjdp * NewNameZ 92433965Sjdp * 92533965Sjdp * Repsonse: 92633965Sjdp * 92733965Sjdp */ 92833965Sjdpstatic krb5_error_code 92933965Sjdpkcm_op_move_cache(krb5_context context, 93033965Sjdp kcm_client *client, 93133965Sjdp kcm_operation opcode, 93233965Sjdp krb5_storage *request, 93333965Sjdp krb5_storage *response) 93433965Sjdp{ 93533965Sjdp krb5_error_code ret; 93633965Sjdp kcm_ccache oldid, newid; 93733965Sjdp char *oldname, *newname; 93833965Sjdp 93933965Sjdp ret = krb5_ret_stringz(request, &oldname); 94033965Sjdp if (ret) 94133965Sjdp return ret; 94233965Sjdp 94333965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, oldname); 94433965Sjdp 94533965Sjdp ret = krb5_ret_stringz(request, &newname); 94633965Sjdp if (ret) { 94733965Sjdp free(oldname); 94833965Sjdp return ret; 94933965Sjdp } 95033965Sjdp 95133965Sjdp /* move to ourself is simple, done! */ 95233965Sjdp if (strcmp(oldname, newname) == 0) { 95333965Sjdp free(oldname); 95433965Sjdp free(newname); 95589864Sobrien return 0; 95633965Sjdp } 95733965Sjdp 95833965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid); 95933965Sjdp if (ret) { 96033965Sjdp free(oldname); 96160514Sobrien free(newname); 96233965Sjdp return ret; 96333965Sjdp } 96433965Sjdp 96533965Sjdp /* Check if new credential cache exists, if not create one. */ 96633965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, newname, &newid); 96733965Sjdp if (ret == KRB5_FCC_NOFILE) 96833965Sjdp ret = kcm_ccache_new_client(context, client, newname, &newid); 96933965Sjdp free(newname); 97033965Sjdp 97133965Sjdp if (ret) { 97260514Sobrien free(oldname); 97333965Sjdp kcm_release_ccache(context, oldid); 97433965Sjdp return ret; 97533965Sjdp } 97689864Sobrien 97789864Sobrien HEIMDAL_MUTEX_lock(&oldid->mutex); 97889864Sobrien HEIMDAL_MUTEX_lock(&newid->mutex); 97933965Sjdp 98033965Sjdp /* move content */ 98133965Sjdp { 98233965Sjdp kcm_ccache_data tmp; 98333965Sjdp 98433965Sjdp#define MOVE(n,o,f) { tmp.f = n->f ; n->f = o->f; o->f = tmp.f; } 98533965Sjdp 98633965Sjdp MOVE(newid, oldid, flags); 98733965Sjdp MOVE(newid, oldid, client); 98833965Sjdp MOVE(newid, oldid, server); 98933965Sjdp MOVE(newid, oldid, creds); 99033965Sjdp MOVE(newid, oldid, tkt_life); 99133965Sjdp MOVE(newid, oldid, renew_life); 99233965Sjdp MOVE(newid, oldid, key); 99333965Sjdp MOVE(newid, oldid, kdc_offset); 99433965Sjdp#undef MOVE 99533965Sjdp } 99633965Sjdp 99733965Sjdp HEIMDAL_MUTEX_unlock(&oldid->mutex); 99833965Sjdp HEIMDAL_MUTEX_unlock(&newid->mutex); 99933965Sjdp 100033965Sjdp kcm_release_ccache(context, oldid); 100133965Sjdp kcm_release_ccache(context, newid); 100233965Sjdp 100333965Sjdp ret = kcm_ccache_destroy_client(context, client, oldname); 100433965Sjdp if (ret == 0) 100533965Sjdp kcm_drop_default_cache(context, client, oldname); 100633965Sjdp 100733965Sjdp free(oldname); 100833965Sjdp 100933965Sjdp return ret; 101033965Sjdp} 101133965Sjdp 101233965Sjdpstatic krb5_error_code 101333965Sjdpkcm_op_get_cache_uuid_list(krb5_context context, 101433965Sjdp kcm_client *client, 101533965Sjdp kcm_operation opcode, 101633965Sjdp krb5_storage *request, 101733965Sjdp krb5_storage *response) 101833965Sjdp{ 101933965Sjdp KCM_LOG_REQUEST(context, client, opcode); 102033965Sjdp 102133965Sjdp return kcm_ccache_get_uuids(context, client, opcode, response); 102233965Sjdp} 102333965Sjdp 102433965Sjdpstatic krb5_error_code 102533965Sjdpkcm_op_get_cache_by_uuid(krb5_context context, 102633965Sjdp kcm_client *client, 102733965Sjdp kcm_operation opcode, 102833965Sjdp krb5_storage *request, 102933965Sjdp krb5_storage *response) 103033965Sjdp{ 103133965Sjdp krb5_error_code ret; 103233965Sjdp kcmuuid_t uuid; 103333965Sjdp ssize_t sret; 103433965Sjdp kcm_ccache cache; 103533965Sjdp 103633965Sjdp KCM_LOG_REQUEST(context, client, opcode); 103733965Sjdp 103833965Sjdp sret = krb5_storage_read(request, &uuid, sizeof(uuid)); 103933965Sjdp if (sret != sizeof(uuid)) { 104033965Sjdp krb5_clear_error_message(context); 104133965Sjdp return KRB5_CC_IO; 104233965Sjdp } 104333965Sjdp 104433965Sjdp ret = kcm_ccache_resolve_by_uuid(context, uuid, &cache); 104533965Sjdp if (ret) 104633965Sjdp return ret; 104733965Sjdp 104833965Sjdp ret = kcm_access(context, client, opcode, cache); 104933965Sjdp if (ret) 105033965Sjdp ret = KRB5_FCC_NOFILE; 105133965Sjdp 105233965Sjdp if (ret == 0) 105333965Sjdp ret = krb5_store_stringz(response, cache->name); 105433965Sjdp 105533965Sjdp kcm_release_ccache(context, cache); 105633965Sjdp 105733965Sjdp return ret; 105833965Sjdp} 105933965Sjdp 106033965Sjdpstruct kcm_default_cache *default_caches; 106133965Sjdp 106233965Sjdpstatic krb5_error_code 106333965Sjdpkcm_op_get_default_cache(krb5_context context, 106433965Sjdp kcm_client *client, 106533965Sjdp kcm_operation opcode, 106633965Sjdp krb5_storage *request, 106733965Sjdp krb5_storage *response) 106833965Sjdp{ 106933965Sjdp struct kcm_default_cache *c; 107033965Sjdp krb5_error_code ret; 107133965Sjdp const char *name = NULL; 107233965Sjdp char *n = NULL; 107333965Sjdp 107433965Sjdp KCM_LOG_REQUEST(context, client, opcode); 107533965Sjdp 107633965Sjdp for (c = default_caches; c != NULL; c = c->next) { 107733965Sjdp if (kcm_is_same_session(client, c->uid, c->session)) { 107833965Sjdp name = c->name; 107933965Sjdp break; 108033965Sjdp } 108133965Sjdp } 108233965Sjdp if (name == NULL) 108333965Sjdp name = n = kcm_ccache_first_name(client); 108433965Sjdp 108533965Sjdp if (name == NULL) { 108633965Sjdp asprintf(&n, "%d", (int)client->uid); 108733965Sjdp name = n; 108833965Sjdp } 108933965Sjdp if (name == NULL) 109033965Sjdp return ENOMEM; 109133965Sjdp ret = krb5_store_stringz(response, name); 109233965Sjdp if (n) 109333965Sjdp free(n); 109433965Sjdp return ret; 109533965Sjdp} 109633965Sjdp 109733965Sjdpstatic void 109833965Sjdpkcm_drop_default_cache(krb5_context context, kcm_client *client, char *name) 109933965Sjdp{ 110033965Sjdp struct kcm_default_cache **c; 110133965Sjdp 110233965Sjdp for (c = &default_caches; *c != NULL; c = &(*c)->next) { 110333965Sjdp if (!kcm_is_same_session(client, (*c)->uid, (*c)->session)) 110433965Sjdp continue; 110533965Sjdp if (strcmp((*c)->name, name) == 0) { 110633965Sjdp struct kcm_default_cache *h = *c; 110733965Sjdp *c = (*c)->next; 110833965Sjdp free(h->name); 110933965Sjdp free(h); 111033965Sjdp break; 111133965Sjdp } 111233965Sjdp } 111333965Sjdp} 111433965Sjdp 111533965Sjdpstatic krb5_error_code 111633965Sjdpkcm_op_set_default_cache(krb5_context context, 111733965Sjdp kcm_client *client, 111833965Sjdp kcm_operation opcode, 111933965Sjdp krb5_storage *request, 112033965Sjdp krb5_storage *response) 112133965Sjdp{ 112233965Sjdp struct kcm_default_cache *c; 112333965Sjdp krb5_error_code ret; 112433965Sjdp char *name; 112533965Sjdp 112633965Sjdp ret = krb5_ret_stringz(request, &name); 112733965Sjdp if (ret) 112833965Sjdp return ret; 112933965Sjdp 113033965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 113133965Sjdp 113233965Sjdp for (c = default_caches; c != NULL; c = c->next) { 113333965Sjdp if (kcm_is_same_session(client, c->uid, c->session)) 113433965Sjdp break; 113533965Sjdp } 113633965Sjdp if (c == NULL) { 113733965Sjdp c = malloc(sizeof(*c)); 113833965Sjdp if (c == NULL) 113933965Sjdp return ENOMEM; 114033965Sjdp c->session = client->session; 114133965Sjdp c->uid = client->uid; 114233965Sjdp c->name = strdup(name); 114333965Sjdp 114433965Sjdp c->next = default_caches; 114533965Sjdp default_caches = c; 114633965Sjdp } else { 114733965Sjdp free(c->name); 114833965Sjdp c->name = strdup(name); 114933965Sjdp } 115033965Sjdp 115133965Sjdp return 0; 115233965Sjdp} 115333965Sjdp 115433965Sjdpstatic krb5_error_code 115533965Sjdpkcm_op_get_kdc_offset(krb5_context context, 115633965Sjdp kcm_client *client, 115733965Sjdp kcm_operation opcode, 115833965Sjdp krb5_storage *request, 115933965Sjdp krb5_storage *response) 116033965Sjdp{ 116133965Sjdp krb5_error_code ret; 116233965Sjdp kcm_ccache ccache; 116333965Sjdp char *name; 116433965Sjdp 116533965Sjdp ret = krb5_ret_stringz(request, &name); 116633965Sjdp if (ret) 116733965Sjdp return ret; 116833965Sjdp 116933965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 117033965Sjdp 117133965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); 117233965Sjdp free(name); 117333965Sjdp if (ret) 117433965Sjdp return ret; 117533965Sjdp 117633965Sjdp HEIMDAL_MUTEX_lock(&ccache->mutex); 117733965Sjdp ret = krb5_store_int32(response, ccache->kdc_offset); 117833965Sjdp HEIMDAL_MUTEX_unlock(&ccache->mutex); 117933965Sjdp 118033965Sjdp kcm_release_ccache(context, ccache); 118133965Sjdp 118233965Sjdp return ret; 118333965Sjdp} 118433965Sjdp 118533965Sjdpstatic krb5_error_code 118633965Sjdpkcm_op_set_kdc_offset(krb5_context context, 118733965Sjdp kcm_client *client, 118833965Sjdp kcm_operation opcode, 118933965Sjdp krb5_storage *request, 119033965Sjdp krb5_storage *response) 119133965Sjdp{ 119233965Sjdp krb5_error_code ret; 119333965Sjdp kcm_ccache ccache; 119433965Sjdp int32_t offset; 119533965Sjdp char *name; 119633965Sjdp 119733965Sjdp ret = krb5_ret_stringz(request, &name); 119833965Sjdp if (ret) 119933965Sjdp return ret; 120033965Sjdp 120133965Sjdp KCM_LOG_REQUEST_NAME(context, client, opcode, name); 120233965Sjdp 120333965Sjdp ret = krb5_ret_int32(request, &offset); 120433965Sjdp if (ret) { 120533965Sjdp free(name); 120633965Sjdp return ret; 120733965Sjdp } 120833965Sjdp 120933965Sjdp ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); 121033965Sjdp free(name); 121133965Sjdp if (ret) 121233965Sjdp return ret; 121333965Sjdp 121433965Sjdp HEIMDAL_MUTEX_lock(&ccache->mutex); 121533965Sjdp ccache->kdc_offset = offset; 121633965Sjdp HEIMDAL_MUTEX_unlock(&ccache->mutex); 121738891Sjdp 121833965Sjdp kcm_release_ccache(context, ccache); 121933965Sjdp 122033965Sjdp return ret; 122133965Sjdp} 122233965Sjdp 122333965Sjdpstruct kcm_ntlm_cred { 122433965Sjdp kcmuuid_t uuid; 122533965Sjdp char *user; 122633965Sjdp char *domain; 122733965Sjdp krb5_data nthash; 122833965Sjdp uid_t uid; 122933965Sjdp pid_t session; 123033965Sjdp struct kcm_ntlm_cred *next; 123133965Sjdp}; 123233965Sjdp 123338891Sjdpstatic struct kcm_ntlm_cred *ntlm_head; 123433965Sjdp 123533965Sjdpstatic void 123633965Sjdpfree_cred(struct kcm_ntlm_cred *cred) 123733965Sjdp{ 123833965Sjdp free(cred->user); 123933965Sjdp free(cred->domain); 124033965Sjdp krb5_data_free(&cred->nthash); 124138891Sjdp free(cred); 124238891Sjdp} 124333965Sjdp 124433965Sjdp 124533965Sjdp/* 124633965Sjdp * name 124733965Sjdp * domain 124838891Sjdp * ntlm hash 124933965Sjdp * 125033965Sjdp * Reply: 125133965Sjdp * uuid 125233965Sjdp */ 125333965Sjdp 125433965Sjdpstatic struct kcm_ntlm_cred * 125533965Sjdpfind_ntlm_cred(const char *user, const char *domain, kcm_client *client) 125633965Sjdp{ 125733965Sjdp struct kcm_ntlm_cred *c; 125833965Sjdp 125933965Sjdp for (c = ntlm_head; c != NULL; c = c->next) 126033965Sjdp if ((user[0] == '\0' || strcmp(user, c->user) == 0) && 126133965Sjdp (domain == NULL || strcmp(domain, c->domain) == 0) && 126233965Sjdp kcm_is_same_session(client, c->uid, c->session)) 126333965Sjdp return c; 126433965Sjdp 126538891Sjdp return NULL; 126638891Sjdp} 126733965Sjdp 126833965Sjdpstatic krb5_error_code 126933965Sjdpkcm_op_add_ntlm_cred(krb5_context context, 127033965Sjdp kcm_client *client, 127133965Sjdp kcm_operation opcode, 127233965Sjdp krb5_storage *request, 127333965Sjdp krb5_storage *response) 127433965Sjdp{ 127533965Sjdp struct kcm_ntlm_cred *cred, *c; 127638891Sjdp krb5_error_code ret; 127733965Sjdp 127833965Sjdp cred = calloc(1, sizeof(*cred)); 127933965Sjdp if (cred == NULL) 128033965Sjdp return ENOMEM; 128133965Sjdp 128238891Sjdp RAND_bytes(cred->uuid, sizeof(cred->uuid)); 128333965Sjdp 128433965Sjdp ret = krb5_ret_stringz(request, &cred->user); 128533965Sjdp if (ret) 128633965Sjdp goto error; 128733965Sjdp 128833965Sjdp ret = krb5_ret_stringz(request, &cred->domain); 128933965Sjdp if (ret) 129033965Sjdp goto error; 129133965Sjdp 129233965Sjdp ret = krb5_ret_data(request, &cred->nthash); 129333965Sjdp if (ret) 129433965Sjdp goto error; 129533965Sjdp 129699467Sobrien /* search for dups */ 129799467Sobrien c = find_ntlm_cred(cred->user, cred->domain, client); 129833965Sjdp if (c) { 129933965Sjdp krb5_data hash = c->nthash; 130033965Sjdp c->nthash = cred->nthash; 130133965Sjdp cred->nthash = hash; 130233965Sjdp free_cred(cred); 130333965Sjdp cred = c; 130433965Sjdp } else { 130533965Sjdp cred->next = ntlm_head; 130633965Sjdp ntlm_head = cred; 130733965Sjdp } 130833965Sjdp 130933965Sjdp cred->uid = client->uid; 131033965Sjdp cred->session = client->session; 131133965Sjdp 131233965Sjdp /* write response */ 131333965Sjdp (void)krb5_storage_write(response, &cred->uuid, sizeof(cred->uuid)); 131433965Sjdp 131533965Sjdp return 0; 131633965Sjdp 131733965Sjdp error: 131833965Sjdp free_cred(cred); 131933965Sjdp 132033965Sjdp return ret; 132133965Sjdp} 132233965Sjdp 132333965Sjdp/* 132433965Sjdp * { "HAVE_NTLM_CRED", NULL }, 132533965Sjdp * 132633965Sjdp * input: 132733965Sjdp * name 132833965Sjdp * domain 132933965Sjdp */ 133033965Sjdp 133133965Sjdpstatic krb5_error_code 133233965Sjdpkcm_op_have_ntlm_cred(krb5_context context, 133333965Sjdp kcm_client *client, 133433965Sjdp kcm_operation opcode, 133559431Sobrien krb5_storage *request, 133633965Sjdp krb5_storage *response) 133733965Sjdp{ 133833965Sjdp struct kcm_ntlm_cred *c; 133933965Sjdp char *user = NULL, *domain = NULL; 134033965Sjdp krb5_error_code ret; 134133965Sjdp 134233965Sjdp ret = krb5_ret_stringz(request, &user); 134333965Sjdp if (ret) 134460514Sobrien goto error; 134533965Sjdp 134660514Sobrien ret = krb5_ret_stringz(request, &domain); 134760514Sobrien if (ret) 134860514Sobrien goto error; 134933965Sjdp 135033965Sjdp if (domain[0] == '\0') { 135133965Sjdp free(domain); 135233965Sjdp domain = NULL; 135333965Sjdp } 135433965Sjdp 135533965Sjdp c = find_ntlm_cred(user, domain, client); 135633965Sjdp if (c == NULL) 135733965Sjdp ret = ENOENT; 135833965Sjdp 135933965Sjdp error: 136033965Sjdp free(user); 136133965Sjdp if (domain) 136233965Sjdp free(domain); 136333965Sjdp 136433965Sjdp return ret; 136533965Sjdp} 136633965Sjdp 136733965Sjdp/* 136833965Sjdp * { "DEL_NTLM_CRED", NULL }, 136933965Sjdp * 137033965Sjdp * input: 137160514Sobrien * name 137233965Sjdp * domain 137333965Sjdp */ 137433965Sjdp 137533965Sjdpstatic krb5_error_code 137633965Sjdpkcm_op_del_ntlm_cred(krb5_context context, 137760514Sobrien kcm_client *client, 137833965Sjdp kcm_operation opcode, 137933965Sjdp krb5_storage *request, 138033965Sjdp krb5_storage *response) 138133965Sjdp{ 138233965Sjdp struct kcm_ntlm_cred **cp, *c; 138333965Sjdp char *user = NULL, *domain = NULL; 138433965Sjdp krb5_error_code ret; 138560514Sobrien 138633965Sjdp ret = krb5_ret_stringz(request, &user); 138733965Sjdp if (ret) 138833965Sjdp goto error; 138933965Sjdp 139033965Sjdp ret = krb5_ret_stringz(request, &domain); 139133965Sjdp if (ret) 139233965Sjdp goto error; 139333965Sjdp 139433965Sjdp for (cp = &ntlm_head; *cp != NULL; cp = &(*cp)->next) { 139533965Sjdp if (strcmp(user, (*cp)->user) == 0 && strcmp(domain, (*cp)->domain) == 0 && 139633965Sjdp kcm_is_same_session(client, (*cp)->uid, (*cp)->session)) 139733965Sjdp { 139860514Sobrien c = *cp; 139933965Sjdp *cp = c->next; 140060514Sobrien 140160514Sobrien free_cred(c); 140260514Sobrien break; 140333965Sjdp } 140433965Sjdp } 140533965Sjdp 140633965Sjdp error: 140733965Sjdp free(user); 140833965Sjdp free(domain); 140933965Sjdp 141033965Sjdp return ret; 141133965Sjdp} 141233965Sjdp 141333965Sjdp/* 141433965Sjdp * { "DO_NTLM_AUTH", NULL }, 141533965Sjdp * 141633965Sjdp * input: 141733965Sjdp * name:string 141833965Sjdp * domain:string 141933965Sjdp * type2:data 142033965Sjdp * 142133965Sjdp * reply: 142233965Sjdp * type3:data 142333965Sjdp * flags:int32 142433965Sjdp * session-key:data 142533965Sjdp */ 142633965Sjdp 142733965Sjdp#define NTLM_FLAG_SESSIONKEY 1 142833965Sjdp#define NTLM_FLAG_NTLM2_SESSION 2 142933965Sjdp#define NTLM_FLAG_KEYEX 4 143033965Sjdp 143133965Sjdpstatic krb5_error_code 143233965Sjdpkcm_op_do_ntlm(krb5_context context, 143333965Sjdp kcm_client *client, 143433965Sjdp kcm_operation opcode, 143533965Sjdp krb5_storage *request, 143633965Sjdp krb5_storage *response) 143733965Sjdp{ 143833965Sjdp struct kcm_ntlm_cred *c; 143933965Sjdp struct ntlm_type2 type2; 144033965Sjdp struct ntlm_type3 type3; 144133965Sjdp char *user = NULL, *domain = NULL; 144233965Sjdp struct ntlm_buf ndata, sessionkey; 144333965Sjdp krb5_data data; 144433965Sjdp krb5_error_code ret; 144533965Sjdp uint32_t flags = 0; 144633965Sjdp 144733965Sjdp memset(&type2, 0, sizeof(type2)); 144833965Sjdp memset(&type3, 0, sizeof(type3)); 144933965Sjdp sessionkey.data = NULL; 145033965Sjdp sessionkey.length = 0; 145133965Sjdp 145233965Sjdp ret = krb5_ret_stringz(request, &user); 145333965Sjdp if (ret) 145433965Sjdp goto error; 145533965Sjdp 145633965Sjdp ret = krb5_ret_stringz(request, &domain); 145733965Sjdp if (ret) 145889864Sobrien goto error; 145991050Sobrien 146033965Sjdp if (domain[0] == '\0') { 146133965Sjdp free(domain); 146233965Sjdp domain = NULL; 146333965Sjdp } 146433965Sjdp 146533965Sjdp c = find_ntlm_cred(user, domain, client); 146633965Sjdp if (c == NULL) { 146789864Sobrien ret = EINVAL; 146833965Sjdp goto error; 146933965Sjdp } 147033965Sjdp 147133965Sjdp ret = krb5_ret_data(request, &data); 147233965Sjdp if (ret) 147333965Sjdp goto error; 147433965Sjdp 147533965Sjdp ndata.data = data.data; 147633965Sjdp ndata.length = data.length; 147733965Sjdp 147833965Sjdp ret = heim_ntlm_decode_type2(&ndata, &type2); 147933965Sjdp krb5_data_free(&data); 148033965Sjdp if (ret) 148133965Sjdp goto error; 148233965Sjdp 148333965Sjdp if (domain && strcmp(domain, type2.targetname) == 0) { 148433965Sjdp ret = EINVAL; 148533965Sjdp goto error; 148633965Sjdp } 148733965Sjdp 148833965Sjdp type3.username = c->user; 148933965Sjdp type3.flags = type2.flags; 149033965Sjdp type3.targetname = type2.targetname; 149133965Sjdp type3.ws = rk_UNCONST("workstation"); 149233965Sjdp 149333965Sjdp /* 149460514Sobrien * NTLM Version 1 if no targetinfo buffer. 149533965Sjdp */ 149689864Sobrien 149789864Sobrien if (1 || type2.targetinfo.length == 0) { 149878836Sobrien struct ntlm_buf sessionkey; 149933965Sjdp 150033965Sjdp if (type2.flags & NTLM_NEG_NTLM2_SESSION) { 150189864Sobrien unsigned char nonce[8]; 150233965Sjdp 150333965Sjdp if (RAND_bytes(nonce, sizeof(nonce)) != 1) { 150433965Sjdp ret = EINVAL; 150533965Sjdp goto error; 150633965Sjdp } 150733965Sjdp 150833965Sjdp ret = heim_ntlm_calculate_ntlm2_sess(nonce, 150933965Sjdp type2.challenge, 151033965Sjdp c->nthash.data, 151133965Sjdp &type3.lm, 151233965Sjdp &type3.ntlm); 151333965Sjdp } else { 151433965Sjdp ret = heim_ntlm_calculate_ntlm1(c->nthash.data, 151533965Sjdp c->nthash.length, 151633965Sjdp type2.challenge, 151733965Sjdp &type3.ntlm); 151833965Sjdp 151933965Sjdp } 152033965Sjdp if (ret) 152160514Sobrien goto error; 152233965Sjdp 152333965Sjdp ret = heim_ntlm_build_ntlm1_master(c->nthash.data, 152489864Sobrien c->nthash.length, 152533965Sjdp &sessionkey, 152633965Sjdp &type3.sessionkey); 152733965Sjdp if (ret) { 152833965Sjdp if (type3.lm.data) 152933965Sjdp free(type3.lm.data); 153033965Sjdp if (type3.ntlm.data) 153133965Sjdp free(type3.ntlm.data); 153233965Sjdp goto error; 153333965Sjdp } 153433965Sjdp 153533965Sjdp free(sessionkey.data); 153633965Sjdp if (ret) { 153733965Sjdp if (type3.lm.data) 153833965Sjdp free(type3.lm.data); 153933965Sjdp if (type3.ntlm.data) 154033965Sjdp free(type3.ntlm.data); 154133965Sjdp goto error; 154233965Sjdp } 154333965Sjdp flags |= NTLM_FLAG_SESSIONKEY; 154460514Sobrien#if 0 154533965Sjdp } else { 154633965Sjdp struct ntlm_buf sessionkey; 154789864Sobrien unsigned char ntlmv2[16]; 154833965Sjdp struct ntlm_targetinfo ti; 154933965Sjdp 155033965Sjdp /* verify infotarget */ 155133965Sjdp 155233965Sjdp ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti); 155333965Sjdp if(ret) { 155433965Sjdp _gss_ntlm_delete_sec_context(minor_status, 155533965Sjdp context_handle, NULL); 155633965Sjdp *minor_status = ret; 155733965Sjdp return GSS_S_FAILURE; 155833965Sjdp } 155933965Sjdp 156033965Sjdp if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) { 156133965Sjdp _gss_ntlm_delete_sec_context(minor_status, 156233965Sjdp context_handle, NULL); 156333965Sjdp *minor_status = EINVAL; 156433965Sjdp return GSS_S_FAILURE; 156533965Sjdp } 156633965Sjdp 156733965Sjdp ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data, 156860514Sobrien ctx->client->key.length, 156933965Sjdp type3.username, 157033965Sjdp name->domain, 157133965Sjdp type2.challenge, 157233965Sjdp &type2.targetinfo, 157333965Sjdp ntlmv2, 157433965Sjdp &type3.ntlm); 157533965Sjdp if (ret) { 157633965Sjdp _gss_ntlm_delete_sec_context(minor_status, 157733965Sjdp context_handle, NULL); 157833965Sjdp *minor_status = ret; 157933965Sjdp return GSS_S_FAILURE; 158033965Sjdp } 158133965Sjdp 158233965Sjdp ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2), 158333965Sjdp &sessionkey, 158433965Sjdp &type3.sessionkey); 158533965Sjdp memset(ntlmv2, 0, sizeof(ntlmv2)); 158633965Sjdp if (ret) { 158733965Sjdp _gss_ntlm_delete_sec_context(minor_status, 158833965Sjdp context_handle, NULL); 158933965Sjdp *minor_status = ret; 159033965Sjdp return GSS_S_FAILURE; 159133965Sjdp } 159233965Sjdp 159333965Sjdp flags |= NTLM_FLAG_NTLM2_SESSION | 159433965Sjdp NTLM_FLAG_SESSION; 159533965Sjdp 159633965Sjdp if (type3.flags & NTLM_NEG_KEYEX) 159733965Sjdp flags |= NTLM_FLAG_KEYEX; 159833965Sjdp 159933965Sjdp ret = krb5_data_copy(&ctx->sessionkey, 160033965Sjdp sessionkey.data, sessionkey.length); 160133965Sjdp free(sessionkey.data); 160233965Sjdp if (ret) { 160333965Sjdp _gss_ntlm_delete_sec_context(minor_status, 160433965Sjdp context_handle, NULL); 160533965Sjdp *minor_status = ret; 160633965Sjdp return GSS_S_FAILURE; 160733965Sjdp } 160833965Sjdp#endif 160933965Sjdp } 161033965Sjdp 161133965Sjdp#if 0 161233965Sjdp if (flags & NTLM_FLAG_NTLM2_SESSION) { 161333965Sjdp _gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX), 161433965Sjdp ctx->sessionkey.data, 161533965Sjdp ctx->sessionkey.length); 161633965Sjdp _gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX), 161733965Sjdp ctx->sessionkey.data, 161833965Sjdp ctx->sessionkey.length); 1619 } else { 1620 flags |= NTLM_FLAG_SESSION; 1621 RC4_set_key(&ctx->u.v1.crypto_recv.key, 1622 ctx->sessionkey.length, 1623 ctx->sessionkey.data); 1624 RC4_set_key(&ctx->u.v1.crypto_send.key, 1625 ctx->sessionkey.length, 1626 ctx->sessionkey.data); 1627 } 1628#endif 1629 1630 ret = heim_ntlm_encode_type3(&type3, &ndata); 1631 if (ret) 1632 goto error; 1633 1634 data.data = ndata.data; 1635 data.length = ndata.length; 1636 ret = krb5_store_data(response, data); 1637 heim_ntlm_free_buf(&ndata); 1638 if (ret) goto error; 1639 1640 ret = krb5_store_int32(response, flags); 1641 if (ret) goto error; 1642 1643 data.data = sessionkey.data; 1644 data.length = sessionkey.length; 1645 1646 ret = krb5_store_data(response, data); 1647 if (ret) goto error; 1648 1649 error: 1650 free(type3.username); 1651 heim_ntlm_free_type2(&type2); 1652 free(user); 1653 if (domain) 1654 free(domain); 1655 1656 return ret; 1657} 1658 1659 1660/* 1661 * { "GET_NTLM_UUID_LIST", NULL } 1662 * 1663 * reply: 1664 * 1 user domain 1665 * 0 [ end of list ] 1666 */ 1667 1668static krb5_error_code 1669kcm_op_get_ntlm_user_list(krb5_context context, 1670 kcm_client *client, 1671 kcm_operation opcode, 1672 krb5_storage *request, 1673 krb5_storage *response) 1674{ 1675 struct kcm_ntlm_cred *c; 1676 krb5_error_code ret; 1677 1678 for (c = ntlm_head; c != NULL; c = c->next) { 1679 if (!kcm_is_same_session(client, c->uid, c->session)) 1680 continue; 1681 1682 ret = krb5_store_uint32(response, 1); 1683 if (ret) 1684 return ret; 1685 ret = krb5_store_stringz(response, c->user); 1686 if (ret) 1687 return ret; 1688 ret = krb5_store_stringz(response, c->domain); 1689 if (ret) 1690 return ret; 1691 } 1692 return krb5_store_uint32(response, 0); 1693} 1694 1695/* 1696 * 1697 */ 1698 1699static struct kcm_op kcm_ops[] = { 1700 { "NOOP", kcm_op_noop }, 1701 { "GET_NAME", kcm_op_get_name }, 1702 { "RESOLVE", kcm_op_noop }, 1703 { "GEN_NEW", kcm_op_gen_new }, 1704 { "INITIALIZE", kcm_op_initialize }, 1705 { "DESTROY", kcm_op_destroy }, 1706 { "STORE", kcm_op_store }, 1707 { "RETRIEVE", kcm_op_retrieve }, 1708 { "GET_PRINCIPAL", kcm_op_get_principal }, 1709 { "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list }, 1710 { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid }, 1711 { "REMOVE_CRED", kcm_op_remove_cred }, 1712 { "SET_FLAGS", kcm_op_set_flags }, 1713 { "CHOWN", kcm_op_chown }, 1714 { "CHMOD", kcm_op_chmod }, 1715 { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket }, 1716 { "GET_TICKET", kcm_op_get_ticket }, 1717 { "MOVE_CACHE", kcm_op_move_cache }, 1718 { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list }, 1719 { "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid }, 1720 { "GET_DEFAULT_CACHE", kcm_op_get_default_cache }, 1721 { "SET_DEFAULT_CACHE", kcm_op_set_default_cache }, 1722 { "GET_KDC_OFFSET", kcm_op_get_kdc_offset }, 1723 { "SET_KDC_OFFSET", kcm_op_set_kdc_offset }, 1724 { "ADD_NTLM_CRED", kcm_op_add_ntlm_cred }, 1725 { "HAVE_USER_CRED", kcm_op_have_ntlm_cred }, 1726 { "DEL_NTLM_CRED", kcm_op_del_ntlm_cred }, 1727 { "DO_NTLM_AUTH", kcm_op_do_ntlm }, 1728 { "GET_NTLM_USER_LIST", kcm_op_get_ntlm_user_list } 1729}; 1730 1731 1732const char * 1733kcm_op2string(kcm_operation opcode) 1734{ 1735 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) 1736 return "Unknown operation"; 1737 1738 return kcm_ops[opcode].name; 1739} 1740 1741krb5_error_code 1742kcm_dispatch(krb5_context context, 1743 kcm_client *client, 1744 krb5_data *req_data, 1745 krb5_data *resp_data) 1746{ 1747 krb5_error_code ret; 1748 kcm_method method; 1749 krb5_storage *req_sp = NULL; 1750 krb5_storage *resp_sp = NULL; 1751 uint16_t opcode; 1752 1753 resp_sp = krb5_storage_emem(); 1754 if (resp_sp == NULL) { 1755 return ENOMEM; 1756 } 1757 1758 if (client->pid == -1) { 1759 kcm_log(0, "Client had invalid process number"); 1760 ret = KRB5_FCC_INTERNAL; 1761 goto out; 1762 } 1763 1764 req_sp = krb5_storage_from_data(req_data); 1765 if (req_sp == NULL) { 1766 kcm_log(0, "Process %d: failed to initialize storage from data", 1767 client->pid); 1768 ret = KRB5_CC_IO; 1769 goto out; 1770 } 1771 1772 ret = krb5_ret_uint16(req_sp, &opcode); 1773 if (ret) { 1774 kcm_log(0, "Process %d: didn't send a message", client->pid); 1775 goto out; 1776 } 1777 1778 if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) { 1779 kcm_log(0, "Process %d: invalid operation code %d", 1780 client->pid, opcode); 1781 ret = KRB5_FCC_INTERNAL; 1782 goto out; 1783 } 1784 method = kcm_ops[opcode].method; 1785 if (method == NULL) { 1786 kcm_log(0, "Process %d: operation code %s not implemented", 1787 client->pid, kcm_op2string(opcode)); 1788 ret = KRB5_FCC_INTERNAL; 1789 goto out; 1790 } 1791 1792 /* seek past place for status code */ 1793 krb5_storage_seek(resp_sp, 4, SEEK_SET); 1794 1795 ret = (*method)(context, client, opcode, req_sp, resp_sp); 1796 1797out: 1798 if (req_sp != NULL) { 1799 krb5_storage_free(req_sp); 1800 } 1801 1802 krb5_storage_seek(resp_sp, 0, SEEK_SET); 1803 krb5_store_int32(resp_sp, ret); 1804 1805 ret = krb5_storage_to_data(resp_sp, resp_data); 1806 krb5_storage_free(resp_sp); 1807 1808 return ret; 1809} 1810 1811