1178825Sdfr/* 2178825Sdfr * Copyright (c) 2005, PADL Software Pty Ltd. 3178825Sdfr * All rights reserved. 4178825Sdfr * 5178825Sdfr * Redistribution and use in source and binary forms, with or without 6178825Sdfr * modification, are permitted provided that the following conditions 7178825Sdfr * are met: 8178825Sdfr * 9178825Sdfr * 1. Redistributions of source code must retain the above copyright 10178825Sdfr * notice, this list of conditions and the following disclaimer. 11178825Sdfr * 12178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13178825Sdfr * notice, this list of conditions and the following disclaimer in the 14178825Sdfr * documentation and/or other materials provided with the distribution. 15178825Sdfr * 16178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors 17178825Sdfr * may be used to endorse or promote products derived from this software 18178825Sdfr * without specific prior written permission. 19178825Sdfr * 20178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30178825Sdfr * SUCH DAMAGE. 31178825Sdfr */ 32178825Sdfr 33178825Sdfr#include "kcm_locl.h" 34178825Sdfr 35178825SdfrRCSID("$Id: acquire.c 22118 2007-12-03 21:44:00Z lha $"); 36178825Sdfr 37178825Sdfrstatic krb5_error_code 38178825Sdfrchange_pw_and_update_keytab(krb5_context context, kcm_ccache ccache); 39178825Sdfr 40178825Sdfr/* 41178825Sdfr * Get a new ticket using a keytab/cached key and swap it into 42178825Sdfr * an existing redentials cache 43178825Sdfr */ 44178825Sdfr 45178825Sdfrkrb5_error_code 46178825Sdfrkcm_ccache_acquire(krb5_context context, 47178825Sdfr kcm_ccache ccache, 48178825Sdfr krb5_creds **credp) 49178825Sdfr{ 50178825Sdfr krb5_error_code ret = 0; 51178825Sdfr krb5_creds cred; 52178825Sdfr krb5_const_realm realm; 53178825Sdfr krb5_get_init_creds_opt opt; 54178825Sdfr krb5_ccache_data ccdata; 55178825Sdfr char *in_tkt_service = NULL; 56178825Sdfr int done = 0; 57178825Sdfr 58178825Sdfr memset(&cred, 0, sizeof(cred)); 59178825Sdfr 60178825Sdfr KCM_ASSERT_VALID(ccache); 61178825Sdfr 62178825Sdfr /* We need a cached key or keytab to acquire credentials */ 63178825Sdfr if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) { 64178825Sdfr if (ccache->key.keyblock.keyvalue.length == 0) 65178825Sdfr krb5_abortx(context, 66178825Sdfr "kcm_ccache_acquire: KCM_FLAGS_USE_CACHED_KEY without key"); 67178825Sdfr } else if (ccache->flags & KCM_FLAGS_USE_KEYTAB) { 68178825Sdfr if (ccache->key.keytab == NULL) 69178825Sdfr krb5_abortx(context, 70178825Sdfr "kcm_ccache_acquire: KCM_FLAGS_USE_KEYTAB without keytab"); 71178825Sdfr } else { 72178825Sdfr kcm_log(0, "Cannot acquire initial credentials for cache %s without key", 73178825Sdfr ccache->name); 74178825Sdfr return KRB5_FCC_INTERNAL; 75178825Sdfr } 76178825Sdfr 77178825Sdfr HEIMDAL_MUTEX_lock(&ccache->mutex); 78178825Sdfr 79178825Sdfr /* Fake up an internal ccache */ 80178825Sdfr kcm_internal_ccache(context, ccache, &ccdata); 81178825Sdfr 82178825Sdfr /* Now, actually acquire the creds */ 83178825Sdfr if (ccache->server != NULL) { 84178825Sdfr ret = krb5_unparse_name(context, ccache->server, &in_tkt_service); 85178825Sdfr if (ret) { 86178825Sdfr kcm_log(0, "Failed to unparse service principal name for cache %s: %s", 87178825Sdfr ccache->name, krb5_get_err_text(context, ret)); 88178825Sdfr return ret; 89178825Sdfr } 90178825Sdfr } 91178825Sdfr 92178825Sdfr realm = krb5_principal_get_realm(context, ccache->client); 93178825Sdfr 94178825Sdfr krb5_get_init_creds_opt_init(&opt); 95178825Sdfr krb5_get_init_creds_opt_set_default_flags(context, "kcm", realm, &opt); 96178825Sdfr if (ccache->tkt_life != 0) 97178825Sdfr krb5_get_init_creds_opt_set_tkt_life(&opt, ccache->tkt_life); 98178825Sdfr if (ccache->renew_life != 0) 99178825Sdfr krb5_get_init_creds_opt_set_renew_life(&opt, ccache->renew_life); 100178825Sdfr 101178825Sdfr if (ccache->flags & KCM_FLAGS_USE_CACHED_KEY) { 102178825Sdfr ret = krb5_get_init_creds_keyblock(context, 103178825Sdfr &cred, 104178825Sdfr ccache->client, 105178825Sdfr &ccache->key.keyblock, 106178825Sdfr 0, 107178825Sdfr in_tkt_service, 108178825Sdfr &opt); 109178825Sdfr } else { 110178825Sdfr /* loosely based on lib/krb5/init_creds_pw.c */ 111178825Sdfr while (!done) { 112178825Sdfr ret = krb5_get_init_creds_keytab(context, 113178825Sdfr &cred, 114178825Sdfr ccache->client, 115178825Sdfr ccache->key.keytab, 116178825Sdfr 0, 117178825Sdfr in_tkt_service, 118178825Sdfr &opt); 119178825Sdfr switch (ret) { 120178825Sdfr case KRB5KDC_ERR_KEY_EXPIRED: 121178825Sdfr if (in_tkt_service != NULL && 122178825Sdfr strcmp(in_tkt_service, "kadmin/changepw") == 0) { 123178825Sdfr goto out; 124178825Sdfr } 125178825Sdfr 126178825Sdfr ret = change_pw_and_update_keytab(context, ccache); 127178825Sdfr if (ret) 128178825Sdfr goto out; 129178825Sdfr break; 130178825Sdfr case 0: 131178825Sdfr default: 132178825Sdfr done = 1; 133178825Sdfr break; 134178825Sdfr } 135178825Sdfr } 136178825Sdfr } 137178825Sdfr 138178825Sdfr if (ret) { 139178825Sdfr kcm_log(0, "Failed to acquire credentials for cache %s: %s", 140178825Sdfr ccache->name, krb5_get_err_text(context, ret)); 141178825Sdfr if (in_tkt_service != NULL) 142178825Sdfr free(in_tkt_service); 143178825Sdfr goto out; 144178825Sdfr } 145178825Sdfr 146178825Sdfr if (in_tkt_service != NULL) 147178825Sdfr free(in_tkt_service); 148178825Sdfr 149178825Sdfr /* Swap them in */ 150178825Sdfr kcm_ccache_remove_creds_internal(context, ccache); 151178825Sdfr 152178825Sdfr ret = kcm_ccache_store_cred_internal(context, ccache, &cred, 0, credp); 153178825Sdfr if (ret) { 154178825Sdfr kcm_log(0, "Failed to store credentials for cache %s: %s", 155178825Sdfr ccache->name, krb5_get_err_text(context, ret)); 156178825Sdfr krb5_free_cred_contents(context, &cred); 157178825Sdfr goto out; 158178825Sdfr } 159178825Sdfr 160178825Sdfrout: 161178825Sdfr HEIMDAL_MUTEX_unlock(&ccache->mutex); 162178825Sdfr 163178825Sdfr return ret; 164178825Sdfr} 165178825Sdfr 166178825Sdfrstatic krb5_error_code 167178825Sdfrchange_pw(krb5_context context, 168178825Sdfr kcm_ccache ccache, 169178825Sdfr char *cpn, 170178825Sdfr char *newpw) 171178825Sdfr{ 172178825Sdfr krb5_error_code ret; 173178825Sdfr krb5_creds cpw_cred; 174178825Sdfr int result_code; 175178825Sdfr krb5_data result_code_string; 176178825Sdfr krb5_data result_string; 177178825Sdfr krb5_get_init_creds_opt options; 178178825Sdfr 179178825Sdfr memset(&cpw_cred, 0, sizeof(cpw_cred)); 180178825Sdfr 181178825Sdfr krb5_get_init_creds_opt_init(&options); 182178825Sdfr krb5_get_init_creds_opt_set_tkt_life(&options, 60); 183178825Sdfr krb5_get_init_creds_opt_set_forwardable(&options, FALSE); 184178825Sdfr krb5_get_init_creds_opt_set_proxiable(&options, FALSE); 185178825Sdfr 186178825Sdfr krb5_data_zero(&result_code_string); 187178825Sdfr krb5_data_zero(&result_string); 188178825Sdfr 189178825Sdfr ret = krb5_get_init_creds_keytab(context, 190178825Sdfr &cpw_cred, 191178825Sdfr ccache->client, 192178825Sdfr ccache->key.keytab, 193178825Sdfr 0, 194178825Sdfr "kadmin/changepw", 195178825Sdfr &options); 196178825Sdfr if (ret) { 197178825Sdfr kcm_log(0, "Failed to acquire password change credentials " 198178825Sdfr "for principal %s: %s", 199178825Sdfr cpn, krb5_get_err_text(context, ret)); 200178825Sdfr goto out; 201178825Sdfr } 202178825Sdfr 203178825Sdfr ret = krb5_set_password(context, 204178825Sdfr &cpw_cred, 205178825Sdfr newpw, 206178825Sdfr ccache->client, 207178825Sdfr &result_code, 208178825Sdfr &result_code_string, 209178825Sdfr &result_string); 210178825Sdfr if (ret) { 211178825Sdfr kcm_log(0, "Failed to change password for principal %s: %s", 212178825Sdfr cpn, krb5_get_err_text(context, ret)); 213178825Sdfr goto out; 214178825Sdfr } 215178825Sdfr 216178825Sdfr if (result_code) { 217178825Sdfr kcm_log(0, "Failed to change password for principal %s: %.*s", 218178825Sdfr cpn, 219178825Sdfr (int)result_string.length, 220178825Sdfr result_string.length > 0 ? (char *)result_string.data : ""); 221178825Sdfr goto out; 222178825Sdfr } 223178825Sdfr 224178825Sdfrout: 225178825Sdfr krb5_data_free(&result_string); 226178825Sdfr krb5_data_free(&result_code_string); 227178825Sdfr krb5_free_cred_contents(context, &cpw_cred); 228178825Sdfr 229178825Sdfr return ret; 230178825Sdfr} 231178825Sdfr 232178825Sdfrstruct kcm_keyseed_data { 233178825Sdfr krb5_salt salt; 234178825Sdfr const char *password; 235178825Sdfr}; 236178825Sdfr 237178825Sdfrstatic krb5_error_code 238178825Sdfrkcm_password_key_proc(krb5_context context, 239178825Sdfr krb5_enctype etype, 240178825Sdfr krb5_salt salt, 241178825Sdfr krb5_const_pointer keyseed, 242178825Sdfr krb5_keyblock **key) 243178825Sdfr{ 244178825Sdfr krb5_error_code ret; 245178825Sdfr struct kcm_keyseed_data *s = (struct kcm_keyseed_data *)keyseed; 246178825Sdfr 247178825Sdfr /* we may be called multiple times */ 248178825Sdfr krb5_free_salt(context, s->salt); 249178825Sdfr krb5_data_zero(&s->salt.saltvalue); 250178825Sdfr 251178825Sdfr /* stash the salt */ 252178825Sdfr s->salt.salttype = salt.salttype; 253178825Sdfr 254178825Sdfr ret = krb5_data_copy(&s->salt.saltvalue, 255178825Sdfr salt.saltvalue.data, 256178825Sdfr salt.saltvalue.length); 257178825Sdfr if (ret) 258178825Sdfr return ret; 259178825Sdfr 260178825Sdfr *key = (krb5_keyblock *)malloc(sizeof(**key)); 261178825Sdfr if (*key == NULL) { 262178825Sdfr return ENOMEM; 263178825Sdfr } 264178825Sdfr 265178825Sdfr ret = krb5_string_to_key_salt(context, etype, s->password, 266178825Sdfr s->salt, *key); 267178825Sdfr if (ret) { 268178825Sdfr free(*key); 269178825Sdfr *key = NULL; 270178825Sdfr } 271178825Sdfr 272178825Sdfr return ret; 273178825Sdfr} 274178825Sdfr 275178825Sdfrstatic krb5_error_code 276178825Sdfrget_salt_and_kvno(krb5_context context, 277178825Sdfr kcm_ccache ccache, 278178825Sdfr krb5_enctype *etypes, 279178825Sdfr char *cpn, 280178825Sdfr char *newpw, 281178825Sdfr krb5_salt *salt, 282178825Sdfr unsigned *kvno) 283178825Sdfr{ 284178825Sdfr krb5_error_code ret; 285178825Sdfr krb5_creds creds; 286178825Sdfr krb5_ccache_data ccdata; 287178825Sdfr krb5_flags options = 0; 288178825Sdfr krb5_kdc_rep reply; 289178825Sdfr struct kcm_keyseed_data s; 290178825Sdfr 291178825Sdfr memset(&creds, 0, sizeof(creds)); 292178825Sdfr memset(&reply, 0, sizeof(reply)); 293178825Sdfr 294178825Sdfr s.password = NULL; 295178825Sdfr s.salt.salttype = (int)ETYPE_NULL; 296178825Sdfr krb5_data_zero(&s.salt.saltvalue); 297178825Sdfr 298178825Sdfr *kvno = 0; 299178825Sdfr kcm_internal_ccache(context, ccache, &ccdata); 300178825Sdfr s.password = newpw; 301178825Sdfr 302178825Sdfr /* Do an AS-REQ to determine salt and key version number */ 303178825Sdfr ret = krb5_copy_principal(context, ccache->client, &creds.client); 304178825Sdfr if (ret) 305178825Sdfr return ret; 306178825Sdfr 307178825Sdfr /* Yes, get a ticket to ourselves */ 308178825Sdfr ret = krb5_copy_principal(context, ccache->client, &creds.server); 309178825Sdfr if (ret) { 310178825Sdfr krb5_free_principal(context, creds.client); 311178825Sdfr return ret; 312178825Sdfr } 313178825Sdfr 314178825Sdfr ret = krb5_get_in_tkt(context, 315178825Sdfr options, 316178825Sdfr NULL, 317178825Sdfr etypes, 318178825Sdfr NULL, 319178825Sdfr kcm_password_key_proc, 320178825Sdfr &s, 321178825Sdfr NULL, 322178825Sdfr NULL, 323178825Sdfr &creds, 324178825Sdfr &ccdata, 325178825Sdfr &reply); 326178825Sdfr if (ret) { 327178825Sdfr kcm_log(0, "Failed to get self ticket for principal %s: %s", 328178825Sdfr cpn, krb5_get_err_text(context, ret)); 329178825Sdfr krb5_free_salt(context, s.salt); 330178825Sdfr } else { 331178825Sdfr *salt = s.salt; /* retrieve stashed salt */ 332178825Sdfr if (reply.kdc_rep.enc_part.kvno != NULL) 333178825Sdfr *kvno = *(reply.kdc_rep.enc_part.kvno); 334178825Sdfr } 335178825Sdfr /* ccache may have been modified but it will get trashed anyway */ 336178825Sdfr 337178825Sdfr krb5_free_cred_contents(context, &creds); 338178825Sdfr krb5_free_kdc_rep(context, &reply); 339178825Sdfr 340178825Sdfr return ret; 341178825Sdfr} 342178825Sdfr 343178825Sdfrstatic krb5_error_code 344178825Sdfrupdate_keytab_entry(krb5_context context, 345178825Sdfr kcm_ccache ccache, 346178825Sdfr krb5_enctype etype, 347178825Sdfr char *cpn, 348178825Sdfr char *spn, 349178825Sdfr char *newpw, 350178825Sdfr krb5_salt salt, 351178825Sdfr unsigned kvno) 352178825Sdfr{ 353178825Sdfr krb5_error_code ret; 354178825Sdfr krb5_keytab_entry entry; 355178825Sdfr krb5_data pw; 356178825Sdfr 357178825Sdfr memset(&entry, 0, sizeof(entry)); 358178825Sdfr 359178825Sdfr pw.data = (char *)newpw; 360178825Sdfr pw.length = strlen(newpw); 361178825Sdfr 362178825Sdfr ret = krb5_string_to_key_data_salt(context, etype, pw, 363178825Sdfr salt, &entry.keyblock); 364178825Sdfr if (ret) { 365178825Sdfr kcm_log(0, "String to key conversion failed for principal %s " 366178825Sdfr "and etype %d: %s", 367178825Sdfr cpn, etype, krb5_get_err_text(context, ret)); 368178825Sdfr return ret; 369178825Sdfr } 370178825Sdfr 371178825Sdfr if (spn == NULL) { 372178825Sdfr ret = krb5_copy_principal(context, ccache->client, 373178825Sdfr &entry.principal); 374178825Sdfr if (ret) { 375178825Sdfr kcm_log(0, "Failed to copy principal name %s: %s", 376178825Sdfr cpn, krb5_get_err_text(context, ret)); 377178825Sdfr return ret; 378178825Sdfr } 379178825Sdfr } else { 380178825Sdfr ret = krb5_parse_name(context, spn, &entry.principal); 381178825Sdfr if (ret) { 382178825Sdfr kcm_log(0, "Failed to parse SPN alias %s: %s", 383178825Sdfr spn, krb5_get_err_text(context, ret)); 384178825Sdfr return ret; 385178825Sdfr } 386178825Sdfr } 387178825Sdfr 388178825Sdfr entry.vno = kvno; 389178825Sdfr entry.timestamp = time(NULL); 390178825Sdfr 391178825Sdfr ret = krb5_kt_add_entry(context, ccache->key.keytab, &entry); 392178825Sdfr if (ret) { 393178825Sdfr kcm_log(0, "Failed to update keytab for principal %s " 394178825Sdfr "and etype %d: %s", 395178825Sdfr cpn, etype, krb5_get_err_text(context, ret)); 396178825Sdfr } 397178825Sdfr 398178825Sdfr krb5_kt_free_entry(context, &entry); 399178825Sdfr 400178825Sdfr return ret; 401178825Sdfr} 402178825Sdfr 403178825Sdfrstatic krb5_error_code 404178825Sdfrupdate_keytab_entries(krb5_context context, 405178825Sdfr kcm_ccache ccache, 406178825Sdfr krb5_enctype *etypes, 407178825Sdfr char *cpn, 408178825Sdfr char *spn, 409178825Sdfr char *newpw, 410178825Sdfr krb5_salt salt, 411178825Sdfr unsigned kvno) 412178825Sdfr{ 413178825Sdfr krb5_error_code ret = 0; 414178825Sdfr int i; 415178825Sdfr 416178825Sdfr for (i = 0; etypes[i] != ETYPE_NULL; i++) { 417178825Sdfr ret = update_keytab_entry(context, ccache, etypes[i], 418178825Sdfr cpn, spn, newpw, salt, kvno); 419178825Sdfr if (ret) 420178825Sdfr break; 421178825Sdfr } 422178825Sdfr 423178825Sdfr return ret; 424178825Sdfr} 425178825Sdfr 426178825Sdfrstatic void 427178825Sdfrgenerate_random_pw(krb5_context context, 428178825Sdfr char *buf, 429178825Sdfr size_t bufsiz) 430178825Sdfr{ 431178825Sdfr unsigned char x[512], *p; 432178825Sdfr size_t i; 433178825Sdfr 434178825Sdfr memset(x, 0, sizeof(x)); 435178825Sdfr krb5_generate_random_block(x, sizeof(x)); 436178825Sdfr p = x; 437178825Sdfr 438178825Sdfr for (i = 0; i < bufsiz; i++) { 439178825Sdfr while (isprint(*p) == 0) 440178825Sdfr p++; 441178825Sdfr 442178825Sdfr if (p - x >= sizeof(x)) { 443178825Sdfr krb5_generate_random_block(x, sizeof(x)); 444178825Sdfr p = x; 445178825Sdfr } 446178825Sdfr buf[i] = (char)*p++; 447178825Sdfr } 448178825Sdfr buf[bufsiz - 1] = '\0'; 449178825Sdfr memset(x, 0, sizeof(x)); 450178825Sdfr} 451178825Sdfr 452178825Sdfrstatic krb5_error_code 453178825Sdfrchange_pw_and_update_keytab(krb5_context context, 454178825Sdfr kcm_ccache ccache) 455178825Sdfr{ 456178825Sdfr char newpw[121]; 457178825Sdfr krb5_error_code ret; 458178825Sdfr unsigned kvno; 459178825Sdfr krb5_salt salt; 460178825Sdfr krb5_enctype *etypes = NULL; 461178825Sdfr int i; 462178825Sdfr char *cpn = NULL; 463178825Sdfr char **spns = NULL; 464178825Sdfr 465178825Sdfr krb5_data_zero(&salt.saltvalue); 466178825Sdfr 467178825Sdfr ret = krb5_unparse_name(context, ccache->client, &cpn); 468178825Sdfr if (ret) { 469178825Sdfr kcm_log(0, "Failed to unparse name: %s", 470178825Sdfr krb5_get_err_text(context, ret)); 471178825Sdfr goto out; 472178825Sdfr } 473178825Sdfr 474178825Sdfr ret = krb5_get_default_in_tkt_etypes(context, &etypes); 475178825Sdfr if (ret) { 476178825Sdfr kcm_log(0, "Failed to determine default encryption types: %s", 477178825Sdfr krb5_get_err_text(context, ret)); 478178825Sdfr goto out; 479178825Sdfr } 480178825Sdfr 481178825Sdfr /* Generate a random password (there is no set keys protocol) */ 482178825Sdfr generate_random_pw(context, newpw, sizeof(newpw)); 483178825Sdfr 484178825Sdfr /* Change it */ 485178825Sdfr ret = change_pw(context, ccache, cpn, newpw); 486178825Sdfr if (ret) 487178825Sdfr goto out; 488178825Sdfr 489178825Sdfr /* Do an AS-REQ to determine salt and key version number */ 490178825Sdfr ret = get_salt_and_kvno(context, ccache, etypes, cpn, newpw, 491178825Sdfr &salt, &kvno); 492178825Sdfr if (ret) { 493178825Sdfr kcm_log(0, "Failed to determine salting principal for principal %s: %s", 494178825Sdfr cpn, krb5_get_err_text(context, ret)); 495178825Sdfr goto out; 496178825Sdfr } 497178825Sdfr 498178825Sdfr /* Add canonical name */ 499178825Sdfr ret = update_keytab_entries(context, ccache, etypes, cpn, 500178825Sdfr NULL, newpw, salt, kvno); 501178825Sdfr if (ret) 502178825Sdfr goto out; 503178825Sdfr 504178825Sdfr /* Add SPN aliases, if any */ 505178825Sdfr spns = krb5_config_get_strings(context, NULL, "kcm", 506178825Sdfr "system_ccache", "spn_aliases", NULL); 507178825Sdfr if (spns != NULL) { 508178825Sdfr for (i = 0; spns[i] != NULL; i++) { 509178825Sdfr ret = update_keytab_entries(context, ccache, etypes, cpn, 510178825Sdfr spns[i], newpw, salt, kvno); 511178825Sdfr if (ret) 512178825Sdfr goto out; 513178825Sdfr } 514178825Sdfr } 515178825Sdfr 516178825Sdfr kcm_log(0, "Changed expired password for principal %s in cache %s", 517178825Sdfr cpn, ccache->name); 518178825Sdfr 519178825Sdfrout: 520178825Sdfr if (cpn != NULL) 521178825Sdfr free(cpn); 522178825Sdfr if (spns != NULL) 523178825Sdfr krb5_config_free_strings(spns); 524178825Sdfr if (etypes != NULL) 525178825Sdfr free(etypes); 526178825Sdfr krb5_free_salt(context, salt); 527178825Sdfr memset(newpw, 0, sizeof(newpw)); 528178825Sdfr 529178825Sdfr return ret; 530178825Sdfr} 531178825Sdfr 532