110db1377Sgtb /*
210db1377Sgtb  * lib/krb5/os/changepw.c
310db1377Sgtb  *
410db1377Sgtb  * Copyright 1990,1999,2001 by the Massachusetts Institute of Technology.
510db1377Sgtb  * All Rights Reserved.
610db1377Sgtb  *
710db1377Sgtb  * Export of this software from the United States of America may
810db1377Sgtb  *   require a specific license from the United States Government.
910db1377Sgtb  *   It is the responsibility of any person or organization contemplating
1010db1377Sgtb  *   export to obtain such a license before exporting.
1110db1377Sgtb  *
1210db1377Sgtb  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
1310db1377Sgtb  * distribute this software and its documentation for any purpose and
1410db1377Sgtb  * without fee is hereby granted, provided that the above copyright
1510db1377Sgtb  * notice appear in all copies and that both that copyright notice and
1610db1377Sgtb  * this permission notice appear in supporting documentation, and that
1710db1377Sgtb  * the name of M.I.T. not be used in advertising or publicity pertaining
1810db1377Sgtb  * to distribution of the software without specific, written prior
1910db1377Sgtb  * permission.  Furthermore if you modify this software you must label
2010db1377Sgtb  * your software as modified software and not distribute it in such a
2110db1377Sgtb  * fashion that it might be confused with the original M.I.T. software.
2210db1377Sgtb  * M.I.T. makes no representations about the suitability of
2310db1377Sgtb  * this software for any purpose.  It is provided "as is" without express
2410db1377Sgtb  * or implied warranty.
2510db1377Sgtb  *
2610db1377Sgtb  */
2710db1377Sgtb /*
2810db1377Sgtb  * krb5_set_password - Implements set password per RFC 3244
2910db1377Sgtb  * Added by Paul W. Nelson, Thursby Software Systems, Inc.
30159d09a2SMark Phalan  * Modified by Todd Stecher, Isilon Systems, to use krb1.4 socket infrastructure
3110db1377Sgtb  */
3210db1377Sgtb 
3310db1377Sgtb #include "fake-addrinfo.h"
3410db1377Sgtb #include "k5-int.h"
3510db1377Sgtb #include "os-proto.h"
36159d09a2SMark Phalan #include "cm.h"
3710db1377Sgtb 
3810db1377Sgtb #include <stdio.h>
3910db1377Sgtb #include <errno.h>
4010db1377Sgtb 
4110db1377Sgtb #ifndef GETSOCKNAME_ARG3_TYPE
4210db1377Sgtb #define GETSOCKNAME_ARG3_TYPE int
4310db1377Sgtb #endif
4410db1377Sgtb 
45159d09a2SMark Phalan struct sendto_callback_context {
46159d09a2SMark Phalan     krb5_context 	context;
47159d09a2SMark Phalan     krb5_auth_context 	auth_context;
48159d09a2SMark Phalan     krb5_principal 	set_password_for;
49159d09a2SMark Phalan     char 		*newpw;
50159d09a2SMark Phalan     krb5_data 		ap_req;
51159d09a2SMark Phalan };
52159d09a2SMark Phalan 
53159d09a2SMark Phalan 
5410db1377Sgtb /*
5510db1377Sgtb  * Wrapper function for the two backends
5610db1377Sgtb  */
5710db1377Sgtb 
5810db1377Sgtb static krb5_error_code
krb5_locate_kpasswd(krb5_context context,const krb5_data * realm,struct addrlist * addrlist,krb5_boolean useTcp)5910db1377Sgtb krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
60159d09a2SMark Phalan 		    struct addrlist *addrlist, krb5_boolean useTcp)
6110db1377Sgtb {
6210db1377Sgtb     krb5_error_code code;
63159d09a2SMark Phalan     int sockType = (useTcp ? SOCK_STREAM : SOCK_DGRAM);
64159d09a2SMark Phalan 
65159d09a2SMark Phalan     code = krb5int_locate_server (context, realm, addrlist,
66159d09a2SMark Phalan 				  locate_service_kpasswd, sockType, 0);
6710db1377Sgtb 
6810db1377Sgtb     if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
69159d09a2SMark Phalan 	code = krb5int_locate_server (context, realm, addrlist,
70159d09a2SMark Phalan 				      locate_service_kadmin, SOCK_STREAM, 0);
7110db1377Sgtb 	if (!code) {
7210db1377Sgtb 	    /* Success with admin_server but now we need to change the
73159d09a2SMark Phalan 	       port number to use DEFAULT_KPASSWD_PORT and the socktype.  */
7410db1377Sgtb 	    int i;
75159d09a2SMark Phalan 	    for (i=0; i<addrlist->naddrs; i++) {
76159d09a2SMark Phalan 		struct addrinfo *a = addrlist->addrs[i].ai;
7710db1377Sgtb 		if (a->ai_family == AF_INET)
7810db1377Sgtb 		    sa2sin (a->ai_addr)->sin_port = htons(DEFAULT_KPASSWD_PORT);
79159d09a2SMark Phalan 		if (sockType != SOCK_STREAM)
80159d09a2SMark Phalan 		    a->ai_socktype = sockType;
8110db1377Sgtb 	    }
8210db1377Sgtb 	}
8310db1377Sgtb     }
8410db1377Sgtb     return (code);
8510db1377Sgtb }
8610db1377Sgtb 
8710db1377Sgtb 
88159d09a2SMark Phalan /**
89159d09a2SMark Phalan  * This routine is used for a callback in sendto_kdc.c code. Simply
90159d09a2SMark Phalan  * put, we need the client addr to build the krb_priv portion of the
91159d09a2SMark Phalan  * password request.
92*55fea89dSDan Cross  */
93159d09a2SMark Phalan 
94159d09a2SMark Phalan 
kpasswd_sendto_msg_cleanup(void * callback_context,krb5_data * message)95159d09a2SMark Phalan static void kpasswd_sendto_msg_cleanup (void* callback_context, krb5_data* message)
9610db1377Sgtb {
97159d09a2SMark Phalan     struct sendto_callback_context *ctx = callback_context;
98*55fea89dSDan Cross     krb5_free_data_contents(ctx->context, message);
99159d09a2SMark Phalan }
100*55fea89dSDan Cross 
101159d09a2SMark Phalan 
kpasswd_sendto_msg_callback(struct conn_state * conn,void * callback_context,krb5_data * message)102159d09a2SMark Phalan static int kpasswd_sendto_msg_callback(struct conn_state *conn, void *callback_context, krb5_data* message)
103159d09a2SMark Phalan {
104159d09a2SMark Phalan     krb5_error_code 			code = 0;
105159d09a2SMark Phalan     struct sockaddr_storage 		local_addr;
106159d09a2SMark Phalan     krb5_address 			local_kaddr;
107159d09a2SMark Phalan     struct sendto_callback_context	*ctx = callback_context;
108159d09a2SMark Phalan     GETSOCKNAME_ARG3_TYPE 		addrlen;
109159d09a2SMark Phalan     krb5_data				output;
110159d09a2SMark Phalan 
111159d09a2SMark Phalan     memset (message, 0, sizeof(krb5_data));
112159d09a2SMark Phalan 
113159d09a2SMark Phalan     /*
114159d09a2SMark Phalan      * We need the local addr from the connection socket
115159d09a2SMark Phalan      */
116159d09a2SMark Phalan     addrlen = sizeof(local_addr);
11710db1377Sgtb 
118159d09a2SMark Phalan     if (getsockname(conn->fd, ss2sa(&local_addr), &addrlen) < 0) {
11910db1377Sgtb 	code = SOCKET_ERRNO;
12010db1377Sgtb 	goto cleanup;
12110db1377Sgtb     }
12210db1377Sgtb 
123159d09a2SMark Phalan     /* some brain-dead OS's don't return useful information from
124159d09a2SMark Phalan      * the getsockname call.  Namely, windows and solaris.  */
12510db1377Sgtb 
126159d09a2SMark Phalan     if (ss2sin(&local_addr)->sin_addr.s_addr != 0) {
127159d09a2SMark Phalan 	local_kaddr.addrtype = ADDRTYPE_INET;
128159d09a2SMark Phalan 	local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr);
129159d09a2SMark Phalan 	local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr;
130159d09a2SMark Phalan     } else {
131159d09a2SMark Phalan 	krb5_address **addrs;
13210db1377Sgtb 
133159d09a2SMark Phalan 	code = krb5_os_localaddr(ctx->context, &addrs);
134159d09a2SMark Phalan 	if (code)
135159d09a2SMark Phalan 	    goto cleanup;
13610db1377Sgtb 
137159d09a2SMark Phalan 	local_kaddr.magic = addrs[0]->magic;
138159d09a2SMark Phalan 	local_kaddr.addrtype = addrs[0]->addrtype;
139159d09a2SMark Phalan 	local_kaddr.length = addrs[0]->length;
140159d09a2SMark Phalan 	local_kaddr.contents = malloc(addrs[0]->length);
141159d09a2SMark Phalan 	if (local_kaddr.contents == NULL && addrs[0]->length != 0) {
142159d09a2SMark Phalan 	    code = errno;
143159d09a2SMark Phalan 	    krb5_free_addresses(ctx->context, addrs);
14410db1377Sgtb 	    goto cleanup;
14510db1377Sgtb 	}
146159d09a2SMark Phalan 	memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
14710db1377Sgtb 
148159d09a2SMark Phalan 	krb5_free_addresses(ctx->context, addrs);
149159d09a2SMark Phalan     }
15010db1377Sgtb 
15110db1377Sgtb 
152159d09a2SMark Phalan     /*
153159d09a2SMark Phalan      * TBD:  Does this tamper w/ the auth context in such a way
154159d09a2SMark Phalan      * to break us?  Yes - provide 1 per conn-state / host...
155159d09a2SMark Phalan      */
15610db1377Sgtb 
15710db1377Sgtb 
158159d09a2SMark Phalan     if ((code = krb5_auth_con_setaddrs(ctx->context, ctx->auth_context,
159*55fea89dSDan Cross 				       &local_kaddr, NULL)))
160159d09a2SMark Phalan 	goto cleanup;
16110db1377Sgtb 
162159d09a2SMark Phalan     if (ctx->set_password_for)
163*55fea89dSDan Cross 	code = krb5int_mk_setpw_req(ctx->context,
164*55fea89dSDan Cross 				    ctx->auth_context,
165*55fea89dSDan Cross 				    &ctx->ap_req,
166*55fea89dSDan Cross 				    ctx->set_password_for,
167*55fea89dSDan Cross 				    ctx->newpw,
168159d09a2SMark Phalan 				    &output);
169159d09a2SMark Phalan     else
170*55fea89dSDan Cross 	code = krb5int_mk_chpw_req(ctx->context,
171*55fea89dSDan Cross 				   ctx->auth_context,
172159d09a2SMark Phalan 				   &ctx->ap_req,
173*55fea89dSDan Cross 				   ctx->newpw,
174159d09a2SMark Phalan 				   &output);
175159d09a2SMark Phalan     if (code)
176159d09a2SMark Phalan 	goto cleanup;
17710db1377Sgtb 
178159d09a2SMark Phalan     message->length = output.length;
179159d09a2SMark Phalan     message->data = output.data;
18010db1377Sgtb 
181159d09a2SMark Phalan cleanup:
182159d09a2SMark Phalan     return code;
183159d09a2SMark Phalan }
184159d09a2SMark Phalan 
185159d09a2SMark Phalan 
186159d09a2SMark Phalan /*
187159d09a2SMark Phalan ** The logic for setting and changing a password is mostly the same
188*55fea89dSDan Cross ** krb5_change_set_password handles both cases
189159d09a2SMark Phalan **	if set_password_for is NULL, then a password change is performed,
190159d09a2SMark Phalan **  otherwise, the password is set for the principal indicated in set_password_for
191159d09a2SMark Phalan */
192159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
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)193159d09a2SMark Phalan krb5_change_set_password(krb5_context context, krb5_creds *creds, char *newpw,
194159d09a2SMark Phalan 			 krb5_principal set_password_for,
195159d09a2SMark Phalan 			 int *result_code, krb5_data *result_code_string,
196159d09a2SMark Phalan 			 krb5_data *result_string)
197159d09a2SMark Phalan {
198159d09a2SMark Phalan     krb5_data 			chpw_rep;
199159d09a2SMark Phalan     krb5_address 		remote_kaddr;
200159d09a2SMark Phalan     krb5_boolean		useTcp = 0;
201159d09a2SMark Phalan     GETSOCKNAME_ARG3_TYPE 	addrlen;
202159d09a2SMark Phalan     krb5_error_code 		code = 0;
203159d09a2SMark Phalan     char 			*code_string;
204159d09a2SMark Phalan     int				local_result_code;
205*55fea89dSDan Cross 
206159d09a2SMark Phalan     struct sendto_callback_context  callback_ctx;
207159d09a2SMark Phalan     struct sendto_callback_info	callback_info;
208159d09a2SMark Phalan     struct sockaddr_storage	remote_addr;
209159d09a2SMark Phalan     struct addrlist 		al = ADDRLIST_INIT;
210159d09a2SMark Phalan 
211159d09a2SMark Phalan     memset( &callback_ctx, 0, sizeof(struct sendto_callback_context));
212159d09a2SMark Phalan     callback_ctx.context = context;
213159d09a2SMark Phalan     callback_ctx.newpw = newpw;
214159d09a2SMark Phalan     callback_ctx.set_password_for = set_password_for;
215159d09a2SMark Phalan 
216*55fea89dSDan Cross     if ((code = krb5_auth_con_init(callback_ctx.context,
217159d09a2SMark Phalan 				   &callback_ctx.auth_context)))
218159d09a2SMark Phalan 	goto cleanup;
219159d09a2SMark Phalan 
220*55fea89dSDan Cross     if ((code = krb5_mk_req_extended(callback_ctx.context,
221159d09a2SMark Phalan 				     &callback_ctx.auth_context,
222159d09a2SMark Phalan 				     AP_OPTS_USE_SUBKEY,
223*55fea89dSDan Cross 				     NULL,
224*55fea89dSDan Cross 				     creds,
225159d09a2SMark Phalan 				     &callback_ctx.ap_req)))
226159d09a2SMark Phalan 	goto cleanup;
227159d09a2SMark Phalan 
228159d09a2SMark Phalan     do {
229159d09a2SMark Phalan 	if ((code = krb5_locate_kpasswd(callback_ctx.context,
230159d09a2SMark Phalan 					krb5_princ_realm(callback_ctx.context,
231159d09a2SMark Phalan 							 creds->server),
232159d09a2SMark Phalan 					&al, useTcp)))
233159d09a2SMark Phalan 	    break;
23410db1377Sgtb 
23510db1377Sgtb 	addrlen = sizeof(remote_addr);
23610db1377Sgtb 
237159d09a2SMark Phalan 	callback_info.context = (void*) &callback_ctx;
238159d09a2SMark Phalan 	callback_info.pfn_callback = kpasswd_sendto_msg_callback;
239159d09a2SMark Phalan 	callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
240159d09a2SMark Phalan 
241*55fea89dSDan Cross 	if ((code = krb5int_sendto(callback_ctx.context,
242*55fea89dSDan Cross 				   NULL,
243*55fea89dSDan Cross 				   &al,
244159d09a2SMark Phalan 				   &callback_info,
245159d09a2SMark Phalan 				   &chpw_rep,
246159d09a2SMark Phalan 				   NULL,
247159d09a2SMark Phalan 				   NULL,
248159d09a2SMark Phalan 				   ss2sa(&remote_addr),
249159d09a2SMark Phalan                                    &addrlen,
250159d09a2SMark Phalan 				   NULL,
251159d09a2SMark Phalan 				   NULL,
252159d09a2SMark Phalan 				   NULL
253159d09a2SMark Phalan 		 ))) {
254159d09a2SMark Phalan 
255159d09a2SMark Phalan 	    /*
256159d09a2SMark Phalan 	     * Here we may want to switch to TCP on some errors.
257159d09a2SMark Phalan 	     * right?
258159d09a2SMark Phalan 	     */
259159d09a2SMark Phalan 	    break;
26010db1377Sgtb 	}
26110db1377Sgtb 
26210db1377Sgtb 	remote_kaddr.addrtype = ADDRTYPE_INET;
26310db1377Sgtb 	remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
26410db1377Sgtb 	remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
26510db1377Sgtb 
266*55fea89dSDan Cross 	if ((code = krb5_auth_con_setaddrs(callback_ctx.context,
267*55fea89dSDan Cross 					   callback_ctx.auth_context,
268*55fea89dSDan Cross 					   NULL,
269159d09a2SMark Phalan 					   &remote_kaddr)))
270159d09a2SMark Phalan 	    break;
271159d09a2SMark Phalan 
272159d09a2SMark Phalan 	if (set_password_for)
273*55fea89dSDan Cross 	    code = krb5int_rd_setpw_rep(callback_ctx.context,
274*55fea89dSDan Cross 					callback_ctx.auth_context,
275*55fea89dSDan Cross 					&chpw_rep,
276*55fea89dSDan Cross 					&local_result_code,
277159d09a2SMark Phalan 					result_string);
27810db1377Sgtb 	else
279*55fea89dSDan Cross 	    code = krb5int_rd_chpw_rep(callback_ctx.context,
280*55fea89dSDan Cross 				       callback_ctx.auth_context,
281*55fea89dSDan Cross 				       &chpw_rep,
282*55fea89dSDan Cross 				       &local_result_code,
283159d09a2SMark Phalan 				       result_string);
284159d09a2SMark Phalan 
285159d09a2SMark Phalan 	if (code) {
286159d09a2SMark Phalan 	    if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
287159d09a2SMark Phalan 		krb5int_free_addrlist (&al);
288159d09a2SMark Phalan 		useTcp = 1;
289159d09a2SMark Phalan 		continue;
290159d09a2SMark Phalan 	    }
29110db1377Sgtb 
292159d09a2SMark Phalan 	    break;
29310db1377Sgtb 	}
29410db1377Sgtb 
29510db1377Sgtb 	if (result_code)
29610db1377Sgtb 	    *result_code = local_result_code;
297*55fea89dSDan Cross 
29810db1377Sgtb 	if (result_code_string) {
299159d09a2SMark Phalan 	    if (set_password_for)
300*55fea89dSDan Cross 		code = krb5int_setpw_result_code_string(callback_ctx.context,
301*55fea89dSDan Cross 							local_result_code,
302159d09a2SMark Phalan 							(const char **)&code_string);
303159d09a2SMark Phalan 	    else
304*55fea89dSDan Cross 		code = krb5_chpw_result_code_string(callback_ctx.context,
305*55fea89dSDan Cross 						    local_result_code,
306159d09a2SMark Phalan 						    &code_string);
307159d09a2SMark Phalan 	    if(code)
308159d09a2SMark Phalan 		goto cleanup;
30910db1377Sgtb 
31010db1377Sgtb 	    result_code_string->length = strlen(code_string);
31110db1377Sgtb 	    result_code_string->data = malloc(result_code_string->length);
31210db1377Sgtb 	    if (result_code_string->data == NULL) {
31310db1377Sgtb 		code = ENOMEM;
31410db1377Sgtb 		goto cleanup;
31510db1377Sgtb 	    }
31610db1377Sgtb 	    strncpy(result_code_string->data, code_string, result_code_string->length);
31710db1377Sgtb 	}
31810db1377Sgtb 
319159d09a2SMark Phalan 	if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
320159d09a2SMark Phalan 	    krb5int_free_addrlist (&al);
321159d09a2SMark Phalan 	    useTcp = 1;
322159d09a2SMark Phalan         } else {
323159d09a2SMark Phalan 	    break;
324*55fea89dSDan Cross 	}
325159d09a2SMark Phalan     } while (TRUE);
32610db1377Sgtb 
32710db1377Sgtb cleanup:
328159d09a2SMark Phalan     if (callback_ctx.auth_context != NULL)
329159d09a2SMark Phalan 	krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context);
33010db1377Sgtb 
33110db1377Sgtb     krb5int_free_addrlist (&al);
332159d09a2SMark Phalan     krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req);
33310db1377Sgtb 
33410db1377Sgtb     return(code);
33510db1377Sgtb }
33610db1377Sgtb 
33710db1377Sgtb 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)33810db1377Sgtb krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *result_code, krb5_data *result_code_string, krb5_data *result_string)
33910db1377Sgtb {
34010db1377Sgtb 	return krb5_change_set_password(
34110db1377Sgtb 		context, creds, newpw, NULL, result_code, result_code_string, result_string );
34210db1377Sgtb }
34310db1377Sgtb 
34410db1377Sgtb /*
34510db1377Sgtb  * krb5_set_password - Implements set password per RFC 3244
34610db1377Sgtb  *
34710db1377Sgtb  */
34810db1377Sgtb 
34910db1377Sgtb 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)35010db1377Sgtb krb5_set_password(
35110db1377Sgtb 	krb5_context context,
35210db1377Sgtb 	krb5_creds *creds,
35310db1377Sgtb 	char *newpw,
35410db1377Sgtb 	krb5_principal change_password_for,
35510db1377Sgtb 	int *result_code, krb5_data *result_code_string, krb5_data *result_string
35610db1377Sgtb 	)
35710db1377Sgtb {
35810db1377Sgtb 	return krb5_change_set_password(
35910db1377Sgtb 		context, creds, newpw, change_password_for, result_code, result_code_string, result_string );
36010db1377Sgtb }
36110db1377Sgtb 
36210db1377Sgtb 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)36310db1377Sgtb krb5_set_password_using_ccache(
36410db1377Sgtb 	krb5_context context,
36510db1377Sgtb 	krb5_ccache ccache,
36610db1377Sgtb 	char *newpw,
36710db1377Sgtb 	krb5_principal change_password_for,
36810db1377Sgtb 	int *result_code, krb5_data *result_code_string, krb5_data *result_string
36910db1377Sgtb 	)
37010db1377Sgtb {
371159d09a2SMark Phalan     krb5_creds		creds;
372159d09a2SMark Phalan     krb5_creds		*credsp;
373159d09a2SMark Phalan     krb5_error_code	code;
37410db1377Sgtb 
375159d09a2SMark Phalan     /*
376159d09a2SMark Phalan     ** get the proper creds for use with krb5_set_password -
377159d09a2SMark Phalan     */
378159d09a2SMark Phalan     memset (&creds, 0, sizeof(creds));
379159d09a2SMark Phalan     /*
380159d09a2SMark Phalan     ** first get the principal for the password service -
381159d09a2SMark Phalan     */
382159d09a2SMark Phalan     code = krb5_cc_get_principal (context, ccache, &creds.client);
383159d09a2SMark Phalan     if (!code) {
384*55fea89dSDan Cross 	code = krb5_build_principal(context, &creds.server,
385159d09a2SMark Phalan 				    krb5_princ_realm(context, change_password_for)->length,
386159d09a2SMark Phalan 				    krb5_princ_realm(context, change_password_for)->data,
387159d09a2SMark Phalan 				    "kadmin", "changepw", NULL);
388159d09a2SMark Phalan 	if (!code) {
389159d09a2SMark Phalan 	    code = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
390159d09a2SMark Phalan 	    if (!code) {
391159d09a2SMark Phalan 		code = krb5_set_password(context, credsp, newpw, change_password_for,
392159d09a2SMark Phalan 					 result_code, result_code_string,
393159d09a2SMark Phalan 					 result_string);
394159d09a2SMark Phalan 		krb5_free_creds(context, credsp);
395159d09a2SMark Phalan 	    }
39610db1377Sgtb 	}
397159d09a2SMark Phalan 	krb5_free_cred_contents(context, &creds);
398159d09a2SMark Phalan     }
399159d09a2SMark Phalan     return code;
40010db1377Sgtb }
401