Cleanup usage of LINUX_VERSION_CODE for older kernels
[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 module_param(authtab_addr, long, 0);
29 MODULE_PARM_DESC(authtab_addr, "Address of the authtab array.");
30
31 extern struct auth_ops *authtab[] __attribute__((weak));
32 static struct auth_ops **afs_authtab;
33 static struct auth_ops *afs_new_authtab[RPC_AUTH_MAXFLAVOR];
34 static struct auth_ops *afs_orig_authtab[RPC_AUTH_MAXFLAVOR];
35
36 static int whine_memory = 0;
37
38 afs_lock_t afs_xnfssrv;
39
40 struct nfs_server_thread {
41     struct nfs_server_thread *next;     /* next in chain */
42     pid_t pid;                          /* pid of this thread */
43     int active;                         /* this thread is servicing an RPC */
44     struct sockaddr_in client_addr;     /* latest client of this thread */
45     int client_addrlen;
46     afs_int32 uid;                      /* AFS UID/PAG for this thread */
47     afs_int32 code;                     /* What should InitReq return? */
48     int flavor;                         /* auth flavor */
49     uid_t client_uid;                   /* UID claimed by client */
50     gid_t client_gid;                   /* GID claimed by client */
51     gid_t client_g0, client_g1;         /* groups claimed by client */
52 };
53
54 static struct nfs_server_thread *nfssrv_list = 0;
55
56 static struct nfs_server_thread *find_nfs_thread(int create)
57 {
58     struct nfs_server_thread *this;
59
60     /* Check that this is an nfsd kernel thread */
61     if (current->files != init_task.files || strcmp(current->comm, "nfsd"))
62         return 0;
63
64     ObtainWriteLock(&afs_xnfssrv, 804);
65     for (this = nfssrv_list; this; this = this->next)
66         if (this->pid == current->pid)
67             break;
68     if (!this && create) {
69         this = afs_osi_Alloc(sizeof(struct nfs_server_thread));
70         if (this) {
71             this->next = nfssrv_list;
72             this->pid  = current->pid;
73             this->client_addrlen = 0;
74             nfssrv_list = this;
75             printk("afs: added nfsd task %d/%d\n",
76                    current->tgid, current->pid);
77         } else if (!whine_memory) {
78             whine_memory = 1;
79             printk("afs: failed to allocate memory for nfsd task %d/%d\n",
80                    current->tgid, current->pid);
81         }
82     }
83     ReleaseWriteLock(&afs_xnfssrv);
84     return this;
85 }
86
87 static int
88 svcauth_afs_accept(struct svc_rqst *rqstp, u32 *authp)
89 {
90     struct nfs_server_thread *ns;
91     struct afs_exporter *outexp;
92     afs_ucred_t *credp;
93     struct sockaddr_in *addr;
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 #if HAVE_LINUX_SVC_ADDR_IN
108     addr = svc_addr_in(rqstp);
109 #else
110     addr = &rqstp->rq_addr;
111 #endif
112
113     ns->active          = 1;
114     ns->flavor          = rqstp->rq_authop->flavour;
115     ns->code            = EACCES;
116     ns->client_addr     = *addr;
117     ns->client_addrlen  = rqstp->rq_addrlen;
118     ns->client_uid      = afs_cr_uid(&rqstp->rq_cred);
119     ns->client_gid      = afs_cr_gid(&rqstp->rq_cred);
120     if (afs_cr_group_info(&rqstp->rq_cred)->ngroups > 0)
121         ns->client_g0   = GROUP_AT(afs_cr_group_info(&rqstp->rq_cred), 0);
122     else
123         ns->client_g0   = -1;
124     if (afs_cr_group_info(&rqstp->rq_cred)->ngroups > 1)
125         ns->client_g1   = GROUP_AT(afs_cr_group_info(&rqstp->rq_cred), 1);
126     else
127         ns->client_g1   = -1;
128
129     if (addr->sin_family != AF_INET) {
130         printk("afs: NFS request from non-IPv4 client (family %d len %d)\n",
131                addr->sin_family, rqstp->rq_addrlen);
132         goto done;
133     }
134
135     credp = crget();
136     afs_set_cr_uid(credp, afs_cr_uid(&rqstp->rq_cred));
137     afs_set_cr_gid(credp, afs_cr_gid(&rqstp->rq_cred));
138     get_group_info(afs_cr_group_info(&rqstp->rq_cred));
139     afs_set_cr_group_info(credp, afs_cr_group_info(&rqstp->rq_cred));
140
141     /* avoid creating wildcard entries by mapping anonymous
142      * clients to afs_nobody */
143     if (afs_cr_uid(credp) == -1)
144         afs_set_cr_uid(credp, -2);
145     code = afs_nfsclient_reqhandler(0, &credp, addr->sin_addr.s_addr,
146                                     &ns->uid, &outexp);
147     if (!code && outexp) EXP_RELE(outexp);
148     if (!code) ns->code = 0;
149     if (code)
150         printk("afs: svcauth_afs_accept: afs_nfsclient_reqhandler: %d\n", code);
151     crfree(credp);
152
153 done:
154     AFS_GUNLOCK();
155     return SVC_OK;
156 }
157
158
159 int osi_linux_nfs_initreq(struct vrequest *av, afs_ucred_t *cr, int *code)
160 {
161     struct nfs_server_thread *ns;
162
163     ns = find_nfs_thread(0);
164     if (!ns || !ns->active)
165         return 0;
166
167     *code = ns->code;
168     if (!ns->code) {
169         afs_cr_ruid(cr) = NFSXLATOR_CRED;
170         av->uid = ns->uid;
171     }
172     return 1;
173 }
174
175 void osi_linux_nfssrv_init(void)
176 {
177     int i;
178
179     nfssrv_list = 0;
180     AFS_RWLOCK_INIT(&afs_xnfssrv, "afs_xnfssrv");
181
182     if (authtab && !IS_ERR(authtab))
183            afs_authtab = authtab;
184     else if (authtab_addr) afs_authtab = (struct auth_ops **)authtab_addr;
185     else {
186         printk("Warning: Unable to find the address of authtab\n");
187         printk("NFS Translator hooks will not be installed\n");
188         printk("To correct, specify authtab_addr=<authtab>\n");
189         afs_authtab = 0;
190         return;
191     }
192
193     for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
194         afs_orig_authtab[i] = afs_authtab[i];
195         if (!afs_orig_authtab[i] || afs_orig_authtab[i]->flavour != i ||
196             !try_module_get(afs_orig_authtab[i]->owner)) {
197             afs_orig_authtab[i] = 0;
198             continue;
199         }
200
201         afs_new_authtab[i] = afs_osi_Alloc(sizeof(struct auth_ops));
202         osi_Assert(afs_new_authtab[i] != NULL);
203         *(afs_new_authtab[i]) = *(afs_orig_authtab[i]);
204         afs_new_authtab[i]->owner = THIS_MODULE;
205         afs_new_authtab[i]->accept = svcauth_afs_accept;
206         /* afs_new_authtab[i]->release = svcauth_afs_release; */
207         svc_auth_unregister(i);
208         svc_auth_register(i, afs_new_authtab[i]);
209     }
210 }
211
212 void osi_linux_nfssrv_shutdown(void)
213 {
214     struct nfs_server_thread *next;
215     int i;
216
217     if (afs_authtab) {
218         for (i = 0; i < RPC_AUTH_MAXFLAVOR; i++) {
219             if (!afs_orig_authtab[i])
220                 continue;
221             svc_auth_unregister(i);
222             svc_auth_register(i, afs_orig_authtab[i]);
223             module_put(afs_orig_authtab[i]->owner);
224             afs_osi_Free(afs_new_authtab[i], sizeof(struct auth_ops));
225         }
226     }
227
228     AFS_GLOCK();
229     ObtainWriteLock(&afs_xnfssrv, 805);
230     while (nfssrv_list) {
231         next = nfssrv_list->next;
232         afs_osi_Free(nfssrv_list, sizeof(struct nfs_server_thread));
233         nfssrv_list = next;
234     }
235     ReleaseWriteLock(&afs_xnfssrv);
236     AFS_GUNLOCK();
237 }
238 #endif /* AFS_NONFSTRANS */
239