2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <krb5_locl.h>
43 static krb5_error_code
44 get_kdc_address (krb5_context context
,
50 struct hostent
*hostent
;
55 ret
= krb5_get_krbhst (context
,
63 dot
= strchr (p
, ':');
67 #ifdef HAVE_GETHOSTBYNAME2
68 hostent
= gethostbyname2 (p
, AF_INET6
);
70 hostent
= gethostbyname2 (p
, AF_INET
);
72 hostent
= gethostbyname (p
);
74 krb5_free_krbhst (context
, hostlist
);
76 return h_errno
; /* XXX */
78 return krb5_h_addr2sockaddr (hostent
->h_addrtype
,
79 hostent
->h_addr_list
[0],
82 krb5_getportbyname (context
,
88 static krb5_error_code
89 send_request (krb5_context context
,
90 krb5_auth_context
*auth_context
,
98 krb5_data ap_req_data
;
99 krb5_data krb_priv_data
;
100 krb5_data passwd_data
;
105 struct msghdr msghdr
;
107 krb5_data_zero (&ap_req_data
);
109 ret
= krb5_mk_req_extended (context
,
111 AP_OPTS_MUTUAL_REQUIRED
,
118 passwd_data
.data
= passwd
;
119 passwd_data
.length
= strlen(passwd
);
121 krb5_data_zero (&krb_priv_data
);
123 ret
= krb5_mk_priv (context
,
131 len
= 6 + ap_req_data
.length
+ krb_priv_data
.length
;
133 *p
++ = (len
>> 8) & 0xFF;
134 *p
++ = (len
>> 0) & 0xFF;
137 *p
++ = (ap_req_data
.length
>> 8) & 0xFF;
138 *p
++ = (ap_req_data
.length
>> 0) & 0xFF;
140 memset(&msghdr
, 0, sizeof(msghdr
));
141 msghdr
.msg_name
= (void *)sa
;
142 msghdr
.msg_namelen
= sa_size
;
143 msghdr
.msg_iov
= iov
;
144 msghdr
.msg_iovlen
= sizeof(iov
)/sizeof(*iov
);
146 msghdr
.msg_control
= NULL
;
147 msghdr
.msg_controllen
= 0;
150 iov
[0].iov_base
= (void*)header
;
152 iov
[1].iov_base
= ap_req_data
.data
;
153 iov
[1].iov_len
= ap_req_data
.length
;
154 iov
[2].iov_base
= krb_priv_data
.data
;
155 iov
[2].iov_len
= krb_priv_data
.length
;
157 if (sendmsg (sock
, &msghdr
, 0) < 0)
160 krb5_data_free (&ap_req_data
);
161 krb5_data_free (&krb_priv_data
);
166 str2data (krb5_data
*d
,
175 d
->length
= vasprintf ((char **)&d
->data
, fmt
, args
);
179 static krb5_error_code
180 process_reply (krb5_context context
,
181 krb5_auth_context auth_context
,
184 krb5_data
*result_code_string
,
185 krb5_data
*result_string
)
188 u_char reply
[BUFSIZ
];
190 u_int16_t pkt_len
, pkt_ver
;
191 krb5_data ap_rep_data
;
193 ret
= recvfrom (sock
, reply
, sizeof(reply
), 0, NULL
, NULL
);
198 pkt_len
= (reply
[0] << 8) | (reply
[1]);
199 pkt_ver
= (reply
[2] << 8) | (reply
[3]);
201 if (pkt_len
!= len
) {
202 str2data (result_string
, "client: wrong len in reply");
203 *result_code
= KRB5_KPASSWD_MALFORMED
;
206 if (pkt_ver
!= 0x0001) {
207 str2data (result_string
,
208 "client: wrong version number (%d)", pkt_ver
);
209 *result_code
= KRB5_KPASSWD_MALFORMED
;
213 ap_rep_data
.data
= reply
+ 6;
214 ap_rep_data
.length
= (reply
[4] << 8) | (reply
[5]);
216 if (ap_rep_data
.length
) {
217 krb5_ap_rep_enc_part
*ap_rep
;
221 ret
= krb5_rd_rep (context
,
228 krb5_free_ap_rep_enc_part (context
, ap_rep
);
230 priv_data
.data
= (u_char
*)ap_rep_data
.data
+ ap_rep_data
.length
;
231 priv_data
.length
= len
- ap_rep_data
.length
- 6;
233 ret
= krb5_rd_priv (context
,
239 krb5_data_free (result_code_string
);
243 if (result_code_string
->length
< 2) {
244 *result_code
= KRB5_KPASSWD_MALFORMED
;
245 str2data (result_string
,
246 "client: bad length in result");
249 p
= result_code_string
->data
;
251 *result_code
= (p
[0] << 8) | p
[1];
252 krb5_data_copy (result_string
,
253 (unsigned char*)result_code_string
->data
+ 2,
254 result_code_string
->length
- 2);
261 ret
= decode_KRB_ERROR(reply
+ 6, len
- 6, &error
, &size
);
265 if (error
.e_data
->length
< 2) {
266 krb5_warnx (context
, "too short e_data to print anything usable");
270 p
= error
.e_data
->data
;
271 *result_code
= (p
[0] << 8) | p
[1];
272 krb5_data_copy (result_string
,
274 error
.e_data
->length
- 2);
280 krb5_change_password (krb5_context context
,
284 krb5_data
*result_code_string
,
285 krb5_data
*result_string
)
288 krb5_auth_context auth_context
= NULL
;
296 ret
= krb5_auth_con_init (context
, &auth_context
);
300 buf
= malloc (krb5_max_sockaddr_size ());
305 sa
= (struct sockaddr
*)buf
;
307 ret
= get_kdc_address (context
, creds
->client
->realm
, sa
, &sa_size
);
311 sock
= socket (sa
->sa_family
, SOCK_DGRAM
, 0);
317 krb5_auth_con_setflags (context
, auth_context
,
318 KRB5_AUTH_CONTEXT_DO_SEQUENCE
);
320 for (i
= 0; i
< 5; ++i
) {
324 ret
= send_request (context
,
335 FD_SET(sock
, &fdset
);
339 ret
= select (sock
+ 1, &fdset
, NULL
, NULL
, &tv
);
340 if (ret
< 0 && errno
!= EINTR
)
346 ret
= KRB5_KDC_UNREACH
;
350 ret
= process_reply (context
,
358 krb5_auth_con_free (context
, auth_context
);