DEVEL15-linux-2-6-27-20080816
[openafs.git] / src / afs / afs_nfsclnt.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13 RCSID
14     ("$Header$");
15
16 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
17 #include "afs/sysincludes.h"    /* Standard vendor system headers */
18 #include "afsincludes.h"        /* Afs-based standard headers */
19 #include "afs/afs_stats.h"      /* statistics */
20 #include "afs/nfsclient.h"
21 #include "rx/rx_globals.h"
22 #include "afs/pagcb.h"
23
24 void afs_nfsclient_hold(), afs_PutNfsClientPag(), afs_nfsclient_GC();
25 static void afs_nfsclient_getcreds();
26 int afs_nfsclient_sysname(), afs_nfsclient_stats(), afs_nfsclient_checkhost();
27 afs_int32 afs_nfsclient_gethost();
28 #ifdef AFS_AIX_IAUTH_ENV
29 int afs_allnfsreqs, afs_nfscalls;
30 #endif
31
32 /* routines exported to the "AFS exporter" layer */
33 struct exporterops nfs_exportops = {
34     afs_nfsclient_reqhandler,
35     afs_nfsclient_hold,
36     afs_PutNfsClientPag,        /* Used to be afs_nfsclient_rele */
37     afs_nfsclient_sysname,
38     afs_nfsclient_GC,
39     afs_nfsclient_stats,
40     afs_nfsclient_checkhost,
41     afs_nfsclient_gethost
42 };
43
44
45 struct nfsclientpag *afs_nfspags[NNFSCLIENTS];
46 afs_lock_t afs_xnfspag /*, afs_xnfsreq */ ;
47 extern struct afs_exporter *afs_nfsexporter;
48
49 /* Creates an nfsclientpag structure for the (uid, host) pair if one doesn't exist. RefCount is incremented and it's time stamped. */
50 static struct nfsclientpag *
51 afs_GetNfsClientPag(uid, host)
52      register afs_int32 uid, host;
53 {
54     register struct nfsclientpag *np;
55     register afs_int32 i, now;
56
57 #if defined(AFS_SGIMP_ENV)
58     osi_Assert(ISAFS_GLOCK());
59 #endif
60     AFS_STATCNT(afs_GetNfsClientPag);
61     i = NHash(host);
62     now = osi_Time();
63     MObtainWriteLock(&afs_xnfspag, 314);
64     for (np = afs_nfspags[i]; np; np = np->next) {
65         if (np->uid == uid && np->host == host) {
66             np->refCount++;
67             np->lastcall = now;
68             MReleaseWriteLock(&afs_xnfspag);
69             return np;
70         }
71     }
72     /* next try looking for NOPAG dude, if we didn't find an exact match */
73     for (np = afs_nfspags[i]; np; np = np->next) {
74         if (np->uid == NOPAG && np->host == host) {
75             np->refCount++;
76             np->lastcall = now;
77             MReleaseWriteLock(&afs_xnfspag);
78             return np;
79         }
80     }
81     np = (struct nfsclientpag *)afs_osi_Alloc(sizeof(struct nfsclientpag));
82     memset((char *)np, 0, sizeof(struct nfsclientpag));
83     /* Copy the necessary afs_exporter fields */
84     memcpy((char *)np, (char *)afs_nfsexporter, sizeof(struct afs_exporter));
85     np->next = afs_nfspags[i];
86     afs_nfspags[i] = np;
87     np->uid = uid;
88     np->host = host;
89     np->refCount = 1;
90     np->lastcall = now;
91     MReleaseWriteLock(&afs_xnfspag);
92     return np;
93 }
94
95
96 /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call .
97 It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */
98 void
99 afs_PutNfsClientPag(np)
100      register struct nfsclientpag *np;
101 {
102 #if defined(AFS_SGIMP_ENV)
103     osi_Assert(ISAFS_GLOCK());
104 #endif
105     AFS_STATCNT(afs_PutNfsClientPag);
106     --np->refCount;
107 }
108
109
110 /* Return the nfsclientpag structure associated with the (uid, host) or {pag, host} pair, if pag is nonzero. RefCount is incremented and it's time stamped. */
111 static struct nfsclientpag *
112 afs_FindNfsClientPag(uid, host, pag)
113      register afs_int32 uid, host, pag;
114 {
115     register struct nfsclientpag *np;
116     register afs_int32 i;
117
118 #if defined(AFS_SGIMP_ENV)
119     osi_Assert(ISAFS_GLOCK());
120 #endif
121     AFS_STATCNT(afs_FindNfsClientPag);
122     i = NHash(host);
123     MObtainWriteLock(&afs_xnfspag, 315);
124     for (np = afs_nfspags[i]; np; np = np->next) {
125         if (np->host == host) {
126             if ((pag && pag == np->pag) || (!pag && (uid == np->uid))) {
127                 np->refCount++;
128                 np->lastcall = osi_Time();
129                 MReleaseWriteLock(&afs_xnfspag);
130                 return np;
131             }
132         }
133     }
134     /* still not there, try looking for a wildcard dude */
135     for (np = afs_nfspags[i]; np; np = np->next) {
136         if (np->host == host) {
137             if (np->uid == NOPAG) {
138                 np->refCount++;
139                 np->lastcall = osi_Time();
140                 MReleaseWriteLock(&afs_xnfspag);
141                 return np;
142             }
143         }
144     }
145     MReleaseWriteLock(&afs_xnfspag);
146     return NULL;
147 }
148
149
150 /* routine to initialize the exporter, made global so we can call it
151  * from pioctl calls.
152  */
153 struct afs_exporter *afs_nfsexported = 0;
154 static afs_int32 init_nfsexporter = 0;
155
156 void
157 afs_nfsclient_init(void)
158 {
159 #if defined(AFS_SGIMP_ENV)
160     osi_Assert(ISAFS_GLOCK());
161 #endif
162     if (!init_nfsexporter) {
163         extern struct afs_exporter *exporter_add();
164
165         init_nfsexporter = 1;
166         LOCK_INIT(&afs_xnfspag, "afs_xnfspag");
167         afs_nfsexported =
168             exporter_add(0, &nfs_exportops, EXP_EXPORTED, EXP_NFS, NULL);
169     }
170 }
171
172
173 /* Main handler routine for the NFS exporter. It's called in the early
174  * phases of any remote call (via the NFS server or pioctl).
175  */
176 int
177 afs_nfsclient_reqhandler(struct afs_exporter *exporter,
178                          struct AFS_UCRED **cred,
179                          afs_int32 host, afs_int32 *pagparam,
180                          struct afs_exporter **outexporter)
181 {
182     register struct nfsclientpag *np, *tnp;
183     extern struct unixuser *afs_FindUser(), *afs_GetUser();
184     register struct unixuser *au = 0;
185     afs_int32 uid, pag, code = 0;
186
187     AFS_ASSERT_GLOCK();
188     AFS_STATCNT(afs_nfsclient_reqhandler);
189     if (!afs_nfsexporter)
190         afs_nfsexporter = afs_nfsexported;
191
192     afs_nfsexporter->exp_stats.calls++;
193     if (!(afs_nfsexporter->exp_states & EXP_EXPORTED)) {
194         /* No afs requests accepted as long as EXPORTED flag is turned 'off'. Set/Reset via a pioctl call (fs exportafs). Note that this is on top of the /etc/exports nfs requirement (i.e. /afs must be exported to all or whomever there too!)
195          */
196         afs_nfsexporter->exp_stats.rejectedcalls++;
197         return EINVAL;
198     }
199 /*    ObtainWriteLock(&afs_xnfsreq); */
200     pag = PagInCred(*cred);
201 #if defined(AFS_SUN510_ENV)
202     uid = crgetuid(*cred);
203 #else
204     uid = (*cred)->cr_uid;
205 #endif
206     /* Do this early, so pag management knows */
207 #ifdef  AFS_OSF_ENV
208     (*cred)->cr_ruid = NFSXLATOR_CRED;  /* Identify it as nfs xlator call */
209 #else
210     (*cred)->cr_rgid = NFSXLATOR_CRED;  /* Identify it as nfs xlator call */
211 #endif
212     if ((afs_nfsexporter->exp_states & EXP_CLIPAGS) && pag != NOPAG) {
213         uid = pag;
214     } else if (pag != NOPAG) {
215         /* Do some minimal pag verification */
216         if (pag > getpag()) {
217             pag = NOPAG;        /* treat it as not paged since couldn't be good  */
218         } else {
219             if ((au = afs_FindUser(pag, -1, READ_LOCK))) {
220                 if (!au->exporter) {
221                     pag = NOPAG;
222                     afs_PutUser(au, READ_LOCK);
223                     au = NULL;
224                 }
225             } else
226                 pag = NOPAG;    /*  No unixuser struct so pag not trusted  */
227         }
228     }
229     np = afs_FindNfsClientPag(uid, host, 0);
230     afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag,
231                ICL_TYPE_LONG, (*cred)->cr_uid, ICL_TYPE_INT32, host,
232                ICL_TYPE_POINTER, np);
233     /* If remote-pags are enabled, we are no longer interested in what PAG
234      * they claimed, and from here on we should behave as if they claimed
235      * none at all, which is to say we use the (local) pag named in the
236      * nfsclientpag structure (if any).  This is deferred until here so
237      * that we can log the PAG they claimed.
238      */
239     if ((afs_nfsexporter->exp_states & EXP_CLIPAGS))
240         pag = NOPAG;
241     if (!np) {
242         /* Even if there is a "good" pag coming in we don't accept it if no nfsclientpag struct exists for the user since that would mean that the translator rebooted and therefore we ignore all older pag values */
243 #ifdef  AFS_OSF_ENV
244         if (code = setpag(u.u_procp, cred, -1, &pag, 0)) {      /* XXX u.u_procp is a no-op XXX */
245 #else
246         if ((code = setpag(cred, -1, &pag, 0))) {
247 #endif
248             if (au)
249                 afs_PutUser(au, READ_LOCK);
250 /*          ReleaseWriteLock(&afs_xnfsreq);             */
251 #if defined(KERNEL_HAVE_UERROR)
252             setuerror(code);
253 #endif
254             return (code);
255         }
256         np = afs_GetNfsClientPag(uid, host);
257         np->pag = pag;
258         np->client_uid = (*cred)->cr_uid;
259     } else {
260         if (pag == NOPAG) {
261 #ifdef  AFS_OSF_ENV
262             if (code = setpag(u.u_procp, cred, np->pag, &pag, 0)) {     /* XXX u.u_procp is a no-op XXX */
263 #else
264             if ((code = setpag(cred, np->pag, &pag, 0))) {
265 #endif
266                 afs_PutNfsClientPag(np);
267 /*              ReleaseWriteLock(&afs_xnfsreq); */
268 #if defined(KERNEL_HAVE_UERROR)
269                 setuerror(code);
270 #endif
271                 return (code);
272             }
273         } else if (au->exporter
274                    && ((struct afs_exporter *)np != au->exporter)) {
275             tnp = (struct nfsclientpag *)au->exporter;
276             if (tnp->uid && (tnp->uid != (afs_int32) - 2)) {    /* allow "root" initiators */
277                 /* Pag doesn't belong to caller; treat it as an unpaged call too */
278 #ifdef  AFS_OSF_ENV
279                 if (code = setpag(u.u_procp, cred, np->pag, &pag, 0)) { /* XXX u.u_procp is a no-op XXX */
280 #else
281                 if ((code = setpag(cred, np->pag, &pag, 0))) {
282 #endif
283                     afs_PutNfsClientPag(np);
284                     afs_PutUser(au, READ_LOCK);
285                     /*      ReleaseWriteLock(&afs_xnfsreq);     */
286 #if defined(KERNEL_HAVE_UERROR)
287                     setuerror(code);
288 #endif
289                     return (code);
290                 }
291                 afs_nfsexporter->exp_stats.invalidpag++;
292             }
293         }
294     }
295     if (au)
296         afs_PutUser(au, READ_LOCK);
297     au = afs_GetUser(pag, -1, WRITE_LOCK);
298     if (!(au->exporter)) {      /* Created new unixuser struct */
299         np->refCount++;         /* so it won't disappear */
300         au->exporter = (struct afs_exporter *)np;
301         if ((afs_nfsexporter->exp_states & EXP_CALLBACK))
302             afs_nfsclient_getcreds(au);
303     } else while (au->states & UNFSGetCreds) {
304         afs_osi_Sleep((void *)au);
305     }
306     *pagparam = pag;
307     *outexporter = (struct afs_exporter *)np;
308     afs_PutUser(au, WRITE_LOCK);
309 /*    ReleaseWriteLock(&afs_xnfsreq);   */
310     return 0;
311 }
312
313 void
314 afs_nfsclient_getcreds(au)
315     struct unixuser *au;
316 {
317     struct nfsclientpag *np = (struct nfsclientpag *)(au->exporter);
318     struct rx_securityClass *csec;
319     struct rx_connection *tconn;
320     SysNameList tsysnames;
321     CredInfos tcreds;
322     CredInfo *tcred;
323     struct unixuser *tu;
324     struct cell *tcell;
325     int code, i, cellnum;
326
327     au->states |= UNFSGetCreds;
328     memset(&tcreds, 0, sizeof(tcreds));
329     memset(&tsysnames, 0, sizeof(tsysnames));
330
331     /* Get a connection */
332     /* This sucks a little.  We should cache the connections or something.
333      * But at this point I don't yet think it's worth the effort.
334      */
335     csec = rxnull_NewClientSecurityObject();
336     AFS_GUNLOCK();
337     tconn = rx_NewConnection(np->host, htons(7001), PAGCB_SERVICEID, csec, 0);
338     AFS_GLOCK();
339
340     /* Get the sysname, if needed */
341     if (!np->sysnamecount) {
342         AFS_GUNLOCK();
343         code = PAGCB_GetSysName(tconn, np->uid, &tsysnames);
344         AFS_GLOCK();
345         if (code ||
346             tsysnames.SysNameList_len <= 0 ||
347             tsysnames.SysNameList_len > MAXNUMSYSNAMES)
348             goto done;
349     
350         for(i = 0; i < np->sysnamecount; i++)
351             afs_osi_Free(np->sysname[i], MAXSYSNAME);
352
353         np->sysnamecount = tsysnames.SysNameList_len;
354         for(i = 0; i < np->sysnamecount; i++)
355             np->sysname[i] = tsysnames.SysNameList_val[i].sysname;
356         afs_osi_Free(tsysnames.SysNameList_val,
357                      tsysnames.SysNameList_len * sizeof(SysNameEnt));
358     }
359
360     /* Get credentials */
361     AFS_GUNLOCK();
362     code = PAGCB_GetCreds(tconn, np->uid, &tcreds);
363     AFS_GLOCK();
364     if (code)
365         goto done;
366
367     /* Now, set the credentials they gave us... */
368     for (i = 0; i < tcreds.CredInfos_len; i++) {
369         tcred = &tcreds.CredInfos_val[i];
370
371         /* Find the cell.  If it is unknown to us, punt this entry. */
372         tcell = afs_GetCellByName(tcred->cellname, READ_LOCK);
373         afs_osi_Free(tcred->cellname, strlen(tcred->cellname) + 1);
374         if (!tcell) {
375             memset(tcred->ct.HandShakeKey, 0, 8);
376             memset(tcred->st.st_val, 0, tcred->st.st_len);
377             afs_osi_Free(tcred->st.st_val, tcred->st.st_len);
378             continue;
379         }
380         cellnum = tcell->cellNum;
381         afs_PutCell(tcell, READ_LOCK);
382
383         /* Find the appropriate unixuser.  This might be the same as
384          * the one we were passed (au), but that's OK.
385          */
386         tu = afs_GetUser(np->pag, cellnum, WRITE_LOCK);
387         if (!(tu->exporter)) {  /* Created new unixuser struct */
388             np->refCount++;             /* so it won't disappear */
389             tu->exporter = (struct afs_exporter *)np;
390         }
391
392         /* free any old secret token, and keep the new one */
393         if (tu->stp != NULL) {
394             afs_osi_Free(tu->stp, tu->stLen);
395         }
396         tu->stp = tcred->st.st_val;
397         tu->stLen = tcred->st.st_len;
398
399         /* copy the clear token */
400         memset(&tu->ct, 0, sizeof(tu->ct));
401         memcpy(tu->ct.HandShakeKey, tcred->ct.HandShakeKey, 8);
402         memset(tcred->ct.HandShakeKey, 0, 8);
403         tu->ct.AuthHandle     = tcred->ct.AuthHandle;
404         tu->ct.ViceId         = tcred->ct.ViceId;
405         tu->ct.BeginTimestamp = tcred->ct.BeginTimestamp;
406         tu->ct.EndTimestamp   = tcred->ct.EndTimestamp;
407
408         /* Set everything else, reset connections, and move on. */
409         tu->vid = tcred->vid;
410         tu->states |= UHasTokens;
411         tu->states &= ~UTokensBad;
412         afs_SetPrimary(tu, !!(tcred->states & UPrimary));
413         tu->tokenTime = osi_Time();
414         afs_ResetUserConns(tu);
415         afs_PutUser(tu, WRITE_LOCK);
416     }
417     afs_osi_Free(tcreds.CredInfos_val, tcreds.CredInfos_len * sizeof(CredInfo));
418
419 done:
420     AFS_GUNLOCK();
421     rx_DestroyConnection(tconn);
422     AFS_GLOCK();
423     au->states &= ~UNFSGetCreds;
424     afs_osi_Wakeup((void *)au);
425 }
426
427
428 /* It's called whenever a new unixuser structure is created for the remote user associated with the nfsclientpag structure, np */
429 void
430 afs_nfsclient_hold(np)
431      register struct nfsclientpag *np;
432 {
433 #if defined(AFS_SGIMP_ENV)
434     osi_Assert(ISAFS_GLOCK());
435 #endif
436     AFS_STATCNT(afs_nfsclient_hold);
437     np->refCount++;
438 }
439
440
441 /* check if this exporter corresponds to the specified host */
442 int
443 afs_nfsclient_checkhost(np, host)
444     register struct nfsclientpag *np;
445 {
446     if (np->type != EXP_NFS)
447         return 0;
448     return np->host == host;
449 }
450
451
452 /* get the host for this exporter, or 0 if there is an error */
453 afs_int32
454 afs_nfsclient_gethost(np)
455     register struct nfsclientpag *np;
456 {
457     if (np->type != EXP_NFS)
458         return 0;
459     return np->host;
460 }
461
462
463 /* if inname is non-null, a new system name value is set for the remote user (inname contains the new sysname). In all cases, outname returns the current sysname value for this remote user */
464 int 
465 afs_nfsclient_sysname(register struct nfsclientpag *np, char *inname, 
466                       char ***outname, int *num, int allpags)
467 {
468     register struct nfsclientpag *tnp;
469     register afs_int32 i;
470     char *cp;
471     int count, t;
472 #if defined(AFS_SGIMP_ENV)
473     osi_Assert(ISAFS_GLOCK());
474 #endif
475     AFS_STATCNT(afs_nfsclient_sysname);
476     if (allpags > 0) {
477         /* update every client, not just the one making the request */
478         i = NHash(np->host);
479         MObtainWriteLock(&afs_xnfspag, 315);
480         for (tnp = afs_nfspags[i]; tnp; tnp = tnp->next) {
481             if (tnp != np && tnp->host == np->host)
482                 afs_nfsclient_sysname(tnp, inname, outname, num, -1);
483         }
484         MReleaseWriteLock(&afs_xnfspag);
485     }
486     if (inname) {
487             for(count=0; count < np->sysnamecount;++count) {
488                 afs_osi_Free(np->sysname[count], MAXSYSNAME);
489                 np->sysname[count] = NULL;
490             }
491         for(count=0; count < *num;++count) {
492             np->sysname[count]= afs_osi_Alloc(MAXSYSNAME);
493         }
494         cp = inname;
495         for(count=0; count < *num;++count) {
496             t = strlen(cp);
497             memcpy(np->sysname[count], cp, t+1); /* include null */
498             cp += t+1;
499         }
500         np->sysnamecount = *num;
501     }
502     if (allpags >= 0) {
503         /* Don't touch our arguments when called recursively */
504         *outname = np->sysname;
505         *num = np->sysnamecount;
506         if (!np->sysname[0])
507             return ENODEV; /* XXX */
508     }
509     return 0;
510 }
511
512
513 /* Garbage collect routine for the nfs exporter. When pag is -1 then all entries are removed (used by the nfsclient_shutdown routine); else if it's non zero then only the entry with that pag is removed, else all "timedout" entries are removed. TimedOut entries are those who have no "unixuser" structures associated with them (i.e. unixusercnt == 0) and they haven't had any activity the last NFSCLIENTGC seconds */
514 void
515 afs_nfsclient_GC(exporter, pag)
516      register struct afs_exporter *exporter;
517      register afs_int32 pag;
518 {
519     register struct nfsclientpag *np, **tnp, *nnp;
520     register afs_int32 i, delflag;
521         int count;
522
523 #if defined(AFS_SGIMP_ENV)
524     osi_Assert(ISAFS_GLOCK());
525 #endif
526     AFS_STATCNT(afs_nfsclient_GC);
527     MObtainWriteLock(&afs_xnfspag, 316);
528     for (i = 0; i < NNFSCLIENTS; i++) {
529         for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) {
530             nnp = np->next;
531             delflag = 0;
532             if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC)
533                 delflag = 1;
534             if ((pag == -1) || (!pag && delflag)
535                 || (pag && (np->refCount == 0) && (np->pag == pag))) {
536                 *tnp = np->next;
537                 for(count=0; count < np->sysnamecount;++count) {
538                         afs_osi_Free(np->sysname[count], MAXSYSNAME);
539                 }
540                 afs_osi_Free(np, sizeof(struct nfsclientpag));
541             } else {
542                 tnp = &np->next;
543             }
544         }
545     }
546     MReleaseWriteLock(&afs_xnfspag);
547 }
548
549
550 int
551 afs_nfsclient_stats(export)
552      register struct afs_exporter *export;
553 {
554     /* Nothing much to do here yet since most important stats are collected directly in the afs_exporter structure itself */
555     AFS_STATCNT(afs_nfsclient_stats);
556     return 0;
557 }
558
559 #ifdef AFS_AIX41_ENV
560 /* This is exposed so that vop_fid can test it, even if iauth is not
561  *  installed.
562  */
563 extern int afs_iauth_initd;
564 #endif
565
566 #ifdef AFS_AIX_IAUTH_ENV
567 char *afs_nfs_id = "AFSNFSTRANS";
568 /* afs_iauth_verify is the AFS authenticator for NFS.
569  *
570  * always returns 0.
571  */
572 int
573 afs_iauth_verify(long id, fsid_t * fsidp, long host, int uid,
574                  struct AFS_UCRED *credp, struct exportinfo *exp)
575 {
576     int code;
577     struct nfsclientpag *nfs_pag;
578     afs_int32 dummypag;
579     struct afs_exporter *outexporter = 0;
580
581
582     /* Still needs basic test to see if exporter is on. And need to check the
583      * whole no submounts bit.
584      */
585
586     if (id != (long)id)
587         return 0;               /* not us. */
588
589     /* Only care if it's AFS */
590     if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) {
591         return 0;
592     }
593
594     AFS_GLOCK();
595     code =
596         afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp, host,
597                                  &dummypag, &outexporter);
598     if (!code && outexporter)
599         EXP_RELE(outexporter);
600
601     if (code) {
602         /* ensure anonymous cred. */
603         credp->cr_uid = credp->cr_ruid = (uid_t) - 2;   /* anonymous */
604     }
605
606     /* Mark this thread as an NFS translator thread. */
607     credp->cr_rgid = NFSXLATOR_CRED;
608
609     AFS_GUNLOCK();
610     return 0;
611 }
612
613 /* afs_iauth_register - register the iauth verify routine. Returns 0 on success
614  * and -1 on failure. Can fail because DFS has already registered.
615  */
616 int
617 afs_iauth_register()
618 {
619     if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify))
620         return -1;
621     else {
622         afs_iauth_initd = 1;
623         return 0;
624     }
625 }
626
627 /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown. 
628  */
629 void
630 afs_iauth_unregister()
631 {
632     if (afs_iauth_initd)
633         nfs_iauth_unregister((unsigned long)afs_nfs_id);
634     afs_iauth_initd = 0;
635 }
636 #endif /* AFS_AIX_IAUTH_ENV */
637
638
639
640 void
641 shutdown_nfsclnt()
642 {
643 #if defined(AFS_SGIMP_ENV)
644     osi_Assert(ISAFS_GLOCK());
645 #endif
646     AFS_STATCNT(afs_nfsclient_shutdown);
647 #ifdef AFS_AIX_IAUTH_ENV
648     afs_iauth_register();
649 #endif
650     afs_nfsclient_GC(afs_nfsexporter, -1);
651     init_nfsexporter = 0;
652 }
653 #endif /* AFS_NONFSTRANS */