xref: /illumos-gate/usr/src/lib/krb5/kadm5/srv/chgpwd.c (revision 46c8d03d)
17c478bd9Sstevel@tonic-gate /*
2*46c8d03dSMark Phalan  * Copyright 2010 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  * lib/krb5/kadm5/srv/chgpwd.c
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * Copyright 1998 by the Massachusetts Institute of Technology.
107c478bd9Sstevel@tonic-gate  * All Rights Reserved.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
137c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
147c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
157c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
187c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
197c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
207c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
217c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
227c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
237c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
247c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
257c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
267c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
277c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
287c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
297c478bd9Sstevel@tonic-gate  * or implied warranty.
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * chgpwd.c - Handles changepw requests issued from non-Solaris krb5 clients.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <locale.h>
397c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
407c478bd9Sstevel@tonic-gate #include <syslog.h>
417c478bd9Sstevel@tonic-gate #include <krb5/adm_proto.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	MAXAPREQ 1500
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static krb5_error_code
process_chpw_request(krb5_context context,void * server_handle,char * realm,int s,krb5_keytab keytab,struct sockaddr_in * sin,krb5_data * req,krb5_data * rep)467c478bd9Sstevel@tonic-gate process_chpw_request(krb5_context context, void *server_handle,
477c478bd9Sstevel@tonic-gate 			char *realm, int s, krb5_keytab keytab,
487c478bd9Sstevel@tonic-gate 			struct sockaddr_in *sin, krb5_data *req,
497c478bd9Sstevel@tonic-gate 			krb5_data *rep)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	krb5_error_code ret;
527c478bd9Sstevel@tonic-gate 	char *ptr;
537c478bd9Sstevel@tonic-gate 	int plen, vno;
547c478bd9Sstevel@tonic-gate 	krb5_address local_kaddr, remote_kaddr;
557c478bd9Sstevel@tonic-gate 	int allocated_mem = 0;
567c478bd9Sstevel@tonic-gate 	krb5_data ap_req, ap_rep;
577c478bd9Sstevel@tonic-gate 	krb5_auth_context auth_context;
587c478bd9Sstevel@tonic-gate 	krb5_principal changepw;
597c478bd9Sstevel@tonic-gate 	krb5_ticket *ticket;
607c478bd9Sstevel@tonic-gate 	krb5_data cipher, clear;
617c478bd9Sstevel@tonic-gate 	struct sockaddr local_addr, remote_addr;
627c478bd9Sstevel@tonic-gate 	int addrlen;
637c478bd9Sstevel@tonic-gate 	krb5_replay_data replay;
647c478bd9Sstevel@tonic-gate 	krb5_error krberror;
657c478bd9Sstevel@tonic-gate 	int numresult;
667c478bd9Sstevel@tonic-gate 	char strresult[1024];
672278144aSsemery 	char *clientstr;
6846736d35Ssemery 	size_t clen;
6946736d35Ssemery 	char *cdots;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	ret = 0;
727c478bd9Sstevel@tonic-gate 	rep->length = 0;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	auth_context = NULL;
757c478bd9Sstevel@tonic-gate 	changepw = NULL;
767c478bd9Sstevel@tonic-gate 	ap_rep.length = 0;
777c478bd9Sstevel@tonic-gate 	ap_rep.data = NULL;
787c478bd9Sstevel@tonic-gate 	ticket = NULL;
797c478bd9Sstevel@tonic-gate 	clear.length = 0;
807c478bd9Sstevel@tonic-gate 	clear.data = NULL;
817c478bd9Sstevel@tonic-gate 	cipher.length = 0;
827c478bd9Sstevel@tonic-gate 	cipher.data = NULL;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	if (req->length < 4) {
857c478bd9Sstevel@tonic-gate 		/*
867c478bd9Sstevel@tonic-gate 		 * either this, or the server is printing bad messages,
877c478bd9Sstevel@tonic-gate 		 * or the caller passed in garbage
887c478bd9Sstevel@tonic-gate 		 */
897c478bd9Sstevel@tonic-gate 		ret = KRB5KRB_AP_ERR_MODIFIED;
907c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_MALFORMED;
917c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Request was truncated",
927c478bd9Sstevel@tonic-gate 				sizeof (strresult));
937c478bd9Sstevel@tonic-gate 		goto chpwfail;
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	ptr = req->data;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/*
997c478bd9Sstevel@tonic-gate 	 * Verify length
1007c478bd9Sstevel@tonic-gate 	 */
1017c478bd9Sstevel@tonic-gate 	plen = (*ptr++ & 0xff);
1027c478bd9Sstevel@tonic-gate 	plen = (plen<<8) | (*ptr++ & 0xff);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	if (plen != req->length)
1057c478bd9Sstevel@tonic-gate 		return (KRB5KRB_AP_ERR_MODIFIED);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
1087c478bd9Sstevel@tonic-gate 	 * Verify version number
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	vno = (*ptr++ & 0xff);
1117c478bd9Sstevel@tonic-gate 	vno = (vno<<8) | (*ptr++ & 0xff);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	if (vno != 1) {
1147c478bd9Sstevel@tonic-gate 		ret = KRB5KDC_ERR_BAD_PVNO;
1157c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_MALFORMED;
1167c478bd9Sstevel@tonic-gate 		(void) snprintf(strresult, sizeof (strresult),
1177c478bd9Sstevel@tonic-gate 		    "Request contained unknown protocol version number %d",
1187c478bd9Sstevel@tonic-gate 		    vno);
1197c478bd9Sstevel@tonic-gate 		goto chpwfail;
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/*
1237c478bd9Sstevel@tonic-gate 	 * Read, check ap-req length
1247c478bd9Sstevel@tonic-gate 	 */
1257c478bd9Sstevel@tonic-gate 	ap_req.length = (*ptr++ & 0xff);
1267c478bd9Sstevel@tonic-gate 	ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	if (ptr + ap_req.length >= req->data + req->length) {
1297c478bd9Sstevel@tonic-gate 		ret = KRB5KRB_AP_ERR_MODIFIED;
1307c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_MALFORMED;
1317c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Request was truncated in AP-REQ",
1327c478bd9Sstevel@tonic-gate 					sizeof (strresult));
1337c478bd9Sstevel@tonic-gate 		goto chpwfail;
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/*
1377c478bd9Sstevel@tonic-gate 	 * Verify ap_req
1387c478bd9Sstevel@tonic-gate 	 */
1397c478bd9Sstevel@tonic-gate 	ap_req.data = ptr;
1407c478bd9Sstevel@tonic-gate 	ptr += ap_req.length;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (ret = krb5_auth_con_init(context, &auth_context)) {
143a0709436Smp 		krb5_klog_syslog(LOG_ERR,
144a0709436Smp 				gettext("Change password request failed. "
14585393f1dSmp 					"Failed initializing auth context: %s"),
146a0709436Smp 				error_message(ret));
1477c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
1487c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Failed initializing auth context",
1497c478bd9Sstevel@tonic-gate 					sizeof (strresult));
1507c478bd9Sstevel@tonic-gate 		goto chpwfail;
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if (ret = krb5_auth_con_setflags(context, auth_context,
1547c478bd9Sstevel@tonic-gate 					KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
155a0709436Smp 		krb5_klog_syslog(LOG_ERR,
156a0709436Smp 				gettext("Change password request failed. "
157a0709436Smp 						"Failed setting auth "
158a0709436Smp 					    "context flags: %s"),
159a0709436Smp 				error_message(ret));
1607c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
1617c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Failed initializing auth context",
1627c478bd9Sstevel@tonic-gate 					sizeof (strresult));
1637c478bd9Sstevel@tonic-gate 		goto chpwfail;
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
1677c478bd9Sstevel@tonic-gate 				    "kadmin", "changepw", NULL)) {
168a0709436Smp 		krb5_klog_syslog(LOG_ERR,
169a0709436Smp 			gettext("Change password request failed "
170a0709436Smp 					"Failed to build kadmin/changepw "
171a0709436Smp 					"principal: %s"),
172a0709436Smp 			error_message(ret));
1737c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
1747c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult,
1757c478bd9Sstevel@tonic-gate 				"Failed building kadmin/changepw principal",
1767c478bd9Sstevel@tonic-gate 				sizeof (strresult));
1777c478bd9Sstevel@tonic-gate 		goto chpwfail;
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
1817c478bd9Sstevel@tonic-gate 			NULL, &ticket);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	if (ret) {
184a0709436Smp 		char kt_name[MAX_KEYTAB_NAME_LEN];
185a0709436Smp 		if (krb5_kt_get_name(context, keytab,
186a0709436Smp 				kt_name, sizeof (kt_name)))
187a0709436Smp 			strncpy(kt_name, "default keytab", sizeof (kt_name));
188a0709436Smp 
189a0709436Smp 		switch (ret) {
190a0709436Smp 		case KRB5_KT_NOTFOUND:
191a0709436Smp 		krb5_klog_syslog(LOG_ERR,
192a0709436Smp 			gettext("Change password request failed because "
193a0709436Smp 					"keytab entry \"kadmin/changepw\" "
194a0709436Smp 					"is missing from \"%s\""),
195a0709436Smp 			kt_name);
196a0709436Smp 		break;
197a0709436Smp 		case ENOENT:
198a0709436Smp 		krb5_klog_syslog(LOG_ERR,
199a0709436Smp 			gettext("Change password request failed because "
200a0709436Smp 					"keytab file \"%s\" does not exist"),
201a0709436Smp 			kt_name);
202a0709436Smp 		break;
203a0709436Smp 		default:
204a0709436Smp 		krb5_klog_syslog(LOG_ERR,
205a0709436Smp 			gettext("Change password request failed. "
20685393f1dSmp 				"Failed to parse Kerberos AP_REQ message: %s"),
207a0709436Smp 			error_message(ret));
208a0709436Smp 		}
209a0709436Smp 
2107c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_AUTHERROR;
2117c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Failed reading application request",
2127c478bd9Sstevel@tonic-gate 					sizeof (strresult));
2137c478bd9Sstevel@tonic-gate 		goto chpwfail;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * Set up address info
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	addrlen = sizeof (local_addr);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	if (getsockname(s, &local_addr, &addrlen) < 0) {
2227c478bd9Sstevel@tonic-gate 		ret = errno;
2237c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
2247c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult,
2257c478bd9Sstevel@tonic-gate 				"Failed getting server internet address",
2267c478bd9Sstevel@tonic-gate 				sizeof (strresult));
2277c478bd9Sstevel@tonic-gate 		goto chpwfail;
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/*
2317c478bd9Sstevel@tonic-gate 	 * Some brain-dead OS's don't return useful information from
2327c478bd9Sstevel@tonic-gate 	 * the getsockname call.  Namely, windows and solaris.
2337c478bd9Sstevel@tonic-gate 	 */
2347c478bd9Sstevel@tonic-gate 	if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) {
2357c478bd9Sstevel@tonic-gate 		local_kaddr.addrtype = ADDRTYPE_INET;
2367c478bd9Sstevel@tonic-gate 		local_kaddr.length = sizeof (((struct sockaddr_in *)
2377c478bd9Sstevel@tonic-gate 						&local_addr)->sin_addr);
2387c478bd9Sstevel@tonic-gate 		/* CSTYLED */
2397c478bd9Sstevel@tonic-gate 		local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&local_addr)->sin_addr);
2407c478bd9Sstevel@tonic-gate 	} else {
2417c478bd9Sstevel@tonic-gate 		krb5_address **addrs;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		krb5_os_localaddr(context, &addrs);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 		local_kaddr.magic = addrs[0]->magic;
2467c478bd9Sstevel@tonic-gate 		local_kaddr.addrtype = addrs[0]->addrtype;
2477c478bd9Sstevel@tonic-gate 		local_kaddr.length = addrs[0]->length;
2487c478bd9Sstevel@tonic-gate 		if ((local_kaddr.contents = malloc(addrs[0]->length)) == 0) {
2497c478bd9Sstevel@tonic-gate 			ret = errno;
2507c478bd9Sstevel@tonic-gate 			numresult = KRB5_KPASSWD_HARDERROR;
2517c478bd9Sstevel@tonic-gate 			(void) strlcpy(strresult,
2527c478bd9Sstevel@tonic-gate 				"Malloc failed for local_kaddr",
2537c478bd9Sstevel@tonic-gate 				sizeof (strresult));
2547c478bd9Sstevel@tonic-gate 			goto chpwfail;
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		(void) memcpy(local_kaddr.contents, addrs[0]->contents,
2587c478bd9Sstevel@tonic-gate 				addrs[0]->length);
2597c478bd9Sstevel@tonic-gate 		allocated_mem++;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		krb5_free_addresses(context, addrs);
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	addrlen = sizeof (remote_addr);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (getpeername(s, &remote_addr, &addrlen) < 0) {
2677c478bd9Sstevel@tonic-gate 		ret = errno;
2687c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
2697c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult,
2707c478bd9Sstevel@tonic-gate 				"Failed getting client internet address",
2717c478bd9Sstevel@tonic-gate 				sizeof (strresult));
2727c478bd9Sstevel@tonic-gate 		goto chpwfail;
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	remote_kaddr.addrtype = ADDRTYPE_INET;
2767c478bd9Sstevel@tonic-gate 	remote_kaddr.length = sizeof (((struct sockaddr_in *)
2777c478bd9Sstevel@tonic-gate 					&remote_addr)->sin_addr);
2787c478bd9Sstevel@tonic-gate 	/* CSTYLED */
2797c478bd9Sstevel@tonic-gate 	remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr);
2807c478bd9Sstevel@tonic-gate 	remote_kaddr.addrtype = ADDRTYPE_INET;
2817c478bd9Sstevel@tonic-gate 	remote_kaddr.length = sizeof (sin->sin_addr);
2827c478bd9Sstevel@tonic-gate 	remote_kaddr.contents = (krb5_octet *) &sin->sin_addr;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * mk_priv requires that the local address be set.
2867c478bd9Sstevel@tonic-gate 	 * getsockname is used for this.  rd_priv requires that the
2877c478bd9Sstevel@tonic-gate 	 * remote address be set.  recvfrom is used for this.  If
2887c478bd9Sstevel@tonic-gate 	 * rd_priv is given a local address, and the message has the
2897c478bd9Sstevel@tonic-gate 	 * recipient addr in it, this will be checked.  However, there
2907c478bd9Sstevel@tonic-gate 	 * is simply no way to know ahead of time what address the
2917c478bd9Sstevel@tonic-gate 	 * message will be delivered *to*.  Therefore, it is important
2927c478bd9Sstevel@tonic-gate 	 * that either no recipient address is in the messages when
2937c478bd9Sstevel@tonic-gate 	 * mk_priv is called, or that no local address is passed to
2947c478bd9Sstevel@tonic-gate 	 * rd_priv.  Both is a better idea, and I have done that.  In
2957c478bd9Sstevel@tonic-gate 	 * summary, when mk_priv is called, *only* a local address is
2967c478bd9Sstevel@tonic-gate 	 * specified.  when rd_priv is called, *only* a remote address
2977c478bd9Sstevel@tonic-gate 	 * is specified.  Are we having fun yet?
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	if (ret = krb5_auth_con_setaddrs(context, auth_context, NULL,
3007c478bd9Sstevel@tonic-gate 					&remote_kaddr)) {
3017c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
3027c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult,
3037c478bd9Sstevel@tonic-gate 				"Failed storing client internet address",
3047c478bd9Sstevel@tonic-gate 				sizeof (strresult));
3057c478bd9Sstevel@tonic-gate 		goto chpwfail;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/*
3097c478bd9Sstevel@tonic-gate 	 * Verify that this is an AS_REQ ticket
3107c478bd9Sstevel@tonic-gate 	 */
3117c478bd9Sstevel@tonic-gate 	if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) {
3127c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_AUTHERROR;
3137c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult,
3147c478bd9Sstevel@tonic-gate 				"Ticket must be derived from a password",
3157c478bd9Sstevel@tonic-gate 				sizeof (strresult));
3167c478bd9Sstevel@tonic-gate 		goto chpwfail;
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * Construct the ap-rep
3217c478bd9Sstevel@tonic-gate 	 */
3227c478bd9Sstevel@tonic-gate 	if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) {
3237c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_AUTHERROR;
3247c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult,
3257c478bd9Sstevel@tonic-gate 				"Failed replying to application request",
3267c478bd9Sstevel@tonic-gate 				sizeof (strresult));
3277c478bd9Sstevel@tonic-gate 		goto chpwfail;
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * Decrypt the new password
3327c478bd9Sstevel@tonic-gate 	 */
3337c478bd9Sstevel@tonic-gate 	cipher.length = (req->data + req->length) - ptr;
3347c478bd9Sstevel@tonic-gate 	cipher.data = ptr;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	if (ret = krb5_rd_priv(context, auth_context, &cipher,
3377c478bd9Sstevel@tonic-gate 				&clear, &replay)) {
3387c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
3397c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Failed decrypting request",
3407c478bd9Sstevel@tonic-gate 					sizeof (strresult));
3417c478bd9Sstevel@tonic-gate 		goto chpwfail;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3442278144aSsemery 	ret = krb5_unparse_name(context, ticket->enc_part2->client, &clientstr);
3452278144aSsemery 	if (ret) {
3462278144aSsemery 		numresult = KRB5_KPASSWD_HARDERROR;
3472278144aSsemery 		(void) strcpy(strresult, "Failed decrypting request");
3482278144aSsemery 		goto chpwfail;
3492278144aSsemery 	}
3502278144aSsemery 
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * Change the password
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	if ((ptr = (char *)malloc(clear.length + 1)) == NULL) {
3557c478bd9Sstevel@tonic-gate 		ret = errno;
3567c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
3577c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Malloc failed for ptr",
3587c478bd9Sstevel@tonic-gate 			sizeof (strresult));
3592278144aSsemery 		krb5_free_unparsed_name(context, clientstr);
3607c478bd9Sstevel@tonic-gate 		goto chpwfail;
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 	(void) memcpy(ptr, clear.data, clear.length);
3637c478bd9Sstevel@tonic-gate 	ptr[clear.length] = '\0';
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	ret = (kadm5_ret_t)kadm5_chpass_principal_util(server_handle,
3667c478bd9Sstevel@tonic-gate 						ticket->enc_part2->client,
3677c478bd9Sstevel@tonic-gate 						ptr, NULL, strresult,
3687c478bd9Sstevel@tonic-gate 						sizeof (strresult));
3692278144aSsemery 
3707c478bd9Sstevel@tonic-gate 	/*
3717c478bd9Sstevel@tonic-gate 	 * Zap the password
3727c478bd9Sstevel@tonic-gate 	 */
3737c478bd9Sstevel@tonic-gate 	(void) memset(clear.data, 0, clear.length);
3747c478bd9Sstevel@tonic-gate 	(void) memset(ptr, 0, clear.length);
3757c478bd9Sstevel@tonic-gate 	if (clear.data != NULL) {
3767c478bd9Sstevel@tonic-gate 		krb5_xfree(clear.data);
3777c478bd9Sstevel@tonic-gate 		clear.data = NULL;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	free(ptr);
3807c478bd9Sstevel@tonic-gate 	clear.length = 0;
3817c478bd9Sstevel@tonic-gate 
38246736d35Ssemery 	clen = strlen(clientstr);
38346736d35Ssemery 	trunc_name(&clen, &cdots);
38446736d35Ssemery 	krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %.*s%s: %s",
3852278144aSsemery 		inet_ntoa(((struct sockaddr_in *)&remote_addr)->sin_addr),
38646736d35Ssemery 		clen, clientstr, cdots, ret ? error_message(ret) : "success");
3872278144aSsemery 	krb5_free_unparsed_name(context, clientstr);
3882278144aSsemery 
3897c478bd9Sstevel@tonic-gate 	if (ret) {
3907c478bd9Sstevel@tonic-gate 		if ((ret != KADM5_PASS_Q_TOOSHORT) &&
3917c478bd9Sstevel@tonic-gate 		    (ret != KADM5_PASS_REUSE) &&
3927c478bd9Sstevel@tonic-gate 		    (ret != KADM5_PASS_Q_CLASS) &&
3937c478bd9Sstevel@tonic-gate 		    (ret != KADM5_PASS_Q_DICT) &&
3947c478bd9Sstevel@tonic-gate 		    (ret != KADM5_PASS_TOOSOON))
3957c478bd9Sstevel@tonic-gate 			numresult = KRB5_KPASSWD_HARDERROR;
3967c478bd9Sstevel@tonic-gate 		else
3977c478bd9Sstevel@tonic-gate 			numresult = KRB5_KPASSWD_SOFTERROR;
3987c478bd9Sstevel@tonic-gate 		/*
3997c478bd9Sstevel@tonic-gate 		 * strresult set by kadb5_chpass_principal_util()
4007c478bd9Sstevel@tonic-gate 		 */
4017c478bd9Sstevel@tonic-gate 		goto chpwfail;
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/*
4057c478bd9Sstevel@tonic-gate 	 * Success!
4067c478bd9Sstevel@tonic-gate 	 */
4077c478bd9Sstevel@tonic-gate 	numresult = KRB5_KPASSWD_SUCCESS;
4087c478bd9Sstevel@tonic-gate 	(void) strlcpy(strresult, "", sizeof (strresult));
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate chpwfail:
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	clear.length = 2 + strlen(strresult);
4137c478bd9Sstevel@tonic-gate 	if (clear.data != NULL) {
4147c478bd9Sstevel@tonic-gate 		krb5_xfree(clear.data);
4157c478bd9Sstevel@tonic-gate 		clear.data = NULL;
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 	if ((clear.data = (char *)malloc(clear.length)) == NULL) {
4187c478bd9Sstevel@tonic-gate 		ret = errno;
4197c478bd9Sstevel@tonic-gate 		numresult = KRB5_KPASSWD_HARDERROR;
4207c478bd9Sstevel@tonic-gate 		(void) strlcpy(strresult, "Malloc failed for clear.data",
4217c478bd9Sstevel@tonic-gate 			sizeof (strresult));
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4242278144aSsemery 	ptr = clear.data;
4252278144aSsemery 
4262278144aSsemery 	*ptr++ = (numresult>>8) & 0xff;
4272278144aSsemery 	*ptr++ = numresult & 0xff;
4282278144aSsemery 
4292278144aSsemery 	(void) memcpy(ptr, strresult, strlen(strresult));
4302278144aSsemery 
4317c478bd9Sstevel@tonic-gate 	cipher.length = 0;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (ap_rep.length) {
4347c478bd9Sstevel@tonic-gate 		if (ret = krb5_auth_con_setaddrs(context, auth_context,
4357c478bd9Sstevel@tonic-gate 					&local_kaddr, NULL)) {
4367c478bd9Sstevel@tonic-gate 		    numresult = KRB5_KPASSWD_HARDERROR;
4377c478bd9Sstevel@tonic-gate 		    (void) strlcpy(strresult,
4387c478bd9Sstevel@tonic-gate 			"Failed storing client and server internet addresses",
4397c478bd9Sstevel@tonic-gate 			sizeof (strresult));
4407c478bd9Sstevel@tonic-gate 		} else {
4417c478bd9Sstevel@tonic-gate 			if (ret = krb5_mk_priv(context, auth_context, &clear,
4427c478bd9Sstevel@tonic-gate 						&cipher, &replay)) {
4437c478bd9Sstevel@tonic-gate 				numresult = KRB5_KPASSWD_HARDERROR;
4447c478bd9Sstevel@tonic-gate 				(void) strlcpy(strresult,
4457c478bd9Sstevel@tonic-gate 					"Failed encrypting reply",
4467c478bd9Sstevel@tonic-gate 					sizeof (strresult));
4477c478bd9Sstevel@tonic-gate 			}
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	/*
4527c478bd9Sstevel@tonic-gate 	 * If no KRB-PRIV was constructed, then we need a KRB-ERROR.
4537c478bd9Sstevel@tonic-gate 	 * If this fails, just bail.  There's nothing else we can do.
4547c478bd9Sstevel@tonic-gate 	 */
4557c478bd9Sstevel@tonic-gate 	if (cipher.length == 0) {
4567c478bd9Sstevel@tonic-gate 		/*
4577c478bd9Sstevel@tonic-gate 		 * Clear out ap_rep now, so that it won't be inserted
4587c478bd9Sstevel@tonic-gate 		 * in the reply
4597c478bd9Sstevel@tonic-gate 		 */
4607c478bd9Sstevel@tonic-gate 		if (ap_rep.length) {
4617c478bd9Sstevel@tonic-gate 			if (ap_rep.data != NULL)
4627c478bd9Sstevel@tonic-gate 				krb5_xfree(ap_rep.data);
4637c478bd9Sstevel@tonic-gate 			ap_rep.data = NULL;
4647c478bd9Sstevel@tonic-gate 			ap_rep.length = 0;
4657c478bd9Sstevel@tonic-gate 		}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		krberror.ctime = 0;
4687c478bd9Sstevel@tonic-gate 		krberror.cusec = 0;
4697c478bd9Sstevel@tonic-gate 		krberror.susec = 0;
4707c478bd9Sstevel@tonic-gate 		if (ret = krb5_timeofday(context, &krberror.stime))
4717c478bd9Sstevel@tonic-gate 			goto bailout;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		/*
4747c478bd9Sstevel@tonic-gate 		 * This is really icky.  but it's what all the other callers
4757c478bd9Sstevel@tonic-gate 		 * to mk_error do.
4767c478bd9Sstevel@tonic-gate 		 */
4777c478bd9Sstevel@tonic-gate 		krberror.error = ret;
4787c478bd9Sstevel@tonic-gate 		krberror.error -= ERROR_TABLE_BASE_krb5;
4797c478bd9Sstevel@tonic-gate 		if (krberror.error < 0 || krberror.error > 128)
4807c478bd9Sstevel@tonic-gate 			krberror.error = KRB_ERR_GENERIC;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 		krberror.client = NULL;
4837c478bd9Sstevel@tonic-gate 		if (ret = krb5_build_principal(context, &krberror.server,
4847c478bd9Sstevel@tonic-gate 					    strlen(realm), realm,
4857c478bd9Sstevel@tonic-gate 					    "kadmin", "changepw", NULL)) {
4867c478bd9Sstevel@tonic-gate 			goto bailout;
4877c478bd9Sstevel@tonic-gate 		}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		krberror.text.length = 0;
4907c478bd9Sstevel@tonic-gate 		krberror.e_data = clear;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		ret = krb5_mk_error(context, &krberror, &cipher);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, krberror.server);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		if (ret)
4977c478bd9Sstevel@tonic-gate 			goto bailout;
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/*
5017c478bd9Sstevel@tonic-gate 	 * Construct the reply
5027c478bd9Sstevel@tonic-gate 	 */
5037c478bd9Sstevel@tonic-gate 	rep->length = 6 + ap_rep.length + cipher.length;
5047c478bd9Sstevel@tonic-gate 	if ((rep->data = (char *)malloc(rep->length)) == NULL)  {
5057c478bd9Sstevel@tonic-gate 		ret = errno;
5067c478bd9Sstevel@tonic-gate 		goto bailout;
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 	ptr = rep->data;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	/*
5117c478bd9Sstevel@tonic-gate 	 * Length
5127c478bd9Sstevel@tonic-gate 	 */
5137c478bd9Sstevel@tonic-gate 	*ptr++ = (rep->length>>8) & 0xff;
5147c478bd9Sstevel@tonic-gate 	*ptr++ = rep->length & 0xff;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/*
5177c478bd9Sstevel@tonic-gate 	 * Version == 0x0001 big-endian
5187c478bd9Sstevel@tonic-gate 	 */
5197c478bd9Sstevel@tonic-gate 	*ptr++ = 0;
5207c478bd9Sstevel@tonic-gate 	*ptr++ = 1;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	/*
5237c478bd9Sstevel@tonic-gate 	 * ap_rep length, big-endian
5247c478bd9Sstevel@tonic-gate 	 */
5257c478bd9Sstevel@tonic-gate 	*ptr++ = (ap_rep.length>>8) & 0xff;
5267c478bd9Sstevel@tonic-gate 	*ptr++ = ap_rep.length & 0xff;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/*
5297c478bd9Sstevel@tonic-gate 	 * ap-rep data
5307c478bd9Sstevel@tonic-gate 	 */
5317c478bd9Sstevel@tonic-gate 	if (ap_rep.length) {
5327c478bd9Sstevel@tonic-gate 		(void) memcpy(ptr, ap_rep.data, ap_rep.length);
5337c478bd9Sstevel@tonic-gate 		ptr += ap_rep.length;
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	/*
5377c478bd9Sstevel@tonic-gate 	 * krb-priv or krb-error
5387c478bd9Sstevel@tonic-gate 	 */
5397c478bd9Sstevel@tonic-gate 	(void) memcpy(ptr, cipher.data, cipher.length);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate bailout:
5427c478bd9Sstevel@tonic-gate 	if (auth_context)
5437c478bd9Sstevel@tonic-gate 		krb5_auth_con_free(context, auth_context);
5447c478bd9Sstevel@tonic-gate 	if (changepw)
5457c478bd9Sstevel@tonic-gate 		krb5_free_principal(context, changepw);
5467c478bd9Sstevel@tonic-gate 	if (ap_rep.data != NULL)
5477c478bd9Sstevel@tonic-gate 		krb5_xfree(ap_rep.data);
5487c478bd9Sstevel@tonic-gate 	if (ticket)
5497c478bd9Sstevel@tonic-gate 		krb5_free_ticket(context, ticket);
5507c478bd9Sstevel@tonic-gate 	if (clear.data != NULL)
5517c478bd9Sstevel@tonic-gate 		krb5_xfree(clear.data);
5527c478bd9Sstevel@tonic-gate 	if (cipher.data != NULL)
5537c478bd9Sstevel@tonic-gate 		krb5_xfree(cipher.data);
5547c478bd9Sstevel@tonic-gate 	if (allocated_mem)
5557c478bd9Sstevel@tonic-gate 		krb5_xfree(local_kaddr.contents);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	return (ret);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate /*
5627c478bd9Sstevel@tonic-gate  * This routine is used to handle password-change requests received
5637c478bd9Sstevel@tonic-gate  * on kpasswd-port 464 from MIT/M$ clients.
5647c478bd9Sstevel@tonic-gate  */
5657c478bd9Sstevel@tonic-gate void
handle_chpw(krb5_context context,int s1,void * serverhandle,kadm5_config_params * params)5667c478bd9Sstevel@tonic-gate handle_chpw(krb5_context context, int s1,
5677c478bd9Sstevel@tonic-gate 		void *serverhandle, kadm5_config_params *params)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	krb5_error_code ret;
5707c478bd9Sstevel@tonic-gate 	char req[MAXAPREQ];
5717c478bd9Sstevel@tonic-gate 	int len;
5727c478bd9Sstevel@tonic-gate 	struct sockaddr_in from;
5737c478bd9Sstevel@tonic-gate 	int fromlen;
5747c478bd9Sstevel@tonic-gate 	krb5_keytab kt;
5757c478bd9Sstevel@tonic-gate 	krb5_data reqdata, repdata;
5767c478bd9Sstevel@tonic-gate 	int s2 = -1;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	reqdata.length = 0;
5797c478bd9Sstevel@tonic-gate 	reqdata.data = NULL;
5807c478bd9Sstevel@tonic-gate 	repdata.length = 0;
5817c478bd9Sstevel@tonic-gate 	repdata.data = NULL;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	fromlen = sizeof (from);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if ((len = recvfrom(s1, req, sizeof (req), 0, (struct sockaddr *)&from,
5867c478bd9Sstevel@tonic-gate 			    &fromlen)) < 0) {
5877c478bd9Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't receive "
5887c478bd9Sstevel@tonic-gate 				"request: %s"), error_message(errno));
5897c478bd9Sstevel@tonic-gate 		return;
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
592*46c8d03dSMark Phalan 	/*
593*46c8d03dSMark Phalan 	 * Solaris Kerberos:
594*46c8d03dSMark Phalan 	 * The only caller is kadmind, which is the master and therefore has the
595*46c8d03dSMark Phalan 	 * correct keys in the KDB, rather than obtaining them via the
596*46c8d03dSMark Phalan 	 * kadm5.keytab, by default.
597*46c8d03dSMark Phalan 	 */
598*46c8d03dSMark Phalan 	if ((ret = krb5_kt_resolve(context, "KDB:", &kt))) {
5997c478bd9Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't open "
6007c478bd9Sstevel@tonic-gate 				"admin keytab %s"), error_message(ret));
6017c478bd9Sstevel@tonic-gate 		return;
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	reqdata.length = len;
6057c478bd9Sstevel@tonic-gate 	reqdata.data = req;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * This is really obscure.  s1 is used for all communications.  it
6097c478bd9Sstevel@tonic-gate 	 * is left unconnected in case the server is multihomed and routes
6107c478bd9Sstevel@tonic-gate 	 * are asymmetric.  s2 is connected to resolve routes and get
6117c478bd9Sstevel@tonic-gate 	 * addresses.  this is the *only* way to get proper addresses for
6127c478bd9Sstevel@tonic-gate 	 * multihomed hosts if routing is asymmetric.
6137c478bd9Sstevel@tonic-gate 	 *
6147c478bd9Sstevel@tonic-gate 	 * A related problem in the server, but not the client, is that
6157c478bd9Sstevel@tonic-gate 	 * many os's have no way to disconnect a connected udp socket, so
6167c478bd9Sstevel@tonic-gate 	 * the s2 socket needs to be closed and recreated for each
6177c478bd9Sstevel@tonic-gate 	 * request.  The s1 socket must not be closed, or else queued
6187c478bd9Sstevel@tonic-gate 	 * requests will be lost.
6197c478bd9Sstevel@tonic-gate 	 *
6207c478bd9Sstevel@tonic-gate 	 * A "naive" client implementation (one socket, no connect,
6217c478bd9Sstevel@tonic-gate 	 * hostname resolution to get the local ip addr) will work and
6227c478bd9Sstevel@tonic-gate 	 * interoperate if the client is single-homed.
6237c478bd9Sstevel@tonic-gate 	 */
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
6267c478bd9Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("chpw: Cannot create "
6277c478bd9Sstevel@tonic-gate 				"connecting socket: %s"), error_message(errno));
6287c478bd9Sstevel@tonic-gate 		goto cleanup;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (connect(s2, (struct sockaddr *)&from, sizeof (from)) < 0) {
6327c478bd9Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("chpw: Couldn't connect "
6337c478bd9Sstevel@tonic-gate 				"to client: %s"), error_message(errno));
6347c478bd9Sstevel@tonic-gate 		if (s2 > 0)
6357c478bd9Sstevel@tonic-gate 			(void) close(s2);
6367c478bd9Sstevel@tonic-gate 		goto cleanup;
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	if ((ret = process_chpw_request(context, serverhandle,
6407c478bd9Sstevel@tonic-gate 					params->realm, s2, kt, &from,
6417c478bd9Sstevel@tonic-gate 					&reqdata, &repdata))) {
6427c478bd9Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("chpw: Error processing "
6437c478bd9Sstevel@tonic-gate 				"request: %s"), error_message(ret));
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (s2 > 0)
6477c478bd9Sstevel@tonic-gate 		(void) close(s2);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	if (repdata.length == 0 || repdata.data == NULL) {
6507c478bd9Sstevel@tonic-gate 		/*
6517c478bd9Sstevel@tonic-gate 		 * Just return.  This means something really bad happened
6527c478bd9Sstevel@tonic-gate 		 */
6537c478bd9Sstevel@tonic-gate 		goto cleanup;
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	len = sendto(s1, repdata.data, repdata.length, 0,
6577c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)&from, sizeof (from));
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if (len < repdata.length) {
6607c478bd9Sstevel@tonic-gate 		krb5_xfree(repdata.data);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("chpw: Error sending reply:"
6637c478bd9Sstevel@tonic-gate 				" %s"), error_message(errno));
6647c478bd9Sstevel@tonic-gate 		goto cleanup;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	if (repdata.data != NULL)
6687c478bd9Sstevel@tonic-gate 		krb5_xfree(repdata.data);
6697c478bd9Sstevel@tonic-gate cleanup:
6707c478bd9Sstevel@tonic-gate 	krb5_kt_close(context, kt);
6717c478bd9Sstevel@tonic-gate }
672