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