8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / krb5 / kadm5 / clnt / chpw.c
blob543f6a51ab82d019604e43c107658430301c36ed
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
7 #include <string.h>
9 #include "k5-int.h"
10 #include <kadm5/admin.h>
11 #include <client_internal.h>
12 #include "auth_con.h"
13 #include <locale.h>
16 krb5_error_code
17 krb5int_mk_chpw_req(
18 krb5_context context,
19 krb5_auth_context auth_context,
20 krb5_data *ap_req,
21 char *passwd,
22 krb5_data *packet)
24 krb5_error_code ret = 0;
25 krb5_data clearpw;
26 krb5_data cipherpw;
27 krb5_replay_data replay;
28 char *ptr;
30 cipherpw.data = NULL;
32 if ((ret = krb5_auth_con_setflags(context, auth_context,
33 KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
34 goto cleanup;
36 clearpw.length = strlen(passwd);
37 clearpw.data = passwd;
39 if ((ret = krb5_mk_priv(context, auth_context,
40 &clearpw, &cipherpw, &replay)))
41 goto cleanup;
43 packet->length = 6 + ap_req->length + cipherpw.length;
44 packet->data = (char *) malloc(packet->length);
45 if (packet->data == NULL)
47 ret = ENOMEM;
48 goto cleanup;
50 ptr = packet->data;
52 /* length */
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.
62 *ptr++ = 0;
63 *ptr++ = 1;
65 /* ap_req length, big-endian */
67 *ptr++ = (ap_req->length>>8) & 0xff;
68 *ptr++ = ap_req->length & 0xff;
70 /* ap-req data */
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);
79 cleanup:
80 if(cipherpw.data != NULL) /* allocated by krb5_mk_priv */
81 free(cipherpw.data);
83 return(ret);
86 krb5_error_code
87 krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
89 char *ptr;
90 int plen, vno;
91 krb5_data ap_rep;
92 krb5_ap_rep_enc_part *ap_rep_enc;
93 krb5_error_code ret;
94 krb5_data cipherresult;
95 krb5_data clearresult;
96 krb5_error *krberror;
97 krb5_replay_data replay;
98 krb5_keyblock *tmp;
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);
106 ptr = packet->data;
108 /* verify length */
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)))
123 return(ret);
125 if (krberror->e_data.data == NULL) {
126 ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
127 krb5_free_error(context, krberror);
128 return (ret);
131 else
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);
158 if (ap_rep.length) {
159 /* verify ap_rep */
160 ap_rep.data = ptr;
161 ptr += ap_rep.length;
164 * Save send_subkey to later smash recv_subkey.
166 ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
167 if (ret)
168 return ret;
170 ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
171 if (ret) {
172 krb5_free_keyblock(context, tmp);
173 return(ret);
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);
188 if (ret)
189 return ret;
191 ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
192 &replay);
194 if (ret)
195 return(ret);
196 } else {
197 cipherresult.data = ptr;
198 cipherresult.length = (packet->data + packet->length) - ptr;
200 if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
201 return(ret);
203 clearresult = krberror->e_data;
206 if (clearresult.length < 2) {
207 ret = KRB5KRB_AP_ERR_MODIFIED;
208 goto cleanup;
211 ptr = clearresult.data;
213 local_result_code = (*ptr++ & 0xff);
214 local_result_code = (local_result_code<<8) | (*ptr++ & 0xff);
216 if (result_code)
217 *result_code = local_result_code;
220 * Make sure the result code is in range for this
221 * protocol.
223 if ((local_result_code < KRB5_KPASSWD_SUCCESS) ||
224 (local_result_code > KRB5_KPASSWD_ETYPE_NOSUPP)) {
225 ret = KRB5KRB_AP_ERR_MODIFIED;
226 goto cleanup;
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;
233 goto cleanup;
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) {
241 ret = ENOMEM;
242 goto cleanup;
244 memcpy(result_data->data, ptr, result_data->length);
245 } else {
246 result_data->data = NULL;
249 ret = 0;
251 cleanup:
252 if (ap_rep.length) {
253 krb5_xfree(clearresult.data);
254 } else {
255 krb5_free_error(context, krberror);
258 return(ret);