2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
10 #include <kadm5/admin.h>
11 #include <client_internal.h>
19 krb5_auth_context auth_context
,
24 krb5_error_code ret
= 0;
27 krb5_replay_data replay
;
32 if ((ret
= krb5_auth_con_setflags(context
, auth_context
,
33 KRB5_AUTH_CONTEXT_DO_SEQUENCE
)))
36 clearpw
.length
= strlen(passwd
);
37 clearpw
.data
= passwd
;
39 if ((ret
= krb5_mk_priv(context
, auth_context
,
40 &clearpw
, &cipherpw
, &replay
)))
43 packet
->length
= 6 + ap_req
->length
+ cipherpw
.length
;
44 packet
->data
= (char *) malloc(packet
->length
);
45 if (packet
->data
== NULL
)
54 *ptr
++ = (packet
->length
>> 8) & 0xff;
55 *ptr
++ = packet
->length
& 0xff;
57 /* version == 0x0001 big-endian
58 * NOTE: when MS and MIT start supporting the latest
59 * version of the passwd change protocol (v2),
60 * this value will change to 2.
65 /* ap_req length, big-endian */
67 *ptr
++ = (ap_req
->length
>>8) & 0xff;
68 *ptr
++ = ap_req
->length
& 0xff;
72 memcpy(ptr
, ap_req
->data
, ap_req
->length
);
73 ptr
+= ap_req
->length
;
75 /* krb-priv of password */
77 memcpy(ptr
, cipherpw
.data
, cipherpw
.length
);
80 if(cipherpw
.data
!= NULL
) /* allocated by krb5_mk_priv */
87 krb5int_rd_chpw_rep(krb5_context context
, krb5_auth_context auth_context
, krb5_data
*packet
, int *result_code
, krb5_data
*result_data
)
92 krb5_ap_rep_enc_part
*ap_rep_enc
;
94 krb5_data cipherresult
;
95 krb5_data clearresult
;
97 krb5_replay_data replay
;
99 int local_result_code
;
101 if (packet
->length
< 4)
102 /* either this, or the server is printing bad messages,
103 or the caller passed in garbage */
104 return(KRB5KRB_AP_ERR_MODIFIED
);
110 plen
= (*ptr
++ & 0xff);
111 plen
= (plen
<<8) | (*ptr
++ & 0xff);
113 if (plen
!= packet
->length
)
116 * MS KDCs *may* send back a KRB_ERROR. Although
117 * not 100% correct via RFC3244, it's something
118 * we can workaround here.
120 if (krb5_is_krb_error(packet
)) {
122 if ((ret
= krb5_rd_error(context
, packet
, &krberror
)))
125 if (krberror
->e_data
.data
== NULL
) {
126 ret
= ERROR_TABLE_BASE_krb5
+ (krb5_error_code
) krberror
->error
;
127 krb5_free_error(context
, krberror
);
133 return(KRB5KRB_AP_ERR_MODIFIED
);
138 /* verify version number */
140 vno
= (*ptr
++ & 0xff);
141 vno
= (vno
<<8) | (*ptr
++ & 0xff);
144 * when the servers update to v2 of the protocol,
145 * "2" will be a valid version number here
147 if (vno
!= 1 && vno
!= 2)
148 return (KRB5KDC_ERR_BAD_PVNO
);
150 /* read, check ap-rep length */
152 ap_rep
.length
= (*ptr
++ & 0xff);
153 ap_rep
.length
= (ap_rep
.length
<<8) | (*ptr
++ & 0xff);
155 if (ptr
+ ap_rep
.length
>= packet
->data
+ packet
->length
)
156 return(KRB5KRB_AP_ERR_MODIFIED
);
161 ptr
+= ap_rep
.length
;
164 * Save send_subkey to later smash recv_subkey.
166 ret
= krb5_auth_con_getsendsubkey(context
, auth_context
, &tmp
);
170 ret
= krb5_rd_rep(context
, auth_context
, &ap_rep
, &ap_rep_enc
);
172 krb5_free_keyblock(context
, tmp
);
176 krb5_free_ap_rep_enc_part(context
, ap_rep_enc
);
178 /* extract and decrypt the result */
180 cipherresult
.data
= ptr
;
181 cipherresult
.length
= (packet
->data
+ packet
->length
) - ptr
;
184 * Smash recv_subkey to be send_subkey, per spec.
186 ret
= krb5_auth_con_setrecvsubkey(context
, auth_context
, tmp
);
187 krb5_free_keyblock(context
, tmp
);
191 ret
= krb5_rd_priv(context
, auth_context
, &cipherresult
, &clearresult
,
197 cipherresult
.data
= ptr
;
198 cipherresult
.length
= (packet
->data
+ packet
->length
) - ptr
;
200 if ((ret
= krb5_rd_error(context
, &cipherresult
, &krberror
)))
203 clearresult
= krberror
->e_data
;
206 if (clearresult
.length
< 2) {
207 ret
= KRB5KRB_AP_ERR_MODIFIED
;
211 ptr
= clearresult
.data
;
213 local_result_code
= (*ptr
++ & 0xff);
214 local_result_code
= (local_result_code
<<8) | (*ptr
++ & 0xff);
217 *result_code
= local_result_code
;
220 * Make sure the result code is in range for this
223 if ((local_result_code
< KRB5_KPASSWD_SUCCESS
) ||
224 (local_result_code
> KRB5_KPASSWD_ETYPE_NOSUPP
)) {
225 ret
= KRB5KRB_AP_ERR_MODIFIED
;
229 /* all success replies should be authenticated/encrypted */
231 if ((ap_rep
.length
== 0) && (local_result_code
== KRB5_KPASSWD_SUCCESS
)) {
232 ret
= KRB5KRB_AP_ERR_MODIFIED
;
236 result_data
->length
= (clearresult
.data
+ clearresult
.length
) - ptr
;
238 if (result_data
->length
) {
239 result_data
->data
= (char *) malloc(result_data
->length
);
240 if (result_data
->data
== NULL
) {
244 memcpy(result_data
->data
, ptr
, result_data
->length
);
246 result_data
->data
= NULL
;
253 krb5_xfree(clearresult
.data
);
255 krb5_free_error(context
, krberror
);