xref: /onnv-gate/usr/src/lib/krb5/kadm5/clnt/client_init.c (revision 6656:229d08ee2c75)
10Sstevel@tonic-gate /*
2*6656Ssemery  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * $Header: /cvs/krbdev/krb5/src/lib/kadm5/clnt/client_init.c,v 1.13.2.2 2000/05/09 13:17:14 raeburn Exp $
60Sstevel@tonic-gate  */
70Sstevel@tonic-gate 
80Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
90Sstevel@tonic-gate 
100Sstevel@tonic-gate /*
110Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * All rights reserved.
140Sstevel@tonic-gate  *
150Sstevel@tonic-gate  * Export of this software from the United States of America may require
160Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
170Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
180Sstevel@tonic-gate  * obtain such a license before exporting.
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
210Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
220Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
230Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
240Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
250Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
260Sstevel@tonic-gate  * to distribution of the software without specific, written prior
270Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
280Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
290Sstevel@tonic-gate  * or implied warranty.
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
320Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
330Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * $Header: /afs/athena.mit.edu/astaff/project/krbdev/.cvsroot/src/lib/kadm5/clnt/client_init.c,v 1.6 1996/11/07 17:13:44 tytso Exp $
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <stdio.h>
440Sstevel@tonic-gate #include <netdb.h>
454960Swillf #include "autoconf.h"
462881Smp153739 #ifdef HAVE_MEMORY_H
470Sstevel@tonic-gate #include <memory.h>
482881Smp153739 #endif
490Sstevel@tonic-gate #include <string.h>
500Sstevel@tonic-gate #include <com_err.h>
510Sstevel@tonic-gate #include <sys/types.h>
520Sstevel@tonic-gate #include <sys/socket.h>
530Sstevel@tonic-gate #include <netinet/in.h>
544960Swillf #include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
550Sstevel@tonic-gate #include <krb5.h>
560Sstevel@tonic-gate #ifdef __STDC__
570Sstevel@tonic-gate #include <stdlib.h>
580Sstevel@tonic-gate #endif
590Sstevel@tonic-gate #include <libintl.h>
600Sstevel@tonic-gate 
612881Smp153739 #include <kadm5/admin.h>
622881Smp153739 #include <kadm5/kadm_rpc.h>
632881Smp153739 #include "client_internal.h"
642881Smp153739 
650Sstevel@tonic-gate #include <syslog.h>
660Sstevel@tonic-gate #include <gssapi/gssapi.h>
670Sstevel@tonic-gate #include <gssapi_krb5.h>
680Sstevel@tonic-gate #include <gssapiP_krb5.h>
690Sstevel@tonic-gate #include <rpc/clnt.h>
702881Smp153739 
710Sstevel@tonic-gate #include <iprop_hdr.h>
720Sstevel@tonic-gate #include "iprop.h"
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #define	ADM_CCACHE  "/tmp/ovsec_adm.XXXXXX"
750Sstevel@tonic-gate 
762881Smp153739 static int old_auth_gssapi = 0;
770Sstevel@tonic-gate /* connection timeout to kadmind in seconds */
780Sstevel@tonic-gate #define		KADMIND_CONNECT_TIMEOUT	25
790Sstevel@tonic-gate 
800Sstevel@tonic-gate int _kadm5_check_handle();
810Sstevel@tonic-gate 
820Sstevel@tonic-gate enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
850Sstevel@tonic-gate 				   enum init_type init_type,
860Sstevel@tonic-gate 				   char *pass,
870Sstevel@tonic-gate 				   krb5_ccache ccache_in,
880Sstevel@tonic-gate 				   char *service_name,
890Sstevel@tonic-gate 				   kadm5_config_params *params,
900Sstevel@tonic-gate 				   krb5_ui_4 struct_version,
910Sstevel@tonic-gate 				   krb5_ui_4 api_version,
924960Swillf 				   char **db_args,
930Sstevel@tonic-gate 				   void **server_handle);
940Sstevel@tonic-gate 
950Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_creds(char *client_name,
960Sstevel@tonic-gate 				  krb5_ccache ccache,
970Sstevel@tonic-gate 				  char *service_name,
980Sstevel@tonic-gate 				  kadm5_config_params *params,
990Sstevel@tonic-gate 				  krb5_ui_4 struct_version,
1000Sstevel@tonic-gate 				  krb5_ui_4 api_version,
1014960Swillf 				  char **db_args,
1020Sstevel@tonic-gate 				  void **server_handle)
1030Sstevel@tonic-gate {
1042881Smp153739      return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache,
1050Sstevel@tonic-gate 			    service_name, params,
1064960Swillf 			    struct_version, api_version, db_args,
1070Sstevel@tonic-gate 			    server_handle);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
1120Sstevel@tonic-gate 				     char *service_name,
1130Sstevel@tonic-gate 				     kadm5_config_params *params,
1140Sstevel@tonic-gate 				     krb5_ui_4 struct_version,
1150Sstevel@tonic-gate 				     krb5_ui_4 api_version,
1164960Swillf 				     char **db_args,
1170Sstevel@tonic-gate 				     void **server_handle)
1180Sstevel@tonic-gate {
1192881Smp153739      return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
1200Sstevel@tonic-gate 			    service_name, params, struct_version,
1214960Swillf 			    api_version, db_args, server_handle);
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate kadm5_ret_t kadm5_init(char *client_name, char *pass,
1252881Smp153739 		       char *service_name,
1262881Smp153739 		       kadm5_config_params *params,
1272881Smp153739 		       krb5_ui_4 struct_version,
1282881Smp153739 		       krb5_ui_4 api_version,
1294960Swillf 		       char **db_args,
1302881Smp153739 		       void **server_handle)
1310Sstevel@tonic-gate {
1322881Smp153739      return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
1330Sstevel@tonic-gate 			    service_name, params, struct_version,
1344960Swillf 			    api_version, db_args, server_handle);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
1380Sstevel@tonic-gate 				 char *service_name,
1390Sstevel@tonic-gate 				 kadm5_config_params *params,
1400Sstevel@tonic-gate 				 krb5_ui_4 struct_version,
1410Sstevel@tonic-gate 				 krb5_ui_4 api_version,
1424960Swillf 				 char **db_args,
1430Sstevel@tonic-gate 				 void **server_handle)
1440Sstevel@tonic-gate {
1452881Smp153739      return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL,
1460Sstevel@tonic-gate 			    service_name, params, struct_version,
1474960Swillf 			    api_version, db_args, server_handle);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate krb5_error_code  kadm5_free_config_params();
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate static void
1530Sstevel@tonic-gate display_status_1(m, code, type, mech)
1540Sstevel@tonic-gate char *m;
1550Sstevel@tonic-gate OM_uint32 code;
1560Sstevel@tonic-gate int type;
1570Sstevel@tonic-gate const gss_OID mech;
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	OM_uint32 maj_stat, min_stat;
1600Sstevel@tonic-gate 	gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
1610Sstevel@tonic-gate 	OM_uint32 msg_ctx;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	msg_ctx = 0;
1640Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR, "%s\n", m);
1650Sstevel@tonic-gate 	/* LINTED */
1660Sstevel@tonic-gate 	while (1) {
1670Sstevel@tonic-gate 		maj_stat = gss_display_status(&min_stat, code,
1680Sstevel@tonic-gate 					    type, mech,
1690Sstevel@tonic-gate 					    &msg_ctx, &msg);
1700Sstevel@tonic-gate 		if (maj_stat != GSS_S_COMPLETE) {
1710Sstevel@tonic-gate 			syslog(LOG_ERR,
1720Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
1730Sstevel@tonic-gate 				    "error in gss_display_status"
1740Sstevel@tonic-gate 				    " called from <%s>\n"), m);
1750Sstevel@tonic-gate 			break;
1760Sstevel@tonic-gate 		} else
1770Sstevel@tonic-gate 			syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
1780Sstevel@tonic-gate 						"GSS-API error : %s\n"),
1790Sstevel@tonic-gate 			    m);
1800Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
1810Sstevel@tonic-gate 					"GSS-API error : %s\n"),
1820Sstevel@tonic-gate 		    (char *)msg.value);
1830Sstevel@tonic-gate 		if (msg.length != 0)
1840Sstevel@tonic-gate 			(void) gss_release_buffer(&min_stat, &msg);
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 		if (!msg_ctx)
1870Sstevel@tonic-gate 			break;
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate  * Function: display_status
1930Sstevel@tonic-gate  *
1940Sstevel@tonic-gate  * Purpose: displays GSS-API messages
1950Sstevel@tonic-gate  *
1960Sstevel@tonic-gate  * Arguments:
1970Sstevel@tonic-gate  *
1980Sstevel@tonic-gate  * 	msg		a string to be displayed with the message
1990Sstevel@tonic-gate  * 	maj_stat	the GSS-API major status code
2000Sstevel@tonic-gate  * 	min_stat	the GSS-API minor status code
2010Sstevel@tonic-gate  *	mech		kerberos mech
2020Sstevel@tonic-gate  * Effects:
2030Sstevel@tonic-gate  *
2040Sstevel@tonic-gate  * The GSS-API messages associated with maj_stat and min_stat are
2050Sstevel@tonic-gate  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
2060Sstevel@tonic-gate  * followed by a newline.
2070Sstevel@tonic-gate  */
2080Sstevel@tonic-gate void
2090Sstevel@tonic-gate display_status(msg, maj_stat, min_stat, mech)
2100Sstevel@tonic-gate char *msg;
2110Sstevel@tonic-gate OM_uint32 maj_stat;
2120Sstevel@tonic-gate OM_uint32 min_stat;
2130Sstevel@tonic-gate char *mech;
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate 	gss_OID mech_oid;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
2180Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
2190Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
2200Sstevel@tonic-gate 				"Invalid mechanism oid <%s>"), mech);
2210Sstevel@tonic-gate 		return;
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	display_status_1(msg, maj_stat, GSS_C_GSS_CODE, mech_oid);
2250Sstevel@tonic-gate 	display_status_1(msg, min_stat, GSS_C_MECH_CODE, mech_oid);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate  * Open an fd for the given address and connect asynchronously. Wait
2300Sstevel@tonic-gate  * KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds
2310Sstevel@tonic-gate  * change fd to blocking and return it, else return -1.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate static int
2340Sstevel@tonic-gate get_connection(struct netconfig *nconf, struct netbuf netaddr)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	struct t_info tinfo;
2370Sstevel@tonic-gate 	struct t_call sndcall;
2380Sstevel@tonic-gate 	struct t_call *rcvcall = NULL;
2390Sstevel@tonic-gate 	int connect_time;
2400Sstevel@tonic-gate 	int flags;
2410Sstevel@tonic-gate 	int fd;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	(void) memset(&tinfo, 0, sizeof (tinfo));
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	/* we'l open with O_NONBLOCK and avoid an fcntl */
2460Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR | O_NONBLOCK, &tinfo);
2470Sstevel@tonic-gate 	if (fd == -1) {
2480Sstevel@tonic-gate 		return (-1);
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if (t_bind(fd, (struct t_bind *)NULL, (struct t_bind *)NULL) == -1) {
2520Sstevel@tonic-gate 		(void) close(fd);
2530Sstevel@tonic-gate 		return (-1);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	/* we can't connect unless fd is in IDLE state */
2570Sstevel@tonic-gate 	if (t_getstate(fd) != T_IDLE) {
2580Sstevel@tonic-gate 		(void) close(fd);
2590Sstevel@tonic-gate 		return (-1);
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/* setup connect parameters */
2630Sstevel@tonic-gate 	netaddr.len = netaddr.maxlen = __rpc_get_a_size(tinfo.addr);
2640Sstevel@tonic-gate 	sndcall.addr = netaddr;
2650Sstevel@tonic-gate 	sndcall.opt.len = sndcall.udata.len = 0;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */
2680Sstevel@tonic-gate 	connect_time = time(NULL) + KADMIND_CONNECT_TIMEOUT;
2690Sstevel@tonic-gate 	if (t_connect(fd, &sndcall, rcvcall) != 0) {
2700Sstevel@tonic-gate 		if (t_errno != TNODATA) {
2710Sstevel@tonic-gate 			(void) close(fd);
2720Sstevel@tonic-gate 			return (-1);
2730Sstevel@tonic-gate 		}
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	/* loop till success or timeout */
2770Sstevel@tonic-gate 	for (;;) {
2780Sstevel@tonic-gate 		if (t_rcvconnect(fd, rcvcall) == 0)
2790Sstevel@tonic-gate 			break;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 		if (t_errno != TNODATA || time(NULL) > connect_time) {
2820Sstevel@tonic-gate 			/* we have either timed out or caught an error */
2830Sstevel@tonic-gate 			(void) close(fd);
2840Sstevel@tonic-gate 			if (rcvcall != NULL)
2850Sstevel@tonic-gate 				t_free((char *)rcvcall, T_CALL);
2860Sstevel@tonic-gate 			return (-1);
2870Sstevel@tonic-gate 		}
2880Sstevel@tonic-gate 		sleep(1);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	/* make the fd blocking (synchronous) */
2920Sstevel@tonic-gate 	flags = fcntl(fd, F_GETFL, 0);
2930Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
2940Sstevel@tonic-gate 	if (rcvcall != NULL)
2950Sstevel@tonic-gate 		t_free((char *)rcvcall, T_CALL);
2960Sstevel@tonic-gate 	return (fd);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate /*
3000Sstevel@tonic-gate  * Open an RPCSEC_GSS connection and
3010Sstevel@tonic-gate  * get a client handle to use for future RPCSEC calls.
3020Sstevel@tonic-gate  *
3030Sstevel@tonic-gate  * This function is only used when changing passwords and
3040Sstevel@tonic-gate  * the kpasswd_protocol is RPCSEC_GSS
3050Sstevel@tonic-gate  */
3060Sstevel@tonic-gate static int
3070Sstevel@tonic-gate _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle,
3080Sstevel@tonic-gate 				    char *client_name,
3090Sstevel@tonic-gate 				    char *service_name)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate 	struct netbuf netaddr;
3120Sstevel@tonic-gate 	struct hostent *hp;
3130Sstevel@tonic-gate 	int fd;
3140Sstevel@tonic-gate 	struct sockaddr_in addr;
3150Sstevel@tonic-gate 	struct sockaddr_in *sin;
3160Sstevel@tonic-gate 	struct netconfig *nconf;
3170Sstevel@tonic-gate 	int code = 0;
3180Sstevel@tonic-gate 	generic_ret *r;
3190Sstevel@tonic-gate 	char *ccname_orig;
3200Sstevel@tonic-gate 	char *iprop_svc;
3210Sstevel@tonic-gate 	boolean_t iprop_enable = B_FALSE;
3220Sstevel@tonic-gate 	char mech[] = "kerberos_v5";
3230Sstevel@tonic-gate 	gss_OID mech_oid;
3240Sstevel@tonic-gate 	gss_OID_set_desc oid_set;
3250Sstevel@tonic-gate 	gss_name_t gss_client;
3260Sstevel@tonic-gate 	gss_buffer_desc input_name;
3270Sstevel@tonic-gate 	gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL;
3280Sstevel@tonic-gate 	rpc_gss_options_req_t   options_req;
3290Sstevel@tonic-gate 	rpc_gss_options_ret_t   options_ret;
3300Sstevel@tonic-gate 	rpc_gss_service_t service = rpc_gss_svc_privacy;
3310Sstevel@tonic-gate 	OM_uint32 gssstat, minor_stat;
3320Sstevel@tonic-gate 	void *handlep;
3330Sstevel@tonic-gate 	enum clnt_stat rpc_err_code;
334*6656Ssemery 	char *server = handle->params.admin_server;
3350Sstevel@tonic-gate 
336*6656Ssemery 	/*
337*6656Ssemery 	 * Try to find the kpasswd_server first if this is for the changepw
338*6656Ssemery 	 * service.  If defined then it should be resolvable else return error.
339*6656Ssemery 	 */
340*6656Ssemery 	if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE,
341*6656Ssemery 	    strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0) {
342*6656Ssemery 		if (handle->params.kpasswd_server != NULL)
343*6656Ssemery 			server = handle->params.kpasswd_server;
344*6656Ssemery 	}
345*6656Ssemery 	hp = gethostbyname(server);
3460Sstevel@tonic-gate 	if (hp == (struct hostent *)NULL) {
3470Sstevel@tonic-gate 		code = KADM5_BAD_SERVER_NAME;
3480Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
3490Sstevel@tonic-gate 					    "bad server name\n"));
3500Sstevel@tonic-gate 		goto cleanup;
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	memset(&addr, 0, sizeof (addr));
3540Sstevel@tonic-gate 	addr.sin_family = hp->h_addrtype;
3550Sstevel@tonic-gate 	(void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr,
3560Sstevel@tonic-gate 		    sizeof (addr.sin_addr));
3570Sstevel@tonic-gate 	addr.sin_port = htons((ushort_t)handle->params.kadmind_port);
3580Sstevel@tonic-gate 	sin = &addr;
3590Sstevel@tonic-gate #ifdef DEBUG
3600Sstevel@tonic-gate 	printf("kadmin_port %d\n", handle->params.kadmind_port);
3610Sstevel@tonic-gate 	printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n",
3620Sstevel@tonic-gate 	    addr.sin_port, addr.sin_family, addr.sin_zero);
3630Sstevel@tonic-gate 	printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1,
3640Sstevel@tonic-gate 	    addr.sin_addr.S_un.S_un_w.s_w2);
3650Sstevel@tonic-gate #endif
3660Sstevel@tonic-gate 	if ((handlep = setnetconfig()) == (void *) NULL) {
3670Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
3680Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
3690Sstevel@tonic-gate 				    "cannot get any transport information"));
3700Sstevel@tonic-gate 		goto error;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	while (nconf = getnetconfig(handlep)) {
3740Sstevel@tonic-gate 		if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
3750Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
3760Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0))
3770Sstevel@tonic-gate 			break;
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (nconf == (struct netconfig *)NULL)
3810Sstevel@tonic-gate 		goto error;
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/* Transform addr to netbuf */
3840Sstevel@tonic-gate 	(void) memset(&netaddr, 0, sizeof (netaddr));
3850Sstevel@tonic-gate 	netaddr.buf = (char *)sin;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	/* get an fd connected to the given address */
3880Sstevel@tonic-gate 	fd =  get_connection(nconf, netaddr);
3890Sstevel@tonic-gate 	if (fd == -1) {
3900Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
3910Sstevel@tonic-gate 			"unable to open connection to ADMIN server "
3920Sstevel@tonic-gate 			"(t_error %i)"), t_errno);
3930Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
3940Sstevel@tonic-gate 		goto error;
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate #ifdef DEBUG
3980Sstevel@tonic-gate 	printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS);
3990Sstevel@tonic-gate 	printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, "
4000Sstevel@tonic-gate 	    "nc_protofmly: %s\n",
4010Sstevel@tonic-gate 	    nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag,
4020Sstevel@tonic-gate 	    nconf->nc_protofmly);
4030Sstevel@tonic-gate 	printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n",
4040Sstevel@tonic-gate 	    nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups,
4050Sstevel@tonic-gate 	    nconf->nc_unused);
4060Sstevel@tonic-gate 	printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen,
4070Sstevel@tonic-gate 	    netaddr.buf, netaddr.len);
4080Sstevel@tonic-gate #endif
4090Sstevel@tonic-gate  	/*
4100Sstevel@tonic-gate 	 * Tell clnt_tli_create that given fd is already connected
4110Sstevel@tonic-gate 	 *
4120Sstevel@tonic-gate 	 * If the service_name and client_name are iprop-centric,
4130Sstevel@tonic-gate 	 * we need to clnt_tli_create to the appropriate RPC prog
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	iprop_svc = strdup(KIPROP_SVC_NAME);
4160Sstevel@tonic-gate 	if (iprop_svc == NULL)
4170Sstevel@tonic-gate 		return (ENOMEM);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if ((strstr(service_name, iprop_svc) != NULL) &&
4200Sstevel@tonic-gate 	    (strstr(client_name, iprop_svc) != NULL)) {
4210Sstevel@tonic-gate 		iprop_enable = B_TRUE;
4220Sstevel@tonic-gate 		handle->clnt = clnt_tli_create(fd, nconf, NULL,
4230Sstevel@tonic-gate 				    KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 	else
4260Sstevel@tonic-gate 		handle->clnt = clnt_tli_create(fd, nconf, NULL,
4270Sstevel@tonic-gate 				    KADM, KADMVERS, 0, 0);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	if (iprop_svc)
4300Sstevel@tonic-gate 		free(iprop_svc);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (handle->clnt == NULL) {
4330Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
4340Sstevel@tonic-gate 					"clnt_tli_create failed\n"));
4350Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
4360Sstevel@tonic-gate 		(void) close(fd);
4370Sstevel@tonic-gate 		goto error;
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 	/*
4400Sstevel@tonic-gate 	 * The rpc-handle was created on an fd opened and connected
4410Sstevel@tonic-gate 	 * by us, so we have to explicitly tell rpc to close it.
4420Sstevel@tonic-gate 	 */
4430Sstevel@tonic-gate 	if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) {
4440Sstevel@tonic-gate 		clnt_pcreateerror("ERROR:");
4450Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
4460Sstevel@tonic-gate 			"clnt_control failed to set CLSET_FD_CLOSE"));
4470Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
4480Sstevel@tonic-gate 		(void) close(fd);
4490Sstevel@tonic-gate 		goto error;
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	handle->lhandle->clnt = handle->clnt;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/* now that handle->clnt is set, we can check the handle */
4550Sstevel@tonic-gate 	if (code = _kadm5_check_handle((void *) handle))
4560Sstevel@tonic-gate 		goto error;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * The RPC connection is open; establish the GSS-API
4600Sstevel@tonic-gate 	 * authentication context.
4610Sstevel@tonic-gate 	 */
4620Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
4630Sstevel@tonic-gate 				    "have an rpc connection open\n"));
4640Sstevel@tonic-gate 	/* use the kadm5 cache */
4650Sstevel@tonic-gate 	ccname_orig = getenv("KRB5CCNAME");
4660Sstevel@tonic-gate 	if (ccname_orig)
4670Sstevel@tonic-gate 		ccname_orig = strdup(ccname_orig);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	(void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR,
4720Sstevel@tonic-gate 		dgettext(TEXT_DOMAIN,
4730Sstevel@tonic-gate 			"current credential cache: %s"), handle->cache_name);
4740Sstevel@tonic-gate 	input_name.value = client_name;
4750Sstevel@tonic-gate 	input_name.length = strlen((char *)input_name.value) + 1;
4760Sstevel@tonic-gate 	gssstat = gss_import_name(&minor_stat, &input_name,
4770Sstevel@tonic-gate 				(gss_OID)gss_nt_krb5_name, &gss_client);
4780Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
4790Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
4800Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR,
4810Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
4820Sstevel@tonic-gate 				"gss_import_name failed for client name\n"));
4830Sstevel@tonic-gate 		goto error;
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
4870Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
4880Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
4890Sstevel@tonic-gate 				"Invalid mechanism oid <%s>"), mech);
4900Sstevel@tonic-gate 		goto error;
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	oid_set.count = 1;
4940Sstevel@tonic-gate 	oid_set.elements = mech_oid;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
4970Sstevel@tonic-gate 				&oid_set, GSS_C_INITIATE,
4980Sstevel@tonic-gate 				&gss_client_creds, NULL, NULL);
4990Sstevel@tonic-gate 	(void) gss_release_name(&minor_stat, &gss_client);
5000Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
5010Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
5020Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
5030Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
5040Sstevel@tonic-gate 				"could not acquire credentials, "
5050Sstevel@tonic-gate 				"major error code: %d\n"), gssstat);
5060Sstevel@tonic-gate 		goto error;
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 	handle->my_cred = gss_client_creds;
5090Sstevel@tonic-gate 	options_req.my_cred = gss_client_creds;
5100Sstevel@tonic-gate 	options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
5110Sstevel@tonic-gate 	options_req.time_req = 0;
5120Sstevel@tonic-gate 	options_req.input_channel_bindings = NULL;
5130Sstevel@tonic-gate #ifndef INIT_TEST
5140Sstevel@tonic-gate 	handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt,
5150Sstevel@tonic-gate 						service_name,
5160Sstevel@tonic-gate 						mech,
5170Sstevel@tonic-gate 						service,
5180Sstevel@tonic-gate 						NULL,
5190Sstevel@tonic-gate 						&options_req,
5200Sstevel@tonic-gate 						&options_ret);
5210Sstevel@tonic-gate #endif /* ! INIT_TEST */
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (ccname_orig) {
5240Sstevel@tonic-gate 		(void) krb5_setenv("KRB5CCNAME", ccname_orig, 1);
5250Sstevel@tonic-gate 		free(ccname_orig);
5260Sstevel@tonic-gate 	} else
5270Sstevel@tonic-gate 		(void) krb5_unsetenv("KRB5CCNAME");
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (handle->clnt->cl_auth == NULL) {
5300Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
5310Sstevel@tonic-gate 		display_status(dgettext(TEXT_DOMAIN,
5320Sstevel@tonic-gate 					"rpc_gss_seccreate failed\n"),
5330Sstevel@tonic-gate 			    options_ret.major_status,
5340Sstevel@tonic-gate 			    options_ret.minor_status,
5350Sstevel@tonic-gate 			    mech);
5360Sstevel@tonic-gate 		goto error;
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	/*
5400Sstevel@tonic-gate 	 * Bypass the remainder of the code and return straightaway
5410Sstevel@tonic-gate 	 * if the gss service requested is kiprop
5420Sstevel@tonic-gate 	 */
5430Sstevel@tonic-gate 	if (iprop_enable == B_TRUE) {
5440Sstevel@tonic-gate 		code = 0;
5450Sstevel@tonic-gate 		goto cleanup;
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	r = init_1(&handle->api_version, handle->clnt, &rpc_err_code);
5490Sstevel@tonic-gate 	if (r == NULL) {
5500Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
5510Sstevel@tonic-gate 			"error during admin api initialization\n"));
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 		if (rpc_err_code == RPC_CANTENCODEARGS) {
5540Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
5550Sstevel@tonic-gate 				"encryption needed to encode RPC data may not be "
5560Sstevel@tonic-gate 				"installed/configured on this system"));
5570Sstevel@tonic-gate 			code = KADM5_RPC_ERROR_CANTENCODEARGS;
5580Sstevel@tonic-gate 		} else if (rpc_err_code == RPC_CANTDECODEARGS) {
5590Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
5600Sstevel@tonic-gate 				"encryption needed to decode RPC data may not be "
5610Sstevel@tonic-gate 				"installed/configured on the server"));
5620Sstevel@tonic-gate 			code = KADM5_RPC_ERROR_CANTDECODEARGS;
5630Sstevel@tonic-gate 		} else
5640Sstevel@tonic-gate 			code = KADM5_RPC_ERROR;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		goto error;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 	if (r->code) {
5700Sstevel@tonic-gate 		code = r->code;
5710Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
5720Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
5730Sstevel@tonic-gate 				"error during admin api initialization: %d\n"),
5740Sstevel@tonic-gate 			r->code);
5750Sstevel@tonic-gate 		goto error;
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate error:
5780Sstevel@tonic-gate cleanup:
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	if (handlep != (void *) NULL)
5810Sstevel@tonic-gate 		(void) endnetconfig(handlep);
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * gss_client_creds is freed only when there is an error condition,
5840Sstevel@tonic-gate 	 * given that rpc_gss_seccreate() will assign the cred pointer to the
5850Sstevel@tonic-gate 	 * my_cred member in the auth handle's private data structure.
5860Sstevel@tonic-gate 	 */
5870Sstevel@tonic-gate 	if (code && (gss_client_creds != GSS_C_NO_CREDENTIAL))
5880Sstevel@tonic-gate 		(void) gss_release_cred(&minor_stat, &gss_client_creds);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	return (code);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
5940Sstevel@tonic-gate 				   enum init_type init_type,
5950Sstevel@tonic-gate 				   char *pass,
5960Sstevel@tonic-gate 				   krb5_ccache ccache_in,
5970Sstevel@tonic-gate 				   char *service_name,
5980Sstevel@tonic-gate 				   kadm5_config_params *params_in,
5990Sstevel@tonic-gate 				   krb5_ui_4 struct_version,
6000Sstevel@tonic-gate 				   krb5_ui_4 api_version,
6014960Swillf 				   char **db_args,
6020Sstevel@tonic-gate 				   void **server_handle)
6030Sstevel@tonic-gate {
6042881Smp153739      int i;
6052881Smp153739      krb5_creds	creds;
6062881Smp153739      krb5_ccache ccache = NULL;
6072881Smp153739      krb5_timestamp  now;
6082881Smp153739      OM_uint32 gssstat, minor_stat;
6092881Smp153739      kadm5_server_handle_t handle;
6102881Smp153739      kadm5_config_params params_local;
6112881Smp153739      int code = 0;
6122881Smp153739      krb5_get_init_creds_opt opt;
6132881Smp153739      gss_buffer_desc input_name;
6142881Smp153739      krb5_error_code kret;
6152881Smp153739      krb5_int32 starttime;
6162881Smp153739      char *server = NULL;
6172881Smp153739      krb5_principal serverp = NULL, clientp = NULL;
6184807Smp153739      krb5_principal saved_server = NULL;
6192881Smp153739      bool_t cpw = FALSE;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
6220Sstevel@tonic-gate 		"entering kadm5_init_any\n"));
6232881Smp153739      if (! server_handle) {
6242881Smp153739 	 return EINVAL;
6252881Smp153739      }
6260Sstevel@tonic-gate 
6272881Smp153739      if (! (handle = malloc(sizeof(*handle)))) {
6282881Smp153739 	  return ENOMEM;
6292881Smp153739      }
6302881Smp153739      if (! (handle->lhandle = malloc(sizeof(*handle)))) {
6312881Smp153739 	  free(handle);
6322881Smp153739 	  return ENOMEM;
6332881Smp153739      }
6340Sstevel@tonic-gate 
6352881Smp153739      handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
6362881Smp153739      handle->struct_version = struct_version;
6372881Smp153739      handle->api_version = api_version;
6382881Smp153739      handle->clnt = 0;
6392881Smp153739      handle->cache_name = 0;
6402881Smp153739      handle->destroy_cache = 0;
6412881Smp153739      *handle->lhandle = *handle;
6422881Smp153739      handle->lhandle->api_version = KADM5_API_VERSION_2;
6432881Smp153739      handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
6442881Smp153739      handle->lhandle->lhandle = handle->lhandle;
6450Sstevel@tonic-gate 
6462881Smp153739     kret = krb5_init_context(&handle->context);
6470Sstevel@tonic-gate 	if (kret) {
6480Sstevel@tonic-gate 		free(handle->lhandle);
6490Sstevel@tonic-gate 		free(handle);
6500Sstevel@tonic-gate 		return (kret);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6532881Smp153739      if(service_name == NULL || client_name == NULL) {
6542881Smp153739 	krb5_free_context(handle->context);
6552881Smp153739 	free(handle->lhandle);
6562881Smp153739 	free(handle);
6572881Smp153739 	return EINVAL;
6582881Smp153739      }
6592881Smp153739      memset((char *) &creds, 0, sizeof(creds));
6600Sstevel@tonic-gate 
6612881Smp153739      /*
6622881Smp153739       * Verify the version numbers before proceeding; we can't use
6632881Smp153739       * CHECK_HANDLE because not all fields are set yet.
6642881Smp153739       */
6652881Smp153739      GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
6660Sstevel@tonic-gate 			  KADM5_NEW_LIB_API_VERSION);
6672881Smp153739 
6682881Smp153739      /*
6692881Smp153739       * Acquire relevant profile entries.  In version 2, merge values
6702881Smp153739       * in params_in with values from profile, based on
6712881Smp153739       * params_in->mask.
6722881Smp153739       *
6732881Smp153739       * In version 1, we've given a realm (which may be NULL) instead
6742881Smp153739       * of params_in.  So use that realm, make params_in contain an
6752881Smp153739       * empty mask, and behave like version 2.
6762881Smp153739       */
6772881Smp153739      memset((char *) &params_local, 0, sizeof(params_local));
6782881Smp153739      if (api_version == KADM5_API_VERSION_1) {
6792881Smp153739 	  if (params_in)
6802881Smp153739 	       params_local.mask = KADM5_CONFIG_REALM;
6812881Smp153739 	  params_in = &params_local;
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate #define ILLEGAL_PARAMS ( \
6852881Smp153739 		KADM5_CONFIG_ACL_FILE	| KADM5_CONFIG_ADB_LOCKFILE | \
6862881Smp153739 		KADM5_CONFIG_DBNAME	| KADM5_CONFIG_ADBNAME | \
6872881Smp153739 		KADM5_CONFIG_DICT_FILE	| KADM5_CONFIG_ADMIN_KEYTAB | \
6882881Smp153739 			KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \
6892881Smp153739 			KADM5_CONFIG_ENCTYPE	| KADM5_CONFIG_MAX_LIFE	| \
6902881Smp153739 			KADM5_CONFIG_MAX_RLIFE	| KADM5_CONFIG_EXPIRATION | \
6912881Smp153739 			KADM5_CONFIG_FLAGS	| KADM5_CONFIG_ENCTYPES	| \
6922881Smp153739 			KADM5_CONFIG_MKEY_FROM_KBD)
6930Sstevel@tonic-gate 
6942881Smp153739      if (params_in && params_in->mask & ILLEGAL_PARAMS) {
6950Sstevel@tonic-gate 		krb5_free_context(handle->context);
6960Sstevel@tonic-gate 		free(handle->lhandle);
6972881Smp153739 	  free(handle);
6980Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
6990Sstevel@tonic-gate 			"bad client parameters, returning %d"),
7000Sstevel@tonic-gate 			KADM5_BAD_CLIENT_PARAMS);
7012881Smp153739 	  return KADM5_BAD_CLIENT_PARAMS;
7022881Smp153739      }
7030Sstevel@tonic-gate 
7042881Smp153739      if ((code = kadm5_get_config_params(handle->context,
7050Sstevel@tonic-gate 					DEFAULT_PROFILE_PATH,
7060Sstevel@tonic-gate 					"KRB5_CONFIG",
7070Sstevel@tonic-gate 					params_in,
7080Sstevel@tonic-gate 					&handle->params))) {
7092881Smp153739 	  krb5_free_context(handle->context);
7102881Smp153739 	  free(handle->lhandle);
7112881Smp153739 	  free(handle);
7120Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
7130Sstevel@tonic-gate 			"failed to get config_params, return: %d\n"), code);
7142881Smp153739 	  return(code);
7152881Smp153739      }
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
7180Sstevel@tonic-gate 			 KADM5_CONFIG_ADMIN_SERVER | \
7190Sstevel@tonic-gate 			 KADM5_CONFIG_KADMIND_PORT)
720*6656Ssemery #define KPW_REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
721*6656Ssemery 			 KADM5_CONFIG_KPASSWD_SERVER | \
722*6656Ssemery 			 KADM5_CONFIG_KPASSWD_PORT)
7230Sstevel@tonic-gate 
724*6656Ssemery      if (((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) &&
725*6656Ssemery 	 ((handle->params.mask & KPW_REQUIRED_PARAMS) != KPW_REQUIRED_PARAMS)) {
7260Sstevel@tonic-gate 		(void) kadm5_free_config_params(handle->context,
7270Sstevel@tonic-gate 						&handle->params);
7282881Smp153739 	  krb5_free_context(handle->context);
7290Sstevel@tonic-gate 		free(handle->lhandle);
7302881Smp153739 	  free(handle);
7310Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7320Sstevel@tonic-gate 			"missing config parameters\n"));
7332881Smp153739 	  return KADM5_MISSING_KRB5_CONF_PARAMS;
7342881Smp153739      }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/*
7370Sstevel@tonic-gate 	 * Acquire a service ticket for service_name@realm in the name of
7380Sstevel@tonic-gate 	 * client_name, using password pass (which could be NULL), and
7390Sstevel@tonic-gate 	 * create a ccache to store them in.  If INIT_CREDS, use the
7400Sstevel@tonic-gate 	 * ccache we were provided instead.
7410Sstevel@tonic-gate 	 */
7420Sstevel@tonic-gate 	if ((code = krb5_parse_name(handle->context, client_name,
7430Sstevel@tonic-gate 			    &creds.client))) {
7440Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7450Sstevel@tonic-gate 			    "could not parse client name\n"));
7460Sstevel@tonic-gate 		goto error;
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 	clientp = creds.client;
7490Sstevel@tonic-gate 
75096Ssemery 	if (strncmp(service_name, KADM5_CHANGEPW_HOST_SERVICE,
75196Ssemery 	    strlen(KADM5_CHANGEPW_HOST_SERVICE)) == 0)
75296Ssemery 		cpw = TRUE;
75396Ssemery 
7540Sstevel@tonic-gate 	if (init_type == INIT_PASS &&
75596Ssemery 	    handle->params.kpasswd_protocol == KRB5_CHGPWD_CHANGEPW_V2 &&
75696Ssemery 	    cpw == TRUE) {
7570Sstevel@tonic-gate 		/*
7580Sstevel@tonic-gate 		 * The 'service_name' is constructed by the caller
7590Sstevel@tonic-gate 		 * but its done before the parameter which determines
7600Sstevel@tonic-gate 		 * the kpasswd_protocol is found.  The servers that
7610Sstevel@tonic-gate 		 * support the SET/CHANGE password protocol expect
7620Sstevel@tonic-gate 		 * a slightly different service principal than
7630Sstevel@tonic-gate 		 * the normal SEAM kadmind so construct the correct
7640Sstevel@tonic-gate 		 * name here and then forget it.
7650Sstevel@tonic-gate 		 */
7660Sstevel@tonic-gate 		char *newsvcname = NULL;
7670Sstevel@tonic-gate 		newsvcname = malloc(strlen(KADM5_CHANGEPW_SERVICE) +
7680Sstevel@tonic-gate 				    strlen(handle->params.realm) + 2);
7690Sstevel@tonic-gate 		if (newsvcname == NULL) {
7704152Sps57422 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7714152Sps57422 					    "could not malloc\n"));
7724152Sps57422 			code = ENOMEM;
7734152Sps57422 			goto error;
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 		sprintf(newsvcname, "%s@%s", KADM5_CHANGEPW_SERVICE,
7760Sstevel@tonic-gate 			handle->params.realm);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 		if ((code = krb5_parse_name(handle->context, newsvcname,
7790Sstevel@tonic-gate 					    &creds.server))) {
7800Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7810Sstevel@tonic-gate 					    "could not parse server "
7820Sstevel@tonic-gate 					    "name\n"));
7830Sstevel@tonic-gate 			free(newsvcname);
7840Sstevel@tonic-gate 			goto error;
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 		free(newsvcname);
7870Sstevel@tonic-gate 	} else {
7880Sstevel@tonic-gate 		input_name.value = service_name;
7890Sstevel@tonic-gate 		input_name.length = strlen((char *)input_name.value) + 1;
7905053Sgtb 		gssstat = krb5_gss_import_name(&minor_stat,
7910Sstevel@tonic-gate 				    &input_name,
7920Sstevel@tonic-gate 				    (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
7930Sstevel@tonic-gate 				    (gss_name_t *)&creds.server);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		if (gssstat != GSS_S_COMPLETE) {
7960Sstevel@tonic-gate 			code = KADM5_GSS_ERROR;
7970Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
7980Sstevel@tonic-gate 				"gss_import_name failed for client name\n"));
7990Sstevel@tonic-gate 			goto error;
8000Sstevel@tonic-gate 		}
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 	serverp = creds.server;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/* XXX temporarily fix a bug in krb5_cc_get_type */
8050Sstevel@tonic-gate #undef krb5_cc_get_type
8060Sstevel@tonic-gate #define krb5_cc_get_type(context, cache) ((cache)->ops->prefix)
8072881Smp153739 
8080Sstevel@tonic-gate 
8092881Smp153739      if (init_type == INIT_CREDS) {
8102881Smp153739 	  ccache = ccache_in;
8112881Smp153739 	  handle->cache_name = (char *)
8122881Smp153739 	       malloc(strlen(krb5_cc_get_type(handle->context, ccache)) +
8132881Smp153739 		      strlen(krb5_cc_get_name(handle->context, ccache)) + 2);
8142881Smp153739 	  if (handle->cache_name == NULL) {
8152881Smp153739 	       code = ENOMEM;
8162881Smp153739 	       goto error;
8172881Smp153739 	  }
8182881Smp153739 	  sprintf(handle->cache_name, "%s:%s",
8192881Smp153739 		  krb5_cc_get_type(handle->context, ccache),
8202881Smp153739 		  krb5_cc_get_name(handle->context, ccache));
8212881Smp153739      } else {
8222881Smp153739 #if 0
8232881Smp153739 	  handle->cache_name =
8242881Smp153739 	       (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1);
8252881Smp153739 	  if (handle->cache_name == NULL) {
8262881Smp153739 	       code = ENOMEM;
8272881Smp153739 	       goto error;
8282881Smp153739 	  }
8292881Smp153739 	  sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE);
8302881Smp153739 	  mktemp(handle->cache_name + strlen("FILE:"));
8312881Smp153739 #endif
8322881Smp153739 	  {
8332881Smp153739 	      static int counter = 0;
8342881Smp153739 	      handle->cache_name = malloc(sizeof("MEMORY:kadm5_")
8352881Smp153739 					  + 3*sizeof(counter));
8362881Smp153739 	      sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++);
8372881Smp153739 	  }
8382881Smp153739 
8392881Smp153739 	  if ((code = krb5_cc_resolve(handle->context, handle->cache_name,
8402881Smp153739 				      &ccache)))
8412881Smp153739 	       goto error;
8422881Smp153739 
8432881Smp153739 	  if ((code = krb5_cc_initialize (handle->context, ccache,
8442881Smp153739 					  creds.client)))
8452881Smp153739 	       goto error;
8460Sstevel@tonic-gate 
8472881Smp153739 	  handle->destroy_cache = 1;
8482881Smp153739      }
8492881Smp153739      handle->lhandle->cache_name = handle->cache_name;
8500Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
8510Sstevel@tonic-gate 		"cache created: %s\n"), handle->cache_name);
8522881Smp153739 
8532881Smp153739      if ((code = krb5_timeofday(handle->context, &now)))
8542881Smp153739 	  goto error;
8550Sstevel@tonic-gate 
8562881Smp153739      /*
8572881Smp153739       * Get a ticket, use the method specified in init_type.
8582881Smp153739       */
8592881Smp153739 
8602881Smp153739      creds.times.starttime = 0; /* start timer at KDC */
8612881Smp153739      creds.times.endtime = 0; /* endtime will be limited by service */
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	memset(&opt, 0, sizeof (opt));
8640Sstevel@tonic-gate 	krb5_get_init_creds_opt_init(&opt);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	if (creds.times.endtime) {
8670Sstevel@tonic-gate 		if (creds.times.starttime)
8680Sstevel@tonic-gate 			starttime = creds.times.starttime;
8690Sstevel@tonic-gate 		else
8700Sstevel@tonic-gate 			starttime = now;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_tkt_life(&opt,
8730Sstevel@tonic-gate 			creds.times.endtime - starttime);
8740Sstevel@tonic-gate 	}
8750Sstevel@tonic-gate 	code = krb5_unparse_name(handle->context, creds.server, &server);
8760Sstevel@tonic-gate 	if (code)
8770Sstevel@tonic-gate 		goto error;
8780Sstevel@tonic-gate 
8794807Smp153739 	/*
8804807Smp153739 	 * Solaris Kerberos:
8814807Smp153739 	 * Save the original creds.server as krb5_get_init_creds*() always
8824807Smp153739 	 * sets the realm of the server to the client realm.
8834807Smp153739 	 */
8844807Smp153739 	code = krb5_copy_principal(handle->context, creds.server, &saved_server);
8854807Smp153739 	if (code)
8864807Smp153739 		goto error;
8874807Smp153739 
8880Sstevel@tonic-gate 	if (init_type == INIT_PASS) {
8890Sstevel@tonic-gate 		code = krb5_get_init_creds_password(handle->context,
8900Sstevel@tonic-gate 			&creds, creds.client, pass, NULL,
8910Sstevel@tonic-gate 			NULL, creds.times.starttime,
8920Sstevel@tonic-gate 			server, &opt);
8930Sstevel@tonic-gate 	} else if (init_type == INIT_SKEY) {
8940Sstevel@tonic-gate 		krb5_keytab kt = NULL;
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		if (!(pass && (code = krb5_kt_resolve(handle->context,
8970Sstevel@tonic-gate 					pass, &kt)))) {
8980Sstevel@tonic-gate 			code = krb5_get_init_creds_keytab(
8990Sstevel@tonic-gate 					handle->context,
9000Sstevel@tonic-gate 					&creds, creds.client, kt,
9010Sstevel@tonic-gate 					creds.times.starttime,
9020Sstevel@tonic-gate 					server, &opt);
9030Sstevel@tonic-gate 
9042881Smp153739 	       if (pass) krb5_kt_close(handle->context, kt);
9052881Smp153739 	  }
9062881Smp153739      }
9070Sstevel@tonic-gate 
9082881Smp153739      /* Improved error messages */
9092881Smp153739      if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
9102881Smp153739      if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
9112881Smp153739 	  code = KADM5_SECURE_PRINC_MISSING;
9120Sstevel@tonic-gate 
9132881Smp153739      if (code != 0) {
9140Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
9150Sstevel@tonic-gate 			"failed to obtain credentials cache\n"));
9164807Smp153739 		krb5_free_principal(handle->context, saved_server);
9170Sstevel@tonic-gate 		goto error;
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate 
9205062Smp153739 	/*
9214807Smp153739 	 * Solaris Kerberos:
9224807Smp153739 	 * If the server principal had an empty realm then store that in
9234807Smp153739 	 * the cred cache and not the server realm as returned by
9245062Smp153739 	 * krb5_get_init_creds_{keytab|password}(). This ensures that rpcsec_gss
9255062Smp153739 	 * will find the credential in the cred cache even if a "fallback"
9265062Smp153739 	 * method is being used to determine the realm.
9274807Smp153739 	 */
9285062Smp153739 	if (init_type != INIT_CREDS) {
9295062Smp153739 		krb5_free_principal(handle->context, creds.server);
9305062Smp153739 	}
9314807Smp153739 	creds.server = saved_server;
9324807Smp153739 
9330Sstevel@tonic-gate 	/*
9340Sstevel@tonic-gate 	 * If we got this far, save the creds in the cache.
9350Sstevel@tonic-gate 	 */
9360Sstevel@tonic-gate 	if (ccache) {
9370Sstevel@tonic-gate 		code = krb5_cc_store_cred(handle->context, ccache, &creds);
9380Sstevel@tonic-gate 	}
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "obtained credentials cache\n"));
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate #ifdef ZEROPASSWD
9432881Smp153739      if (pass != NULL)
9442881Smp153739 	  memset(pass, 0, strlen(pass));
9450Sstevel@tonic-gate #endif
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	if (init_type != INIT_PASS ||
94896Ssemery 	    handle->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC ||
94996Ssemery 	    cpw == FALSE) {
9500Sstevel@tonic-gate 		code = _kadm5_initialize_rpcsec_gss_handle(handle,
9510Sstevel@tonic-gate 					client_name, service_name);
9525062Smp153739 
9535062Smp153739 		/*
9545062Smp153739 		 * Solaris Kerberos:
9555062Smp153739 		 * If _kadm5_initialize_rpcsec_gss_handle() fails it will have
9565062Smp153739 		 * called krb5_gss_release_cred(). If the credential cache is a
9575062Smp153739 		 * MEMORY cred cache krb5_gss_release_cred() destroys the
9585062Smp153739 		 * cred cache data. Make sure that the cred-cache is closed
9595062Smp153739 		 * to prevent a double free in the "error" code.
9605062Smp153739 		 */
9615062Smp153739 		if (code != 0) {
9625062Smp153739 			if (init_type != INIT_CREDS)
9635062Smp153739 				krb5_cc_close(handle->context, ccache);
9640Sstevel@tonic-gate 			goto error;
9655062Smp153739 		}
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	*server_handle = (void *) handle;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	if (init_type != INIT_CREDS)
9710Sstevel@tonic-gate 		krb5_cc_close(handle->context, ccache);
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	goto cleanup;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate error:
9762881Smp153739      /*
9772881Smp153739       * Note that it is illegal for this code to execute if "handle"
9782881Smp153739       * has not been allocated and initialized.  I.e., don't use "goto
9792881Smp153739       * error" before the block of code at the top of the function
9802881Smp153739       * that allocates and initializes "handle".
9812881Smp153739       */
9822881Smp153739      if (handle->cache_name)
9830Sstevel@tonic-gate 	 free(handle->cache_name);
9842881Smp153739      if (handle->destroy_cache && ccache)
9850Sstevel@tonic-gate 	 krb5_cc_destroy(handle->context, ccache);
9862881Smp153739      if(handle->clnt && handle->clnt->cl_auth)
9870Sstevel@tonic-gate 	  AUTH_DESTROY(handle->clnt->cl_auth);
9882881Smp153739      if(handle->clnt)
9890Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
9900Sstevel@tonic-gate 	(void) kadm5_free_config_params(handle->context, &handle->params);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate cleanup:
9930Sstevel@tonic-gate 	if (server)
9940Sstevel@tonic-gate 		free(server);
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	/*
9971692Ssemery 	 * cred's server and client pointers could have been overwritten
9981692Ssemery 	 * by the krb5_get_init_* functions.  If the addresses are different
9991692Ssemery 	 * before and after the calls then we must free the memory that
10001692Ssemery 	 * was allocated before the call.
10010Sstevel@tonic-gate 	 */
10021692Ssemery 	if (clientp && clientp != creds.client)
10030Sstevel@tonic-gate 		krb5_free_principal(handle->context, clientp);
10041692Ssemery 
10051692Ssemery 	if (serverp && serverp != creds.server)
10060Sstevel@tonic-gate 		krb5_free_principal(handle->context, serverp);
10070Sstevel@tonic-gate 
10082881Smp153739      krb5_free_cred_contents(handle->context, &creds);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	/*
10110Sstevel@tonic-gate 	 * Dont clean up the handle if the code is OK (code==0)
10120Sstevel@tonic-gate 	 * because it is returned to the caller in the 'server_handle'
10130Sstevel@tonic-gate 	 * ptr.
10140Sstevel@tonic-gate 	 */
10152881Smp153739      if (code) {
10160Sstevel@tonic-gate 		krb5_free_context(handle->context);
10170Sstevel@tonic-gate 		free(handle->lhandle);
10180Sstevel@tonic-gate 	  free(handle);
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 
10212881Smp153739      return code;
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate kadm5_ret_t
10250Sstevel@tonic-gate kadm5_destroy(void *server_handle)
10260Sstevel@tonic-gate {
10272881Smp153739      krb5_ccache	    ccache = NULL;
10282881Smp153739      int		    code = KADM5_OK;
10292881Smp153739      kadm5_server_handle_t	handle =
10300Sstevel@tonic-gate 	  (kadm5_server_handle_t) server_handle;
10310Sstevel@tonic-gate 	OM_uint32 min_stat;
10320Sstevel@tonic-gate 
10332881Smp153739      CHECK_HANDLE(server_handle);
10342881Smp153739 /* SUNW14resync:
10352881Smp153739  * krb5_cc_resolve() will resolve a ccache with the same data that
10362881Smp153739  * handle->my_cred points to. If the ccache is a MEMORY ccache then
10372881Smp153739  * gss_release_cred() will free that data (it doesn't do this when ccache
10382881Smp153739  * is a FILE ccache).
10392881Smp153739  * if'ed out to avoid the double free.
10402881Smp153739  */
10412881Smp153739 #if 0
10422881Smp153739      if (handle->destroy_cache && handle->cache_name) {
10430Sstevel@tonic-gate 	 if ((code = krb5_cc_resolve(handle->context,
10440Sstevel@tonic-gate 				     handle->cache_name, &ccache)) == 0)
10450Sstevel@tonic-gate 	     code = krb5_cc_destroy (handle->context, ccache);
10462881Smp153739      }
10472881Smp153739 #endif
10482881Smp153739      if (handle->cache_name)
10490Sstevel@tonic-gate 	 free(handle->cache_name);
10502881Smp153739      if (handle->clnt && handle->clnt->cl_auth) {
10510Sstevel@tonic-gate 		/*
10520Sstevel@tonic-gate 		 * Since kadm5 doesn't use the default credentials we
10530Sstevel@tonic-gate 		 * must clean this up manually.
10540Sstevel@tonic-gate 		 */
10550Sstevel@tonic-gate 		if (handle->my_cred != GSS_C_NO_CREDENTIAL)
10560Sstevel@tonic-gate 			(void) gss_release_cred(&min_stat, &handle->my_cred);
10572881Smp153739 	  AUTH_DESTROY(handle->clnt->cl_auth);
10580Sstevel@tonic-gate 	}
10592881Smp153739      if (handle->clnt)
10600Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
10612881Smp153739      if (handle->lhandle)
10622881Smp153739           free (handle->lhandle);
10632881Smp153739 
10642881Smp153739      kadm5_free_config_params(handle->context, &handle->params);
10652881Smp153739      krb5_free_context(handle->context);
10660Sstevel@tonic-gate 
10672881Smp153739      handle->magic_number = 0;
10682881Smp153739      free(handle);
10690Sstevel@tonic-gate 
10702881Smp153739      return code;
10712881Smp153739 }
10722881Smp153739 /* not supported on client */
10732881Smp153739 kadm5_ret_t kadm5_lock(void *server_handle)
10742881Smp153739 {
10752881Smp153739     return EINVAL;
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate 
10782881Smp153739 /* not supported on client */
10792881Smp153739 kadm5_ret_t kadm5_unlock(void *server_handle)
10800Sstevel@tonic-gate {
10812881Smp153739     return EINVAL;
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate 
10842881Smp153739 kadm5_ret_t kadm5_flush(void *server_handle)
10850Sstevel@tonic-gate {
10862881Smp153739      return KADM5_OK;
10872881Smp153739 }
10882881Smp153739 
10892881Smp153739 int _kadm5_check_handle(void *handle)
10902881Smp153739 {
10912881Smp153739      CHECK_HANDLE(handle);
10922881Smp153739      return 0;
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate 
10954960Swillf krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
10964960Swillf {
10974960Swillf     return krb5_init_context(ctx);
10984960Swillf }
10994960Swillf 
11000Sstevel@tonic-gate /*
11010Sstevel@tonic-gate  * Stub function for kadmin.  It was created to eliminate the dependency on
11020Sstevel@tonic-gate  * libkdb's ulog functions.  The srv equivalent makes the actual calls.
11030Sstevel@tonic-gate  */
11040Sstevel@tonic-gate krb5_error_code
11050Sstevel@tonic-gate kadm5_init_iprop(void *handle)
11060Sstevel@tonic-gate {
11070Sstevel@tonic-gate 	return (0);
11080Sstevel@tonic-gate }
1109