2 ** set password functions added by Paul W. Nelson, Thursby Software Systems, Inc.
11 krb5int_mk_chpw_req(krb5_context context,
12 krb5_auth_context auth_context,
17 krb5_error_code ret = 0;
20 krb5_replay_data replay;
25 if ((ret = krb5_auth_con_setflags(context, auth_context,
26 KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
29 clearpw.length = strlen(passwd);
30 clearpw.data = passwd;
32 if ((ret = krb5_mk_priv(context, auth_context,
33 &clearpw, &cipherpw, &replay)))
36 packet->length = 6 + ap_req->length + cipherpw.length;
37 packet->data = (char *) malloc(packet->length);
38 if (packet->data == NULL) {
46 *ptr++ = (packet->length>> 8) & 0xff;
47 *ptr++ = packet->length & 0xff;
49 /* version == 0x0001 big-endian */
54 /* ap_req length, big-endian */
56 *ptr++ = (ap_req->length>>8) & 0xff;
57 *ptr++ = ap_req->length & 0xff;
61 memcpy(ptr, ap_req->data, ap_req->length);
62 ptr += ap_req->length;
64 /* krb-priv of password */
66 memcpy(ptr, cipherpw.data, cipherpw.length);
69 if (cipherpw.data != NULL) /* allocated by krb5_mk_priv */
76 krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context,
77 krb5_data *packet, int *result_code, krb5_data *result_data)
82 krb5_ap_rep_enc_part *ap_rep_enc;
84 krb5_data cipherresult;
85 krb5_data clearresult;
87 krb5_replay_data replay;
90 if (packet->length < 4)
91 /* either this, or the server is printing bad messages,
92 or the caller passed in garbage */
93 return(KRB5KRB_AP_ERR_MODIFIED);
99 plen = (*ptr++ & 0xff);
100 plen = (plen<<8) | (*ptr++ & 0xff);
102 if (plen != packet->length) {
104 * MS KDCs *may* send back a KRB_ERROR. Although
105 * not 100% correct via RFC3244, it's something
106 * we can workaround here.
108 if (krb5_is_krb_error(packet)) {
110 if ((ret = krb5_rd_error(context, packet, &krberror)))
113 if (krberror->e_data.data == NULL) {
114 ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
115 krb5_free_error(context, krberror);
119 return(KRB5KRB_AP_ERR_MODIFIED);
124 /* verify version number */
126 vno = (*ptr++ & 0xff);
127 vno = (vno<<8) | (*ptr++ & 0xff);
130 return(KRB5KDC_ERR_BAD_PVNO);
132 /* read, check ap-rep length */
134 ap_rep.length = (*ptr++ & 0xff);
135 ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);
137 if (ptr + ap_rep.length >= packet->data + packet->length)
138 return(KRB5KRB_AP_ERR_MODIFIED);
143 ptr += ap_rep.length;
146 * Save send_subkey to later smash recv_subkey.
148 ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
152 ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
154 krb5_free_keyblock(context, tmp);
158 krb5_free_ap_rep_enc_part(context, ap_rep_enc);
160 /* extract and decrypt the result */
162 cipherresult.data = ptr;
163 cipherresult.length = (packet->data + packet->length) - ptr;
166 * Smash recv_subkey to be send_subkey, per spec.
168 ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp);
169 krb5_free_keyblock(context, tmp);
173 ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
179 cipherresult.data = ptr;
180 cipherresult.length = (packet->data + packet->length) - ptr;
182 if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
185 clearresult = krberror->e_data;
188 if (clearresult.length < 2) {
189 ret = KRB5KRB_AP_ERR_MODIFIED;
193 ptr = clearresult.data;
195 *result_code = (*ptr++ & 0xff);
196 *result_code = (*result_code<<8) | (*ptr++ & 0xff);
198 if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
199 (*result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)) {
200 ret = KRB5KRB_AP_ERR_MODIFIED;
204 /* all success replies should be authenticated/encrypted */
206 if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
207 ret = KRB5KRB_AP_ERR_MODIFIED;
211 result_data->length = (clearresult.data + clearresult.length) - ptr;
213 if (result_data->length) {
214 result_data->data = (char *) malloc(result_data->length);
215 if (result_data->data == NULL) {
219 memcpy(result_data->data, ptr, result_data->length);
221 result_data->data = NULL;
228 krb5_xfree(clearresult.data);
230 krb5_free_error(context, krberror);
236 krb5_error_code KRB5_CALLCONV
237 krb5_chpw_result_code_string(krb5_context context, int result_code,
240 switch (result_code) {
241 case KRB5_KPASSWD_MALFORMED:
242 *code_string = "Malformed request error";
244 case KRB5_KPASSWD_HARDERROR:
245 *code_string = "Server error";
247 case KRB5_KPASSWD_AUTHERROR:
248 *code_string = "Authentication error";
250 case KRB5_KPASSWD_SOFTERROR:
251 *code_string = "Password change rejected";
254 *code_string = "Password change failed";
262 krb5int_mk_setpw_req(krb5_context context,
263 krb5_auth_context auth_context,
265 krb5_principal targprinc,
271 krb5_data *encoded_setpw;
275 cipherpw.data = NULL;
278 if ((ret = krb5_auth_con_setflags(context, auth_context,
279 KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
282 ret = encode_krb5_setpw_req(targprinc, passwd, &encoded_setpw);
287 if ((ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
288 krb5_free_data(context, encoded_setpw);
291 krb5_free_data(context, encoded_setpw);
294 packet->length = 6 + ap_req->length + cipherpw.length;
295 packet->data = (char *) malloc(packet->length);
296 if (packet->data == NULL) {
302 ** build the packet -
304 /* put in the length */
305 *ptr++ = (packet->length>>8) & 0xff;
306 *ptr++ = packet->length & 0xff;
307 /* put in the version */
310 /* the ap_req length is big endian */
311 *ptr++ = (ap_req->length>>8) & 0xff;
312 *ptr++ = ap_req->length & 0xff;
313 /* put in the request data */
314 memcpy(ptr, ap_req->data, ap_req->length);
315 ptr += ap_req->length;
317 ** put in the "private" password data -
319 memcpy(ptr, cipherpw.data, cipherpw.length);
323 krb5_free_data_contents(context, &cipherpw);
324 if ((ret != 0) && packet->data) {
332 krb5int_rd_setpw_rep(krb5_context context, krb5_auth_context auth_context,
334 int *result_code, krb5_data *result_data)
337 unsigned int message_length, version_number;
339 krb5_ap_rep_enc_part *ap_rep_enc;
341 krb5_data cipherresult;
342 krb5_data clearresult;
343 krb5_keyblock *tmpkey;
345 ** validate the packet length -
347 if (packet->length < 4)
348 return(KRB5KRB_AP_ERR_MODIFIED);
353 ** see if it is an error
355 if (krb5_is_krb_error(packet)) {
356 krb5_error *krberror;
357 if ((ret = krb5_rd_error(context, packet, &krberror)))
359 if (krberror->e_data.data == NULL) {
360 ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
361 krb5_free_error(context, krberror);
364 clearresult = krberror->e_data;
365 krberror->e_data.data = NULL; /*So we can free it later*/
366 krberror->e_data.length = 0;
367 krb5_free_error(context, krberror);
369 } else { /* Not an error*/
372 ** validate the message length -
373 ** length is big endian
375 message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
378 ** make sure the message length and packet length agree -
380 if (message_length != packet->length)
381 return(KRB5KRB_AP_ERR_MODIFIED);
383 ** get the version number -
385 version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
388 ** make sure we support the version returned -
391 ** set password version is 0xff80, change password version is 1
393 if (version_number != 1 && version_number != 0xff80)
394 return(KRB5KDC_ERR_BAD_PVNO);
396 ** now fill in ap_rep with the reply -
399 ** get the reply length -
401 ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
404 ** validate ap_rep length agrees with the packet length -
406 if (ptr + ap_rep.length >= packet->data + packet->length)
407 return(KRB5KRB_AP_ERR_MODIFIED);
409 ** if data was returned, set the ap_rep ptr -
413 ptr += ap_rep.length;
416 * Save send_subkey to later smash recv_subkey.
418 ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmpkey);
422 ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
424 krb5_free_keyblock(context, tmpkey);
428 krb5_free_ap_rep_enc_part(context, ap_rep_enc);
430 ** now decrypt the result -
432 cipherresult.data = ptr;
433 cipherresult.length = (packet->data + packet->length) - ptr;
436 * Smash recv_subkey to be send_subkey, per spec.
438 ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmpkey);
439 krb5_free_keyblock(context, tmpkey);
443 ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
447 } /*We got an ap_rep*/
449 return (KRB5KRB_AP_ERR_MODIFIED);
450 } /*Response instead of error*/
453 ** validate the cleartext length
455 if (clearresult.length < 2) {
456 ret = KRB5KRB_AP_ERR_MODIFIED;
460 ** now decode the result -
462 ptr = clearresult.data;
464 *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
468 ** result code 5 is access denied
470 if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5)) {
471 ret = KRB5KRB_AP_ERR_MODIFIED;
475 ** all success replies should be authenticated/encrypted
477 if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
478 ret = KRB5KRB_AP_ERR_MODIFIED;
483 result_data->length = (clearresult.data + clearresult.length) - ptr;
485 if (result_data->length) {
486 result_data->data = (char *) malloc(result_data->length);
487 if (result_data->data)
488 memcpy(result_data->data, ptr, result_data->length);
490 result_data->data = NULL;
495 krb5_free_data_contents(context, &clearresult);
500 krb5int_setpw_result_code_string(krb5_context context, int result_code,
501 const char **code_string)
503 switch (result_code) {
504 case KRB5_KPASSWD_MALFORMED:
505 *code_string = "Malformed request error";
507 case KRB5_KPASSWD_HARDERROR:
508 *code_string = "Server error";
510 case KRB5_KPASSWD_AUTHERROR:
511 *code_string = "Authentication error";
513 case KRB5_KPASSWD_SOFTERROR:
514 *code_string = "Password change rejected";
516 case 5: /* access denied */
517 *code_string = "Access denied";
519 case 6: /* bad version */
520 *code_string = "Wrong protocol version";
522 case 7: /* initial flag is needed */
523 *code_string = "Initial password required";
526 *code_string = "Success";
528 *code_string = "Password change failed";