xref: /onnv-gate/usr/src/lib/krb5/kadm5/clnt/client_init.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  *
5*0Sstevel@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 $
6*0Sstevel@tonic-gate  */
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
9*0Sstevel@tonic-gate 
10*0Sstevel@tonic-gate /*
11*0Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * All rights reserved.
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * Export of this software from the United States of America may require
16*0Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
17*0Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
18*0Sstevel@tonic-gate  * obtain such a license before exporting.
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
21*0Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
22*0Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
23*0Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
24*0Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
25*0Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
26*0Sstevel@tonic-gate  * to distribution of the software without specific, written prior
27*0Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
28*0Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
29*0Sstevel@tonic-gate  * or implied warranty.
30*0Sstevel@tonic-gate  *
31*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
32*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
33*0Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
39*0Sstevel@tonic-gate  *
40*0Sstevel@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 $
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include <stdio.h>
44*0Sstevel@tonic-gate #include <netdb.h>
45*0Sstevel@tonic-gate #include <memory.h>
46*0Sstevel@tonic-gate #include <string.h>
47*0Sstevel@tonic-gate #include <com_err.h>
48*0Sstevel@tonic-gate #include <sys/types.h>
49*0Sstevel@tonic-gate #include <sys/socket.h>
50*0Sstevel@tonic-gate #include <netinet/in.h>
51*0Sstevel@tonic-gate #include <krb5.h>
52*0Sstevel@tonic-gate #include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
53*0Sstevel@tonic-gate #ifdef __STDC__
54*0Sstevel@tonic-gate #include <stdlib.h>
55*0Sstevel@tonic-gate #endif
56*0Sstevel@tonic-gate #include <libintl.h>
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #include <syslog.h>
59*0Sstevel@tonic-gate #include <gssapi/gssapi.h>
60*0Sstevel@tonic-gate #include <gssapi_krb5.h>
61*0Sstevel@tonic-gate #include <gssapiP_krb5.h>
62*0Sstevel@tonic-gate #include <kadm5/kadm_rpc.h>
63*0Sstevel@tonic-gate #include <rpc/clnt.h>
64*0Sstevel@tonic-gate #include <kadm5/admin.h>
65*0Sstevel@tonic-gate #include "client_internal.h"
66*0Sstevel@tonic-gate #include <iprop_hdr.h>
67*0Sstevel@tonic-gate #include "iprop.h"
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate #define	ADM_CCACHE  "/tmp/ovsec_adm.XXXXXX"
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate /* connection timeout to kadmind in seconds */
72*0Sstevel@tonic-gate #define		KADMIND_CONNECT_TIMEOUT	25
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate int _kadm5_check_handle();
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
79*0Sstevel@tonic-gate 				   enum init_type init_type,
80*0Sstevel@tonic-gate 				   char *pass,
81*0Sstevel@tonic-gate 				   krb5_ccache ccache_in,
82*0Sstevel@tonic-gate 				   char *service_name,
83*0Sstevel@tonic-gate 				   kadm5_config_params *params,
84*0Sstevel@tonic-gate 				   krb5_ui_4 struct_version,
85*0Sstevel@tonic-gate 				   krb5_ui_4 api_version,
86*0Sstevel@tonic-gate 				   void **server_handle);
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_creds(char *client_name,
89*0Sstevel@tonic-gate 				  krb5_ccache ccache,
90*0Sstevel@tonic-gate 				  char *service_name,
91*0Sstevel@tonic-gate 				  kadm5_config_params *params,
92*0Sstevel@tonic-gate 				  krb5_ui_4 struct_version,
93*0Sstevel@tonic-gate 				  krb5_ui_4 api_version,
94*0Sstevel@tonic-gate 				  void **server_handle)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache,
97*0Sstevel@tonic-gate 			    service_name, params,
98*0Sstevel@tonic-gate 			    struct_version, api_version,
99*0Sstevel@tonic-gate 			    server_handle);
100*0Sstevel@tonic-gate }
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
104*0Sstevel@tonic-gate 				     char *service_name,
105*0Sstevel@tonic-gate 				     kadm5_config_params *params,
106*0Sstevel@tonic-gate 				     krb5_ui_4 struct_version,
107*0Sstevel@tonic-gate 				     krb5_ui_4 api_version,
108*0Sstevel@tonic-gate 				     void **server_handle)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
111*0Sstevel@tonic-gate 			    service_name, params, struct_version,
112*0Sstevel@tonic-gate 			    api_version, server_handle);
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate kadm5_ret_t kadm5_init(char *client_name, char *pass,
116*0Sstevel@tonic-gate 			 char *service_name,
117*0Sstevel@tonic-gate 			 kadm5_config_params *params,
118*0Sstevel@tonic-gate 			 krb5_ui_4 struct_version,
119*0Sstevel@tonic-gate 			 krb5_ui_4 api_version,
120*0Sstevel@tonic-gate 			 void **server_handle)
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
123*0Sstevel@tonic-gate 			    service_name, params, struct_version,
124*0Sstevel@tonic-gate 			    api_version, server_handle);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
128*0Sstevel@tonic-gate 				 char *service_name,
129*0Sstevel@tonic-gate 				 kadm5_config_params *params,
130*0Sstevel@tonic-gate 				 krb5_ui_4 struct_version,
131*0Sstevel@tonic-gate 				 krb5_ui_4 api_version,
132*0Sstevel@tonic-gate 				 void **server_handle)
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL,
135*0Sstevel@tonic-gate 			    service_name, params, struct_version,
136*0Sstevel@tonic-gate 			    api_version, server_handle);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate krb5_error_code  kadm5_free_config_params();
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate static void
142*0Sstevel@tonic-gate display_status_1(m, code, type, mech)
143*0Sstevel@tonic-gate char *m;
144*0Sstevel@tonic-gate OM_uint32 code;
145*0Sstevel@tonic-gate int type;
146*0Sstevel@tonic-gate const gss_OID mech;
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	OM_uint32 maj_stat, min_stat;
149*0Sstevel@tonic-gate 	gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
150*0Sstevel@tonic-gate 	OM_uint32 msg_ctx;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	msg_ctx = 0;
153*0Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR, "%s\n", m);
154*0Sstevel@tonic-gate 	/* LINTED */
155*0Sstevel@tonic-gate 	while (1) {
156*0Sstevel@tonic-gate 		maj_stat = gss_display_status(&min_stat, code,
157*0Sstevel@tonic-gate 					    type, mech,
158*0Sstevel@tonic-gate 					    &msg_ctx, &msg);
159*0Sstevel@tonic-gate 		if (maj_stat != GSS_S_COMPLETE) {
160*0Sstevel@tonic-gate 			syslog(LOG_ERR,
161*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
162*0Sstevel@tonic-gate 				    "error in gss_display_status"
163*0Sstevel@tonic-gate 				    " called from <%s>\n"), m);
164*0Sstevel@tonic-gate 			break;
165*0Sstevel@tonic-gate 		} else
166*0Sstevel@tonic-gate 			syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
167*0Sstevel@tonic-gate 						"GSS-API error : %s\n"),
168*0Sstevel@tonic-gate 			    m);
169*0Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
170*0Sstevel@tonic-gate 					"GSS-API error : %s\n"),
171*0Sstevel@tonic-gate 		    (char *)msg.value);
172*0Sstevel@tonic-gate 		if (msg.length != 0)
173*0Sstevel@tonic-gate 			(void) gss_release_buffer(&min_stat, &msg);
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 		if (!msg_ctx)
176*0Sstevel@tonic-gate 			break;
177*0Sstevel@tonic-gate 	}
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  * Function: display_status
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  * Purpose: displays GSS-API messages
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  * Arguments:
186*0Sstevel@tonic-gate  *
187*0Sstevel@tonic-gate  * 	msg		a string to be displayed with the message
188*0Sstevel@tonic-gate  * 	maj_stat	the GSS-API major status code
189*0Sstevel@tonic-gate  * 	min_stat	the GSS-API minor status code
190*0Sstevel@tonic-gate  *	mech		kerberos mech
191*0Sstevel@tonic-gate  * Effects:
192*0Sstevel@tonic-gate  *
193*0Sstevel@tonic-gate  * The GSS-API messages associated with maj_stat and min_stat are
194*0Sstevel@tonic-gate  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
195*0Sstevel@tonic-gate  * followed by a newline.
196*0Sstevel@tonic-gate  */
197*0Sstevel@tonic-gate void
198*0Sstevel@tonic-gate display_status(msg, maj_stat, min_stat, mech)
199*0Sstevel@tonic-gate char *msg;
200*0Sstevel@tonic-gate OM_uint32 maj_stat;
201*0Sstevel@tonic-gate OM_uint32 min_stat;
202*0Sstevel@tonic-gate char *mech;
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate 	gss_OID mech_oid;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
207*0Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
208*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
209*0Sstevel@tonic-gate 				"Invalid mechanism oid <%s>"), mech);
210*0Sstevel@tonic-gate 		return;
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	display_status_1(msg, maj_stat, GSS_C_GSS_CODE, mech_oid);
214*0Sstevel@tonic-gate 	display_status_1(msg, min_stat, GSS_C_MECH_CODE, mech_oid);
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate /*
218*0Sstevel@tonic-gate  * Open an fd for the given address and connect asynchronously. Wait
219*0Sstevel@tonic-gate  * KADMIND_CONNECT_TIMEOUT seconds or till it succeeds. If it succeeds
220*0Sstevel@tonic-gate  * change fd to blocking and return it, else return -1.
221*0Sstevel@tonic-gate  */
222*0Sstevel@tonic-gate static int
223*0Sstevel@tonic-gate get_connection(struct netconfig *nconf, struct netbuf netaddr)
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	struct t_info tinfo;
226*0Sstevel@tonic-gate 	struct t_call sndcall;
227*0Sstevel@tonic-gate 	struct t_call *rcvcall = NULL;
228*0Sstevel@tonic-gate 	int connect_time;
229*0Sstevel@tonic-gate 	int flags;
230*0Sstevel@tonic-gate 	int fd;
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	(void) memset(&tinfo, 0, sizeof (tinfo));
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	/* we'l open with O_NONBLOCK and avoid an fcntl */
235*0Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR | O_NONBLOCK, &tinfo);
236*0Sstevel@tonic-gate 	if (fd == -1) {
237*0Sstevel@tonic-gate 		return (-1);
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	if (t_bind(fd, (struct t_bind *)NULL, (struct t_bind *)NULL) == -1) {
241*0Sstevel@tonic-gate 		(void) close(fd);
242*0Sstevel@tonic-gate 		return (-1);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	/* we can't connect unless fd is in IDLE state */
246*0Sstevel@tonic-gate 	if (t_getstate(fd) != T_IDLE) {
247*0Sstevel@tonic-gate 		(void) close(fd);
248*0Sstevel@tonic-gate 		return (-1);
249*0Sstevel@tonic-gate 	}
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	/* setup connect parameters */
252*0Sstevel@tonic-gate 	netaddr.len = netaddr.maxlen = __rpc_get_a_size(tinfo.addr);
253*0Sstevel@tonic-gate 	sndcall.addr = netaddr;
254*0Sstevel@tonic-gate 	sndcall.opt.len = sndcall.udata.len = 0;
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	/* we wait for KADMIND_CONNECT_TIMEOUT seconds from now */
257*0Sstevel@tonic-gate 	connect_time = time(NULL) + KADMIND_CONNECT_TIMEOUT;
258*0Sstevel@tonic-gate 	if (t_connect(fd, &sndcall, rcvcall) != 0) {
259*0Sstevel@tonic-gate 		if (t_errno != TNODATA) {
260*0Sstevel@tonic-gate 			(void) close(fd);
261*0Sstevel@tonic-gate 			return (-1);
262*0Sstevel@tonic-gate 		}
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	/* loop till success or timeout */
266*0Sstevel@tonic-gate 	for (;;) {
267*0Sstevel@tonic-gate 		if (t_rcvconnect(fd, rcvcall) == 0)
268*0Sstevel@tonic-gate 			break;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 		if (t_errno != TNODATA || time(NULL) > connect_time) {
271*0Sstevel@tonic-gate 			/* we have either timed out or caught an error */
272*0Sstevel@tonic-gate 			(void) close(fd);
273*0Sstevel@tonic-gate 			if (rcvcall != NULL)
274*0Sstevel@tonic-gate 				t_free((char *)rcvcall, T_CALL);
275*0Sstevel@tonic-gate 			return (-1);
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 		sleep(1);
278*0Sstevel@tonic-gate 	}
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	/* make the fd blocking (synchronous) */
281*0Sstevel@tonic-gate 	flags = fcntl(fd, F_GETFL, 0);
282*0Sstevel@tonic-gate 	(void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
283*0Sstevel@tonic-gate 	if (rcvcall != NULL)
284*0Sstevel@tonic-gate 		t_free((char *)rcvcall, T_CALL);
285*0Sstevel@tonic-gate 	return (fd);
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate /*
289*0Sstevel@tonic-gate  * Open an RPCSEC_GSS connection and
290*0Sstevel@tonic-gate  * get a client handle to use for future RPCSEC calls.
291*0Sstevel@tonic-gate  *
292*0Sstevel@tonic-gate  * This function is only used when changing passwords and
293*0Sstevel@tonic-gate  * the kpasswd_protocol is RPCSEC_GSS
294*0Sstevel@tonic-gate  */
295*0Sstevel@tonic-gate static int
296*0Sstevel@tonic-gate _kadm5_initialize_rpcsec_gss_handle(kadm5_server_handle_t handle,
297*0Sstevel@tonic-gate 				    char *client_name,
298*0Sstevel@tonic-gate 				    char *service_name)
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	struct netbuf netaddr;
301*0Sstevel@tonic-gate 	struct hostent *hp;
302*0Sstevel@tonic-gate 	int fd;
303*0Sstevel@tonic-gate 	struct sockaddr_in addr;
304*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
305*0Sstevel@tonic-gate 	struct netconfig *nconf;
306*0Sstevel@tonic-gate 	int code = 0;
307*0Sstevel@tonic-gate 	generic_ret *r;
308*0Sstevel@tonic-gate 	char *ccname_orig;
309*0Sstevel@tonic-gate 	char *iprop_svc;
310*0Sstevel@tonic-gate 	boolean_t iprop_enable = B_FALSE;
311*0Sstevel@tonic-gate 	char mech[] = "kerberos_v5";
312*0Sstevel@tonic-gate 	gss_OID mech_oid;
313*0Sstevel@tonic-gate 	gss_OID_set_desc oid_set;
314*0Sstevel@tonic-gate 	gss_name_t gss_client;
315*0Sstevel@tonic-gate 	gss_buffer_desc input_name;
316*0Sstevel@tonic-gate 	gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL;
317*0Sstevel@tonic-gate 	rpc_gss_options_req_t   options_req;
318*0Sstevel@tonic-gate 	rpc_gss_options_ret_t   options_ret;
319*0Sstevel@tonic-gate 	rpc_gss_service_t service = rpc_gss_svc_privacy;
320*0Sstevel@tonic-gate 	OM_uint32 gssstat, minor_stat;
321*0Sstevel@tonic-gate 	void *handlep;
322*0Sstevel@tonic-gate 	enum clnt_stat rpc_err_code;
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	hp = gethostbyname(handle->params.admin_server);
325*0Sstevel@tonic-gate 	if (hp == (struct hostent *)NULL) {
326*0Sstevel@tonic-gate 		code = KADM5_BAD_SERVER_NAME;
327*0Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
328*0Sstevel@tonic-gate 					    "bad server name\n"));
329*0Sstevel@tonic-gate 		goto cleanup;
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	memset(&addr, 0, sizeof (addr));
333*0Sstevel@tonic-gate 	addr.sin_family = hp->h_addrtype;
334*0Sstevel@tonic-gate 	(void) memcpy((char *)&addr.sin_addr, (char *)hp->h_addr,
335*0Sstevel@tonic-gate 		    sizeof (addr.sin_addr));
336*0Sstevel@tonic-gate 	addr.sin_port = htons((ushort_t)handle->params.kadmind_port);
337*0Sstevel@tonic-gate 	sin = &addr;
338*0Sstevel@tonic-gate #ifdef DEBUG
339*0Sstevel@tonic-gate 	printf("kadmin_port %d\n", handle->params.kadmind_port);
340*0Sstevel@tonic-gate 	printf("addr: sin_port: %d, sin_family: %d, sin_zero %s\n",
341*0Sstevel@tonic-gate 	    addr.sin_port, addr.sin_family, addr.sin_zero);
342*0Sstevel@tonic-gate 	printf("sin_addr %d:%d\n", addr.sin_addr.S_un.S_un_w.s_w1,
343*0Sstevel@tonic-gate 	    addr.sin_addr.S_un.S_un_w.s_w2);
344*0Sstevel@tonic-gate #endif
345*0Sstevel@tonic-gate 	if ((handlep = setnetconfig()) == (void *) NULL) {
346*0Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
347*0Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
348*0Sstevel@tonic-gate 				    "cannot get any transport information"));
349*0Sstevel@tonic-gate 		goto error;
350*0Sstevel@tonic-gate 	}
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	while (nconf = getnetconfig(handlep)) {
353*0Sstevel@tonic-gate 		if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
354*0Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
355*0Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0))
356*0Sstevel@tonic-gate 			break;
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	if (nconf == (struct netconfig *)NULL)
360*0Sstevel@tonic-gate 		goto error;
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/* Transform addr to netbuf */
363*0Sstevel@tonic-gate 	(void) memset(&netaddr, 0, sizeof (netaddr));
364*0Sstevel@tonic-gate 	netaddr.buf = (char *)sin;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/* get an fd connected to the given address */
367*0Sstevel@tonic-gate 	fd =  get_connection(nconf, netaddr);
368*0Sstevel@tonic-gate 	if (fd == -1) {
369*0Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
370*0Sstevel@tonic-gate 			"unable to open connection to ADMIN server "
371*0Sstevel@tonic-gate 			"(t_error %i)"), t_errno);
372*0Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
373*0Sstevel@tonic-gate 		goto error;
374*0Sstevel@tonic-gate 	}
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate #ifdef DEBUG
377*0Sstevel@tonic-gate 	printf("fd: %d, KADM: %d, KADMVERS %d\n", fd, KADM, KADMVERS);
378*0Sstevel@tonic-gate 	printf("nconf: nc_netid: %s, nc_semantics: %d, nc_flag: %d, "
379*0Sstevel@tonic-gate 	    "nc_protofmly: %s\n",
380*0Sstevel@tonic-gate 	    nconf->nc_netid, nconf->nc_semantics, nconf->nc_flag,
381*0Sstevel@tonic-gate 	    nconf->nc_protofmly);
382*0Sstevel@tonic-gate 	printf("nc_proto: %s, nc_device: %s, nc_nlookups: %d, nc_used: %d\n",
383*0Sstevel@tonic-gate 	    nconf->nc_proto, nconf->nc_device, nconf->nc_nlookups,
384*0Sstevel@tonic-gate 	    nconf->nc_unused);
385*0Sstevel@tonic-gate 	printf("netaddr: maxlen %d, buf: %s, len: %d\n", netaddr.maxlen,
386*0Sstevel@tonic-gate 	    netaddr.buf, netaddr.len);
387*0Sstevel@tonic-gate #endif
388*0Sstevel@tonic-gate  	/*
389*0Sstevel@tonic-gate 	 * Tell clnt_tli_create that given fd is already connected
390*0Sstevel@tonic-gate 	 *
391*0Sstevel@tonic-gate 	 * If the service_name and client_name are iprop-centric,
392*0Sstevel@tonic-gate 	 * we need to clnt_tli_create to the appropriate RPC prog
393*0Sstevel@tonic-gate 	 */
394*0Sstevel@tonic-gate 	iprop_svc = strdup(KIPROP_SVC_NAME);
395*0Sstevel@tonic-gate 	if (iprop_svc == NULL)
396*0Sstevel@tonic-gate 		return (ENOMEM);
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	if ((strstr(service_name, iprop_svc) != NULL) &&
399*0Sstevel@tonic-gate 	    (strstr(client_name, iprop_svc) != NULL)) {
400*0Sstevel@tonic-gate 		iprop_enable = B_TRUE;
401*0Sstevel@tonic-gate 		handle->clnt = clnt_tli_create(fd, nconf, NULL,
402*0Sstevel@tonic-gate 				    KRB5_IPROP_PROG, KRB5_IPROP_VERS, 0, 0);
403*0Sstevel@tonic-gate 	}
404*0Sstevel@tonic-gate 	else
405*0Sstevel@tonic-gate 		handle->clnt = clnt_tli_create(fd, nconf, NULL,
406*0Sstevel@tonic-gate 				    KADM, KADMVERS, 0, 0);
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	if (iprop_svc)
409*0Sstevel@tonic-gate 		free(iprop_svc);
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	if (handle->clnt == NULL) {
412*0Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
413*0Sstevel@tonic-gate 					"clnt_tli_create failed\n"));
414*0Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
415*0Sstevel@tonic-gate 		(void) close(fd);
416*0Sstevel@tonic-gate 		goto error;
417*0Sstevel@tonic-gate 	}
418*0Sstevel@tonic-gate 	/*
419*0Sstevel@tonic-gate 	 * The rpc-handle was created on an fd opened and connected
420*0Sstevel@tonic-gate 	 * by us, so we have to explicitly tell rpc to close it.
421*0Sstevel@tonic-gate 	 */
422*0Sstevel@tonic-gate 	if (clnt_control(handle->clnt, CLSET_FD_CLOSE, NULL) != TRUE) {
423*0Sstevel@tonic-gate 		clnt_pcreateerror("ERROR:");
424*0Sstevel@tonic-gate 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
425*0Sstevel@tonic-gate 			"clnt_control failed to set CLSET_FD_CLOSE"));
426*0Sstevel@tonic-gate 		code = KADM5_RPC_ERROR;
427*0Sstevel@tonic-gate 		(void) close(fd);
428*0Sstevel@tonic-gate 		goto error;
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	handle->lhandle->clnt = handle->clnt;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	/* now that handle->clnt is set, we can check the handle */
434*0Sstevel@tonic-gate 	if (code = _kadm5_check_handle((void *) handle))
435*0Sstevel@tonic-gate 		goto error;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	/*
438*0Sstevel@tonic-gate 	 * The RPC connection is open; establish the GSS-API
439*0Sstevel@tonic-gate 	 * authentication context.
440*0Sstevel@tonic-gate 	 */
441*0Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
442*0Sstevel@tonic-gate 				    "have an rpc connection open\n"));
443*0Sstevel@tonic-gate 	/* use the kadm5 cache */
444*0Sstevel@tonic-gate 	ccname_orig = getenv("KRB5CCNAME");
445*0Sstevel@tonic-gate 	if (ccname_orig)
446*0Sstevel@tonic-gate 		ccname_orig = strdup(ccname_orig);
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	(void) krb5_setenv("KRB5CCNAME", handle->cache_name, 1);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR,
451*0Sstevel@tonic-gate 		dgettext(TEXT_DOMAIN,
452*0Sstevel@tonic-gate 			"current credential cache: %s"), handle->cache_name);
453*0Sstevel@tonic-gate 	input_name.value = client_name;
454*0Sstevel@tonic-gate 	input_name.length = strlen((char *)input_name.value) + 1;
455*0Sstevel@tonic-gate 	gssstat = gss_import_name(&minor_stat, &input_name,
456*0Sstevel@tonic-gate 				(gss_OID)gss_nt_krb5_name, &gss_client);
457*0Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
458*0Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
459*0Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR,
460*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
461*0Sstevel@tonic-gate 				"gss_import_name failed for client name\n"));
462*0Sstevel@tonic-gate 		goto error;
463*0Sstevel@tonic-gate 	}
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (!rpc_gss_mech_to_oid(mech, (rpc_gss_OID *)&mech_oid)) {
466*0Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
467*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
468*0Sstevel@tonic-gate 				"Invalid mechanism oid <%s>"), mech);
469*0Sstevel@tonic-gate 		goto error;
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	oid_set.count = 1;
473*0Sstevel@tonic-gate 	oid_set.elements = mech_oid;
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
476*0Sstevel@tonic-gate 				&oid_set, GSS_C_INITIATE,
477*0Sstevel@tonic-gate 				&gss_client_creds, NULL, NULL);
478*0Sstevel@tonic-gate 	(void) gss_release_name(&minor_stat, &gss_client);
479*0Sstevel@tonic-gate 	if (gssstat != GSS_S_COMPLETE) {
480*0Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
481*0Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
482*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
483*0Sstevel@tonic-gate 				"could not acquire credentials, "
484*0Sstevel@tonic-gate 				"major error code: %d\n"), gssstat);
485*0Sstevel@tonic-gate 		goto error;
486*0Sstevel@tonic-gate 	}
487*0Sstevel@tonic-gate 	handle->my_cred = gss_client_creds;
488*0Sstevel@tonic-gate 	options_req.my_cred = gss_client_creds;
489*0Sstevel@tonic-gate 	options_req.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
490*0Sstevel@tonic-gate 	options_req.time_req = 0;
491*0Sstevel@tonic-gate 	options_req.input_channel_bindings = NULL;
492*0Sstevel@tonic-gate #ifndef INIT_TEST
493*0Sstevel@tonic-gate 	handle->clnt->cl_auth = rpc_gss_seccreate(handle->clnt,
494*0Sstevel@tonic-gate 						service_name,
495*0Sstevel@tonic-gate 						mech,
496*0Sstevel@tonic-gate 						service,
497*0Sstevel@tonic-gate 						NULL,
498*0Sstevel@tonic-gate 						&options_req,
499*0Sstevel@tonic-gate 						&options_ret);
500*0Sstevel@tonic-gate #endif /* ! INIT_TEST */
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	if (ccname_orig) {
503*0Sstevel@tonic-gate 		(void) krb5_setenv("KRB5CCNAME", ccname_orig, 1);
504*0Sstevel@tonic-gate 		free(ccname_orig);
505*0Sstevel@tonic-gate 	} else
506*0Sstevel@tonic-gate 		(void) krb5_unsetenv("KRB5CCNAME");
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	if (handle->clnt->cl_auth == NULL) {
509*0Sstevel@tonic-gate 		code = KADM5_GSS_ERROR;
510*0Sstevel@tonic-gate 		display_status(dgettext(TEXT_DOMAIN,
511*0Sstevel@tonic-gate 					"rpc_gss_seccreate failed\n"),
512*0Sstevel@tonic-gate 			    options_ret.major_status,
513*0Sstevel@tonic-gate 			    options_ret.minor_status,
514*0Sstevel@tonic-gate 			    mech);
515*0Sstevel@tonic-gate 		goto error;
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	/*
519*0Sstevel@tonic-gate 	 * Bypass the remainder of the code and return straightaway
520*0Sstevel@tonic-gate 	 * if the gss service requested is kiprop
521*0Sstevel@tonic-gate 	 */
522*0Sstevel@tonic-gate 	if (iprop_enable == B_TRUE) {
523*0Sstevel@tonic-gate 		code = 0;
524*0Sstevel@tonic-gate 		goto cleanup;
525*0Sstevel@tonic-gate 	}
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	r = init_1(&handle->api_version, handle->clnt, &rpc_err_code);
528*0Sstevel@tonic-gate 	if (r == NULL) {
529*0Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
530*0Sstevel@tonic-gate 			"error during admin api initialization\n"));
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 		if (rpc_err_code == RPC_CANTENCODEARGS) {
533*0Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
534*0Sstevel@tonic-gate 				"encryption needed to encode RPC data may not be "
535*0Sstevel@tonic-gate 				"installed/configured on this system"));
536*0Sstevel@tonic-gate 			code = KADM5_RPC_ERROR_CANTENCODEARGS;
537*0Sstevel@tonic-gate 		} else if (rpc_err_code == RPC_CANTDECODEARGS) {
538*0Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
539*0Sstevel@tonic-gate 				"encryption needed to decode RPC data may not be "
540*0Sstevel@tonic-gate 				"installed/configured on the server"));
541*0Sstevel@tonic-gate 			code = KADM5_RPC_ERROR_CANTDECODEARGS;
542*0Sstevel@tonic-gate 		} else
543*0Sstevel@tonic-gate 			code = KADM5_RPC_ERROR;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 		goto error;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	}
548*0Sstevel@tonic-gate 	if (r->code) {
549*0Sstevel@tonic-gate 		code = r->code;
550*0Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR,
551*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN,
552*0Sstevel@tonic-gate 				"error during admin api initialization: %d\n"),
553*0Sstevel@tonic-gate 			r->code);
554*0Sstevel@tonic-gate 		goto error;
555*0Sstevel@tonic-gate 	}
556*0Sstevel@tonic-gate error:
557*0Sstevel@tonic-gate cleanup:
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	if (handlep != (void *) NULL)
560*0Sstevel@tonic-gate 		(void) endnetconfig(handlep);
561*0Sstevel@tonic-gate 	/*
562*0Sstevel@tonic-gate 	 * gss_client_creds is freed only when there is an error condition,
563*0Sstevel@tonic-gate 	 * given that rpc_gss_seccreate() will assign the cred pointer to the
564*0Sstevel@tonic-gate 	 * my_cred member in the auth handle's private data structure.
565*0Sstevel@tonic-gate 	 */
566*0Sstevel@tonic-gate 	if (code && (gss_client_creds != GSS_C_NO_CREDENTIAL))
567*0Sstevel@tonic-gate 		(void) gss_release_cred(&minor_stat, &gss_client_creds);
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	return (code);
570*0Sstevel@tonic-gate }
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate static kadm5_ret_t _kadm5_init_any(char *client_name,
573*0Sstevel@tonic-gate 				   enum init_type init_type,
574*0Sstevel@tonic-gate 				   char *pass,
575*0Sstevel@tonic-gate 				   krb5_ccache ccache_in,
576*0Sstevel@tonic-gate 				   char *service_name,
577*0Sstevel@tonic-gate 				   kadm5_config_params *params_in,
578*0Sstevel@tonic-gate 				   krb5_ui_4 struct_version,
579*0Sstevel@tonic-gate 				   krb5_ui_4 api_version,
580*0Sstevel@tonic-gate 				   void **server_handle)
581*0Sstevel@tonic-gate {
582*0Sstevel@tonic-gate 	int i;
583*0Sstevel@tonic-gate 	krb5_creds	creds;
584*0Sstevel@tonic-gate 	krb5_ccache ccache = NULL;
585*0Sstevel@tonic-gate 	krb5_timestamp  now;
586*0Sstevel@tonic-gate 	OM_uint32 gssstat, minor_stat;
587*0Sstevel@tonic-gate 	kadm5_server_handle_t handle;
588*0Sstevel@tonic-gate 	kadm5_config_params params_local;
589*0Sstevel@tonic-gate 	int code = 0;
590*0Sstevel@tonic-gate 	krb5_get_init_creds_opt opt;
591*0Sstevel@tonic-gate 	gss_buffer_desc input_name;
592*0Sstevel@tonic-gate 	krb5_error_code kret;
593*0Sstevel@tonic-gate 	krb5_int32 starttime;
594*0Sstevel@tonic-gate 	char *server = NULL;
595*0Sstevel@tonic-gate 	krb5_principal serverp = NULL, clientp = NULL;
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
598*0Sstevel@tonic-gate 		"entering kadm5_init_any\n"));
599*0Sstevel@tonic-gate 	if (! server_handle) {
600*0Sstevel@tonic-gate 		return (EINVAL);
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	if (! (handle = malloc(sizeof(*handle)))) {
604*0Sstevel@tonic-gate 		return (ENOMEM);
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 	if (! (handle->lhandle = malloc(sizeof(*handle)))) {
607*0Sstevel@tonic-gate 		free(handle);
608*0Sstevel@tonic-gate 		return (ENOMEM);
609*0Sstevel@tonic-gate 	}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
612*0Sstevel@tonic-gate 	handle->struct_version = struct_version;
613*0Sstevel@tonic-gate 	handle->api_version = api_version;
614*0Sstevel@tonic-gate 	handle->clnt = 0;
615*0Sstevel@tonic-gate 	handle->cache_name = 0;
616*0Sstevel@tonic-gate 	handle->destroy_cache = 0;
617*0Sstevel@tonic-gate 	*handle->lhandle = *handle;
618*0Sstevel@tonic-gate 	handle->lhandle->api_version = KADM5_API_VERSION_2;
619*0Sstevel@tonic-gate 	handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
620*0Sstevel@tonic-gate 	handle->lhandle->lhandle = handle->lhandle;
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	kret = krb5_init_context(&handle->context);
623*0Sstevel@tonic-gate 	if (kret) {
624*0Sstevel@tonic-gate 		free(handle->lhandle);
625*0Sstevel@tonic-gate 		free(handle);
626*0Sstevel@tonic-gate 		return (kret);
627*0Sstevel@tonic-gate 	}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	if(service_name == NULL || client_name == NULL) {
630*0Sstevel@tonic-gate 		krb5_free_context(handle->context);
631*0Sstevel@tonic-gate 		free(handle->lhandle);
632*0Sstevel@tonic-gate 		free(handle);
633*0Sstevel@tonic-gate 		return (EINVAL);
634*0Sstevel@tonic-gate 	}
635*0Sstevel@tonic-gate 	memset((char *) &creds, 0, sizeof(creds));
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	/*
638*0Sstevel@tonic-gate 	 * Verify the version numbers before proceeding; we can't use
639*0Sstevel@tonic-gate 	 * CHECK_HANDLE because not all fields are set yet.
640*0Sstevel@tonic-gate 	 */
641*0Sstevel@tonic-gate 	GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
642*0Sstevel@tonic-gate 			  KADM5_NEW_LIB_API_VERSION);
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	/*
645*0Sstevel@tonic-gate 	 * Acquire relevant profile entries.  In version 2, merge values
646*0Sstevel@tonic-gate 	 * in params_in with values from profile, based on
647*0Sstevel@tonic-gate 	 * params_in->mask.
648*0Sstevel@tonic-gate 	 *
649*0Sstevel@tonic-gate 	 * In version 1, we've given a realm (which may be NULL) instead
650*0Sstevel@tonic-gate 	 * of params_in.  So use that realm, make params_in contain an
651*0Sstevel@tonic-gate 	 * empty mask, and behave like version 2.
652*0Sstevel@tonic-gate 	 */
653*0Sstevel@tonic-gate 	memset((char *) &params_local, 0, sizeof(params_local));
654*0Sstevel@tonic-gate 	if (api_version == KADM5_API_VERSION_1) {
655*0Sstevel@tonic-gate 		if (params_in)
656*0Sstevel@tonic-gate 			params_local.mask = KADM5_CONFIG_REALM;
657*0Sstevel@tonic-gate 		params_in = &params_local;
658*0Sstevel@tonic-gate 	}
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate #define ILLEGAL_PARAMS ( \
661*0Sstevel@tonic-gate 	KADM5_CONFIG_ACL_FILE	| KADM5_CONFIG_ADB_LOCKFILE | \
662*0Sstevel@tonic-gate 	KADM5_CONFIG_DBNAME	| KADM5_CONFIG_ADBNAME | \
663*0Sstevel@tonic-gate 	KADM5_CONFIG_DICT_FILE	| KADM5_CONFIG_ADMIN_KEYTAB | \
664*0Sstevel@tonic-gate 	KADM5_CONFIG_STASH_FILE | KADM5_CONFIG_MKEY_NAME | \
665*0Sstevel@tonic-gate 	KADM5_CONFIG_ENCTYPE	| KADM5_CONFIG_MAX_LIFE	| \
666*0Sstevel@tonic-gate 	KADM5_CONFIG_MAX_RLIFE	| KADM5_CONFIG_EXPIRATION | \
667*0Sstevel@tonic-gate 	KADM5_CONFIG_FLAGS	| KADM5_CONFIG_ENCTYPES	| \
668*0Sstevel@tonic-gate 	KADM5_CONFIG_MKEY_FROM_KBD)
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	if (params_in && params_in->mask & ILLEGAL_PARAMS) {
671*0Sstevel@tonic-gate 		krb5_free_context(handle->context);
672*0Sstevel@tonic-gate 		free(handle->lhandle);
673*0Sstevel@tonic-gate 		free(handle);
674*0Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
675*0Sstevel@tonic-gate 			"bad client parameters, returning %d"),
676*0Sstevel@tonic-gate 			KADM5_BAD_CLIENT_PARAMS);
677*0Sstevel@tonic-gate 		return (KADM5_BAD_CLIENT_PARAMS);
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 	if ((code = kadm5_get_config_params(handle->context,
681*0Sstevel@tonic-gate 					DEFAULT_PROFILE_PATH,
682*0Sstevel@tonic-gate 					"KRB5_CONFIG",
683*0Sstevel@tonic-gate 					params_in,
684*0Sstevel@tonic-gate 					&handle->params))) {
685*0Sstevel@tonic-gate 		krb5_free_context(handle->context);
686*0Sstevel@tonic-gate 		free(handle->lhandle);
687*0Sstevel@tonic-gate 		free(handle);
688*0Sstevel@tonic-gate 		ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
689*0Sstevel@tonic-gate 			"failed to get config_params, return: %d\n"), code);
690*0Sstevel@tonic-gate 		return(code);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
694*0Sstevel@tonic-gate 			 KADM5_CONFIG_ADMIN_SERVER | \
695*0Sstevel@tonic-gate 			 KADM5_CONFIG_KADMIND_PORT)
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
698*0Sstevel@tonic-gate 		(void) kadm5_free_config_params(handle->context,
699*0Sstevel@tonic-gate 						&handle->params);
700*0Sstevel@tonic-gate 		krb5_free_context(handle->context);
701*0Sstevel@tonic-gate 		free(handle->lhandle);
702*0Sstevel@tonic-gate 		free(handle);
703*0Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
704*0Sstevel@tonic-gate 			"missing config parameters\n"));
705*0Sstevel@tonic-gate 		return (KADM5_MISSING_CONF_PARAMS);
706*0Sstevel@tonic-gate 	}
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	/*
709*0Sstevel@tonic-gate 	 * Acquire a service ticket for service_name@realm in the name of
710*0Sstevel@tonic-gate 	 * client_name, using password pass (which could be NULL), and
711*0Sstevel@tonic-gate 	 * create a ccache to store them in.  If INIT_CREDS, use the
712*0Sstevel@tonic-gate 	 * ccache we were provided instead.
713*0Sstevel@tonic-gate 	 */
714*0Sstevel@tonic-gate 	if ((code = krb5_parse_name(handle->context, client_name,
715*0Sstevel@tonic-gate 			    &creds.client))) {
716*0Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
717*0Sstevel@tonic-gate 			    "could not parse client name\n"));
718*0Sstevel@tonic-gate 		goto error;
719*0Sstevel@tonic-gate 	}
720*0Sstevel@tonic-gate 	clientp = creds.client;
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	if (init_type == INIT_PASS &&
723*0Sstevel@tonic-gate 	    handle->params.kpasswd_protocol == KRB5_CHGPWD_CHANGEPW_V2) {
724*0Sstevel@tonic-gate 		/*
725*0Sstevel@tonic-gate 		 * The 'service_name' is constructed by the caller
726*0Sstevel@tonic-gate 		 * but its done before the parameter which determines
727*0Sstevel@tonic-gate 		 * the kpasswd_protocol is found.  The servers that
728*0Sstevel@tonic-gate 		 * support the SET/CHANGE password protocol expect
729*0Sstevel@tonic-gate 		 * a slightly different service principal than
730*0Sstevel@tonic-gate 		 * the normal SEAM kadmind so construct the correct
731*0Sstevel@tonic-gate 		 * name here and then forget it.
732*0Sstevel@tonic-gate 		 */
733*0Sstevel@tonic-gate 		char *newsvcname = NULL;
734*0Sstevel@tonic-gate 		newsvcname = malloc(strlen(KADM5_CHANGEPW_SERVICE) +
735*0Sstevel@tonic-gate 				    strlen(handle->params.realm) + 2);
736*0Sstevel@tonic-gate 		if (newsvcname == NULL) {
737*0Sstevel@tonic-gate 			return (ENOMEM);
738*0Sstevel@tonic-gate 		}
739*0Sstevel@tonic-gate 		sprintf(newsvcname, "%s@%s", KADM5_CHANGEPW_SERVICE,
740*0Sstevel@tonic-gate 			handle->params.realm);
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 		if ((code = krb5_parse_name(handle->context, newsvcname,
743*0Sstevel@tonic-gate 					    &creds.server))) {
744*0Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
745*0Sstevel@tonic-gate 					    "could not parse server "
746*0Sstevel@tonic-gate 					    "name\n"));
747*0Sstevel@tonic-gate 			free(newsvcname);
748*0Sstevel@tonic-gate 			goto error;
749*0Sstevel@tonic-gate 		}
750*0Sstevel@tonic-gate 		free(newsvcname);
751*0Sstevel@tonic-gate 	} else {
752*0Sstevel@tonic-gate 		input_name.value = service_name;
753*0Sstevel@tonic-gate 		input_name.length = strlen((char *)input_name.value) + 1;
754*0Sstevel@tonic-gate 		gssstat = krb5_gss_import_name(handle->context,
755*0Sstevel@tonic-gate 				    &minor_stat,
756*0Sstevel@tonic-gate 				    &input_name,
757*0Sstevel@tonic-gate 				    (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
758*0Sstevel@tonic-gate 				    (gss_name_t *)&creds.server);
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 		if (gssstat != GSS_S_COMPLETE) {
761*0Sstevel@tonic-gate 			code = KADM5_GSS_ERROR;
762*0Sstevel@tonic-gate 			ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
763*0Sstevel@tonic-gate 				"gss_import_name failed for client name\n"));
764*0Sstevel@tonic-gate 			goto error;
765*0Sstevel@tonic-gate 		}
766*0Sstevel@tonic-gate 	}
767*0Sstevel@tonic-gate 	serverp = creds.server;
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 	/* XXX temporarily fix a bug in krb5_cc_get_type */
770*0Sstevel@tonic-gate #undef krb5_cc_get_type
771*0Sstevel@tonic-gate #define krb5_cc_get_type(context, cache) ((cache)->ops->prefix)
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	if (init_type == INIT_CREDS) {
774*0Sstevel@tonic-gate 		ccache = ccache_in;
775*0Sstevel@tonic-gate 		handle->cache_name = (char *)
776*0Sstevel@tonic-gate 			malloc(strlen(krb5_cc_get_type(handle->context, ccache)) +
777*0Sstevel@tonic-gate 		    	strlen(krb5_cc_get_name(handle->context, ccache)) + 2);
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 		if (handle->cache_name == NULL) {
780*0Sstevel@tonic-gate 			code = ENOMEM;
781*0Sstevel@tonic-gate 			goto error;
782*0Sstevel@tonic-gate 		}
783*0Sstevel@tonic-gate 		sprintf(handle->cache_name, "%s:%s",
784*0Sstevel@tonic-gate 			krb5_cc_get_type(handle->context, ccache),
785*0Sstevel@tonic-gate 			krb5_cc_get_name(handle->context, ccache));
786*0Sstevel@tonic-gate 	} else {
787*0Sstevel@tonic-gate 		handle->cache_name =
788*0Sstevel@tonic-gate 			(char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1);
789*0Sstevel@tonic-gate 		if (handle->cache_name == NULL) {
790*0Sstevel@tonic-gate 			code = ENOMEM;
791*0Sstevel@tonic-gate 			goto error;
792*0Sstevel@tonic-gate 		}
793*0Sstevel@tonic-gate 		sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE);
794*0Sstevel@tonic-gate 		mktemp(handle->cache_name + strlen("FILE:"));
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 		if ((code = krb5_cc_resolve(handle->context,
797*0Sstevel@tonic-gate 			handle->cache_name, &ccache)))
798*0Sstevel@tonic-gate 			goto error;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 		if ((code = krb5_cc_initialize (handle->context, ccache,
801*0Sstevel@tonic-gate 					  creds.client)))
802*0Sstevel@tonic-gate 			goto error;
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 		handle->destroy_cache = 1;
805*0Sstevel@tonic-gate 	}
806*0Sstevel@tonic-gate 	handle->lhandle->cache_name = handle->cache_name;
807*0Sstevel@tonic-gate 	ADMIN_LOG(LOG_ERR, dgettext(TEXT_DOMAIN,
808*0Sstevel@tonic-gate 		"cache created: %s\n"), handle->cache_name);
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	if ((code = krb5_timeofday(handle->context, &now)))
811*0Sstevel@tonic-gate 		goto error;
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 	/*
814*0Sstevel@tonic-gate 	 * Get a ticket, use the method specified in init_type.
815*0Sstevel@tonic-gate 	 */
816*0Sstevel@tonic-gate 	creds.times.starttime = 0; /* start timer at KDC */
817*0Sstevel@tonic-gate 	creds.times.endtime = 0; /* endtime will be limited by service */
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 	memset(&opt, 0, sizeof (opt));
820*0Sstevel@tonic-gate 	krb5_get_init_creds_opt_init(&opt);
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 	if (creds.times.endtime) {
823*0Sstevel@tonic-gate 		if (creds.times.starttime)
824*0Sstevel@tonic-gate 			starttime = creds.times.starttime;
825*0Sstevel@tonic-gate 		else
826*0Sstevel@tonic-gate 			starttime = now;
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 		krb5_get_init_creds_opt_set_tkt_life(&opt,
829*0Sstevel@tonic-gate 			creds.times.endtime - starttime);
830*0Sstevel@tonic-gate 	}
831*0Sstevel@tonic-gate 	code = krb5_unparse_name(handle->context, creds.server, &server);
832*0Sstevel@tonic-gate 	if (code)
833*0Sstevel@tonic-gate 		goto error;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	if (init_type == INIT_PASS) {
836*0Sstevel@tonic-gate 		code = krb5_get_init_creds_password(handle->context,
837*0Sstevel@tonic-gate 			&creds, creds.client, pass, NULL,
838*0Sstevel@tonic-gate 			NULL, creds.times.starttime,
839*0Sstevel@tonic-gate 			server, &opt);
840*0Sstevel@tonic-gate 	} else if (init_type == INIT_SKEY) {
841*0Sstevel@tonic-gate 		krb5_keytab kt = NULL;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 		if (!(pass && (code = krb5_kt_resolve(handle->context,
844*0Sstevel@tonic-gate 					pass, &kt)))) {
845*0Sstevel@tonic-gate 			code = krb5_get_init_creds_keytab(
846*0Sstevel@tonic-gate 					handle->context,
847*0Sstevel@tonic-gate 					&creds, creds.client, kt,
848*0Sstevel@tonic-gate 					creds.times.starttime,
849*0Sstevel@tonic-gate 					server, &opt);
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate 			if (pass)
852*0Sstevel@tonic-gate 				krb5_kt_close(handle->context, kt);
853*0Sstevel@tonic-gate 		}
854*0Sstevel@tonic-gate 	}
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	/* Improved error messages */
857*0Sstevel@tonic-gate 	if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
858*0Sstevel@tonic-gate 		code = KADM5_BAD_PASSWORD;
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
861*0Sstevel@tonic-gate 		code = KADM5_SECURE_PRINC_MISSING;
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 	if (code != 0) {
864*0Sstevel@tonic-gate 		ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN,
865*0Sstevel@tonic-gate 			"failed to obtain credentials cache\n"));
866*0Sstevel@tonic-gate 		goto error;
867*0Sstevel@tonic-gate 	}
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 	/*
870*0Sstevel@tonic-gate 	 * If we got this far, save the creds in the cache.
871*0Sstevel@tonic-gate 	 */
872*0Sstevel@tonic-gate 	if (ccache) {
873*0Sstevel@tonic-gate 		code = krb5_cc_store_cred(handle->context, ccache, &creds);
874*0Sstevel@tonic-gate 	}
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 	ADMIN_LOGO(LOG_ERR, dgettext(TEXT_DOMAIN, "obtained credentials cache\n"));
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate #ifdef ZEROPASSWD
879*0Sstevel@tonic-gate 	if (pass != NULL)
880*0Sstevel@tonic-gate 		memset(pass, 0, strlen(pass));
881*0Sstevel@tonic-gate #endif
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	if (init_type != INIT_PASS ||
884*0Sstevel@tonic-gate 	    handle->params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC) {
885*0Sstevel@tonic-gate 		code = _kadm5_initialize_rpcsec_gss_handle(handle,
886*0Sstevel@tonic-gate 					client_name, service_name);
887*0Sstevel@tonic-gate 		if (code != 0)
888*0Sstevel@tonic-gate 			goto error;
889*0Sstevel@tonic-gate 	}
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	*server_handle = (void *) handle;
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	if (init_type != INIT_CREDS)
894*0Sstevel@tonic-gate 		krb5_cc_close(handle->context, ccache);
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	goto cleanup;
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate error:
899*0Sstevel@tonic-gate 	/*
900*0Sstevel@tonic-gate 	* Note that it is illegal for this code to execute if "handle"
901*0Sstevel@tonic-gate 	* has not been allocated and initialized.  I.e., don't use "goto
902*0Sstevel@tonic-gate 	* error" before the block of code at the top of the function
903*0Sstevel@tonic-gate 	* that allocates and initializes "handle".
904*0Sstevel@tonic-gate 	*/
905*0Sstevel@tonic-gate 	if (handle->cache_name)
906*0Sstevel@tonic-gate 	 free(handle->cache_name);
907*0Sstevel@tonic-gate 	if (handle->destroy_cache && ccache)
908*0Sstevel@tonic-gate 	 krb5_cc_destroy(handle->context, ccache);
909*0Sstevel@tonic-gate 	if(handle->clnt && handle->clnt->cl_auth)
910*0Sstevel@tonic-gate 	  AUTH_DESTROY(handle->clnt->cl_auth);
911*0Sstevel@tonic-gate 	if(handle->clnt)
912*0Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
913*0Sstevel@tonic-gate 	(void) kadm5_free_config_params(handle->context, &handle->params);
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate cleanup:
916*0Sstevel@tonic-gate 	if (server)
917*0Sstevel@tonic-gate 		free(server);
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	/*
920*0Sstevel@tonic-gate 	 * Creds server and client members may actually be different
921*0Sstevel@tonic-gate 	 * from when initially passed into the get_init_* functions.
922*0Sstevel@tonic-gate 	 * So we must free the members we allocated above since get_init
923*0Sstevel@tonic-gate 	 * zeros the members out, without freeing first.
924*0Sstevel@tonic-gate 	 */
925*0Sstevel@tonic-gate 	if (clientp != NULL) {
926*0Sstevel@tonic-gate 		krb5_free_principal(handle->context, clientp);
927*0Sstevel@tonic-gate 		clientp = NULL;
928*0Sstevel@tonic-gate 	}
929*0Sstevel@tonic-gate 	if (serverp != NULL) {
930*0Sstevel@tonic-gate 		krb5_free_principal(handle->context, serverp);
931*0Sstevel@tonic-gate 		serverp = NULL;
932*0Sstevel@tonic-gate 	}
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	krb5_free_cred_contents(handle->context, &creds);
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 	/*
937*0Sstevel@tonic-gate 	 * Dont clean up the handle if the code is OK (code==0)
938*0Sstevel@tonic-gate 	 * because it is returned to the caller in the 'server_handle'
939*0Sstevel@tonic-gate 	 * ptr.
940*0Sstevel@tonic-gate 	 */
941*0Sstevel@tonic-gate 	if (code) {
942*0Sstevel@tonic-gate 		krb5_free_context(handle->context);
943*0Sstevel@tonic-gate 		free(handle->lhandle);
944*0Sstevel@tonic-gate 	  free(handle);
945*0Sstevel@tonic-gate 	}
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 	return (code);
948*0Sstevel@tonic-gate }
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate kadm5_ret_t
951*0Sstevel@tonic-gate kadm5_destroy(void *server_handle)
952*0Sstevel@tonic-gate {
953*0Sstevel@tonic-gate 	krb5_ccache	    ccache = NULL;
954*0Sstevel@tonic-gate 	int		    code = KADM5_OK;
955*0Sstevel@tonic-gate 	kadm5_server_handle_t	handle =
956*0Sstevel@tonic-gate 	  (kadm5_server_handle_t) server_handle;
957*0Sstevel@tonic-gate 	OM_uint32 min_stat;
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	CHECK_HANDLE(server_handle);
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 	if (handle->destroy_cache && handle->cache_name) {
962*0Sstevel@tonic-gate 	 if ((code = krb5_cc_resolve(handle->context,
963*0Sstevel@tonic-gate 				     handle->cache_name, &ccache)) == 0)
964*0Sstevel@tonic-gate 	     code = krb5_cc_destroy (handle->context, ccache);
965*0Sstevel@tonic-gate 	}
966*0Sstevel@tonic-gate 	if (handle->cache_name)
967*0Sstevel@tonic-gate 	 free(handle->cache_name);
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	if (handle->clnt && handle->clnt->cl_auth) {
970*0Sstevel@tonic-gate 		/*
971*0Sstevel@tonic-gate 		 * Since kadm5 doesn't use the default credentials we
972*0Sstevel@tonic-gate 		 * must clean this up manually.
973*0Sstevel@tonic-gate 		 */
974*0Sstevel@tonic-gate 		if (handle->my_cred != GSS_C_NO_CREDENTIAL)
975*0Sstevel@tonic-gate 			(void) gss_release_cred(&min_stat, &handle->my_cred);
976*0Sstevel@tonic-gate 		AUTH_DESTROY(handle->clnt->cl_auth);
977*0Sstevel@tonic-gate 	}
978*0Sstevel@tonic-gate 	if (handle->clnt)
979*0Sstevel@tonic-gate 	  clnt_destroy(handle->clnt);
980*0Sstevel@tonic-gate 	if (handle->lhandle)
981*0Sstevel@tonic-gate 	    free (handle->lhandle);
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 	kadm5_free_config_params(handle->context, &handle->params);
984*0Sstevel@tonic-gate 	krb5_free_context(handle->context);
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 	handle->magic_number = 0;
987*0Sstevel@tonic-gate 	free(handle);
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	return (code);
990*0Sstevel@tonic-gate }
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate /*ARGSUSED*/
993*0Sstevel@tonic-gate kadm5_ret_t
994*0Sstevel@tonic-gate kadm5_flush(void *server_handle)
995*0Sstevel@tonic-gate {
996*0Sstevel@tonic-gate 	return (KADM5_OK);
997*0Sstevel@tonic-gate }
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate int
1000*0Sstevel@tonic-gate _kadm5_check_handle(void *handle)
1001*0Sstevel@tonic-gate {
1002*0Sstevel@tonic-gate 	CHECK_HANDLE(handle);
1003*0Sstevel@tonic-gate 	return (0);
1004*0Sstevel@tonic-gate }
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate /*
1007*0Sstevel@tonic-gate  * Stub function for kadmin.  It was created to eliminate the dependency on
1008*0Sstevel@tonic-gate  * libkdb's ulog functions.  The srv equivalent makes the actual calls.
1009*0Sstevel@tonic-gate  */
1010*0Sstevel@tonic-gate krb5_error_code
1011*0Sstevel@tonic-gate kadm5_init_iprop(void *handle)
1012*0Sstevel@tonic-gate {
1013*0Sstevel@tonic-gate 	return (0);
1014*0Sstevel@tonic-gate }
1015