Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / LINUX / osi_nfssrv.c
1 /*
2 * vi:set cin noet sw=4 tw=70:
3 * Copyright 2006, International Business Machines Corporation and others.
4 * All Rights Reserved.
5 *
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
9 */
10
11 /*
12 * Filesystem export operations for Linux
13 */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17
18 #if !defined(AFS_NONFSTRANS) || defined(AFS_AIX_IAUTH_ENV)
19 #include <linux/module.h> /* early to avoid printf->printk mapping */
20 #include <linux/fs.h>
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "nfsclient.h"
24 #include <linux/sunrpc/svc.h>
25 #include <linux/sunrpc/svcauth.h>
26
27 static unsigned long authtab_addr = 0;
28 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
29 module_param(authtab_addr, long, 0);
30 #else
31 MODULE_PARM(authtab_addr, "l");
32 #endif
33 MODULE_PARM_DESC(authtab_addr, "Address of the authtab array.");
34
35 extern struct auth_ops *authtab[] __attribute__((weak));
36 static struct auth_ops **afs_authtab;
37 static struct auth_ops *afs_new_authtab[RPC_AUTH_MAXFLAVOR];
38 static struct auth_ops *afs_orig_authtab[RPC_AUTH_MAXFLAVOR];
39
40 static int whine_memory = 0;
41
42 afs_lock_t afs_xnfssrv;
43
44 struct nfs_server_thread {
45 struct nfs_server_thread *next; /* next in chain */
46 pid_t pid; /* pid of this thread */
47 int active; /* this thread is servicing an RPC */
48 struct sockaddr_in client_addr; /* latest client of this thread */
49 int client_addrlen;
50 afs_int32 uid; /* AFS UID/PAG for this thread */
51 afs_int32 code; /* What should InitReq return? */
52 int flavor; /* auth flavor */
53 uid_t client_uid; /* UID claimed by client */
54 gid_t client_gid; /* GID claimed by client */
55 gid_t client_g0, client_g1; /* groups claimed by client */
56 };
57
58 static struct nfs_server_thread *nfssrv_list = 0;
59
60 static struct nfs_server_thread *find_nfs_thread(int create)
61 {
62 struct nfs_server_thread *this;
63
64 /* Check that this is an nfsd kernel thread */
65 if (current->files != init_task.files || strcmp(current->comm, "nfsd"))
66 return 0;
67
68 ObtainWriteLock(&afs_xnfssrv, 804);
69 for (this = nfssrv_list; this; this = this->next)
70 if (this->pid == current->pid)
71 break;
72 if (!this && create) {
73 this = afs_osi_Alloc(sizeof(struct nfs_server_thread));
74 if (this) {
75 this->next = nfssrv_list;
76 this->pid = current->pid;
77 this->client_addrlen = 0;
78 nfssrv_list = this;
79 printk("afs: added nfsd task %d/%d\n",
80 current->tgid, current->pid);
81 } else if (!whine_memory) {
82 whine_memory = 1;
83 printk("afs: failed to allocate memory for nfsd task %d/%d\n",
84 current->tgid, current->pid);
85 }
86 }
87 ReleaseWriteLock(&afs_xnfssrv);
88 return this;
89 }
90
91 static int
92 svcauth_afs_accept(struct svc_rqst *rqstp, u32 *authp)
93 {
94 struct nfs_server_thread *ns;
95 struct afs_exporter *outexp;
96 afs_ucred_t *credp;
97 struct sockaddr_in *addr;
98 int code;
99
100 code = afs_orig_authtab[rqstp->rq_authop->flavour]->accept(rqstp, authp);
101 if (code != SVC_OK)
102 return code;
103
104 AFS_GLOCK();
105 ns = find_nfs_thread(1);
106 if (!ns) {
107 AFS_GUNLOCK();
108 /* XXX maybe we should fail this with rpc_system_err? */
109 return SVC_OK;
110 }
111 #if HAVE_LINUX_SVC_ADDR_IN
112 addr = svc_addr_in(rqstp);
113 #else
114 addr = &rqstp->rq_addr;
115 #endif
116
117 ns->active = 1;
118 ns->flavor = rqstp->rq_authop->flavour;
119 ns->code = EACCES;
120 ns->client_addr = *addr;
121 ns->client_addrlen = rqstp->rq_addrlen;
122 ns->client_uid = afs_cr_uid(&rqstp->rq_cred);
123 ns->client_gid = afs_cr_gid(&rqstp->rq_cred);
124 if (afs_cr_group_info(&rqstp->rq_cred)->ngroups > 0)
125 ns->client_g0 = GROUP_AT(afs_cr_group_info(&rqstp->rq_cred), 0);
126 else
127 ns->client_g0 = -1;
128 if (afs_cr_group_info(&rqstp->rq_cred)->ngroups > 1)
129 ns->client_g1 = GROUP_AT(afs_cr_group_info(&rqstp->rq_cred), 1);
130 else
131 ns->client_g1 = -1;
132
133 if (addr->sin_family != AF_INET) {
134 printk("afs: NFS request from non-IPv4 client (family %d len %d)\n",
135 addr->sin_family, rqstp->rq_addrlen);
136 goto done;
137 }
138
139 credp = crget();
140 afs_set_cr_uid(credp, afs_cr_uid(&rqstp->rq_cred));
141 afs_set_cr_gid(credp, afs_cr_gid(&rqstp->rq_cred));
142 get_group_info(afs_cr_group_info(&rqstp->rq_cred));
143 afs_set_cr_group_info(credp, afs_cr_group_info(&rqstp->rq_cred));
144
145 /* avoid creating wildcard entries by mapping anonymous
146 * clients to afs_nobody */
147 if (afs_cr_uid(credp) == -1)
148 afs_set_cr_uid(credp, -2);
149 code = afs_nfsclient_reqhandler(0, &credp, addr->sin_addr.s_addr,
150 &ns->uid, &outexp);
151 if (!code && outexp) EXP_RELE(outexp);
152 if (!code) ns->code = 0;
153 if (code)
154 printk("afs: svcauth_afs_accept: afs_nfsclient_reqhandler: %d\n", code);
155 crfree(credp);
156
157 done:
158 AFS_GUNLOCK();
159 return SVC_OK;
160 }
161
162
163 #if 0
164 /* This doesn't work, because they helpfully NULL out rqstp->authop
165 * before calling us, so we have no way to tell what the original
166 * auth flavor was.
167 */
168 static int
169 svcauth_afs_release(struct svc_rqst *rqstp)
170 {
171 struct nfs_server_thread *ns;
172
173 AFS_GLOCK();
174 ns = find_nfs_thread(0);
175 if (ns) ns->active = 0;
176 AFS_GUNLOCK();
177
178 return afs_orig_authtab[rqstp->rq_authop->flavour]->release(rqstp);
179 }
180 #endif
181
182
183 int osi_linux_nfs_initreq(struct vrequest *av, afs_ucred_t *cr, int *code)
184 {
185 struct nfs_server_thread *ns;
186
187 ns = find_nfs_thread(0);
188 if (!ns || !ns->active)
189 return 0;
190
191 *code = ns->code;
192 if (!ns->code) {
193 afs_cr_ruid(cr) = NFSXLATOR_CRED;
194 av->uid = ns->uid;
195 }
196 return 1;
197 }
198
199 void osi_linux_nfssrv_init(void)
200 {
201 int i;
202
203 nfssrv_list = 0;
204 AFS_RWLOCK_INIT(&afs_xnfssrv, "afs_xnfssrv");
205
206 if (authtab && !IS_ERR(authtab))
207 afs_authtab = authtab;
208 else if (authtab_addr) afs_authtab = (struct auth_ops **)authtab_addr;
209 else {
210 printk("Warning: Unable to find the address of authtab\n");
211 printk("NFS Translator hooks will not be installed\n");
212 printk("To correct, specify authtab_addr=<authtab>\n");
213 afs_authtab = 0;
214 return;
215 }
216
217 for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
218 afs_orig_authtab[i] = afs_authtab[i];
219 if (!afs_orig_authtab[i] || afs_orig_authtab[i]->flavour != i ||
220 !try_module_get(afs_orig_authtab[i]->owner)) {
221 afs_orig_authtab[i] = 0;
222 continue;
223 }
224
225 afs_new_authtab[i] = afs_osi_Alloc(sizeof(struct auth_ops));
226 osi_Assert(afs_new_authtab[i] != NULL);
227 *(afs_new_authtab[i]) = *(afs_orig_authtab[i]);
228 afs_new_authtab[i]->owner = THIS_MODULE;
229 afs_new_authtab[i]->accept = svcauth_afs_accept;
230 /* afs_new_authtab[i]->release = svcauth_afs_release; */
231 svc_auth_unregister(i);
232 svc_auth_register(i, afs_new_authtab[i]);
233 }
234 }
235
236 void osi_linux_nfssrv_shutdown(void)
237 {
238 struct nfs_server_thread *next;
239 int i;
240
241 if (afs_authtab) {
242 for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
243 if (!afs_orig_authtab[i])
244 continue;
245 svc_auth_unregister(i);
246 svc_auth_register(i, afs_orig_authtab[i]);
247 module_put(afs_orig_authtab[i]->owner);
248 afs_osi_Free(afs_new_authtab[i], sizeof(struct auth_ops));
249 }
250 }
251
252 AFS_GLOCK();
253 ObtainWriteLock(&afs_xnfssrv, 805);
254 while (nfssrv_list) {
255 next = nfssrv_list->next;
256 afs_osi_Free(nfssrv_list, sizeof(struct nfs_server_thread));
257 nfssrv_list = next;
258 }
259 ReleaseWriteLock(&afs_xnfssrv);
260 AFS_GUNLOCK();
261 }
262 #endif /* AFS_NONFSTRANS */
263