1 /*	$NetBSD: nfs_prot_svc.c,v 1.1.1.2 2009/03/20 20:26:49 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2009 Erez Zadok
5  * Copyright (c) 1989 Jan-Simon Pendry
6  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7  * Copyright (c) 1989 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry at Imperial College, London.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgment:
23  *      This product includes software developed by the University of
24  *      California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *
42  * File: am-utils/amd/nfs_prot_svc.c
43  *
44  */
45 
46 #ifdef HAVE_CONFIG_H
47 # include <config.h>
48 #endif /* HAVE_CONFIG_H */
49 #include <am_defs.h>
50 #include <amd.h>
51 
52 /* external definitions */
53 extern voidp nfsproc_null_2_svc(voidp, struct svc_req *);
54 extern nfsattrstat *nfsproc_getattr_2_svc(am_nfs_fh *, struct svc_req *);
55 extern nfsattrstat *nfsproc_setattr_2_svc(nfssattrargs *, struct svc_req *);
56 extern voidp nfsproc_root_2_svc(voidp, struct svc_req *);
57 extern nfsdiropres *nfsproc_lookup_2_svc(nfsdiropargs *, struct svc_req *);
58 extern nfsreadlinkres *nfsproc_readlink_2_svc(am_nfs_fh *, struct svc_req *);
59 extern nfsreadres *nfsproc_read_2_svc(nfsreadargs *, struct svc_req *);
60 extern voidp nfsproc_writecache_2_svc(voidp, struct svc_req *);
61 extern nfsattrstat *nfsproc_write_2_svc(nfswriteargs *, struct svc_req *);
62 extern nfsdiropres *nfsproc_create_2_svc(nfscreateargs *, struct svc_req *);
63 extern nfsstat *nfsproc_remove_2_svc(nfsdiropargs *, struct svc_req *);
64 extern nfsstat *nfsproc_rename_2_svc(nfsrenameargs *, struct svc_req *);
65 extern nfsstat *nfsproc_link_2_svc(nfslinkargs *, struct svc_req *);
66 extern nfsstat *nfsproc_symlink_2_svc(nfssymlinkargs *, struct svc_req *);
67 extern nfsdiropres *nfsproc_mkdir_2_svc(nfscreateargs *, struct svc_req *);
68 extern nfsstat *nfsproc_rmdir_2_svc(nfsdiropargs *, struct svc_req *);
69 extern nfsreaddirres *nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *);
70 extern nfsstatfsres *nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *);
71 
72 /* global variables */
73 SVCXPRT *current_transp;
74 
75 /* typedefs */
76 typedef char *(*nfssvcproc_t)(voidp, struct svc_req *);
77 
78 
79 void
80 nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
81 {
82   union {
83     am_nfs_fh		nfsproc_getattr_2_arg;
84     nfssattrargs	nfsproc_setattr_2_arg;
85     nfsdiropargs	nfsproc_lookup_2_arg;
86     am_nfs_fh		nfsproc_readlink_2_arg;
87     nfsreadargs		nfsproc_read_2_arg;
88     nfswriteargs	nfsproc_write_2_arg;
89     nfscreateargs	nfsproc_create_2_arg;
90     nfsdiropargs	nfsproc_remove_2_arg;
91     nfsrenameargs	nfsproc_rename_2_arg;
92     nfslinkargs		nfsproc_link_2_arg;
93     nfssymlinkargs	nfsproc_symlink_2_arg;
94     nfscreateargs	nfsproc_mkdir_2_arg;
95     nfsdiropargs	fsproc_rmdir_2_arg;
96     nfsreaddirargs	nfsproc_readdir_2_arg;
97     am_nfs_fh		nfsproc_statfs_2_arg;
98   } argument;
99   char *result;
100   xdrproc_t xdr_argument, xdr_result;
101   nfssvcproc_t local;
102 
103 #ifdef HAVE_TRANSPORT_TYPE_TLI
104   /*
105    * On TLI systems we don't use an INET network type, but a "ticlts" (see
106    * /etc/netconfig and conf/transp_tli.c:create_nfs_service).  This means
107    * that packets could only come from the loopback interface, and we don't
108    * need to check them and filter possibly spoofed packets.  Therefore we
109    * only need to check if the UID caller is correct.
110    */
111 # ifdef HAVE___RPC_GET_LOCAL_UID
112   uid_t u;
113   /* extern definition for an internal libnsl function */
114   extern int __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid);
115   if (__rpc_get_local_uid(transp, &u) >= 0  &&  u != 0) {
116     plog(XLOG_WARNING, "ignoring request from UID %ld, must be 0", (long) u);
117     return;
118   }
119 # else /* not HAVE___RPC_GET_LOCAL_UID */
120   dlog("cannot verify local uid for rpc request");
121 # endif /* HAVE___RPC_GET_LOCAL_UID */
122 #else /* not HAVE_TRANPORT_TYPE_TLI */
123   struct sockaddr_in *sinp;
124   char dq[20], dq2[28];
125   sinp = amu_svc_getcaller(rqstp->rq_xprt);
126 # ifdef MNT2_NFS_OPT_RESVPORT
127   /* Verify that the request comes from a reserved port */
128   if (sinp &&
129       ntohs(sinp->sin_port) >= IPPORT_RESERVED &&
130       !(gopt.flags & CFM_NFS_INSECURE_PORT)) {
131     plog(XLOG_WARNING, "ignoring request from %s:%u, port not reserved",
132 	 inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
133 	 ntohs(sinp->sin_port));
134     return;
135   }
136 # endif /* MNT2_NFS_OPT_RESVPORT */
137   /* if the address does not match, ignore the request */
138   if (sinp && (sinp->sin_addr.s_addr != myipaddr.s_addr)) {
139     if (gopt.flags & CFM_NFS_ANY_INTERFACE) {
140       if (!is_interface_local(sinp->sin_addr.s_addr)) {
141 	plog(XLOG_WARNING, "ignoring request from %s:%u, not a local interface",
142 	     inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
143 	     ntohs(sinp->sin_port));
144       }
145     } else {
146       plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s",
147 	   inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
148 	   ntohs(sinp->sin_port),
149 	   inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr));
150       return;
151     }
152   }
153 #endif /* not HAVE_TRANPORT_TYPE_TLI */
154 
155   current_transp = NULL;
156 
157   switch (rqstp->rq_proc) {
158 
159   case NFSPROC_NULL:
160     xdr_argument = (xdrproc_t) xdr_void;
161     xdr_result = (xdrproc_t) xdr_void;
162     local = (nfssvcproc_t) nfsproc_null_2_svc;
163     break;
164 
165   case NFSPROC_GETATTR:
166     xdr_argument = (xdrproc_t) xdr_nfs_fh;
167     xdr_result = (xdrproc_t) xdr_attrstat;
168     local = (nfssvcproc_t) nfsproc_getattr_2_svc;
169     break;
170 
171   case NFSPROC_SETATTR:
172     xdr_argument = (xdrproc_t) xdr_sattrargs;
173     xdr_result = (xdrproc_t) xdr_attrstat;
174     local = (nfssvcproc_t) nfsproc_setattr_2_svc;
175     break;
176 
177   case NFSPROC_ROOT:
178     xdr_argument = (xdrproc_t) xdr_void;
179     xdr_result = (xdrproc_t) xdr_void;
180     local = (nfssvcproc_t) nfsproc_root_2_svc;
181     break;
182 
183   case NFSPROC_LOOKUP:
184     xdr_argument = (xdrproc_t) xdr_diropargs;
185     xdr_result = (xdrproc_t) xdr_diropres;
186     local = (nfssvcproc_t) nfsproc_lookup_2_svc;
187     /*
188      * Cheap way to pass transp down to amfs_auto_lookuppn so it can
189      * be stored in the am_node structure and later used for
190      * quick_reply().
191      */
192     current_transp = transp;
193     break;
194 
195   case NFSPROC_READLINK:
196     xdr_argument = (xdrproc_t) xdr_nfs_fh;
197     xdr_result = (xdrproc_t) xdr_readlinkres;
198     local = (nfssvcproc_t) nfsproc_readlink_2_svc;
199     break;
200 
201   case NFSPROC_READ:
202     xdr_argument = (xdrproc_t) xdr_readargs;
203     xdr_result = (xdrproc_t) xdr_readres;
204     local = (nfssvcproc_t) nfsproc_read_2_svc;
205     break;
206 
207   case NFSPROC_WRITECACHE:
208     xdr_argument = (xdrproc_t) xdr_void;
209     xdr_result = (xdrproc_t) xdr_void;
210     local = (nfssvcproc_t) nfsproc_writecache_2_svc;
211     break;
212 
213   case NFSPROC_WRITE:
214     xdr_argument = (xdrproc_t) xdr_writeargs;
215     xdr_result = (xdrproc_t) xdr_attrstat;
216     local = (nfssvcproc_t) nfsproc_write_2_svc;
217     break;
218 
219   case NFSPROC_CREATE:
220     xdr_argument = (xdrproc_t) xdr_createargs;
221     xdr_result = (xdrproc_t) xdr_diropres;
222     local = (nfssvcproc_t) nfsproc_create_2_svc;
223     break;
224 
225   case NFSPROC_REMOVE:
226     xdr_argument = (xdrproc_t) xdr_diropargs;
227     xdr_result = (xdrproc_t) xdr_nfsstat;
228     local = (nfssvcproc_t) nfsproc_remove_2_svc;
229     break;
230 
231   case NFSPROC_RENAME:
232     xdr_argument = (xdrproc_t) xdr_renameargs;
233     xdr_result = (xdrproc_t) xdr_nfsstat;
234     local = (nfssvcproc_t) nfsproc_rename_2_svc;
235     break;
236 
237   case NFSPROC_LINK:
238     xdr_argument = (xdrproc_t) xdr_linkargs;
239     xdr_result = (xdrproc_t) xdr_nfsstat;
240     local = (nfssvcproc_t) nfsproc_link_2_svc;
241     break;
242 
243   case NFSPROC_SYMLINK:
244     xdr_argument = (xdrproc_t) xdr_symlinkargs;
245     xdr_result = (xdrproc_t) xdr_nfsstat;
246     local = (nfssvcproc_t) nfsproc_symlink_2_svc;
247     break;
248 
249   case NFSPROC_MKDIR:
250     xdr_argument = (xdrproc_t) xdr_createargs;
251     xdr_result = (xdrproc_t) xdr_diropres;
252     local = (nfssvcproc_t) nfsproc_mkdir_2_svc;
253     break;
254 
255   case NFSPROC_RMDIR:
256     xdr_argument = (xdrproc_t) xdr_diropargs;
257     xdr_result = (xdrproc_t) xdr_nfsstat;
258     local = (nfssvcproc_t) nfsproc_rmdir_2_svc;
259     break;
260 
261   case NFSPROC_READDIR:
262     xdr_argument = (xdrproc_t) xdr_readdirargs;
263     xdr_result = (xdrproc_t) xdr_readdirres;
264     local = (nfssvcproc_t) nfsproc_readdir_2_svc;
265     break;
266 
267   case NFSPROC_STATFS:
268     xdr_argument = (xdrproc_t) xdr_nfs_fh;
269     xdr_result = (xdrproc_t) xdr_statfsres;
270     local = (nfssvcproc_t) nfsproc_statfs_2_svc;
271     break;
272 
273   default:
274     svcerr_noproc(transp);
275     return;
276   }
277 
278   memset((char *) &argument, 0, sizeof(argument));
279   if (!svc_getargs(transp,
280 		   (XDRPROC_T_TYPE) xdr_argument,
281 		   (SVC_IN_ARG_TYPE) &argument)) {
282     plog(XLOG_ERROR,
283 	 "NFS xdr decode failed for %d %d %d",
284 	 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
285     svcerr_decode(transp);
286     return;
287   }
288   result = (*local) (&argument, rqstp);
289 
290   current_transp = NULL;
291 
292   if (result != NULL && !svc_sendreply(transp,
293 				       (XDRPROC_T_TYPE) xdr_result,
294 				       result)) {
295     svcerr_systemerr(transp);
296   }
297   if (!svc_freeargs(transp,
298 		    (XDRPROC_T_TYPE) xdr_argument,
299 		    (SVC_IN_ARG_TYPE) & argument)) {
300     plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_2");
301     going_down(1);
302   }
303 }
304