1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 ** set password functions added by Paul W. Nelson, Thursby Software Systems, Inc.
13 krb5int_mk_chpw_req(krb5_context context,
14 krb5_auth_context auth_context,
19 krb5_error_code ret = 0;
22 krb5_replay_data replay;
27 if ((ret = krb5_auth_con_setflags(context, auth_context,
28 KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
31 clearpw.length = strlen(passwd);
32 clearpw.data = passwd;
34 if ((ret = krb5_mk_priv(context, auth_context,
35 &clearpw, &cipherpw, &replay)))
38 packet->length = 6 + ap_req->length + cipherpw.length;
39 packet->data = (char *) malloc(packet->length);
40 if (packet->data == NULL) {
48 store_16_be(packet->length, ptr);
51 /* version == 0x0001 big-endian */
56 /* ap_req length, big-endian */
58 store_16_be(ap_req->length, ptr);
63 memcpy(ptr, ap_req->data, ap_req->length);
64 ptr += ap_req->length;
66 /* krb-priv of password */
68 memcpy(ptr, cipherpw.data, cipherpw.length);
71 if (cipherpw.data != NULL) /* allocated by krb5_mk_priv */
77 /* Decode error_packet as a KRB-ERROR message and retrieve its e-data into
79 static krb5_error_code
80 get_error_edata(krb5_context context, const krb5_data *error_packet,
81 krb5_data **edata_out)
84 krb5_error *krberror = NULL;
88 ret = krb5_rd_error(context, error_packet, &krberror);
92 if (krberror->e_data.data == NULL) {
93 /* Return a krb5 error code based on the error number. */
94 ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code)krberror->error;
98 ret = krb5_copy_data(context, &krberror->e_data, edata_out);
101 krb5_free_error(context, krberror);
105 /* Decode a reply to produce the clear-text output. */
106 static krb5_error_code
107 get_clear_result(krb5_context context, krb5_auth_context auth_context,
108 const krb5_data *packet, krb5_data **clear_out,
109 krb5_boolean *is_error_out)
112 char *ptr, *end = packet->data + packet->length;
113 unsigned int plen, vno, aplen;
114 krb5_data ap_rep, cipher, error;
115 krb5_ap_rep_enc_part *ap_rep_enc;
116 krb5_replay_data replay;
117 krb5_key send_subkey = NULL;
118 krb5_data clear = empty_data();
121 *is_error_out = FALSE;
123 /* Check for an unframed KRB-ERROR (expected for RFC 3244 requests; also
124 * received from MS AD for version 1 requests). */
125 if (krb5_is_krb_error(packet)) {
126 *is_error_out = TRUE;
127 return get_error_edata(context, packet, clear_out);
130 if (packet->length < 6)
131 return KRB5KRB_AP_ERR_MODIFIED;
133 /* Decode and verify the length. */
135 plen = (*ptr++ & 0xff);
136 plen = (plen << 8) | (*ptr++ & 0xff);
137 if (plen != packet->length)
138 return KRB5KRB_AP_ERR_MODIFIED;
140 /* Decode and verify the version number. */
141 vno = (*ptr++ & 0xff);
142 vno = (vno << 8) | (*ptr++ & 0xff);
143 if (vno != 1 && vno != 0xff80)
144 return KRB5KDC_ERR_BAD_PVNO;
146 /* Decode and check the AP-REP length. */
147 aplen = (*ptr++ & 0xff);
148 aplen = (aplen << 8) | (*ptr++ & 0xff);
149 if (aplen > end - ptr)
150 return KRB5KRB_AP_ERR_MODIFIED;
152 /* A zero-length AP-REQ indicates a framed KRB-ERROR response. (Expected
153 * for protocol version 1; specified but unusual for RFC 3244 requests.) */
155 *is_error_out = TRUE;
156 error = make_data(ptr, end - ptr);
157 return get_error_edata(context, &error, clear_out);
160 /* We have an AP-REP. Save send_subkey to later smash recv_subkey. */
161 ret = krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
165 /* Verify the AP-REP. */
166 ap_rep = make_data(ptr, aplen);
167 ptr += ap_rep.length;
168 ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
171 krb5_free_ap_rep_enc_part(context, ap_rep_enc);
173 /* Smash recv_subkey to be send_subkey, per spec. */
174 ret = krb5_auth_con_setrecvsubkey_k(context, auth_context, send_subkey);
178 /* Extract and decrypt the result. */
179 cipher = make_data(ptr, end - ptr);
180 ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay);
184 ret = krb5_copy_data(context, &clear, clear_out);
187 *is_error_out = FALSE;
190 krb5_k_free_key(context, send_subkey);
191 krb5_free_data_contents(context, &clear);
196 krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context,
197 krb5_data *packet, int *result_code_out,
198 krb5_data *result_data_out)
201 krb5_data result_data, *clear = NULL;
202 krb5_boolean is_error;
206 *result_code_out = 0;
207 *result_data_out = empty_data();
209 ret = get_clear_result(context, auth_context, packet, &clear, &is_error);
213 if (clear->length < 2) {
214 ret = KRB5KRB_AP_ERR_MODIFIED;
218 /* Decode and check the result code. */
220 result_code = (*ptr++ & 0xff);
221 result_code = (result_code << 8) | (*ptr++ & 0xff);
222 if (result_code < KRB5_KPASSWD_SUCCESS ||
223 result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED) {
224 ret = KRB5KRB_AP_ERR_MODIFIED;
228 /* Successful replies must not come from errors. */
229 if (is_error && result_code == KRB5_KPASSWD_SUCCESS) {
230 ret = KRB5KRB_AP_ERR_MODIFIED;
234 result_data = make_data(ptr, clear->data + clear->length - ptr);
235 ret = krb5int_copy_data_contents(context, &result_data, result_data_out);
238 *result_code_out = result_code;
241 krb5_free_data(context, clear);
245 krb5_error_code KRB5_CALLCONV
246 krb5_chpw_result_code_string(krb5_context context, int result_code,
249 switch (result_code) {
250 case KRB5_KPASSWD_MALFORMED:
251 *code_string = _("Malformed request error");
253 case KRB5_KPASSWD_HARDERROR:
254 *code_string = _("Server error");
256 case KRB5_KPASSWD_AUTHERROR:
257 *code_string = _("Authentication error");
259 case KRB5_KPASSWD_SOFTERROR:
260 *code_string = _("Password change rejected");
262 case KRB5_KPASSWD_ACCESSDENIED:
263 *code_string = _("Access denied");
265 case KRB5_KPASSWD_BAD_VERSION:
266 *code_string = _("Wrong protocol version");
268 case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:
269 *code_string = _("Initial password required");
272 *code_string = _("Password change failed");
280 krb5int_mk_setpw_req(krb5_context context,
281 krb5_auth_context auth_context,
283 krb5_principal targprinc,
289 krb5_data *encoded_setpw;
290 struct krb5_setpw_req req;
294 cipherpw.data = NULL;
297 if ((ret = krb5_auth_con_setflags(context, auth_context,
298 KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
301 req.target = targprinc;
302 req.password.data = passwd;
303 req.password.length = strlen(passwd);
304 ret = encode_krb5_setpw_req(&req, &encoded_setpw);
309 if ((ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
310 krb5_free_data(context, encoded_setpw);
313 krb5_free_data(context, encoded_setpw);
316 packet->length = 6 + ap_req->length + cipherpw.length;
317 packet->data = (char *) malloc(packet->length);
318 if (packet->data == NULL) {
324 ** build the packet -
326 /* put in the length */
327 store_16_be(packet->length, ptr);
329 /* put in the version */
332 /* the ap_req length is big endian */
333 store_16_be(ap_req->length, ptr);
335 /* put in the request data */
336 memcpy(ptr, ap_req->data, ap_req->length);
337 ptr += ap_req->length;
339 ** put in the "private" password data -
341 memcpy(ptr, cipherpw.data, cipherpw.length);
345 krb5_free_data_contents(context, &cipherpw);
346 if ((ret != 0) && packet->data) {