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