1c5c4113dSnw141292 /*
2c5c4113dSnw141292 * CDDL HEADER START
3c5c4113dSnw141292 *
4c5c4113dSnw141292 * The contents of this file are subject to the terms of the
5c5c4113dSnw141292 * Common Development and Distribution License (the "License").
6c5c4113dSnw141292 * You may not use this file except in compliance with the License.
7c5c4113dSnw141292 *
8c5c4113dSnw141292 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c5c4113dSnw141292 * or http://www.opensolaris.org/os/licensing.
10c5c4113dSnw141292 * See the License for the specific language governing permissions
11c5c4113dSnw141292 * and limitations under the License.
12c5c4113dSnw141292 *
13c5c4113dSnw141292 * When distributing Covered Code, include this CDDL HEADER in each
14c5c4113dSnw141292 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c5c4113dSnw141292 * If applicable, add the following below this CDDL HEADER, with the
16c5c4113dSnw141292 * fields enclosed by brackets "[]" replaced with your own identifying
17c5c4113dSnw141292 * information: Portions Copyright [yyyy] [name of copyright owner]
18c5c4113dSnw141292 *
19c5c4113dSnw141292 * CDDL HEADER END
20c5c4113dSnw141292 */
21c5c4113dSnw141292 /*
22*1fdeec65Sjoyce mcintosh * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23c5c4113dSnw141292 */
24c5c4113dSnw141292
25c5c4113dSnw141292 /*
26c5c4113dSnw141292 * Utility routines
27c5c4113dSnw141292 */
28c5c4113dSnw141292
29c5c4113dSnw141292 #include <stdio.h>
30c5c4113dSnw141292 #include <stdlib.h>
31c5c4113dSnw141292 #include <errno.h>
32c5c4113dSnw141292 #include <libintl.h>
33*1fdeec65Sjoyce mcintosh #include <assert.h>
34*1fdeec65Sjoyce mcintosh #include <ucontext.h>
35*1fdeec65Sjoyce mcintosh #include <pthread.h>
36c5c4113dSnw141292 #include "idmap_impl.h"
37c5c4113dSnw141292
38c5c4113dSnw141292 #define _UDT_SIZE_INCR 1
39c5c4113dSnw141292
40c5c4113dSnw141292 #define _GET_IDS_SIZE_INCR 1
41c5c4113dSnw141292
42c5c4113dSnw141292 static struct timeval TIMEOUT = { 25, 0 };
43c5c4113dSnw141292
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
59c5c4113dSnw141292 idmap_retcode
_udt_extend_batch(idmap_udt_handle_t * udthandle)604edd44c5Sjp151216 _udt_extend_batch(idmap_udt_handle_t *udthandle)
614edd44c5Sjp151216 {
62c5c4113dSnw141292 idmap_update_op *tmplist;
63c5c4113dSnw141292 size_t nsize;
64c5c4113dSnw141292
65c5c4113dSnw141292 if (udthandle->next >= udthandle->batch.idmap_update_batch_len) {
66c5c4113dSnw141292 nsize = (udthandle->batch.idmap_update_batch_len +
67c5c4113dSnw141292 _UDT_SIZE_INCR) * sizeof (*tmplist);
68c5c4113dSnw141292 tmplist = realloc(
69c5c4113dSnw141292 udthandle->batch.idmap_update_batch_val, nsize);
70c5c4113dSnw141292 if (tmplist == NULL)
71c5c4113dSnw141292 return (IDMAP_ERR_MEMORY);
72c5c4113dSnw141292 (void) memset((uchar_t *)tmplist +
73c5c4113dSnw141292 (udthandle->batch.idmap_update_batch_len *
74c5c4113dSnw141292 sizeof (*tmplist)), 0,
75c5c4113dSnw141292 _UDT_SIZE_INCR * sizeof (*tmplist));
76c5c4113dSnw141292 udthandle->batch.idmap_update_batch_val = tmplist;
77c5c4113dSnw141292 udthandle->batch.idmap_update_batch_len += _UDT_SIZE_INCR;
78c5c4113dSnw141292 }
79c5c4113dSnw141292 udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
80651c0131Sbaban OP_NONE;
81c5c4113dSnw141292 return (IDMAP_SUCCESS);
82c5c4113dSnw141292 }
83c5c4113dSnw141292
84c5c4113dSnw141292 idmap_retcode
_get_ids_extend_batch(idmap_get_handle_t * gh)854edd44c5Sjp151216 _get_ids_extend_batch(idmap_get_handle_t *gh)
864edd44c5Sjp151216 {
87c5c4113dSnw141292 idmap_mapping *t1;
88c5c4113dSnw141292 idmap_get_res_t *t2;
89c5c4113dSnw141292 size_t nsize, len;
90c5c4113dSnw141292
91c5c4113dSnw141292 len = gh->batch.idmap_mapping_batch_len;
92c5c4113dSnw141292 if (gh->next >= len) {
93c5c4113dSnw141292 /* extend the request array */
94c5c4113dSnw141292 nsize = (len + _GET_IDS_SIZE_INCR) * sizeof (*t1);
95c5c4113dSnw141292 t1 = realloc(gh->batch.idmap_mapping_batch_val, nsize);
96c5c4113dSnw141292 if (t1 == NULL)
97c5c4113dSnw141292 return (IDMAP_ERR_MEMORY);
98c5c4113dSnw141292 (void) memset((uchar_t *)t1 + (len * sizeof (*t1)), 0,
99c5c4113dSnw141292 _GET_IDS_SIZE_INCR * sizeof (*t1));
100c5c4113dSnw141292 gh->batch.idmap_mapping_batch_val = t1;
101c5c4113dSnw141292
102c5c4113dSnw141292 /* extend the return list */
103c5c4113dSnw141292 nsize = (len + _GET_IDS_SIZE_INCR) * sizeof (*t2);
104c5c4113dSnw141292 t2 = realloc(gh->retlist, nsize);
105c5c4113dSnw141292 if (t2 == NULL)
106c5c4113dSnw141292 return (IDMAP_ERR_MEMORY);
107c5c4113dSnw141292 (void) memset((uchar_t *)t2 + (len * sizeof (*t2)), 0,
108c5c4113dSnw141292 _GET_IDS_SIZE_INCR * sizeof (*t2));
109c5c4113dSnw141292 gh->retlist = t2;
110c5c4113dSnw141292
111c5c4113dSnw141292 gh->batch.idmap_mapping_batch_len += _GET_IDS_SIZE_INCR;
112c5c4113dSnw141292 }
113c5c4113dSnw141292 return (IDMAP_SUCCESS);
114c5c4113dSnw141292 }
115c5c4113dSnw141292
116c5c4113dSnw141292 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)117c5c4113dSnw141292 _iter_get_next_list(int type, idmap_iter_t *iter,
118c5c4113dSnw141292 void *arg, uchar_t **list, size_t valsize,
1194edd44c5Sjp151216 xdrproc_t xdr_arg_proc, xdrproc_t xdr_res_proc)
1204edd44c5Sjp151216 {
121*1fdeec65Sjoyce mcintosh idmap_stat rc;
122c5c4113dSnw141292
123c5c4113dSnw141292 iter->next = 0;
124c5c4113dSnw141292 iter->retlist = NULL;
125c5c4113dSnw141292
126c5c4113dSnw141292 /* init the result */
127c5c4113dSnw141292 if (*list) {
128c5c4113dSnw141292 xdr_free(xdr_res_proc, (caddr_t)*list);
129c5c4113dSnw141292 } else {
130c5c4113dSnw141292 if ((*list = malloc(valsize)) == NULL) {
131c5c4113dSnw141292 errno = ENOMEM;
132c5c4113dSnw141292 return (IDMAP_ERR_MEMORY);
133c5c4113dSnw141292 }
134c5c4113dSnw141292 }
135c5c4113dSnw141292 (void) memset(*list, 0, valsize);
136c5c4113dSnw141292
137*1fdeec65Sjoyce mcintosh rc = _idmap_clnt_call(type,
138c5c4113dSnw141292 xdr_arg_proc, (caddr_t)arg,
139c5c4113dSnw141292 xdr_res_proc, (caddr_t)*list,
140c5c4113dSnw141292 TIMEOUT);
141*1fdeec65Sjoyce mcintosh if (rc != IDMAP_SUCCESS) {
142c5c4113dSnw141292 free(*list);
143*1fdeec65Sjoyce mcintosh return (rc);
144c5c4113dSnw141292 }
145c5c4113dSnw141292 iter->retlist = *list;
146c5c4113dSnw141292 return (IDMAP_SUCCESS);
147c5c4113dSnw141292 }
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)
1564edd44c5Sjp151216 {
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
168651c0131Sbaban clnt_geterr(clnt, &r_err);
169651c0131Sbaban errno = r_err.re_errno;
170651c0131Sbaban switch (r_err.re_errno) {
171651c0131Sbaban case ENOMEM:
172651c0131Sbaban return (IDMAP_ERR_MEMORY);
173651c0131Sbaban case EBADF:
174651c0131Sbaban return (IDMAP_ERR_RPC_HANDLE);
175651c0131Sbaban default:
176651c0131Sbaban return (IDMAP_ERR_RPC);
177651c0131Sbaban }
178651c0131Sbaban }
179651c0131Sbaban
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;
325*1fdeec65Sjoyce mcintosh }
326*1fdeec65Sjoyce mcintosh }
327*1fdeec65Sjoyce mcintosh
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