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