1ba7b222eSGlenn Barry /*
2ba7b222eSGlenn Barry * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3ba7b222eSGlenn Barry * Use is subject to license terms.
4ba7b222eSGlenn Barry */
510db1377Sgtb /*
610db1377Sgtb ** set password functions added by Paul W. Nelson, Thursby Software Systems, Inc.
710db1377Sgtb */
810db1377Sgtb #include <string.h>
910db1377Sgtb
1010db1377Sgtb #include "k5-int.h"
11159d09a2SMark Phalan /* Solaris Kerberos */
12159d09a2SMark Phalan /* #include "krb5_err.h" */
1310db1377Sgtb #include "auth_con.h"
1410db1377Sgtb
1510db1377Sgtb
16*55fea89dSDan Cross krb5_error_code
krb5int_mk_chpw_req(krb5_context context,krb5_auth_context auth_context,krb5_data * ap_req,char * passwd,krb5_data * packet)17159d09a2SMark Phalan krb5int_mk_chpw_req(
18*55fea89dSDan Cross krb5_context context,
19*55fea89dSDan Cross krb5_auth_context auth_context,
20159d09a2SMark Phalan krb5_data *ap_req,
21*55fea89dSDan Cross char *passwd,
22159d09a2SMark Phalan krb5_data *packet)
2310db1377Sgtb {
2410db1377Sgtb krb5_error_code ret = 0;
2510db1377Sgtb krb5_data clearpw;
2610db1377Sgtb krb5_data cipherpw;
2710db1377Sgtb krb5_replay_data replay;
2810db1377Sgtb char *ptr;
2910db1377Sgtb
3010db1377Sgtb cipherpw.data = NULL;
3110db1377Sgtb
3210db1377Sgtb if ((ret = krb5_auth_con_setflags(context, auth_context,
3310db1377Sgtb KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
3410db1377Sgtb goto cleanup;
3510db1377Sgtb
3610db1377Sgtb clearpw.length = strlen(passwd);
3710db1377Sgtb clearpw.data = passwd;
3810db1377Sgtb
3910db1377Sgtb if ((ret = krb5_mk_priv(context, auth_context,
4010db1377Sgtb &clearpw, &cipherpw, &replay)))
4110db1377Sgtb goto cleanup;
4210db1377Sgtb
4310db1377Sgtb packet->length = 6 + ap_req->length + cipherpw.length;
4410db1377Sgtb packet->data = (char *) malloc(packet->length);
4510db1377Sgtb if (packet->data == NULL)
46159d09a2SMark Phalan {
4710db1377Sgtb ret = ENOMEM;
4810db1377Sgtb goto cleanup;
49159d09a2SMark Phalan }
5010db1377Sgtb ptr = packet->data;
5110db1377Sgtb
5210db1377Sgtb /* length */
5310db1377Sgtb
54159d09a2SMark Phalan *ptr++ = (packet->length>> 8) & 0xff;
5510db1377Sgtb *ptr++ = packet->length & 0xff;
5610db1377Sgtb
5710db1377Sgtb /* version == 0x0001 big-endian */
5810db1377Sgtb
5910db1377Sgtb *ptr++ = 0;
6010db1377Sgtb *ptr++ = 1;
6110db1377Sgtb
6210db1377Sgtb /* ap_req length, big-endian */
6310db1377Sgtb
6410db1377Sgtb *ptr++ = (ap_req->length>>8) & 0xff;
6510db1377Sgtb *ptr++ = ap_req->length & 0xff;
6610db1377Sgtb
6710db1377Sgtb /* ap-req data */
6810db1377Sgtb
6910db1377Sgtb memcpy(ptr, ap_req->data, ap_req->length);
7010db1377Sgtb ptr += ap_req->length;
7110db1377Sgtb
7210db1377Sgtb /* krb-priv of password */
7310db1377Sgtb
7410db1377Sgtb memcpy(ptr, cipherpw.data, cipherpw.length);
7510db1377Sgtb
7610db1377Sgtb cleanup:
7710db1377Sgtb if(cipherpw.data != NULL) /* allocated by krb5_mk_priv */
7810db1377Sgtb free(cipherpw.data);
79*55fea89dSDan Cross
8010db1377Sgtb return(ret);
8110db1377Sgtb }
8210db1377Sgtb
83*55fea89dSDan Cross krb5_error_code
krb5int_rd_chpw_rep(krb5_context context,krb5_auth_context auth_context,krb5_data * packet,int * result_code,krb5_data * result_data)8410db1377Sgtb krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
8510db1377Sgtb {
8610db1377Sgtb char *ptr;
8710db1377Sgtb int plen, vno;
8810db1377Sgtb krb5_data ap_rep;
8910db1377Sgtb krb5_ap_rep_enc_part *ap_rep_enc;
9010db1377Sgtb krb5_error_code ret;
9110db1377Sgtb krb5_data cipherresult;
9210db1377Sgtb krb5_data clearresult;
93159d09a2SMark Phalan /* Solaris Kerberos */
94159d09a2SMark Phalan krb5_error *krberror = NULL;
9510db1377Sgtb krb5_replay_data replay;
9610db1377Sgtb krb5_keyblock *tmp;
9710db1377Sgtb
9810db1377Sgtb if (packet->length < 4)
9910db1377Sgtb /* either this, or the server is printing bad messages,
10010db1377Sgtb or the caller passed in garbage */
10110db1377Sgtb return(KRB5KRB_AP_ERR_MODIFIED);
10210db1377Sgtb
10310db1377Sgtb ptr = packet->data;
10410db1377Sgtb
10510db1377Sgtb /* verify length */
10610db1377Sgtb
10710db1377Sgtb plen = (*ptr++ & 0xff);
10810db1377Sgtb plen = (plen<<8) | (*ptr++ & 0xff);
10910db1377Sgtb
110*55fea89dSDan Cross if (plen != packet->length)
111159d09a2SMark Phalan {
112159d09a2SMark Phalan /*
113159d09a2SMark Phalan * MS KDCs *may* send back a KRB_ERROR. Although
114159d09a2SMark Phalan * not 100% correct via RFC3244, it's something
115159d09a2SMark Phalan * we can workaround here.
116159d09a2SMark Phalan */
117159d09a2SMark Phalan if (krb5_is_krb_error(packet)) {
118159d09a2SMark Phalan
119159d09a2SMark Phalan if ((ret = krb5_rd_error(context, packet, &krberror)))
120159d09a2SMark Phalan return(ret);
121159d09a2SMark Phalan
122159d09a2SMark Phalan if (krberror->e_data.data == NULL) {
123159d09a2SMark Phalan ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
124159d09a2SMark Phalan krb5_free_error(context, krberror);
125159d09a2SMark Phalan return (ret);
126159d09a2SMark Phalan }
127159d09a2SMark Phalan }
128159d09a2SMark Phalan else
129159d09a2SMark Phalan {
130159d09a2SMark Phalan return(KRB5KRB_AP_ERR_MODIFIED);
131159d09a2SMark Phalan }
132159d09a2SMark Phalan }
133159d09a2SMark Phalan
134159d09a2SMark Phalan /* Solaris Kerberos */
135159d09a2SMark Phalan if (krberror != NULL) {
136159d09a2SMark Phalan krb5_free_error(context, krberror);
137159d09a2SMark Phalan krberror = NULL;
138159d09a2SMark Phalan }
13910db1377Sgtb
14010db1377Sgtb /* verify version number */
14110db1377Sgtb
14210db1377Sgtb vno = (*ptr++ & 0xff);
14310db1377Sgtb vno = (vno<<8) | (*ptr++ & 0xff);
14410db1377Sgtb
14510db1377Sgtb if (vno != 1)
14610db1377Sgtb return(KRB5KDC_ERR_BAD_PVNO);
14710db1377Sgtb
14810db1377Sgtb /* read, check ap-rep length */
14910db1377Sgtb
15010db1377Sgtb ap_rep.length = (*ptr++ & 0xff);
15110db1377Sgtb ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);
15210db1377Sgtb
15310db1377Sgtb if (ptr + ap_rep.length >= packet->data + packet->length)
15410db1377Sgtb return(KRB5KRB_AP_ERR_MODIFIED);
15510db1377Sgtb
15610db1377Sgtb if (ap_rep.length) {
15710db1377Sgtb /* verify ap_rep */
15810db1377Sgtb ap_rep.data = ptr;
15910db1377Sgtb ptr += ap_rep.length;
16010db1377Sgtb
16110db1377Sgtb /*
16210db1377Sgtb * Save send_subkey to later smash recv_subkey.
16310db1377Sgtb */
16410db1377Sgtb ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
16510db1377Sgtb if (ret)
16610db1377Sgtb return ret;
16710db1377Sgtb
16810db1377Sgtb ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
16910db1377Sgtb if (ret) {
17010db1377Sgtb krb5_free_keyblock(context, tmp);
17110db1377Sgtb return(ret);
17210db1377Sgtb }
17310db1377Sgtb
17410db1377Sgtb krb5_free_ap_rep_enc_part(context, ap_rep_enc);
17510db1377Sgtb
17610db1377Sgtb /* extract and decrypt the result */
17710db1377Sgtb
17810db1377Sgtb cipherresult.data = ptr;
17910db1377Sgtb cipherresult.length = (packet->data + packet->length) - ptr;
18010db1377Sgtb
18110db1377Sgtb /*
18210db1377Sgtb * Smash recv_subkey to be send_subkey, per spec.
18310db1377Sgtb */
18410db1377Sgtb ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp);
18510db1377Sgtb krb5_free_keyblock(context, tmp);
18610db1377Sgtb if (ret)
18710db1377Sgtb return ret;
18810db1377Sgtb
18910db1377Sgtb ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
19010db1377Sgtb &replay);
19110db1377Sgtb
19210db1377Sgtb if (ret)
19310db1377Sgtb return(ret);
19410db1377Sgtb } else {
19510db1377Sgtb cipherresult.data = ptr;
19610db1377Sgtb cipherresult.length = (packet->data + packet->length) - ptr;
19710db1377Sgtb
19810db1377Sgtb if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
19910db1377Sgtb return(ret);
20010db1377Sgtb
20110db1377Sgtb clearresult = krberror->e_data;
20210db1377Sgtb }
20310db1377Sgtb
20410db1377Sgtb if (clearresult.length < 2) {
20510db1377Sgtb ret = KRB5KRB_AP_ERR_MODIFIED;
20610db1377Sgtb goto cleanup;
20710db1377Sgtb }
20810db1377Sgtb
20910db1377Sgtb ptr = clearresult.data;
21010db1377Sgtb
21110db1377Sgtb *result_code = (*ptr++ & 0xff);
21210db1377Sgtb *result_code = (*result_code<<8) | (*ptr++ & 0xff);
21310db1377Sgtb
21410db1377Sgtb if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
21510db1377Sgtb (*result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)) {
21610db1377Sgtb ret = KRB5KRB_AP_ERR_MODIFIED;
21710db1377Sgtb goto cleanup;
21810db1377Sgtb }
21910db1377Sgtb
22010db1377Sgtb /* all success replies should be authenticated/encrypted */
22110db1377Sgtb
22210db1377Sgtb if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
22310db1377Sgtb ret = KRB5KRB_AP_ERR_MODIFIED;
22410db1377Sgtb goto cleanup;
22510db1377Sgtb }
22610db1377Sgtb
22710db1377Sgtb result_data->length = (clearresult.data + clearresult.length) - ptr;
22810db1377Sgtb
22910db1377Sgtb if (result_data->length) {
23010db1377Sgtb result_data->data = (char *) malloc(result_data->length);
23110db1377Sgtb if (result_data->data == NULL) {
23210db1377Sgtb ret = ENOMEM;
23310db1377Sgtb goto cleanup;
23410db1377Sgtb }
23510db1377Sgtb memcpy(result_data->data, ptr, result_data->length);
23610db1377Sgtb } else {
23710db1377Sgtb result_data->data = NULL;
23810db1377Sgtb }
23910db1377Sgtb
24010db1377Sgtb ret = 0;
24110db1377Sgtb
24210db1377Sgtb cleanup:
24310db1377Sgtb if (ap_rep.length) {
24410db1377Sgtb krb5_xfree(clearresult.data);
24510db1377Sgtb } else {
24610db1377Sgtb krb5_free_error(context, krberror);
24710db1377Sgtb }
24810db1377Sgtb
24910db1377Sgtb return(ret);
25010db1377Sgtb }
25110db1377Sgtb
25210db1377Sgtb krb5_error_code KRB5_CALLCONV
krb5_chpw_result_code_string(krb5_context context,int result_code,char ** code_string)25310db1377Sgtb krb5_chpw_result_code_string(krb5_context context, int result_code, char **code_string)
25410db1377Sgtb {
25510db1377Sgtb switch (result_code) {
25610db1377Sgtb case KRB5_KPASSWD_MALFORMED:
25710db1377Sgtb *code_string = "Malformed request error";
25810db1377Sgtb break;
25910db1377Sgtb case KRB5_KPASSWD_HARDERROR:
26010db1377Sgtb *code_string = "Server error";
26110db1377Sgtb break;
26210db1377Sgtb case KRB5_KPASSWD_AUTHERROR:
26310db1377Sgtb *code_string = "Authentication error";
26410db1377Sgtb break;
26510db1377Sgtb case KRB5_KPASSWD_SOFTERROR:
26610db1377Sgtb *code_string = "Password change rejected";
26710db1377Sgtb break;
26810db1377Sgtb default:
26910db1377Sgtb *code_string = "Password change failed";
27010db1377Sgtb break;
27110db1377Sgtb }
27210db1377Sgtb
27310db1377Sgtb return(0);
27410db1377Sgtb }
27510db1377Sgtb
276*55fea89dSDan Cross krb5_error_code
krb5int_mk_setpw_req(krb5_context context,krb5_auth_context auth_context,krb5_data * ap_req,krb5_principal targprinc,char * passwd,krb5_data * packet)27710db1377Sgtb krb5int_mk_setpw_req(
27810db1377Sgtb krb5_context context,
27910db1377Sgtb krb5_auth_context auth_context,
28010db1377Sgtb krb5_data *ap_req,
28110db1377Sgtb krb5_principal targprinc,
28210db1377Sgtb char *passwd,
28310db1377Sgtb krb5_data *packet )
28410db1377Sgtb {
28510db1377Sgtb krb5_error_code ret;
28610db1377Sgtb krb5_data cipherpw;
28710db1377Sgtb krb5_data *encoded_setpw;
288ba7b222eSGlenn Barry struct krb5_setpw_req req;
28910db1377Sgtb
29010db1377Sgtb char *ptr;
29110db1377Sgtb
292ba7b222eSGlenn Barry cipherpw.data = NULL;
293ba7b222eSGlenn Barry cipherpw.length = 0;
294*55fea89dSDan Cross
29510db1377Sgtb if ((ret = krb5_auth_con_setflags(context, auth_context,
29610db1377Sgtb KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
29710db1377Sgtb return(ret);
29810db1377Sgtb
299ba7b222eSGlenn Barry req.target = targprinc;
300ba7b222eSGlenn Barry req.password.data = passwd;
301ba7b222eSGlenn Barry req.password.length = strlen(passwd);
302ba7b222eSGlenn Barry ret = encode_krb5_setpw_req(&req, &encoded_setpw);
30310db1377Sgtb if (ret) {
30410db1377Sgtb return ret;
30510db1377Sgtb }
30610db1377Sgtb
30710db1377Sgtb if ( (ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
30810db1377Sgtb krb5_free_data( context, encoded_setpw);
30910db1377Sgtb return(ret);
31010db1377Sgtb }
31110db1377Sgtb krb5_free_data( context, encoded_setpw);
312*55fea89dSDan Cross
31310db1377Sgtb
31410db1377Sgtb packet->length = 6 + ap_req->length + cipherpw.length;
31510db1377Sgtb packet->data = (char *) malloc(packet->length);
31610db1377Sgtb if (packet->data == NULL) {
31710db1377Sgtb ret = ENOMEM;
31810db1377Sgtb goto cleanup;
31910db1377Sgtb }
32010db1377Sgtb ptr = packet->data;
32110db1377Sgtb /*
32210db1377Sgtb ** build the packet -
32310db1377Sgtb */
32410db1377Sgtb /* put in the length */
32510db1377Sgtb *ptr++ = (packet->length>>8) & 0xff;
32610db1377Sgtb *ptr++ = packet->length & 0xff;
32710db1377Sgtb /* put in the version */
32810db1377Sgtb *ptr++ = (char)0xff;
32910db1377Sgtb *ptr++ = (char)0x80;
33010db1377Sgtb /* the ap_req length is big endian */
33110db1377Sgtb *ptr++ = (ap_req->length>>8) & 0xff;
33210db1377Sgtb *ptr++ = ap_req->length & 0xff;
33310db1377Sgtb /* put in the request data */
33410db1377Sgtb memcpy(ptr, ap_req->data, ap_req->length);
33510db1377Sgtb ptr += ap_req->length;
33610db1377Sgtb /*
33710db1377Sgtb ** put in the "private" password data -
33810db1377Sgtb */
33910db1377Sgtb memcpy(ptr, cipherpw.data, cipherpw.length);
34010db1377Sgtb ret = 0;
34110db1377Sgtb cleanup:
34210db1377Sgtb if (cipherpw.data)
34310db1377Sgtb krb5_free_data_contents(context, &cipherpw);
34410db1377Sgtb if ((ret != 0) && packet->data) {
34510db1377Sgtb free( packet->data);
34610db1377Sgtb packet->data = NULL;
34710db1377Sgtb }
34810db1377Sgtb return ret;
34910db1377Sgtb }
35010db1377Sgtb
351*55fea89dSDan Cross krb5_error_code
krb5int_rd_setpw_rep(krb5_context context,krb5_auth_context auth_context,krb5_data * packet,int * result_code,krb5_data * result_data)35210db1377Sgtb krb5int_rd_setpw_rep( krb5_context context, krb5_auth_context auth_context, krb5_data *packet,
35310db1377Sgtb int *result_code, krb5_data *result_data )
35410db1377Sgtb {
35510db1377Sgtb char *ptr;
35610db1377Sgtb unsigned int message_length, version_number;
35710db1377Sgtb krb5_data ap_rep;
35810db1377Sgtb krb5_ap_rep_enc_part *ap_rep_enc;
35910db1377Sgtb krb5_error_code ret;
36010db1377Sgtb krb5_data cipherresult;
36110db1377Sgtb krb5_data clearresult;
36210db1377Sgtb krb5_keyblock *tmpkey;
36310db1377Sgtb /*
36410db1377Sgtb ** validate the packet length -
36510db1377Sgtb */
36610db1377Sgtb if (packet->length < 4)
36710db1377Sgtb return(KRB5KRB_AP_ERR_MODIFIED);
36810db1377Sgtb
36910db1377Sgtb ptr = packet->data;
37010db1377Sgtb
37110db1377Sgtb /*
37210db1377Sgtb ** see if it is an error
37310db1377Sgtb */
37410db1377Sgtb if (krb5_is_krb_error(packet)) {
37510db1377Sgtb krb5_error *krberror;
37610db1377Sgtb if ((ret = krb5_rd_error(context, packet, &krberror)))
37710db1377Sgtb return(ret);
37810db1377Sgtb if (krberror->e_data.data == NULL) {
37910db1377Sgtb ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
38010db1377Sgtb krb5_free_error(context, krberror);
38110db1377Sgtb return (ret);
38210db1377Sgtb }
38310db1377Sgtb clearresult = krberror->e_data;
38410db1377Sgtb krberror->e_data.data = NULL; /*So we can free it later*/
38510db1377Sgtb krberror->e_data.length = 0;
38610db1377Sgtb krb5_free_error(context, krberror);
387*55fea89dSDan Cross
38810db1377Sgtb } else { /* Not an error*/
38910db1377Sgtb
39010db1377Sgtb /*
39110db1377Sgtb ** validate the message length -
392*55fea89dSDan Cross ** length is big endian
39310db1377Sgtb */
39410db1377Sgtb message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
39510db1377Sgtb ptr += 2;
39610db1377Sgtb /*
39710db1377Sgtb ** make sure the message length and packet length agree -
39810db1377Sgtb */
39910db1377Sgtb if (message_length != packet->length)
40010db1377Sgtb return(KRB5KRB_AP_ERR_MODIFIED);
40110db1377Sgtb /*
40210db1377Sgtb ** get the version number -
40310db1377Sgtb */
40410db1377Sgtb version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
40510db1377Sgtb ptr += 2;
40610db1377Sgtb /*
40710db1377Sgtb ** make sure we support the version returned -
40810db1377Sgtb */
40910db1377Sgtb /*
41010db1377Sgtb ** set password version is 0xff80, change password version is 1
41110db1377Sgtb */
412159d09a2SMark Phalan if (version_number != 1 && version_number != 0xff80)
41310db1377Sgtb return(KRB5KDC_ERR_BAD_PVNO);
41410db1377Sgtb /*
41510db1377Sgtb ** now fill in ap_rep with the reply -
41610db1377Sgtb */
41710db1377Sgtb /*
41810db1377Sgtb ** get the reply length -
41910db1377Sgtb */
42010db1377Sgtb ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
42110db1377Sgtb ptr += 2;
42210db1377Sgtb /*
42310db1377Sgtb ** validate ap_rep length agrees with the packet length -
42410db1377Sgtb */
42510db1377Sgtb if (ptr + ap_rep.length >= packet->data + packet->length)
42610db1377Sgtb return(KRB5KRB_AP_ERR_MODIFIED);
42710db1377Sgtb /*
42810db1377Sgtb ** if data was returned, set the ap_rep ptr -
42910db1377Sgtb */
43010db1377Sgtb if( ap_rep.length ) {
43110db1377Sgtb ap_rep.data = ptr;
43210db1377Sgtb ptr += ap_rep.length;
43310db1377Sgtb
43410db1377Sgtb /*
43510db1377Sgtb * Save send_subkey to later smash recv_subkey.
43610db1377Sgtb */
43710db1377Sgtb ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmpkey);
43810db1377Sgtb if (ret)
43910db1377Sgtb return ret;
44010db1377Sgtb
44110db1377Sgtb ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
44210db1377Sgtb if (ret) {
44310db1377Sgtb krb5_free_keyblock(context, tmpkey);
44410db1377Sgtb return(ret);
44510db1377Sgtb }
44610db1377Sgtb
44710db1377Sgtb krb5_free_ap_rep_enc_part(context, ap_rep_enc);
44810db1377Sgtb /*
44910db1377Sgtb ** now decrypt the result -
45010db1377Sgtb */
45110db1377Sgtb cipherresult.data = ptr;
45210db1377Sgtb cipherresult.length = (packet->data + packet->length) - ptr;
45310db1377Sgtb
45410db1377Sgtb /*
45510db1377Sgtb * Smash recv_subkey to be send_subkey, per spec.
45610db1377Sgtb */
45710db1377Sgtb ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmpkey);
45810db1377Sgtb krb5_free_keyblock(context, tmpkey);
45910db1377Sgtb if (ret)
46010db1377Sgtb return ret;
46110db1377Sgtb
46210db1377Sgtb ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
46310db1377Sgtb NULL);
46410db1377Sgtb if (ret)
46510db1377Sgtb return(ret);
46610db1377Sgtb } /*We got an ap_rep*/
46710db1377Sgtb else
46810db1377Sgtb return (KRB5KRB_AP_ERR_MODIFIED);
46910db1377Sgtb } /*Response instead of error*/
47010db1377Sgtb
47110db1377Sgtb /*
472*55fea89dSDan Cross ** validate the cleartext length
47310db1377Sgtb */
47410db1377Sgtb if (clearresult.length < 2) {
47510db1377Sgtb ret = KRB5KRB_AP_ERR_MODIFIED;
47610db1377Sgtb goto cleanup;
47710db1377Sgtb }
47810db1377Sgtb /*
47910db1377Sgtb ** now decode the result -
48010db1377Sgtb */
48110db1377Sgtb ptr = clearresult.data;
48210db1377Sgtb
48310db1377Sgtb *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
48410db1377Sgtb ptr += 2;
48510db1377Sgtb
48610db1377Sgtb /*
48710db1377Sgtb ** result code 5 is access denied
48810db1377Sgtb */
48910db1377Sgtb if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5))
49010db1377Sgtb {
49110db1377Sgtb ret = KRB5KRB_AP_ERR_MODIFIED;
49210db1377Sgtb goto cleanup;
49310db1377Sgtb }
49410db1377Sgtb /*
49510db1377Sgtb ** all success replies should be authenticated/encrypted
49610db1377Sgtb */
49710db1377Sgtb if( (ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS) )
49810db1377Sgtb {
49910db1377Sgtb ret = KRB5KRB_AP_ERR_MODIFIED;
50010db1377Sgtb goto cleanup;
50110db1377Sgtb }
50210db1377Sgtb
50310db1377Sgtb if (result_data) {
50410db1377Sgtb result_data->length = (clearresult.data + clearresult.length) - ptr;
50510db1377Sgtb
50610db1377Sgtb if (result_data->length)
50710db1377Sgtb {
50810db1377Sgtb result_data->data = (char *) malloc(result_data->length);
50910db1377Sgtb if (result_data->data)
51010db1377Sgtb memcpy(result_data->data, ptr, result_data->length);
51110db1377Sgtb }
51210db1377Sgtb else
51310db1377Sgtb result_data->data = NULL;
51410db1377Sgtb }
51510db1377Sgtb ret = 0;
51610db1377Sgtb
51710db1377Sgtb cleanup:
51810db1377Sgtb krb5_free_data_contents(context, &clearresult);
51910db1377Sgtb return(ret);
52010db1377Sgtb }
52110db1377Sgtb
522*55fea89dSDan Cross krb5_error_code
krb5int_setpw_result_code_string(krb5_context context,int result_code,const char ** code_string)52310db1377Sgtb krb5int_setpw_result_code_string( krb5_context context, int result_code, const char **code_string )
52410db1377Sgtb {
52510db1377Sgtb switch (result_code)
52610db1377Sgtb {
52710db1377Sgtb case KRB5_KPASSWD_MALFORMED:
52810db1377Sgtb *code_string = "Malformed request error";
52910db1377Sgtb break;
53010db1377Sgtb case KRB5_KPASSWD_HARDERROR:
53110db1377Sgtb *code_string = "Server error";
53210db1377Sgtb break;
53310db1377Sgtb case KRB5_KPASSWD_AUTHERROR:
53410db1377Sgtb *code_string = "Authentication error";
53510db1377Sgtb break;
53610db1377Sgtb case KRB5_KPASSWD_SOFTERROR:
53710db1377Sgtb *code_string = "Password change rejected";
53810db1377Sgtb break;
53910db1377Sgtb case 5: /* access denied */
54010db1377Sgtb *code_string = "Access denied";
54110db1377Sgtb break;
54210db1377Sgtb case 6: /* bad version */
54310db1377Sgtb *code_string = "Wrong protocol version";
54410db1377Sgtb break;
54510db1377Sgtb case 7: /* initial flag is needed */
54610db1377Sgtb *code_string = "Initial password required";
54710db1377Sgtb break;
54810db1377Sgtb case 0:
54906307114SToomas Soome *code_string = "Success";
55006307114SToomas Soome break;
55110db1377Sgtb default:
55210db1377Sgtb *code_string = "Password change failed";
55310db1377Sgtb break;
55410db1377Sgtb }
55510db1377Sgtb
55610db1377Sgtb return(0);
55710db1377Sgtb }
55810db1377Sgtb
559