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 "../afs/param.h" /* Should be always first */
11 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
13 #include "../afs/sysincludes.h" /* Standard vendor system headers */
14 #include "../afs/afsincludes.h" /* Afs-based standard headers */
15 #include "../afs/afs_stats.h" /* statistics */
16 #include "../afs/nfsclient.h"
18 int afs_nfsclient_reqhandler(), afs_nfsclient_hold(), afs_PutNfsClientPag();
19 int afs_nfsclient_sysname(), afs_nfsclient_GC(), afs_nfsclient_stats();
20 #ifdef AFS_AIX_IAUTH_ENV
21 int afs_allnfsreqs, afs_nfscalls;
24 /* routines exported to the "AFS exporter" layer */
25 struct exporterops nfs_exportops = {
26 afs_nfsclient_reqhandler,
28 afs_PutNfsClientPag, /* Used to be afs_nfsclient_rele */
29 afs_nfsclient_sysname,
35 struct nfsclientpag *afs_nfspags[NNFSCLIENTS];
36 afs_lock_t afs_xnfspag /*, afs_xnfsreq */;
37 extern struct afs_exporter *afs_nfsexporter;
39 /* Creates an nfsclientpag structure for the (uid, host) pair if one doesn't exist. RefCount is incremented and it's time stamped. */
40 static struct nfsclientpag *afs_GetNfsClientPag(uid, host)
41 register afs_int32 uid, host;
43 register struct nfsclientpag *np;
44 register afs_int32 i, now;
46 #if defined(AFS_SGIMP_ENV)
47 osi_Assert(ISAFS_GLOCK());
49 AFS_STATCNT(afs_GetNfsClientPag);
52 MObtainWriteLock(&afs_xnfspag,314);
53 for (np = afs_nfspags[i]; np; np = np->next) {
54 if (np->uid == uid && np->host == host) {
57 MReleaseWriteLock(&afs_xnfspag);
61 /* next try looking for NOPAG dude, if we didn't find an exact match */
62 for (np = afs_nfspags[i]; np; np = np->next) {
63 if (np->uid == NOPAG && np->host == host) {
66 MReleaseWriteLock(&afs_xnfspag);
70 np = (struct nfsclientpag *) afs_osi_Alloc(sizeof (struct nfsclientpag));
71 bzero((char *)np, sizeof(struct nfsclientpag));
72 /* Copy the necessary afs_exporter fields */
73 bcopy((char *)afs_nfsexporter, (char *)np, sizeof(struct afs_exporter));
74 np->next = afs_nfspags[i];
80 MReleaseWriteLock(&afs_xnfspag);
85 /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call .
86 It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */
87 int afs_PutNfsClientPag(np)
88 register struct nfsclientpag *np;
90 #if defined(AFS_SGIMP_ENV)
91 osi_Assert(ISAFS_GLOCK());
93 AFS_STATCNT(afs_PutNfsClientPag);
98 /* 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. */
99 static struct nfsclientpag *afs_FindNfsClientPag(uid, host, pag)
100 register afs_int32 uid, host, pag;
102 register struct nfsclientpag *np;
103 register afs_int32 i;
105 #if defined(AFS_SGIMP_ENV)
106 osi_Assert(ISAFS_GLOCK());
108 AFS_STATCNT(afs_FindNfsClientPag);
110 MObtainWriteLock(&afs_xnfspag,315);
111 for (np = afs_nfspags[i]; np; np = np->next) {
112 if (np->host == host) {
113 if ((pag && pag == np->pag) || (!pag && (uid == np->uid))) {
115 np->lastcall = osi_Time();
116 MReleaseWriteLock(&afs_xnfspag);
121 /* still not there, try looking for a wildcard dude */
122 for (np = afs_nfspags[i]; np; np = np->next) {
123 if (np->host == host) {
124 if (np->uid == NOPAG) {
126 np->lastcall = osi_Time();
127 MReleaseWriteLock(&afs_xnfspag);
132 MReleaseWriteLock(&afs_xnfspag);
133 return (struct nfsclientpag *) 0;
137 /* routine to initialize the exporter, made global so we can call it
140 struct afs_exporter *afs_nfsexported = 0;
141 static afs_int32 init_nfsexporter = 0;
142 afs_nfsclient_init() {
143 #if defined(AFS_SGIMP_ENV)
144 osi_Assert(ISAFS_GLOCK());
146 if (!init_nfsexporter) {
147 extern struct afs_exporter *exporter_add();
149 init_nfsexporter = 1;
150 LOCK_INIT(&afs_xnfspag, "afs_xnfspag");
151 afs_nfsexported = exporter_add(0, &nfs_exportops, EXP_EXPORTED, EXP_NFS, (char *)0);
156 /* Main handler routine for the NFS exporter. It's called in the early
157 * phases of any remote call (via the NFS server or pioctl).
159 int afs_nfsclient_reqhandler(exporter, cred, host, pagparam, outexporter)
160 register struct afs_exporter *exporter, **outexporter;
161 struct AFS_UCRED **cred;
162 register afs_int32 host;
165 register struct nfsclientpag *np, *tnp;
166 extern struct unixuser *afs_FindUser(), *afs_GetUser();
167 register struct unixuser *au = 0;
168 afs_int32 pag, code = 0;
171 AFS_STATCNT(afs_nfsclient_reqhandler);
172 if (!afs_nfsexporter) afs_nfsexporter = afs_nfsexported;
174 afs_nfsexporter->exp_stats.calls++;
175 if (!(afs_nfsexporter->exp_states & EXP_EXPORTED)) {
176 /* 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!)
178 afs_nfsexporter->exp_stats.rejectedcalls++;
181 /* ObtainWriteLock(&afs_xnfsreq); */
182 pag = PagInCred(*cred);
184 /* Do some minimal pag verification */
185 if (pag > getpag()) {
186 pag = NOPAG; /* treat it as not paged since couldn't be good */
188 if (au = afs_FindUser(pag, -1, READ_LOCK)) {
191 afs_PutUser(au, READ_LOCK);
192 au = (struct unixuser *)0;
195 pag = NOPAG; /* No unixuser struct so pag not trusted */
198 np = afs_FindNfsClientPag((*cred)->cr_uid, host, 0);
199 afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag,
200 ICL_TYPE_LONG, (*cred)->cr_uid, ICL_TYPE_INT32, host,
201 ICL_TYPE_POINTER, np);
203 /* 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 */
205 if (code = setpag(u.u_procp, cred, -1, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
207 if (code = setpag(cred, -1, &pag, 1)) {
209 if (au) afs_PutUser(au, READ_LOCK);
210 /* ReleaseWriteLock(&afs_xnfsreq); */
211 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV)
216 np = afs_GetNfsClientPag((*cred)->cr_uid, host);
221 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
223 if (code = setpag(cred, np->pag, &pag, 1)) {
225 afs_PutNfsClientPag(np);
226 /* ReleaseWriteLock(&afs_xnfsreq); */
227 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV)
232 } else if (au->exporter && ((struct afs_exporter *)np != au->exporter)) {
233 tnp = (struct nfsclientpag *)au->exporter;
234 if (tnp->uid && (tnp->uid != (afs_int32)-2)) { /* allow "root" initiators */
235 /* Pag doesn't belong to caller; treat it as an unpaged call too */
237 if (code = setpag(u.u_procp, cred, np->pag, &pag, 1)) { /* XXX u.u_procp is a no-op XXX */
239 if (code = setpag(cred, np->pag, &pag, 1)) {
241 afs_PutNfsClientPag(np);
242 afs_PutUser(au, READ_LOCK);
243 /* ReleaseWriteLock(&afs_xnfsreq); */
244 #if !defined(AFS_SUN5_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SGI64_ENV)
249 afs_nfsexporter->exp_stats.invalidpag++;
253 if (au) afs_PutUser(au, READ_LOCK);
254 au = afs_GetUser(pag, -1, WRITE_LOCK);
255 if (!(au->exporter)) { /* Created new unixuser struct */
256 np->refCount++; /* so it won't disappear */
257 au->exporter = (struct afs_exporter *)np;
260 *outexporter = (struct afs_exporter *)np;
261 afs_PutUser(au, WRITE_LOCK);
263 (*cred)->cr_ruid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
265 (*cred)->cr_rgid = NFSXLATOR_CRED; /* Identify it as nfs xlator call */
267 /* ReleaseWriteLock(&afs_xnfsreq); */
272 /* It's called whenever a new unixuser structure is created for the remote user associated with the nfsclientpag structure, np */
273 int afs_nfsclient_hold(np)
274 register struct nfsclientpag *np;
276 #if defined(AFS_SGIMP_ENV)
277 osi_Assert(ISAFS_GLOCK());
279 AFS_STATCNT(afs_nfsclient_hold);
284 /* 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 */
285 int afs_nfsclient_sysname(np, inname, outname)
286 register struct nfsclientpag *np;
287 char *inname, *outname;
289 #if defined(AFS_SGIMP_ENV)
290 osi_Assert(ISAFS_GLOCK());
292 AFS_STATCNT(afs_nfsclient_sysname);
295 np->sysname = afs_osi_Alloc(MAXSYSNAME);
297 strcpy(np->sysname, inname);
298 } else if (!np->sysname) {
299 return ENODEV; /* XXX */
301 strcpy(outname, np->sysname);
306 /* 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 */
307 int afs_nfsclient_GC(exporter, pag)
308 register struct afs_exporter *exporter;
309 register afs_int32 pag;
311 register struct nfsclientpag *np, **tnp, *nnp;
312 register afs_int32 i, delflag;
314 #if defined(AFS_SGIMP_ENV)
315 osi_Assert(ISAFS_GLOCK());
317 AFS_STATCNT(afs_nfsclient_GC);
318 MObtainWriteLock(&afs_xnfspag,316);
319 for (i = 0; i < NNFSCLIENTS; i++) {
320 for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) {
323 if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC)
325 if ((pag == -1) || (!pag && delflag) || (pag && (np->refCount == 0) && (np->pag == pag))) {
327 if (np->sysname) afs_osi_Free(np->sysname, MAXSYSNAME);
328 afs_osi_Free(np, sizeof(struct nfsclientpag));
334 MReleaseWriteLock(&afs_xnfspag);
338 int afs_nfsclient_stats(export)
339 register struct afs_exporter *export;
341 /* Nothing much to do here yet since most important stats are collected directly in the afs_exporter structure itself */
342 AFS_STATCNT(afs_nfsclient_stats);
347 /* This is exposed so that vop_fid can test it, even if iauth is not
350 extern int afs_iauth_initd;
353 #ifdef AFS_AIX_IAUTH_ENV
354 char *afs_nfs_id = "AFSNFSTRANS";
355 /* afs_iauth_verify is the AFS authenticator for NFS.
359 int afs_iauth_verify(long id, fsid_t *fsidp, long host,
360 int uid, struct AFS_UCRED *credp, struct exportinfo *exp)
363 struct nfsclientpag *nfs_pag;
365 struct afs_exporter *outexporter = 0;
368 /* Still needs basic test to see if exporter is on. And need to check the
369 * whole no submounts bit.
373 return 0; /* not us. */
375 /* Only care if it's AFS */
376 if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) {
381 code = afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp,
382 host, &dummypag, &outexporter);
383 if (!code && outexporter)
384 EXP_RELE(outexporter);
387 /* ensure anonymous cred. */
388 credp->cr_uid = credp->cr_ruid = (uid_t)-2; /* anonymous */
391 /* Mark this thread as an NFS translator thread. */
392 credp->cr_rgid = NFSXLATOR_CRED;
398 /* afs_iauth_register - register the iauth verify routine. Returns 0 on success
399 * and -1 on failure. Can fail because DFS has already registered.
401 int afs_iauth_register()
403 if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify))
411 /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown.
413 void afs_iauth_unregister()
416 nfs_iauth_unregister((unsigned long)afs_nfs_id);
419 #endif /* AFS_AIX_IAUTH_ENV */
424 extern int afs_allnfsreqs, afs_nfscalls;
426 #if defined(AFS_SGIMP_ENV)
427 osi_Assert(ISAFS_GLOCK());
429 AFS_STATCNT(afs_nfsclient_shutdown);
430 #ifdef AFS_AIX_IAUTH_ENV
431 afs_iauth_register();
433 afs_nfsclient_GC(afs_nfsexporter, -1);
434 init_nfsexporter = 0;
435 /* The following are for the nfs/afs server */
436 afs_allnfsreqs = afs_nfscalls = 0;
438 #endif /* AFS_DEC_ENV */
439 #endif /* AFS_NONFSTRANS */