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