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(register struct nfsclientpag *np, char *inname,
303 char **outname[], int *num)
307 #if defined(AFS_SGIMP_ENV)
308 osi_Assert(ISAFS_GLOCK());
310 AFS_STATCNT(afs_nfsclient_sysname);
313 for(count=0; count < np->sysnamecount;++count) {
314 afs_osi_Free(np->sysname[count], MAXSYSNAME);
317 for(count=0; count < *num;++count) {
318 np->sysname[count]= afs_osi_Alloc(MAXSYSNAME);
321 for(count=0; count < *num;++count) {
323 memcpy(np->sysname[count], cp, t+1); /* include null */
326 np->sysnamecount = *num;
327 } else if (!np->sysname) {
328 return ENODEV; /* XXX */
330 *outname = np->sysname;
331 *num = np->sysnamecount;
336 /* 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 */
338 afs_nfsclient_GC(exporter, pag)
339 register struct afs_exporter *exporter;
340 register afs_int32 pag;
342 register struct nfsclientpag *np, **tnp, *nnp;
343 register afs_int32 i, delflag;
345 #if defined(AFS_SGIMP_ENV)
346 osi_Assert(ISAFS_GLOCK());
348 AFS_STATCNT(afs_nfsclient_GC);
349 MObtainWriteLock(&afs_xnfspag, 316);
350 for (i = 0; i < NNFSCLIENTS; i++) {
351 for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) {
354 if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC)
356 if ((pag == -1) || (!pag && delflag)
357 || (pag && (np->refCount == 0) && (np->pag == pag))) {
360 afs_osi_Free(np->sysname, MAXSYSNAME);
361 afs_osi_Free(np, sizeof(struct nfsclientpag));
367 MReleaseWriteLock(&afs_xnfspag);
372 afs_nfsclient_stats(export)
373 register struct afs_exporter *export;
375 /* Nothing much to do here yet since most important stats are collected directly in the afs_exporter structure itself */
376 AFS_STATCNT(afs_nfsclient_stats);
381 /* This is exposed so that vop_fid can test it, even if iauth is not
384 extern int afs_iauth_initd;
387 #ifdef AFS_AIX_IAUTH_ENV
388 char *afs_nfs_id = "AFSNFSTRANS";
389 /* afs_iauth_verify is the AFS authenticator for NFS.
394 afs_iauth_verify(long id, fsid_t * fsidp, long host, int uid,
395 struct AFS_UCRED *credp, struct exportinfo *exp)
398 struct nfsclientpag *nfs_pag;
400 struct afs_exporter *outexporter = 0;
403 /* Still needs basic test to see if exporter is on. And need to check the
404 * whole no submounts bit.
408 return 0; /* not us. */
410 /* Only care if it's AFS */
411 if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) {
417 afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp, host,
418 &dummypag, &outexporter);
419 if (!code && outexporter)
420 EXP_RELE(outexporter);
423 /* ensure anonymous cred. */
424 credp->cr_uid = credp->cr_ruid = (uid_t) - 2; /* anonymous */
427 /* Mark this thread as an NFS translator thread. */
428 credp->cr_rgid = NFSXLATOR_CRED;
434 /* afs_iauth_register - register the iauth verify routine. Returns 0 on success
435 * and -1 on failure. Can fail because DFS has already registered.
440 if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify))
448 /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown.
451 afs_iauth_unregister()
454 nfs_iauth_unregister((unsigned long)afs_nfs_id);
457 #endif /* AFS_AIX_IAUTH_ENV */
464 extern int afs_allnfsreqs, afs_nfscalls;
467 #if defined(AFS_SGIMP_ENV)
468 osi_Assert(ISAFS_GLOCK());
470 AFS_STATCNT(afs_nfsclient_shutdown);
471 #ifdef AFS_AIX_IAUTH_ENV
472 afs_iauth_register();
474 afs_nfsclient_GC(afs_nfsexporter, -1);
475 init_nfsexporter = 0;
477 /* The following are for the nfs/afs server */
478 afs_allnfsreqs = afs_nfscalls = 0;
481 #endif /* AFS_DEC_ENV */
482 #endif /* AFS_NONFSTRANS */