2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "afs/param.h"
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"
22 int afs_nfsclient_reqhandler(), afs_nfsclient_hold(), afs_PutNfsClientPag();
23 int afs_nfsclient_sysname(), afs_nfsclient_GC(), afs_nfsclient_stats();
24 #ifdef AFS_AIX_IAUTH_ENV
25 int afs_allnfsreqs, afs_nfscalls;
28 /* routines exported to the "AFS exporter" layer */
29 struct exporterops nfs_exportops = {
30 afs_nfsclient_reqhandler,
32 afs_PutNfsClientPag, /* Used to be afs_nfsclient_rele */
33 afs_nfsclient_sysname,
39 struct nfsclientpag *afs_nfspags[NNFSCLIENTS];
40 afs_lock_t afs_xnfspag /*, afs_xnfsreq */ ;
41 extern struct afs_exporter *afs_nfsexporter;
43 /* Creates an nfsclientpag structure for the (uid, host) pair if one doesn't exist. RefCount is incremented and it's time stamped. */
44 static struct nfsclientpag *
45 afs_GetNfsClientPag(uid, host)
46 register afs_int32 uid, host;
48 register struct nfsclientpag *np;
49 register afs_int32 i, now;
51 #if defined(AFS_SGIMP_ENV)
52 osi_Assert(ISAFS_GLOCK());
54 AFS_STATCNT(afs_GetNfsClientPag);
57 MObtainWriteLock(&afs_xnfspag, 314);
58 for (np = afs_nfspags[i]; np; np = np->next) {
59 if (np->uid == uid && np->host == host) {
62 MReleaseWriteLock(&afs_xnfspag);
66 /* next try looking for NOPAG dude, if we didn't find an exact match */
67 for (np = afs_nfspags[i]; np; np = np->next) {
68 if (np->uid == NOPAG && np->host == host) {
71 MReleaseWriteLock(&afs_xnfspag);
75 np = (struct nfsclientpag *)afs_osi_Alloc(sizeof(struct nfsclientpag));
76 memset((char *)np, 0, sizeof(struct nfsclientpag));
77 /* Copy the necessary afs_exporter fields */
78 memcpy((char *)np, (char *)afs_nfsexporter, sizeof(struct afs_exporter));
79 np->next = afs_nfspags[i];
85 MReleaseWriteLock(&afs_xnfspag);
90 /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call .
91 It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */
93 afs_PutNfsClientPag(np)
94 register struct nfsclientpag *np;
96 #if defined(AFS_SGIMP_ENV)
97 osi_Assert(ISAFS_GLOCK());
99 AFS_STATCNT(afs_PutNfsClientPag);
104 /* 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. */
105 static struct nfsclientpag *
106 afs_FindNfsClientPag(uid, host, pag)
107 register afs_int32 uid, host, pag;
109 register struct nfsclientpag *np;
110 register afs_int32 i;
112 #if defined(AFS_SGIMP_ENV)
113 osi_Assert(ISAFS_GLOCK());
115 AFS_STATCNT(afs_FindNfsClientPag);
117 MObtainWriteLock(&afs_xnfspag, 315);
118 for (np = afs_nfspags[i]; np; np = np->next) {
119 if (np->host == host) {
120 if ((pag && pag == np->pag) || (!pag && (uid == np->uid))) {
122 np->lastcall = osi_Time();
123 MReleaseWriteLock(&afs_xnfspag);
128 /* still not there, try looking for a wildcard dude */
129 for (np = afs_nfspags[i]; np; np = np->next) {
130 if (np->host == host) {
131 if (np->uid == NOPAG) {
133 np->lastcall = osi_Time();
134 MReleaseWriteLock(&afs_xnfspag);
139 MReleaseWriteLock(&afs_xnfspag);
144 /* routine to initialize the exporter, made global so we can call it
147 struct afs_exporter *afs_nfsexported = 0;
148 static afs_int32 init_nfsexporter = 0;
151 #if defined(AFS_SGIMP_ENV)
152 osi_Assert(ISAFS_GLOCK());
154 if (!init_nfsexporter) {
155 extern struct afs_exporter *exporter_add();
157 init_nfsexporter = 1;
158 LOCK_INIT(&afs_xnfspag, "afs_xnfspag");
160 exporter_add(0, &nfs_exportops, EXP_EXPORTED, EXP_NFS, NULL);
165 /* Main handler routine for the NFS exporter. It's called in the early
166 * phases of any remote call (via the NFS server or pioctl).
169 afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
170 register struct afs_exporter *exporter, **outexporter;
171 struct AFS_UCRED **cred;
172 register afs_int32 host;
175 register struct nfsclientpag *np, *tnp;
176 extern struct unixuser *afs_FindUser(), *afs_GetUser();
177 register struct unixuser *au = 0;
178 afs_int32 pag, code = 0;
181 AFS_STATCNT(afs_nfsclient_reqhandler);
182 if (!afs_nfsexporter)
183 afs_nfsexporter = afs_nfsexported;
185 afs_nfsexporter->exp_stats.calls++;
186 if (!(afs_nfsexporter->exp_states & EXP_EXPORTED)) {
187 /* 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!)
189 afs_nfsexporter->exp_stats.rejectedcalls++;
192 /* ObtainWriteLock(&afs_xnfsreq); */
193 pag = PagInCred(*cred);
195 /* Do some minimal pag verification */
196 if (pag > getpag()) {
197 pag = NOPAG; /* treat it as not paged since couldn't be good */
199 if (au = afs_FindUser(pag, -1, READ_LOCK)) {
202 afs_PutUser(au, READ_LOCK);
206 pag = NOPAG; /* No unixuser struct so pag not trusted */
209 np = afs_FindNfsClientPag((*cred)->cr_uid, host, 0);
210 afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag,
211 ICL_TYPE_LONG, (*cred)->cr_uid, ICL_TYPE_INT32, host,
212 ICL_TYPE_POINTER, np);
214 /* 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 */
216 if (code = setpag(u.u_procp, cred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
218 if (code = setpag(cred, -1, &pag, 1)) {
221 afs_PutUser(au, READ_LOCK);
222 /* ReleaseWriteLock(&afs_xnfsreq); */
223 #if defined(KERNEL_HAVE_UERROR)
228 np = afs_GetNfsClientPag((*cred)->cr_uid, host);
233 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
235 if (code = setpag(cred, np->pag, &pag, 1)) {
237 afs_PutNfsClientPag(np);
238 /* ReleaseWriteLock(&afs_xnfsreq); */
239 #if defined(KERNEL_HAVE_UERROR)
244 } else if (au->exporter
245 && ((struct afs_exporter *)np != au->exporter)) {
246 tnp = (struct nfsclientpag *)au->exporter;
247 if (tnp->uid && (tnp->uid != (afs_int32) - 2)) { /* allow "root" initiators */
248 /* Pag doesn't belong to caller; treat it as an unpaged call too */
250 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
252 if (code = setpag(cred, np->pag, &pag, 1)) {
254 afs_PutNfsClientPag(np);
255 afs_PutUser(au, READ_LOCK);
256 /* ReleaseWriteLock(&afs_xnfsreq); */
257 #if defined(KERNEL_HAVE_UERROR)
262 afs_nfsexporter->exp_stats.invalidpag++;
267 afs_PutUser(au, READ_LOCK);
268 au = afs_GetUser(pag, -1, WRITE_LOCK);
269 if (!(au->exporter)) { /* Created new unixuser struct */
270 np->refCount++; /* so it won't disappear */
271 au->exporter = (struct afs_exporter *)np;
274 *outexporter = (struct afs_exporter *)np;
275 afs_PutUser(au, WRITE_LOCK);
277 (*cred)->cr_ruid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
279 (*cred)->cr_rgid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
281 /* ReleaseWriteLock(&afs_xnfsreq); */
286 /* It's called whenever a new unixuser structure is created for the remote user associated with the nfsclientpag structure, np */
288 afs_nfsclient_hold(np)
289 register struct nfsclientpag *np;
291 #if defined(AFS_SGIMP_ENV)
292 osi_Assert(ISAFS_GLOCK());
294 AFS_STATCNT(afs_nfsclient_hold);
299 /* 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 */
301 afs_nfsclient_sysname(register struct nfsclientpag *np, char *inname,
302 char **outname[], int *num)
306 #if defined(AFS_SGIMP_ENV)
307 osi_Assert(ISAFS_GLOCK());
309 AFS_STATCNT(afs_nfsclient_sysname);
312 for(count=0; count < np->sysnamecount;++count) {
313 afs_osi_Free(np->sysname[count], MAXSYSNAME);
316 for(count=0; count < *num;++count) {
317 np->sysname[count]= afs_osi_Alloc(MAXSYSNAME);
320 for(count=0; count < *num;++count) {
322 memcpy(np->sysname[count], cp, t+1); /* include null */
325 np->sysnamecount = *num;
326 } else if (!np->sysname) {
327 return ENODEV; /* XXX */
329 *outname = np->sysname;
330 *num = np->sysnamecount;
335 /* 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 */
337 afs_nfsclient_GC(exporter, pag)
338 register struct afs_exporter *exporter;
339 register afs_int32 pag;
341 register struct nfsclientpag *np, **tnp, *nnp;
342 register afs_int32 i, delflag;
344 #if defined(AFS_SGIMP_ENV)
345 osi_Assert(ISAFS_GLOCK());
347 AFS_STATCNT(afs_nfsclient_GC);
348 MObtainWriteLock(&afs_xnfspag, 316);
349 for (i = 0; i < NNFSCLIENTS; i++) {
350 for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) {
353 if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC)
355 if ((pag == -1) || (!pag && delflag)
356 || (pag && (np->refCount == 0) && (np->pag == pag))) {
359 afs_osi_Free(np->sysname, MAXSYSNAME);
360 afs_osi_Free(np, sizeof(struct nfsclientpag));
366 MReleaseWriteLock(&afs_xnfspag);
371 afs_nfsclient_stats(export)
372 register struct afs_exporter *export;
374 /* Nothing much to do here yet since most important stats are collected directly in the afs_exporter structure itself */
375 AFS_STATCNT(afs_nfsclient_stats);
380 /* This is exposed so that vop_fid can test it, even if iauth is not
383 extern int afs_iauth_initd;
386 #ifdef AFS_AIX_IAUTH_ENV
387 char *afs_nfs_id = "AFSNFSTRANS";
388 /* afs_iauth_verify is the AFS authenticator for NFS.
393 afs_iauth_verify(long id, fsid_t * fsidp, long host, int uid,
394 struct AFS_UCRED *credp, struct exportinfo *exp)
397 struct nfsclientpag *nfs_pag;
399 struct afs_exporter *outexporter = 0;
402 /* Still needs basic test to see if exporter is on. And need to check the
403 * whole no submounts bit.
407 return 0; /* not us. */
409 /* Only care if it's AFS */
410 if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) {
416 afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp, host,
417 &dummypag, &outexporter);
418 if (!code && outexporter)
419 EXP_RELE(outexporter);
422 /* ensure anonymous cred. */
423 credp->cr_uid = credp->cr_ruid = (uid_t) - 2; /* anonymous */
426 /* Mark this thread as an NFS translator thread. */
427 credp->cr_rgid = NFSXLATOR_CRED;
433 /* afs_iauth_register - register the iauth verify routine. Returns 0 on success
434 * and -1 on failure. Can fail because DFS has already registered.
439 if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify))
447 /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown.
450 afs_iauth_unregister()
453 nfs_iauth_unregister((unsigned long)afs_nfs_id);
456 #endif /* AFS_AIX_IAUTH_ENV */
462 #if defined(AFS_SGIMP_ENV)
463 osi_Assert(ISAFS_GLOCK());
465 AFS_STATCNT(afs_nfsclient_shutdown);
466 #ifdef AFS_AIX_IAUTH_ENV
467 afs_iauth_register();
469 afs_nfsclient_GC(afs_nfsexporter, -1);
470 init_nfsexporter = 0;
472 #endif /* AFS_NONFSTRANS */