xref: /titanic_50/usr/src/lib/krb5/kadm5/clnt/chpw.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
17c478bd9Sstevel@tonic-gate /*
2*159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate #include <string.h>
87c478bd9Sstevel@tonic-gate 
9*159d09a2SMark Phalan #include "k5-int.h"
107c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
117c478bd9Sstevel@tonic-gate #include <client_internal.h>
12*159d09a2SMark Phalan #include "auth_con.h"
137c478bd9Sstevel@tonic-gate #include <locale.h>
147c478bd9Sstevel@tonic-gate 
15*159d09a2SMark Phalan 
16*159d09a2SMark Phalan krb5_error_code
krb5int_mk_chpw_req(krb5_context context,krb5_auth_context auth_context,krb5_data * ap_req,char * passwd,krb5_data * packet)17*159d09a2SMark Phalan krb5int_mk_chpw_req(
18*159d09a2SMark Phalan 	krb5_context context,
19*159d09a2SMark Phalan 	krb5_auth_context auth_context,
20*159d09a2SMark Phalan 	krb5_data *ap_req,
21*159d09a2SMark Phalan 	char *passwd,
22*159d09a2SMark Phalan 	krb5_data *packet)
237c478bd9Sstevel@tonic-gate {
247c478bd9Sstevel@tonic-gate     krb5_error_code ret = 0;
257c478bd9Sstevel@tonic-gate     krb5_data clearpw;
267c478bd9Sstevel@tonic-gate     krb5_data cipherpw;
277c478bd9Sstevel@tonic-gate     krb5_replay_data replay;
287c478bd9Sstevel@tonic-gate     char *ptr;
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate     cipherpw.data = NULL;
317c478bd9Sstevel@tonic-gate 
32*159d09a2SMark Phalan     if ((ret = krb5_auth_con_setflags(context, auth_context,
33*159d09a2SMark Phalan 				      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
347c478bd9Sstevel@tonic-gate 	  goto cleanup;
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate     clearpw.length = strlen(passwd);
377c478bd9Sstevel@tonic-gate     clearpw.data = passwd;
387c478bd9Sstevel@tonic-gate 
39*159d09a2SMark Phalan     if ((ret = krb5_mk_priv(context, auth_context,
40*159d09a2SMark Phalan 			    &clearpw, &cipherpw, &replay)))
417c478bd9Sstevel@tonic-gate       goto cleanup;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate     packet->length = 6 + ap_req->length + cipherpw.length;
447c478bd9Sstevel@tonic-gate     packet->data = (char *) malloc(packet->length);
457c478bd9Sstevel@tonic-gate     if (packet->data == NULL)
467c478bd9Sstevel@tonic-gate 	{
477c478bd9Sstevel@tonic-gate 	    ret = ENOMEM;
487c478bd9Sstevel@tonic-gate 	    goto cleanup;
497c478bd9Sstevel@tonic-gate 	}
507c478bd9Sstevel@tonic-gate     ptr = packet->data;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate     /* length */
53*159d09a2SMark Phalan 
547c478bd9Sstevel@tonic-gate     *ptr++ = (packet->length>> 8) & 0xff;
557c478bd9Sstevel@tonic-gate     *ptr++ = packet->length & 0xff;
567c478bd9Sstevel@tonic-gate 
57*159d09a2SMark Phalan     /* version == 0x0001 big-endian
587c478bd9Sstevel@tonic-gate      * NOTE: when MS and MIT start supporting the latest
597c478bd9Sstevel@tonic-gate      *	version of the passwd change protocol (v2),
607c478bd9Sstevel@tonic-gate      *	this value will change to 2.
617c478bd9Sstevel@tonic-gate      */
627c478bd9Sstevel@tonic-gate     *ptr++ = 0;
637c478bd9Sstevel@tonic-gate     *ptr++ = 1;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate     /* ap_req length, big-endian */
66*159d09a2SMark Phalan 
677c478bd9Sstevel@tonic-gate     *ptr++ = (ap_req->length>>8) & 0xff;
687c478bd9Sstevel@tonic-gate     *ptr++ = ap_req->length & 0xff;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate     /* ap-req data */
71*159d09a2SMark Phalan 
727c478bd9Sstevel@tonic-gate     memcpy(ptr, ap_req->data, ap_req->length);
737c478bd9Sstevel@tonic-gate     ptr += ap_req->length;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate     /* krb-priv of password */
76*159d09a2SMark Phalan 
777c478bd9Sstevel@tonic-gate     memcpy(ptr, cipherpw.data, cipherpw.length);
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate cleanup:
807c478bd9Sstevel@tonic-gate     if(cipherpw.data != NULL)  /* allocated by krb5_mk_priv */
817c478bd9Sstevel@tonic-gate       free(cipherpw.data);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate     return(ret);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
86*159d09a2SMark Phalan 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)87*159d09a2SMark Phalan krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate     char *ptr;
907c478bd9Sstevel@tonic-gate     int plen, vno;
917c478bd9Sstevel@tonic-gate     krb5_data ap_rep;
927c478bd9Sstevel@tonic-gate     krb5_ap_rep_enc_part *ap_rep_enc;
937c478bd9Sstevel@tonic-gate     krb5_error_code ret;
947c478bd9Sstevel@tonic-gate     krb5_data cipherresult;
957c478bd9Sstevel@tonic-gate     krb5_data clearresult;
967c478bd9Sstevel@tonic-gate     krb5_error *krberror;
977c478bd9Sstevel@tonic-gate     krb5_replay_data replay;
987c478bd9Sstevel@tonic-gate     krb5_keyblock *tmp;
997c478bd9Sstevel@tonic-gate     int local_result_code;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate     if (packet->length < 4)
102*159d09a2SMark Phalan 	/* either this, or the server is printing bad messages,
103*159d09a2SMark Phalan 	   or the caller passed in garbage */
1047c478bd9Sstevel@tonic-gate 	return(KRB5KRB_AP_ERR_MODIFIED);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate     ptr = packet->data;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate     /* verify length */
109*159d09a2SMark Phalan 
1107c478bd9Sstevel@tonic-gate     plen = (*ptr++ & 0xff);
1117c478bd9Sstevel@tonic-gate     plen = (plen<<8) | (*ptr++ & 0xff);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate     if (plen != packet->length)
114*159d09a2SMark Phalan 	{
115*159d09a2SMark Phalan 		/*
116*159d09a2SMark Phalan 		 * MS KDCs *may* send back a KRB_ERROR.  Although
117*159d09a2SMark Phalan 		 * not 100% correct via RFC3244, it's something
118*159d09a2SMark Phalan 		 * we can workaround here.
119*159d09a2SMark Phalan 		 */
120*159d09a2SMark Phalan 		if (krb5_is_krb_error(packet)) {
121*159d09a2SMark Phalan 
122*159d09a2SMark Phalan 			if ((ret = krb5_rd_error(context, packet, &krberror)))
123*159d09a2SMark Phalan 			return(ret);
124*159d09a2SMark Phalan 
125*159d09a2SMark Phalan 			if (krberror->e_data.data  == NULL) {
126*159d09a2SMark Phalan 				ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
127*159d09a2SMark Phalan 				krb5_free_error(context, krberror);
128*159d09a2SMark Phalan 				return (ret);
129*159d09a2SMark Phalan 			}
130*159d09a2SMark Phalan 		}
131*159d09a2SMark Phalan 		else
132*159d09a2SMark Phalan 		{
1337c478bd9Sstevel@tonic-gate 			return(KRB5KRB_AP_ERR_MODIFIED);
134*159d09a2SMark Phalan 		}
135*159d09a2SMark Phalan 	}
136*159d09a2SMark Phalan 
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate     /* verify version number */
139*159d09a2SMark Phalan 
1407c478bd9Sstevel@tonic-gate     vno = (*ptr++ & 0xff);
1417c478bd9Sstevel@tonic-gate     vno = (vno<<8) | (*ptr++ & 0xff);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * when the servers update to v2 of the protocol,
1457c478bd9Sstevel@tonic-gate 	 * "2" will be a valid version number here
1467c478bd9Sstevel@tonic-gate 	 */
1477c478bd9Sstevel@tonic-gate 	if (vno != 1 && vno != 2)
1487c478bd9Sstevel@tonic-gate 		return (KRB5KDC_ERR_BAD_PVNO);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate     /* read, check ap-rep length */
151*159d09a2SMark Phalan 
1527c478bd9Sstevel@tonic-gate     ap_rep.length = (*ptr++ & 0xff);
1537c478bd9Sstevel@tonic-gate     ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate     if (ptr + ap_rep.length >= packet->data + packet->length)
1567c478bd9Sstevel@tonic-gate 	return(KRB5KRB_AP_ERR_MODIFIED);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate     if (ap_rep.length) {
1597c478bd9Sstevel@tonic-gate 	/* verify ap_rep */
1607c478bd9Sstevel@tonic-gate 	ap_rep.data = ptr;
1617c478bd9Sstevel@tonic-gate 	ptr += ap_rep.length;
1627c478bd9Sstevel@tonic-gate 
16345526e97Ssemery 	/*
16445526e97Ssemery 	 * Save send_subkey to later smash recv_subkey.
16545526e97Ssemery 	 */
16645526e97Ssemery 	ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
16745526e97Ssemery 	if (ret)
168*159d09a2SMark Phalan 	    return ret;
1697c478bd9Sstevel@tonic-gate 
170*159d09a2SMark Phalan 	ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
171*159d09a2SMark Phalan 	if (ret) {
17245526e97Ssemery 	    krb5_free_keyblock(context, tmp);
17345526e97Ssemery 	    return(ret);
17445526e97Ssemery 	}
17545526e97Ssemery 
1767c478bd9Sstevel@tonic-gate 	krb5_free_ap_rep_enc_part(context, ap_rep_enc);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/* extract and decrypt the result */
179*159d09a2SMark Phalan 
1807c478bd9Sstevel@tonic-gate 	cipherresult.data = ptr;
1817c478bd9Sstevel@tonic-gate 	cipherresult.length = (packet->data + packet->length) - ptr;
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
18445526e97Ssemery 	 * Smash recv_subkey to be send_subkey, per spec.
1857c478bd9Sstevel@tonic-gate 	 */
18645526e97Ssemery 	ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp);
18745526e97Ssemery 	krb5_free_keyblock(context, tmp);
18845526e97Ssemery 	if (ret)
189*159d09a2SMark Phalan 	    return ret;
1907c478bd9Sstevel@tonic-gate 
191*159d09a2SMark Phalan 	ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
192*159d09a2SMark Phalan 			   &replay);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if (ret)
1957c478bd9Sstevel@tonic-gate 	    return(ret);
1967c478bd9Sstevel@tonic-gate     } else {
1977c478bd9Sstevel@tonic-gate 	cipherresult.data = ptr;
1987c478bd9Sstevel@tonic-gate 	cipherresult.length = (packet->data + packet->length) - ptr;
1997c478bd9Sstevel@tonic-gate 
200*159d09a2SMark Phalan 	if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
2017c478bd9Sstevel@tonic-gate 	    return(ret);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	clearresult = krberror->e_data;
2047c478bd9Sstevel@tonic-gate     }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate     if (clearresult.length < 2) {
2077c478bd9Sstevel@tonic-gate 	ret = KRB5KRB_AP_ERR_MODIFIED;
2087c478bd9Sstevel@tonic-gate 	goto cleanup;
2097c478bd9Sstevel@tonic-gate     }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate     ptr = clearresult.data;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate     local_result_code = (*ptr++ & 0xff);
2147c478bd9Sstevel@tonic-gate     local_result_code = (local_result_code<<8) | (*ptr++ & 0xff);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (result_code)
2177c478bd9Sstevel@tonic-gate 		*result_code = local_result_code;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * Make sure the result code is in range for this
2217c478bd9Sstevel@tonic-gate 	 * protocol.
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate     if ((local_result_code < KRB5_KPASSWD_SUCCESS) ||
2247c478bd9Sstevel@tonic-gate 	 (local_result_code > KRB5_KPASSWD_ETYPE_NOSUPP)) {
2257c478bd9Sstevel@tonic-gate 	ret = KRB5KRB_AP_ERR_MODIFIED;
2267c478bd9Sstevel@tonic-gate 	goto cleanup;
2277c478bd9Sstevel@tonic-gate     }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate     /* all success replies should be authenticated/encrypted */
230*159d09a2SMark Phalan 
231*159d09a2SMark Phalan     if ((ap_rep.length == 0) && (local_result_code == KRB5_KPASSWD_SUCCESS)) {
2327c478bd9Sstevel@tonic-gate 	ret = KRB5KRB_AP_ERR_MODIFIED;
2337c478bd9Sstevel@tonic-gate 	goto cleanup;
2347c478bd9Sstevel@tonic-gate     }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate     result_data->length = (clearresult.data + clearresult.length) - ptr;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate     if (result_data->length) {
2397c478bd9Sstevel@tonic-gate 	result_data->data = (char *) malloc(result_data->length);
2407c478bd9Sstevel@tonic-gate 	if (result_data->data == NULL) {
2417c478bd9Sstevel@tonic-gate 	    ret = ENOMEM;
2427c478bd9Sstevel@tonic-gate 	    goto cleanup;
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 	memcpy(result_data->data, ptr, result_data->length);
2457c478bd9Sstevel@tonic-gate     } else {
2467c478bd9Sstevel@tonic-gate 	result_data->data = NULL;
2477c478bd9Sstevel@tonic-gate     }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate     ret = 0;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate cleanup:
2527c478bd9Sstevel@tonic-gate     if (ap_rep.length) {
2537c478bd9Sstevel@tonic-gate 	krb5_xfree(clearresult.data);
2547c478bd9Sstevel@tonic-gate     } else {
2557c478bd9Sstevel@tonic-gate 	krb5_free_error(context, krberror);
2567c478bd9Sstevel@tonic-gate     }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate     return(ret);
2597c478bd9Sstevel@tonic-gate }
260