xref: /titanic_52/usr/src/lib/krb5/kadm5/clnt/client_init.c (revision 159d09a20817016f09b3ea28d1bdada4a336bb91)
17c478bd9Sstevel@tonic-gate /*
2bd211b85Ssemery  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
6*159d09a2SMark Phalan 
7*159d09a2SMark Phalan 
8*159d09a2SMark Phalan /*
9*159d09a2SMark Phalan  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
10*159d09a2SMark Phalan  */
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate /*
137c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  * All rights reserved.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
187c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
197c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
207c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
237c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
247c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
257c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
267c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
277c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
287c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
297c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
307c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
317c478bd9Sstevel@tonic-gate  * or implied warranty.
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
347c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
357c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <netdb.h>
4054925bf6Swillf #include "autoconf.h"
4156a424ccSmp153739 #ifdef HAVE_MEMORY_H
427c478bd9Sstevel@tonic-gate #include <memory.h>
4356a424ccSmp153739 #endif
447c478bd9Sstevel@tonic-gate #include <string.h>
457c478bd9Sstevel@tonic-gate #include <com_err.h>
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/socket.h>
487c478bd9Sstevel@tonic-gate #include <netinet/in.h>
497c478bd9Sstevel@tonic-gate #include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
5054925bf6Swillf #include <krb5.h>
517c478bd9Sstevel@tonic-gate #ifdef __STDC__
527c478bd9Sstevel@tonic-gate #include <stdlib.h>
537c478bd9Sstevel@tonic-gate #endif
547c478bd9Sstevel@tonic-gate #include <libintl.h>
557c478bd9Sstevel@tonic-gate 
5656a424ccSmp153739 #include <kadm5/admin.h>
5756a424ccSmp153739 #include <kadm5/kadm_rpc.h>
5856a424ccSmp153739 #include "client_internal.h"
5956a424ccSmp153739 
607c478bd9Sstevel@tonic-gate #include <syslog.h>
617c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
627c478bd9Sstevel@tonic-gate #include <gssapi_krb5.h>
637c478bd9Sstevel@tonic-gate #include <gssapiP_krb5.h>
647c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
6556a424ccSmp153739 
667c478bd9Sstevel@tonic-gate #include <iprop_hdr.h>
677c478bd9Sstevel@tonic-gate #include "iprop.h"
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	ADM_CCACHE  "/tmp/ovsec_adm.XXXXXX"
707c478bd9Sstevel@tonic-gate 
7156a424ccSmp153739 static int old_auth_gssapi = 0;
727c478bd9Sstevel@tonic-gate /* connection timeout to kadmind in seconds */
737c478bd9Sstevel@tonic-gate #define		KADMIND_CONNECT_TIMEOUT	25
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate int _kadm5_check_handle();
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
807c478bd9Sstevel@tonic-gate 				   enum init_type init_type,
817c478bd9Sstevel@tonic-gate 				   char *pass,
827c478bd9Sstevel@tonic-gate 				   krb5_ccache ccache_in,
837c478bd9Sstevel@tonic-gate 				   char *service_name,
847c478bd9Sstevel@tonic-gate 				   kadm5_config_params *params,
857c478bd9Sstevel@tonic-gate 				   krb5_ui_4 struct_version,
867c478bd9Sstevel@tonic-gate 				   krb5_ui_4 api_version,
8754925bf6Swillf 				   char **db_args,
887c478bd9Sstevel@tonic-gate 				   void **server_handle);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_creds(char *client_name,
917c478bd9Sstevel@tonic-gate 				  krb5_ccache ccache,
927c478bd9Sstevel@tonic-gate 				  char *service_name,
937c478bd9Sstevel@tonic-gate 				  kadm5_config_params *params,
947c478bd9Sstevel@tonic-gate 				  krb5_ui_4 struct_version,
957c478bd9Sstevel@tonic-gate 				  krb5_ui_4 api_version,
9654925bf6Swillf 				  char **db_args,
977c478bd9Sstevel@tonic-gate 				  void **server_handle)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate      return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache,
1007c478bd9Sstevel@tonic-gate 			    service_name, params,
10154925bf6Swillf 			    struct_version, api_version, db_args,
1027c478bd9Sstevel@tonic-gate 			    server_handle);
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
1077c478bd9Sstevel@tonic-gate 				     char *service_name,
1087c478bd9Sstevel@tonic-gate 				     kadm5_config_params *params,
1097c478bd9Sstevel@tonic-gate 				     krb5_ui_4 struct_version,
1107c478bd9Sstevel@tonic-gate 				     krb5_ui_4 api_version,
11154925bf6Swillf 				     char **db_args,
1127c478bd9Sstevel@tonic-gate 				     void **server_handle)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate      return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
1157c478bd9Sstevel@tonic-gate 			    service_name, params, struct_version,
11654925bf6Swillf 			    api_version, db_args, server_handle);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_init(char *client_name, char *pass,
1207c478bd9Sstevel@tonic-gate 		       char *service_name,
1217c478bd9Sstevel@tonic-gate 		       kadm5_config_params *params,
1227c478bd9Sstevel@tonic-gate 		       krb5_ui_4 struct_version,
1237c478bd9Sstevel@tonic-gate 		       krb5_ui_4 api_version,
12454925bf6Swillf 		       char **db_args,
1257c478bd9Sstevel@tonic-gate 		       void **server_handle)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate      return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
1287c478bd9Sstevel@tonic-gate 			    service_name, params, struct_version,
12954925bf6Swillf 			    api_version, db_args, server_handle);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
1337c478bd9Sstevel@tonic-gate 				 char *service_name,
1347c478bd9Sstevel@tonic-gate 				 kadm5_config_params *params,
1357c478bd9Sstevel@tonic-gate 				 krb5_ui_4 struct_version,
1367c478bd9Sstevel@tonic-gate 				 krb5_ui_4 api_version,
13754925bf6Swillf 				 char **db_args,
1387c478bd9Sstevel@tonic-gate 				 void **server_handle)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate      return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL,
1417c478bd9Sstevel@tonic-gate 			    service_name, params, struct_version,
14254925bf6Swillf 			    api_version, db_args, server_handle);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate krb5_error_code  kadm5_free_config_params();
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static void
1487c478bd9Sstevel@tonic-gate display_status_1(m, code, type, mech)
1497c478bd9Sstevel@tonic-gate char *m;
1507c478bd9Sstevel@tonic-gate OM_uint32 code;
1517c478bd9Sstevel@tonic-gate int type;
1527c478bd9Sstevel@tonic-gate const gss_OID mech;
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	OM_uint32 maj_stat, min_stat;
1557c478bd9Sstevel@tonic-gate 	gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
1567c478bd9Sstevel@tonic-gate 	OM_uint32 msg_ctx;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	msg_ctx = 0;
1597c478bd9Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR, "%s\n", m);
1607c478bd9Sstevel@tonic-gate 	/* LINTED */
1617c478bd9Sstevel@tonic-gate 	while (1) {
1627c478bd9Sstevel@tonic-gate 		maj_stat = gss_display_status(&min_stat, code,
1637c478bd9Sstevel@tonic-gate 					    type, mech,
1647c478bd9Sstevel@tonic-gate 					    &msg_ctx, &msg);
1657c478bd9Sstevel@tonic-gate 		if (maj_stat != GSS_S_COMPLETE) {
1667c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
1677c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
1687c478bd9Sstevel@tonic-gate 				    "error in gss_display_status"
1697c478bd9Sstevel@tonic-gate 				    " called from <%s>\n"), m);
1707c478bd9Sstevel@tonic-gate 			break;
1717c478bd9Sstevel@tonic-gate 		} else
1727c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
1737c478bd9Sstevel@tonic-gate 						"GSS-API error : %s\n"),
1747c478bd9Sstevel@tonic-gate 			    m);
1757c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
1767c478bd9Sstevel@tonic-gate 					"GSS-API error : %s\n"),
1777c478bd9Sstevel@tonic-gate 		    (char *)msg.value);
1787c478bd9Sstevel@tonic-gate 		if (msg.length != 0)
1797c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&min_stat, &msg);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		if (!msg_ctx)
1827c478bd9Sstevel@tonic-gate 			break;
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * Function: display_status
1887c478bd9Sstevel@tonic-gate  *
1897c478bd9Sstevel@tonic-gate  * Purpose: displays GSS-API messages
1907c478bd9Sstevel@tonic-gate  *
1917c478bd9Sstevel@tonic-gate  * Arguments:
1927c478bd9Sstevel@tonic-gate  *
1937c478bd9Sstevel@tonic-gate  * 	msg		a string to be displayed with the message
1947c478bd9Sstevel@tonic-gate  * 	maj_stat	the GSS-API major status code
1957c478bd9Sstevel@tonic-gate  * 	min_stat	the GSS-API minor status code
1967c478bd9Sstevel@tonic-gate  *	mech		kerberos mech
1977c478bd9Sstevel@tonic-gate  * Effects:
1987c478bd9Sstevel@tonic-gate  *
1997c478bd9Sstevel@tonic-gate  * The GSS-API messages associated with maj_stat and min_stat are
2007c478bd9Sstevel@tonic-gate  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
2017c478bd9Sstevel@tonic-gate  * followed by a newline.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate void
2047c478bd9Sstevel@tonic-gate display_status(msg, maj_stat, min_stat, mech)
2057c478bd9Sstevel@tonic-gate char *msg;
2067c478bd9Sstevel@tonic-gate OM_uint32 maj_stat;
2077c478bd9Sstevel@tonic-gate OM_uint32 min_stat;
2087c478bd9Sstevel@tonic-gate char *mech;
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	gss_OID mech_oid;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
2137c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
2147c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
2157c478bd9Sstevel@tonic-gate 				"Invalid mechanism oid <%s>"), mech);
2167c478bd9Sstevel@tonic-gate 		return;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	display_status_1(msg, maj_stat, GSS_C_GSS_CODE, mech_oid);
2207c478bd9Sstevel@tonic-gate 	display_status_1(msg, min_stat, GSS_C_MECH_CODE, mech_oid);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate  * Open an fd for the given address and connect asynchronously. Wait
2257c478bd9Sstevel@tonic-gate  * KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds
2267c478bd9Sstevel@tonic-gate  * change fd to blocking and return it, else return -1.
2277c478bd9Sstevel@tonic-gate  */
2287c478bd9Sstevel@tonic-gate static int
2297c478bd9Sstevel@tonic-gate get_connection(struct netconfig *nconf, struct netbuf netaddr)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	struct t_info tinfo;
2327c478bd9Sstevel@tonic-gate 	struct t_call sndcall;
2337c478bd9Sstevel@tonic-gate 	struct t_call *rcvcall = NULL;
2347c478bd9Sstevel@tonic-gate 	int connect_time;
2357c478bd9Sstevel@tonic-gate 	int flags;
2367c478bd9Sstevel@tonic-gate 	int fd;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	(void) memset(&tinfo, 0, sizeof (tinfo));
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/* we'l open with O_NONBLOCK and avoid an fcntl */
2417c478bd9Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR | O_NONBLOCK, &tinfo);
2427c478bd9Sstevel@tonic-gate 	if (fd == -1) {
2437c478bd9Sstevel@tonic-gate 		return (-1);
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	if (t_bind(fd, (struct t_bind *)NULL, (struct t_bind *)NULL) == -1) {
2477c478bd9Sstevel@tonic-gate 		(void) close(fd);
2487c478bd9Sstevel@tonic-gate 		return (-1);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	/* we can't connect unless fd is in IDLE state */
2527c478bd9Sstevel@tonic-gate 	if (t_getstate(fd) != T_IDLE) {
2537c478bd9Sstevel@tonic-gate 		(void) close(fd);
2547c478bd9Sstevel@tonic-gate 		return (-1);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/* setup connect parameters */
2587c478bd9Sstevel@tonic-gate 	netaddr.len = netaddr.maxlen = __rpc_get_a_size(tinfo.addr);
2597c478bd9Sstevel@tonic-gate 	sndcall.addr = netaddr;
2607c478bd9Sstevel@tonic-gate 	sndcall.opt.len = sndcall.udata.len = 0;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */
2637c478bd9Sstevel@tonic-gate 	connect_time = time(NULL) + KADMIND_CONNECT_TIMEOUT;
2647c478bd9Sstevel@tonic-gate 	if (t_connect(fd, &sndcall, rcvcall) != 0) {
2657c478bd9Sstevel@tonic-gate 		if (t_errno != TNODATA) {
2667c478bd9Sstevel@tonic-gate 			(void) close(fd);
2677c478bd9Sstevel@tonic-gate 			return (-1);
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/* loop till success or timeout */
2727c478bd9Sstevel@tonic-gate 	for (;;) {
2737c478bd9Sstevel@tonic-gate 		if (t_rcvconnect(fd, rcvcall) == 0)
2747c478bd9Sstevel@tonic-gate 			break;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		if (t_errno != TNODATA || time(NULL) > connect_time) {
2777c478bd9Sstevel@tonic-gate 			/* we have either timed out or caught an error */
2787c478bd9Sstevel@tonic-gate 			(void) close(fd);
2797c478bd9Sstevel@tonic-gate 			if (rcvcall != NULL)
2807c478bd9Sstevel@tonic-gate 				t_free((char *)rcvcall, T_CALL);
2817c478bd9Sstevel@tonic-gate 			return (-1);
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 		sleep(1);
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/* make the fd blocking (synchronous) */
2877c478bd9Sstevel@tonic-gate 	flags = fcntl(fd, F_GETFL, 0);
2887c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
2897c478bd9Sstevel@tonic-gate 	if (rcvcall != NULL)
2907c478bd9Sstevel@tonic-gate 		t_free((char *)rcvcall, T_CALL);
2917c478bd9Sstevel@tonic-gate 	return (fd);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate /*
2957c478bd9Sstevel@tonic-gate  * Open an RPCSEC_GSS connection and
2967c478bd9Sstevel@tonic-gate  * get a client handle to use for future RPCSEC calls.
2977c478bd9Sstevel@tonic-gate  *
2987c478bd9Sstevel@tonic-gate  * This function is only used when changing passwords and
2997c478bd9Sstevel@tonic-gate  * the kpasswd_protocol is RPCSEC_GSS
3007c478bd9Sstevel@tonic-gate  */
3017c478bd9Sstevel@tonic-gate static int
3027c478bd9Sstevel@tonic-gate _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle,
3037c478bd9Sstevel@tonic-gate 				    char *client_name,
3047c478bd9Sstevel@tonic-gate 				    char *service_name)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	struct netbuf netaddr;
3077c478bd9Sstevel@tonic-gate 	struct hostent *hp;
3087c478bd9Sstevel@tonic-gate 	int fd;
3097c478bd9Sstevel@tonic-gate 	struct sockaddr_in addr;
3107c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
3117c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
3127c478bd9Sstevel@tonic-gate 	int code = 0;
3137c478bd9Sstevel@tonic-gate 	generic_ret *r;
3147c478bd9Sstevel@tonic-gate 	char *ccname_orig;
3157c478bd9Sstevel@tonic-gate 	char *iprop_svc;
3167c478bd9Sstevel@tonic-gate 	boolean_t iprop_enable = B_FALSE;
3177c478bd9Sstevel@tonic-gate 	char mech[] = "kerberos_v5";
3187c478bd9Sstevel@tonic-gate 	gss_OID mech_oid;
3197c478bd9Sstevel@tonic-gate 	gss_OID_set_desc oid_set;
3207c478bd9Sstevel@tonic-gate 	gss_name_t gss_client;
3217c478bd9Sstevel@tonic-gate 	gss_buffer_desc input_name;
3227c478bd9Sstevel@tonic-gate 	gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL;
3237c478bd9Sstevel@tonic-gate 	rpc_gss_options_req_t   options_req;
3247c478bd9Sstevel@tonic-gate 	rpc_gss_options_ret_t   options_ret;
3257c478bd9Sstevel@tonic-gate 	rpc_gss_service_t service = rpc_gss_svc_privacy;
3267c478bd9Sstevel@tonic-gate 	OM_uint32 gssstat, minor_stat;
3277c478bd9Sstevel@tonic-gate 	void *handlep;
3287c478bd9Sstevel@tonic-gate 	enum clnt_stat rpc_err_code;
329bd211b85Ssemery 	char *server = handle->params.admin_server;
3307c478bd9Sstevel@tonic-gate 
331bd211b85Ssemery 	/*
332bd211b85Ssemery 	 * Try to find the kpasswd_server first if this is for the changepw
333bd211b85Ssemery 	 * service.  If defined then it should be resolvable else return error.
334bd211b85Ssemery 	 */
335bd211b85Ssemery 	if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE,
336bd211b85Ssemery 	    strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0) {
337bd211b85Ssemery 		if (handle->params.kpasswd_server != NULL)
338bd211b85Ssemery 			server = handle->params.kpasswd_server;
339bd211b85Ssemery 	}
340bd211b85Ssemery 	hp = gethostbyname(server);
3417c478bd9Sstevel@tonic-gate 	if (hp == (struct hostent *)NULL) {
3427c478bd9Sstevel@tonic-gate 		code = KADM5_BAD_SERVER_NAME;
3437c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
3447c478bd9Sstevel@tonic-gate 					    "bad server name\n"));
3457c478bd9Sstevel@tonic-gate 		goto cleanup;
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	memset(&addr, 0, sizeof (addr));
3497c478bd9Sstevel@tonic-gate 	addr.sin_family = hp->h_addrtype;
3507c478bd9Sstevel@tonic-gate 	(void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr,
3517c478bd9Sstevel@tonic-gate 		    sizeof (addr.sin_addr));
3527c478bd9Sstevel@tonic-gate 	addr.sin_port = htons((ushort_t)handle->params.kadmind_port);
3537c478bd9Sstevel@tonic-gate 	sin = &addr;
3547c478bd9Sstevel@tonic-gate #ifdef DEBUG
3557c478bd9Sstevel@tonic-gate 	printf("kadmin_port %d\n", handle->params.kadmind_port);
3567c478bd9Sstevel@tonic-gate 	printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n",
3577c478bd9Sstevel@tonic-gate 	    addr.sin_port, addr.sin_family, addr.sin_zero);
3587c478bd9Sstevel@tonic-gate 	printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1,
3597c478bd9Sstevel@tonic-gate 	    addr.sin_addr.S_un.S_un_w.s_w2);
3607c478bd9Sstevel@tonic-gate #endif
3617c478bd9Sstevel@tonic-gate 	if ((handlep = setnetconfig()) == (void *) NULL) {
3627c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
3637c478bd9Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
3647c478bd9Sstevel@tonic-gate 				    "cannot get any transport information"));
3657c478bd9Sstevel@tonic-gate 		goto error;
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	while (nconf = getnetconfig(handlep)) {
3697c478bd9Sstevel@tonic-gate 		if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
3707c478bd9Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
3717c478bd9Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0))
3727c478bd9Sstevel@tonic-gate 			break;
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	if (nconf == (struct netconfig *)NULL)
3767c478bd9Sstevel@tonic-gate 		goto error;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	/* Transform addr to netbuf */
3797c478bd9Sstevel@tonic-gate 	(void) memset(&netaddr, 0, sizeof (netaddr));
3807c478bd9Sstevel@tonic-gate 	netaddr.buf = (char *)sin;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	/* get an fd connected to the given address */
3837c478bd9Sstevel@tonic-gate 	fd =  get_connection(nconf, netaddr);
3847c478bd9Sstevel@tonic-gate 	if (fd == -1) {
3857c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
3867c478bd9Sstevel@tonic-gate 			"unable to open connection to ADMIN server "
3877c478bd9Sstevel@tonic-gate 			"(t_error %i)"), t_errno);
3887c478bd9Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
3897c478bd9Sstevel@tonic-gate 		goto error;
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate #ifdef DEBUG
3937c478bd9Sstevel@tonic-gate 	printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS);
3947c478bd9Sstevel@tonic-gate 	printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, "
3957c478bd9Sstevel@tonic-gate 	    "nc_protofmly: %s\n",
3967c478bd9Sstevel@tonic-gate 	    nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag,
3977c478bd9Sstevel@tonic-gate 	    nconf->nc_protofmly);
3987c478bd9Sstevel@tonic-gate 	printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n",
3997c478bd9Sstevel@tonic-gate 	    nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups,
4007c478bd9Sstevel@tonic-gate 	    nconf->nc_unused);
4017c478bd9Sstevel@tonic-gate 	printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen,
4027c478bd9Sstevel@tonic-gate 	    netaddr.buf, netaddr.len);
4037c478bd9Sstevel@tonic-gate #endif
4047c478bd9Sstevel@tonic-gate  	/*
4057c478bd9Sstevel@tonic-gate 	 * Tell clnt_tli_create that given fd is already connected
4067c478bd9Sstevel@tonic-gate 	 *
4077c478bd9Sstevel@tonic-gate 	 * If the service_name and client_name are iprop-centric,
4087c478bd9Sstevel@tonic-gate 	 * we need to clnt_tli_create to the appropriate RPC prog
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 	iprop_svc = strdup(KIPROP_SVC_NAME);
4117c478bd9Sstevel@tonic-gate 	if (iprop_svc == NULL)
4127c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	if ((strstr(service_name, iprop_svc) != NULL) &&
4157c478bd9Sstevel@tonic-gate 	    (strstr(client_name, iprop_svc) != NULL)) {
4167c478bd9Sstevel@tonic-gate 		iprop_enable = B_TRUE;
4177c478bd9Sstevel@tonic-gate 		handle->clnt = clnt_tli_create(fd, nconf, NULL,
4187c478bd9Sstevel@tonic-gate 				    KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0);
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 	else
4217c478bd9Sstevel@tonic-gate 		handle->clnt = clnt_tli_create(fd, nconf, NULL,
4227c478bd9Sstevel@tonic-gate 				    KADM, KADMVERS, 0, 0);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (iprop_svc)
4257c478bd9Sstevel@tonic-gate 		free(iprop_svc);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (handle->clnt == NULL) {
4287c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
4297c478bd9Sstevel@tonic-gate 					"clnt_tli_create failed\n"));
4307c478bd9Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
4317c478bd9Sstevel@tonic-gate 		(void) close(fd);
4327c478bd9Sstevel@tonic-gate 		goto error;
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 	/*
4357c478bd9Sstevel@tonic-gate 	 * The rpc-handle was created on an fd opened and connected
4367c478bd9Sstevel@tonic-gate 	 * by us, so we have to explicitly tell rpc to close it.
4377c478bd9Sstevel@tonic-gate 	 */
4387c478bd9Sstevel@tonic-gate 	if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) {
4397c478bd9Sstevel@tonic-gate 		clnt_pcreateerror("ERROR:");
4407c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
4417c478bd9Sstevel@tonic-gate 			"clnt_control failed to set CLSET_FD_CLOSE"));
4427c478bd9Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
4437c478bd9Sstevel@tonic-gate 		(void) close(fd);
4447c478bd9Sstevel@tonic-gate 		goto error;
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	handle->lhandle->clnt = handle->clnt;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/* now that handle->clnt is set, we can check the handle */
4507c478bd9Sstevel@tonic-gate 	if (code = _kadm5_check_handle((void *) handle))
4517c478bd9Sstevel@tonic-gate 		goto error;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/*
4547c478bd9Sstevel@tonic-gate 	 * The RPC connection is open; establish the GSS-API
4557c478bd9Sstevel@tonic-gate 	 * authentication context.
4567c478bd9Sstevel@tonic-gate 	 */
4577c478bd9Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
4587c478bd9Sstevel@tonic-gate 				    "have an rpc connection open\n"));
4597c478bd9Sstevel@tonic-gate 	/* use the kadm5 cache */
4607c478bd9Sstevel@tonic-gate 	ccname_orig = getenv("KRB5CCNAME");
4617c478bd9Sstevel@tonic-gate 	if (ccname_orig)
4627c478bd9Sstevel@tonic-gate 		ccname_orig = strdup(ccname_orig);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	(void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR,
4677c478bd9Sstevel@tonic-gate 		dgettext(TEXT_DOMAIN,
4687c478bd9Sstevel@tonic-gate 			"current credential cache: %s"), handle->cache_name);
4697c478bd9Sstevel@tonic-gate 	input_name.value = client_name;
4707c478bd9Sstevel@tonic-gate 	input_name.length = strlen((char *)input_name.value) + 1;
4717c478bd9Sstevel@tonic-gate 	gssstat = gss_import_name(&minor_stat, &input_name,
4727c478bd9Sstevel@tonic-gate 				(gss_OID)gss_nt_krb5_name, &gss_client);
4737c478bd9Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
4747c478bd9Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
4757c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR,
4767c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
4777c478bd9Sstevel@tonic-gate 				"gss_import_name failed for client name\n"));
4787c478bd9Sstevel@tonic-gate 		goto error;
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
4827c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
4837c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
4847c478bd9Sstevel@tonic-gate 				"Invalid mechanism oid <%s>"), mech);
4857c478bd9Sstevel@tonic-gate 		goto error;
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	oid_set.count = 1;
4897c478bd9Sstevel@tonic-gate 	oid_set.elements = mech_oid;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
4927c478bd9Sstevel@tonic-gate 				&oid_set, GSS_C_INITIATE,
4937c478bd9Sstevel@tonic-gate 				&gss_client_creds, NULL, NULL);
4947c478bd9Sstevel@tonic-gate 	(void) gss_release_name(&minor_stat, &gss_client);
4957c478bd9Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
4967c478bd9Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
4977c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
4987c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
4997c478bd9Sstevel@tonic-gate 				"could not acquire credentials, "
5007c478bd9Sstevel@tonic-gate 				"major error code: %d\n"), gssstat);
5017c478bd9Sstevel@tonic-gate 		goto error;
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 	handle->my_cred = gss_client_creds;
5047c478bd9Sstevel@tonic-gate 	options_req.my_cred = gss_client_creds;
5057c478bd9Sstevel@tonic-gate 	options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
5067c478bd9Sstevel@tonic-gate 	options_req.time_req = 0;
5077c478bd9Sstevel@tonic-gate 	options_req.input_channel_bindings = NULL;
5087c478bd9Sstevel@tonic-gate #ifndef INIT_TEST
5097c478bd9Sstevel@tonic-gate 	handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt,
5107c478bd9Sstevel@tonic-gate 						service_name,
5117c478bd9Sstevel@tonic-gate 						mech,
5127c478bd9Sstevel@tonic-gate 						service,
5137c478bd9Sstevel@tonic-gate 						NULL,
5147c478bd9Sstevel@tonic-gate 						&options_req,
5157c478bd9Sstevel@tonic-gate 						&options_ret);
5167c478bd9Sstevel@tonic-gate #endif /* ! INIT_TEST */
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (ccname_orig) {
5197c478bd9Sstevel@tonic-gate 		(void) krb5_setenv("KRB5CCNAME", ccname_orig, 1);
5207c478bd9Sstevel@tonic-gate 		free(ccname_orig);
5217c478bd9Sstevel@tonic-gate 	} else
5227c478bd9Sstevel@tonic-gate 		(void) krb5_unsetenv("KRB5CCNAME");
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (handle->clnt->cl_auth == NULL) {
5257c478bd9Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
5267c478bd9Sstevel@tonic-gate 		display_status(dgettext(TEXT_DOMAIN,
5277c478bd9Sstevel@tonic-gate 					"rpc_gss_seccreate failed\n"),
5287c478bd9Sstevel@tonic-gate 			    options_ret.major_status,
5297c478bd9Sstevel@tonic-gate 			    options_ret.minor_status,
5307c478bd9Sstevel@tonic-gate 			    mech);
5317c478bd9Sstevel@tonic-gate 		goto error;
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/*
5357c478bd9Sstevel@tonic-gate 	 * Bypass the remainder of the code and return straightaway
5367c478bd9Sstevel@tonic-gate 	 * if the gss service requested is kiprop
5377c478bd9Sstevel@tonic-gate 	 */
5387c478bd9Sstevel@tonic-gate 	if (iprop_enable == B_TRUE) {
5397c478bd9Sstevel@tonic-gate 		code = 0;
5407c478bd9Sstevel@tonic-gate 		goto cleanup;
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 
543*159d09a2SMark Phalan 	r = init_2(&handle->api_version, handle->clnt);
544*159d09a2SMark Phalan 	/* Solaris Kerberos: 163 resync */
5457c478bd9Sstevel@tonic-gate 	if (r == NULL) {
5467c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
5477c478bd9Sstevel@tonic-gate 			"error during admin api initialization\n"));
5487c478bd9Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
5497c478bd9Sstevel@tonic-gate 		goto error;
5507c478bd9Sstevel@tonic-gate 	}
551*159d09a2SMark Phalan 
5527c478bd9Sstevel@tonic-gate 	if (r->code) {
5537c478bd9Sstevel@tonic-gate 		code = r->code;
5547c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
5557c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
5567c478bd9Sstevel@tonic-gate 				"error during admin api initialization: %d\n"),
5577c478bd9Sstevel@tonic-gate 			r->code);
5587c478bd9Sstevel@tonic-gate 		goto error;
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate error:
5617c478bd9Sstevel@tonic-gate cleanup:
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	if (handlep != (void *) NULL)
5647c478bd9Sstevel@tonic-gate 		(void) endnetconfig(handlep);
5657c478bd9Sstevel@tonic-gate 	/*
5667c478bd9Sstevel@tonic-gate 	 * gss_client_creds is freed only when there is an error condition,
5677c478bd9Sstevel@tonic-gate 	 * given that rpc_gss_seccreate() will assign the cred pointer to the
5687c478bd9Sstevel@tonic-gate 	 * my_cred member in the auth handle's private data structure.
5697c478bd9Sstevel@tonic-gate 	 */
5707c478bd9Sstevel@tonic-gate 	if (code && (gss_client_creds != GSS_C_NO_CREDENTIAL))
5717c478bd9Sstevel@tonic-gate 		(void) gss_release_cred(&minor_stat, &gss_client_creds);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	return (code);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
5777c478bd9Sstevel@tonic-gate 				   enum init_type init_type,
5787c478bd9Sstevel@tonic-gate 				   char *pass,
5797c478bd9Sstevel@tonic-gate 				   krb5_ccache ccache_in,
5807c478bd9Sstevel@tonic-gate 				   char *service_name,
5817c478bd9Sstevel@tonic-gate 				   kadm5_config_params *params_in,
5827c478bd9Sstevel@tonic-gate 				   krb5_ui_4 struct_version,
5837c478bd9Sstevel@tonic-gate 				   krb5_ui_4 api_version,
58454925bf6Swillf 				   char **db_args,
5857c478bd9Sstevel@tonic-gate 				   void **server_handle)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate      int i;
5887c478bd9Sstevel@tonic-gate      krb5_creds	creds;
5897c478bd9Sstevel@tonic-gate      krb5_ccache ccache = NULL;
5907c478bd9Sstevel@tonic-gate      krb5_timestamp  now;
5917c478bd9Sstevel@tonic-gate      OM_uint32 gssstat, minor_stat;
5927c478bd9Sstevel@tonic-gate      kadm5_server_handle_t handle;
5937c478bd9Sstevel@tonic-gate      kadm5_config_params params_local;
5947c478bd9Sstevel@tonic-gate      int code = 0;
5957c478bd9Sstevel@tonic-gate      krb5_get_init_creds_opt opt;
5967c478bd9Sstevel@tonic-gate      gss_buffer_desc input_name;
5977c478bd9Sstevel@tonic-gate      krb5_error_code kret;
5987c478bd9Sstevel@tonic-gate      krb5_int32 starttime;
5997c478bd9Sstevel@tonic-gate      char *server = NULL;
6007c478bd9Sstevel@tonic-gate      krb5_principal serverp = NULL, clientp = NULL;
601fe598cdcSmp153739      krb5_principal saved_server = NULL;
60245526e97Ssemery      bool_t cpw = FALSE;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
6057c478bd9Sstevel@tonic-gate 		"entering kadm5_init_any\n"));
6067c478bd9Sstevel@tonic-gate      if (! server_handle) {
60756a424ccSmp153739 	 return EINVAL;
6087c478bd9Sstevel@tonic-gate      }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate      if (! (handle = malloc(sizeof(*handle)))) {
61156a424ccSmp153739 	  return ENOMEM;
6127c478bd9Sstevel@tonic-gate      }
6137c478bd9Sstevel@tonic-gate      if (! (handle->lhandle = malloc(sizeof(*handle)))) {
6147c478bd9Sstevel@tonic-gate 	  free(handle);
61556a424ccSmp153739 	  return ENOMEM;
6167c478bd9Sstevel@tonic-gate      }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate      handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
6197c478bd9Sstevel@tonic-gate      handle->struct_version = struct_version;
6207c478bd9Sstevel@tonic-gate      handle->api_version = api_version;
6217c478bd9Sstevel@tonic-gate      handle->clnt = 0;
6227c478bd9Sstevel@tonic-gate      handle->cache_name = 0;
6237c478bd9Sstevel@tonic-gate      handle->destroy_cache = 0;
6247c478bd9Sstevel@tonic-gate      *handle->lhandle = *handle;
6257c478bd9Sstevel@tonic-gate      handle->lhandle->api_version = KADM5_API_VERSION_2;
6267c478bd9Sstevel@tonic-gate      handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
6277c478bd9Sstevel@tonic-gate      handle->lhandle->lhandle = handle->lhandle;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate     kret = krb5_init_context(&handle->context);
6307c478bd9Sstevel@tonic-gate 	if (kret) {
6317c478bd9Sstevel@tonic-gate 		free(handle->lhandle);
6327c478bd9Sstevel@tonic-gate 		free(handle);
6337c478bd9Sstevel@tonic-gate 		return (kret);
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate      if(service_name == NULL || client_name == NULL) {
6377c478bd9Sstevel@tonic-gate 	krb5_free_context(handle->context);
6387c478bd9Sstevel@tonic-gate 	free(handle->lhandle);
6397c478bd9Sstevel@tonic-gate 	free(handle);
64056a424ccSmp153739 	return EINVAL;
6417c478bd9Sstevel@tonic-gate      }
6427c478bd9Sstevel@tonic-gate      memset((char *) &creds, 0, sizeof(creds));
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate      /*
6457c478bd9Sstevel@tonic-gate       * Verify the version numbers before proceeding; we can't use
6467c478bd9Sstevel@tonic-gate       * CHECK_HANDLE because not all fields are set yet.
6477c478bd9Sstevel@tonic-gate       */
6487c478bd9Sstevel@tonic-gate      GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
6497c478bd9Sstevel@tonic-gate 			  KADM5_NEW_LIB_API_VERSION);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate      /*
6527c478bd9Sstevel@tonic-gate       * Acquire relevant profile entries.  In version 2, merge values
6537c478bd9Sstevel@tonic-gate       * in params_in with values from profile, based on
6547c478bd9Sstevel@tonic-gate       * params_in->mask.
6557c478bd9Sstevel@tonic-gate       *
6567c478bd9Sstevel@tonic-gate       * In version 1, we've given a realm (which may be NULL) instead
6577c478bd9Sstevel@tonic-gate       * of params_in.  So use that realm, make params_in contain an
6587c478bd9Sstevel@tonic-gate       * empty mask, and behave like version 2.
6597c478bd9Sstevel@tonic-gate       */
6607c478bd9Sstevel@tonic-gate      memset((char *) &params_local, 0, sizeof(params_local));
6617c478bd9Sstevel@tonic-gate      if (api_version == KADM5_API_VERSION_1) {
6627c478bd9Sstevel@tonic-gate 	  if (params_in)
6637c478bd9Sstevel@tonic-gate 	       params_local.mask = KADM5_CONFIG_REALM;
6647c478bd9Sstevel@tonic-gate 	  params_in = &params_local;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate #define ILLEGAL_PARAMS ( \
6687c478bd9Sstevel@tonic-gate 		KADM5_CONFIG_ACL_FILE	| KADM5_CONFIG_ADB_LOCKFILE | \
6697c478bd9Sstevel@tonic-gate 		KADM5_CONFIG_DBNAME	| KADM5_CONFIG_ADBNAME | \
6707c478bd9Sstevel@tonic-gate 		KADM5_CONFIG_DICT_FILE	| KADM5_CONFIG_ADMIN_KEYTAB | \
6717c478bd9Sstevel@tonic-gate 			KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \
6727c478bd9Sstevel@tonic-gate 			KADM5_CONFIG_ENCTYPE	| KADM5_CONFIG_MAX_LIFE	| \
6737c478bd9Sstevel@tonic-gate 			KADM5_CONFIG_MAX_RLIFE	| KADM5_CONFIG_EXPIRATION | \
6747c478bd9Sstevel@tonic-gate 			KADM5_CONFIG_FLAGS	| KADM5_CONFIG_ENCTYPES	| \
6757c478bd9Sstevel@tonic-gate 			KADM5_CONFIG_MKEY_FROM_KBD)
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate      if (params_in && params_in->mask & ILLEGAL_PARAMS) {
6787c478bd9Sstevel@tonic-gate 		krb5_free_context(handle->context);
6797c478bd9Sstevel@tonic-gate 		free(handle->lhandle);
6807c478bd9Sstevel@tonic-gate 	  free(handle);
6817c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
6827c478bd9Sstevel@tonic-gate 			"bad client parameters, returning %d"),
6837c478bd9Sstevel@tonic-gate 			KADM5_BAD_CLIENT_PARAMS);
68456a424ccSmp153739 	  return KADM5_BAD_CLIENT_PARAMS;
6857c478bd9Sstevel@tonic-gate      }
6867c478bd9Sstevel@tonic-gate 
687*159d09a2SMark Phalan      if ((code = kadm5_get_config_params(handle->context, 0,
688*159d09a2SMark Phalan 					 params_in, &handle->params))) {
6897c478bd9Sstevel@tonic-gate 	  krb5_free_context(handle->context);
6907c478bd9Sstevel@tonic-gate 	  free(handle->lhandle);
6917c478bd9Sstevel@tonic-gate 	  free(handle);
6927c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
6937c478bd9Sstevel@tonic-gate 			"failed to get config_params, return: %d\n"), code);
6947c478bd9Sstevel@tonic-gate 	  return(code);
6957c478bd9Sstevel@tonic-gate      }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
6987c478bd9Sstevel@tonic-gate 			 KADM5_CONFIG_ADMIN_SERVER | \
6997c478bd9Sstevel@tonic-gate 			 KADM5_CONFIG_KADMIND_PORT)
700bd211b85Ssemery #define KPW_REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
701bd211b85Ssemery 			 KADM5_CONFIG_KPASSWD_SERVER | \
702bd211b85Ssemery 			 KADM5_CONFIG_KPASSWD_PORT)
7037c478bd9Sstevel@tonic-gate 
704bd211b85Ssemery      if (((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) &&
705bd211b85Ssemery 	 ((handle->params.mask & KPW_REQUIRED_PARAMS) != KPW_REQUIRED_PARAMS)) {
7067c478bd9Sstevel@tonic-gate 		(void) kadm5_free_config_params(handle->context,
7077c478bd9Sstevel@tonic-gate 						&handle->params);
7087c478bd9Sstevel@tonic-gate 	  krb5_free_context(handle->context);
7097c478bd9Sstevel@tonic-gate 		free(handle->lhandle);
7107c478bd9Sstevel@tonic-gate 	  free(handle);
7117c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7127c478bd9Sstevel@tonic-gate 			"missing config parameters\n"));
71356a424ccSmp153739 	  return KADM5_MISSING_KRB5_CONF_PARAMS;
7147c478bd9Sstevel@tonic-gate      }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	/*
7177c478bd9Sstevel@tonic-gate 	 * Acquire a service ticket for service_name@realm in the name of
7187c478bd9Sstevel@tonic-gate 	 * client_name, using password pass (which could be NULL), and
7197c478bd9Sstevel@tonic-gate 	 * create a ccache to store them in.  If INIT_CREDS, use the
7207c478bd9Sstevel@tonic-gate 	 * ccache we were provided instead.
7217c478bd9Sstevel@tonic-gate 	 */
7227c478bd9Sstevel@tonic-gate 	if ((code = krb5_parse_name(handle->context, client_name,
7237c478bd9Sstevel@tonic-gate 			    &creds.client))) {
7247c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7257c478bd9Sstevel@tonic-gate 			    "could not parse client name\n"));
7267c478bd9Sstevel@tonic-gate 		goto error;
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 	clientp = creds.client;
7297c478bd9Sstevel@tonic-gate 
73045526e97Ssemery 	if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE,
73145526e97Ssemery 	    strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0)
73245526e97Ssemery 		cpw = TRUE;
73345526e97Ssemery 
7347c478bd9Sstevel@tonic-gate 	if (init_type == INIT_PASS &&
73545526e97Ssemery 	    handle->params.kpasswd_protocol == KRB5_CHGPWD_CHANGEPW_V2 &&
73645526e97Ssemery 	    cpw == TRUE) {
7377c478bd9Sstevel@tonic-gate 		/*
7387c478bd9Sstevel@tonic-gate 		 * The 'service_name' is constructed by the caller
7397c478bd9Sstevel@tonic-gate 		 * but its done before the parameter which determines
7407c478bd9Sstevel@tonic-gate 		 * the kpasswd_protocol is found.  The servers that
7417c478bd9Sstevel@tonic-gate 		 * support the SET/CHANGE password protocol expect
7427c478bd9Sstevel@tonic-gate 		 * a slightly different service principal than
7437c478bd9Sstevel@tonic-gate 		 * the normal SEAM kadmind so construct the correct
7447c478bd9Sstevel@tonic-gate 		 * name here and then forget it.
7457c478bd9Sstevel@tonic-gate 		 */
7467c478bd9Sstevel@tonic-gate 		char *newsvcname = NULL;
7477c478bd9Sstevel@tonic-gate 		newsvcname = malloc(strlen(KADM5_CHANGEPW_SERVICE) +
7487c478bd9Sstevel@tonic-gate 				    strlen(handle->params.realm) + 2);
7497c478bd9Sstevel@tonic-gate 		if (newsvcname == NULL) {
750d9976468Sps57422 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
751d9976468Sps57422 					    "could not malloc\n"));
752d9976468Sps57422 			code = ENOMEM;
753d9976468Sps57422 			goto error;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 		sprintf(newsvcname, "%s@%s", KADM5_CHANGEPW_SERVICE,
7567c478bd9Sstevel@tonic-gate 			handle->params.realm);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		if ((code = krb5_parse_name(handle->context, newsvcname,
7597c478bd9Sstevel@tonic-gate 					    &creds.server))) {
7607c478bd9Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7617c478bd9Sstevel@tonic-gate 					    "could not parse server "
7627c478bd9Sstevel@tonic-gate 					    "name\n"));
7637c478bd9Sstevel@tonic-gate 			free(newsvcname);
7647c478bd9Sstevel@tonic-gate 			goto error;
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 		free(newsvcname);
7677c478bd9Sstevel@tonic-gate 	} else {
7687c478bd9Sstevel@tonic-gate 		input_name.value = service_name;
7697c478bd9Sstevel@tonic-gate 		input_name.length = strlen((char *)input_name.value) + 1;
770ab9b2e15Sgtb 		gssstat = krb5_gss_import_name(&minor_stat,
7717c478bd9Sstevel@tonic-gate 				    &input_name,
7727c478bd9Sstevel@tonic-gate 				    (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
7737c478bd9Sstevel@tonic-gate 				    (gss_name_t *)&creds.server);
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		if (gssstat != GSS_S_COMPLETE) {
7767c478bd9Sstevel@tonic-gate 			code = KADM5_GSS_ERROR;
7777c478bd9Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7787c478bd9Sstevel@tonic-gate 				"gss_import_name failed for client name\n"));
7797c478bd9Sstevel@tonic-gate 			goto error;
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 	}
7827c478bd9Sstevel@tonic-gate 	serverp = creds.server;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	/* XXX temporarily fix a bug in krb5_cc_get_type */
7857c478bd9Sstevel@tonic-gate #undef krb5_cc_get_type
7867c478bd9Sstevel@tonic-gate #define krb5_cc_get_type(context, cache) ((cache)->ops->prefix)
7877c478bd9Sstevel@tonic-gate 
78856a424ccSmp153739 
7897c478bd9Sstevel@tonic-gate      if (init_type == INIT_CREDS) {
7907c478bd9Sstevel@tonic-gate 	  ccache = ccache_in;
7917c478bd9Sstevel@tonic-gate 	  handle->cache_name = (char *)
7927c478bd9Sstevel@tonic-gate 	       malloc(strlen(krb5_cc_get_type(handle->context, ccache)) +
7937c478bd9Sstevel@tonic-gate 		      strlen(krb5_cc_get_name(handle->context, ccache)) + 2);
7947c478bd9Sstevel@tonic-gate 	  if (handle->cache_name == NULL) {
7957c478bd9Sstevel@tonic-gate 	       code = ENOMEM;
7967c478bd9Sstevel@tonic-gate 	       goto error;
7977c478bd9Sstevel@tonic-gate 	  }
7987c478bd9Sstevel@tonic-gate 	  sprintf(handle->cache_name, "%s:%s",
7997c478bd9Sstevel@tonic-gate 		  krb5_cc_get_type(handle->context, ccache),
8007c478bd9Sstevel@tonic-gate 		  krb5_cc_get_name(handle->context, ccache));
8017c478bd9Sstevel@tonic-gate      } else {
80256a424ccSmp153739 #if 0
8037c478bd9Sstevel@tonic-gate 	  handle->cache_name =
8047c478bd9Sstevel@tonic-gate 	       (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1);
8057c478bd9Sstevel@tonic-gate 	  if (handle->cache_name == NULL) {
8067c478bd9Sstevel@tonic-gate 	       code = ENOMEM;
8077c478bd9Sstevel@tonic-gate 	       goto error;
8087c478bd9Sstevel@tonic-gate 	  }
8097c478bd9Sstevel@tonic-gate 	  sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE);
8107c478bd9Sstevel@tonic-gate 	  mktemp(handle->cache_name + strlen("FILE:"));
81156a424ccSmp153739 #endif
81256a424ccSmp153739 	  {
81356a424ccSmp153739 	      static int counter = 0;
81456a424ccSmp153739 	      handle->cache_name = malloc(sizeof("MEMORY:kadm5_")
81556a424ccSmp153739 					  + 3*sizeof(counter));
81656a424ccSmp153739 	      sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++);
81756a424ccSmp153739 	  }
8187c478bd9Sstevel@tonic-gate 
81956a424ccSmp153739 	  if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
82056a424ccSmp153739 				      &ccache)))
8217c478bd9Sstevel@tonic-gate 	       goto error;
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	  if ((code = krb5_cc_initialize (handle->context, ccache,
8247c478bd9Sstevel@tonic-gate 					  creds.client)))
8257c478bd9Sstevel@tonic-gate 	       goto error;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	  handle->destroy_cache = 1;
8287c478bd9Sstevel@tonic-gate      }
8297c478bd9Sstevel@tonic-gate      handle->lhandle->cache_name = handle->cache_name;
8307c478bd9Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
8317c478bd9Sstevel@tonic-gate 		"cache created: %s\n"), handle->cache_name);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate      if ((code = krb5_timeofday(handle->context, &now)))
8347c478bd9Sstevel@tonic-gate 	  goto error;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate      /*
8377c478bd9Sstevel@tonic-gate       * Get a ticket, use the method specified in init_type.
8387c478bd9Sstevel@tonic-gate       */
83956a424ccSmp153739 
8407c478bd9Sstevel@tonic-gate      creds.times.starttime = 0; /* start timer at KDC */
8417c478bd9Sstevel@tonic-gate      creds.times.endtime = 0; /* endtime will be limited by service */
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	memset(&opt, 0, sizeof (opt));
8447c478bd9Sstevel@tonic-gate 	krb5_get_init_creds_opt_init(&opt);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	if (creds.times.endtime) {
8477c478bd9Sstevel@tonic-gate 		if (creds.times.starttime)
8487c478bd9Sstevel@tonic-gate 			starttime = creds.times.starttime;
8497c478bd9Sstevel@tonic-gate 		else
8507c478bd9Sstevel@tonic-gate 			starttime = now;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_tkt_life(&opt,
8537c478bd9Sstevel@tonic-gate 			creds.times.endtime - starttime);
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 	code = krb5_unparse_name(handle->context, creds.server, &server);
8567c478bd9Sstevel@tonic-gate 	if (code)
8577c478bd9Sstevel@tonic-gate 		goto error;
8587c478bd9Sstevel@tonic-gate 
859fe598cdcSmp153739 	/*
860fe598cdcSmp153739 	 * Solaris Kerberos:
861fe598cdcSmp153739 	 * Save the original creds.server as krb5_get_init_creds*() always
862fe598cdcSmp153739 	 * sets the realm of the server to the client realm.
863fe598cdcSmp153739 	 */
864fe598cdcSmp153739 	code = krb5_copy_principal(handle->context, creds.server, &saved_server);
865fe598cdcSmp153739 	if (code)
866fe598cdcSmp153739 		goto error;
867fe598cdcSmp153739 
8687c478bd9Sstevel@tonic-gate 	if (init_type == INIT_PASS) {
8697c478bd9Sstevel@tonic-gate 		code = krb5_get_init_creds_password(handle->context,
8707c478bd9Sstevel@tonic-gate 			&creds, creds.client, pass, NULL,
8717c478bd9Sstevel@tonic-gate 			NULL, creds.times.starttime,
8727c478bd9Sstevel@tonic-gate 			server, &opt);
8737c478bd9Sstevel@tonic-gate 	} else if (init_type == INIT_SKEY) {
8747c478bd9Sstevel@tonic-gate 		krb5_keytab kt = NULL;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 		if (!(pass && (code = krb5_kt_resolve(handle->context,
8777c478bd9Sstevel@tonic-gate 					pass, &kt)))) {
8787c478bd9Sstevel@tonic-gate 			code = krb5_get_init_creds_keytab(
8797c478bd9Sstevel@tonic-gate 					handle->context,
8807c478bd9Sstevel@tonic-gate 					&creds, creds.client, kt,
8817c478bd9Sstevel@tonic-gate 					creds.times.starttime,
8827c478bd9Sstevel@tonic-gate 					server, &opt);
8837c478bd9Sstevel@tonic-gate 
88456a424ccSmp153739 	       if (pass) krb5_kt_close(handle->context, kt);
8857c478bd9Sstevel@tonic-gate 	  }
8867c478bd9Sstevel@tonic-gate      }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate      /* Improved error messages */
88956a424ccSmp153739      if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
8907c478bd9Sstevel@tonic-gate      if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
8917c478bd9Sstevel@tonic-gate 	  code = KADM5_SECURE_PRINC_MISSING;
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate      if (code != 0) {
8947c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
8957c478bd9Sstevel@tonic-gate 			"failed to obtain credentials cache\n"));
896fe598cdcSmp153739 		krb5_free_principal(handle->context, saved_server);
8977c478bd9Sstevel@tonic-gate 		goto error;
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	/*
901fe598cdcSmp153739 	 * Solaris Kerberos:
902fe598cdcSmp153739 	 * If the server principal had an empty realm then store that in
903fe598cdcSmp153739 	 * the cred cache and not the server realm as returned by
904d67a66d0Smp153739 	 * krb5_get_init_creds_{keytab|password}(). This ensures that rpcsec_gss
905d67a66d0Smp153739 	 * will find the credential in the cred cache even if a "fallback"
906d67a66d0Smp153739 	 * method is being used to determine the realm.
907fe598cdcSmp153739 	 */
908d67a66d0Smp153739 	if (init_type != INIT_CREDS) {
909fe598cdcSmp153739 		krb5_free_principal(handle->context, creds.server);
910d67a66d0Smp153739 	}
911fe598cdcSmp153739 	creds.server = saved_server;
912fe598cdcSmp153739 
913fe598cdcSmp153739 	/*
9147c478bd9Sstevel@tonic-gate 	 * If we got this far, save the creds in the cache.
9157c478bd9Sstevel@tonic-gate 	 */
9167c478bd9Sstevel@tonic-gate 	if (ccache) {
9177c478bd9Sstevel@tonic-gate 		code = krb5_cc_store_cred(handle->context, ccache, &creds);
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "obtained credentials cache\n"));
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate #ifdef ZEROPASSWD
9237c478bd9Sstevel@tonic-gate      if (pass != NULL)
9247c478bd9Sstevel@tonic-gate 	  memset(pass, 0, strlen(pass));
9257c478bd9Sstevel@tonic-gate #endif
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	if (init_type != INIT_PASS ||
92845526e97Ssemery 	    handle->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC ||
92945526e97Ssemery 	    cpw == FALSE) {
9307c478bd9Sstevel@tonic-gate 		code = _kadm5_initialize_rpcsec_gss_handle(handle,
9317c478bd9Sstevel@tonic-gate 					client_name, service_name);
932d67a66d0Smp153739 
933d67a66d0Smp153739 		/*
934d67a66d0Smp153739 		 * Solaris Kerberos:
935d67a66d0Smp153739 		 * If _kadm5_initialize_rpcsec_gss_handle() fails it will have
936d67a66d0Smp153739 		 * called krb5_gss_release_cred(). If the credential cache is a
937d67a66d0Smp153739 		 * MEMORY cred cache krb5_gss_release_cred() destroys the
938d67a66d0Smp153739 		 * cred cache data. Make sure that the cred-cache is closed
939d67a66d0Smp153739 		 * to prevent a double free in the "error" code.
940d67a66d0Smp153739 		 */
941d67a66d0Smp153739 		if (code != 0) {
942*159d09a2SMark Phalan 			if (init_type != INIT_CREDS) {
943d67a66d0Smp153739 				krb5_cc_close(handle->context, ccache);
944*159d09a2SMark Phalan 				ccache = NULL;
945*159d09a2SMark Phalan 			}
9467c478bd9Sstevel@tonic-gate 			goto error;
9477c478bd9Sstevel@tonic-gate 		}
948d67a66d0Smp153739 	}
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	*server_handle = (void *) handle;
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (init_type != INIT_CREDS)
9537c478bd9Sstevel@tonic-gate 		krb5_cc_close(handle->context, ccache);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	goto cleanup;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate error:
9587c478bd9Sstevel@tonic-gate      /*
9597c478bd9Sstevel@tonic-gate       * Note that it is illegal for this code to execute if "handle"
9607c478bd9Sstevel@tonic-gate       * has not been allocated and initialized.  I.e., don't use "goto
9617c478bd9Sstevel@tonic-gate       * error" before the block of code at the top of the function
9627c478bd9Sstevel@tonic-gate       * that allocates and initializes "handle".
9637c478bd9Sstevel@tonic-gate       */
9647c478bd9Sstevel@tonic-gate      if (handle->cache_name)
9657c478bd9Sstevel@tonic-gate 	 free(handle->cache_name);
9667c478bd9Sstevel@tonic-gate      if (handle->destroy_cache && ccache)
9677c478bd9Sstevel@tonic-gate 	 krb5_cc_destroy(handle->context, ccache);
9687c478bd9Sstevel@tonic-gate      if(handle->clnt && handle->clnt->cl_auth)
9697c478bd9Sstevel@tonic-gate 	  AUTH_DESTROY(handle->clnt->cl_auth);
9707c478bd9Sstevel@tonic-gate      if(handle->clnt)
9717c478bd9Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
9727c478bd9Sstevel@tonic-gate 	(void) kadm5_free_config_params(handle->context, &handle->params);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate cleanup:
9757c478bd9Sstevel@tonic-gate 	if (server)
9767c478bd9Sstevel@tonic-gate 		free(server);
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	/*
979e49962a0Ssemery 	 * cred's server and client pointers could have been overwritten
980e49962a0Ssemery 	 * by the krb5_get_init_* functions.  If the addresses are different
981e49962a0Ssemery 	 * before and after the calls then we must free the memory that
982e49962a0Ssemery 	 * was allocated before the call.
9837c478bd9Sstevel@tonic-gate 	 */
984e49962a0Ssemery 	if (clientp && clientp != creds.client)
9857c478bd9Sstevel@tonic-gate 		krb5_free_principal(handle->context, clientp);
986e49962a0Ssemery 
987e49962a0Ssemery 	if (serverp && serverp != creds.server)
9887c478bd9Sstevel@tonic-gate 		krb5_free_principal(handle->context, serverp);
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate      krb5_free_cred_contents(handle->context, &creds);
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	/*
9937c478bd9Sstevel@tonic-gate 	 * Dont clean up the handle if the code is OK (code==0)
9947c478bd9Sstevel@tonic-gate 	 * because it is returned to the caller in the 'server_handle'
9957c478bd9Sstevel@tonic-gate 	 * ptr.
9967c478bd9Sstevel@tonic-gate 	 */
9977c478bd9Sstevel@tonic-gate      if (code) {
9987c478bd9Sstevel@tonic-gate 		krb5_free_context(handle->context);
9997c478bd9Sstevel@tonic-gate 		free(handle->lhandle);
10007c478bd9Sstevel@tonic-gate 	  free(handle);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 
100356a424ccSmp153739      return code;
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate kadm5_ret_t
10077c478bd9Sstevel@tonic-gate kadm5_destroy(void *server_handle)
10087c478bd9Sstevel@tonic-gate {
10097c478bd9Sstevel@tonic-gate      krb5_ccache	    ccache = NULL;
10107c478bd9Sstevel@tonic-gate      int		    code = KADM5_OK;
10117c478bd9Sstevel@tonic-gate      kadm5_server_handle_t	handle =
10127c478bd9Sstevel@tonic-gate 	  (kadm5_server_handle_t) server_handle;
10137c478bd9Sstevel@tonic-gate 	OM_uint32 min_stat;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate      CHECK_HANDLE(server_handle);
101656a424ccSmp153739 /* SUNW14resync:
101756a424ccSmp153739  * krb5_cc_resolve() will resolve a ccache with the same data that
101856a424ccSmp153739  * handle->my_cred points to. If the ccache is a MEMORY ccache then
101956a424ccSmp153739  * gss_release_cred() will free that data (it doesn't do this when ccache
102056a424ccSmp153739  * is a FILE ccache).
102156a424ccSmp153739  * if'ed out to avoid the double free.
102256a424ccSmp153739  */
102356a424ccSmp153739 #if 0
10247c478bd9Sstevel@tonic-gate      if (handle->destroy_cache && handle->cache_name) {
10257c478bd9Sstevel@tonic-gate 	 if ((code = krb5_cc_resolve(handle->context,
10267c478bd9Sstevel@tonic-gate 				     handle->cache_name, &ccache)) == 0)
10277c478bd9Sstevel@tonic-gate 	     code = krb5_cc_destroy (handle->context, ccache);
10287c478bd9Sstevel@tonic-gate      }
102956a424ccSmp153739 #endif
10307c478bd9Sstevel@tonic-gate      if (handle->cache_name)
10317c478bd9Sstevel@tonic-gate 	 free(handle->cache_name);
10327c478bd9Sstevel@tonic-gate      if (handle->clnt && handle->clnt->cl_auth) {
10337c478bd9Sstevel@tonic-gate 		/*
10347c478bd9Sstevel@tonic-gate 		 * Since kadm5 doesn't use the default credentials we
10357c478bd9Sstevel@tonic-gate 		 * must clean this up manually.
10367c478bd9Sstevel@tonic-gate 		 */
10377c478bd9Sstevel@tonic-gate 		if (handle->my_cred != GSS_C_NO_CREDENTIAL)
10387c478bd9Sstevel@tonic-gate 			(void) gss_release_cred(&min_stat, &handle->my_cred);
10397c478bd9Sstevel@tonic-gate 	  AUTH_DESTROY(handle->clnt->cl_auth);
10407c478bd9Sstevel@tonic-gate 	}
10417c478bd9Sstevel@tonic-gate      if (handle->clnt)
10427c478bd9Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
10437c478bd9Sstevel@tonic-gate      if (handle->lhandle)
10447c478bd9Sstevel@tonic-gate           free (handle->lhandle);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate      kadm5_free_config_params(handle->context, &handle->params);
10477c478bd9Sstevel@tonic-gate      krb5_free_context(handle->context);
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate      handle->magic_number = 0;
10507c478bd9Sstevel@tonic-gate      free(handle);
10517c478bd9Sstevel@tonic-gate 
105256a424ccSmp153739      return code;
10537c478bd9Sstevel@tonic-gate }
105456a424ccSmp153739 /* not supported on client */
105556a424ccSmp153739 kadm5_ret_t kadm5_lock(void *server_handle)
10567c478bd9Sstevel@tonic-gate {
105756a424ccSmp153739     return EINVAL;
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
106056a424ccSmp153739 /* not supported on client */
106156a424ccSmp153739 kadm5_ret_t kadm5_unlock(void *server_handle)
106256a424ccSmp153739 {
106356a424ccSmp153739     return EINVAL;
106456a424ccSmp153739 }
106556a424ccSmp153739 
106656a424ccSmp153739 kadm5_ret_t kadm5_flush(void *server_handle)
106756a424ccSmp153739 {
106856a424ccSmp153739      return KADM5_OK;
106956a424ccSmp153739 }
107056a424ccSmp153739 
107156a424ccSmp153739 int _kadm5_check_handle(void *handle)
10727c478bd9Sstevel@tonic-gate {
10737c478bd9Sstevel@tonic-gate      CHECK_HANDLE(handle);
107456a424ccSmp153739      return 0;
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate 
107754925bf6Swillf krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
107854925bf6Swillf {
107954925bf6Swillf     return krb5_init_context(ctx);
108054925bf6Swillf }
108154925bf6Swillf 
10827c478bd9Sstevel@tonic-gate /*
10837c478bd9Sstevel@tonic-gate  * Stub function for kadmin.  It was created to eliminate the dependency on
10847c478bd9Sstevel@tonic-gate  * libkdb's ulog functions.  The srv equivalent makes the actual calls.
10857c478bd9Sstevel@tonic-gate  */
10867c478bd9Sstevel@tonic-gate krb5_error_code
10877c478bd9Sstevel@tonic-gate kadm5_init_iprop(void *handle)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate 	return (0);
10907c478bd9Sstevel@tonic-gate }
1091