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)
18 #include "afs/sysincludes.h" /* Standard vendor system headers */
19 #include "afsincludes.h" /* Afs-based standard headers */
20 #include "afs/afs_stats.h" /* statistics */
21 #include "afs/nfsclient.h"
23 int afs_nfsclient_reqhandler(), afs_nfsclient_hold(), afs_PutNfsClientPag();
24 int afs_nfsclient_sysname(), afs_nfsclient_GC(), afs_nfsclient_stats();
25 #ifdef AFS_AIX_IAUTH_ENV
26 int afs_allnfsreqs, afs_nfscalls;
29 /* routines exported to the "AFS exporter" layer */
30 struct exporterops nfs_exportops = {
31 afs_nfsclient_reqhandler,
33 afs_PutNfsClientPag, /* Used to be afs_nfsclient_rele */
34 afs_nfsclient_sysname,
40 struct nfsclientpag *afs_nfspags[NNFSCLIENTS];
41 afs_lock_t afs_xnfspag /*, afs_xnfsreq */ ;
42 extern struct afs_exporter *afs_nfsexporter;
44 /* Creates an nfsclientpag structure for the (uid, host) pair if one doesn't exist. RefCount is incremented and it's time stamped. */
45 static struct nfsclientpag *
46 afs_GetNfsClientPag(uid, host)
47 register afs_int32 uid, host;
49 register struct nfsclientpag *np;
50 register afs_int32 i, now;
52 #if defined(AFS_SGIMP_ENV)
53 osi_Assert(ISAFS_GLOCK());
55 AFS_STATCNT(afs_GetNfsClientPag);
58 MObtainWriteLock(&afs_xnfspag, 314);
59 for (np = afs_nfspags[i]; np; np = np->next) {
60 if (np->uid == uid && np->host == host) {
63 MReleaseWriteLock(&afs_xnfspag);
67 /* next try looking for NOPAG dude, if we didn't find an exact match */
68 for (np = afs_nfspags[i]; np; np = np->next) {
69 if (np->uid == NOPAG && np->host == host) {
72 MReleaseWriteLock(&afs_xnfspag);
76 np = (struct nfsclientpag *)afs_osi_Alloc(sizeof(struct nfsclientpag));
77 memset((char *)np, 0, sizeof(struct nfsclientpag));
78 /* Copy the necessary afs_exporter fields */
79 memcpy((char *)np, (char *)afs_nfsexporter, sizeof(struct afs_exporter));
80 np->next = afs_nfspags[i];
86 MReleaseWriteLock(&afs_xnfspag);
91 /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call .
92 It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */
94 afs_PutNfsClientPag(np)
95 register struct nfsclientpag *np;
97 #if defined(AFS_SGIMP_ENV)
98 osi_Assert(ISAFS_GLOCK());
100 AFS_STATCNT(afs_PutNfsClientPag);
105 /* 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. */
106 static struct nfsclientpag *
107 afs_FindNfsClientPag(uid, host, pag)
108 register afs_int32 uid, host, pag;
110 register struct nfsclientpag *np;
111 register afs_int32 i;
113 #if defined(AFS_SGIMP_ENV)
114 osi_Assert(ISAFS_GLOCK());
116 AFS_STATCNT(afs_FindNfsClientPag);
118 MObtainWriteLock(&afs_xnfspag, 315);
119 for (np = afs_nfspags[i]; np; np = np->next) {
120 if (np->host == host) {
121 if ((pag && pag == np->pag) || (!pag && (uid == np->uid))) {
123 np->lastcall = osi_Time();
124 MReleaseWriteLock(&afs_xnfspag);
129 /* still not there, try looking for a wildcard dude */
130 for (np = afs_nfspags[i]; np; np = np->next) {
131 if (np->host == host) {
132 if (np->uid == NOPAG) {
134 np->lastcall = osi_Time();
135 MReleaseWriteLock(&afs_xnfspag);
140 MReleaseWriteLock(&afs_xnfspag);
145 /* routine to initialize the exporter, made global so we can call it
148 struct afs_exporter *afs_nfsexported = 0;
149 static afs_int32 init_nfsexporter = 0;
152 #if defined(AFS_SGIMP_ENV)
153 osi_Assert(ISAFS_GLOCK());
155 if (!init_nfsexporter) {
156 extern struct afs_exporter *exporter_add();
158 init_nfsexporter = 1;
159 LOCK_INIT(&afs_xnfspag, "afs_xnfspag");
161 exporter_add(0, &nfs_exportops, EXP_EXPORTED, EXP_NFS, NULL);
166 /* Main handler routine for the NFS exporter. It's called in the early
167 * phases of any remote call (via the NFS server or pioctl).
170 afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
171 register struct afs_exporter *exporter, **outexporter;
172 struct AFS_UCRED **cred;
173 register afs_int32 host;
176 register struct nfsclientpag *np, *tnp;
177 extern struct unixuser *afs_FindUser(), *afs_GetUser();
178 register struct unixuser *au = 0;
179 afs_int32 pag, code = 0;
182 AFS_STATCNT(afs_nfsclient_reqhandler);
183 if (!afs_nfsexporter)
184 afs_nfsexporter = afs_nfsexported;
186 afs_nfsexporter->exp_stats.calls++;
187 if (!(afs_nfsexporter->exp_states & EXP_EXPORTED)) {
188 /* 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!)
190 afs_nfsexporter->exp_stats.rejectedcalls++;
193 /* ObtainWriteLock(&afs_xnfsreq); */
194 pag = PagInCred(*cred);
196 /* Do some minimal pag verification */
197 if (pag > getpag()) {
198 pag = NOPAG; /* treat it as not paged since couldn't be good */
200 if (au = afs_FindUser(pag, -1, READ_LOCK)) {
203 afs_PutUser(au, READ_LOCK);
207 pag = NOPAG; /* No unixuser struct so pag not trusted */
210 np = afs_FindNfsClientPag((*cred)->cr_uid, host, 0);
211 afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag,
212 ICL_TYPE_LONG, (*cred)->cr_uid, ICL_TYPE_INT32, host,
213 ICL_TYPE_POINTER, np);
215 /* 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 */
217 if (code = setpag(u.u_procp, cred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
219 if (code = setpag(cred, -1, &pag, 1)) {
222 afs_PutUser(au, READ_LOCK);
223 /* ReleaseWriteLock(&afs_xnfsreq); */
224 #if defined(KERNEL_HAVE_UERROR)
229 np = afs_GetNfsClientPag((*cred)->cr_uid, host);
234 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
236 if (code = setpag(cred, np->pag, &pag, 1)) {
238 afs_PutNfsClientPag(np);
239 /* ReleaseWriteLock(&afs_xnfsreq); */
240 #if defined(KERNEL_HAVE_UERROR)
245 } else if (au->exporter
246 && ((struct afs_exporter *)np != au->exporter)) {
247 tnp = (struct nfsclientpag *)au->exporter;
248 if (tnp->uid && (tnp->uid != (afs_int32) - 2)) { /* allow "root" initiators */
249 /* Pag doesn't belong to caller; treat it as an unpaged call too */
251 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
253 if (code = setpag(cred, np->pag, &pag, 1)) {
255 afs_PutNfsClientPag(np);
256 afs_PutUser(au, READ_LOCK);
257 /* ReleaseWriteLock(&afs_xnfsreq); */
258 #if defined(KERNEL_HAVE_UERROR)
263 afs_nfsexporter->exp_stats.invalidpag++;
268 afs_PutUser(au, READ_LOCK);
269 au = afs_GetUser(pag, -1, WRITE_LOCK);
270 if (!(au->exporter)) { /* Created new unixuser struct */
271 np->refCount++; /* so it won't disappear */
272 au->exporter = (struct afs_exporter *)np;
275 *outexporter = (struct afs_exporter *)np;
276 afs_PutUser(au, WRITE_LOCK);
278 (*cred)->cr_ruid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
280 (*cred)->cr_rgid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
282 /* ReleaseWriteLock(&afs_xnfsreq); */
287 /* It's called whenever a new unixuser structure is created for the remote user associated with the nfsclientpag structure, np */
289 afs_nfsclient_hold(np)
290 register struct nfsclientpag *np;
292 #if defined(AFS_SGIMP_ENV)
293 osi_Assert(ISAFS_GLOCK());
295 AFS_STATCNT(afs_nfsclient_hold);
300 /* 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 */
302 afs_nfsclient_sysname(np, inname, outname)
303 register struct nfsclientpag *np;
304 char *inname, *outname;
306 #if defined(AFS_SGIMP_ENV)
307 osi_Assert(ISAFS_GLOCK());
309 AFS_STATCNT(afs_nfsclient_sysname);
312 np->sysname = afs_osi_Alloc(MAXSYSNAME);
314 strcpy(np->sysname, inname);
315 } else if (!np->sysname) {
316 return ENODEV; /* XXX */
318 strcpy(outname, np->sysname);
323 /* 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 */
325 afs_nfsclient_GC(exporter, pag)
326 register struct afs_exporter *exporter;
327 register afs_int32 pag;
329 register struct nfsclientpag *np, **tnp, *nnp;
330 register afs_int32 i, delflag;
332 #if defined(AFS_SGIMP_ENV)
333 osi_Assert(ISAFS_GLOCK());
335 AFS_STATCNT(afs_nfsclient_GC);
336 MObtainWriteLock(&afs_xnfspag, 316);
337 for (i = 0; i < NNFSCLIENTS; i++) {
338 for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) {
341 if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC)
343 if ((pag == -1) || (!pag && delflag)
344 || (pag && (np->refCount == 0) && (np->pag == pag))) {
347 afs_osi_Free(np->sysname, MAXSYSNAME);
348 afs_osi_Free(np, sizeof(struct nfsclientpag));
354 MReleaseWriteLock(&afs_xnfspag);
359 afs_nfsclient_stats(export)
360 register struct afs_exporter *export;
362 /* Nothing much to do here yet since most important stats are collected directly in the afs_exporter structure itself */
363 AFS_STATCNT(afs_nfsclient_stats);
368 /* This is exposed so that vop_fid can test it, even if iauth is not
371 extern int afs_iauth_initd;
374 #ifdef AFS_AIX_IAUTH_ENV
375 char *afs_nfs_id = "AFSNFSTRANS";
376 /* afs_iauth_verify is the AFS authenticator for NFS.
381 afs_iauth_verify(long id, fsid_t * fsidp, long host, int uid,
382 struct AFS_UCRED *credp, struct exportinfo *exp)
385 struct nfsclientpag *nfs_pag;
387 struct afs_exporter *outexporter = 0;
390 /* Still needs basic test to see if exporter is on. And need to check the
391 * whole no submounts bit.
395 return 0; /* not us. */
397 /* Only care if it's AFS */
398 if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) {
404 afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp, host,
405 &dummypag, &outexporter);
406 if (!code && outexporter)
407 EXP_RELE(outexporter);
410 /* ensure anonymous cred. */
411 credp->cr_uid = credp->cr_ruid = (uid_t) - 2; /* anonymous */
414 /* Mark this thread as an NFS translator thread. */
415 credp->cr_rgid = NFSXLATOR_CRED;
421 /* afs_iauth_register - register the iauth verify routine. Returns 0 on success
422 * and -1 on failure. Can fail because DFS has already registered.
427 if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify))
435 /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown.
438 afs_iauth_unregister()
441 nfs_iauth_unregister((unsigned long)afs_nfs_id);
444 #endif /* AFS_AIX_IAUTH_ENV */
451 extern int afs_allnfsreqs, afs_nfscalls;
454 #if defined(AFS_SGIMP_ENV)
455 osi_Assert(ISAFS_GLOCK());
457 AFS_STATCNT(afs_nfsclient_shutdown);
458 #ifdef AFS_AIX_IAUTH_ENV
459 afs_iauth_register();
461 afs_nfsclient_GC(afs_nfsexporter, -1);
462 init_nfsexporter = 0;
464 /* The following are for the nfs/afs server */
465 afs_allnfsreqs = afs_nfscalls = 0;
468 #endif /* AFS_DEC_ENV */
469 #endif /* AFS_NONFSTRANS */