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
);
86 krb5int_rd_chpw_rep(krb5_context context
, krb5_auth_context auth_context
, krb5_data
*packet
, int *result_code
, krb5_data
*result_data
)
91 krb5_ap_rep_enc_part
*ap_rep_enc
;
93 krb5_data cipherresult
;
94 krb5_data clearresult
;
96 krb5_replay_data replay
;
98 int local_result_code
;
100 if (packet
->length
< 4)
101 /* either this, or the server is printing bad messages,
102 or the caller passed in garbage */
103 return(KRB5KRB_AP_ERR_MODIFIED
);
109 plen
= (*ptr
++ & 0xff);
110 plen
= (plen
<<8) | (*ptr
++ & 0xff);
112 if (plen
!= packet
->length
)
115 * MS KDCs *may* send back a KRB_ERROR. Although
116 * not 100% correct via RFC3244, it's something
117 * we can workaround here.
119 if (krb5_is_krb_error(packet
)) {
121 if ((ret
= krb5_rd_error(context
, packet
, &krberror
)))
124 if (krberror
->e_data
.data
== NULL
) {
125 ret
= ERROR_TABLE_BASE_krb5
+ (krb5_error_code
) krberror
->error
;
126 krb5_free_error(context
, krberror
);
132 return(KRB5KRB_AP_ERR_MODIFIED
);
137 /* verify version number */
139 vno
= (*ptr
++ & 0xff);
140 vno
= (vno
<<8) | (*ptr
++ & 0xff);
143 * when the servers update to v2 of the protocol,
144 * "2" will be a valid version number here
146 if (vno
!= 1 && vno
!= 2)
147 return (KRB5KDC_ERR_BAD_PVNO
);
149 /* read, check ap-rep length */
151 ap_rep
.length
= (*ptr
++ & 0xff);
152 ap_rep
.length
= (ap_rep
.length
<<8) | (*ptr
++ & 0xff);
154 if (ptr
+ ap_rep
.length
>= packet
->data
+ packet
->length
)
155 return(KRB5KRB_AP_ERR_MODIFIED
);
160 ptr
+= ap_rep
.length
;
163 * Save send_subkey to later smash recv_subkey.
165 ret
= krb5_auth_con_getsendsubkey(context
, auth_context
, &tmp
);
169 ret
= krb5_rd_rep(context
, auth_context
, &ap_rep
, &ap_rep_enc
);
171 krb5_free_keyblock(context
, tmp
);
175 krb5_free_ap_rep_enc_part(context
, ap_rep_enc
);
177 /* extract and decrypt the result */
179 cipherresult
.data
= ptr
;
180 cipherresult
.length
= (packet
->data
+ packet
->length
) - ptr
;
183 * Smash recv_subkey to be send_subkey, per spec.
185 ret
= krb5_auth_con_setrecvsubkey(context
, auth_context
, tmp
);
186 krb5_free_keyblock(context
, tmp
);
190 ret
= krb5_rd_priv(context
, auth_context
, &cipherresult
, &clearresult
,
196 cipherresult
.data
= ptr
;
197 cipherresult
.length
= (packet
->data
+ packet
->length
) - ptr
;
199 if ((ret
= krb5_rd_error(context
, &cipherresult
, &krberror
)))
202 clearresult
= krberror
->e_data
;
205 if (clearresult
.length
< 2) {
206 ret
= KRB5KRB_AP_ERR_MODIFIED
;
210 ptr
= clearresult
.data
;
212 local_result_code
= (*ptr
++ & 0xff);
213 local_result_code
= (local_result_code
<<8) | (*ptr
++ & 0xff);
216 *result_code
= local_result_code
;
219 * Make sure the result code is in range for this
222 if ((local_result_code
< KRB5_KPASSWD_SUCCESS
) ||
223 (local_result_code
> KRB5_KPASSWD_ETYPE_NOSUPP
)) {
224 ret
= KRB5KRB_AP_ERR_MODIFIED
;
228 /* all success replies should be authenticated/encrypted */
230 if ((ap_rep
.length
== 0) && (local_result_code
== KRB5_KPASSWD_SUCCESS
)) {
231 ret
= KRB5KRB_AP_ERR_MODIFIED
;
235 result_data
->length
= (clearresult
.data
+ clearresult
.length
) - ptr
;
237 if (result_data
->length
) {
238 result_data
->data
= (char *) malloc(result_data
->length
);
239 if (result_data
->data
== NULL
) {
243 memcpy(result_data
->data
, ptr
, result_data
->length
);
245 result_data
->data
= NULL
;
252 krb5_xfree(clearresult
.data
);
254 krb5_free_error(context
, krberror
);