1/* 2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#define KRB5_DEPRECATED 35 36#include <krb5_locl.h> 37 38#undef __attribute__ 39#define __attribute__(X) 40 41 42static void 43str2data (krb5_data *d, 44 const char *fmt, 45 ...) __attribute__ ((format (printf, 2, 3))); 46 47static void 48str2data (krb5_data *d, 49 const char *fmt, 50 ...) 51{ 52 va_list args; 53 char *str; 54 55 va_start(args, fmt); 56 d->length = vasprintf (&str, fmt, args); 57 va_end(args); 58 d->data = str; 59} 60 61/* 62 * Change password protocol defined by 63 * draft-ietf-cat-kerb-chg-password-02.txt 64 * 65 * Share the response part of the protocol with MS set password 66 * (RFC3244) 67 */ 68 69static krb5_error_code 70chgpw_send_request (krb5_context context, 71 krb5_auth_context *auth_context, 72 krb5_creds *creds, 73 krb5_principal targprinc, 74 int is_stream, 75 int sock, 76 const char *passwd, 77 const char *host) 78{ 79 krb5_error_code ret; 80 krb5_data ap_req_data; 81 krb5_data krb_priv_data; 82 krb5_data passwd_data; 83 size_t len; 84 u_char header[6]; 85 struct iovec iov[3]; 86 struct msghdr msghdr; 87 88 if (is_stream) 89 return KRB5_KPASSWD_MALFORMED; 90 91 if (targprinc && 92 krb5_principal_compare(context, creds->client, targprinc) != TRUE) 93 return KRB5_KPASSWD_MALFORMED; 94 95 krb5_data_zero (&ap_req_data); 96 97 ret = krb5_mk_req_extended (context, 98 auth_context, 99 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, 100 NULL, /* in_data */ 101 creds, 102 &ap_req_data); 103 if (ret) 104 return ret; 105 106 passwd_data.data = rk_UNCONST(passwd); 107 passwd_data.length = strlen(passwd); 108 109 krb5_data_zero (&krb_priv_data); 110 111 ret = krb5_mk_priv (context, 112 *auth_context, 113 &passwd_data, 114 &krb_priv_data, 115 NULL); 116 if (ret) 117 goto out2; 118 119 len = 6 + ap_req_data.length + krb_priv_data.length; 120 header[0] = (len >> 8) & 0xFF; 121 header[1] = (len >> 0) & 0xFF; 122 header[2] = 0; 123 header[3] = 1; 124 header[4] = (ap_req_data.length >> 8) & 0xFF; 125 header[5] = (ap_req_data.length >> 0) & 0xFF; 126 127 memset(&msghdr, 0, sizeof(msghdr)); 128 msghdr.msg_name = NULL; 129 msghdr.msg_namelen = 0; 130 msghdr.msg_iov = iov; 131 msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); 132#if 0 133 msghdr.msg_control = NULL; 134 msghdr.msg_controllen = 0; 135#endif 136 137 iov[0].iov_base = (void*)header; 138 iov[0].iov_len = 6; 139 iov[1].iov_base = ap_req_data.data; 140 iov[1].iov_len = ap_req_data.length; 141 iov[2].iov_base = krb_priv_data.data; 142 iov[2].iov_len = krb_priv_data.length; 143 144 if (sendmsg (sock, &msghdr, 0) < 0) { 145 ret = errno; 146 krb5_set_error_message(context, ret, "sendmsg %s: %s", 147 host, strerror(ret)); 148 } 149 150 krb5_data_free (&krb_priv_data); 151out2: 152 krb5_data_free (&ap_req_data); 153 return ret; 154} 155 156/* 157 * Set password protocol as defined by RFC3244 -- 158 * Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols 159 */ 160 161static krb5_error_code 162setpw_send_request (krb5_context context, 163 krb5_auth_context *auth_context, 164 krb5_creds *creds, 165 krb5_principal targprinc, 166 int is_stream, 167 int sock, 168 const char *passwd, 169 const char *host) 170{ 171 krb5_error_code ret; 172 krb5_data ap_req_data; 173 krb5_data krb_priv_data; 174 krb5_data pwd_data; 175 ChangePasswdDataMS chpw; 176 size_t len; 177 u_char header[4 + 6]; 178 u_char *p; 179 struct iovec iov[3]; 180 struct msghdr msghdr; 181 182 krb5_data_zero (&ap_req_data); 183 184 ret = krb5_mk_req_extended (context, 185 auth_context, 186 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, 187 NULL, /* in_data */ 188 creds, 189 &ap_req_data); 190 if (ret) 191 return ret; 192 193 chpw.newpasswd.length = strlen(passwd); 194 chpw.newpasswd.data = rk_UNCONST(passwd); 195 if (targprinc) { 196 chpw.targname = &targprinc->name; 197 chpw.targrealm = &targprinc->realm; 198 } else { 199 chpw.targname = NULL; 200 chpw.targrealm = NULL; 201 } 202 203 ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length, 204 &chpw, &len, ret); 205 if (ret) { 206 krb5_data_free (&ap_req_data); 207 return ret; 208 } 209 210 if(pwd_data.length != len) 211 krb5_abortx(context, "internal error in ASN.1 encoder"); 212 213 ret = krb5_mk_priv (context, 214 *auth_context, 215 &pwd_data, 216 &krb_priv_data, 217 NULL); 218 if (ret) 219 goto out2; 220 221 len = 6 + ap_req_data.length + krb_priv_data.length; 222 p = header; 223 if (is_stream) { 224 _krb5_put_int(p, len, 4); 225 p += 4; 226 } 227 *p++ = (len >> 8) & 0xFF; 228 *p++ = (len >> 0) & 0xFF; 229 *p++ = 0xff; 230 *p++ = 0x80; 231 *p++ = (ap_req_data.length >> 8) & 0xFF; 232 *p = (ap_req_data.length >> 0) & 0xFF; 233 234 memset(&msghdr, 0, sizeof(msghdr)); 235 msghdr.msg_name = NULL; 236 msghdr.msg_namelen = 0; 237 msghdr.msg_iov = iov; 238 msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov); 239#if 0 240 msghdr.msg_control = NULL; 241 msghdr.msg_controllen = 0; 242#endif 243 244 iov[0].iov_base = (void*)header; 245 if (is_stream) 246 iov[0].iov_len = 10; 247 else 248 iov[0].iov_len = 6; 249 iov[1].iov_base = ap_req_data.data; 250 iov[1].iov_len = ap_req_data.length; 251 iov[2].iov_base = krb_priv_data.data; 252 iov[2].iov_len = krb_priv_data.length; 253 254 if (sendmsg (sock, &msghdr, 0) < 0) { 255 ret = errno; 256 krb5_set_error_message(context, ret, "sendmsg %s: %s", 257 host, strerror(ret)); 258 } 259 260 krb5_data_free (&krb_priv_data); 261out2: 262 krb5_data_free (&ap_req_data); 263 krb5_data_free (&pwd_data); 264 return ret; 265} 266 267static krb5_error_code 268process_reply (krb5_context context, 269 krb5_auth_context auth_context, 270 int is_stream, 271 int sock, 272 int *result_code, 273 krb5_data *result_code_string, 274 krb5_data *result_string, 275 const char *host) 276{ 277 krb5_error_code ret; 278 u_char reply[1024 * 3]; 279 ssize_t len; 280 uint16_t pkt_len, pkt_ver; 281 krb5_data ap_rep_data; 282 int save_errno; 283 284 len = 0; 285 if (is_stream) { 286 while (len < sizeof(reply)) { 287 unsigned long size; 288 289 ret = recvfrom (sock, reply + len, sizeof(reply) - len, 290 0, NULL, NULL); 291 if (ret < 0) { 292 save_errno = errno; 293 krb5_set_error_message(context, save_errno, 294 "recvfrom %s: %s", 295 host, strerror(save_errno)); 296 return save_errno; 297 } else if (ret == 0) { 298 krb5_set_error_message(context, 1,"recvfrom timeout %s", host); 299 return 1; 300 } 301 len += ret; 302 if (len < 4) 303 continue; 304 _krb5_get_int(reply, &size, 4); 305 if (size + 4 < len) 306 continue; 307 memmove(reply, reply + 4, size); 308 len = size; 309 break; 310 } 311 if (len == sizeof(reply)) { 312 krb5_set_error_message(context, ENOMEM, 313 N_("Message too large from %s", "host"), 314 host); 315 return ENOMEM; 316 } 317 } else { 318 ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL); 319 if (ret < 0) { 320 save_errno = errno; 321 krb5_set_error_message(context, save_errno, 322 "recvfrom %s: %s", 323 host, strerror(save_errno)); 324 return save_errno; 325 } 326 len = ret; 327 } 328 329 if (len < 6) { 330 str2data (result_string, "server %s sent to too short message " 331 "(%ld bytes)", host, (long)len); 332 *result_code = KRB5_KPASSWD_MALFORMED; 333 return 0; 334 } 335 336 pkt_len = (reply[0] << 8) | (reply[1]); 337 pkt_ver = (reply[2] << 8) | (reply[3]); 338 339 if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) { 340 KRB_ERROR error; 341 size_t size; 342 u_char *p; 343 344 memset(&error, 0, sizeof(error)); 345 346 ret = decode_KRB_ERROR(reply, len, &error, &size); 347 if (ret) 348 return ret; 349 350 if (error.e_data->length < 2) { 351 str2data(result_string, "server %s sent too short " 352 "e_data to print anything usable", host); 353 free_KRB_ERROR(&error); 354 *result_code = KRB5_KPASSWD_MALFORMED; 355 return 0; 356 } 357 358 p = error.e_data->data; 359 *result_code = (p[0] << 8) | p[1]; 360 if (error.e_data->length == 2) 361 str2data(result_string, "server only sent error code"); 362 else 363 krb5_data_copy (result_string, 364 p + 2, 365 error.e_data->length - 2); 366 free_KRB_ERROR(&error); 367 return 0; 368 } 369 370 if (pkt_len != len) { 371 str2data (result_string, "client: wrong len in reply"); 372 *result_code = KRB5_KPASSWD_MALFORMED; 373 return 0; 374 } 375 if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) { 376 str2data (result_string, 377 "client: wrong version number (%d)", pkt_ver); 378 *result_code = KRB5_KPASSWD_MALFORMED; 379 return 0; 380 } 381 382 ap_rep_data.data = reply + 6; 383 ap_rep_data.length = (reply[4] << 8) | (reply[5]); 384 385 if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) { 386 str2data (result_string, "client: wrong AP len in reply"); 387 *result_code = KRB5_KPASSWD_MALFORMED; 388 return 0; 389 } 390 391 if (ap_rep_data.length) { 392 krb5_ap_rep_enc_part *ap_rep; 393 krb5_data priv_data; 394 u_char *p; 395 396 priv_data.data = (u_char*)ap_rep_data.data + ap_rep_data.length; 397 priv_data.length = len - ap_rep_data.length - 6; 398 399 ret = krb5_rd_rep (context, 400 auth_context, 401 &ap_rep_data, 402 &ap_rep); 403 if (ret) 404 return ret; 405 406 krb5_free_ap_rep_enc_part (context, ap_rep); 407 408 ret = krb5_rd_priv (context, 409 auth_context, 410 &priv_data, 411 result_code_string, 412 NULL); 413 if (ret) { 414 krb5_data_free (result_code_string); 415 return ret; 416 } 417 418 if (result_code_string->length < 2) { 419 *result_code = KRB5_KPASSWD_MALFORMED; 420 str2data (result_string, 421 "client: bad length in result"); 422 return 0; 423 } 424 425 p = result_code_string->data; 426 427 *result_code = (p[0] << 8) | p[1]; 428 krb5_data_copy (result_string, 429 (unsigned char*)result_code_string->data + 2, 430 result_code_string->length - 2); 431 return 0; 432 } else { 433 KRB_ERROR error; 434 size_t size; 435 u_char *p; 436 437 ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size); 438 if (ret) { 439 return ret; 440 } 441 if (error.e_data->length < 2) { 442 krb5_warnx (context, "too short e_data to print anything usable"); 443 return 1; /* XXX */ 444 } 445 446 p = error.e_data->data; 447 *result_code = (p[0] << 8) | p[1]; 448 krb5_data_copy (result_string, 449 p + 2, 450 error.e_data->length - 2); 451 return 0; 452 } 453} 454 455 456/* 457 * change the password using the credentials in `creds' (for the 458 * principal indicated in them) to `newpw', storing the result of 459 * the operation in `result_*' and an error code or 0. 460 */ 461 462typedef krb5_error_code (*kpwd_send_request) (krb5_context, 463 krb5_auth_context *, 464 krb5_creds *, 465 krb5_principal, 466 int, 467 int, 468 const char *, 469 const char *); 470typedef krb5_error_code (*kpwd_process_reply) (krb5_context, 471 krb5_auth_context, 472 int, 473 int, 474 int *, 475 krb5_data *, 476 krb5_data *, 477 const char *); 478 479static struct kpwd_proc { 480 const char *name; 481 int flags; 482#define SUPPORT_TCP 1 483#define SUPPORT_UDP 2 484 kpwd_send_request send_req; 485 kpwd_process_reply process_rep; 486} procs[] = { 487 { 488 "MS set password", 489 SUPPORT_TCP|SUPPORT_UDP, 490 setpw_send_request, 491 process_reply 492 }, 493 { 494 "change password", 495 SUPPORT_UDP, 496 chgpw_send_request, 497 process_reply 498 }, 499 { NULL } 500}; 501 502/* 503 * 504 */ 505 506static krb5_error_code 507change_password_loop (krb5_context context, 508 krb5_creds *creds, 509 krb5_principal targprinc, 510 const char *newpw, 511 int *result_code, 512 krb5_data *result_code_string, 513 krb5_data *result_string, 514 struct kpwd_proc *proc) 515{ 516 krb5_error_code ret; 517 krb5_auth_context auth_context = NULL; 518 krb5_krbhst_handle handle = NULL; 519 krb5_krbhst_info *hi; 520 int sock; 521 unsigned int i; 522 int done = 0; 523 krb5_realm realm; 524 525 if (targprinc) 526 realm = targprinc->realm; 527 else 528 realm = creds->client->realm; 529 530 ret = krb5_auth_con_init (context, &auth_context); 531 if (ret) 532 return ret; 533 534 krb5_auth_con_setflags (context, auth_context, 535 KRB5_AUTH_CONTEXT_DO_SEQUENCE); 536 537 ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle); 538 if (ret) 539 goto out; 540 541 while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) { 542 struct addrinfo *ai, *a; 543 int is_stream; 544 545 switch (hi->proto) { 546 case KRB5_KRBHST_UDP: 547 if ((proc->flags & SUPPORT_UDP) == 0) 548 continue; 549 is_stream = 0; 550 break; 551 case KRB5_KRBHST_TCP: 552 if ((proc->flags & SUPPORT_TCP) == 0) 553 continue; 554 is_stream = 1; 555 break; 556 default: 557 continue; 558 } 559 560 ret = krb5_krbhst_get_addrinfo(context, hi, &ai); 561 if (ret) 562 continue; 563 564 for (a = ai; !done && a != NULL; a = a->ai_next) { 565 int replied = 0; 566 567 sock = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol); 568 if (sock < 0) 569 continue; 570 rk_cloexec(sock); 571 572 ret = connect(sock, a->ai_addr, a->ai_addrlen); 573 if (ret < 0) { 574 close (sock); 575 goto out; 576 } 577 578 ret = krb5_auth_con_genaddrs (context, auth_context, sock, 579 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR); 580 if (ret) { 581 close (sock); 582 goto out; 583 } 584 585 for (i = 0; !done && i < 5; ++i) { 586 fd_set fdset; 587 struct timeval tv; 588 589 if (!replied) { 590 replied = 0; 591 592 ret = (*proc->send_req) (context, 593 &auth_context, 594 creds, 595 targprinc, 596 is_stream, 597 sock, 598 newpw, 599 hi->hostname); 600 if (ret) { 601 close(sock); 602 goto out; 603 } 604 } 605 606 if (sock >= FD_SETSIZE) { 607 ret = ERANGE; 608 krb5_set_error_message(context, ret, 609 "fd %d too large", sock); 610 close (sock); 611 goto out; 612 } 613 614 FD_ZERO(&fdset); 615 FD_SET(sock, &fdset); 616 tv.tv_usec = 0; 617 tv.tv_sec = 1 + (1 << i); 618 619 ret = select (sock + 1, &fdset, NULL, NULL, &tv); 620 if (ret < 0 && errno != EINTR) { 621 close(sock); 622 goto out; 623 } 624 if (ret == 1) { 625 ret = (*proc->process_rep) (context, 626 auth_context, 627 is_stream, 628 sock, 629 result_code, 630 result_code_string, 631 result_string, 632 hi->hostname); 633 if (ret == 0) 634 done = 1; 635 else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL) 636 replied = 1; 637 } else { 638 ret = KRB5_KDC_UNREACH; 639 } 640 } 641 close (sock); 642 } 643 } 644 645 out: 646 krb5_krbhst_free (context, handle); 647 krb5_auth_con_free (context, auth_context); 648 649 if (ret == KRB5_KDC_UNREACH) { 650 krb5_set_error_message(context, 651 ret, 652 N_("Unable to reach any changepw server " 653 " in realm %s", "realm"), realm); 654 *result_code = KRB5_KPASSWD_HARDERROR; 655 } 656 return ret; 657} 658 659#ifndef HEIMDAL_SMALLER 660 661static struct kpwd_proc * 662find_chpw_proto(const char *name) 663{ 664 struct kpwd_proc *p; 665 for (p = procs; p->name != NULL; p++) { 666 if (strcmp(p->name, name) == 0) 667 return p; 668 } 669 return NULL; 670} 671 672/** 673 * krb5_change_password() is deprecated, use krb5_set_password(). 674 * 675 * @param context a Keberos context 676 * @param creds 677 * @param newpw 678 * @param result_code 679 * @param result_code_string 680 * @param result_string 681 * 682 * @return On sucess password is changed. 683 684 * @ingroup @krb5_deprecated 685 */ 686 687krb5_error_code KRB5_LIB_FUNCTION 688krb5_change_password (krb5_context context, 689 krb5_creds *creds, 690 const char *newpw, 691 int *result_code, 692 krb5_data *result_code_string, 693 krb5_data *result_string) 694 KRB5_DEPRECATED 695{ 696 struct kpwd_proc *p = find_chpw_proto("change password"); 697 698 *result_code = KRB5_KPASSWD_MALFORMED; 699 result_code_string->data = result_string->data = NULL; 700 result_code_string->length = result_string->length = 0; 701 702 if (p == NULL) 703 return KRB5_KPASSWD_MALFORMED; 704 705 return change_password_loop(context, creds, NULL, newpw, 706 result_code, result_code_string, 707 result_string, p); 708} 709#endif /* HEIMDAL_SMALLER */ 710 711/** 712 * Change password using creds. 713 * 714 * @param context a Keberos context 715 * @param creds The initial kadmin/passwd for the principal or an admin principal 716 * @param newpw The new password to set 717 * @param targprinc if unset, the default principal is used. 718 * @param result_code Result code, KRB5_KPASSWD_SUCCESS is when password is changed. 719 * @param result_code_string binary message from the server, contains 720 * at least the result_code. 721 * @param result_string A message from the kpasswd service or the 722 * library in human printable form. The string is NUL terminated. 723 * 724 * @return On sucess and *result_code is KRB5_KPASSWD_SUCCESS, the password is changed. 725 726 * @ingroup @krb5 727 */ 728 729krb5_error_code KRB5_LIB_FUNCTION 730krb5_set_password(krb5_context context, 731 krb5_creds *creds, 732 const char *newpw, 733 krb5_principal targprinc, 734 int *result_code, 735 krb5_data *result_code_string, 736 krb5_data *result_string) 737{ 738 krb5_principal principal = NULL; 739 krb5_error_code ret = 0; 740 int i; 741 742 *result_code = KRB5_KPASSWD_MALFORMED; 743 krb5_data_zero(result_code_string); 744 krb5_data_zero(result_string); 745 746 if (targprinc == NULL) { 747 ret = krb5_get_default_principal(context, &principal); 748 if (ret) 749 return ret; 750 } else 751 principal = targprinc; 752 753 for (i = 0; procs[i].name != NULL; i++) { 754 *result_code = 0; 755 ret = change_password_loop(context, creds, principal, newpw, 756 result_code, result_code_string, 757 result_string, 758 &procs[i]); 759 if (ret == 0 && *result_code == 0) 760 break; 761 } 762 763 if (targprinc == NULL) 764 krb5_free_principal(context, principal); 765 return ret; 766} 767 768/* 769 * 770 */ 771 772krb5_error_code KRB5_LIB_FUNCTION 773krb5_set_password_using_ccache(krb5_context context, 774 krb5_ccache ccache, 775 const char *newpw, 776 krb5_principal targprinc, 777 int *result_code, 778 krb5_data *result_code_string, 779 krb5_data *result_string) 780{ 781 krb5_creds creds, *credsp; 782 krb5_error_code ret; 783 krb5_principal principal = NULL; 784 785 *result_code = KRB5_KPASSWD_MALFORMED; 786 result_code_string->data = result_string->data = NULL; 787 result_code_string->length = result_string->length = 0; 788 789 memset(&creds, 0, sizeof(creds)); 790 791 if (targprinc == NULL) { 792 ret = krb5_cc_get_principal(context, ccache, &principal); 793 if (ret) 794 return ret; 795 } else 796 principal = targprinc; 797 798 ret = krb5_make_principal(context, &creds.server, 799 krb5_principal_get_realm(context, principal), 800 "kadmin", "changepw", NULL); 801 if (ret) 802 goto out; 803 804 ret = krb5_cc_get_principal(context, ccache, &creds.client); 805 if (ret) { 806 krb5_free_principal(context, creds.server); 807 goto out; 808 } 809 810 ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp); 811 krb5_free_principal(context, creds.server); 812 krb5_free_principal(context, creds.client); 813 if (ret) 814 goto out; 815 816 ret = krb5_set_password(context, 817 credsp, 818 newpw, 819 principal, 820 result_code, 821 result_code_string, 822 result_string); 823 824 krb5_free_creds(context, credsp); 825 826 return ret; 827 out: 828 if (targprinc == NULL) 829 krb5_free_principal(context, principal); 830 return ret; 831} 832 833/* 834 * 835 */ 836 837const char* KRB5_LIB_FUNCTION 838krb5_passwd_result_to_string (krb5_context context, 839 int result) 840{ 841 static const char *strings[] = { 842 "Success", 843 "Malformed", 844 "Hard error", 845 "Auth error", 846 "Soft error" , 847 "Access denied", 848 "Bad version", 849 "Initial flag needed" 850 }; 851 852 if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED) 853 return "unknown result code"; 854 else 855 return strings[result]; 856} 857