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"
15 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
17 #include "../afs/sysincludes.h" /* Standard vendor system headers */
18 #include "../afs/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 *afs_GetNfsClientPag(uid, host)
45 register afs_int32 uid, host;
47 register struct nfsclientpag *np;
48 register afs_int32 i, now;
50 #if defined(AFS_SGIMP_ENV)
51 osi_Assert(ISAFS_GLOCK());
53 AFS_STATCNT(afs_GetNfsClientPag);
56 MObtainWriteLock(&afs_xnfspag,314);
57 for (np = afs_nfspags[i]; np; np = np->next) {
58 if (np->uid == uid && np->host == host) {
61 MReleaseWriteLock(&afs_xnfspag);
65 /* next try looking for NOPAG dude, if we didn't find an exact match */
66 for (np = afs_nfspags[i]; np; np = np->next) {
67 if (np->uid == NOPAG && np->host == host) {
70 MReleaseWriteLock(&afs_xnfspag);
74 np = (struct nfsclientpag *) afs_osi_Alloc(sizeof (struct nfsclientpag));
75 memset((char *)np, 0, sizeof(struct nfsclientpag));
76 /* Copy the necessary afs_exporter fields */
77 memcpy((char *)np, (char *)afs_nfsexporter, sizeof(struct afs_exporter));
78 np->next = afs_nfspags[i];
84 MReleaseWriteLock(&afs_xnfspag);
89 /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call .
90 It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */
91 int afs_PutNfsClientPag(np)
92 register struct nfsclientpag *np;
94 #if defined(AFS_SGIMP_ENV)
95 osi_Assert(ISAFS_GLOCK());
97 AFS_STATCNT(afs_PutNfsClientPag);
102 /* 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. */
103 static struct nfsclientpag *afs_FindNfsClientPag(uid, host, pag)
104 register afs_int32 uid, host, pag;
106 register struct nfsclientpag *np;
107 register afs_int32 i;
109 #if defined(AFS_SGIMP_ENV)
110 osi_Assert(ISAFS_GLOCK());
112 AFS_STATCNT(afs_FindNfsClientPag);
114 MObtainWriteLock(&afs_xnfspag,315);
115 for (np = afs_nfspags[i]; np; np = np->next) {
116 if (np->host == host) {
117 if ((pag && pag == np->pag) || (!pag && (uid == np->uid))) {
119 np->lastcall = osi_Time();
120 MReleaseWriteLock(&afs_xnfspag);
125 /* still not there, try looking for a wildcard dude */
126 for (np = afs_nfspags[i]; np; np = np->next) {
127 if (np->host == host) {
128 if (np->uid == NOPAG) {
130 np->lastcall = osi_Time();
131 MReleaseWriteLock(&afs_xnfspag);
136 MReleaseWriteLock(&afs_xnfspag);
137 return (struct nfsclientpag *) 0;
141 /* routine to initialize the exporter, made global so we can call it
144 struct afs_exporter *afs_nfsexported = 0;
145 static afs_int32 init_nfsexporter = 0;
146 afs_nfsclient_init() {
147 #if defined(AFS_SGIMP_ENV)
148 osi_Assert(ISAFS_GLOCK());
150 if (!init_nfsexporter) {
151 extern struct afs_exporter *exporter_add();
153 init_nfsexporter = 1;
154 LOCK_INIT(&afs_xnfspag, "afs_xnfspag");
155 afs_nfsexported = exporter_add(0, &nfs_exportops, EXP_EXPORTED, EXP_NFS, (char *)0);
160 /* Main handler routine for the NFS exporter. It's called in the early
161 * phases of any remote call (via the NFS server or pioctl).
163 int afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
164 register struct afs_exporter *exporter, **outexporter;
165 struct AFS_UCRED **cred;
166 register afs_int32 host;
169 register struct nfsclientpag *np, *tnp;
170 extern struct unixuser *afs_FindUser(), *afs_GetUser();
171 register struct unixuser *au = 0;
172 afs_int32 pag, code = 0;
175 AFS_STATCNT(afs_nfsclient_reqhandler);
176 if (!afs_nfsexporter) afs_nfsexporter = afs_nfsexported;
178 afs_nfsexporter->exp_stats.calls++;
179 if (!(afs_nfsexporter->exp_states & EXP_EXPORTED)) {
180 /* 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!)
182 afs_nfsexporter->exp_stats.rejectedcalls++;
185 /* ObtainWriteLock(&afs_xnfsreq); */
186 pag = PagInCred(*cred);
188 /* Do some minimal pag verification */
189 if (pag > getpag()) {
190 pag = NOPAG; /* treat it as not paged since couldn't be good */
192 if (au = afs_FindUser(pag, -1, READ_LOCK)) {
195 afs_PutUser(au, READ_LOCK);
196 au = (struct unixuser *)0;
199 pag = NOPAG; /* No unixuser struct so pag not trusted */
202 np = afs_FindNfsClientPag((*cred)->cr_uid, host, 0);
203 afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag,
204 ICL_TYPE_LONG, (*cred)->cr_uid, ICL_TYPE_INT32, host,
205 ICL_TYPE_POINTER, np);
207 /* 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 */
209 if (code = setpag(u.u_procp, cred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
211 if (code = setpag(cred, -1, &pag, 1)) {
213 if (au) afs_PutUser(au, READ_LOCK);
214 /* ReleaseWriteLock(&afs_xnfsreq); */
215 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV)
220 np = afs_GetNfsClientPag((*cred)->cr_uid, host);
225 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
227 if (code = setpag(cred, np->pag, &pag, 1)) {
229 afs_PutNfsClientPag(np);
230 /* ReleaseWriteLock(&afs_xnfsreq); */
231 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV)
236 } else if (au->exporter && ((struct afs_exporter *)np != au->exporter)) {
237 tnp = (struct nfsclientpag *)au->exporter;
238 if (tnp->uid && (tnp->uid != (afs_int32)-2)) { /* allow "root" initiators */
239 /* Pag doesn't belong to caller; treat it as an unpaged call too */
241 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
243 if (code = setpag(cred, np->pag, &pag, 1)) {
245 afs_PutNfsClientPag(np);
246 afs_PutUser(au, READ_LOCK);
247 /* ReleaseWriteLock(&afs_xnfsreq); */
248 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV)
253 afs_nfsexporter->exp_stats.invalidpag++;
257 if (au) afs_PutUser(au, READ_LOCK);
258 au = afs_GetUser(pag, -1, WRITE_LOCK);
259 if (!(au->exporter)) { /* Created new unixuser struct */
260 np->refCount++; /* so it won't disappear */
261 au->exporter = (struct afs_exporter *)np;
264 *outexporter = (struct afs_exporter *)np;
265 afs_PutUser(au, WRITE_LOCK);
267 (*cred)->cr_ruid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
269 (*cred)->cr_rgid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
271 /* ReleaseWriteLock(&afs_xnfsreq); */
276 /* It's called whenever a new unixuser structure is created for the remote user associated with the nfsclientpag structure, np */
277 int afs_nfsclient_hold(np)
278 register struct nfsclientpag *np;
280 #if defined(AFS_SGIMP_ENV)
281 osi_Assert(ISAFS_GLOCK());
283 AFS_STATCNT(afs_nfsclient_hold);
288 /* 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 */
289 int afs_nfsclient_sysname(np, inname, outname)
290 register struct nfsclientpag *np;
291 char *inname, *outname;
293 #if defined(AFS_SGIMP_ENV)
294 osi_Assert(ISAFS_GLOCK());
296 AFS_STATCNT(afs_nfsclient_sysname);
299 np->sysname = afs_osi_Alloc(MAXSYSNAME);
301 strcpy(np->sysname, inname);
302 } else if (!np->sysname) {
303 return ENODEV; /* XXX */
305 strcpy(outname, np->sysname);
310 /* 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 */
311 int afs_nfsclient_GC(exporter, pag)
312 register struct afs_exporter *exporter;
313 register afs_int32 pag;
315 register struct nfsclientpag *np, **tnp, *nnp;
316 register afs_int32 i, delflag;
318 #if defined(AFS_SGIMP_ENV)
319 osi_Assert(ISAFS_GLOCK());
321 AFS_STATCNT(afs_nfsclient_GC);
322 MObtainWriteLock(&afs_xnfspag,316);
323 for (i = 0; i < NNFSCLIENTS; i++) {
324 for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) {
327 if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC)
329 if ((pag == -1) || (!pag && delflag) || (pag && (np->refCount == 0) && (np->pag == pag))) {
331 if (np->sysname) afs_osi_Free(np->sysname, MAXSYSNAME);
332 afs_osi_Free(np, sizeof(struct nfsclientpag));
338 MReleaseWriteLock(&afs_xnfspag);
342 int afs_nfsclient_stats(export)
343 register struct afs_exporter *export;
345 /* Nothing much to do here yet since most important stats are collected directly in the afs_exporter structure itself */
346 AFS_STATCNT(afs_nfsclient_stats);
351 /* This is exposed so that vop_fid can test it, even if iauth is not
354 extern int afs_iauth_initd;
357 #ifdef AFS_AIX_IAUTH_ENV
358 char *afs_nfs_id = "AFSNFSTRANS";
359 /* afs_iauth_verify is the AFS authenticator for NFS.
363 int afs_iauth_verify(long id, fsid_t *fsidp, long host,
364 int uid, struct AFS_UCRED *credp, struct exportinfo *exp)
367 struct nfsclientpag *nfs_pag;
369 struct afs_exporter *outexporter = 0;
372 /* Still needs basic test to see if exporter is on. And need to check the
373 * whole no submounts bit.
377 return 0; /* not us. */
379 /* Only care if it's AFS */
380 if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) {
385 code = afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp,
386 host, &dummypag, &outexporter);
387 if (!code && outexporter)
388 EXP_RELE(outexporter);
391 /* ensure anonymous cred. */
392 credp->cr_uid = credp->cr_ruid = (uid_t)-2; /* anonymous */
395 /* Mark this thread as an NFS translator thread. */
396 credp->cr_rgid = NFSXLATOR_CRED;
402 /* afs_iauth_register - register the iauth verify routine. Returns 0 on success
403 * and -1 on failure. Can fail because DFS has already registered.
405 int afs_iauth_register()
407 if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify))
415 /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown.
417 void afs_iauth_unregister()
420 nfs_iauth_unregister((unsigned long)afs_nfs_id);
423 #endif /* AFS_AIX_IAUTH_ENV */
428 extern int afs_allnfsreqs, afs_nfscalls;
430 #if defined(AFS_SGIMP_ENV)
431 osi_Assert(ISAFS_GLOCK());
433 AFS_STATCNT(afs_nfsclient_shutdown);
434 #ifdef AFS_AIX_IAUTH_ENV
435 afs_iauth_register();
437 afs_nfsclient_GC(afs_nfsexporter, -1);
438 init_nfsexporter = 0;
439 /* The following are for the nfs/afs server */
440 afs_allnfsreqs = afs_nfscalls = 0;
442 #endif /* AFS_DEC_ENV */
443 #endif /* AFS_NONFSTRANS */