xref: /illumos-gate/usr/src/lib/libidmap/common/utils.c (revision 6a634c9d)
1c5c4113dSnw /*
2c5c4113dSnw  * CDDL HEADER START
3c5c4113dSnw  *
4c5c4113dSnw  * The contents of this file are subject to the terms of the
5c5c4113dSnw  * Common Development and Distribution License (the "License").
6c5c4113dSnw  * You may not use this file except in compliance with the License.
7c5c4113dSnw  *
8c5c4113dSnw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c5c4113dSnw  * or http://www.opensolaris.org/os/licensing.
10c5c4113dSnw  * See the License for the specific language governing permissions
11c5c4113dSnw  * and limitations under the License.
12c5c4113dSnw  *
13c5c4113dSnw  * When distributing Covered Code, include this CDDL HEADER in each
14c5c4113dSnw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c5c4113dSnw  * If applicable, add the following below this CDDL HEADER, with the
16c5c4113dSnw  * fields enclosed by brackets "[]" replaced with your own identifying
17c5c4113dSnw  * information: Portions Copyright [yyyy] [name of copyright owner]
18c5c4113dSnw  *
19c5c4113dSnw  * CDDL HEADER END
20c5c4113dSnw  */
21c5c4113dSnw /*
22*1fdeec65Sjoyce mcintosh  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23c5c4113dSnw  */
24c5c4113dSnw 
25c5c4113dSnw /*
26c5c4113dSnw  * Utility routines
27c5c4113dSnw  */
28c5c4113dSnw 
29c5c4113dSnw #include <stdio.h>
30c5c4113dSnw #include <stdlib.h>
31c5c4113dSnw #include <errno.h>
32c5c4113dSnw #include <libintl.h>
33*1fdeec65Sjoyce mcintosh #include <assert.h>
34*1fdeec65Sjoyce mcintosh #include <ucontext.h>
35*1fdeec65Sjoyce mcintosh #include <pthread.h>
36c5c4113dSnw #include "idmap_impl.h"
37c5c4113dSnw 
38c5c4113dSnw #define	_UDT_SIZE_INCR	1
39c5c4113dSnw 
40c5c4113dSnw #define	_GET_IDS_SIZE_INCR	1
41c5c4113dSnw 
42c5c4113dSnw static struct timeval TIMEOUT = { 25, 0 };
43c5c4113dSnw 
44*1fdeec65Sjoyce mcintosh struct idmap_handle {
45*1fdeec65Sjoyce mcintosh 	CLIENT		*client;
46*1fdeec65Sjoyce mcintosh 	boolean_t	failed;
47*1fdeec65Sjoyce mcintosh 	rwlock_t	lock;
48*1fdeec65Sjoyce mcintosh };
49*1fdeec65Sjoyce mcintosh 
50*1fdeec65Sjoyce mcintosh static struct idmap_handle idmap_handle = {
51*1fdeec65Sjoyce mcintosh 	NULL,		/* client */
52*1fdeec65Sjoyce mcintosh 	B_TRUE,		/* failed */
53*1fdeec65Sjoyce mcintosh 	DEFAULTRWLOCK,	/* lock */
54*1fdeec65Sjoyce mcintosh };
55*1fdeec65Sjoyce mcintosh 
56*1fdeec65Sjoyce mcintosh static idmap_stat _idmap_clnt_connect(void);
57*1fdeec65Sjoyce mcintosh static void _idmap_clnt_disconnect(void);
58*1fdeec65Sjoyce mcintosh 
59c5c4113dSnw idmap_retcode
_udt_extend_batch(idmap_udt_handle_t * udthandle)604edd44c5Sjp _udt_extend_batch(idmap_udt_handle_t *udthandle)
614edd44c5Sjp {
62c5c4113dSnw 	idmap_update_op	*tmplist;
63c5c4113dSnw 	size_t		nsize;
64c5c4113dSnw 
65c5c4113dSnw 	if (udthandle->next >= udthandle->batch.idmap_update_batch_len) {
66c5c4113dSnw 		nsize = (udthandle->batch.idmap_update_batch_len +
674edd44c5Sjp 		    _UDT_SIZE_INCR) * sizeof (*tmplist);
68c5c4113dSnw 		tmplist = realloc(
694edd44c5Sjp 		    udthandle->batch.idmap_update_batch_val, nsize);
70c5c4113dSnw 		if (tmplist == NULL)
71c5c4113dSnw 			return (IDMAP_ERR_MEMORY);
72c5c4113dSnw 		(void) memset((uchar_t *)tmplist +
734edd44c5Sjp 		    (udthandle->batch.idmap_update_batch_len *
744edd44c5Sjp 		    sizeof (*tmplist)), 0,
754edd44c5Sjp 		    _UDT_SIZE_INCR * sizeof (*tmplist));
76c5c4113dSnw 		udthandle->batch.idmap_update_batch_val = tmplist;
77c5c4113dSnw 		udthandle->batch.idmap_update_batch_len += _UDT_SIZE_INCR;
78c5c4113dSnw 	}
79c5c4113dSnw 	udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
804edd44c5Sjp 	    OP_NONE;
81c5c4113dSnw 	return (IDMAP_SUCCESS);
82c5c4113dSnw }
83c5c4113dSnw 
84c5c4113dSnw idmap_retcode
_get_ids_extend_batch(idmap_get_handle_t * gh)854edd44c5Sjp _get_ids_extend_batch(idmap_get_handle_t *gh)
864edd44c5Sjp {
87c5c4113dSnw 	idmap_mapping	*t1;
88c5c4113dSnw 	idmap_get_res_t	*t2;
89c5c4113dSnw 	size_t		nsize, len;
90c5c4113dSnw 
91c5c4113dSnw 	len = gh->batch.idmap_mapping_batch_len;
92c5c4113dSnw 	if (gh->next >= len) {
93c5c4113dSnw 		/* extend the request array */
94c5c4113dSnw 		nsize = (len + _GET_IDS_SIZE_INCR) * sizeof (*t1);
95c5c4113dSnw 		t1 = realloc(gh->batch.idmap_mapping_batch_val, nsize);
96c5c4113dSnw 		if (t1 == NULL)
97c5c4113dSnw 			return (IDMAP_ERR_MEMORY);
98c5c4113dSnw 		(void) memset((uchar_t *)t1 + (len * sizeof (*t1)), 0,
994edd44c5Sjp 		    _GET_IDS_SIZE_INCR * sizeof (*t1));
100c5c4113dSnw 		gh->batch.idmap_mapping_batch_val = t1;
101c5c4113dSnw 
102c5c4113dSnw 		/* extend the return list */
103c5c4113dSnw 		nsize = (len + _GET_IDS_SIZE_INCR) * sizeof (*t2);
104c5c4113dSnw 		t2 = realloc(gh->retlist, nsize);
105c5c4113dSnw 		if (t2 == NULL)
106c5c4113dSnw 			return (IDMAP_ERR_MEMORY);
107c5c4113dSnw 		(void) memset((uchar_t *)t2 + (len * sizeof (*t2)), 0,
1084edd44c5Sjp 		    _GET_IDS_SIZE_INCR * sizeof (*t2));
109c5c4113dSnw 		gh->retlist = t2;
110c5c4113dSnw 
111c5c4113dSnw 		gh->batch.idmap_mapping_batch_len += _GET_IDS_SIZE_INCR;
112c5c4113dSnw 	}
113c5c4113dSnw 	return (IDMAP_SUCCESS);
114c5c4113dSnw }
115c5c4113dSnw 
116c5c4113dSnw idmap_stat
_iter_get_next_list(int type,idmap_iter_t * iter,void * arg,uchar_t ** list,size_t valsize,xdrproc_t xdr_arg_proc,xdrproc_t xdr_res_proc)117c5c4113dSnw _iter_get_next_list(int type, idmap_iter_t *iter,
118c5c4113dSnw 		void *arg, uchar_t **list, size_t valsize,
1194edd44c5Sjp 		xdrproc_t xdr_arg_proc, xdrproc_t xdr_res_proc)
1204edd44c5Sjp {
121*1fdeec65Sjoyce mcintosh 	idmap_stat rc;
122c5c4113dSnw 
123c5c4113dSnw 	iter->next = 0;
124c5c4113dSnw 	iter->retlist = NULL;
125c5c4113dSnw 
126c5c4113dSnw 	/* init the result */
127c5c4113dSnw 	if (*list) {
128c5c4113dSnw 		xdr_free(xdr_res_proc, (caddr_t)*list);
129c5c4113dSnw 	} else {
130c5c4113dSnw 		if ((*list = malloc(valsize)) == NULL) {
131c5c4113dSnw 			errno = ENOMEM;
132c5c4113dSnw 			return (IDMAP_ERR_MEMORY);
133c5c4113dSnw 		}
134c5c4113dSnw 	}
135c5c4113dSnw 	(void) memset(*list, 0, valsize);
136c5c4113dSnw 
137*1fdeec65Sjoyce mcintosh 	rc = _idmap_clnt_call(type,
1384edd44c5Sjp 	    xdr_arg_proc, (caddr_t)arg,
1394edd44c5Sjp 	    xdr_res_proc, (caddr_t)*list,
1404edd44c5Sjp 	    TIMEOUT);
141*1fdeec65Sjoyce mcintosh 	if (rc != IDMAP_SUCCESS) {
142c5c4113dSnw 		free(*list);
143*1fdeec65Sjoyce mcintosh 		return (rc);
144c5c4113dSnw 	}
145c5c4113dSnw 	iter->retlist = *list;
146c5c4113dSnw 	return (IDMAP_SUCCESS);
147c5c4113dSnw }
148651c0131Sbaban 
149*1fdeec65Sjoyce mcintosh /*
150*1fdeec65Sjoyce mcintosh  * Convert the return values from an RPC request into an idmap return code.
151*1fdeec65Sjoyce mcintosh  * Set errno on error.
152*1fdeec65Sjoyce mcintosh  */
153*1fdeec65Sjoyce mcintosh static
154651c0131Sbaban idmap_stat
_idmap_rpc2stat(enum clnt_stat clntstat,CLIENT * clnt)155*1fdeec65Sjoyce mcintosh _idmap_rpc2stat(enum clnt_stat clntstat, CLIENT *clnt)
1564edd44c5Sjp {
157651c0131Sbaban 	/*
158651c0131Sbaban 	 * We only deal with door_call(3C) errors here. We look at
159651c0131Sbaban 	 * r_err.re_errno instead of r_err.re_status because we need
160651c0131Sbaban 	 * to differentiate between RPC failures caused by bad door fd
161651c0131Sbaban 	 * and others.
162651c0131Sbaban 	 */
163651c0131Sbaban 	struct rpc_err r_err;
164*1fdeec65Sjoyce mcintosh 
165*1fdeec65Sjoyce mcintosh 	if (clntstat == RPC_SUCCESS)
166*1fdeec65Sjoyce mcintosh 		return (IDMAP_SUCCESS);
167*1fdeec65Sjoyce mcintosh 
168*1fdeec65Sjoyce mcintosh 	clnt_geterr(clnt, &r_err);
169*1fdeec65Sjoyce mcintosh 	errno = r_err.re_errno;
170*1fdeec65Sjoyce mcintosh 	switch (r_err.re_errno) {
171*1fdeec65Sjoyce mcintosh 	case ENOMEM:
172*1fdeec65Sjoyce mcintosh 		return (IDMAP_ERR_MEMORY);
173*1fdeec65Sjoyce mcintosh 	case EBADF:
174*1fdeec65Sjoyce mcintosh 		return (IDMAP_ERR_RPC_HANDLE);
175*1fdeec65Sjoyce mcintosh 	default:
176*1fdeec65Sjoyce mcintosh 		return (IDMAP_ERR_RPC);
177*1fdeec65Sjoyce mcintosh 	}
178*1fdeec65Sjoyce mcintosh }
179*1fdeec65Sjoyce mcintosh 
180*1fdeec65Sjoyce mcintosh /*
181*1fdeec65Sjoyce mcintosh  * Management of the connection to idmapd.
182*1fdeec65Sjoyce mcintosh  *
183*1fdeec65Sjoyce mcintosh  * The intent is that connections to idmapd are automatically maintained,
184*1fdeec65Sjoyce mcintosh  * reconnecting if necessary.  No attempt is made to retry connnection
185*1fdeec65Sjoyce mcintosh  * attempts; a failure to connect yields an immediate error return.
186*1fdeec65Sjoyce mcintosh  *
187*1fdeec65Sjoyce mcintosh  * State of the connection is maintained through the "client" and "failed"
188*1fdeec65Sjoyce mcintosh  * elements of the handle structure:
189*1fdeec65Sjoyce mcintosh  *
190*1fdeec65Sjoyce mcintosh  * client   failed
191*1fdeec65Sjoyce mcintosh  * NULL     true     Failed on a previous request and was not recovered.
192*1fdeec65Sjoyce mcintosh  * NULL     false    Should never happen.
193*1fdeec65Sjoyce mcintosh  * nonNULL  true     Structure exists, but an error has occurred.  Waiting
194*1fdeec65Sjoyce mcintosh  *                   for a chance to attempt to reconnect.
195*1fdeec65Sjoyce mcintosh  * nonNULL  false    Connection is good.
196*1fdeec65Sjoyce mcintosh  *
197*1fdeec65Sjoyce mcintosh  * Note that the initial state is NULL/true, so that the first request
198*1fdeec65Sjoyce mcintosh  * will establish the initial connection.
199*1fdeec65Sjoyce mcintosh  *
200*1fdeec65Sjoyce mcintosh  * Concurrency is managed through the rw lock "lock".  Only the writer is
201*1fdeec65Sjoyce mcintosh  * allowed to connect or disconnect, and thus only the writer can set
202*1fdeec65Sjoyce mcintosh  * "failed" to "false".  Readers are allowed to use the "client" pointer,
203*1fdeec65Sjoyce mcintosh  * and to set "failed" to "true", indicating that they have encountered a
204*1fdeec65Sjoyce mcintosh  * failure.  The "client" pointer is only valid while one holds a reader
205*1fdeec65Sjoyce mcintosh  * lock.  Once "failed" has been set to "true", all requests (including
206*1fdeec65Sjoyce mcintosh  * the retry of the failing request) will attempt to gain the writer lock.
207*1fdeec65Sjoyce mcintosh  * When they succeed, indicating that there are no requests in flight and
208*1fdeec65Sjoyce mcintosh  * thus no outstanding references to the CLIENT structure, they check
209*1fdeec65Sjoyce mcintosh  * again to see if the connection is still failed (since another thread
210*1fdeec65Sjoyce mcintosh  * might have fixed it), and then if it is still failed they disconnect
211*1fdeec65Sjoyce mcintosh  * and reconnect.
212*1fdeec65Sjoyce mcintosh  */
213*1fdeec65Sjoyce mcintosh 
214*1fdeec65Sjoyce mcintosh /*
215*1fdeec65Sjoyce mcintosh  * Make an RPC call.  Automatically reconnect if the connection to idmapd
216*1fdeec65Sjoyce mcintosh  * fails.  Convert RPC results to idmap return codes.
217*1fdeec65Sjoyce mcintosh  */
218*1fdeec65Sjoyce mcintosh idmap_stat
_idmap_clnt_call(const rpcproc_t procnum,const xdrproc_t inproc,const caddr_t in,const xdrproc_t outproc,caddr_t out,const struct timeval tout)219*1fdeec65Sjoyce mcintosh _idmap_clnt_call(
220*1fdeec65Sjoyce mcintosh     const rpcproc_t procnum,
221*1fdeec65Sjoyce mcintosh     const xdrproc_t inproc,
222*1fdeec65Sjoyce mcintosh     const caddr_t in,
223*1fdeec65Sjoyce mcintosh     const xdrproc_t outproc,
224*1fdeec65Sjoyce mcintosh     caddr_t out,
225*1fdeec65Sjoyce mcintosh     const struct timeval tout)
226*1fdeec65Sjoyce mcintosh {
227*1fdeec65Sjoyce mcintosh 	enum clnt_stat	clntstat;
228*1fdeec65Sjoyce mcintosh 	idmap_stat rc;
229*1fdeec65Sjoyce mcintosh 
230*1fdeec65Sjoyce mcintosh 	(void) rw_rdlock(&idmap_handle.lock);
231*1fdeec65Sjoyce mcintosh 	for (;;) {
232*1fdeec65Sjoyce mcintosh 		if (idmap_handle.failed) {
233*1fdeec65Sjoyce mcintosh 			/* No connection.  Bid to see if we should fix it. */
234*1fdeec65Sjoyce mcintosh 			(void) rw_unlock(&idmap_handle.lock);
235*1fdeec65Sjoyce mcintosh 			/* Somebody else might fix it here. */
236*1fdeec65Sjoyce mcintosh 			(void) rw_wrlock(&idmap_handle.lock);
237*1fdeec65Sjoyce mcintosh 			/*
238*1fdeec65Sjoyce mcintosh 			 * At this point, everybody else is asleep waiting
239*1fdeec65Sjoyce mcintosh 			 * for us.  Check to see if somebody else has already
240*1fdeec65Sjoyce mcintosh 			 * fixed the problem.
241*1fdeec65Sjoyce mcintosh 			 */
242*1fdeec65Sjoyce mcintosh 			if (idmap_handle.failed) {
243*1fdeec65Sjoyce mcintosh 				/* It's our job to fix. */
244*1fdeec65Sjoyce mcintosh 				_idmap_clnt_disconnect();
245*1fdeec65Sjoyce mcintosh 				rc = _idmap_clnt_connect();
246*1fdeec65Sjoyce mcintosh 				if (rc != IDMAP_SUCCESS) {
247*1fdeec65Sjoyce mcintosh 					/* We couldn't fix it. */
248*1fdeec65Sjoyce mcintosh 					assert(idmap_handle.failed);
249*1fdeec65Sjoyce mcintosh 					assert(idmap_handle.client == NULL);
250*1fdeec65Sjoyce mcintosh 					break;
251*1fdeec65Sjoyce mcintosh 				}
252*1fdeec65Sjoyce mcintosh 				/* We fixed it. */
253*1fdeec65Sjoyce mcintosh 				idmap_handle.failed = B_FALSE;
254*1fdeec65Sjoyce mcintosh 			}
255*1fdeec65Sjoyce mcintosh 
256*1fdeec65Sjoyce mcintosh 			/* It's fixed now. */
257*1fdeec65Sjoyce mcintosh 			(void) rw_unlock(&idmap_handle.lock);
258*1fdeec65Sjoyce mcintosh 			/*
259*1fdeec65Sjoyce mcintosh 			 * Starting here, somebody might declare it failed
260*1fdeec65Sjoyce mcintosh 			 * again.
261*1fdeec65Sjoyce mcintosh 			 */
262*1fdeec65Sjoyce mcintosh 			(void) rw_rdlock(&idmap_handle.lock);
263*1fdeec65Sjoyce mcintosh 			continue;
264*1fdeec65Sjoyce mcintosh 		}
265*1fdeec65Sjoyce mcintosh 
266*1fdeec65Sjoyce mcintosh 		clntstat = clnt_call(idmap_handle.client, procnum, inproc, in,
267*1fdeec65Sjoyce mcintosh 		    outproc, out, tout);
268*1fdeec65Sjoyce mcintosh 		rc = _idmap_rpc2stat(clntstat, idmap_handle.client);
269*1fdeec65Sjoyce mcintosh 		if (rc == IDMAP_ERR_RPC_HANDLE) {
270*1fdeec65Sjoyce mcintosh 			/* Failed.  Needs to be reconnected. */
271*1fdeec65Sjoyce mcintosh 			idmap_handle.failed = B_TRUE;
272*1fdeec65Sjoyce mcintosh 			continue;
273*1fdeec65Sjoyce mcintosh 		}
274*1fdeec65Sjoyce mcintosh 
275*1fdeec65Sjoyce mcintosh 		/* Success or unrecoverable failure. */
276*1fdeec65Sjoyce mcintosh 		break;
277*1fdeec65Sjoyce mcintosh 	}
278*1fdeec65Sjoyce mcintosh 	(void) rw_unlock(&idmap_handle.lock);
279*1fdeec65Sjoyce mcintosh 	return (rc);
280*1fdeec65Sjoyce mcintosh }
281*1fdeec65Sjoyce mcintosh 
282*1fdeec65Sjoyce mcintosh #define	MIN_STACK_NEEDS	65536
283*1fdeec65Sjoyce mcintosh 
284*1fdeec65Sjoyce mcintosh /*
285*1fdeec65Sjoyce mcintosh  * Connect to idmapd.
286*1fdeec65Sjoyce mcintosh  * Must be single-threaded through rw_wrlock(&idmap_handle.lock).
287*1fdeec65Sjoyce mcintosh  */
288*1fdeec65Sjoyce mcintosh static
289*1fdeec65Sjoyce mcintosh idmap_stat
_idmap_clnt_connect(void)290*1fdeec65Sjoyce mcintosh _idmap_clnt_connect(void)
291*1fdeec65Sjoyce mcintosh {
292*1fdeec65Sjoyce mcintosh 	uint_t			sendsz = 0;
293*1fdeec65Sjoyce mcintosh 	stack_t			st;
294*1fdeec65Sjoyce mcintosh 
295*1fdeec65Sjoyce mcintosh 	/*
296*1fdeec65Sjoyce mcintosh 	 * clnt_door_call() alloca()s sendsz bytes (twice too, once for
297*1fdeec65Sjoyce mcintosh 	 * the call args buffer and once for the call result buffer), so
298*1fdeec65Sjoyce mcintosh 	 * we want to pick a sendsz that will be large enough, but not
299*1fdeec65Sjoyce mcintosh 	 * too large.
300*1fdeec65Sjoyce mcintosh 	 */
301*1fdeec65Sjoyce mcintosh 	if (stack_getbounds(&st) == 0) {
302*1fdeec65Sjoyce mcintosh 		/*
303*1fdeec65Sjoyce mcintosh 		 * Estimate how much stack space is left;
304*1fdeec65Sjoyce mcintosh 		 * st.ss_sp is the top of stack.
305*1fdeec65Sjoyce mcintosh 		 */
306*1fdeec65Sjoyce mcintosh 		if ((char *)&sendsz < (char *)st.ss_sp)
307*1fdeec65Sjoyce mcintosh 			/* stack grows up */
308*1fdeec65Sjoyce mcintosh 			sendsz = ((char *)st.ss_sp - (char *)&sendsz);
309*1fdeec65Sjoyce mcintosh 		else
310*1fdeec65Sjoyce mcintosh 			/* stack grows down */
311*1fdeec65Sjoyce mcintosh 			sendsz = ((char *)&sendsz - (char *)st.ss_sp);
312*1fdeec65Sjoyce mcintosh 
313*1fdeec65Sjoyce mcintosh 		if (sendsz <= MIN_STACK_NEEDS) {
314*1fdeec65Sjoyce mcintosh 			sendsz = 0;	/* RPC call may fail */
315*1fdeec65Sjoyce mcintosh 		} else {
316*1fdeec65Sjoyce mcintosh 			/* Leave 64Kb (just a guess) for our needs */
317*1fdeec65Sjoyce mcintosh 			sendsz -= MIN_STACK_NEEDS;
318*1fdeec65Sjoyce mcintosh 
319*1fdeec65Sjoyce mcintosh 			/* Divide the stack space left by two */
320*1fdeec65Sjoyce mcintosh 			sendsz = RNDUP(sendsz / 2);
321*1fdeec65Sjoyce mcintosh 
322*1fdeec65Sjoyce mcintosh 			/* Limit sendsz to 256KB */
323*1fdeec65Sjoyce mcintosh 			if (sendsz > IDMAP_MAX_DOOR_RPC)
324*1fdeec65Sjoyce mcintosh 				sendsz = IDMAP_MAX_DOOR_RPC;
325651c0131Sbaban 		}
326651c0131Sbaban 	}
327651c0131Sbaban 
328*1fdeec65Sjoyce mcintosh 	idmap_handle.client = clnt_door_create(IDMAP_PROG, IDMAP_V1, sendsz);
329*1fdeec65Sjoyce mcintosh 	if (idmap_handle.client == NULL)
330*1fdeec65Sjoyce mcintosh 		return (IDMAP_ERR_RPC);
331*1fdeec65Sjoyce mcintosh 
332*1fdeec65Sjoyce mcintosh 	return (IDMAP_SUCCESS);
333*1fdeec65Sjoyce mcintosh }
334*1fdeec65Sjoyce mcintosh 
335*1fdeec65Sjoyce mcintosh /*
336*1fdeec65Sjoyce mcintosh  * Disconnect from idmapd, if we're connected.
337*1fdeec65Sjoyce mcintosh  */
338*1fdeec65Sjoyce mcintosh static
339*1fdeec65Sjoyce mcintosh void
_idmap_clnt_disconnect(void)340*1fdeec65Sjoyce mcintosh _idmap_clnt_disconnect(void)
341*1fdeec65Sjoyce mcintosh {
342*1fdeec65Sjoyce mcintosh 	CLIENT *clnt;
343*1fdeec65Sjoyce mcintosh 
344*1fdeec65Sjoyce mcintosh 	clnt = idmap_handle.client;
345*1fdeec65Sjoyce mcintosh 	if (clnt != NULL) {
346*1fdeec65Sjoyce mcintosh 		if (clnt->cl_auth)
347*1fdeec65Sjoyce mcintosh 			auth_destroy(clnt->cl_auth);
348*1fdeec65Sjoyce mcintosh 		clnt_destroy(clnt);
349*1fdeec65Sjoyce mcintosh 		idmap_handle.client = NULL;
350*1fdeec65Sjoyce mcintosh 	}
351651c0131Sbaban }
352