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
= roken_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 (&krb_priv_data
);
162 krb5_data_free (&ap_req_data
);
167 str2data (krb5_data
*d
,
174 d
->length
= vasprintf ((char **)&d
->data
, fmt
, args
);
178 static krb5_error_code
179 process_reply (krb5_context context
,
180 krb5_auth_context auth_context
,
183 krb5_data
*result_code_string
,
184 krb5_data
*result_string
)
187 u_char reply
[BUFSIZ
];
189 u_int16_t pkt_len
, pkt_ver
;
190 krb5_data ap_rep_data
;
192 ret
= recvfrom (sock
, reply
, sizeof(reply
), 0, NULL
, NULL
);
197 pkt_len
= (reply
[0] << 8) | (reply
[1]);
198 pkt_ver
= (reply
[2] << 8) | (reply
[3]);
200 if (pkt_len
!= len
) {
201 str2data (result_string
, "client: wrong len in reply");
202 *result_code
= KRB5_KPASSWD_MALFORMED
;
205 if (pkt_ver
!= 0x0001) {
206 str2data (result_string
,
207 "client: wrong version number (%d)", pkt_ver
);
208 *result_code
= KRB5_KPASSWD_MALFORMED
;
212 ap_rep_data
.data
= reply
+ 6;
213 ap_rep_data
.length
= (reply
[4] << 8) | (reply
[5]);
215 if (ap_rep_data
.length
) {
216 krb5_ap_rep_enc_part
*ap_rep
;
220 ret
= krb5_rd_rep (context
,
227 krb5_free_ap_rep_enc_part (context
, ap_rep
);
229 priv_data
.data
= (u_char
*)ap_rep_data
.data
+ ap_rep_data
.length
;
230 priv_data
.length
= len
- ap_rep_data
.length
- 6;
232 ret
= krb5_rd_priv (context
,
238 krb5_data_free (result_code_string
);
242 if (result_code_string
->length
< 2) {
243 *result_code
= KRB5_KPASSWD_MALFORMED
;
244 str2data (result_string
,
245 "client: bad length in result");
248 p
= result_code_string
->data
;
250 *result_code
= (p
[0] << 8) | p
[1];
251 krb5_data_copy (result_string
,
252 (unsigned char*)result_code_string
->data
+ 2,
253 result_code_string
->length
- 2);
260 ret
= decode_KRB_ERROR(reply
+ 6, len
- 6, &error
, &size
);
264 if (error
.e_data
->length
< 2) {
265 krb5_warnx (context
, "too short e_data to print anything usable");
269 p
= error
.e_data
->data
;
270 *result_code
= (p
[0] << 8) | p
[1];
271 krb5_data_copy (result_string
,
273 error
.e_data
->length
- 2);
279 krb5_change_password (krb5_context context
,
283 krb5_data
*result_code_string
,
284 krb5_data
*result_string
)
287 krb5_auth_context auth_context
= NULL
;
294 ret
= krb5_auth_con_init (context
, &auth_context
);
298 buf
= malloc (krb5_max_sockaddr_size ());
303 sa
= (struct sockaddr
*)buf
;
305 ret
= get_kdc_address (context
, creds
->client
->realm
, sa
, &sa_size
);
309 sock
= socket (sa
->sa_family
, SOCK_DGRAM
, 0);
315 krb5_auth_con_setflags (context
, auth_context
,
316 KRB5_AUTH_CONTEXT_DO_SEQUENCE
);
318 for (i
= 0; i
< 5; ++i
) {
322 ret
= send_request (context
,
333 FD_SET(sock
, &fdset
);
337 ret
= select (sock
+ 1, &fdset
, NULL
, NULL
, &tv
);
338 if (ret
< 0 && errno
!= EINTR
)
344 ret
= KRB5_KDC_UNREACH
;
348 ret
= process_reply (context
,
356 krb5_auth_con_free (context
, auth_context
);