2 * vi:set cin noet sw=4 tw=70:
3 * Copyright 2006, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
12 * Filesystem export operations for Linux
14 #include <afsconfig.h>
15 #include "afs/param.h"
20 #include <linux/module.h> /* early to avoid printf->printk mapping */
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "nfsclient.h"
24 #include "h/smp_lock.h"
25 #include <linux/sunrpc/svc.h>
26 #include <linux/sunrpc/svcauth.h>
28 static unsigned long authtab_addr = 0;
29 MODULE_PARM(authtab_addr, "l");
30 MODULE_PARM_DESC(authtab_addr, "Address of the authtab array.");
32 extern struct auth_ops *authtab[] __attribute__((weak));
33 static struct auth_ops **afs_authtab;
34 static struct auth_ops *afs_new_authtab[RPC_AUTH_MAXFLAVOR];
35 static struct auth_ops *afs_orig_authtab[RPC_AUTH_MAXFLAVOR];
37 static int whine_memory = 0;
39 afs_lock_t afs_xnfssrv;
41 struct nfs_server_thread {
42 struct nfs_server_thread *next; /* next in chain */
43 pid_t pid; /* pid of this thread */
44 int active; /* this thread is servicing an RPC */
45 struct sockaddr_in client_addr; /* latest client of this thread */
47 afs_int32 uid; /* AFS UID/PAG for this thread */
48 afs_int32 code; /* What should InitReq return? */
49 int flavor; /* auth flavor */
50 uid_t client_uid; /* UID claimed by client */
51 gid_t client_gid; /* GID claimed by client */
52 gid_t client_g0, client_g1; /* groups claimed by client */
55 static struct nfs_server_thread *nfssrv_list = 0;
57 static struct nfs_server_thread *find_nfs_thread(int create)
59 struct nfs_server_thread *this;
61 /* Check that this is an nfsd kernel thread */
62 if (current->files != init_task.files || strcmp(current->comm, "nfsd"))
65 ObtainWriteLock(&afs_xnfssrv, 804);
66 for (this = nfssrv_list; this; this = this->next)
67 if (this->pid == current->pid)
69 if (!this && create) {
70 this = afs_osi_Alloc(sizeof(struct nfs_server_thread));
72 this->next = nfssrv_list;
73 this->pid = current->pid;
74 this->client_addrlen = 0;
76 printk("afs: added nfsd task %d/%d\n",
77 current->tgid, current->pid);
78 } else if (!whine_memory) {
80 printk("afs: failed to allocate memory for nfsd task %d/%d\n",
81 current->tgid, current->pid);
84 ReleaseWriteLock(&afs_xnfssrv);
89 svcauth_afs_accept(struct svc_rqst *rqstp, u32 *authp)
91 struct nfs_server_thread *ns;
92 struct afs_exporter *outexp;
93 struct AFS_UCRED *credp;
96 code = afs_orig_authtab[rqstp->rq_authop->flavour]->accept(rqstp, authp);
101 ns = find_nfs_thread(1);
104 /* XXX maybe we should fail this with rpc_system_err? */
109 ns->flavor = rqstp->rq_authop->flavour;
111 ns->client_addr = rqstp->rq_addr;
112 ns->client_addrlen = rqstp->rq_addrlen;
113 ns->client_uid = rqstp->rq_cred.cr_uid;
114 ns->client_gid = rqstp->rq_cred.cr_gid;
115 if (rqstp->rq_cred.cr_group_info->ngroups > 0)
116 ns->client_g0 = GROUP_AT(rqstp->rq_cred.cr_group_info, 0);
119 if (rqstp->rq_cred.cr_group_info->ngroups > 1)
120 ns->client_g1 = GROUP_AT(rqstp->rq_cred.cr_group_info, 1);
124 /* NB: Don't check the length; it's not always filled in! */
125 if (rqstp->rq_addr.sin_family != AF_INET) {
126 printk("afs: NFS request from non-IPv4 client (family %d len %d)\n",
127 rqstp->rq_addr.sin_family, rqstp->rq_addrlen);
132 credp->cr_uid = rqstp->rq_cred.cr_uid;
133 credp->cr_gid = rqstp->rq_cred.cr_gid;
134 get_group_info(rqstp->rq_cred.cr_group_info);
135 credp->cr_group_info = rqstp->rq_cred.cr_group_info;
137 /* avoid creating wildcard entries by mapping anonymous
138 * clients to afs_nobody */
139 if (credp->cr_uid == -1)
141 code = afs_nfsclient_reqhandler(0, &credp, rqstp->rq_addr.sin_addr.s_addr,
143 if (!code && outexp) EXP_RELE(outexp);
144 if (!code) ns->code = 0;
146 printk("afs: svcauth_afs_accept: afs_nfsclient_reqhandler: %d\n", code);
156 /* This doesn't work, because they helpfully NULL out rqstp->authop
157 * before calling us, so we have no way to tell what the original
161 svcauth_afs_release(struct svc_rqst *rqstp)
163 struct nfs_server_thread *ns;
166 ns = find_nfs_thread(0);
167 if (ns) ns->active = 0;
170 return afs_orig_authtab[rqstp->rq_authop->flavour]->release(rqstp);
175 int osi_linux_nfs_initreq(struct vrequest *av, struct AFS_UCRED *cr, int *code)
177 struct nfs_server_thread *ns;
179 ns = find_nfs_thread(0);
180 if (!ns || !ns->active)
185 cr->cr_ruid = NFSXLATOR_CRED;
191 void osi_linux_nfssrv_init(void)
196 RWLOCK_INIT(&afs_xnfssrv, "afs_xnfssrv");
198 if (authtab) afs_authtab = authtab;
199 else if (authtab_addr) afs_authtab = (struct auth_ops **)authtab_addr;
201 printk("Warning: Unable to find the address of authtab\n");
202 printk("NFS Translator hooks will not be installed\n");
203 printk("To correct, specify authtab_addr=<authtab>\n");
208 for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
209 afs_orig_authtab[i] = afs_authtab[i];
210 if (!afs_orig_authtab[i] || afs_orig_authtab[i]->flavour != i ||
211 !try_module_get(afs_orig_authtab[i]->owner)) {
212 afs_orig_authtab[i] = 0;
216 afs_new_authtab[i] = afs_osi_Alloc(sizeof(struct auth_ops));
217 *(afs_new_authtab[i]) = *(afs_orig_authtab[i]);
218 afs_new_authtab[i]->owner = THIS_MODULE;
219 afs_new_authtab[i]->accept = svcauth_afs_accept;
220 /* afs_new_authtab[i]->release = svcauth_afs_release; */
221 svc_auth_unregister(i);
222 svc_auth_register(i, afs_new_authtab[i]);
226 void osi_linux_nfssrv_shutdown(void)
228 struct nfs_server_thread *next;
232 for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
233 if (!afs_orig_authtab[i])
235 svc_auth_unregister(i);
236 svc_auth_register(i, afs_orig_authtab[i]);
237 module_put(afs_orig_authtab[i]->owner);
238 afs_osi_Free(afs_new_authtab[i], sizeof(struct auth_ops));
243 ObtainWriteLock(&afs_xnfssrv, 805);
244 while (nfssrv_list) {
245 next = nfssrv_list->next;
246 afs_osi_Free(nfssrv_list, sizeof(struct nfs_server_thread));
249 ReleaseWriteLock(&afs_xnfssrv);