xref: /illumos-gate/usr/src/lib/krb5/kadm5/clnt/changepw.c (revision 159d09a2)
17c478bd9Sstevel@tonic-gate /*
2*159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3505d05c7Sgtb  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * lib/krb5/os/changepw.c
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Copyright 1990,1999 by the Massachusetts Institute of Technology.
117c478bd9Sstevel@tonic-gate  * All Rights Reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
147c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
157c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
167c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
197c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
207c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
217c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
227c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
237c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
247c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
257c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
267c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
277c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
287c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
297c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
307c478bd9Sstevel@tonic-gate  * or implied warranty.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #define	NEED_SOCKETS
357c478bd9Sstevel@tonic-gate #include <k5-int.h>
367c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
377c478bd9Sstevel@tonic-gate #include <client_internal.h>
387c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
397c478bd9Sstevel@tonic-gate #include <gssapi_krb5.h>
407c478bd9Sstevel@tonic-gate #include <gssapiP_krb5.h>
41*159d09a2SMark Phalan #include <krb5.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* #include "adm_err.h" */
447c478bd9Sstevel@tonic-gate #include <stdio.h>
457c478bd9Sstevel@tonic-gate #include <errno.h>
467c478bd9Sstevel@tonic-gate 
47*159d09a2SMark Phalan extern krb5_error_code krb5int_mk_chpw_req(krb5_context  context,
487c478bd9Sstevel@tonic-gate 					krb5_auth_context auth_context,
497c478bd9Sstevel@tonic-gate 					krb5_data *ap_req, char *passwd,
507c478bd9Sstevel@tonic-gate 					krb5_data *packet);
517c478bd9Sstevel@tonic-gate 
52*159d09a2SMark Phalan extern krb5_error_code krb5int_rd_chpw_rep(krb5_context context,
537c478bd9Sstevel@tonic-gate 					krb5_auth_context auth_context,
547c478bd9Sstevel@tonic-gate 					krb5_data *packet, int *result_code,
557c478bd9Sstevel@tonic-gate 					krb5_data *result_data);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * _kadm5_get_kpasswd_protocol
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * returns the password change protocol value to the caller.
617c478bd9Sstevel@tonic-gate  * Since the 'handle' is an opaque value to higher up callers,
627c478bd9Sstevel@tonic-gate  * this method is needed to provide a way for them to get a peek
637c478bd9Sstevel@tonic-gate  * at the protocol being used without having to expose the entire
647c478bd9Sstevel@tonic-gate  * handle structure.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate krb5_chgpwd_prot
_kadm5_get_kpasswd_protocol(void * handle)677c478bd9Sstevel@tonic-gate _kadm5_get_kpasswd_protocol(void *handle)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	kadm5_server_handle_t srvrhdl = (kadm5_server_handle_t)handle;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	return (srvrhdl->params.kpasswd_protocol);
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * krb5_change_password
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * Prepare and send a CHANGEPW request to a password server
787c478bd9Sstevel@tonic-gate  * using UDP datagrams.  This is only used for sending to
797c478bd9Sstevel@tonic-gate  * non-SEAM servers which support the Marc Horowitz defined
807c478bd9Sstevel@tonic-gate  * protocol (1998) for password changing.
817c478bd9Sstevel@tonic-gate  *
82505d05c7Sgtb  * SUNW14resync - added _local as it conflicts with one in krb5.h
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_change_password_local(context,params,creds,newpw,srvr_rsp_code,srvr_msg)85505d05c7Sgtb krb5_change_password_local(context, params, creds, newpw, srvr_rsp_code,
867c478bd9Sstevel@tonic-gate 		    srvr_msg)
877c478bd9Sstevel@tonic-gate krb5_context context;
887c478bd9Sstevel@tonic-gate kadm5_config_params *params;
897c478bd9Sstevel@tonic-gate krb5_creds *creds;
907c478bd9Sstevel@tonic-gate char *newpw;
917c478bd9Sstevel@tonic-gate kadm5_ret_t *srvr_rsp_code;
927c478bd9Sstevel@tonic-gate krb5_data *srvr_msg;
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	krb5_auth_context auth_context;
957c478bd9Sstevel@tonic-gate 	krb5_data ap_req, chpw_req, chpw_rep;
967c478bd9Sstevel@tonic-gate 	krb5_address local_kaddr, remote_kaddr;
977c478bd9Sstevel@tonic-gate 	krb5_error_code code = 0;
987c478bd9Sstevel@tonic-gate 	int i, addrlen;
997c478bd9Sstevel@tonic-gate 	struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr;
1007c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin_p;
1017c478bd9Sstevel@tonic-gate 	struct hostent *hp;
1027c478bd9Sstevel@tonic-gate 	int naddr_p;
1037c478bd9Sstevel@tonic-gate 	int cc, local_result_code, tmp_len;
1047c478bd9Sstevel@tonic-gate 	SOCKET s1 = INVALID_SOCKET;
1057c478bd9Sstevel@tonic-gate 	SOCKET s2 = INVALID_SOCKET;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/* Initialize values so that cleanup call can safely check for NULL */
1097c478bd9Sstevel@tonic-gate 	auth_context = NULL;
1107c478bd9Sstevel@tonic-gate 	addr_p = NULL;
1117c478bd9Sstevel@tonic-gate 	memset(&chpw_req, 0, sizeof (krb5_data));
1127c478bd9Sstevel@tonic-gate 	memset(&chpw_rep, 0, sizeof (krb5_data));
1137c478bd9Sstevel@tonic-gate 	memset(&ap_req, 0, sizeof (krb5_data));
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/* initialize auth_context so that we know we have to free it */
1167c478bd9Sstevel@tonic-gate 	if ((code = krb5_auth_con_init(context, &auth_context)))
1177c478bd9Sstevel@tonic-gate 		goto cleanup;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	if (code = krb5_mk_req_extended(context, &auth_context,
1207c478bd9Sstevel@tonic-gate 					AP_OPTS_USE_SUBKEY,
1217c478bd9Sstevel@tonic-gate 					NULL, creds, &ap_req))
1227c478bd9Sstevel@tonic-gate 		goto cleanup;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	/*
1257c478bd9Sstevel@tonic-gate 	 * find the address of the kpasswd_server.
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 	addr_p = (struct sockaddr *)malloc(sizeof (struct sockaddr));
1287c478bd9Sstevel@tonic-gate 	if (!addr_p)
1297c478bd9Sstevel@tonic-gate 		goto cleanup;
1307c478bd9Sstevel@tonic-gate 	memset(addr_p, 0, sizeof (struct sockaddr));
1317c478bd9Sstevel@tonic-gate 	if ((hp = gethostbyname(params->kpasswd_server)) == NULL) {
1327c478bd9Sstevel@tonic-gate 		code = KRB5_REALM_CANT_RESOLVE;
1337c478bd9Sstevel@tonic-gate 		goto cleanup;
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 	sin_p = (struct sockaddr_in *)addr_p;
1367c478bd9Sstevel@tonic-gate 	memset((char *)sin_p, 0, sizeof (struct sockaddr));
1377c478bd9Sstevel@tonic-gate 	sin_p->sin_family = hp->h_addrtype;
1387c478bd9Sstevel@tonic-gate 	sin_p->sin_port = htons(params->kpasswd_port);
1397c478bd9Sstevel@tonic-gate 	memcpy((char *)&sin_p->sin_addr, (char *)hp->h_addr, hp->h_length);
1407c478bd9Sstevel@tonic-gate 	naddr_p = 1;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * this is really obscure.  s1 is used for all communications.  it
1457c478bd9Sstevel@tonic-gate 	 * is left unconnected in case the server is multihomed and routes
1467c478bd9Sstevel@tonic-gate 	 * are asymmetric.  s2 is connected to resolve routes and get
1477c478bd9Sstevel@tonic-gate 	 * addresses.  this is the *only* way to get proper addresses for
1487c478bd9Sstevel@tonic-gate 	 * multihomed hosts if routing is asymmetric.
1497c478bd9Sstevel@tonic-gate 	 *
1507c478bd9Sstevel@tonic-gate 	 * A related problem in the server, but not the client, is that
1517c478bd9Sstevel@tonic-gate 	 * many os's have no way to disconnect a connected udp socket, so
1527c478bd9Sstevel@tonic-gate 	 * the s2 socket needs to be closed and recreated for each
1537c478bd9Sstevel@tonic-gate 	 * request.  The s1 socket must not be closed, or else queued
1547c478bd9Sstevel@tonic-gate 	 * requests will be lost.
1557c478bd9Sstevel@tonic-gate 	 *
1567c478bd9Sstevel@tonic-gate 	 * A "naive" client implementation (one socket, no connect,
1577c478bd9Sstevel@tonic-gate 	 * hostname resolution to get the local ip addr) will work and
1587c478bd9Sstevel@tonic-gate 	 * interoperate if the client is single-homed.
1597c478bd9Sstevel@tonic-gate 	 */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
1627c478bd9Sstevel@tonic-gate 	{
1637c478bd9Sstevel@tonic-gate 		code = errno;
1647c478bd9Sstevel@tonic-gate 		goto cleanup;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
1687c478bd9Sstevel@tonic-gate 	{
1697c478bd9Sstevel@tonic-gate 		code = errno;
1707c478bd9Sstevel@tonic-gate 		goto cleanup;
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	for (i = 0; i < naddr_p; i++)
1747c478bd9Sstevel@tonic-gate 	{
1757c478bd9Sstevel@tonic-gate 		fd_set fdset;
1767c478bd9Sstevel@tonic-gate 		struct timeval timeout;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 		if (connect(s2, &addr_p[i], sizeof (addr_p[i])) ==
1797c478bd9Sstevel@tonic-gate 		    SOCKET_ERROR)
1807c478bd9Sstevel@tonic-gate 		{
1817c478bd9Sstevel@tonic-gate 			if ((errno == ECONNREFUSED) ||
1827c478bd9Sstevel@tonic-gate 			    (errno == EHOSTUNREACH))
1837c478bd9Sstevel@tonic-gate 				continue; /* try the next addr */
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 			code = errno;
1867c478bd9Sstevel@tonic-gate 			goto cleanup;
1877c478bd9Sstevel@tonic-gate 		}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 		addrlen = sizeof (local_addr);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		if (getsockname(s2, &local_addr, &addrlen) < 0)
1927c478bd9Sstevel@tonic-gate 		{
1937c478bd9Sstevel@tonic-gate 			if ((errno == ECONNREFUSED) ||
1947c478bd9Sstevel@tonic-gate 			    (errno == EHOSTUNREACH))
1957c478bd9Sstevel@tonic-gate 				continue; /* try the next addr */
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 			code = errno;
1987c478bd9Sstevel@tonic-gate 			goto cleanup;
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 		/*
2027c478bd9Sstevel@tonic-gate 		 * some brain-dead OS's don't return useful information from
2037c478bd9Sstevel@tonic-gate 		 * the getsockname call.  Namely, windows and solaris.
2047c478bd9Sstevel@tonic-gate 		 */
2057c478bd9Sstevel@tonic-gate 		if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0)
2067c478bd9Sstevel@tonic-gate 		{
2077c478bd9Sstevel@tonic-gate 			local_kaddr.addrtype = ADDRTYPE_INET;
2087c478bd9Sstevel@tonic-gate 			local_kaddr.length = sizeof (((struct sockaddr_in *)
2097c478bd9Sstevel@tonic-gate 						    &local_addr)->sin_addr);
2107c478bd9Sstevel@tonic-gate 			local_kaddr.contents = (krb5_octet *)
2117c478bd9Sstevel@tonic-gate 				&(((struct sockaddr_in *)
2127c478bd9Sstevel@tonic-gate 				&local_addr)->sin_addr);
2137c478bd9Sstevel@tonic-gate 		}
2147c478bd9Sstevel@tonic-gate 		else
2157c478bd9Sstevel@tonic-gate 		{
2167c478bd9Sstevel@tonic-gate 			krb5_address **addrs;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 			krb5_os_localaddr(context, &addrs);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 			local_kaddr.magic = addrs[0]->magic;
2217c478bd9Sstevel@tonic-gate 			local_kaddr.addrtype = addrs[0]->addrtype;
2227c478bd9Sstevel@tonic-gate 			local_kaddr.length = addrs[0]->length;
2237c478bd9Sstevel@tonic-gate 			local_kaddr.contents = malloc(addrs[0]->length);
2247c478bd9Sstevel@tonic-gate 			memcpy(local_kaddr.contents, addrs[0]->contents,
2257c478bd9Sstevel@tonic-gate 			    addrs[0]->length);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			krb5_free_addresses(context, addrs);
2287c478bd9Sstevel@tonic-gate 		}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		addrlen = sizeof (remote_addr);
2317c478bd9Sstevel@tonic-gate 		if (getpeername(s2, &remote_addr, &addrlen) < 0)
2327c478bd9Sstevel@tonic-gate 		{
2337c478bd9Sstevel@tonic-gate 			if ((errno == ECONNREFUSED) ||
2347c478bd9Sstevel@tonic-gate 			    (errno == EHOSTUNREACH))
2357c478bd9Sstevel@tonic-gate 				continue; /* try the next addr */
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 			code = errno;
2387c478bd9Sstevel@tonic-gate 			goto cleanup;
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 		remote_kaddr.addrtype = ADDRTYPE_INET;
2427c478bd9Sstevel@tonic-gate 		remote_kaddr.length = sizeof (((struct sockaddr_in *)
2437c478bd9Sstevel@tonic-gate 					    &remote_addr)->sin_addr);
2447c478bd9Sstevel@tonic-gate 		remote_kaddr.contents = (krb5_octet *)
2457c478bd9Sstevel@tonic-gate 			&(((struct sockaddr_in *)&remote_addr)->sin_addr);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		/*
2487c478bd9Sstevel@tonic-gate 		 * mk_priv requires that the local address be set.
2497c478bd9Sstevel@tonic-gate 		 * getsockname is used for this.  rd_priv requires that the
2507c478bd9Sstevel@tonic-gate 		 * remote address be set.  recvfrom is used for this.  If
2517c478bd9Sstevel@tonic-gate 		 * rd_priv is given a local address, and the message has the
2527c478bd9Sstevel@tonic-gate 		 * recipient addr in it, this will be checked.  However, there
2537c478bd9Sstevel@tonic-gate 		 * is simply no way to know ahead of time what address the
2547c478bd9Sstevel@tonic-gate 		 * message will be delivered *to*.  Therefore, it is important
2557c478bd9Sstevel@tonic-gate 		 * that either no recipient address is in the messages when
2567c478bd9Sstevel@tonic-gate 		 * mk_priv is called, or that no local address is passed to
2577c478bd9Sstevel@tonic-gate 		 * rd_priv.  Both is a better idea, and I have done that.  In
2587c478bd9Sstevel@tonic-gate 		 * summary, when mk_priv is called, *only* a local address is
2597c478bd9Sstevel@tonic-gate 		 * specified.  when rd_priv is called, *only* a remote address
2607c478bd9Sstevel@tonic-gate 		 * is specified.  Are we having fun yet?
2617c478bd9Sstevel@tonic-gate 		 */
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		if (code = krb5_auth_con_setaddrs(context, auth_context,
2647c478bd9Sstevel@tonic-gate 						&local_kaddr, NULL))
2657c478bd9Sstevel@tonic-gate 		{
2667c478bd9Sstevel@tonic-gate 			code = errno;
2677c478bd9Sstevel@tonic-gate 			goto cleanup;
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 
270*159d09a2SMark Phalan 		if (code = krb5int_mk_chpw_req(context, auth_context,
2717c478bd9Sstevel@tonic-gate 					    &ap_req, newpw, &chpw_req))
2727c478bd9Sstevel@tonic-gate 		{
2737c478bd9Sstevel@tonic-gate 			code = errno;
2747c478bd9Sstevel@tonic-gate 			goto cleanup;
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0,
2787c478bd9Sstevel@tonic-gate 		    (struct sockaddr *)&addr_p[i],
2797c478bd9Sstevel@tonic-gate 		    sizeof (addr_p[i]))) != chpw_req.length)
2807c478bd9Sstevel@tonic-gate 		{
2817c478bd9Sstevel@tonic-gate 			if ((cc < 0) && ((errno == ECONNREFUSED) ||
2827c478bd9Sstevel@tonic-gate 					(errno == EHOSTUNREACH)))
2837c478bd9Sstevel@tonic-gate 				continue; /* try the next addr */
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 			code = (cc < 0) ? errno : ECONNABORTED;
2867c478bd9Sstevel@tonic-gate 			goto cleanup;
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		chpw_rep.length = 1500;
2907c478bd9Sstevel@tonic-gate 		chpw_rep.data = (char *)malloc(chpw_rep.length);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		/* XXX need a timeout/retry loop here */
2937c478bd9Sstevel@tonic-gate 		FD_ZERO(&fdset);
2947c478bd9Sstevel@tonic-gate 		FD_SET(s1, &fdset);
2957c478bd9Sstevel@tonic-gate 		timeout.tv_sec = 120;
2967c478bd9Sstevel@tonic-gate 		timeout.tv_usec = 0;
2977c478bd9Sstevel@tonic-gate 		switch (select(s1 + 1, &fdset, 0, 0, &timeout)) {
2987c478bd9Sstevel@tonic-gate 		case -1:
2997c478bd9Sstevel@tonic-gate 			code = errno;
3007c478bd9Sstevel@tonic-gate 			goto cleanup;
3017c478bd9Sstevel@tonic-gate 		case 0:
3027c478bd9Sstevel@tonic-gate 			code = ETIMEDOUT;
3037c478bd9Sstevel@tonic-gate 			goto cleanup;
3047c478bd9Sstevel@tonic-gate 		default:
3057c478bd9Sstevel@tonic-gate 			/* fall through */
3067c478bd9Sstevel@tonic-gate 			;
3077c478bd9Sstevel@tonic-gate 		}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 		tmp_len = sizeof (tmp_addr);
3107c478bd9Sstevel@tonic-gate 		if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length,
3117c478bd9Sstevel@tonic-gate 				0, &tmp_addr, &tmp_len)) < 0)
3127c478bd9Sstevel@tonic-gate 		{
3137c478bd9Sstevel@tonic-gate 			code = errno;
3147c478bd9Sstevel@tonic-gate 			goto cleanup;
3157c478bd9Sstevel@tonic-gate 		}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		closesocket(s1);
3187c478bd9Sstevel@tonic-gate 		s1 = INVALID_SOCKET;
3197c478bd9Sstevel@tonic-gate 		closesocket(s2);
3207c478bd9Sstevel@tonic-gate 		s2 = INVALID_SOCKET;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		chpw_rep.length = cc;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		if (code = krb5_auth_con_setaddrs(context, auth_context,
3257c478bd9Sstevel@tonic-gate 						NULL, &remote_kaddr))
3267c478bd9Sstevel@tonic-gate 			goto cleanup;
3277c478bd9Sstevel@tonic-gate 
328*159d09a2SMark Phalan 		if (code = krb5int_rd_chpw_rep(context, auth_context, &chpw_rep,
3297c478bd9Sstevel@tonic-gate 					&local_result_code, srvr_msg))
3307c478bd9Sstevel@tonic-gate 			goto cleanup;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		if (srvr_rsp_code)
3337c478bd9Sstevel@tonic-gate 			*srvr_rsp_code = local_result_code;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 		code = 0;
3367c478bd9Sstevel@tonic-gate 		goto cleanup;
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	code = errno;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate cleanup:
3427c478bd9Sstevel@tonic-gate 	if (auth_context != NULL)
3437c478bd9Sstevel@tonic-gate 		krb5_auth_con_free(context, auth_context);
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	if (addr_p != NULL)
3467c478bd9Sstevel@tonic-gate 		krb5_xfree(addr_p);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if (s1 != INVALID_SOCKET)
3497c478bd9Sstevel@tonic-gate 		closesocket(s1);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	if (s2 != INVALID_SOCKET)
3527c478bd9Sstevel@tonic-gate 		closesocket(s2);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	krb5_xfree(chpw_req.data);
3557c478bd9Sstevel@tonic-gate 	krb5_xfree(chpw_rep.data);
3567c478bd9Sstevel@tonic-gate 	krb5_xfree(ap_req.data);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	return (code);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate /*
3637c478bd9Sstevel@tonic-gate  * kadm5_chpass_principal_v2
3647c478bd9Sstevel@tonic-gate  *
3657c478bd9Sstevel@tonic-gate  * New function used to prepare to make the change password request to a
3667c478bd9Sstevel@tonic-gate  * non-SEAM admin server.  The protocol used in this case is not based on
3677c478bd9Sstevel@tonic-gate  * RPCSEC_GSS, it simply makes the request to port 464 (udp and tcp).
3687c478bd9Sstevel@tonic-gate  * This is the same way that MIT KRB5 1.2.1 changes passwords.
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate kadm5_ret_t
kadm5_chpass_principal_v2(void * server_handle,krb5_principal princ,char * newpw,kadm5_ret_t * srvr_rsp_code,krb5_data * srvr_msg)3717c478bd9Sstevel@tonic-gate kadm5_chpass_principal_v2(void *server_handle,
3727c478bd9Sstevel@tonic-gate 			krb5_principal princ,
3737c478bd9Sstevel@tonic-gate 			char *newpw,
3747c478bd9Sstevel@tonic-gate 			kadm5_ret_t *srvr_rsp_code,
3757c478bd9Sstevel@tonic-gate 			krb5_data *srvr_msg)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	kadm5_ret_t code;
3787c478bd9Sstevel@tonic-gate 	kadm5_server_handle_t handle  = (kadm5_server_handle_t)server_handle;
3797c478bd9Sstevel@tonic-gate 	krb5_error_code result;
3807c478bd9Sstevel@tonic-gate 	krb5_creds mcreds;
3817c478bd9Sstevel@tonic-gate 	krb5_creds ncreds;
3827c478bd9Sstevel@tonic-gate 	krb5_ccache ccache;
3837c478bd9Sstevel@tonic-gate 	int cpwlen;
3847c478bd9Sstevel@tonic-gate 	char *cpw_service = NULL;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 * The credentials have already been stored in the cache in the
3887c478bd9Sstevel@tonic-gate 	 * initialization step earlier, but we dont have direct access to it
3897c478bd9Sstevel@tonic-gate 	 * at this level. Derive the cache and fetch the credentials to use for
3907c478bd9Sstevel@tonic-gate 	 * sending the request.
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	memset(&mcreds, 0, sizeof (krb5_creds));
3937c478bd9Sstevel@tonic-gate 	if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
3947c478bd9Sstevel@tonic-gate 				    &ccache)))
3957c478bd9Sstevel@tonic-gate 		return (code);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* set the client principal in the credential match structure */
3987c478bd9Sstevel@tonic-gate 	mcreds.client = princ;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	/*
4017c478bd9Sstevel@tonic-gate 	 * set the server principal (kadmin/changepw@REALM) in the credential
4027c478bd9Sstevel@tonic-gate 	 * match struct
4037c478bd9Sstevel@tonic-gate 	 */
4047c478bd9Sstevel@tonic-gate 	cpwlen = strlen(KADM5_CHANGEPW_SERVICE) +
4057c478bd9Sstevel@tonic-gate 		strlen(handle->params.realm) + 2;
4067c478bd9Sstevel@tonic-gate 	cpw_service = malloc(cpwlen);
4077c478bd9Sstevel@tonic-gate 	if (cpw_service == NULL) {
4087c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	snprintf(cpw_service, cpwlen, "%s@%s",
4127c478bd9Sstevel@tonic-gate 		KADM5_CHANGEPW_SERVICE,	handle->params.realm);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/* generate the server principal from the name string we generated */
4157c478bd9Sstevel@tonic-gate 	if ((code = krb5_parse_name(handle->context, cpw_service,
4167c478bd9Sstevel@tonic-gate 		&mcreds.server))) {
4177c478bd9Sstevel@tonic-gate 		free(cpw_service);
4187c478bd9Sstevel@tonic-gate 		return (code);
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/* Find the credentials in the cache */
4227c478bd9Sstevel@tonic-gate 	if ((code = krb5_cc_retrieve_cred(handle->context, ccache, 0, &mcreds,
4237c478bd9Sstevel@tonic-gate 					&ncreds))) {
4247c478bd9Sstevel@tonic-gate 		free(cpw_service);
4257c478bd9Sstevel@tonic-gate 		return (code);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	/* Now we have all we need to make the change request. */
429505d05c7Sgtb 	result = krb5_change_password_local(handle->context, &handle->params,
4307c478bd9Sstevel@tonic-gate 				    &ncreds, newpw,
4317c478bd9Sstevel@tonic-gate 				    srvr_rsp_code,
4327c478bd9Sstevel@tonic-gate 				    srvr_msg);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	free(cpw_service);
4357c478bd9Sstevel@tonic-gate 	return (result);
4367c478bd9Sstevel@tonic-gate }
437