57be4bb74d34afb0b2bc3e0407d799c8948f46ae
[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 #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>
27
28 static unsigned long authtab_addr = 0;
29 MODULE_PARM(authtab_addr, "l");
30 MODULE_PARM_DESC(authtab_addr, "Address of the authtab array.");
31
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];
36
37 static int whine_memory = 0;
38
39 afs_lock_t afs_xnfssrv;
40
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 */
46     int client_addrlen;
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 */
53 };
54
55 static struct nfs_server_thread *nfssrv_list = 0;
56
57 static struct nfs_server_thread *find_nfs_thread(int create)
58 {
59     struct nfs_server_thread *this;
60
61     /* Check that this is an nfsd kernel thread */
62     if (current->files != init_task.files || strcmp(current->comm, "nfsd"))
63         return 0;
64
65     ObtainWriteLock(&afs_xnfssrv, 804);
66     for (this = nfssrv_list; this; this = this->next)
67         if (this->pid == current->pid)
68             break;
69     if (!this && create) {
70         this = afs_osi_Alloc(sizeof(struct nfs_server_thread));
71         if (this) {
72             this->next = nfssrv_list;
73             this->pid  = current->pid;
74             this->client_addrlen = 0;
75             nfssrv_list = this;
76             printk("afs: added nfsd task %d/%d\n",
77                    current->tgid, current->pid);
78         } else if (!whine_memory) {
79             whine_memory = 1;
80             printk("afs: failed to allocate memory for nfsd task %d/%d\n",
81                    current->tgid, current->pid);
82         }
83     }
84     ReleaseWriteLock(&afs_xnfssrv);
85     return this;
86 }
87
88 static int
89 svcauth_afs_accept(struct svc_rqst *rqstp, u32 *authp)
90 {
91     struct nfs_server_thread *ns;
92     struct afs_exporter *outexp;
93     struct AFS_UCRED *credp;
94     int code;
95
96     code = afs_orig_authtab[rqstp->rq_authop->flavour]->accept(rqstp, authp);
97     if (code != SVC_OK)
98         return code;
99
100     AFS_GLOCK();
101     ns = find_nfs_thread(1);
102     if (!ns) {
103         AFS_GUNLOCK();
104         /* XXX maybe we should fail this with rpc_system_err? */
105         return SVC_OK;
106     }
107
108     ns->active          = 1;
109     ns->flavor          = rqstp->rq_authop->flavour;
110     ns->code            = EACCES;
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);
117     else
118         ns->client_g0   = -1;
119     if (rqstp->rq_cred.cr_group_info->ngroups > 1)
120         ns->client_g1   = GROUP_AT(rqstp->rq_cred.cr_group_info, 1);
121     else
122         ns->client_g1   = -1;
123
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);
128         goto done;
129     }
130
131     credp = crget();
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;
136
137     /* avoid creating wildcard entries by mapping anonymous
138      * clients to afs_nobody */
139     if (credp->cr_uid == -1)
140         credp->cr_uid = -2;
141     code = afs_nfsclient_reqhandler(0, &credp, rqstp->rq_addr.sin_addr.s_addr,
142                                     &ns->uid, &outexp);
143     if (!code && outexp) EXP_RELE(outexp);
144     if (!code) ns->code = 0;
145     if (code)
146         printk("afs: svcauth_afs_accept: afs_nfsclient_reqhandler: %d\n", code);
147     crfree(credp);
148
149 done:
150     AFS_GUNLOCK();
151     return SVC_OK;
152 }
153
154
155 #if 0
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
158  * auth flavor was.
159  */
160 static int
161 svcauth_afs_release(struct svc_rqst *rqstp)
162 {
163     struct nfs_server_thread *ns;
164
165     AFS_GLOCK();
166     ns = find_nfs_thread(0);
167     if (ns) ns->active = 0;
168     AFS_GUNLOCK();
169
170     return afs_orig_authtab[rqstp->rq_authop->flavour]->release(rqstp);
171 }
172 #endif
173
174
175 int osi_linux_nfs_initreq(struct vrequest *av, struct AFS_UCRED *cr, int *code)
176 {
177     struct nfs_server_thread *ns;
178
179     ns = find_nfs_thread(0);
180     if (!ns || !ns->active)
181         return 0;
182
183     *code = ns->code;
184     if (!ns->code) {
185         cr->cr_ruid = NFSXLATOR_CRED;
186         av->uid = ns->uid;
187     }
188     return 1;
189 }
190
191 void osi_linux_nfssrv_init(void)
192 {
193     int i;
194
195     nfssrv_list = 0;
196     RWLOCK_INIT(&afs_xnfssrv, "afs_xnfssrv");
197
198     if (authtab)           afs_authtab = authtab;
199     else if (authtab_addr) afs_authtab = (struct auth_ops **)authtab_addr;
200     else {
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");
204         afs_authtab = 0;
205         return;
206     }
207
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;
213             continue;
214         }
215
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]);
223     }
224 }
225
226 void osi_linux_nfssrv_shutdown(void)
227 {
228     struct nfs_server_thread *next;
229     int i;
230
231     if (afs_authtab) {
232         for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
233             if (!afs_orig_authtab[i])
234                 continue;
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));
239         }
240     }
241
242     AFS_GLOCK();
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));
247         nfssrv_list = next;
248     }
249     ReleaseWriteLock(&afs_xnfssrv);
250     AFS_GUNLOCK();
251 }