Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
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 | |
8 | */ | |
9 | ||
10 | #include <afsconfig.h> | |
11 | #include "afs/param.h" | |
12 | ||
13 | ||
14 | #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV) | |
15 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
16 | #include "afsincludes.h" /* Afs-based standard headers */ | |
17 | #include "afs/afs_stats.h" /* statistics */ | |
18 | #include "afs/nfsclient.h" | |
19 | #include "rx/rx_globals.h" | |
20 | #include "afs/pagcb.h" | |
21 | ||
22 | void afs_nfsclient_hold(), afs_PutNfsClientPag(), afs_nfsclient_GC(); | |
23 | static void afs_nfsclient_getcreds(); | |
24 | int afs_nfsclient_sysname(), afs_nfsclient_stats(), afs_nfsclient_checkhost(); | |
25 | afs_uint32 afs_nfsclient_gethost(); | |
26 | #ifdef AFS_AIX_IAUTH_ENV | |
27 | int afs_allnfsreqs, afs_nfscalls; | |
28 | #endif | |
29 | ||
30 | /* routines exported to the "AFS exporter" layer */ | |
31 | struct exporterops nfs_exportops = { | |
32 | afs_nfsclient_reqhandler, | |
33 | afs_nfsclient_hold, | |
34 | afs_PutNfsClientPag, /* Used to be afs_nfsclient_rele */ | |
35 | afs_nfsclient_sysname, | |
36 | afs_nfsclient_GC, | |
37 | afs_nfsclient_stats, | |
38 | afs_nfsclient_checkhost, | |
39 | afs_nfsclient_gethost | |
40 | }; | |
41 | ||
42 | ||
43 | struct nfsclientpag *afs_nfspags[NNFSCLIENTS]; | |
44 | afs_lock_t afs_xnfspag /*, afs_xnfsreq */ ; | |
45 | extern struct afs_exporter *afs_nfsexporter; | |
46 | ||
47 | /* Creates an nfsclientpag structure for the (uid, host) pair if one doesn't | |
48 | * exist. RefCount is incremented and it's time stamped. */ | |
49 | static struct nfsclientpag * | |
50 | afs_GetNfsClientPag(afs_int32 uid, afs_uint32 host) | |
51 | { | |
52 | struct nfsclientpag *np; | |
53 | afs_int32 i, now; | |
54 | ||
55 | #if defined(AFS_SGIMP_ENV) | |
56 | osi_Assert(ISAFS_GLOCK()); | |
57 | #endif | |
58 | AFS_STATCNT(afs_GetNfsClientPag); | |
59 | i = NHash(host); | |
60 | now = osi_Time(); | |
61 | ObtainWriteLock(&afs_xnfspag, 314); | |
62 | for (np = afs_nfspags[i]; np; np = np->next) { | |
63 | if (np->uid == uid && np->host == host) { | |
64 | np->refCount++; | |
65 | np->lastcall = now; | |
66 | ReleaseWriteLock(&afs_xnfspag); | |
67 | return np; | |
68 | } | |
69 | } | |
70 | /* next try looking for NOPAG dude, if we didn't find an exact match */ | |
71 | for (np = afs_nfspags[i]; np; np = np->next) { | |
72 | if (np->uid == NOPAG && np->host == host) { | |
73 | np->refCount++; | |
74 | np->lastcall = now; | |
75 | ReleaseWriteLock(&afs_xnfspag); | |
76 | return np; | |
77 | } | |
78 | } | |
79 | np = afs_osi_Alloc(sizeof(struct nfsclientpag)); | |
80 | osi_Assert(np != NULL); | |
81 | memset(np, 0, sizeof(struct nfsclientpag)); | |
82 | /* Copy the necessary afs_exporter fields */ | |
83 | memcpy((char *)np, (char *)afs_nfsexporter, sizeof(struct afs_exporter)); | |
84 | np->next = afs_nfspags[i]; | |
85 | afs_nfspags[i] = np; | |
86 | np->uid = uid; | |
87 | np->host = host; | |
88 | np->refCount = 1; | |
89 | np->lastcall = now; | |
90 | ReleaseWriteLock(&afs_xnfspag); | |
91 | return np; | |
92 | } | |
93 | ||
94 | ||
95 | /* Decrement refCount; must always match a previous afs_FindNfsClientPag/afs_GetNfsClientPag call . | |
96 | It's also called whenever a unixuser structure belonging to the remote user associated with the nfsclientpag structure, np, is garbage collected. */ | |
97 | void | |
98 | afs_PutNfsClientPag(np) | |
99 | struct nfsclientpag *np; | |
100 | { | |
101 | #if defined(AFS_SGIMP_ENV) | |
102 | osi_Assert(ISAFS_GLOCK()); | |
103 | #endif | |
104 | AFS_STATCNT(afs_PutNfsClientPag); | |
105 | --np->refCount; | |
106 | } | |
107 | ||
108 | ||
109 | /* Return the nfsclientpag structure associated with the (uid, host) or | |
110 | * {pag, host} pair, if pag is nonzero. RefCount is incremented and it's | |
111 | * time stamped. */ | |
112 | static struct nfsclientpag * | |
113 | afs_FindNfsClientPag(afs_int32 uid, afs_uint32 host, afs_int32 pag) | |
114 | { | |
115 | struct nfsclientpag *np; | |
116 | afs_int32 i; | |
117 | ||
118 | #if defined(AFS_SGIMP_ENV) | |
119 | osi_Assert(ISAFS_GLOCK()); | |
120 | #endif | |
121 | AFS_STATCNT(afs_FindNfsClientPag); | |
122 | i = NHash(host); | |
123 | ObtainWriteLock(&afs_xnfspag, 315); | |
124 | for (np = afs_nfspags[i]; np; np = np->next) { | |
125 | if (np->host == host) { | |
126 | if ((pag && pag == np->pag) || (!pag && (uid == np->uid))) { | |
127 | np->refCount++; | |
128 | np->lastcall = osi_Time(); | |
129 | ReleaseWriteLock(&afs_xnfspag); | |
130 | return np; | |
131 | } | |
132 | } | |
133 | } | |
134 | /* still not there, try looking for a wildcard dude */ | |
135 | for (np = afs_nfspags[i]; np; np = np->next) { | |
136 | if (np->host == host) { | |
137 | if (np->uid == NOPAG) { | |
138 | np->refCount++; | |
139 | np->lastcall = osi_Time(); | |
140 | ReleaseWriteLock(&afs_xnfspag); | |
141 | return np; | |
142 | } | |
143 | } | |
144 | } | |
145 | ReleaseWriteLock(&afs_xnfspag); | |
146 | return NULL; | |
147 | } | |
148 | ||
149 | ||
150 | /* routine to initialize the exporter, made global so we can call it | |
151 | * from pioctl calls. | |
152 | */ | |
153 | struct afs_exporter *afs_nfsexported = 0; | |
154 | static afs_int32 init_nfsexporter = 0; | |
155 | ||
156 | void | |
157 | afs_nfsclient_init(void) | |
158 | { | |
159 | #if defined(AFS_SGIMP_ENV) | |
160 | osi_Assert(ISAFS_GLOCK()); | |
161 | #endif | |
162 | if (!init_nfsexporter) { | |
163 | extern struct afs_exporter *exporter_add(); | |
164 | ||
165 | init_nfsexporter = 1; | |
166 | LOCK_INIT(&afs_xnfspag, "afs_xnfspag"); | |
167 | afs_nfsexported = | |
168 | exporter_add(0, &nfs_exportops, EXP_EXPORTED, EXP_NFS, NULL); | |
169 | } | |
170 | } | |
171 | ||
172 | ||
173 | /* Main handler routine for the NFS exporter. It's called in the early | |
174 | * phases of any remote call (via the NFS server or pioctl). | |
175 | */ | |
176 | int | |
177 | afs_nfsclient_reqhandler(struct afs_exporter *exporter, | |
178 | afs_ucred_t **cred, | |
179 | afs_uint32 host, afs_int32 *pagparam, | |
180 | struct afs_exporter **outexporter) | |
181 | { | |
182 | struct nfsclientpag *np, *tnp; | |
183 | extern struct unixuser *afs_FindUser(), *afs_GetUser(); | |
184 | struct unixuser *au = 0; | |
185 | afs_int32 uid, pag, code = 0; | |
186 | ||
187 | AFS_ASSERT_GLOCK(); | |
188 | AFS_STATCNT(afs_nfsclient_reqhandler); | |
189 | if (!afs_nfsexporter) | |
190 | afs_nfsexporter = afs_nfsexported; | |
191 | ||
192 | afs_nfsexporter->exp_stats.calls++; | |
193 | if (!(afs_nfsexporter->exp_states & EXP_EXPORTED)) { | |
194 | /* No afs requests accepted as long as EXPORTED flag is turned 'off'. | |
195 | * Set/Reset via a pioctl call (fs exportafs). Note that this is on | |
196 | * top of the /etc/exports nfs requirement (i.e. /afs must be | |
197 | * exported to all or whomever there too!) | |
198 | */ | |
199 | afs_nfsexporter->exp_stats.rejectedcalls++; | |
200 | return EINVAL; | |
201 | } | |
202 | /* ObtainWriteLock(&afs_xnfsreq); */ | |
203 | pag = PagInCred(*cred); | |
204 | #if defined(AFS_SUN510_ENV) | |
205 | uid = crgetuid(*cred); | |
206 | #else | |
207 | uid = afs_cr_uid(*cred); | |
208 | #endif | |
209 | /* Do this early, so pag management knows */ | |
210 | afs_set_cr_rgid(*cred, NFSXLATOR_CRED); /* Identify it as nfs xlator call */ | |
211 | if ((afs_nfsexporter->exp_states & EXP_CLIPAGS) && pag != NOPAG) { | |
212 | uid = pag; | |
213 | } else if (pag != NOPAG) { | |
214 | /* Do some minimal pag verification */ | |
215 | if (pag > getpag()) { | |
216 | pag = NOPAG; /* treat it as not paged since couldn't be good */ | |
217 | } else { | |
218 | if ((au = afs_FindUser(pag, -1, READ_LOCK))) { | |
219 | if (!au->exporter) { | |
220 | pag = NOPAG; | |
221 | afs_PutUser(au, READ_LOCK); | |
222 | au = NULL; | |
223 | } | |
224 | } else | |
225 | pag = NOPAG; /* No unixuser struct so pag not trusted */ | |
226 | } | |
227 | } | |
228 | np = afs_FindNfsClientPag(uid, host, 0); | |
229 | afs_Trace4(afs_iclSetp, CM_TRACE_NFSREQH, ICL_TYPE_INT32, pag, | |
230 | ICL_TYPE_LONG, afs_cr_uid(*cred), ICL_TYPE_INT32, host, | |
231 | ICL_TYPE_POINTER, np); | |
232 | /* If remote-pags are enabled, we are no longer interested in what PAG | |
233 | * they claimed, and from here on we should behave as if they claimed | |
234 | * none at all, which is to say we use the (local) pag named in the | |
235 | * nfsclientpag structure (if any). This is deferred until here so | |
236 | * that we can log the PAG they claimed. | |
237 | */ | |
238 | if ((afs_nfsexporter->exp_states & EXP_CLIPAGS)) | |
239 | pag = NOPAG; | |
240 | if (!np) { | |
241 | /* Even if there is a "good" pag coming in we don't accept it if no | |
242 | * nfsclientpag struct exists for the user since that would mean | |
243 | * that the translator rebooted and therefore we ignore all older | |
244 | * pag values | |
245 | */ | |
246 | if ((code = setpag(cred, -1, &pag, 0))) { | |
247 | if (au) | |
248 | afs_PutUser(au, READ_LOCK); | |
249 | /* ReleaseWriteLock(&afs_xnfsreq); */ | |
250 | #if defined(KERNEL_HAVE_UERROR) | |
251 | setuerror(code); | |
252 | #endif | |
253 | return (code); | |
254 | } | |
255 | np = afs_GetNfsClientPag(uid, host); | |
256 | np->pag = pag; | |
257 | np->client_uid = afs_cr_uid(*cred); | |
258 | } else { | |
259 | if (pag == NOPAG) { | |
260 | if ((code = setpag(cred, np->pag, &pag, 0))) { | |
261 | afs_PutNfsClientPag(np); | |
262 | /* ReleaseWriteLock(&afs_xnfsreq); */ | |
263 | #if defined(KERNEL_HAVE_UERROR) | |
264 | setuerror(code); | |
265 | #endif | |
266 | return (code); | |
267 | } | |
268 | } else if (au->exporter | |
269 | && ((struct afs_exporter *)np != au->exporter)) { | |
270 | tnp = (struct nfsclientpag *)au->exporter; | |
271 | if (tnp->uid && (tnp->uid != (afs_int32) - 2)) { /* allow "root" initiators */ | |
272 | /* Pag doesn't belong to caller; treat it as an unpaged call too */ | |
273 | if ((code = setpag(cred, np->pag, &pag, 0))) { | |
274 | afs_PutNfsClientPag(np); | |
275 | afs_PutUser(au, READ_LOCK); | |
276 | /* ReleaseWriteLock(&afs_xnfsreq); */ | |
277 | #if defined(KERNEL_HAVE_UERROR) | |
278 | setuerror(code); | |
279 | #endif | |
280 | return (code); | |
281 | } | |
282 | afs_nfsexporter->exp_stats.invalidpag++; | |
283 | } | |
284 | } | |
285 | } | |
286 | if (au) | |
287 | afs_PutUser(au, READ_LOCK); | |
288 | /* do not get a lock on au; afs_nfsclient_getcreds may write-lock the | |
289 | * same unixuser */ | |
290 | au = afs_GetUser(pag, -1, 0); | |
291 | if (!(au->exporter)) { /* Created new unixuser struct */ | |
292 | np->refCount++; /* so it won't disappear */ | |
293 | au->exporter = (struct afs_exporter *)np; | |
294 | if ((afs_nfsexporter->exp_states & EXP_CALLBACK)) | |
295 | afs_nfsclient_getcreds(au); | |
296 | } else while (au->states & UNFSGetCreds) { | |
297 | afs_osi_Sleep((void *)au); | |
298 | } | |
299 | *pagparam = pag; | |
300 | *outexporter = (struct afs_exporter *)np; | |
301 | afs_PutUser(au, 0); | |
302 | /* ReleaseWriteLock(&afs_xnfsreq); */ | |
303 | return 0; | |
304 | } | |
305 | ||
306 | void | |
307 | afs_nfsclient_getcreds(struct unixuser *au) | |
308 | { | |
309 | struct nfsclientpag *np = (struct nfsclientpag *)(au->exporter); | |
310 | struct rx_securityClass *csec; | |
311 | struct rx_connection *tconn; | |
312 | union tokenUnion *tokenPtr; | |
313 | struct rxkadToken *token; | |
314 | SysNameList tsysnames; | |
315 | CredInfos tcreds; | |
316 | CredInfo *tcred; | |
317 | struct unixuser *tu; | |
318 | struct cell *tcell; | |
319 | int code, i, cellnum; | |
320 | ||
321 | au->states |= UNFSGetCreds; | |
322 | memset(&tcreds, 0, sizeof(tcreds)); | |
323 | memset(&tsysnames, 0, sizeof(tsysnames)); | |
324 | ||
325 | /* Get a connection */ | |
326 | /* This sucks a little. We should cache the connections or something. | |
327 | * But at this point I don't yet think it's worth the effort. | |
328 | */ | |
329 | csec = rxnull_NewClientSecurityObject(); | |
330 | AFS_GUNLOCK(); | |
331 | tconn = rx_NewConnection(np->host, htons(7001), PAGCB_SERVICEID, csec, 0); | |
332 | AFS_GLOCK(); | |
333 | ||
334 | /* Get the sysname, if needed */ | |
335 | if (!np->sysnamecount) { | |
336 | AFS_GUNLOCK(); | |
337 | code = PAGCB_GetSysName(tconn, np->uid, &tsysnames); | |
338 | AFS_GLOCK(); | |
339 | if (code || | |
340 | tsysnames.SysNameList_len <= 0 || | |
341 | tsysnames.SysNameList_len > MAXNUMSYSNAMES) | |
342 | goto done; | |
343 | ||
344 | for(i = 0; i < np->sysnamecount; i++) | |
345 | afs_osi_Free(np->sysname[i], MAXSYSNAME); | |
346 | ||
347 | np->sysnamecount = tsysnames.SysNameList_len; | |
348 | for(i = 0; i < np->sysnamecount; i++) | |
349 | np->sysname[i] = tsysnames.SysNameList_val[i].sysname; | |
350 | afs_osi_Free(tsysnames.SysNameList_val, | |
351 | tsysnames.SysNameList_len * sizeof(SysNameEnt)); | |
352 | } | |
353 | ||
354 | /* Get credentials */ | |
355 | AFS_GUNLOCK(); | |
356 | code = PAGCB_GetCreds(tconn, np->uid, &tcreds); | |
357 | AFS_GLOCK(); | |
358 | if (code) | |
359 | goto done; | |
360 | ||
361 | /* Now, set the credentials they gave us... */ | |
362 | for (i = 0; i < tcreds.CredInfos_len; i++) { | |
363 | tcred = &tcreds.CredInfos_val[i]; | |
364 | ||
365 | /* Find the cell. If it is unknown to us, punt this entry. */ | |
366 | tcell = afs_GetCellByName(tcred->cellname, READ_LOCK); | |
367 | afs_osi_Free(tcred->cellname, strlen(tcred->cellname) + 1); | |
368 | if (!tcell) { | |
369 | memset(tcred->ct.HandShakeKey, 0, 8); | |
370 | memset(tcred->st.st_val, 0, tcred->st.st_len); | |
371 | afs_osi_Free(tcred->st.st_val, tcred->st.st_len); | |
372 | continue; | |
373 | } | |
374 | cellnum = tcell->cellNum; | |
375 | afs_PutCell(tcell, READ_LOCK); | |
376 | ||
377 | /* Find the appropriate unixuser. This might be the same as | |
378 | * the one we were passed (au), but that's OK. | |
379 | */ | |
380 | tu = afs_GetUser(np->pag, cellnum, WRITE_LOCK); | |
381 | if (!(tu->exporter)) { /* Created new unixuser struct */ | |
382 | np->refCount++; /* so it won't disappear */ | |
383 | tu->exporter = (struct afs_exporter *)np; | |
384 | } | |
385 | ||
386 | afs_FreeTokens(&tu->tokens); | |
387 | ||
388 | /* Add a new rxkad token. Using the afs_AddRxkadToken interface | |
389 | * would require another copy, so we do this the hard way */ | |
390 | tokenPtr = afs_AddToken(&tu->tokens, 2); | |
391 | token = &tokenPtr->rxkad; | |
392 | token->ticket = tcred->st.st_val; | |
393 | token->ticketLen = tcred->st.st_len; | |
394 | ||
395 | /* copy the clear token */ | |
396 | memset(&token->clearToken, 0, sizeof(token->clearToken)); | |
397 | memcpy(token->clearToken.HandShakeKey, tcred->ct.HandShakeKey, 8); | |
398 | memset(tcred->ct.HandShakeKey, 0, 8); | |
399 | token->clearToken.AuthHandle = tcred->ct.AuthHandle; | |
400 | token->clearToken.ViceId = tcred->ct.ViceId; | |
401 | token->clearToken.BeginTimestamp = tcred->ct.BeginTimestamp; | |
402 | token->clearToken.EndTimestamp = tcred->ct.EndTimestamp; | |
403 | ||
404 | /* Set everything else, reset connections, and move on. */ | |
405 | tu->viceId = tcred->vid; | |
406 | tu->states |= UHasTokens; | |
407 | tu->states &= ~UTokensBad; | |
408 | afs_SetPrimary(tu, !!(tcred->states & UPrimary)); | |
409 | tu->tokenTime = osi_Time(); | |
410 | afs_ResetUserConns(tu); | |
411 | afs_PutUser(tu, WRITE_LOCK); | |
412 | } | |
413 | afs_osi_Free(tcreds.CredInfos_val, tcreds.CredInfos_len * sizeof(CredInfo)); | |
414 | ||
415 | done: | |
416 | AFS_GUNLOCK(); | |
417 | rx_DestroyConnection(tconn); | |
418 | AFS_GLOCK(); | |
419 | au->states &= ~UNFSGetCreds; | |
420 | afs_osi_Wakeup((void *)au); | |
421 | } | |
422 | ||
423 | ||
424 | /* It's called whenever a new unixuser structure is created for the remote | |
425 | * user associated with the nfsclientpag structure, np */ | |
426 | void | |
427 | afs_nfsclient_hold(struct nfsclientpag *np) | |
428 | { | |
429 | #if defined(AFS_SGIMP_ENV) | |
430 | osi_Assert(ISAFS_GLOCK()); | |
431 | #endif | |
432 | AFS_STATCNT(afs_nfsclient_hold); | |
433 | np->refCount++; | |
434 | } | |
435 | ||
436 | ||
437 | /* check if this exporter corresponds to the specified host */ | |
438 | int | |
439 | afs_nfsclient_checkhost(struct nfsclientpag *np, afs_uint32 host) | |
440 | { | |
441 | if (np->type != EXP_NFS) | |
442 | return 0; | |
443 | return np->host == host; | |
444 | } | |
445 | ||
446 | ||
447 | /* get the host for this exporter, or 0 if there is an error */ | |
448 | afs_uint32 | |
449 | afs_nfsclient_gethost(struct nfsclientpag *np) | |
450 | { | |
451 | if (np->type != EXP_NFS) | |
452 | return 0; | |
453 | return np->host; | |
454 | } | |
455 | ||
456 | ||
457 | /* if inname is non-null, a new system name value is set for the remote | |
458 | * user (inname contains the new sysname). In all cases, outname returns | |
459 | * the current sysname value for this remote user */ | |
460 | int | |
461 | afs_nfsclient_sysname(struct nfsclientpag *np, char *inname, | |
462 | char ***outname, int *num, int allpags) | |
463 | { | |
464 | struct nfsclientpag *tnp; | |
465 | afs_int32 i; | |
466 | char *cp; | |
467 | int count, t; | |
468 | #if defined(AFS_SGIMP_ENV) | |
469 | osi_Assert(ISAFS_GLOCK()); | |
470 | #endif | |
471 | AFS_STATCNT(afs_nfsclient_sysname); | |
472 | if (allpags > 0) { | |
473 | /* update every client, not just the one making the request */ | |
474 | i = NHash(np->host); | |
475 | ObtainWriteLock(&afs_xnfspag, 315); | |
476 | for (tnp = afs_nfspags[i]; tnp; tnp = tnp->next) { | |
477 | if (tnp != np && tnp->host == np->host) | |
478 | afs_nfsclient_sysname(tnp, inname, outname, num, -1); | |
479 | } | |
480 | ReleaseWriteLock(&afs_xnfspag); | |
481 | } | |
482 | if (inname) { | |
483 | for(count=0; count < np->sysnamecount;++count) { | |
484 | afs_osi_Free(np->sysname[count], MAXSYSNAME); | |
485 | np->sysname[count] = NULL; | |
486 | } | |
487 | for(count=0; count < *num;++count) { | |
488 | np->sysname[count]= afs_osi_Alloc(MAXSYSNAME); | |
489 | osi_Assert(np->sysname[count] != NULL); | |
490 | } | |
491 | cp = inname; | |
492 | for(count=0; count < *num;++count) { | |
493 | t = strlen(cp); | |
494 | memcpy(np->sysname[count], cp, t+1); /* include null */ | |
495 | cp += t+1; | |
496 | } | |
497 | np->sysnamecount = *num; | |
498 | } | |
499 | if (allpags >= 0) { | |
500 | /* Don't touch our arguments when called recursively */ | |
501 | *outname = np->sysname; | |
502 | *num = np->sysnamecount; | |
503 | if (!np->sysname[0]) | |
504 | return ENODEV; /* XXX */ | |
505 | } | |
506 | return 0; | |
507 | } | |
508 | ||
509 | ||
510 | /* Garbage collect routine for the nfs exporter. When pag is -1 then all | |
511 | * entries are removed (used by the nfsclient_shutdown routine); else if | |
512 | * it's non zero then only the entry with that pag is removed, else all | |
513 | * "timedout" entries are removed. TimedOut entries are those who have no | |
514 | * "unixuser" structures associated with them (i.e. unixusercnt == 0) and | |
515 | * they haven't had any activity the last NFSCLIENTGC seconds */ | |
516 | void | |
517 | afs_nfsclient_GC(struct afs_exporter *exporter, | |
518 | afs_int32 pag) | |
519 | { | |
520 | struct nfsclientpag *np, **tnp, *nnp; | |
521 | afs_int32 i, delflag; | |
522 | int count; | |
523 | ||
524 | #if defined(AFS_SGIMP_ENV) | |
525 | osi_Assert(ISAFS_GLOCK()); | |
526 | #endif | |
527 | AFS_STATCNT(afs_nfsclient_GC); | |
528 | ObtainWriteLock(&afs_xnfspag, 316); | |
529 | for (i = 0; i < NNFSCLIENTS; i++) { | |
530 | for (tnp = &afs_nfspags[i], np = *tnp; np; np = nnp) { | |
531 | nnp = np->next; | |
532 | delflag = 0; | |
533 | if (np->refCount == 0 && np->lastcall < osi_Time() - NFSCLIENTGC) | |
534 | delflag = 1; | |
535 | if ((pag == -1) || (!pag && delflag) | |
536 | || (pag && (np->refCount == 0) && (np->pag == pag))) { | |
537 | *tnp = np->next; | |
538 | for(count=0; count < np->sysnamecount;++count) { | |
539 | afs_osi_Free(np->sysname[count], MAXSYSNAME); | |
540 | } | |
541 | afs_osi_Free(np, sizeof(struct nfsclientpag)); | |
542 | } else { | |
543 | tnp = &np->next; | |
544 | } | |
545 | } | |
546 | } | |
547 | ReleaseWriteLock(&afs_xnfspag); | |
548 | } | |
549 | ||
550 | ||
551 | int | |
552 | afs_nfsclient_stats(struct afs_exporter *export) | |
553 | { | |
554 | /* Nothing much to do here yet since most important stats are collected | |
555 | * directly in the afs_exporter structure itself */ | |
556 | AFS_STATCNT(afs_nfsclient_stats); | |
557 | return 0; | |
558 | } | |
559 | ||
560 | #ifdef AFS_AIX41_ENV | |
561 | /* This is exposed so that vop_fid can test it, even if iauth is not | |
562 | * installed. | |
563 | */ | |
564 | extern int afs_iauth_initd; | |
565 | #endif | |
566 | ||
567 | #ifdef AFS_AIX_IAUTH_ENV | |
568 | char *afs_nfs_id = "AFSNFSTRANS"; | |
569 | /* afs_iauth_verify is the AFS authenticator for NFS. | |
570 | * | |
571 | * always returns 0. | |
572 | */ | |
573 | int | |
574 | afs_iauth_verify(long id, fsid_t * fsidp, long host, int uid, | |
575 | afs_ucred_t *credp, struct exportinfo *exp) | |
576 | { | |
577 | int code; | |
578 | struct nfsclientpag *nfs_pag; | |
579 | afs_int32 dummypag; | |
580 | struct afs_exporter *outexporter = 0; | |
581 | ||
582 | ||
583 | /* Still needs basic test to see if exporter is on. And need to check the | |
584 | * whole no submounts bit. | |
585 | */ | |
586 | ||
587 | if (id != (long)id) | |
588 | return 0; /* not us. */ | |
589 | ||
590 | /* Only care if it's AFS */ | |
591 | if ((fsidp->val[0] != AFS_VFSMAGIC) || (fsidp->val[1] != AFS_VFSFSID)) { | |
592 | return 0; | |
593 | } | |
594 | ||
595 | AFS_GLOCK(); | |
596 | code = | |
597 | afs_nfsclient_reqhandler((struct afs_exporter *)0, &credp, host, | |
598 | &dummypag, &outexporter); | |
599 | if (!code && outexporter) | |
600 | EXP_RELE(outexporter); | |
601 | ||
602 | if (code) { | |
603 | /* ensure anonymous cred. */ | |
604 | afs_set_cr_uid(credp, (uid_t) -2; /* anonymous */ | |
605 | afs_set_cr_ruid(credp, (uid_t) -2; | |
606 | } | |
607 | ||
608 | /* Mark this thread as an NFS translator thread. */ | |
609 | afs_set_cr_rgid(credp, NFSXLATOR_CRED); | |
610 | ||
611 | AFS_GUNLOCK(); | |
612 | return 0; | |
613 | } | |
614 | ||
615 | /* afs_iauth_register - register the iauth verify routine. Returns 0 on success | |
616 | * and -1 on failure. Can fail because DFS has already registered. | |
617 | */ | |
618 | int | |
619 | afs_iauth_register(void) | |
620 | { | |
621 | if (nfs_iauth_register((unsigned long)afs_nfs_id, afs_iauth_verify)) | |
622 | return -1; | |
623 | else { | |
624 | afs_iauth_initd = 1; | |
625 | return 0; | |
626 | } | |
627 | } | |
628 | ||
629 | /* afs_iauth_unregister - unregister the iauth verify routine. Called on shutdown. | |
630 | */ | |
631 | void | |
632 | afs_iauth_unregister(void) | |
633 | { | |
634 | if (afs_iauth_initd) | |
635 | nfs_iauth_unregister((unsigned long)afs_nfs_id); | |
636 | afs_iauth_initd = 0; | |
637 | } | |
638 | #endif /* AFS_AIX_IAUTH_ENV */ | |
639 | ||
640 | ||
641 | ||
642 | void | |
643 | shutdown_nfsclnt(void) | |
644 | { | |
645 | #if defined(AFS_SGIMP_ENV) | |
646 | osi_Assert(ISAFS_GLOCK()); | |
647 | #endif | |
648 | AFS_STATCNT(afs_nfsclient_shutdown); | |
649 | #ifdef AFS_AIX_IAUTH_ENV | |
650 | afs_iauth_register(); | |
651 | #endif | |
652 | afs_nfsclient_GC(afs_nfsexporter, -1); | |
653 | init_nfsexporter = 0; | |
654 | } | |
655 | #endif /* AFS_NONFSTRANS */ |