Implementation of Microsoft set password client library code provided
authorSam Hartman <hartmans@mit.edu>
Fri, 25 Apr 2003 18:46:22 +0000 (18:46 +0000)
committerSam Hartman <hartmans@mit.edu>
Fri, 25 Apr 2003 18:46:22 +0000 (18:46 +0000)
by Paul Nelson.

Ticket: 1377
Status: open
Tags: pullup

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15373 dc483132-0cff-0310-8789-dd5450dbe970

12 files changed:
README
src/include/ChangeLog
src/include/k5-int.h
src/include/krb5.hin
src/lib/ChangeLog
src/lib/krb5/asn.1/ChangeLog
src/lib/krb5/asn.1/krb5_encode.c
src/lib/krb5/krb/ChangeLog
src/lib/krb5/krb/chpw.c
src/lib/krb5/os/ChangeLog
src/lib/krb5/os/changepw.c
src/lib/krb5_32.def

diff --git a/README b/README
index 1a4ddfca93fdaa9cf8528bd050bb76cc25de9e58..83e706e6249b8b6050faf3b93ff49b7280408460 100644 (file)
--- a/README
+++ b/README
@@ -538,6 +538,9 @@ providing patches for numerous buffer overruns.
 Thanks to Christopher Thompson and Marcus Watts for discovering the
 ftpd security bug.
 
+Thanks to Paul Nelson of Thursby Software Systems for implementing the
+Microsoft set password protocol.
+
 Thanks to the members of the Kerberos V5 development team at MIT, both
 past and present: Danilo Almeida, Jay Berkenbilt, Richard Basch, Mitch
 Berger, John Carr, Don Davis, Alexandra Ellwood, Nancy Gilman, Matt
index 85f8920243e7dd2498a971962fefef8bfe888ecb..53947082b0d5b30e8a41c52fd837a60622c098ca 100644 (file)
@@ -1,3 +1,14 @@
+2003-04-17  Sam Hartman  <hartmans@mit.edu>
+
+       * k5-int.h: Add encode_krb5_setpw_req
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+       * krb5.hin: Add krb5_set_password
+       Move krb5*_chpw internals to k5int.h
+
+       * k5-int.h: Add prototypes for set-password helper functions
+
 2003-04-24  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in ($(srcdir)/krb5/autoconf.stmp): Try running
index 41c325da1ebea95b3c4c2ad93e8506fbcf8ca748..ec7381bcf393c10fd5b7e174379bc0b36c537f24 100644 (file)
@@ -1270,6 +1270,9 @@ krb5_error_code encode_krb5_sam_response
 krb5_error_code encode_krb5_predicted_sam_response
        (const krb5_predicted_sam_response * , krb5_data **);
 
+krb5_error_code encode_krb5_setpw_req
+(const krb5_principal target, char *password, krb5_data **code);
+
 /*************************************************************************
  * End of prototypes for krb5_encode.c
  *************************************************************************/
@@ -1559,6 +1562,29 @@ krb5_error_code KRB5_CALLCONV krb5_cc_retrieve_cred_default
 void krb5int_set_prompt_types
        (krb5_context, krb5_prompt_type *);
 
+/* set and change password helpers */
+
+krb5_error_code krb5int_mk_chpw_req
+       (krb5_context context, krb5_auth_context auth_context,
+                       krb5_data *ap_req, char *passwd, krb5_data *packet);
+krb5_error_code krb5int_rd_chpw_rep
+       (krb5_context context, krb5_auth_context auth_context,
+                      krb5_data *packet, int *result_code,
+                      krb5_data *result_data);
+krb5_error_code KRB5_CALLCONV krb5_chpw_result_code_string
+       (krb5_context context, int result_code,
+                       char **result_codestr);
+krb5_error_code  krb5int_mk_setpw_req
+       (krb5_context context, krb5_auth_context auth_context,
+                       krb5_data *ap_req, krb5_principal targetprinc, char *passwd, krb5_data *packet);
+krb5_error_code krb5int_rd_setpw_rep
+       (krb5_context context, krb5_auth_context auth_context,
+                      krb5_data *packet, int *result_code,
+                      krb5_data *result_data);
+krb5_error_code krb5int_setpw_result_code_string
+       (krb5_context context, int result_code,
+                       const char **result_codestr);
+
 
 
 #if defined(macintosh) && defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
index eece828f1f8e36e10ba703be0be6a83d3f1b5843..d43647dd4c5a4ae9738b539913f7d19490bbfdc8 100644 (file)
@@ -1658,18 +1658,6 @@ krb5_error_code KRB5_CALLCONV krb5_524_conv_principal
        (krb5_context context, krb5_const_principal princ, 
                char *name, char *inst, char *realm);
 
-#if KRB5_PRIVATE
-krb5_error_code KRB5_CALLCONV krb5_mk_chpw_req
-       (krb5_context context, krb5_auth_context auth_context,
-                       krb5_data *ap_req, char *passwd, krb5_data *packet);
-krb5_error_code KRB5_CALLCONV krb5_rd_chpw_rep
-       (krb5_context context, krb5_auth_context auth_context,
-                      krb5_data *packet, int *result_code,
-                      krb5_data *result_data);
-krb5_error_code KRB5_CALLCONV krb5_chpw_result_code_string
-       (krb5_context context, int result_code,
-                       char **result_codestr);
-#endif
 
 /* libkt.spec */
 #if KRB5_PRIVATE
@@ -1871,6 +1859,14 @@ krb5_change_password
        (krb5_context context, krb5_creds *creds, char *newpw,
                        int *result_code, krb5_data *result_code_string,
                        krb5_data *result_string);
+krb5_error_code KRB5_CALLCONV
+krb5_set_password
+       (krb5_context context, krb5_creds *creds, char *newpw, krb5_principal change_password_for,
+                       int *result_code, krb5_data *result_code_string, krb5_data *result_string);
+krb5_error_code KRB5_CALLCONV
+krb5_set_password_using_ccache
+       (krb5_context context, krb5_ccache ccache, char *newpw, krb5_principal change_password_for,
+                       int *result_code, krb5_data *result_code_string, krb5_data *result_string);
 
 #if KRB5_PRIVATE
 #ifndef macintosh
index bfa7678b0cad3dc3543e408f31681ae8034e0724..fb87043923071686bc45c315003950d31f41a658 100644 (file)
@@ -1,3 +1,7 @@
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+       * krb5_32.def: Add krb5_set_password and krb5_set_password_using_ccache
+
 2003-02-10  Tom Yu  <tlyu@mit.edu>
 
        * Makefile.in (K4LIBS): Revert previous.
index 01e6d96cde64f59849c35298eea6860064be0d7f..4eaa5fe61afc90c140e4765b5a41d474b747aaec 100644 (file)
@@ -1,3 +1,7 @@
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+       * krb5_encode.c (encode_krb5_setpw_req): new function
+
 2003-04-13  Ezra Peisach  <epeisach@mit.edu>
 
        * asn1_k_decode.c (asn1_decode_kdc_req_body): Fix memory leak if
index 2a4f7bb14089dea251fade673403adcc4a31b350..04deef0d24d23d081c460b710119b160fe92c3a9 100644 (file)
@@ -822,3 +822,20 @@ krb5_error_code encode_krb5_predicted_sam_response(const krb5_predicted_sam_resp
   sum += length;
   krb5_cleanup();
 }
+
+krb5_error_code encode_krb5_setpw_req(const krb5_principal target,
+                                     char *password, krb5_data **code)
+{
+  /* Macros really want us to have a variable called rep which we do not need*/
+  const char *rep = "dummy string";
+
+  krb5_setup();
+
+  krb5_addfield(target,2,asn1_encode_realm);
+  krb5_addfield(target,1,asn1_encode_principal_name);
+  krb5_addlenfield(strlen(password), password,0,asn1_encode_octetstring);
+  krb5_makeseq();
+
+
+  krb5_cleanup();
+}
index 2dfe4639738201ae7e1a9971440d53db714a1472..a560a9640b1ea5c898cd3a43d6393998f16ebdbb 100644 (file)
@@ -1,3 +1,19 @@
+2003-04-25  Sam Hartman  <hartmans@mit.edu>
+
+       * chpw.c (krb5int_rd_setpw_rep): Fix error handling; allow
+       krberrors to be read correctly; fix memory alloctaion so that
+       allocated structures are freed. 
+
+2003-04-16  Sam Hartman  <hartmans@mit.edu>
+
+       * chpw.c (krb5int_mk_setpw_req): Use encode_krb5_setpw_req.  Fix
+       memory handling to free data that is allocated  
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+       * chpw.c (krb5int_mk_setpw_req krb5int_rd_setpw_rep): New function
+
+=======
 2003-04-24  Ezra Peisach  <epeisach@mit.edu>
 
        * kfree.c (krb5_free_pwd_sequences): Correction to previous
@@ -8,6 +24,7 @@
        * kfree.c (krb5_free_pwd_sequences): Actually free the entire
        sequence of passwd_phase_elements and not just the first one.
 
+>>>>>>> 5.385
 2003-04-13  Ken Raeburn  <raeburn@mit.edu>
 
        * init_ctx.c (DEFAULT_ETYPE_LIST): Add AES with 256 bits at the
index bb2cfe9c7dc1ad1fc1e1aa6439c832815ea94eeb..9c5a4078af2f864872af1f724fe7a895ad9bf6f4 100644 (file)
@@ -1,11 +1,15 @@
+/*
+** set password functions added by Paul W. Nelson, Thursby Software Systems, Inc.
+*/
 #include <string.h>
 
 #include "k5-int.h"
 #include "krb5_err.h"
 #include "auth_con.h"
 
-krb5_error_code KRB5_CALLCONV
-krb5_mk_chpw_req(krb5_context context, krb5_auth_context auth_context, krb5_data *ap_req, char *passwd, krb5_data *packet)
+
+krb5_error_code 
+krb5int_mk_chpw_req(krb5_context context, krb5_auth_context auth_context, krb5_data *ap_req, char *passwd, krb5_data *packet)
 {
     krb5_error_code ret = 0;
     krb5_data clearpw;
@@ -66,8 +70,8 @@ cleanup:
     return(ret);
 }
 
-krb5_error_code KRB5_CALLCONV
-krb5_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
+krb5_error_code 
+krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
 {
     char *ptr;
     int plen, vno;
@@ -221,3 +225,276 @@ krb5_chpw_result_code_string(krb5_context context, int result_code, char **code_
 
    return(0);
 }
+
+krb5_error_code 
+krb5int_mk_setpw_req(
+     krb5_context context,
+     krb5_auth_context auth_context,
+     krb5_data *ap_req,
+     krb5_principal targprinc,
+     char *passwd,
+     krb5_data *packet )
+{
+    krb5_error_code ret;
+    krb5_data  cipherpw;
+    krb5_data  *encoded_setpw;
+
+    char *ptr;
+     int count = 2;
+
+     cipherpw.data = NULL;
+     cipherpw.length = 0;
+     
+    if (ret = krb5_auth_con_setflags(context, auth_context,
+                                    KRB5_AUTH_CONTEXT_DO_SEQUENCE))
+               return(ret);
+
+    ret = encode_krb5_setpw_req(targprinc, passwd, &encoded_setpw);
+    if (ret) {
+       return ret;
+    }
+
+    if ( (ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
+       krb5_free_data( context, encoded_setpw);
+       return(ret);
+    }
+    krb5_free_data( context, encoded_setpw);
+    
+
+    packet->length = 6 + ap_req->length + cipherpw.length;
+    packet->data = (char *) malloc(packet->length);
+    if (packet->data  == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+    ptr = packet->data;
+/*
+** build the packet -
+*/
+/* put in the length */
+    *ptr++ = (packet->length>>8) & 0xff;
+    *ptr++ = packet->length & 0xff;
+/* put in the version */
+    *ptr++ = (char)0xff;
+    *ptr++ = (char)0x80;
+/* the ap_req length is big endian */
+    *ptr++ = (ap_req->length>>8) & 0xff;
+    *ptr++ = ap_req->length & 0xff;
+/* put in the request data */
+    memcpy(ptr, ap_req->data, ap_req->length);
+    ptr += ap_req->length;
+/*
+** put in the "private" password data -
+*/
+    memcpy(ptr, cipherpw.data, cipherpw.length);
+    ret = 0;
+ cleanup:
+    if (cipherpw.data)
+       krb5_free_data_contents(context, &cipherpw);
+    if ((ret != 0) && packet->data) {
+       free( packet->data);
+       packet->data = NULL;
+    }
+    return ret;
+}
+
+krb5_error_code 
+krb5int_rd_setpw_rep( krb5_context context, krb5_auth_context auth_context, krb5_data *packet,
+     int *result_code, krb5_data *result_data )
+{
+    char *ptr;
+    unsigned int message_length, version_number;
+    krb5_data ap_rep;
+    krb5_ap_rep_enc_part *ap_rep_enc;
+    krb5_error_code ret;
+    krb5_data cipherresult;
+    krb5_data clearresult;
+    krb5_replay_data replay;
+/*
+** validate the packet length -
+*/
+    if (packet->length < 4)
+       return(KRB5KRB_AP_ERR_MODIFIED);
+
+    ptr = packet->data;
+
+/*
+** see if it is an error
+*/
+    if (krb5_is_krb_error(packet)) {
+       krb5_error *krberror;
+       if (ret = krb5_rd_error(context, packet, &krberror))
+           return(ret);
+       if (krberror->e_data.data  == NULL) {
+           ret = ERROR_TABLE_BASE_krb5 + krberror->error;
+           krb5_free_error(context, krberror);
+           return (ret);
+       }
+       clearresult = krberror->e_data;
+       krberror->e_data.data  = NULL; /*So we can free it later*/
+       krberror->e_data.length = 0;
+       krb5_free_error(context, krberror);
+               
+    } else { /* Not an error*/
+
+/*
+** validate the message length -
+** length is big endian 
+*/
+       message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+       ptr += 2;
+/*
+** make sure the message length and packet length agree -
+*/
+       if (message_length != packet->length)
+           return(KRB5KRB_AP_ERR_MODIFIED);
+/*
+** get the version number -
+*/
+       version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+       ptr += 2;
+/*
+** make sure we support the version returned -
+*/
+/*
+** set password version is 0xff80, change password version is 1
+*/
+       if (version_number != 0xff80 && version_number != 1)
+           return(KRB5KDC_ERR_BAD_PVNO);
+/*
+** now fill in ap_rep with the reply -
+*/
+/*
+** get the reply length -
+*/
+       ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+       ptr += 2;
+/*
+** validate ap_rep length agrees with the packet length -
+*/
+       if (ptr + ap_rep.length >= packet->data + packet->length)
+           return(KRB5KRB_AP_ERR_MODIFIED);
+/*
+** if data was returned, set the ap_rep ptr -
+*/
+       if( ap_rep.length ) {
+           ap_rep.data = ptr;
+           ptr += ap_rep.length;
+
+           if (ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc))
+               return(ret);
+
+           krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+/*
+** now decrypt the result -
+*/
+           cipherresult.data = ptr;
+           cipherresult.length = (packet->data + packet->length) - ptr;
+
+           {
+               krb5_keyblock *saved_remote_subkey;
+/*
+** save the remote_subkey, so it doesn't get used when decoding 
+*/
+               saved_remote_subkey      = auth_context->remote_subkey;
+               auth_context->remote_subkey = NULL;
+
+               ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+                                  NULL);
+               auth_context->remote_subkey = saved_remote_subkey;
+           }
+
+           if (ret)
+               return(ret);
+       } /*We got an ap_rep*/
+       else
+           return (KRB5KRB_AP_ERR_MODIFIED);
+    } /*Response instead of error*/
+
+/*
+** validate the cleartext length 
+*/
+    if (clearresult.length < 2) {
+       ret = KRB5KRB_AP_ERR_MODIFIED;
+       goto cleanup;
+    }
+/*
+** now decode the result -
+*/
+    ptr = clearresult.data;
+
+    *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+    ptr += 2;
+
+/*
+** result code 5 is access denied
+*/
+    if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5))
+    {
+       ret = KRB5KRB_AP_ERR_MODIFIED;
+       goto cleanup;
+    }
+/*
+** all success replies should be authenticated/encrypted
+*/
+    if( (ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS) )
+    {
+       ret = KRB5KRB_AP_ERR_MODIFIED;
+       goto cleanup;
+    }
+
+    if (result_data) {
+       result_data->length = (clearresult.data + clearresult.length) - ptr;
+
+       if (result_data->length)
+       {
+           result_data->data = (char *) malloc(result_data->length);
+           if (result_data->data)
+               memcpy(result_data->data, ptr, result_data->length);
+       }
+       else
+           result_data->data = NULL;
+    }
+    ret = 0;
+
+ cleanup:
+    krb5_free_data_contents(context, &clearresult);
+    return(ret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_setpw_result_code_string( krb5_context context, int result_code, const char **code_string )
+{
+   switch (result_code)
+   {
+   case KRB5_KPASSWD_MALFORMED:
+      *code_string = "Malformed request error";
+      break;
+   case KRB5_KPASSWD_HARDERROR:
+      *code_string = "Server error";
+      break;
+   case KRB5_KPASSWD_AUTHERROR:
+      *code_string = "Authentication error";
+      break;
+   case KRB5_KPASSWD_SOFTERROR:
+      *code_string = "Password change rejected";
+      break;
+   case 5: /* access denied */
+      *code_string = "Access denied";
+      break;
+   case 6:     /* bad version */
+      *code_string = "Wrong protocol version";
+      break;
+   case 7: /* initial flag is needed */
+      *code_string = "Initial password required";
+      break;
+   case 0:
+         *code_string = "Success";
+   default:
+      *code_string = "Password change failed";
+      break;
+   }
+
+   return(0);
+}
+
index f3406c5b0390af7564a7030067cb7f84064a0c74..112629b1cf99f224979871c341d0f45527ba3c34 100644 (file)
@@ -1,3 +1,16 @@
+2003-04-24  Sam Hartman  <hartmans@mit.edu>
+
+       * changepw.c (krb5_change_set_password): return error from
+       auth_con_setaddrs not last socket errno if auth_con_setaddrs fails 
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+       * changepw.c (krb5_change_set_password): Patches from Paul Nelson
+       to implement Microsoft set password protocol  
+       (krb5_set_password_using_ccache): Use kadmin/changepw in target realm, not local realm and use a two-component principal
+       (krb5_change_set_password): Find the kpasswd server for the realm
+       of the target principal not the client 
+
 2003-04-13  Ken Raeburn  <raeburn@mit.edu>
 
        * read_pwd.c (krb5_read_password): Always free temporary storage
index 60cb3a9158ac89465722b08b2f2f4076f4af1a75..a4f5422f39f3ca10f225677ef307eb8016b2c6b0 100644 (file)
  * or implied warranty.
  *
  */
+/*
+ * krb5_set_password - Implements set password per RFC 3244
+ * Added by Paul W. Nelson, Thursby Software Systems, Inc.
+ */
 
 #define NEED_SOCKETS
 #include "fake-addrinfo.h"
@@ -69,8 +73,16 @@ krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
 }
 
 
+/*
+** The logic for setting and changing a password is mostly the same
+** krb5_change_set_password handles both cases 
+**     if set_password_for is NULL, then a password change is performed,
+**  otherwise, the password is set for the principal indicated in set_password_for
+*/
 krb5_error_code KRB5_CALLCONV
-krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *result_code, krb5_data *result_code_string, krb5_data *result_string)
+krb5_change_set_password(
+       krb5_context context, krb5_creds *creds, char *newpw, krb5_principal set_password_for,
+       int *result_code, krb5_data *result_code_string, krb5_data *result_string)
 {
     krb5_auth_context auth_context;
     krb5_data ap_req, chpw_req, chpw_rep;
@@ -104,7 +116,7 @@ krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *
          goto cleanup;
 
     if ((code = krb5_locate_kpasswd(context,
-                                    krb5_princ_realm(context, creds->client),
+                                    krb5_princ_realm(context, set_password_for),
                                    &al)))
         goto cleanup;
 
@@ -218,14 +230,15 @@ krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *
 
        if ((code = krb5_auth_con_setaddrs(context, auth_context,
                                           &local_kaddr, NULL))) {
-           code = SOCKET_ERRNO;
-           goto cleanup;
+         goto cleanup;
        }
 
-       if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req,
-                                    newpw, &chpw_req)))
+       if( set_password_for )
+               code = krb5int_mk_setpw_req(context, auth_context, &ap_req, set_password_for, newpw, &chpw_req);
+       else
+               code = krb5int_mk_chpw_req(context, auth_context, &ap_req, newpw, &chpw_req);
+       if (code)
        {
-           code = SOCKET_ERRNO;
            goto cleanup;
        }
 
@@ -289,19 +302,23 @@ krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *
                                           NULL, &remote_kaddr)))
            goto cleanup;
 
-       if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
-                                    &local_result_code,
-                                    result_string)))
-           goto cleanup;
+       if( set_password_for )
+               code = krb5int_rd_setpw_rep(context, auth_context, &chpw_rep, &local_result_code, result_string);
+       else
+               code = krb5int_rd_chpw_rep(context, auth_context, &chpw_rep, &local_result_code, result_string);
+       if (code)
+               goto cleanup;
 
        if (result_code)
            *result_code = local_result_code;
 
        if (result_code_string) {
-           if ((code = krb5_chpw_result_code_string(context,
-                                                    local_result_code,
-                                                    &code_string)))
-               goto cleanup;
+               if( set_password_for )
+               code = krb5_setpw_result_code_string(context, local_result_code, (const char **)&code_string);
+               else
+               code = krb5_chpw_result_code_string(context, local_result_code, &code_string);
+               if(code)
+                       goto cleanup;
 
            result_code_string->length = strlen(code_string);
            result_code_string->data = malloc(result_code_string->length);
@@ -343,3 +360,71 @@ cleanup:
 
     return(code);
 }
+
+krb5_error_code KRB5_CALLCONV
+krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *result_code, krb5_data *result_code_string, krb5_data *result_string)
+{
+       return krb5_change_set_password(
+               context, creds, newpw, NULL, result_code, result_code_string, result_string );
+}
+
+/*
+ * krb5_set_password - Implements set password per RFC 3244
+ *
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_password(
+       krb5_context context,
+       krb5_creds *creds,
+       char *newpw,
+       krb5_principal change_password_for,
+       int *result_code, krb5_data *result_code_string, krb5_data *result_string
+       )
+{
+       return krb5_change_set_password(
+               context, creds, newpw, change_password_for, result_code, result_code_string, result_string );
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_password_using_ccache(
+       krb5_context context,
+       krb5_ccache ccache,
+       char *newpw,
+       krb5_principal change_password_for,
+       int *result_code, krb5_data *result_code_string, krb5_data *result_string
+       )
+{
+       krb5_creds              creds;
+       krb5_creds              *credsp;
+       krb5_error_code code;
+
+/*
+** get the proper creds for use with krb5_set_password -
+*/
+       memset( &creds, 0, sizeof(creds) );
+/*
+** first get the principal for the password service -
+*/
+       code = krb5_cc_get_principal( context, ccache, &creds.client );
+       if( !code )
+       {
+               code = krb5_build_principal( context, &creds.server, 
+                               krb5_princ_realm(context, change_password_for)->length,
+                               krb5_princ_realm(context, change_password_for)->data,
+                               "kadmin", "changepw", NULL );
+               if(!code)
+               {
+                       code = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
+                       if( ! code )
+                       {
+                               code = krb5_set_password(context, credsp, newpw, change_password_for,
+                                       result_code, result_code_string,
+                                       result_string);
+                               krb5_free_creds(context, credsp);
+                       }
+               }
+               krb5_free_cred_contents(context, &creds);
+       }
+       return code;
+}
index 53172a85c3a846e017c9d20b81dc8e5fe8df42bb..0d4d5f24d18bbb874bdeca3397e7b0cfcafdd75f 100644 (file)
@@ -204,6 +204,8 @@ EXPORTS
        krb5_sendauth
        krb5_set_default_realm
        krb5_set_default_tgs_enctypes
+krb5_set_password
+krb5_set_password_using_ccache
        krb5_set_principal_realm
        krb5_sname_to_principal
        krb5_string_to_cksumtype