root/source4/heimdal/lib/krb5/changepw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. str2data
  2. chgpw_send_request
  3. setpw_send_request
  4. process_reply
  5. change_password_loop
  6. find_chpw_proto
  7. krb5_change_password
  8. krb5_set_password
  9. krb5_set_password_using_ccache
  10. krb5_passwd_result_to_string

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

/* [<][>][^][v][top][bottom][index][help] */