xref: /freebsd/crypto/heimdal/lib/krb5/changepw.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34*ae771770SStanislav Sedov #include "krb5_locl.h"
35b528cefcSMark Murray 
36*ae771770SStanislav Sedov #undef __attribute__
37*ae771770SStanislav Sedov #define __attribute__(X)
38*ae771770SStanislav Sedov 
398d4ba808SJacques Vidrine 
408d4ba808SJacques Vidrine static void
418d4ba808SJacques Vidrine str2data (krb5_data *d,
428d4ba808SJacques Vidrine 	  const char *fmt,
438d4ba808SJacques Vidrine 	  ...) __attribute__ ((format (printf, 2, 3)));
448d4ba808SJacques Vidrine 
458d4ba808SJacques Vidrine static void
str2data(krb5_data * d,const char * fmt,...)468d4ba808SJacques Vidrine str2data (krb5_data *d,
478d4ba808SJacques Vidrine 	  const char *fmt,
488d4ba808SJacques Vidrine 	  ...)
498d4ba808SJacques Vidrine {
508d4ba808SJacques Vidrine     va_list args;
51c19800e8SDoug Rabson     char *str;
528d4ba808SJacques Vidrine 
538d4ba808SJacques Vidrine     va_start(args, fmt);
54c19800e8SDoug Rabson     d->length = vasprintf (&str, fmt, args);
558d4ba808SJacques Vidrine     va_end(args);
56c19800e8SDoug Rabson     d->data = str;
578d4ba808SJacques Vidrine }
588d4ba808SJacques Vidrine 
598d4ba808SJacques Vidrine /*
608d4ba808SJacques Vidrine  * Change password protocol defined by
618d4ba808SJacques Vidrine  * draft-ietf-cat-kerb-chg-password-02.txt
628d4ba808SJacques Vidrine  *
638d4ba808SJacques Vidrine  * Share the response part of the protocol with MS set password
648d4ba808SJacques Vidrine  * (RFC3244)
658d4ba808SJacques Vidrine  */
66b528cefcSMark Murray 
67b528cefcSMark Murray static krb5_error_code
chgpw_send_request(krb5_context context,krb5_auth_context * auth_context,krb5_creds * creds,krb5_principal targprinc,int is_stream,rk_socket_t sock,const char * passwd,const char * host)688d4ba808SJacques Vidrine chgpw_send_request (krb5_context context,
69b528cefcSMark Murray 		    krb5_auth_context *auth_context,
70b528cefcSMark Murray 		    krb5_creds *creds,
718d4ba808SJacques Vidrine 		    krb5_principal targprinc,
728d4ba808SJacques Vidrine 		    int is_stream,
73*ae771770SStanislav Sedov 		    rk_socket_t sock,
74c19800e8SDoug Rabson 		    const char *passwd,
75adb0ddaeSAssar Westerlund 		    const char *host)
76b528cefcSMark Murray {
77b528cefcSMark Murray     krb5_error_code ret;
78b528cefcSMark Murray     krb5_data ap_req_data;
79b528cefcSMark Murray     krb5_data krb_priv_data;
80b528cefcSMark Murray     krb5_data passwd_data;
81b528cefcSMark Murray     size_t len;
82b528cefcSMark Murray     u_char header[6];
83b528cefcSMark Murray     struct iovec iov[3];
84b528cefcSMark Murray     struct msghdr msghdr;
85b528cefcSMark Murray 
868d4ba808SJacques Vidrine     if (is_stream)
878d4ba808SJacques Vidrine 	return KRB5_KPASSWD_MALFORMED;
888d4ba808SJacques Vidrine 
898d4ba808SJacques Vidrine     if (targprinc &&
908d4ba808SJacques Vidrine 	krb5_principal_compare(context, creds->client, targprinc) != TRUE)
918d4ba808SJacques Vidrine 	return KRB5_KPASSWD_MALFORMED;
928d4ba808SJacques Vidrine 
93b528cefcSMark Murray     krb5_data_zero (&ap_req_data);
94b528cefcSMark Murray 
95b528cefcSMark Murray     ret = krb5_mk_req_extended (context,
96b528cefcSMark Murray 				auth_context,
970cadf2f4SJacques Vidrine 				AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
98b528cefcSMark Murray 				NULL, /* in_data */
99b528cefcSMark Murray 				creds,
100b528cefcSMark Murray 				&ap_req_data);
101b528cefcSMark Murray     if (ret)
102b528cefcSMark Murray 	return ret;
103b528cefcSMark Murray 
104c19800e8SDoug Rabson     passwd_data.data   = rk_UNCONST(passwd);
105b528cefcSMark Murray     passwd_data.length = strlen(passwd);
106b528cefcSMark Murray 
107b528cefcSMark Murray     krb5_data_zero (&krb_priv_data);
108b528cefcSMark Murray 
109b528cefcSMark Murray     ret = krb5_mk_priv (context,
110b528cefcSMark Murray 			*auth_context,
111b528cefcSMark Murray 			&passwd_data,
112b528cefcSMark Murray 			&krb_priv_data,
113b528cefcSMark Murray 			NULL);
114b528cefcSMark Murray     if (ret)
115b528cefcSMark Murray 	goto out2;
116b528cefcSMark Murray 
117b528cefcSMark Murray     len = 6 + ap_req_data.length + krb_priv_data.length;
118*ae771770SStanislav Sedov     header[0] = (len >> 8) & 0xFF;
119*ae771770SStanislav Sedov     header[1] = (len >> 0) & 0xFF;
120*ae771770SStanislav Sedov     header[2] = 0;
121*ae771770SStanislav Sedov     header[3] = 1;
122*ae771770SStanislav Sedov     header[4] = (ap_req_data.length >> 8) & 0xFF;
123*ae771770SStanislav Sedov     header[5] = (ap_req_data.length >> 0) & 0xFF;
124b528cefcSMark Murray 
125b528cefcSMark Murray     memset(&msghdr, 0, sizeof(msghdr));
1264137ff4cSJacques Vidrine     msghdr.msg_name       = NULL;
1274137ff4cSJacques Vidrine     msghdr.msg_namelen    = 0;
128b528cefcSMark Murray     msghdr.msg_iov        = iov;
129b528cefcSMark Murray     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
130b528cefcSMark Murray #if 0
131b528cefcSMark Murray     msghdr.msg_control    = NULL;
132b528cefcSMark Murray     msghdr.msg_controllen = 0;
133b528cefcSMark Murray #endif
134b528cefcSMark Murray 
135b528cefcSMark Murray     iov[0].iov_base    = (void*)header;
136b528cefcSMark Murray     iov[0].iov_len     = 6;
137b528cefcSMark Murray     iov[1].iov_base    = ap_req_data.data;
138b528cefcSMark Murray     iov[1].iov_len     = ap_req_data.length;
139b528cefcSMark Murray     iov[2].iov_base    = krb_priv_data.data;
140b528cefcSMark Murray     iov[2].iov_len     = krb_priv_data.length;
141b528cefcSMark Murray 
142*ae771770SStanislav Sedov     if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) {
143*ae771770SStanislav Sedov 	ret = rk_SOCK_ERRNO;
144*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "sendmsg %s: %s",
145*ae771770SStanislav Sedov 			       host, strerror(ret));
146adb0ddaeSAssar Westerlund     }
147b528cefcSMark Murray 
148b528cefcSMark Murray     krb5_data_free (&krb_priv_data);
149b528cefcSMark Murray out2:
150b528cefcSMark Murray     krb5_data_free (&ap_req_data);
151b528cefcSMark Murray     return ret;
152b528cefcSMark Murray }
153b528cefcSMark Murray 
1548d4ba808SJacques Vidrine /*
1558d4ba808SJacques Vidrine  * Set password protocol as defined by RFC3244 --
1568d4ba808SJacques Vidrine  * Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols
1578d4ba808SJacques Vidrine  */
1585e9cd1aeSAssar Westerlund 
1598d4ba808SJacques Vidrine static krb5_error_code
setpw_send_request(krb5_context context,krb5_auth_context * auth_context,krb5_creds * creds,krb5_principal targprinc,int is_stream,rk_socket_t sock,const char * passwd,const char * host)1608d4ba808SJacques Vidrine setpw_send_request (krb5_context context,
1618d4ba808SJacques Vidrine 		    krb5_auth_context *auth_context,
1628d4ba808SJacques Vidrine 		    krb5_creds *creds,
1638d4ba808SJacques Vidrine 		    krb5_principal targprinc,
1648d4ba808SJacques Vidrine 		    int is_stream,
165*ae771770SStanislav Sedov 		    rk_socket_t sock,
166c19800e8SDoug Rabson 		    const char *passwd,
1678d4ba808SJacques Vidrine 		    const char *host)
168b528cefcSMark Murray {
1698d4ba808SJacques Vidrine     krb5_error_code ret;
1708d4ba808SJacques Vidrine     krb5_data ap_req_data;
1718d4ba808SJacques Vidrine     krb5_data krb_priv_data;
1728d4ba808SJacques Vidrine     krb5_data pwd_data;
1738d4ba808SJacques Vidrine     ChangePasswdDataMS chpw;
174*ae771770SStanislav Sedov     size_t len = 0;
1758d4ba808SJacques Vidrine     u_char header[4 + 6];
1768d4ba808SJacques Vidrine     u_char *p;
1778d4ba808SJacques Vidrine     struct iovec iov[3];
1788d4ba808SJacques Vidrine     struct msghdr msghdr;
179b528cefcSMark Murray 
1808d4ba808SJacques Vidrine     krb5_data_zero (&ap_req_data);
1818d4ba808SJacques Vidrine 
1828d4ba808SJacques Vidrine     ret = krb5_mk_req_extended (context,
1838d4ba808SJacques Vidrine 				auth_context,
1848d4ba808SJacques Vidrine 				AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
1858d4ba808SJacques Vidrine 				NULL, /* in_data */
1868d4ba808SJacques Vidrine 				creds,
1878d4ba808SJacques Vidrine 				&ap_req_data);
1888d4ba808SJacques Vidrine     if (ret)
1898d4ba808SJacques Vidrine 	return ret;
1908d4ba808SJacques Vidrine 
1918d4ba808SJacques Vidrine     chpw.newpasswd.length = strlen(passwd);
192c19800e8SDoug Rabson     chpw.newpasswd.data = rk_UNCONST(passwd);
1938d4ba808SJacques Vidrine     if (targprinc) {
1948d4ba808SJacques Vidrine 	chpw.targname = &targprinc->name;
1958d4ba808SJacques Vidrine 	chpw.targrealm = &targprinc->realm;
1968d4ba808SJacques Vidrine     } else {
1978d4ba808SJacques Vidrine 	chpw.targname = NULL;
1988d4ba808SJacques Vidrine 	chpw.targrealm = NULL;
1998d4ba808SJacques Vidrine     }
2008d4ba808SJacques Vidrine 
2018d4ba808SJacques Vidrine     ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
2028d4ba808SJacques Vidrine 		       &chpw, &len, ret);
2038d4ba808SJacques Vidrine     if (ret) {
2048d4ba808SJacques Vidrine 	krb5_data_free (&ap_req_data);
2058d4ba808SJacques Vidrine 	return ret;
2068d4ba808SJacques Vidrine     }
2078d4ba808SJacques Vidrine 
2088d4ba808SJacques Vidrine     if(pwd_data.length != len)
2098d4ba808SJacques Vidrine 	krb5_abortx(context, "internal error in ASN.1 encoder");
2108d4ba808SJacques Vidrine 
2118d4ba808SJacques Vidrine     ret = krb5_mk_priv (context,
2128d4ba808SJacques Vidrine 			*auth_context,
2138d4ba808SJacques Vidrine 			&pwd_data,
2148d4ba808SJacques Vidrine 			&krb_priv_data,
2158d4ba808SJacques Vidrine 			NULL);
2168d4ba808SJacques Vidrine     if (ret)
2178d4ba808SJacques Vidrine 	goto out2;
2188d4ba808SJacques Vidrine 
2198d4ba808SJacques Vidrine     len = 6 + ap_req_data.length + krb_priv_data.length;
2208d4ba808SJacques Vidrine     p = header;
2218d4ba808SJacques Vidrine     if (is_stream) {
2228d4ba808SJacques Vidrine 	_krb5_put_int(p, len, 4);
2238d4ba808SJacques Vidrine 	p += 4;
2248d4ba808SJacques Vidrine     }
2258d4ba808SJacques Vidrine     *p++ = (len >> 8) & 0xFF;
2268d4ba808SJacques Vidrine     *p++ = (len >> 0) & 0xFF;
2278d4ba808SJacques Vidrine     *p++ = 0xff;
2288d4ba808SJacques Vidrine     *p++ = 0x80;
2298d4ba808SJacques Vidrine     *p++ = (ap_req_data.length >> 8) & 0xFF;
230*ae771770SStanislav Sedov     *p   = (ap_req_data.length >> 0) & 0xFF;
2318d4ba808SJacques Vidrine 
2328d4ba808SJacques Vidrine     memset(&msghdr, 0, sizeof(msghdr));
2338d4ba808SJacques Vidrine     msghdr.msg_name       = NULL;
2348d4ba808SJacques Vidrine     msghdr.msg_namelen    = 0;
2358d4ba808SJacques Vidrine     msghdr.msg_iov        = iov;
2368d4ba808SJacques Vidrine     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
2378d4ba808SJacques Vidrine #if 0
2388d4ba808SJacques Vidrine     msghdr.msg_control    = NULL;
2398d4ba808SJacques Vidrine     msghdr.msg_controllen = 0;
2408d4ba808SJacques Vidrine #endif
2418d4ba808SJacques Vidrine 
2428d4ba808SJacques Vidrine     iov[0].iov_base    = (void*)header;
2438d4ba808SJacques Vidrine     if (is_stream)
2448d4ba808SJacques Vidrine 	iov[0].iov_len     = 10;
2458d4ba808SJacques Vidrine     else
2468d4ba808SJacques Vidrine 	iov[0].iov_len     = 6;
2478d4ba808SJacques Vidrine     iov[1].iov_base    = ap_req_data.data;
2488d4ba808SJacques Vidrine     iov[1].iov_len     = ap_req_data.length;
2498d4ba808SJacques Vidrine     iov[2].iov_base    = krb_priv_data.data;
2508d4ba808SJacques Vidrine     iov[2].iov_len     = krb_priv_data.length;
2518d4ba808SJacques Vidrine 
252*ae771770SStanislav Sedov     if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) {
253*ae771770SStanislav Sedov 	ret = rk_SOCK_ERRNO;
254*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "sendmsg %s: %s",
255*ae771770SStanislav Sedov 			       host, strerror(ret));
2568d4ba808SJacques Vidrine     }
2578d4ba808SJacques Vidrine 
2588d4ba808SJacques Vidrine     krb5_data_free (&krb_priv_data);
2598d4ba808SJacques Vidrine out2:
2608d4ba808SJacques Vidrine     krb5_data_free (&ap_req_data);
2618d4ba808SJacques Vidrine     krb5_data_free (&pwd_data);
2628d4ba808SJacques Vidrine     return ret;
263b528cefcSMark Murray }
264b528cefcSMark Murray 
265b528cefcSMark Murray static krb5_error_code
process_reply(krb5_context context,krb5_auth_context auth_context,int is_stream,rk_socket_t sock,int * result_code,krb5_data * result_code_string,krb5_data * result_string,const char * host)266b528cefcSMark Murray process_reply (krb5_context context,
267b528cefcSMark Murray 	       krb5_auth_context auth_context,
2688d4ba808SJacques Vidrine 	       int is_stream,
269*ae771770SStanislav Sedov 	       rk_socket_t sock,
270b528cefcSMark Murray 	       int *result_code,
271b528cefcSMark Murray 	       krb5_data *result_code_string,
272adb0ddaeSAssar Westerlund 	       krb5_data *result_string,
273adb0ddaeSAssar Westerlund 	       const char *host)
274b528cefcSMark Murray {
275b528cefcSMark Murray     krb5_error_code ret;
2768d4ba808SJacques Vidrine     u_char reply[1024 * 3];
277*ae771770SStanislav Sedov     size_t len;
278c19800e8SDoug Rabson     uint16_t pkt_len, pkt_ver;
2798d4ba808SJacques Vidrine     krb5_data ap_rep_data;
280adb0ddaeSAssar Westerlund     int save_errno;
281b528cefcSMark Murray 
2828d4ba808SJacques Vidrine     len = 0;
2838d4ba808SJacques Vidrine     if (is_stream) {
2848d4ba808SJacques Vidrine 	while (len < sizeof(reply)) {
2858d4ba808SJacques Vidrine 	    unsigned long size;
2868d4ba808SJacques Vidrine 
2878d4ba808SJacques Vidrine 	    ret = recvfrom (sock, reply + len, sizeof(reply) - len,
2888d4ba808SJacques Vidrine 			    0, NULL, NULL);
289*ae771770SStanislav Sedov 	    if (rk_IS_SOCKET_ERROR(ret)) {
290*ae771770SStanislav Sedov 		save_errno = rk_SOCK_ERRNO;
291*ae771770SStanislav Sedov 		krb5_set_error_message(context, save_errno,
292*ae771770SStanislav Sedov 				       "recvfrom %s: %s",
2938d4ba808SJacques Vidrine 				       host, strerror(save_errno));
2948d4ba808SJacques Vidrine 		return save_errno;
2958d4ba808SJacques Vidrine 	    } else if (ret == 0) {
296*ae771770SStanislav Sedov 		krb5_set_error_message(context, 1,"recvfrom timeout %s", host);
2978d4ba808SJacques Vidrine 		return 1;
2988d4ba808SJacques Vidrine 	    }
2998d4ba808SJacques Vidrine 	    len += ret;
3008d4ba808SJacques Vidrine 	    if (len < 4)
3018d4ba808SJacques Vidrine 		continue;
3028d4ba808SJacques Vidrine 	    _krb5_get_int(reply, &size, 4);
3038d4ba808SJacques Vidrine 	    if (size + 4 < len)
3048d4ba808SJacques Vidrine 		continue;
3058d4ba808SJacques Vidrine 	    memmove(reply, reply + 4, size);
3068d4ba808SJacques Vidrine 	    len = size;
3078d4ba808SJacques Vidrine 	    break;
3088d4ba808SJacques Vidrine 	}
3098d4ba808SJacques Vidrine 	if (len == sizeof(reply)) {
310*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM,
311*ae771770SStanislav Sedov 				   N_("Message too large from %s", "host"),
3128d4ba808SJacques Vidrine 				   host);
3138d4ba808SJacques Vidrine 	    return ENOMEM;
3148d4ba808SJacques Vidrine 	}
3158d4ba808SJacques Vidrine     } else {
316b528cefcSMark Murray 	ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
317*ae771770SStanislav Sedov 	if (rk_IS_SOCKET_ERROR(ret)) {
318*ae771770SStanislav Sedov 	    save_errno = rk_SOCK_ERRNO;
319*ae771770SStanislav Sedov 	    krb5_set_error_message(context, save_errno,
320*ae771770SStanislav Sedov 				   "recvfrom %s: %s",
321adb0ddaeSAssar Westerlund 				   host, strerror(save_errno));
322adb0ddaeSAssar Westerlund 	    return save_errno;
323adb0ddaeSAssar Westerlund 	}
324b528cefcSMark Murray 	len = ret;
3258d4ba808SJacques Vidrine     }
3268d4ba808SJacques Vidrine 
3278d4ba808SJacques Vidrine     if (len < 6) {
3288d4ba808SJacques Vidrine 	str2data (result_string, "server %s sent to too short message "
329*ae771770SStanislav Sedov 		  "(%zu bytes)", host, len);
3308d4ba808SJacques Vidrine 	*result_code = KRB5_KPASSWD_MALFORMED;
3318d4ba808SJacques Vidrine 	return 0;
3328d4ba808SJacques Vidrine     }
3338d4ba808SJacques Vidrine 
334b528cefcSMark Murray     pkt_len = (reply[0] << 8) | (reply[1]);
335b528cefcSMark Murray     pkt_ver = (reply[2] << 8) | (reply[3]);
336b528cefcSMark Murray 
3378d4ba808SJacques Vidrine     if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
3388d4ba808SJacques Vidrine 	KRB_ERROR error;
3398d4ba808SJacques Vidrine 	size_t size;
3408d4ba808SJacques Vidrine 	u_char *p;
3418d4ba808SJacques Vidrine 
3428d4ba808SJacques Vidrine 	memset(&error, 0, sizeof(error));
3438d4ba808SJacques Vidrine 
3448d4ba808SJacques Vidrine 	ret = decode_KRB_ERROR(reply, len, &error, &size);
3458d4ba808SJacques Vidrine 	if (ret)
3468d4ba808SJacques Vidrine 	    return ret;
3478d4ba808SJacques Vidrine 
3488d4ba808SJacques Vidrine 	if (error.e_data->length < 2) {
3498d4ba808SJacques Vidrine 	    str2data(result_string, "server %s sent too short "
3508d4ba808SJacques Vidrine 		     "e_data to print anything usable", host);
3518d4ba808SJacques Vidrine 	    free_KRB_ERROR(&error);
3528d4ba808SJacques Vidrine 	    *result_code = KRB5_KPASSWD_MALFORMED;
3538d4ba808SJacques Vidrine 	    return 0;
3548d4ba808SJacques Vidrine 	}
3558d4ba808SJacques Vidrine 
3568d4ba808SJacques Vidrine 	p = error.e_data->data;
3578d4ba808SJacques Vidrine 	*result_code = (p[0] << 8) | p[1];
3588d4ba808SJacques Vidrine 	if (error.e_data->length == 2)
3598d4ba808SJacques Vidrine 	    str2data(result_string, "server only sent error code");
3608d4ba808SJacques Vidrine 	else
3618d4ba808SJacques Vidrine 	    krb5_data_copy (result_string,
3628d4ba808SJacques Vidrine 			    p + 2,
3638d4ba808SJacques Vidrine 			    error.e_data->length - 2);
3648d4ba808SJacques Vidrine 	free_KRB_ERROR(&error);
3658d4ba808SJacques Vidrine 	return 0;
3668d4ba808SJacques Vidrine     }
3678d4ba808SJacques Vidrine 
368b528cefcSMark Murray     if (pkt_len != len) {
369b528cefcSMark Murray 	str2data (result_string, "client: wrong len in reply");
370b528cefcSMark Murray 	*result_code = KRB5_KPASSWD_MALFORMED;
371b528cefcSMark Murray 	return 0;
372b528cefcSMark Murray     }
3738d4ba808SJacques Vidrine     if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
374b528cefcSMark Murray 	str2data (result_string,
375b528cefcSMark Murray 		  "client: wrong version number (%d)", pkt_ver);
376b528cefcSMark Murray 	*result_code = KRB5_KPASSWD_MALFORMED;
377b528cefcSMark Murray 	return 0;
378b528cefcSMark Murray     }
379b528cefcSMark Murray 
380b528cefcSMark Murray     ap_rep_data.data = reply + 6;
381b528cefcSMark Murray     ap_rep_data.length  = (reply[4] << 8) | (reply[5]);
3828d4ba808SJacques Vidrine 
3838d4ba808SJacques Vidrine     if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
3848d4ba808SJacques Vidrine 	str2data (result_string, "client: wrong AP len in reply");
3858d4ba808SJacques Vidrine 	*result_code = KRB5_KPASSWD_MALFORMED;
3868d4ba808SJacques Vidrine 	return 0;
3878d4ba808SJacques Vidrine     }
388b528cefcSMark Murray 
389b528cefcSMark Murray     if (ap_rep_data.length) {
390b528cefcSMark Murray 	krb5_ap_rep_enc_part *ap_rep;
3918d4ba808SJacques Vidrine 	krb5_data priv_data;
392b528cefcSMark Murray 	u_char *p;
393b528cefcSMark Murray 
3948d4ba808SJacques Vidrine 	priv_data.data   = (u_char*)ap_rep_data.data + ap_rep_data.length;
3958d4ba808SJacques Vidrine 	priv_data.length = len - ap_rep_data.length - 6;
3968d4ba808SJacques Vidrine 
397b528cefcSMark Murray 	ret = krb5_rd_rep (context,
398b528cefcSMark Murray 			   auth_context,
399b528cefcSMark Murray 			   &ap_rep_data,
400b528cefcSMark Murray 			   &ap_rep);
401b528cefcSMark Murray 	if (ret)
402b528cefcSMark Murray 	    return ret;
403b528cefcSMark Murray 
404b528cefcSMark Murray 	krb5_free_ap_rep_enc_part (context, ap_rep);
405b528cefcSMark Murray 
406b528cefcSMark Murray 	ret = krb5_rd_priv (context,
407b528cefcSMark Murray 			    auth_context,
408b528cefcSMark Murray 			    &priv_data,
409b528cefcSMark Murray 			    result_code_string,
410b528cefcSMark Murray 			    NULL);
411b528cefcSMark Murray 	if (ret) {
412b528cefcSMark Murray 	    krb5_data_free (result_code_string);
413b528cefcSMark Murray 	    return ret;
414b528cefcSMark Murray 	}
415b528cefcSMark Murray 
416b528cefcSMark Murray 	if (result_code_string->length < 2) {
417b528cefcSMark Murray 	    *result_code = KRB5_KPASSWD_MALFORMED;
418b528cefcSMark Murray 	    str2data (result_string,
419b528cefcSMark Murray 		      "client: bad length in result");
420b528cefcSMark Murray 	    return 0;
421b528cefcSMark Murray 	}
4228d4ba808SJacques Vidrine 
423b528cefcSMark Murray         p = result_code_string->data;
424b528cefcSMark Murray 
425b528cefcSMark Murray         *result_code = (p[0] << 8) | p[1];
426b528cefcSMark Murray         krb5_data_copy (result_string,
427b528cefcSMark Murray                         (unsigned char*)result_code_string->data + 2,
428b528cefcSMark Murray                         result_code_string->length - 2);
429b528cefcSMark Murray         return 0;
430b528cefcSMark Murray     } else {
431b528cefcSMark Murray 	KRB_ERROR error;
432b528cefcSMark Murray 	size_t size;
433b528cefcSMark Murray 	u_char *p;
434b528cefcSMark Murray 
435b528cefcSMark Murray 	ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
436b528cefcSMark Murray 	if (ret) {
437b528cefcSMark Murray 	    return ret;
438b528cefcSMark Murray 	}
439b528cefcSMark Murray 	if (error.e_data->length < 2) {
440b528cefcSMark Murray 	    krb5_warnx (context, "too short e_data to print anything usable");
441adb0ddaeSAssar Westerlund 	    return 1;		/* XXX */
442b528cefcSMark Murray 	}
443b528cefcSMark Murray 
444b528cefcSMark Murray 	p = error.e_data->data;
445b528cefcSMark Murray 	*result_code = (p[0] << 8) | p[1];
446b528cefcSMark Murray 	krb5_data_copy (result_string,
447b528cefcSMark Murray 			p + 2,
448b528cefcSMark Murray 			error.e_data->length - 2);
449b528cefcSMark Murray 	return 0;
450b528cefcSMark Murray     }
451b528cefcSMark Murray }
452b528cefcSMark Murray 
4538d4ba808SJacques Vidrine 
454adb0ddaeSAssar Westerlund /*
455adb0ddaeSAssar Westerlund  * change the password using the credentials in `creds' (for the
456adb0ddaeSAssar Westerlund  * principal indicated in them) to `newpw', storing the result of
457adb0ddaeSAssar Westerlund  * the operation in `result_*' and an error code or 0.
458adb0ddaeSAssar Westerlund  */
459adb0ddaeSAssar Westerlund 
4608d4ba808SJacques Vidrine typedef krb5_error_code (*kpwd_send_request) (krb5_context,
4618d4ba808SJacques Vidrine 					      krb5_auth_context *,
4628d4ba808SJacques Vidrine 					      krb5_creds *,
4638d4ba808SJacques Vidrine 					      krb5_principal,
4648d4ba808SJacques Vidrine 					      int,
465*ae771770SStanislav Sedov 					      rk_socket_t,
466c19800e8SDoug Rabson 					      const char *,
4678d4ba808SJacques Vidrine 					      const char *);
4688d4ba808SJacques Vidrine typedef krb5_error_code (*kpwd_process_reply) (krb5_context,
4698d4ba808SJacques Vidrine 					       krb5_auth_context,
4708d4ba808SJacques Vidrine 					       int,
471*ae771770SStanislav Sedov 					       rk_socket_t,
4728d4ba808SJacques Vidrine 					       int *,
4738d4ba808SJacques Vidrine 					       krb5_data *,
4748d4ba808SJacques Vidrine 					       krb5_data *,
4758d4ba808SJacques Vidrine 					       const char *);
4768d4ba808SJacques Vidrine 
477c19800e8SDoug Rabson static struct kpwd_proc {
4788d4ba808SJacques Vidrine     const char *name;
4798d4ba808SJacques Vidrine     int flags;
4808d4ba808SJacques Vidrine #define SUPPORT_TCP	1
4818d4ba808SJacques Vidrine #define SUPPORT_UDP	2
4828d4ba808SJacques Vidrine     kpwd_send_request send_req;
4838d4ba808SJacques Vidrine     kpwd_process_reply process_rep;
4848d4ba808SJacques Vidrine } procs[] = {
4858d4ba808SJacques Vidrine     {
4868d4ba808SJacques Vidrine 	"MS set password",
4878d4ba808SJacques Vidrine 	SUPPORT_TCP|SUPPORT_UDP,
4888d4ba808SJacques Vidrine 	setpw_send_request,
4898d4ba808SJacques Vidrine 	process_reply
4908d4ba808SJacques Vidrine     },
4918d4ba808SJacques Vidrine     {
4928d4ba808SJacques Vidrine 	"change password",
4938d4ba808SJacques Vidrine 	SUPPORT_UDP,
4948d4ba808SJacques Vidrine 	chgpw_send_request,
4958d4ba808SJacques Vidrine 	process_reply
4968d4ba808SJacques Vidrine     },
497*ae771770SStanislav Sedov     { NULL, 0, NULL, NULL }
4988d4ba808SJacques Vidrine };
4998d4ba808SJacques Vidrine 
5008d4ba808SJacques Vidrine /*
5018d4ba808SJacques Vidrine  *
5028d4ba808SJacques Vidrine  */
5038d4ba808SJacques Vidrine 
5048d4ba808SJacques Vidrine static krb5_error_code
change_password_loop(krb5_context context,krb5_creds * creds,krb5_principal targprinc,const char * newpw,int * result_code,krb5_data * result_code_string,krb5_data * result_string,struct kpwd_proc * proc)5058d4ba808SJacques Vidrine change_password_loop (krb5_context	context,
506b528cefcSMark Murray 		      krb5_creds	*creds,
5078d4ba808SJacques Vidrine 		      krb5_principal	targprinc,
508c19800e8SDoug Rabson 		      const char	*newpw,
509b528cefcSMark Murray 		      int		*result_code,
510b528cefcSMark Murray 		      krb5_data		*result_code_string,
5118d4ba808SJacques Vidrine 		      krb5_data		*result_string,
5128d4ba808SJacques Vidrine 		      struct kpwd_proc	*proc)
513b528cefcSMark Murray {
514b528cefcSMark Murray     krb5_error_code ret;
515b528cefcSMark Murray     krb5_auth_context auth_context = NULL;
5164137ff4cSJacques Vidrine     krb5_krbhst_handle handle = NULL;
5174137ff4cSJacques Vidrine     krb5_krbhst_info *hi;
518*ae771770SStanislav Sedov     rk_socket_t sock;
519*ae771770SStanislav Sedov     unsigned int i;
5205e9cd1aeSAssar Westerlund     int done = 0;
521c19800e8SDoug Rabson     krb5_realm realm;
522c19800e8SDoug Rabson 
523c19800e8SDoug Rabson     if (targprinc)
524c19800e8SDoug Rabson 	realm = targprinc->realm;
525c19800e8SDoug Rabson     else
526c19800e8SDoug Rabson 	realm = creds->client->realm;
527b528cefcSMark Murray 
528b528cefcSMark Murray     ret = krb5_auth_con_init (context, &auth_context);
529b528cefcSMark Murray     if (ret)
530b528cefcSMark Murray 	return ret;
531b528cefcSMark Murray 
5324137ff4cSJacques Vidrine     krb5_auth_con_setflags (context, auth_context,
5334137ff4cSJacques Vidrine 			    KRB5_AUTH_CONTEXT_DO_SEQUENCE);
5344137ff4cSJacques Vidrine 
5354137ff4cSJacques Vidrine     ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
536b528cefcSMark Murray     if (ret)
537b528cefcSMark Murray 	goto out;
538b528cefcSMark Murray 
5398373020dSJacques Vidrine     while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
5404137ff4cSJacques Vidrine 	struct addrinfo *ai, *a;
5418d4ba808SJacques Vidrine 	int is_stream;
5428d4ba808SJacques Vidrine 
5438d4ba808SJacques Vidrine 	switch (hi->proto) {
5448d4ba808SJacques Vidrine 	case KRB5_KRBHST_UDP:
5458d4ba808SJacques Vidrine 	    if ((proc->flags & SUPPORT_UDP) == 0)
5468d4ba808SJacques Vidrine 		continue;
5478d4ba808SJacques Vidrine 	    is_stream = 0;
5488d4ba808SJacques Vidrine 	    break;
5498d4ba808SJacques Vidrine 	case KRB5_KRBHST_TCP:
5508d4ba808SJacques Vidrine 	    if ((proc->flags & SUPPORT_TCP) == 0)
5518d4ba808SJacques Vidrine 		continue;
5528d4ba808SJacques Vidrine 	    is_stream = 1;
5538d4ba808SJacques Vidrine 	    break;
5548d4ba808SJacques Vidrine 	default:
5558d4ba808SJacques Vidrine 	    continue;
5568d4ba808SJacques Vidrine 	}
5574137ff4cSJacques Vidrine 
5584137ff4cSJacques Vidrine 	ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
5594137ff4cSJacques Vidrine 	if (ret)
5604137ff4cSJacques Vidrine 	    continue;
5614137ff4cSJacques Vidrine 
5625e9cd1aeSAssar Westerlund 	for (a = ai; !done && a != NULL; a = a->ai_next) {
5635e9cd1aeSAssar Westerlund 	    int replied = 0;
564b528cefcSMark Murray 
565*ae771770SStanislav Sedov 	    sock = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol);
566*ae771770SStanislav Sedov 	    if (rk_IS_BAD_SOCKET(sock))
567b528cefcSMark Murray 		continue;
568*ae771770SStanislav Sedov 	    rk_cloexec(sock);
569b528cefcSMark Murray 
5704137ff4cSJacques Vidrine 	    ret = connect(sock, a->ai_addr, a->ai_addrlen);
571*ae771770SStanislav Sedov 	    if (rk_IS_SOCKET_ERROR(ret)) {
572*ae771770SStanislav Sedov 		rk_closesocket (sock);
5734137ff4cSJacques Vidrine 		goto out;
5744137ff4cSJacques Vidrine 	    }
5754137ff4cSJacques Vidrine 
5764137ff4cSJacques Vidrine 	    ret = krb5_auth_con_genaddrs (context, auth_context, sock,
5774137ff4cSJacques Vidrine 					  KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
5784137ff4cSJacques Vidrine 	    if (ret) {
579*ae771770SStanislav Sedov 		rk_closesocket (sock);
5804137ff4cSJacques Vidrine 		goto out;
5814137ff4cSJacques Vidrine 	    }
5824137ff4cSJacques Vidrine 
5835e9cd1aeSAssar Westerlund 	    for (i = 0; !done && i < 5; ++i) {
584b528cefcSMark Murray 		fd_set fdset;
585b528cefcSMark Murray 		struct timeval tv;
586b528cefcSMark Murray 
5875e9cd1aeSAssar Westerlund 		if (!replied) {
5885e9cd1aeSAssar Westerlund 		    replied = 0;
5898d4ba808SJacques Vidrine 
5908d4ba808SJacques Vidrine 		    ret = (*proc->send_req) (context,
591b528cefcSMark Murray 					     &auth_context,
592b528cefcSMark Murray 					     creds,
5938d4ba808SJacques Vidrine 					     targprinc,
5948d4ba808SJacques Vidrine 					     is_stream,
595b528cefcSMark Murray 					     sock,
596adb0ddaeSAssar Westerlund 					     newpw,
5974137ff4cSJacques Vidrine 					     hi->hostname);
5985e9cd1aeSAssar Westerlund 		    if (ret) {
599*ae771770SStanislav Sedov 			rk_closesocket(sock);
600b528cefcSMark Murray 			goto out;
6015e9cd1aeSAssar Westerlund 		    }
6025e9cd1aeSAssar Westerlund 		}
6035e9cd1aeSAssar Westerlund 
604*ae771770SStanislav Sedov #ifndef NO_LIMIT_FD_SETSIZE
6055e9cd1aeSAssar Westerlund 		if (sock >= FD_SETSIZE) {
6065e9cd1aeSAssar Westerlund 		    ret = ERANGE;
607*ae771770SStanislav Sedov 		    krb5_set_error_message(context, ret,
608*ae771770SStanislav Sedov 					   "fd %d too large", sock);
609*ae771770SStanislav Sedov 		    rk_closesocket (sock);
6105e9cd1aeSAssar Westerlund 		    goto out;
6115e9cd1aeSAssar Westerlund 		}
612*ae771770SStanislav Sedov #endif
613b528cefcSMark Murray 
614b528cefcSMark Murray 		FD_ZERO(&fdset);
615b528cefcSMark Murray 		FD_SET(sock, &fdset);
616b528cefcSMark Murray 		tv.tv_usec = 0;
6175e9cd1aeSAssar Westerlund 		tv.tv_sec  = 1 + (1 << i);
618b528cefcSMark Murray 
619b528cefcSMark Murray 		ret = select (sock + 1, &fdset, NULL, NULL, &tv);
620*ae771770SStanislav Sedov 		if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) {
621*ae771770SStanislav Sedov 		    rk_closesocket(sock);
6225e9cd1aeSAssar Westerlund 		    goto out;
623b528cefcSMark Murray 		}
6245e9cd1aeSAssar Westerlund 		if (ret == 1) {
6258d4ba808SJacques Vidrine 		    ret = (*proc->process_rep) (context,
626b528cefcSMark Murray 						auth_context,
6278d4ba808SJacques Vidrine 						is_stream,
628b528cefcSMark Murray 						sock,
629b528cefcSMark Murray 						result_code,
630b528cefcSMark Murray 						result_code_string,
631adb0ddaeSAssar Westerlund 						result_string,
6324137ff4cSJacques Vidrine 						hi->hostname);
633b528cefcSMark Murray 		    if (ret == 0)
6345e9cd1aeSAssar Westerlund 			done = 1;
6355e9cd1aeSAssar Westerlund 		    else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
6365e9cd1aeSAssar Westerlund 			replied = 1;
6375e9cd1aeSAssar Westerlund 		} else {
6385e9cd1aeSAssar Westerlund 		    ret = KRB5_KDC_UNREACH;
6395e9cd1aeSAssar Westerlund 		}
6405e9cd1aeSAssar Westerlund 	    }
641*ae771770SStanislav Sedov 	    rk_closesocket (sock);
642b528cefcSMark Murray 	}
6434137ff4cSJacques Vidrine     }
644b528cefcSMark Murray 
645b528cefcSMark Murray  out:
6464137ff4cSJacques Vidrine     krb5_krbhst_free (context, handle);
647b528cefcSMark Murray     krb5_auth_con_free (context, auth_context);
648*ae771770SStanislav Sedov 
649c19800e8SDoug Rabson     if (ret == KRB5_KDC_UNREACH) {
650*ae771770SStanislav Sedov 	krb5_set_error_message(context,
651*ae771770SStanislav Sedov 			       ret,
652*ae771770SStanislav Sedov 			       N_("Unable to reach any changepw server "
653*ae771770SStanislav Sedov 				 " in realm %s", "realm"), realm);
654c19800e8SDoug Rabson 	*result_code = KRB5_KPASSWD_HARDERROR;
655c19800e8SDoug Rabson     }
656b528cefcSMark Murray     return ret;
657b528cefcSMark Murray }
658*ae771770SStanislav Sedov 
659*ae771770SStanislav Sedov #ifndef HEIMDAL_SMALLER
660*ae771770SStanislav Sedov 
661*ae771770SStanislav Sedov static struct kpwd_proc *
find_chpw_proto(const char * name)662*ae771770SStanislav Sedov find_chpw_proto(const char *name)
663*ae771770SStanislav Sedov {
664*ae771770SStanislav Sedov     struct kpwd_proc *p;
665*ae771770SStanislav Sedov     for (p = procs; p->name != NULL; p++) {
666*ae771770SStanislav Sedov 	if (strcmp(p->name, name) == 0)
667*ae771770SStanislav Sedov 	    return p;
668*ae771770SStanislav Sedov     }
669*ae771770SStanislav Sedov     return NULL;
670adb0ddaeSAssar Westerlund }
6714137ff4cSJacques Vidrine 
672*ae771770SStanislav Sedov /**
673*ae771770SStanislav Sedov  * Deprecated: krb5_change_password() is deprecated, use krb5_set_password().
674*ae771770SStanislav Sedov  *
675*ae771770SStanislav Sedov  * @param context a Keberos context
676*ae771770SStanislav Sedov  * @param creds
677*ae771770SStanislav Sedov  * @param newpw
678*ae771770SStanislav Sedov  * @param result_code
679*ae771770SStanislav Sedov  * @param result_code_string
680*ae771770SStanislav Sedov  * @param result_string
681*ae771770SStanislav Sedov  *
682*ae771770SStanislav Sedov  * @return On sucess password is changed.
6838d4ba808SJacques Vidrine 
684*ae771770SStanislav Sedov  * @ingroup @krb5_deprecated
6858d4ba808SJacques Vidrine  */
6868d4ba808SJacques Vidrine 
687*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_change_password(krb5_context context,krb5_creds * creds,const char * newpw,int * result_code,krb5_data * result_code_string,krb5_data * result_string)6888d4ba808SJacques Vidrine krb5_change_password (krb5_context	context,
6898d4ba808SJacques Vidrine 		      krb5_creds	*creds,
690c19800e8SDoug Rabson 		      const char	*newpw,
6918d4ba808SJacques Vidrine 		      int		*result_code,
6928d4ba808SJacques Vidrine 		      krb5_data		*result_code_string,
6938d4ba808SJacques Vidrine 		      krb5_data		*result_string)
694*ae771770SStanislav Sedov     KRB5_DEPRECATED_FUNCTION("Use X instead")
6958d4ba808SJacques Vidrine {
6968d4ba808SJacques Vidrine     struct kpwd_proc *p = find_chpw_proto("change password");
6978d4ba808SJacques Vidrine 
6988d4ba808SJacques Vidrine     *result_code = KRB5_KPASSWD_MALFORMED;
6998d4ba808SJacques Vidrine     result_code_string->data = result_string->data = NULL;
7008d4ba808SJacques Vidrine     result_code_string->length = result_string->length = 0;
7018d4ba808SJacques Vidrine 
7028d4ba808SJacques Vidrine     if (p == NULL)
7038d4ba808SJacques Vidrine 	return KRB5_KPASSWD_MALFORMED;
7048d4ba808SJacques Vidrine 
7058d4ba808SJacques Vidrine     return change_password_loop(context, creds, NULL, newpw,
7068d4ba808SJacques Vidrine 				result_code, result_code_string,
7078d4ba808SJacques Vidrine 				result_string, p);
7088d4ba808SJacques Vidrine }
709*ae771770SStanislav Sedov #endif /* HEIMDAL_SMALLER */
7108d4ba808SJacques Vidrine 
711*ae771770SStanislav Sedov /**
712*ae771770SStanislav Sedov  * Change password using creds.
7138d4ba808SJacques Vidrine  *
714*ae771770SStanislav Sedov  * @param context a Keberos context
715*ae771770SStanislav Sedov  * @param creds The initial kadmin/passwd for the principal or an admin principal
716*ae771770SStanislav Sedov  * @param newpw The new password to set
717*ae771770SStanislav Sedov  * @param targprinc if unset, the default principal is used.
718*ae771770SStanislav Sedov  * @param result_code Result code, KRB5_KPASSWD_SUCCESS is when password is changed.
719*ae771770SStanislav Sedov  * @param result_code_string binary message from the server, contains
720*ae771770SStanislav Sedov  * at least the result_code.
721*ae771770SStanislav Sedov  * @param result_string A message from the kpasswd service or the
722*ae771770SStanislav Sedov  * library in human printable form. The string is NUL terminated.
723*ae771770SStanislav Sedov  *
724*ae771770SStanislav Sedov  * @return On sucess and *result_code is KRB5_KPASSWD_SUCCESS, the password is changed.
725*ae771770SStanislav Sedov 
726*ae771770SStanislav Sedov  * @ingroup @krb5
7278d4ba808SJacques Vidrine  */
7288d4ba808SJacques Vidrine 
729*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_password(krb5_context context,krb5_creds * creds,const char * newpw,krb5_principal targprinc,int * result_code,krb5_data * result_code_string,krb5_data * result_string)7308d4ba808SJacques Vidrine krb5_set_password(krb5_context context,
7318d4ba808SJacques Vidrine 		  krb5_creds *creds,
732c19800e8SDoug Rabson 		  const char *newpw,
7338d4ba808SJacques Vidrine 		  krb5_principal targprinc,
7348d4ba808SJacques Vidrine 		  int *result_code,
7358d4ba808SJacques Vidrine 		  krb5_data *result_code_string,
7368d4ba808SJacques Vidrine 		  krb5_data *result_string)
7378d4ba808SJacques Vidrine {
7388d4ba808SJacques Vidrine     krb5_principal principal = NULL;
7398d4ba808SJacques Vidrine     krb5_error_code ret = 0;
7408d4ba808SJacques Vidrine     int i;
7418d4ba808SJacques Vidrine 
7428d4ba808SJacques Vidrine     *result_code = KRB5_KPASSWD_MALFORMED;
743*ae771770SStanislav Sedov     krb5_data_zero(result_code_string);
744*ae771770SStanislav Sedov     krb5_data_zero(result_string);
7458d4ba808SJacques Vidrine 
7468d4ba808SJacques Vidrine     if (targprinc == NULL) {
7478d4ba808SJacques Vidrine 	ret = krb5_get_default_principal(context, &principal);
7488d4ba808SJacques Vidrine 	if (ret)
7498d4ba808SJacques Vidrine 	    return ret;
7508d4ba808SJacques Vidrine     } else
7518d4ba808SJacques Vidrine 	principal = targprinc;
7528d4ba808SJacques Vidrine 
7538d4ba808SJacques Vidrine     for (i = 0; procs[i].name != NULL; i++) {
7548d4ba808SJacques Vidrine 	*result_code = 0;
755c19800e8SDoug Rabson 	ret = change_password_loop(context, creds, principal, newpw,
7568d4ba808SJacques Vidrine 				   result_code, result_code_string,
7578d4ba808SJacques Vidrine 				   result_string,
7588d4ba808SJacques Vidrine 				   &procs[i]);
7598d4ba808SJacques Vidrine 	if (ret == 0 && *result_code == 0)
7608d4ba808SJacques Vidrine 	    break;
7618d4ba808SJacques Vidrine     }
7628d4ba808SJacques Vidrine 
7638d4ba808SJacques Vidrine     if (targprinc == NULL)
7648d4ba808SJacques Vidrine 	krb5_free_principal(context, principal);
7658d4ba808SJacques Vidrine     return ret;
7668d4ba808SJacques Vidrine }
7678d4ba808SJacques Vidrine 
7688d4ba808SJacques Vidrine /*
7698d4ba808SJacques Vidrine  *
7708d4ba808SJacques Vidrine  */
7718d4ba808SJacques Vidrine 
772*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_set_password_using_ccache(krb5_context context,krb5_ccache ccache,const char * newpw,krb5_principal targprinc,int * result_code,krb5_data * result_code_string,krb5_data * result_string)7738d4ba808SJacques Vidrine krb5_set_password_using_ccache(krb5_context context,
7748d4ba808SJacques Vidrine 			       krb5_ccache ccache,
775c19800e8SDoug Rabson 			       const char *newpw,
7768d4ba808SJacques Vidrine 			       krb5_principal targprinc,
7778d4ba808SJacques Vidrine 			       int *result_code,
7788d4ba808SJacques Vidrine 			       krb5_data *result_code_string,
7798d4ba808SJacques Vidrine 			       krb5_data *result_string)
7808d4ba808SJacques Vidrine {
7818d4ba808SJacques Vidrine     krb5_creds creds, *credsp;
7828d4ba808SJacques Vidrine     krb5_error_code ret;
7838d4ba808SJacques Vidrine     krb5_principal principal = NULL;
7848d4ba808SJacques Vidrine 
7858d4ba808SJacques Vidrine     *result_code = KRB5_KPASSWD_MALFORMED;
7868d4ba808SJacques Vidrine     result_code_string->data = result_string->data = NULL;
7878d4ba808SJacques Vidrine     result_code_string->length = result_string->length = 0;
7888d4ba808SJacques Vidrine 
7898d4ba808SJacques Vidrine     memset(&creds, 0, sizeof(creds));
7908d4ba808SJacques Vidrine 
7918d4ba808SJacques Vidrine     if (targprinc == NULL) {
7928d4ba808SJacques Vidrine 	ret = krb5_cc_get_principal(context, ccache, &principal);
7938d4ba808SJacques Vidrine 	if (ret)
7948d4ba808SJacques Vidrine 	    return ret;
7958d4ba808SJacques Vidrine     } else
7968d4ba808SJacques Vidrine 	principal = targprinc;
7978d4ba808SJacques Vidrine 
7988d4ba808SJacques Vidrine     ret = krb5_make_principal(context, &creds.server,
7998d4ba808SJacques Vidrine 			      krb5_principal_get_realm(context, principal),
8008d4ba808SJacques Vidrine 			      "kadmin", "changepw", NULL);
8018d4ba808SJacques Vidrine     if (ret)
8028d4ba808SJacques Vidrine 	goto out;
8038d4ba808SJacques Vidrine 
8048d4ba808SJacques Vidrine     ret = krb5_cc_get_principal(context, ccache, &creds.client);
8058d4ba808SJacques Vidrine     if (ret) {
8068d4ba808SJacques Vidrine         krb5_free_principal(context, creds.server);
8078d4ba808SJacques Vidrine 	goto out;
8088d4ba808SJacques Vidrine     }
8098d4ba808SJacques Vidrine 
8108d4ba808SJacques Vidrine     ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
8118d4ba808SJacques Vidrine     krb5_free_principal(context, creds.server);
8128d4ba808SJacques Vidrine     krb5_free_principal(context, creds.client);
8138d4ba808SJacques Vidrine     if (ret)
8148d4ba808SJacques Vidrine 	goto out;
8158d4ba808SJacques Vidrine 
8168d4ba808SJacques Vidrine     ret = krb5_set_password(context,
8178d4ba808SJacques Vidrine 			    credsp,
8188d4ba808SJacques Vidrine 			    newpw,
8198d4ba808SJacques Vidrine 			    principal,
8208d4ba808SJacques Vidrine 			    result_code,
8218d4ba808SJacques Vidrine 			    result_code_string,
8228d4ba808SJacques Vidrine 			    result_string);
8238d4ba808SJacques Vidrine 
8248d4ba808SJacques Vidrine     krb5_free_creds(context, credsp);
8258d4ba808SJacques Vidrine 
8268d4ba808SJacques Vidrine     return ret;
8278d4ba808SJacques Vidrine  out:
8288d4ba808SJacques Vidrine     if (targprinc == NULL)
8298d4ba808SJacques Vidrine 	krb5_free_principal(context, principal);
8308d4ba808SJacques Vidrine     return ret;
8318d4ba808SJacques Vidrine }
8328d4ba808SJacques Vidrine 
8338d4ba808SJacques Vidrine /*
8348d4ba808SJacques Vidrine  *
8358d4ba808SJacques Vidrine  */
8368d4ba808SJacques Vidrine 
837*ae771770SStanislav Sedov KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
krb5_passwd_result_to_string(krb5_context context,int result)8384137ff4cSJacques Vidrine krb5_passwd_result_to_string (krb5_context context,
8394137ff4cSJacques Vidrine 			      int result)
8404137ff4cSJacques Vidrine {
8414137ff4cSJacques Vidrine     static const char *strings[] = {
8424137ff4cSJacques Vidrine 	"Success",
8434137ff4cSJacques Vidrine 	"Malformed",
8444137ff4cSJacques Vidrine 	"Hard error",
8454137ff4cSJacques Vidrine 	"Auth error",
8468d4ba808SJacques Vidrine 	"Soft error" ,
8478d4ba808SJacques Vidrine 	"Access denied",
8488d4ba808SJacques Vidrine 	"Bad version",
8498d4ba808SJacques Vidrine 	"Initial flag needed"
8504137ff4cSJacques Vidrine     };
8514137ff4cSJacques Vidrine 
8528d4ba808SJacques Vidrine     if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)
8534137ff4cSJacques Vidrine 	return "unknown result code";
8544137ff4cSJacques Vidrine     else
8554137ff4cSJacques Vidrine 	return strings[result];
8564137ff4cSJacques Vidrine }
857