1178825Sdfr/* 2178825Sdfr * Copyright (c) 2005, PADL Software Pty Ltd. 3178825Sdfr * All rights reserved. 4178825Sdfr * 5233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 6233294Sstas * 7178825Sdfr * Redistribution and use in source and binary forms, with or without 8178825Sdfr * modification, are permitted provided that the following conditions 9178825Sdfr * are met: 10178825Sdfr * 11178825Sdfr * 1. Redistributions of source code must retain the above copyright 12178825Sdfr * notice, this list of conditions and the following disclaimer. 13178825Sdfr * 14178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 15178825Sdfr * notice, this list of conditions and the following disclaimer in the 16178825Sdfr * documentation and/or other materials provided with the distribution. 17178825Sdfr * 18178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors 19178825Sdfr * may be used to endorse or promote products derived from this software 20178825Sdfr * without specific prior written permission. 21178825Sdfr * 22178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 23178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 26178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32178825Sdfr * SUCH DAMAGE. 33178825Sdfr */ 34178825Sdfr 35178825Sdfr#include "kcm_locl.h" 36233294Sstas#include <heimntlm.h> 37178825Sdfr 38233294Sstasstatic void 39233294Sstaskcm_drop_default_cache(krb5_context context, kcm_client *client, char *name); 40178825Sdfr 41233294Sstas 42233294Sstasint 43233294Sstaskcm_is_same_session(kcm_client *client, uid_t uid, pid_t session) 44233294Sstas{ 45233294Sstas#if 0 /* XXX pppd is running in diffrent session the user */ 46233294Sstas if (session != -1) 47233294Sstas return (client->session == session); 48233294Sstas else 49233294Sstas#endif 50233294Sstas return (client->uid == uid); 51233294Sstas} 52233294Sstas 53178825Sdfrstatic krb5_error_code 54178825Sdfrkcm_op_noop(krb5_context context, 55178825Sdfr kcm_client *client, 56178825Sdfr kcm_operation opcode, 57178825Sdfr krb5_storage *request, 58178825Sdfr krb5_storage *response) 59178825Sdfr{ 60178825Sdfr KCM_LOG_REQUEST(context, client, opcode); 61178825Sdfr 62233294Sstas return 0; 63178825Sdfr} 64178825Sdfr 65178825Sdfr/* 66178825Sdfr * Request: 67178825Sdfr * NameZ 68178825Sdfr * Response: 69178825Sdfr * NameZ 70178825Sdfr * 71178825Sdfr */ 72178825Sdfrstatic krb5_error_code 73178825Sdfrkcm_op_get_name(krb5_context context, 74178825Sdfr kcm_client *client, 75178825Sdfr kcm_operation opcode, 76178825Sdfr krb5_storage *request, 77178825Sdfr krb5_storage *response) 78178825Sdfr 79178825Sdfr{ 80178825Sdfr krb5_error_code ret; 81178825Sdfr char *name = NULL; 82178825Sdfr kcm_ccache ccache; 83178825Sdfr 84178825Sdfr ret = krb5_ret_stringz(request, &name); 85178825Sdfr if (ret) 86178825Sdfr return ret; 87178825Sdfr 88178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 89178825Sdfr 90178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 91178825Sdfr name, &ccache); 92178825Sdfr if (ret) { 93178825Sdfr free(name); 94178825Sdfr return ret; 95178825Sdfr } 96178825Sdfr 97178825Sdfr ret = krb5_store_stringz(response, ccache->name); 98178825Sdfr if (ret) { 99233294Sstas kcm_release_ccache(context, ccache); 100178825Sdfr free(name); 101178825Sdfr return ret; 102178825Sdfr } 103178825Sdfr 104178825Sdfr free(name); 105233294Sstas kcm_release_ccache(context, ccache); 106178825Sdfr return 0; 107178825Sdfr} 108178825Sdfr 109178825Sdfr/* 110178825Sdfr * Request: 111233294Sstas * 112178825Sdfr * Response: 113178825Sdfr * NameZ 114178825Sdfr */ 115178825Sdfrstatic krb5_error_code 116178825Sdfrkcm_op_gen_new(krb5_context context, 117178825Sdfr kcm_client *client, 118178825Sdfr kcm_operation opcode, 119178825Sdfr krb5_storage *request, 120178825Sdfr krb5_storage *response) 121178825Sdfr{ 122178825Sdfr krb5_error_code ret; 123178825Sdfr char *name; 124178825Sdfr 125178825Sdfr KCM_LOG_REQUEST(context, client, opcode); 126178825Sdfr 127178825Sdfr name = kcm_ccache_nextid(client->pid, client->uid, client->gid); 128178825Sdfr if (name == NULL) { 129178825Sdfr return KRB5_CC_NOMEM; 130178825Sdfr } 131178825Sdfr 132178825Sdfr ret = krb5_store_stringz(response, name); 133178825Sdfr free(name); 134178825Sdfr 135178825Sdfr return ret; 136178825Sdfr} 137178825Sdfr 138178825Sdfr/* 139178825Sdfr * Request: 140178825Sdfr * NameZ 141178825Sdfr * Principal 142233294Sstas * 143178825Sdfr * Response: 144233294Sstas * 145178825Sdfr */ 146178825Sdfrstatic krb5_error_code 147178825Sdfrkcm_op_initialize(krb5_context context, 148178825Sdfr kcm_client *client, 149178825Sdfr kcm_operation opcode, 150178825Sdfr krb5_storage *request, 151178825Sdfr krb5_storage *response) 152178825Sdfr{ 153178825Sdfr kcm_ccache ccache; 154178825Sdfr krb5_principal principal; 155178825Sdfr krb5_error_code ret; 156178825Sdfr char *name; 157178825Sdfr#if 0 158178825Sdfr kcm_event event; 159178825Sdfr#endif 160178825Sdfr 161178825Sdfr KCM_LOG_REQUEST(context, client, opcode); 162178825Sdfr 163178825Sdfr ret = krb5_ret_stringz(request, &name); 164178825Sdfr if (ret) 165178825Sdfr return ret; 166178825Sdfr 167178825Sdfr ret = krb5_ret_principal(request, &principal); 168178825Sdfr if (ret) { 169178825Sdfr free(name); 170178825Sdfr return ret; 171178825Sdfr } 172178825Sdfr 173178825Sdfr ret = kcm_ccache_new_client(context, client, name, &ccache); 174178825Sdfr if (ret) { 175178825Sdfr free(name); 176178825Sdfr krb5_free_principal(context, principal); 177178825Sdfr return ret; 178178825Sdfr } 179178825Sdfr 180178825Sdfr ccache->client = principal; 181178825Sdfr 182178825Sdfr free(name); 183178825Sdfr 184178825Sdfr#if 0 185178825Sdfr /* 186178825Sdfr * Create a new credentials cache. To mitigate DoS attacks we will 187178825Sdfr * expire it in 30 minutes unless it has some credentials added 188178825Sdfr * to it 189178825Sdfr */ 190178825Sdfr 191178825Sdfr event.fire_time = 30 * 60; 192178825Sdfr event.expire_time = 0; 193178825Sdfr event.backoff_time = 0; 194178825Sdfr event.action = KCM_EVENT_DESTROY_EMPTY_CACHE; 195178825Sdfr event.ccache = ccache; 196178825Sdfr 197178825Sdfr ret = kcm_enqueue_event_relative(context, &event); 198178825Sdfr#endif 199178825Sdfr 200233294Sstas kcm_release_ccache(context, ccache); 201178825Sdfr 202178825Sdfr return ret; 203178825Sdfr} 204178825Sdfr 205178825Sdfr/* 206178825Sdfr * Request: 207178825Sdfr * NameZ 208233294Sstas * 209178825Sdfr * Response: 210233294Sstas * 211178825Sdfr */ 212178825Sdfrstatic krb5_error_code 213178825Sdfrkcm_op_destroy(krb5_context context, 214178825Sdfr kcm_client *client, 215178825Sdfr kcm_operation opcode, 216178825Sdfr krb5_storage *request, 217178825Sdfr krb5_storage *response) 218178825Sdfr{ 219178825Sdfr krb5_error_code ret; 220178825Sdfr char *name; 221178825Sdfr 222178825Sdfr ret = krb5_ret_stringz(request, &name); 223178825Sdfr if (ret) 224178825Sdfr return ret; 225178825Sdfr 226178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 227178825Sdfr 228178825Sdfr ret = kcm_ccache_destroy_client(context, client, name); 229233294Sstas if (ret == 0) 230233294Sstas kcm_drop_default_cache(context, client, name); 231178825Sdfr 232178825Sdfr free(name); 233178825Sdfr 234178825Sdfr return ret; 235178825Sdfr} 236178825Sdfr 237178825Sdfr/* 238178825Sdfr * Request: 239178825Sdfr * NameZ 240178825Sdfr * Creds 241233294Sstas * 242178825Sdfr * Response: 243233294Sstas * 244178825Sdfr */ 245178825Sdfrstatic krb5_error_code 246178825Sdfrkcm_op_store(krb5_context context, 247178825Sdfr kcm_client *client, 248178825Sdfr kcm_operation opcode, 249178825Sdfr krb5_storage *request, 250178825Sdfr krb5_storage *response) 251178825Sdfr{ 252178825Sdfr krb5_creds creds; 253178825Sdfr krb5_error_code ret; 254178825Sdfr kcm_ccache ccache; 255178825Sdfr char *name; 256178825Sdfr 257178825Sdfr ret = krb5_ret_stringz(request, &name); 258178825Sdfr if (ret) 259178825Sdfr return ret; 260178825Sdfr 261178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 262178825Sdfr 263178825Sdfr ret = krb5_ret_creds(request, &creds); 264178825Sdfr if (ret) { 265178825Sdfr free(name); 266178825Sdfr return ret; 267178825Sdfr } 268178825Sdfr 269178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 270178825Sdfr name, &ccache); 271178825Sdfr if (ret) { 272178825Sdfr free(name); 273178825Sdfr krb5_free_cred_contents(context, &creds); 274178825Sdfr return ret; 275178825Sdfr } 276178825Sdfr 277178825Sdfr ret = kcm_ccache_store_cred(context, ccache, &creds, 0); 278178825Sdfr if (ret) { 279178825Sdfr free(name); 280178825Sdfr krb5_free_cred_contents(context, &creds); 281233294Sstas kcm_release_ccache(context, ccache); 282178825Sdfr return ret; 283178825Sdfr } 284178825Sdfr 285178825Sdfr kcm_ccache_enqueue_default(context, ccache, &creds); 286178825Sdfr 287178825Sdfr free(name); 288233294Sstas kcm_release_ccache(context, ccache); 289178825Sdfr 290178825Sdfr return 0; 291178825Sdfr} 292178825Sdfr 293178825Sdfr/* 294178825Sdfr * Request: 295178825Sdfr * NameZ 296178825Sdfr * WhichFields 297178825Sdfr * MatchCreds 298178825Sdfr * 299178825Sdfr * Response: 300178825Sdfr * Creds 301233294Sstas * 302178825Sdfr */ 303178825Sdfrstatic krb5_error_code 304178825Sdfrkcm_op_retrieve(krb5_context context, 305178825Sdfr kcm_client *client, 306178825Sdfr kcm_operation opcode, 307178825Sdfr krb5_storage *request, 308178825Sdfr krb5_storage *response) 309178825Sdfr{ 310178825Sdfr uint32_t flags; 311178825Sdfr krb5_creds mcreds; 312178825Sdfr krb5_error_code ret; 313178825Sdfr kcm_ccache ccache; 314178825Sdfr char *name; 315178825Sdfr krb5_creds *credp; 316178825Sdfr int free_creds = 0; 317178825Sdfr 318178825Sdfr ret = krb5_ret_stringz(request, &name); 319178825Sdfr if (ret) 320178825Sdfr return ret; 321178825Sdfr 322178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 323178825Sdfr 324178825Sdfr ret = krb5_ret_uint32(request, &flags); 325178825Sdfr if (ret) { 326178825Sdfr free(name); 327178825Sdfr return ret; 328178825Sdfr } 329178825Sdfr 330178825Sdfr ret = krb5_ret_creds_tag(request, &mcreds); 331178825Sdfr if (ret) { 332178825Sdfr free(name); 333178825Sdfr return ret; 334178825Sdfr } 335178825Sdfr 336178825Sdfr if (disallow_getting_krbtgt && 337178825Sdfr mcreds.server->name.name_string.len == 2 && 338178825Sdfr strcmp(mcreds.server->name.name_string.val[0], KRB5_TGS_NAME) == 0) 339178825Sdfr { 340178825Sdfr free(name); 341178825Sdfr krb5_free_cred_contents(context, &mcreds); 342178825Sdfr return KRB5_FCC_PERM; 343178825Sdfr } 344178825Sdfr 345178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 346178825Sdfr name, &ccache); 347178825Sdfr if (ret) { 348178825Sdfr free(name); 349178825Sdfr krb5_free_cred_contents(context, &mcreds); 350178825Sdfr return ret; 351178825Sdfr } 352178825Sdfr 353178825Sdfr ret = kcm_ccache_retrieve_cred(context, ccache, flags, 354178825Sdfr &mcreds, &credp); 355233294Sstas if (ret && ((flags & KRB5_GC_CACHED) == 0) && 356233294Sstas !krb5_is_config_principal(context, mcreds.server)) { 357178825Sdfr krb5_ccache_data ccdata; 358178825Sdfr 359178825Sdfr /* try and acquire */ 360178825Sdfr HEIMDAL_MUTEX_lock(&ccache->mutex); 361178825Sdfr 362178825Sdfr /* Fake up an internal ccache */ 363178825Sdfr kcm_internal_ccache(context, ccache, &ccdata); 364178825Sdfr 365178825Sdfr /* glue cc layer will store creds */ 366178825Sdfr ret = krb5_get_credentials(context, 0, &ccdata, &mcreds, &credp); 367178825Sdfr if (ret == 0) 368178825Sdfr free_creds = 1; 369178825Sdfr 370178825Sdfr HEIMDAL_MUTEX_unlock(&ccache->mutex); 371178825Sdfr } 372178825Sdfr 373178825Sdfr if (ret == 0) { 374178825Sdfr ret = krb5_store_creds(response, credp); 375178825Sdfr } 376178825Sdfr 377178825Sdfr free(name); 378178825Sdfr krb5_free_cred_contents(context, &mcreds); 379233294Sstas kcm_release_ccache(context, ccache); 380178825Sdfr 381178825Sdfr if (free_creds) 382178825Sdfr krb5_free_cred_contents(context, credp); 383178825Sdfr 384178825Sdfr return ret; 385178825Sdfr} 386178825Sdfr 387178825Sdfr/* 388178825Sdfr * Request: 389178825Sdfr * NameZ 390178825Sdfr * 391178825Sdfr * Response: 392178825Sdfr * Principal 393178825Sdfr */ 394178825Sdfrstatic krb5_error_code 395178825Sdfrkcm_op_get_principal(krb5_context context, 396178825Sdfr kcm_client *client, 397178825Sdfr kcm_operation opcode, 398178825Sdfr krb5_storage *request, 399178825Sdfr krb5_storage *response) 400178825Sdfr{ 401178825Sdfr krb5_error_code ret; 402178825Sdfr kcm_ccache ccache; 403178825Sdfr char *name; 404178825Sdfr 405178825Sdfr ret = krb5_ret_stringz(request, &name); 406178825Sdfr if (ret) 407178825Sdfr return ret; 408178825Sdfr 409178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 410178825Sdfr 411178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 412178825Sdfr name, &ccache); 413178825Sdfr if (ret) { 414178825Sdfr free(name); 415178825Sdfr return ret; 416178825Sdfr } 417178825Sdfr 418178825Sdfr if (ccache->client == NULL) 419178825Sdfr ret = KRB5_CC_NOTFOUND; 420178825Sdfr else 421178825Sdfr ret = krb5_store_principal(response, ccache->client); 422178825Sdfr 423178825Sdfr free(name); 424233294Sstas kcm_release_ccache(context, ccache); 425178825Sdfr 426178825Sdfr return 0; 427178825Sdfr} 428178825Sdfr 429178825Sdfr/* 430178825Sdfr * Request: 431178825Sdfr * NameZ 432178825Sdfr * 433178825Sdfr * Response: 434233294Sstas * UUIDs 435233294Sstas * 436178825Sdfr */ 437178825Sdfrstatic krb5_error_code 438233294Sstaskcm_op_get_cred_uuid_list(krb5_context context, 439233294Sstas kcm_client *client, 440233294Sstas kcm_operation opcode, 441233294Sstas krb5_storage *request, 442233294Sstas krb5_storage *response) 443178825Sdfr{ 444233294Sstas struct kcm_creds *creds; 445178825Sdfr krb5_error_code ret; 446178825Sdfr kcm_ccache ccache; 447178825Sdfr char *name; 448178825Sdfr 449178825Sdfr ret = krb5_ret_stringz(request, &name); 450178825Sdfr if (ret) 451178825Sdfr return ret; 452178825Sdfr 453178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 454178825Sdfr 455178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 456178825Sdfr name, &ccache); 457233294Sstas free(name); 458233294Sstas if (ret) 459178825Sdfr return ret; 460178825Sdfr 461233294Sstas for (creds = ccache->creds ; creds ; creds = creds->next) { 462233294Sstas ssize_t sret; 463233294Sstas sret = krb5_storage_write(response, &creds->uuid, sizeof(creds->uuid)); 464233294Sstas if (sret != sizeof(creds->uuid)) { 465233294Sstas ret = ENOMEM; 466233294Sstas break; 467233294Sstas } 468178825Sdfr } 469178825Sdfr 470233294Sstas kcm_release_ccache(context, ccache); 471178825Sdfr 472178825Sdfr return ret; 473178825Sdfr} 474178825Sdfr 475178825Sdfr/* 476178825Sdfr * Request: 477178825Sdfr * NameZ 478178825Sdfr * Cursor 479178825Sdfr * 480178825Sdfr * Response: 481178825Sdfr * Creds 482178825Sdfr */ 483178825Sdfrstatic krb5_error_code 484233294Sstaskcm_op_get_cred_by_uuid(krb5_context context, 485233294Sstas kcm_client *client, 486233294Sstas kcm_operation opcode, 487233294Sstas krb5_storage *request, 488233294Sstas krb5_storage *response) 489178825Sdfr{ 490178825Sdfr krb5_error_code ret; 491178825Sdfr kcm_ccache ccache; 492178825Sdfr char *name; 493233294Sstas struct kcm_creds *c; 494233294Sstas kcmuuid_t uuid; 495233294Sstas ssize_t sret; 496178825Sdfr 497178825Sdfr ret = krb5_ret_stringz(request, &name); 498178825Sdfr if (ret) 499178825Sdfr return ret; 500178825Sdfr 501178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 502178825Sdfr 503178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 504178825Sdfr name, &ccache); 505178825Sdfr free(name); 506178825Sdfr if (ret) 507178825Sdfr return ret; 508178825Sdfr 509233294Sstas sret = krb5_storage_read(request, &uuid, sizeof(uuid)); 510233294Sstas if (sret != sizeof(uuid)) { 511233294Sstas kcm_release_ccache(context, ccache); 512233294Sstas krb5_clear_error_message(context); 513233294Sstas return KRB5_CC_IO; 514178825Sdfr } 515178825Sdfr 516233294Sstas c = kcm_ccache_find_cred_uuid(context, ccache, uuid); 517233294Sstas if (c == NULL) { 518233294Sstas kcm_release_ccache(context, ccache); 519233294Sstas return KRB5_CC_END; 520178825Sdfr } 521178825Sdfr 522233294Sstas HEIMDAL_MUTEX_lock(&ccache->mutex); 523233294Sstas ret = krb5_store_creds(response, &c->cred); 524233294Sstas HEIMDAL_MUTEX_unlock(&ccache->mutex); 525178825Sdfr 526233294Sstas kcm_release_ccache(context, ccache); 527178825Sdfr 528178825Sdfr return ret; 529178825Sdfr} 530178825Sdfr 531178825Sdfr/* 532178825Sdfr * Request: 533178825Sdfr * NameZ 534178825Sdfr * WhichFields 535178825Sdfr * MatchCreds 536178825Sdfr * 537178825Sdfr * Response: 538233294Sstas * 539178825Sdfr */ 540178825Sdfrstatic krb5_error_code 541178825Sdfrkcm_op_remove_cred(krb5_context context, 542178825Sdfr kcm_client *client, 543178825Sdfr kcm_operation opcode, 544178825Sdfr krb5_storage *request, 545178825Sdfr krb5_storage *response) 546178825Sdfr{ 547178825Sdfr uint32_t whichfields; 548178825Sdfr krb5_creds mcreds; 549178825Sdfr krb5_error_code ret; 550178825Sdfr kcm_ccache ccache; 551178825Sdfr char *name; 552178825Sdfr 553178825Sdfr ret = krb5_ret_stringz(request, &name); 554178825Sdfr if (ret) 555178825Sdfr return ret; 556178825Sdfr 557178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 558178825Sdfr 559178825Sdfr ret = krb5_ret_uint32(request, &whichfields); 560178825Sdfr if (ret) { 561178825Sdfr free(name); 562178825Sdfr return ret; 563178825Sdfr } 564178825Sdfr 565178825Sdfr ret = krb5_ret_creds_tag(request, &mcreds); 566178825Sdfr if (ret) { 567178825Sdfr free(name); 568178825Sdfr return ret; 569178825Sdfr } 570178825Sdfr 571178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 572178825Sdfr name, &ccache); 573178825Sdfr if (ret) { 574178825Sdfr free(name); 575178825Sdfr krb5_free_cred_contents(context, &mcreds); 576178825Sdfr return ret; 577178825Sdfr } 578178825Sdfr 579178825Sdfr ret = kcm_ccache_remove_cred(context, ccache, whichfields, &mcreds); 580178825Sdfr 581178825Sdfr /* XXX need to remove any events that match */ 582178825Sdfr 583178825Sdfr free(name); 584178825Sdfr krb5_free_cred_contents(context, &mcreds); 585233294Sstas kcm_release_ccache(context, ccache); 586178825Sdfr 587178825Sdfr return ret; 588178825Sdfr} 589178825Sdfr 590178825Sdfr/* 591178825Sdfr * Request: 592178825Sdfr * NameZ 593178825Sdfr * Flags 594178825Sdfr * 595178825Sdfr * Response: 596233294Sstas * 597178825Sdfr */ 598178825Sdfrstatic krb5_error_code 599178825Sdfrkcm_op_set_flags(krb5_context context, 600178825Sdfr kcm_client *client, 601178825Sdfr kcm_operation opcode, 602178825Sdfr krb5_storage *request, 603178825Sdfr krb5_storage *response) 604178825Sdfr{ 605178825Sdfr uint32_t flags; 606178825Sdfr krb5_error_code ret; 607178825Sdfr kcm_ccache ccache; 608178825Sdfr char *name; 609178825Sdfr 610178825Sdfr ret = krb5_ret_stringz(request, &name); 611178825Sdfr if (ret) 612178825Sdfr return ret; 613178825Sdfr 614178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 615178825Sdfr 616178825Sdfr ret = krb5_ret_uint32(request, &flags); 617178825Sdfr if (ret) { 618178825Sdfr free(name); 619178825Sdfr return ret; 620178825Sdfr } 621178825Sdfr 622178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 623178825Sdfr name, &ccache); 624178825Sdfr if (ret) { 625178825Sdfr free(name); 626178825Sdfr return ret; 627178825Sdfr } 628178825Sdfr 629178825Sdfr /* we don't really support any flags yet */ 630178825Sdfr free(name); 631233294Sstas kcm_release_ccache(context, ccache); 632178825Sdfr 633178825Sdfr return 0; 634178825Sdfr} 635178825Sdfr 636178825Sdfr/* 637178825Sdfr * Request: 638178825Sdfr * NameZ 639178825Sdfr * UID 640178825Sdfr * GID 641178825Sdfr * 642178825Sdfr * Response: 643233294Sstas * 644178825Sdfr */ 645178825Sdfrstatic krb5_error_code 646178825Sdfrkcm_op_chown(krb5_context context, 647178825Sdfr kcm_client *client, 648178825Sdfr kcm_operation opcode, 649178825Sdfr krb5_storage *request, 650178825Sdfr krb5_storage *response) 651178825Sdfr{ 652178825Sdfr uint32_t uid; 653178825Sdfr uint32_t gid; 654178825Sdfr krb5_error_code ret; 655178825Sdfr kcm_ccache ccache; 656178825Sdfr char *name; 657178825Sdfr 658178825Sdfr ret = krb5_ret_stringz(request, &name); 659178825Sdfr if (ret) 660178825Sdfr return ret; 661178825Sdfr 662178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 663178825Sdfr 664178825Sdfr ret = krb5_ret_uint32(request, &uid); 665178825Sdfr if (ret) { 666178825Sdfr free(name); 667178825Sdfr return ret; 668178825Sdfr } 669178825Sdfr 670178825Sdfr ret = krb5_ret_uint32(request, &gid); 671178825Sdfr if (ret) { 672178825Sdfr free(name); 673178825Sdfr return ret; 674178825Sdfr } 675178825Sdfr 676178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 677178825Sdfr name, &ccache); 678178825Sdfr if (ret) { 679178825Sdfr free(name); 680178825Sdfr return ret; 681178825Sdfr } 682178825Sdfr 683178825Sdfr ret = kcm_chown(context, client, ccache, uid, gid); 684178825Sdfr 685178825Sdfr free(name); 686233294Sstas kcm_release_ccache(context, ccache); 687178825Sdfr 688178825Sdfr return ret; 689178825Sdfr} 690178825Sdfr 691178825Sdfr/* 692178825Sdfr * Request: 693178825Sdfr * NameZ 694178825Sdfr * Mode 695178825Sdfr * 696178825Sdfr * Response: 697233294Sstas * 698178825Sdfr */ 699178825Sdfrstatic krb5_error_code 700178825Sdfrkcm_op_chmod(krb5_context context, 701178825Sdfr kcm_client *client, 702178825Sdfr kcm_operation opcode, 703178825Sdfr krb5_storage *request, 704178825Sdfr krb5_storage *response) 705178825Sdfr{ 706178825Sdfr uint16_t mode; 707178825Sdfr krb5_error_code ret; 708178825Sdfr kcm_ccache ccache; 709178825Sdfr char *name; 710178825Sdfr 711178825Sdfr ret = krb5_ret_stringz(request, &name); 712178825Sdfr if (ret) 713178825Sdfr return ret; 714178825Sdfr 715178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 716178825Sdfr 717178825Sdfr ret = krb5_ret_uint16(request, &mode); 718178825Sdfr if (ret) { 719178825Sdfr free(name); 720178825Sdfr return ret; 721178825Sdfr } 722178825Sdfr 723178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 724178825Sdfr name, &ccache); 725178825Sdfr if (ret) { 726178825Sdfr free(name); 727178825Sdfr return ret; 728178825Sdfr } 729178825Sdfr 730178825Sdfr ret = kcm_chmod(context, client, ccache, mode); 731178825Sdfr 732178825Sdfr free(name); 733233294Sstas kcm_release_ccache(context, ccache); 734178825Sdfr 735178825Sdfr return ret; 736178825Sdfr} 737178825Sdfr 738178825Sdfr/* 739178825Sdfr * Protocol extensions for moving ticket acquisition responsibility 740178825Sdfr * from client to KCM follow. 741178825Sdfr */ 742178825Sdfr 743178825Sdfr/* 744178825Sdfr * Request: 745178825Sdfr * NameZ 746178825Sdfr * ServerPrincipalPresent 747178825Sdfr * ServerPrincipal OPTIONAL 748178825Sdfr * Key 749178825Sdfr * 750178825Sdfr * Repsonse: 751178825Sdfr * 752178825Sdfr */ 753178825Sdfrstatic krb5_error_code 754178825Sdfrkcm_op_get_initial_ticket(krb5_context context, 755178825Sdfr kcm_client *client, 756178825Sdfr kcm_operation opcode, 757178825Sdfr krb5_storage *request, 758178825Sdfr krb5_storage *response) 759178825Sdfr{ 760178825Sdfr krb5_error_code ret; 761178825Sdfr kcm_ccache ccache; 762178825Sdfr char *name; 763178825Sdfr int8_t not_tgt = 0; 764178825Sdfr krb5_principal server = NULL; 765178825Sdfr krb5_keyblock key; 766178825Sdfr 767178825Sdfr krb5_keyblock_zero(&key); 768178825Sdfr 769178825Sdfr ret = krb5_ret_stringz(request, &name); 770178825Sdfr if (ret) 771178825Sdfr return ret; 772178825Sdfr 773178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 774178825Sdfr 775178825Sdfr ret = krb5_ret_int8(request, ¬_tgt); 776178825Sdfr if (ret) { 777178825Sdfr free(name); 778178825Sdfr return ret; 779178825Sdfr } 780178825Sdfr 781178825Sdfr if (not_tgt) { 782178825Sdfr ret = krb5_ret_principal(request, &server); 783178825Sdfr if (ret) { 784178825Sdfr free(name); 785178825Sdfr return ret; 786178825Sdfr } 787178825Sdfr } 788178825Sdfr 789178825Sdfr ret = krb5_ret_keyblock(request, &key); 790178825Sdfr if (ret) { 791178825Sdfr free(name); 792178825Sdfr if (server != NULL) 793178825Sdfr krb5_free_principal(context, server); 794178825Sdfr return ret; 795178825Sdfr } 796178825Sdfr 797178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 798178825Sdfr name, &ccache); 799178825Sdfr if (ret == 0) { 800178825Sdfr HEIMDAL_MUTEX_lock(&ccache->mutex); 801178825Sdfr 802178825Sdfr if (ccache->server != NULL) { 803178825Sdfr krb5_free_principal(context, ccache->server); 804178825Sdfr ccache->server = NULL; 805178825Sdfr } 806178825Sdfr 807178825Sdfr krb5_free_keyblock(context, &ccache->key.keyblock); 808178825Sdfr 809178825Sdfr ccache->server = server; 810178825Sdfr ccache->key.keyblock = key; 811178825Sdfr ccache->flags |= KCM_FLAGS_USE_CACHED_KEY; 812178825Sdfr 813178825Sdfr ret = kcm_ccache_enqueue_default(context, ccache, NULL); 814178825Sdfr if (ret) { 815178825Sdfr ccache->server = NULL; 816178825Sdfr krb5_keyblock_zero(&ccache->key.keyblock); 817178825Sdfr ccache->flags &= ~(KCM_FLAGS_USE_CACHED_KEY); 818178825Sdfr } 819178825Sdfr 820178825Sdfr HEIMDAL_MUTEX_unlock(&ccache->mutex); 821178825Sdfr } 822178825Sdfr 823178825Sdfr free(name); 824178825Sdfr 825178825Sdfr if (ret != 0) { 826178825Sdfr krb5_free_principal(context, server); 827178825Sdfr krb5_free_keyblock(context, &key); 828178825Sdfr } 829178825Sdfr 830233294Sstas kcm_release_ccache(context, ccache); 831178825Sdfr 832178825Sdfr return ret; 833178825Sdfr} 834178825Sdfr 835178825Sdfr/* 836178825Sdfr * Request: 837178825Sdfr * NameZ 838178825Sdfr * ServerPrincipal 839178825Sdfr * KDCFlags 840178825Sdfr * EncryptionType 841178825Sdfr * 842178825Sdfr * Repsonse: 843178825Sdfr * 844178825Sdfr */ 845178825Sdfrstatic krb5_error_code 846178825Sdfrkcm_op_get_ticket(krb5_context context, 847178825Sdfr kcm_client *client, 848178825Sdfr kcm_operation opcode, 849178825Sdfr krb5_storage *request, 850178825Sdfr krb5_storage *response) 851178825Sdfr{ 852178825Sdfr krb5_error_code ret; 853178825Sdfr kcm_ccache ccache; 854178825Sdfr char *name; 855178825Sdfr krb5_principal server = NULL; 856178825Sdfr krb5_ccache_data ccdata; 857178825Sdfr krb5_creds in, *out; 858178825Sdfr krb5_kdc_flags flags; 859178825Sdfr 860178825Sdfr memset(&in, 0, sizeof(in)); 861178825Sdfr 862178825Sdfr ret = krb5_ret_stringz(request, &name); 863178825Sdfr if (ret) 864178825Sdfr return ret; 865178825Sdfr 866178825Sdfr KCM_LOG_REQUEST_NAME(context, client, opcode, name); 867178825Sdfr 868178825Sdfr ret = krb5_ret_uint32(request, &flags.i); 869178825Sdfr if (ret) { 870178825Sdfr free(name); 871178825Sdfr return ret; 872178825Sdfr } 873178825Sdfr 874178825Sdfr ret = krb5_ret_int32(request, &in.session.keytype); 875178825Sdfr if (ret) { 876178825Sdfr free(name); 877178825Sdfr return ret; 878178825Sdfr } 879178825Sdfr 880178825Sdfr ret = krb5_ret_principal(request, &server); 881178825Sdfr if (ret) { 882178825Sdfr free(name); 883178825Sdfr return ret; 884178825Sdfr } 885178825Sdfr 886178825Sdfr ret = kcm_ccache_resolve_client(context, client, opcode, 887178825Sdfr name, &ccache); 888178825Sdfr if (ret) { 889178825Sdfr krb5_free_principal(context, server); 890178825Sdfr free(name); 891178825Sdfr return ret; 892178825Sdfr } 893233294Sstas 894178825Sdfr HEIMDAL_MUTEX_lock(&ccache->mutex); 895178825Sdfr 896178825Sdfr /* Fake up an internal ccache */ 897178825Sdfr kcm_internal_ccache(context, ccache, &ccdata); 898178825Sdfr 899178825Sdfr in.client = ccache->client; 900178825Sdfr in.server = server; 901178825Sdfr in.times.endtime = 0; 902178825Sdfr 903178825Sdfr /* glue cc layer will store creds */ 904178825Sdfr ret = krb5_get_credentials_with_flags(context, 0, flags, 905178825Sdfr &ccdata, &in, &out); 906178825Sdfr 907178825Sdfr HEIMDAL_MUTEX_unlock(&ccache->mutex); 908178825Sdfr 909233294Sstas krb5_free_principal(context, server); 910233294Sstas 911178825Sdfr if (ret == 0) 912178825Sdfr krb5_free_cred_contents(context, out); 913178825Sdfr 914233294Sstas kcm_release_ccache(context, ccache); 915178825Sdfr free(name); 916178825Sdfr 917178825Sdfr return ret; 918178825Sdfr} 919178825Sdfr 920233294Sstas/* 921233294Sstas * Request: 922233294Sstas * OldNameZ 923233294Sstas * NewNameZ 924233294Sstas * 925233294Sstas * Repsonse: 926233294Sstas * 927233294Sstas */ 928233294Sstasstatic krb5_error_code 929233294Sstaskcm_op_move_cache(krb5_context context, 930233294Sstas kcm_client *client, 931233294Sstas kcm_operation opcode, 932233294Sstas krb5_storage *request, 933233294Sstas krb5_storage *response) 934233294Sstas{ 935233294Sstas krb5_error_code ret; 936233294Sstas kcm_ccache oldid, newid; 937233294Sstas char *oldname, *newname; 938233294Sstas 939233294Sstas ret = krb5_ret_stringz(request, &oldname); 940233294Sstas if (ret) 941233294Sstas return ret; 942233294Sstas 943233294Sstas KCM_LOG_REQUEST_NAME(context, client, opcode, oldname); 944233294Sstas 945233294Sstas ret = krb5_ret_stringz(request, &newname); 946233294Sstas if (ret) { 947233294Sstas free(oldname); 948233294Sstas return ret; 949233294Sstas } 950233294Sstas 951233294Sstas /* move to ourself is simple, done! */ 952233294Sstas if (strcmp(oldname, newname) == 0) { 953233294Sstas free(oldname); 954233294Sstas free(newname); 955233294Sstas return 0; 956233294Sstas } 957233294Sstas 958233294Sstas ret = kcm_ccache_resolve_client(context, client, opcode, oldname, &oldid); 959233294Sstas if (ret) { 960233294Sstas free(oldname); 961233294Sstas free(newname); 962233294Sstas return ret; 963233294Sstas } 964233294Sstas 965233294Sstas /* Check if new credential cache exists, if not create one. */ 966233294Sstas ret = kcm_ccache_resolve_client(context, client, opcode, newname, &newid); 967233294Sstas if (ret == KRB5_FCC_NOFILE) 968233294Sstas ret = kcm_ccache_new_client(context, client, newname, &newid); 969233294Sstas free(newname); 970233294Sstas 971233294Sstas if (ret) { 972233294Sstas free(oldname); 973233294Sstas kcm_release_ccache(context, oldid); 974233294Sstas return ret; 975233294Sstas } 976233294Sstas 977233294Sstas HEIMDAL_MUTEX_lock(&oldid->mutex); 978233294Sstas HEIMDAL_MUTEX_lock(&newid->mutex); 979233294Sstas 980233294Sstas /* move content */ 981233294Sstas { 982233294Sstas kcm_ccache_data tmp; 983233294Sstas 984233294Sstas#define MOVE(n,o,f) { tmp.f = n->f ; n->f = o->f; o->f = tmp.f; } 985233294Sstas 986233294Sstas MOVE(newid, oldid, flags); 987233294Sstas MOVE(newid, oldid, client); 988233294Sstas MOVE(newid, oldid, server); 989233294Sstas MOVE(newid, oldid, creds); 990233294Sstas MOVE(newid, oldid, tkt_life); 991233294Sstas MOVE(newid, oldid, renew_life); 992233294Sstas MOVE(newid, oldid, key); 993233294Sstas MOVE(newid, oldid, kdc_offset); 994233294Sstas#undef MOVE 995233294Sstas } 996233294Sstas 997233294Sstas HEIMDAL_MUTEX_unlock(&oldid->mutex); 998233294Sstas HEIMDAL_MUTEX_unlock(&newid->mutex); 999233294Sstas 1000233294Sstas kcm_release_ccache(context, oldid); 1001233294Sstas kcm_release_ccache(context, newid); 1002233294Sstas 1003233294Sstas ret = kcm_ccache_destroy_client(context, client, oldname); 1004233294Sstas if (ret == 0) 1005233294Sstas kcm_drop_default_cache(context, client, oldname); 1006233294Sstas 1007233294Sstas free(oldname); 1008233294Sstas 1009233294Sstas return ret; 1010233294Sstas} 1011233294Sstas 1012233294Sstasstatic krb5_error_code 1013233294Sstaskcm_op_get_cache_uuid_list(krb5_context context, 1014233294Sstas kcm_client *client, 1015233294Sstas kcm_operation opcode, 1016233294Sstas krb5_storage *request, 1017233294Sstas krb5_storage *response) 1018233294Sstas{ 1019233294Sstas KCM_LOG_REQUEST(context, client, opcode); 1020233294Sstas 1021233294Sstas return kcm_ccache_get_uuids(context, client, opcode, response); 1022233294Sstas} 1023233294Sstas 1024233294Sstasstatic krb5_error_code 1025233294Sstaskcm_op_get_cache_by_uuid(krb5_context context, 1026233294Sstas kcm_client *client, 1027233294Sstas kcm_operation opcode, 1028233294Sstas krb5_storage *request, 1029233294Sstas krb5_storage *response) 1030233294Sstas{ 1031233294Sstas krb5_error_code ret; 1032233294Sstas kcmuuid_t uuid; 1033233294Sstas ssize_t sret; 1034233294Sstas kcm_ccache cache; 1035233294Sstas 1036233294Sstas KCM_LOG_REQUEST(context, client, opcode); 1037233294Sstas 1038233294Sstas sret = krb5_storage_read(request, &uuid, sizeof(uuid)); 1039233294Sstas if (sret != sizeof(uuid)) { 1040233294Sstas krb5_clear_error_message(context); 1041233294Sstas return KRB5_CC_IO; 1042233294Sstas } 1043233294Sstas 1044233294Sstas ret = kcm_ccache_resolve_by_uuid(context, uuid, &cache); 1045233294Sstas if (ret) 1046233294Sstas return ret; 1047233294Sstas 1048233294Sstas ret = kcm_access(context, client, opcode, cache); 1049233294Sstas if (ret) 1050233294Sstas ret = KRB5_FCC_NOFILE; 1051233294Sstas 1052233294Sstas if (ret == 0) 1053233294Sstas ret = krb5_store_stringz(response, cache->name); 1054233294Sstas 1055233294Sstas kcm_release_ccache(context, cache); 1056233294Sstas 1057233294Sstas return ret; 1058233294Sstas} 1059233294Sstas 1060233294Sstasstruct kcm_default_cache *default_caches; 1061233294Sstas 1062233294Sstasstatic krb5_error_code 1063233294Sstaskcm_op_get_default_cache(krb5_context context, 1064233294Sstas kcm_client *client, 1065233294Sstas kcm_operation opcode, 1066233294Sstas krb5_storage *request, 1067233294Sstas krb5_storage *response) 1068233294Sstas{ 1069233294Sstas struct kcm_default_cache *c; 1070233294Sstas krb5_error_code ret; 1071233294Sstas const char *name = NULL; 1072233294Sstas char *n = NULL; 1073233294Sstas 1074233294Sstas KCM_LOG_REQUEST(context, client, opcode); 1075233294Sstas 1076233294Sstas for (c = default_caches; c != NULL; c = c->next) { 1077233294Sstas if (kcm_is_same_session(client, c->uid, c->session)) { 1078233294Sstas name = c->name; 1079233294Sstas break; 1080233294Sstas } 1081233294Sstas } 1082233294Sstas if (name == NULL) 1083233294Sstas name = n = kcm_ccache_first_name(client); 1084233294Sstas 1085233294Sstas if (name == NULL) { 1086233294Sstas asprintf(&n, "%d", (int)client->uid); 1087233294Sstas name = n; 1088233294Sstas } 1089233294Sstas if (name == NULL) 1090233294Sstas return ENOMEM; 1091233294Sstas ret = krb5_store_stringz(response, name); 1092233294Sstas if (n) 1093233294Sstas free(n); 1094233294Sstas return ret; 1095233294Sstas} 1096233294Sstas 1097233294Sstasstatic void 1098233294Sstaskcm_drop_default_cache(krb5_context context, kcm_client *client, char *name) 1099233294Sstas{ 1100233294Sstas struct kcm_default_cache **c; 1101233294Sstas 1102233294Sstas for (c = &default_caches; *c != NULL; c = &(*c)->next) { 1103233294Sstas if (!kcm_is_same_session(client, (*c)->uid, (*c)->session)) 1104233294Sstas continue; 1105233294Sstas if (strcmp((*c)->name, name) == 0) { 1106233294Sstas struct kcm_default_cache *h = *c; 1107233294Sstas *c = (*c)->next; 1108233294Sstas free(h->name); 1109233294Sstas free(h); 1110233294Sstas break; 1111233294Sstas } 1112233294Sstas } 1113233294Sstas} 1114233294Sstas 1115233294Sstasstatic krb5_error_code 1116233294Sstaskcm_op_set_default_cache(krb5_context context, 1117233294Sstas kcm_client *client, 1118233294Sstas kcm_operation opcode, 1119233294Sstas krb5_storage *request, 1120233294Sstas krb5_storage *response) 1121233294Sstas{ 1122233294Sstas struct kcm_default_cache *c; 1123233294Sstas krb5_error_code ret; 1124233294Sstas char *name; 1125233294Sstas 1126233294Sstas ret = krb5_ret_stringz(request, &name); 1127233294Sstas if (ret) 1128233294Sstas return ret; 1129233294Sstas 1130233294Sstas KCM_LOG_REQUEST_NAME(context, client, opcode, name); 1131233294Sstas 1132233294Sstas for (c = default_caches; c != NULL; c = c->next) { 1133233294Sstas if (kcm_is_same_session(client, c->uid, c->session)) 1134233294Sstas break; 1135233294Sstas } 1136233294Sstas if (c == NULL) { 1137233294Sstas c = malloc(sizeof(*c)); 1138233294Sstas if (c == NULL) 1139233294Sstas return ENOMEM; 1140233294Sstas c->session = client->session; 1141233294Sstas c->uid = client->uid; 1142233294Sstas c->name = strdup(name); 1143233294Sstas 1144233294Sstas c->next = default_caches; 1145233294Sstas default_caches = c; 1146233294Sstas } else { 1147233294Sstas free(c->name); 1148233294Sstas c->name = strdup(name); 1149233294Sstas } 1150233294Sstas 1151233294Sstas return 0; 1152233294Sstas} 1153233294Sstas 1154233294Sstasstatic krb5_error_code 1155233294Sstaskcm_op_get_kdc_offset(krb5_context context, 1156233294Sstas kcm_client *client, 1157233294Sstas kcm_operation opcode, 1158233294Sstas krb5_storage *request, 1159233294Sstas krb5_storage *response) 1160233294Sstas{ 1161233294Sstas krb5_error_code ret; 1162233294Sstas kcm_ccache ccache; 1163233294Sstas char *name; 1164233294Sstas 1165233294Sstas ret = krb5_ret_stringz(request, &name); 1166233294Sstas if (ret) 1167233294Sstas return ret; 1168233294Sstas 1169233294Sstas KCM_LOG_REQUEST_NAME(context, client, opcode, name); 1170233294Sstas 1171233294Sstas ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); 1172233294Sstas free(name); 1173233294Sstas if (ret) 1174233294Sstas return ret; 1175233294Sstas 1176233294Sstas HEIMDAL_MUTEX_lock(&ccache->mutex); 1177233294Sstas ret = krb5_store_int32(response, ccache->kdc_offset); 1178233294Sstas HEIMDAL_MUTEX_unlock(&ccache->mutex); 1179233294Sstas 1180233294Sstas kcm_release_ccache(context, ccache); 1181233294Sstas 1182233294Sstas return ret; 1183233294Sstas} 1184233294Sstas 1185233294Sstasstatic krb5_error_code 1186233294Sstaskcm_op_set_kdc_offset(krb5_context context, 1187233294Sstas kcm_client *client, 1188233294Sstas kcm_operation opcode, 1189233294Sstas krb5_storage *request, 1190233294Sstas krb5_storage *response) 1191233294Sstas{ 1192233294Sstas krb5_error_code ret; 1193233294Sstas kcm_ccache ccache; 1194233294Sstas int32_t offset; 1195233294Sstas char *name; 1196233294Sstas 1197233294Sstas ret = krb5_ret_stringz(request, &name); 1198233294Sstas if (ret) 1199233294Sstas return ret; 1200233294Sstas 1201233294Sstas KCM_LOG_REQUEST_NAME(context, client, opcode, name); 1202233294Sstas 1203233294Sstas ret = krb5_ret_int32(request, &offset); 1204233294Sstas if (ret) { 1205233294Sstas free(name); 1206233294Sstas return ret; 1207233294Sstas } 1208233294Sstas 1209233294Sstas ret = kcm_ccache_resolve_client(context, client, opcode, name, &ccache); 1210233294Sstas free(name); 1211233294Sstas if (ret) 1212233294Sstas return ret; 1213233294Sstas 1214233294Sstas HEIMDAL_MUTEX_lock(&ccache->mutex); 1215233294Sstas ccache->kdc_offset = offset; 1216233294Sstas HEIMDAL_MUTEX_unlock(&ccache->mutex); 1217233294Sstas 1218233294Sstas kcm_release_ccache(context, ccache); 1219233294Sstas 1220233294Sstas return ret; 1221233294Sstas} 1222233294Sstas 1223233294Sstasstruct kcm_ntlm_cred { 1224233294Sstas kcmuuid_t uuid; 1225233294Sstas char *user; 1226233294Sstas char *domain; 1227233294Sstas krb5_data nthash; 1228233294Sstas uid_t uid; 1229233294Sstas pid_t session; 1230233294Sstas struct kcm_ntlm_cred *next; 1231233294Sstas}; 1232233294Sstas 1233233294Sstasstatic struct kcm_ntlm_cred *ntlm_head; 1234233294Sstas 1235233294Sstasstatic void 1236233294Sstasfree_cred(struct kcm_ntlm_cred *cred) 1237233294Sstas{ 1238233294Sstas free(cred->user); 1239233294Sstas free(cred->domain); 1240233294Sstas krb5_data_free(&cred->nthash); 1241233294Sstas free(cred); 1242233294Sstas} 1243233294Sstas 1244233294Sstas 1245233294Sstas/* 1246233294Sstas * name 1247233294Sstas * domain 1248233294Sstas * ntlm hash 1249233294Sstas * 1250233294Sstas * Reply: 1251233294Sstas * uuid 1252233294Sstas */ 1253233294Sstas 1254233294Sstasstatic struct kcm_ntlm_cred * 1255233294Sstasfind_ntlm_cred(const char *user, const char *domain, kcm_client *client) 1256233294Sstas{ 1257233294Sstas struct kcm_ntlm_cred *c; 1258233294Sstas 1259233294Sstas for (c = ntlm_head; c != NULL; c = c->next) 1260233294Sstas if ((user[0] == '\0' || strcmp(user, c->user) == 0) && 1261233294Sstas (domain == NULL || strcmp(domain, c->domain) == 0) && 1262233294Sstas kcm_is_same_session(client, c->uid, c->session)) 1263233294Sstas return c; 1264233294Sstas 1265233294Sstas return NULL; 1266233294Sstas} 1267233294Sstas 1268233294Sstasstatic krb5_error_code 1269233294Sstaskcm_op_add_ntlm_cred(krb5_context context, 1270233294Sstas kcm_client *client, 1271233294Sstas kcm_operation opcode, 1272233294Sstas krb5_storage *request, 1273233294Sstas krb5_storage *response) 1274233294Sstas{ 1275233294Sstas struct kcm_ntlm_cred *cred, *c; 1276233294Sstas krb5_error_code ret; 1277233294Sstas 1278233294Sstas cred = calloc(1, sizeof(*cred)); 1279233294Sstas if (cred == NULL) 1280233294Sstas return ENOMEM; 1281233294Sstas 1282233294Sstas RAND_bytes(cred->uuid, sizeof(cred->uuid)); 1283233294Sstas 1284233294Sstas ret = krb5_ret_stringz(request, &cred->user); 1285233294Sstas if (ret) 1286233294Sstas goto error; 1287233294Sstas 1288233294Sstas ret = krb5_ret_stringz(request, &cred->domain); 1289233294Sstas if (ret) 1290233294Sstas goto error; 1291233294Sstas 1292233294Sstas ret = krb5_ret_data(request, &cred->nthash); 1293233294Sstas if (ret) 1294233294Sstas goto error; 1295233294Sstas 1296233294Sstas /* search for dups */ 1297233294Sstas c = find_ntlm_cred(cred->user, cred->domain, client); 1298233294Sstas if (c) { 1299233294Sstas krb5_data hash = c->nthash; 1300233294Sstas c->nthash = cred->nthash; 1301233294Sstas cred->nthash = hash; 1302233294Sstas free_cred(cred); 1303233294Sstas cred = c; 1304233294Sstas } else { 1305233294Sstas cred->next = ntlm_head; 1306233294Sstas ntlm_head = cred; 1307233294Sstas } 1308233294Sstas 1309233294Sstas cred->uid = client->uid; 1310233294Sstas cred->session = client->session; 1311233294Sstas 1312233294Sstas /* write response */ 1313233294Sstas (void)krb5_storage_write(response, &cred->uuid, sizeof(cred->uuid)); 1314233294Sstas 1315233294Sstas return 0; 1316233294Sstas 1317233294Sstas error: 1318233294Sstas free_cred(cred); 1319233294Sstas 1320233294Sstas return ret; 1321233294Sstas} 1322233294Sstas 1323233294Sstas/* 1324233294Sstas * { "HAVE_NTLM_CRED", NULL }, 1325233294Sstas * 1326233294Sstas * input: 1327233294Sstas * name 1328233294Sstas * domain 1329233294Sstas */ 1330233294Sstas 1331233294Sstasstatic krb5_error_code 1332233294Sstaskcm_op_have_ntlm_cred(krb5_context context, 1333233294Sstas kcm_client *client, 1334233294Sstas kcm_operation opcode, 1335233294Sstas krb5_storage *request, 1336233294Sstas krb5_storage *response) 1337233294Sstas{ 1338233294Sstas struct kcm_ntlm_cred *c; 1339233294Sstas char *user = NULL, *domain = NULL; 1340233294Sstas krb5_error_code ret; 1341233294Sstas 1342233294Sstas ret = krb5_ret_stringz(request, &user); 1343233294Sstas if (ret) 1344233294Sstas goto error; 1345233294Sstas 1346233294Sstas ret = krb5_ret_stringz(request, &domain); 1347233294Sstas if (ret) 1348233294Sstas goto error; 1349233294Sstas 1350233294Sstas if (domain[0] == '\0') { 1351233294Sstas free(domain); 1352233294Sstas domain = NULL; 1353233294Sstas } 1354233294Sstas 1355233294Sstas c = find_ntlm_cred(user, domain, client); 1356233294Sstas if (c == NULL) 1357233294Sstas ret = ENOENT; 1358233294Sstas 1359233294Sstas error: 1360233294Sstas free(user); 1361233294Sstas if (domain) 1362233294Sstas free(domain); 1363233294Sstas 1364233294Sstas return ret; 1365233294Sstas} 1366233294Sstas 1367233294Sstas/* 1368233294Sstas * { "DEL_NTLM_CRED", NULL }, 1369233294Sstas * 1370233294Sstas * input: 1371233294Sstas * name 1372233294Sstas * domain 1373233294Sstas */ 1374233294Sstas 1375233294Sstasstatic krb5_error_code 1376233294Sstaskcm_op_del_ntlm_cred(krb5_context context, 1377233294Sstas kcm_client *client, 1378233294Sstas kcm_operation opcode, 1379233294Sstas krb5_storage *request, 1380233294Sstas krb5_storage *response) 1381233294Sstas{ 1382233294Sstas struct kcm_ntlm_cred **cp, *c; 1383233294Sstas char *user = NULL, *domain = NULL; 1384233294Sstas krb5_error_code ret; 1385233294Sstas 1386233294Sstas ret = krb5_ret_stringz(request, &user); 1387233294Sstas if (ret) 1388233294Sstas goto error; 1389233294Sstas 1390233294Sstas ret = krb5_ret_stringz(request, &domain); 1391233294Sstas if (ret) 1392233294Sstas goto error; 1393233294Sstas 1394233294Sstas for (cp = &ntlm_head; *cp != NULL; cp = &(*cp)->next) { 1395233294Sstas if (strcmp(user, (*cp)->user) == 0 && strcmp(domain, (*cp)->domain) == 0 && 1396233294Sstas kcm_is_same_session(client, (*cp)->uid, (*cp)->session)) 1397233294Sstas { 1398233294Sstas c = *cp; 1399233294Sstas *cp = c->next; 1400233294Sstas 1401233294Sstas free_cred(c); 1402233294Sstas break; 1403233294Sstas } 1404233294Sstas } 1405233294Sstas 1406233294Sstas error: 1407233294Sstas free(user); 1408233294Sstas free(domain); 1409233294Sstas 1410233294Sstas return ret; 1411233294Sstas} 1412233294Sstas 1413233294Sstas/* 1414233294Sstas * { "DO_NTLM_AUTH", NULL }, 1415233294Sstas * 1416233294Sstas * input: 1417233294Sstas * name:string 1418233294Sstas * domain:string 1419233294Sstas * type2:data 1420233294Sstas * 1421233294Sstas * reply: 1422233294Sstas * type3:data 1423233294Sstas * flags:int32 1424233294Sstas * session-key:data 1425233294Sstas */ 1426233294Sstas 1427233294Sstas#define NTLM_FLAG_SESSIONKEY 1 1428233294Sstas#define NTLM_FLAG_NTLM2_SESSION 2 1429233294Sstas#define NTLM_FLAG_KEYEX 4 1430233294Sstas 1431233294Sstasstatic krb5_error_code 1432233294Sstaskcm_op_do_ntlm(krb5_context context, 1433233294Sstas kcm_client *client, 1434233294Sstas kcm_operation opcode, 1435233294Sstas krb5_storage *request, 1436233294Sstas krb5_storage *response) 1437233294Sstas{ 1438233294Sstas struct kcm_ntlm_cred *c; 1439233294Sstas struct ntlm_type2 type2; 1440233294Sstas struct ntlm_type3 type3; 1441233294Sstas char *user = NULL, *domain = NULL; 1442233294Sstas struct ntlm_buf ndata, sessionkey; 1443233294Sstas krb5_data data; 1444233294Sstas krb5_error_code ret; 1445233294Sstas uint32_t flags = 0; 1446233294Sstas 1447233294Sstas memset(&type2, 0, sizeof(type2)); 1448233294Sstas memset(&type3, 0, sizeof(type3)); 1449233294Sstas sessionkey.data = NULL; 1450233294Sstas sessionkey.length = 0; 1451233294Sstas 1452233294Sstas ret = krb5_ret_stringz(request, &user); 1453233294Sstas if (ret) 1454233294Sstas goto error; 1455233294Sstas 1456233294Sstas ret = krb5_ret_stringz(request, &domain); 1457233294Sstas if (ret) 1458233294Sstas goto error; 1459233294Sstas 1460233294Sstas if (domain[0] == '\0') { 1461233294Sstas free(domain); 1462233294Sstas domain = NULL; 1463233294Sstas } 1464233294Sstas 1465233294Sstas c = find_ntlm_cred(user, domain, client); 1466233294Sstas if (c == NULL) { 1467233294Sstas ret = EINVAL; 1468233294Sstas goto error; 1469233294Sstas } 1470233294Sstas 1471233294Sstas ret = krb5_ret_data(request, &data); 1472233294Sstas if (ret) 1473233294Sstas goto error; 1474233294Sstas 1475233294Sstas ndata.data = data.data; 1476233294Sstas ndata.length = data.length; 1477233294Sstas 1478233294Sstas ret = heim_ntlm_decode_type2(&ndata, &type2); 1479233294Sstas krb5_data_free(&data); 1480233294Sstas if (ret) 1481233294Sstas goto error; 1482233294Sstas 1483233294Sstas if (domain && strcmp(domain, type2.targetname) == 0) { 1484233294Sstas ret = EINVAL; 1485233294Sstas goto error; 1486233294Sstas } 1487233294Sstas 1488233294Sstas type3.username = c->user; 1489233294Sstas type3.flags = type2.flags; 1490233294Sstas type3.targetname = type2.targetname; 1491233294Sstas type3.ws = rk_UNCONST("workstation"); 1492233294Sstas 1493233294Sstas /* 1494233294Sstas * NTLM Version 1 if no targetinfo buffer. 1495233294Sstas */ 1496233294Sstas 1497233294Sstas if (1 || type2.targetinfo.length == 0) { 1498233294Sstas struct ntlm_buf sessionkey; 1499233294Sstas 1500233294Sstas if (type2.flags & NTLM_NEG_NTLM2_SESSION) { 1501233294Sstas unsigned char nonce[8]; 1502233294Sstas 1503233294Sstas if (RAND_bytes(nonce, sizeof(nonce)) != 1) { 1504233294Sstas ret = EINVAL; 1505233294Sstas goto error; 1506233294Sstas } 1507233294Sstas 1508233294Sstas ret = heim_ntlm_calculate_ntlm2_sess(nonce, 1509233294Sstas type2.challenge, 1510233294Sstas c->nthash.data, 1511233294Sstas &type3.lm, 1512233294Sstas &type3.ntlm); 1513233294Sstas } else { 1514233294Sstas ret = heim_ntlm_calculate_ntlm1(c->nthash.data, 1515233294Sstas c->nthash.length, 1516233294Sstas type2.challenge, 1517233294Sstas &type3.ntlm); 1518233294Sstas 1519233294Sstas } 1520233294Sstas if (ret) 1521233294Sstas goto error; 1522233294Sstas 1523233294Sstas ret = heim_ntlm_build_ntlm1_master(c->nthash.data, 1524233294Sstas c->nthash.length, 1525233294Sstas &sessionkey, 1526233294Sstas &type3.sessionkey); 1527233294Sstas if (ret) { 1528233294Sstas if (type3.lm.data) 1529233294Sstas free(type3.lm.data); 1530233294Sstas if (type3.ntlm.data) 1531233294Sstas free(type3.ntlm.data); 1532233294Sstas goto error; 1533233294Sstas } 1534233294Sstas 1535233294Sstas free(sessionkey.data); 1536233294Sstas if (ret) { 1537233294Sstas if (type3.lm.data) 1538233294Sstas free(type3.lm.data); 1539233294Sstas if (type3.ntlm.data) 1540233294Sstas free(type3.ntlm.data); 1541233294Sstas goto error; 1542233294Sstas } 1543233294Sstas flags |= NTLM_FLAG_SESSIONKEY; 1544233294Sstas#if 0 1545233294Sstas } else { 1546233294Sstas struct ntlm_buf sessionkey; 1547233294Sstas unsigned char ntlmv2[16]; 1548233294Sstas struct ntlm_targetinfo ti; 1549233294Sstas 1550233294Sstas /* verify infotarget */ 1551233294Sstas 1552233294Sstas ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti); 1553233294Sstas if(ret) { 1554233294Sstas _gss_ntlm_delete_sec_context(minor_status, 1555233294Sstas context_handle, NULL); 1556233294Sstas *minor_status = ret; 1557233294Sstas return GSS_S_FAILURE; 1558233294Sstas } 1559233294Sstas 1560233294Sstas if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) { 1561233294Sstas _gss_ntlm_delete_sec_context(minor_status, 1562233294Sstas context_handle, NULL); 1563233294Sstas *minor_status = EINVAL; 1564233294Sstas return GSS_S_FAILURE; 1565233294Sstas } 1566233294Sstas 1567233294Sstas ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data, 1568233294Sstas ctx->client->key.length, 1569233294Sstas type3.username, 1570233294Sstas name->domain, 1571233294Sstas type2.challenge, 1572233294Sstas &type2.targetinfo, 1573233294Sstas ntlmv2, 1574233294Sstas &type3.ntlm); 1575233294Sstas if (ret) { 1576233294Sstas _gss_ntlm_delete_sec_context(minor_status, 1577233294Sstas context_handle, NULL); 1578233294Sstas *minor_status = ret; 1579233294Sstas return GSS_S_FAILURE; 1580233294Sstas } 1581233294Sstas 1582233294Sstas ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2), 1583233294Sstas &sessionkey, 1584233294Sstas &type3.sessionkey); 1585233294Sstas memset(ntlmv2, 0, sizeof(ntlmv2)); 1586233294Sstas if (ret) { 1587233294Sstas _gss_ntlm_delete_sec_context(minor_status, 1588233294Sstas context_handle, NULL); 1589233294Sstas *minor_status = ret; 1590233294Sstas return GSS_S_FAILURE; 1591233294Sstas } 1592233294Sstas 1593233294Sstas flags |= NTLM_FLAG_NTLM2_SESSION | 1594233294Sstas NTLM_FLAG_SESSION; 1595233294Sstas 1596233294Sstas if (type3.flags & NTLM_NEG_KEYEX) 1597233294Sstas flags |= NTLM_FLAG_KEYEX; 1598233294Sstas 1599233294Sstas ret = krb5_data_copy(&ctx->sessionkey, 1600233294Sstas sessionkey.data, sessionkey.length); 1601233294Sstas free(sessionkey.data); 1602233294Sstas if (ret) { 1603233294Sstas _gss_ntlm_delete_sec_context(minor_status, 1604233294Sstas context_handle, NULL); 1605233294Sstas *minor_status = ret; 1606233294Sstas return GSS_S_FAILURE; 1607233294Sstas } 1608233294Sstas#endif 1609233294Sstas } 1610233294Sstas 1611233294Sstas#if 0 1612233294Sstas if (flags & NTLM_FLAG_NTLM2_SESSION) { 1613233294Sstas _gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX), 1614233294Sstas ctx->sessionkey.data, 1615233294Sstas ctx->sessionkey.length); 1616233294Sstas _gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX), 1617233294Sstas ctx->sessionkey.data, 1618233294Sstas ctx->sessionkey.length); 1619233294Sstas } else { 1620233294Sstas flags |= NTLM_FLAG_SESSION; 1621233294Sstas RC4_set_key(&ctx->u.v1.crypto_recv.key, 1622233294Sstas ctx->sessionkey.length, 1623233294Sstas ctx->sessionkey.data); 1624233294Sstas RC4_set_key(&ctx->u.v1.crypto_send.key, 1625233294Sstas ctx->sessionkey.length, 1626233294Sstas ctx->sessionkey.data); 1627233294Sstas } 1628233294Sstas#endif 1629233294Sstas 1630233294Sstas ret = heim_ntlm_encode_type3(&type3, &ndata); 1631233294Sstas if (ret) 1632233294Sstas goto error; 1633233294Sstas 1634233294Sstas data.data = ndata.data; 1635233294Sstas data.length = ndata.length; 1636233294Sstas ret = krb5_store_data(response, data); 1637233294Sstas heim_ntlm_free_buf(&ndata); 1638233294Sstas if (ret) goto error; 1639233294Sstas 1640233294Sstas ret = krb5_store_int32(response, flags); 1641233294Sstas if (ret) goto error; 1642233294Sstas 1643233294Sstas data.data = sessionkey.data; 1644233294Sstas data.length = sessionkey.length; 1645233294Sstas 1646233294Sstas ret = krb5_store_data(response, data); 1647233294Sstas if (ret) goto error; 1648233294Sstas 1649233294Sstas error: 1650233294Sstas free(type3.username); 1651233294Sstas heim_ntlm_free_type2(&type2); 1652233294Sstas free(user); 1653233294Sstas if (domain) 1654233294Sstas free(domain); 1655233294Sstas 1656233294Sstas return ret; 1657233294Sstas} 1658233294Sstas 1659233294Sstas 1660233294Sstas/* 1661233294Sstas * { "GET_NTLM_UUID_LIST", NULL } 1662233294Sstas * 1663233294Sstas * reply: 1664233294Sstas * 1 user domain 1665233294Sstas * 0 [ end of list ] 1666233294Sstas */ 1667233294Sstas 1668233294Sstasstatic krb5_error_code 1669233294Sstaskcm_op_get_ntlm_user_list(krb5_context context, 1670233294Sstas kcm_client *client, 1671233294Sstas kcm_operation opcode, 1672233294Sstas krb5_storage *request, 1673233294Sstas krb5_storage *response) 1674233294Sstas{ 1675233294Sstas struct kcm_ntlm_cred *c; 1676233294Sstas krb5_error_code ret; 1677233294Sstas 1678233294Sstas for (c = ntlm_head; c != NULL; c = c->next) { 1679233294Sstas if (!kcm_is_same_session(client, c->uid, c->session)) 1680233294Sstas continue; 1681233294Sstas 1682233294Sstas ret = krb5_store_uint32(response, 1); 1683233294Sstas if (ret) 1684233294Sstas return ret; 1685233294Sstas ret = krb5_store_stringz(response, c->user); 1686233294Sstas if (ret) 1687233294Sstas return ret; 1688233294Sstas ret = krb5_store_stringz(response, c->domain); 1689233294Sstas if (ret) 1690233294Sstas return ret; 1691233294Sstas } 1692233294Sstas return krb5_store_uint32(response, 0); 1693233294Sstas} 1694233294Sstas 1695233294Sstas/* 1696233294Sstas * 1697233294Sstas */ 1698233294Sstas 1699178825Sdfrstatic struct kcm_op kcm_ops[] = { 1700178825Sdfr { "NOOP", kcm_op_noop }, 1701178825Sdfr { "GET_NAME", kcm_op_get_name }, 1702178825Sdfr { "RESOLVE", kcm_op_noop }, 1703178825Sdfr { "GEN_NEW", kcm_op_gen_new }, 1704178825Sdfr { "INITIALIZE", kcm_op_initialize }, 1705178825Sdfr { "DESTROY", kcm_op_destroy }, 1706178825Sdfr { "STORE", kcm_op_store }, 1707178825Sdfr { "RETRIEVE", kcm_op_retrieve }, 1708178825Sdfr { "GET_PRINCIPAL", kcm_op_get_principal }, 1709233294Sstas { "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list }, 1710233294Sstas { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid }, 1711178825Sdfr { "REMOVE_CRED", kcm_op_remove_cred }, 1712178825Sdfr { "SET_FLAGS", kcm_op_set_flags }, 1713178825Sdfr { "CHOWN", kcm_op_chown }, 1714178825Sdfr { "CHMOD", kcm_op_chmod }, 1715178825Sdfr { "GET_INITIAL_TICKET", kcm_op_get_initial_ticket }, 1716233294Sstas { "GET_TICKET", kcm_op_get_ticket }, 1717233294Sstas { "MOVE_CACHE", kcm_op_move_cache }, 1718233294Sstas { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list }, 1719233294Sstas { "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid }, 1720233294Sstas { "GET_DEFAULT_CACHE", kcm_op_get_default_cache }, 1721233294Sstas { "SET_DEFAULT_CACHE", kcm_op_set_default_cache }, 1722233294Sstas { "GET_KDC_OFFSET", kcm_op_get_kdc_offset }, 1723233294Sstas { "SET_KDC_OFFSET", kcm_op_set_kdc_offset }, 1724233294Sstas { "ADD_NTLM_CRED", kcm_op_add_ntlm_cred }, 1725233294Sstas { "HAVE_USER_CRED", kcm_op_have_ntlm_cred }, 1726233294Sstas { "DEL_NTLM_CRED", kcm_op_del_ntlm_cred }, 1727233294Sstas { "DO_NTLM_AUTH", kcm_op_do_ntlm }, 1728233294Sstas { "GET_NTLM_USER_LIST", kcm_op_get_ntlm_user_list } 1729178825Sdfr}; 1730178825Sdfr 1731178825Sdfr 1732233294Sstasconst char * 1733233294Sstaskcm_op2string(kcm_operation opcode) 1734178825Sdfr{ 1735178825Sdfr if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) 1736178825Sdfr return "Unknown operation"; 1737178825Sdfr 1738178825Sdfr return kcm_ops[opcode].name; 1739178825Sdfr} 1740178825Sdfr 1741178825Sdfrkrb5_error_code 1742178825Sdfrkcm_dispatch(krb5_context context, 1743178825Sdfr kcm_client *client, 1744178825Sdfr krb5_data *req_data, 1745178825Sdfr krb5_data *resp_data) 1746178825Sdfr{ 1747178825Sdfr krb5_error_code ret; 1748178825Sdfr kcm_method method; 1749178825Sdfr krb5_storage *req_sp = NULL; 1750178825Sdfr krb5_storage *resp_sp = NULL; 1751178825Sdfr uint16_t opcode; 1752178825Sdfr 1753178825Sdfr resp_sp = krb5_storage_emem(); 1754178825Sdfr if (resp_sp == NULL) { 1755178825Sdfr return ENOMEM; 1756178825Sdfr } 1757178825Sdfr 1758178825Sdfr if (client->pid == -1) { 1759178825Sdfr kcm_log(0, "Client had invalid process number"); 1760178825Sdfr ret = KRB5_FCC_INTERNAL; 1761178825Sdfr goto out; 1762178825Sdfr } 1763178825Sdfr 1764178825Sdfr req_sp = krb5_storage_from_data(req_data); 1765178825Sdfr if (req_sp == NULL) { 1766178825Sdfr kcm_log(0, "Process %d: failed to initialize storage from data", 1767178825Sdfr client->pid); 1768178825Sdfr ret = KRB5_CC_IO; 1769178825Sdfr goto out; 1770178825Sdfr } 1771178825Sdfr 1772178825Sdfr ret = krb5_ret_uint16(req_sp, &opcode); 1773178825Sdfr if (ret) { 1774178825Sdfr kcm_log(0, "Process %d: didn't send a message", client->pid); 1775178825Sdfr goto out; 1776178825Sdfr } 1777178825Sdfr 1778178825Sdfr if (opcode >= sizeof(kcm_ops)/sizeof(kcm_ops[0])) { 1779178825Sdfr kcm_log(0, "Process %d: invalid operation code %d", 1780178825Sdfr client->pid, opcode); 1781178825Sdfr ret = KRB5_FCC_INTERNAL; 1782178825Sdfr goto out; 1783178825Sdfr } 1784178825Sdfr method = kcm_ops[opcode].method; 1785233294Sstas if (method == NULL) { 1786233294Sstas kcm_log(0, "Process %d: operation code %s not implemented", 1787233294Sstas client->pid, kcm_op2string(opcode)); 1788233294Sstas ret = KRB5_FCC_INTERNAL; 1789233294Sstas goto out; 1790233294Sstas } 1791178825Sdfr 1792178825Sdfr /* seek past place for status code */ 1793178825Sdfr krb5_storage_seek(resp_sp, 4, SEEK_SET); 1794178825Sdfr 1795178825Sdfr ret = (*method)(context, client, opcode, req_sp, resp_sp); 1796178825Sdfr 1797178825Sdfrout: 1798178825Sdfr if (req_sp != NULL) { 1799178825Sdfr krb5_storage_free(req_sp); 1800178825Sdfr } 1801178825Sdfr 1802178825Sdfr krb5_storage_seek(resp_sp, 0, SEEK_SET); 1803178825Sdfr krb5_store_int32(resp_sp, ret); 1804178825Sdfr 1805178825Sdfr ret = krb5_storage_to_data(resp_sp, resp_data); 1806178825Sdfr krb5_storage_free(resp_sp); 1807178825Sdfr 1808178825Sdfr return ret; 1809178825Sdfr} 1810178825Sdfr 1811