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 
6159d09a2SMark Phalan 
7159d09a2SMark Phalan 
8159d09a2SMark Phalan /*
9159d09a2SMark Phalan  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
10159d09a2SMark Phalan  */
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate /*
137c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
14*55fea89dSDan Cross  *
157c478bd9Sstevel@tonic-gate  * All rights reserved.
16*55fea89dSDan Cross  *
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.
21*55fea89dSDan Cross  *
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.
32*55fea89dSDan Cross  *
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"
4156a424ccSmp #ifdef HAVE_MEMORY_H
427c478bd9Sstevel@tonic-gate #include <memory.h>
4356a424ccSmp #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 
5656a424ccSmp #include <kadm5/admin.h>
5756a424ccSmp #include <kadm5/kadm_rpc.h>
5856a424ccSmp #include "client_internal.h"
5956a424ccSmp 
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>
6556a424ccSmp 
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 
7156a424ccSmp 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 
kadm5_init_with_creds(char * client_name,krb5_ccache ccache,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)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 {
9956a424ccSmp      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 
kadm5_init_with_password(char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)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 {
11456a424ccSmp      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 
kadm5_init(char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)1197c478bd9Sstevel@tonic-gate kadm5_ret_t kadm5_init(char *client_name, char *pass,
120*55fea89dSDan Cross 		       char *service_name,
12156a424ccSmp 		       kadm5_config_params *params,
12256a424ccSmp 		       krb5_ui_4 struct_version,
12356a424ccSmp 		       krb5_ui_4 api_version,
12454925bf6Swillf 		       char **db_args,
12556a424ccSmp 		       void **server_handle)
1267c478bd9Sstevel@tonic-gate {
12756a424ccSmp      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 
kadm5_init_with_skey(char * client_name,char * keytab,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)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 {
14056a424ccSmp      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
display_status_1(m,code,type,mech)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
display_status(msg,maj_stat,min_stat,mech)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
get_connection(struct netconfig * nconf,struct netbuf netaddr)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
_kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle,char * client_name,char * service_name)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 	 */
335*55fea89dSDan Cross 	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;
381*55fea89dSDan Cross 
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 
543159d09a2SMark Phalan 	r = init_2(&handle->api_version, handle->clnt);
544159d09a2SMark 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"));
548159d09a2SMark Phalan 		code = KADM5_RPC_ERROR;
5497c478bd9Sstevel@tonic-gate 		goto error;
5507c478bd9Sstevel@tonic-gate 	}
551159d09a2SMark 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 
_kadm5_init_any(char * client_name,enum init_type init_type,char * pass,krb5_ccache ccache_in,char * service_name,kadm5_config_params * params_in,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)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 {
58756a424ccSmp      int i;
58856a424ccSmp      krb5_creds	creds;
58956a424ccSmp      krb5_ccache ccache = NULL;
59056a424ccSmp      krb5_timestamp  now;
59156a424ccSmp      OM_uint32 gssstat, minor_stat;
59256a424ccSmp      kadm5_server_handle_t handle;
59356a424ccSmp      kadm5_config_params params_local;
59456a424ccSmp      int code = 0;
59556a424ccSmp      krb5_get_init_creds_opt opt;
59656a424ccSmp      gss_buffer_desc input_name;
59756a424ccSmp      krb5_error_code kret;
59856a424ccSmp      krb5_int32 starttime;
59956a424ccSmp      char *server = NULL;
60056a424ccSmp      krb5_principal serverp = NULL, clientp = NULL;
601fe598cdcSmp      krb5_principal saved_server = NULL;
60256a424ccSmp      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"));
60656a424ccSmp      if (! server_handle) {
60756a424ccSmp 	 return EINVAL;
60856a424ccSmp      }
60956a424ccSmp 
61056a424ccSmp      if (! (handle = malloc(sizeof(*handle)))) {
61156a424ccSmp 	  return ENOMEM;
61256a424ccSmp      }
61356a424ccSmp      if (! (handle->lhandle = malloc(sizeof(*handle)))) {
61456a424ccSmp 	  free(handle);
61556a424ccSmp 	  return ENOMEM;
61656a424ccSmp      }
61756a424ccSmp 
61856a424ccSmp      handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
61956a424ccSmp      handle->struct_version = struct_version;
62056a424ccSmp      handle->api_version = api_version;
62156a424ccSmp      handle->clnt = 0;
62256a424ccSmp      handle->cache_name = 0;
62356a424ccSmp      handle->destroy_cache = 0;
62456a424ccSmp      *handle->lhandle = *handle;
62556a424ccSmp      handle->lhandle->api_version = KADM5_API_VERSION_2;
62656a424ccSmp      handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
62756a424ccSmp      handle->lhandle->lhandle = handle->lhandle;
62856a424ccSmp 
62956a424ccSmp     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 
63656a424ccSmp      if(service_name == NULL || client_name == NULL) {
63756a424ccSmp 	krb5_free_context(handle->context);
63856a424ccSmp 	free(handle->lhandle);
63956a424ccSmp 	free(handle);
64056a424ccSmp 	return EINVAL;
64156a424ccSmp      }
64256a424ccSmp      memset((char *) &creds, 0, sizeof(creds));
64356a424ccSmp 
64456a424ccSmp      /*
64556a424ccSmp       * Verify the version numbers before proceeding; we can't use
64656a424ccSmp       * CHECK_HANDLE because not all fields are set yet.
64756a424ccSmp       */
64856a424ccSmp      GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
6497c478bd9Sstevel@tonic-gate 			  KADM5_NEW_LIB_API_VERSION);
650*55fea89dSDan Cross 
65156a424ccSmp      /*
65256a424ccSmp       * Acquire relevant profile entries.  In version 2, merge values
65356a424ccSmp       * in params_in with values from profile, based on
65456a424ccSmp       * params_in->mask.
65556a424ccSmp       *
65656a424ccSmp       * In version 1, we've given a realm (which may be NULL) instead
65756a424ccSmp       * of params_in.  So use that realm, make params_in contain an
65856a424ccSmp       * empty mask, and behave like version 2.
65956a424ccSmp       */
66056a424ccSmp      memset((char *) &params_local, 0, sizeof(params_local));
66156a424ccSmp      if (api_version == KADM5_API_VERSION_1) {
66256a424ccSmp 	  if (params_in)
66356a424ccSmp 	       params_local.mask = KADM5_CONFIG_REALM;
66456a424ccSmp 	  params_in = &params_local;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate #define ILLEGAL_PARAMS ( \
66856a424ccSmp 		KADM5_CONFIG_ACL_FILE	| KADM5_CONFIG_ADB_LOCKFILE | \
66956a424ccSmp 		KADM5_CONFIG_DBNAME	| KADM5_CONFIG_ADBNAME | \
67056a424ccSmp 		KADM5_CONFIG_DICT_FILE	| KADM5_CONFIG_ADMIN_KEYTAB | \
67156a424ccSmp 			KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \
67256a424ccSmp 			KADM5_CONFIG_ENCTYPE	| KADM5_CONFIG_MAX_LIFE	| \
67356a424ccSmp 			KADM5_CONFIG_MAX_RLIFE	| KADM5_CONFIG_EXPIRATION | \
67456a424ccSmp 			KADM5_CONFIG_FLAGS	| KADM5_CONFIG_ENCTYPES	| \
67556a424ccSmp 			KADM5_CONFIG_MKEY_FROM_KBD)
67656a424ccSmp 
67756a424ccSmp      if (params_in && params_in->mask & ILLEGAL_PARAMS) {
6787c478bd9Sstevel@tonic-gate 		krb5_free_context(handle->context);
6797c478bd9Sstevel@tonic-gate 		free(handle->lhandle);
68056a424ccSmp 	  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);
68456a424ccSmp 	  return KADM5_BAD_CLIENT_PARAMS;
68556a424ccSmp      }
686*55fea89dSDan Cross 
687159d09a2SMark Phalan      if ((code = kadm5_get_config_params(handle->context, 0,
688159d09a2SMark Phalan 					 params_in, &handle->params))) {
68956a424ccSmp 	  krb5_free_context(handle->context);
69056a424ccSmp 	  free(handle->lhandle);
69156a424ccSmp 	  free(handle);
6927c478bd9Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
6937c478bd9Sstevel@tonic-gate 			"failed to get config_params, return: %d\n"), code);
69456a424ccSmp 	  return(code);
69556a424ccSmp      }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
6987c478bd9Sstevel@tonic-gate 			 KADM5_CONFIG_ADMIN_SERVER | \
699*55fea89dSDan Cross 			 KADM5_CONFIG_KADMIND_PORT)
700bd211b85Ssemery #define KPW_REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
701bd211b85Ssemery 			 KADM5_CONFIG_KPASSWD_SERVER | \
702*55fea89dSDan Cross 			 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);
70856a424ccSmp 	  krb5_free_context(handle->context);
7097c478bd9Sstevel@tonic-gate 		free(handle->lhandle);
71056a424ccSmp 	  free(handle);
7117c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7127c478bd9Sstevel@tonic-gate 			"missing config parameters\n"));
71356a424ccSmp 	  return KADM5_MISSING_KRB5_CONF_PARAMS;
71456a424ccSmp      }
715*55fea89dSDan Cross 
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)
732*55fea89dSDan Cross 		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) {
750d9976468Sps 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
751d9976468Sps 					    "could not malloc\n"));
752d9976468Sps 			code = ENOMEM;
753d9976468Sps 			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;
783*55fea89dSDan Cross 
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)
787*55fea89dSDan Cross 
78856a424ccSmp 
78956a424ccSmp      if (init_type == INIT_CREDS) {
79056a424ccSmp 	  ccache = ccache_in;
79156a424ccSmp 	  handle->cache_name = (char *)
79256a424ccSmp 	       malloc(strlen(krb5_cc_get_type(handle->context, ccache)) +
79356a424ccSmp 		      strlen(krb5_cc_get_name(handle->context, ccache)) + 2);
79456a424ccSmp 	  if (handle->cache_name == NULL) {
79556a424ccSmp 	       code = ENOMEM;
79656a424ccSmp 	       goto error;
79756a424ccSmp 	  }
79856a424ccSmp 	  sprintf(handle->cache_name, "%s:%s",
79956a424ccSmp 		  krb5_cc_get_type(handle->context, ccache),
80056a424ccSmp 		  krb5_cc_get_name(handle->context, ccache));
80156a424ccSmp      } else {
80256a424ccSmp #if 0
80356a424ccSmp 	  handle->cache_name =
80456a424ccSmp 	       (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1);
80556a424ccSmp 	  if (handle->cache_name == NULL) {
80656a424ccSmp 	       code = ENOMEM;
80756a424ccSmp 	       goto error;
80856a424ccSmp 	  }
80956a424ccSmp 	  sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE);
81056a424ccSmp 	  mktemp(handle->cache_name + strlen("FILE:"));
81156a424ccSmp #endif
81256a424ccSmp 	  {
81356a424ccSmp 	      static int counter = 0;
81456a424ccSmp 	      handle->cache_name = malloc(sizeof("MEMORY:kadm5_")
81556a424ccSmp 					  + 3*sizeof(counter));
81656a424ccSmp 	      sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++);
81756a424ccSmp 	  }
818*55fea89dSDan Cross 
81956a424ccSmp 	  if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
820*55fea89dSDan Cross 				      &ccache)))
82156a424ccSmp 	       goto error;
822*55fea89dSDan Cross 
82356a424ccSmp 	  if ((code = krb5_cc_initialize (handle->context, ccache,
824*55fea89dSDan Cross 					  creds.client)))
82556a424ccSmp 	       goto error;
8267c478bd9Sstevel@tonic-gate 
82756a424ccSmp 	  handle->destroy_cache = 1;
82856a424ccSmp      }
82956a424ccSmp      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);
832*55fea89dSDan Cross 
83356a424ccSmp      if ((code = krb5_timeofday(handle->context, &now)))
83456a424ccSmp 	  goto error;
8357c478bd9Sstevel@tonic-gate 
83656a424ccSmp      /*
83756a424ccSmp       * Get a ticket, use the method specified in init_type.
83856a424ccSmp       */
839*55fea89dSDan Cross 
84056a424ccSmp      creds.times.starttime = 0; /* start timer at KDC */
84156a424ccSmp      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 
859fe598cdcSmp 	/*
860fe598cdcSmp 	 * Solaris Kerberos:
861fe598cdcSmp 	 * Save the original creds.server as krb5_get_init_creds*() always
862*55fea89dSDan Cross 	 * sets the realm of the server to the client realm.
863fe598cdcSmp 	 */
864fe598cdcSmp 	code = krb5_copy_principal(handle->context, creds.server, &saved_server);
865fe598cdcSmp 	if (code)
866fe598cdcSmp 		goto error;
867fe598cdcSmp 
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 
88456a424ccSmp 	       if (pass) krb5_kt_close(handle->context, kt);
88556a424ccSmp 	  }
88656a424ccSmp      }
8877c478bd9Sstevel@tonic-gate 
88856a424ccSmp      /* Improved error messages */
88956a424ccSmp      if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
89056a424ccSmp      if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
89156a424ccSmp 	  code = KADM5_SECURE_PRINC_MISSING;
8927c478bd9Sstevel@tonic-gate 
89356a424ccSmp      if (code != 0) {
8947c478bd9Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
8957c478bd9Sstevel@tonic-gate 			"failed to obtain credentials cache\n"));
896fe598cdcSmp 		krb5_free_principal(handle->context, saved_server);
8977c478bd9Sstevel@tonic-gate 		goto error;
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
900d67a66d0Smp 	/*
901fe598cdcSmp 	 * Solaris Kerberos:
902fe598cdcSmp 	 * If the server principal had an empty realm then store that in
903fe598cdcSmp 	 * the cred cache and not the server realm as returned by
904d67a66d0Smp 	 * krb5_get_init_creds_{keytab|password}(). This ensures that rpcsec_gss
905d67a66d0Smp 	 * will find the credential in the cred cache even if a "fallback"
906d67a66d0Smp 	 * method is being used to determine the realm.
907fe598cdcSmp 	 */
908d67a66d0Smp 	if (init_type != INIT_CREDS) {
909d67a66d0Smp 		krb5_free_principal(handle->context, creds.server);
910d67a66d0Smp 	}
911fe598cdcSmp 	creds.server = saved_server;
912fe598cdcSmp 
9137c478bd9Sstevel@tonic-gate 	/*
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
92356a424ccSmp      if (pass != NULL)
92456a424ccSmp 	  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);
932d67a66d0Smp 
933d67a66d0Smp 		/*
934d67a66d0Smp 		 * Solaris Kerberos:
935d67a66d0Smp 		 * If _kadm5_initialize_rpcsec_gss_handle() fails it will have
936d67a66d0Smp 		 * called krb5_gss_release_cred(). If the credential cache is a
937d67a66d0Smp 		 * MEMORY cred cache krb5_gss_release_cred() destroys the
938*55fea89dSDan Cross 		 * cred cache data. Make sure that the cred-cache is closed
939d67a66d0Smp 		 * to prevent a double free in the "error" code.
940d67a66d0Smp 		 */
941d67a66d0Smp 		if (code != 0) {
942159d09a2SMark Phalan 			if (init_type != INIT_CREDS) {
943d67a66d0Smp 				krb5_cc_close(handle->context, ccache);
944159d09a2SMark Phalan 				ccache = NULL;
945159d09a2SMark Phalan 			}
9467c478bd9Sstevel@tonic-gate 			goto error;
947d67a66d0Smp 		}
9487c478bd9Sstevel@tonic-gate 	}
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	*server_handle = (void *) handle;
9517c478bd9Sstevel@tonic-gate 
952*55fea89dSDan Cross 	if (init_type != INIT_CREDS)
9537c478bd9Sstevel@tonic-gate 		krb5_cc_close(handle->context, ccache);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	goto cleanup;
956*55fea89dSDan Cross 
9577c478bd9Sstevel@tonic-gate error:
95856a424ccSmp      /*
95956a424ccSmp       * Note that it is illegal for this code to execute if "handle"
96056a424ccSmp       * has not been allocated and initialized.  I.e., don't use "goto
96156a424ccSmp       * error" before the block of code at the top of the function
96256a424ccSmp       * that allocates and initializes "handle".
96356a424ccSmp       */
96456a424ccSmp      if (handle->cache_name)
9657c478bd9Sstevel@tonic-gate 	 free(handle->cache_name);
96656a424ccSmp      if (handle->destroy_cache && ccache)
9677c478bd9Sstevel@tonic-gate 	 krb5_cc_destroy(handle->context, ccache);
96856a424ccSmp      if(handle->clnt && handle->clnt->cl_auth)
9697c478bd9Sstevel@tonic-gate 	  AUTH_DESTROY(handle->clnt->cl_auth);
97056a424ccSmp      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 
99056a424ccSmp      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 	 */
99756a424ccSmp      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 
100356a424ccSmp      return code;
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate kadm5_ret_t
kadm5_destroy(void * server_handle)10077c478bd9Sstevel@tonic-gate kadm5_destroy(void *server_handle)
10087c478bd9Sstevel@tonic-gate {
100956a424ccSmp      krb5_ccache	    ccache = NULL;
101056a424ccSmp      int		    code = KADM5_OK;
101156a424ccSmp      kadm5_server_handle_t	handle =
10127c478bd9Sstevel@tonic-gate 	  (kadm5_server_handle_t) server_handle;
10137c478bd9Sstevel@tonic-gate 	OM_uint32 min_stat;
10147c478bd9Sstevel@tonic-gate 
101556a424ccSmp      CHECK_HANDLE(server_handle);
101656a424ccSmp /* SUNW14resync:
1017*55fea89dSDan Cross  * krb5_cc_resolve() will resolve a ccache with the same data that
1018*55fea89dSDan Cross  * handle->my_cred points to. If the ccache is a MEMORY ccache then
101956a424ccSmp  * gss_release_cred() will free that data (it doesn't do this when ccache
102056a424ccSmp  * is a FILE ccache).
1021*55fea89dSDan Cross  * if'ed out to avoid the double free.
102256a424ccSmp  */
102356a424ccSmp #if 0
102456a424ccSmp      if (handle->destroy_cache && handle->cache_name) {
10257c478bd9Sstevel@tonic-gate 	 if ((code = krb5_cc_resolve(handle->context,
1026*55fea89dSDan Cross 				     handle->cache_name, &ccache)) == 0)
10277c478bd9Sstevel@tonic-gate 	     code = krb5_cc_destroy (handle->context, ccache);
102856a424ccSmp      }
102956a424ccSmp #endif
103056a424ccSmp      if (handle->cache_name)
10317c478bd9Sstevel@tonic-gate 	 free(handle->cache_name);
103256a424ccSmp      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);
103956a424ccSmp 	  AUTH_DESTROY(handle->clnt->cl_auth);
10407c478bd9Sstevel@tonic-gate 	}
104156a424ccSmp      if (handle->clnt)
10427c478bd9Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
104356a424ccSmp      if (handle->lhandle)
104456a424ccSmp           free (handle->lhandle);
10457c478bd9Sstevel@tonic-gate 
104656a424ccSmp      kadm5_free_config_params(handle->context, &handle->params);
104756a424ccSmp      krb5_free_context(handle->context);
10487c478bd9Sstevel@tonic-gate 
104956a424ccSmp      handle->magic_number = 0;
105056a424ccSmp      free(handle);
10517c478bd9Sstevel@tonic-gate 
105256a424ccSmp      return code;
105356a424ccSmp }
105456a424ccSmp /* not supported on client */
kadm5_lock(void * server_handle)105556a424ccSmp kadm5_ret_t kadm5_lock(void *server_handle)
105656a424ccSmp {
105756a424ccSmp     return EINVAL;
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
106056a424ccSmp /* not supported on client */
kadm5_unlock(void * server_handle)106156a424ccSmp kadm5_ret_t kadm5_unlock(void *server_handle)
10627c478bd9Sstevel@tonic-gate {
106356a424ccSmp     return EINVAL;
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate 
kadm5_flush(void * server_handle)106656a424ccSmp kadm5_ret_t kadm5_flush(void *server_handle)
10677c478bd9Sstevel@tonic-gate {
106856a424ccSmp      return KADM5_OK;
106956a424ccSmp }
107056a424ccSmp 
_kadm5_check_handle(void * handle)107156a424ccSmp int _kadm5_check_handle(void *handle)
107256a424ccSmp {
107356a424ccSmp      CHECK_HANDLE(handle);
107456a424ccSmp      return 0;
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate 
kadm5_init_krb5_context(krb5_context * ctx)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
kadm5_init_iprop(void * handle)10877c478bd9Sstevel@tonic-gate kadm5_init_iprop(void *handle)
10887c478bd9Sstevel@tonic-gate {
10897c478bd9Sstevel@tonic-gate 	return (0);
10907c478bd9Sstevel@tonic-gate }
1091