138494Sobrien/*
2174313Sobrien * Copyright (c) 1997-2006 Erez Zadok
338494Sobrien * Copyright (c) 1989 Jan-Simon Pendry
438494Sobrien * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
538494Sobrien * Copyright (c) 1989 The Regents of the University of California.
638494Sobrien * All rights reserved.
738494Sobrien *
838494Sobrien * This code is derived from software contributed to Berkeley by
938494Sobrien * Jan-Simon Pendry at Imperial College, London.
1038494Sobrien *
1138494Sobrien * Redistribution and use in source and binary forms, with or without
1238494Sobrien * modification, are permitted provided that the following conditions
1338494Sobrien * are met:
1438494Sobrien * 1. Redistributions of source code must retain the above copyright
1538494Sobrien *    notice, this list of conditions and the following disclaimer.
1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1738494Sobrien *    notice, this list of conditions and the following disclaimer in the
1838494Sobrien *    documentation and/or other materials provided with the distribution.
1938494Sobrien * 3. All advertising materials mentioning features or use of this software
2042629Sobrien *    must display the following acknowledgment:
2138494Sobrien *      This product includes software developed by the University of
2238494Sobrien *      California, Berkeley and its contributors.
2338494Sobrien * 4. Neither the name of the University nor the names of its contributors
2438494Sobrien *    may be used to endorse or promote products derived from this software
2538494Sobrien *    without specific prior written permission.
2638494Sobrien *
2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3038494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3738494Sobrien * SUCH DAMAGE.
3838494Sobrien *
3938494Sobrien *
40174313Sobrien * File: am-utils/amd/nfs_prot_svc.c
4138494Sobrien *
4238494Sobrien */
4338494Sobrien
4438494Sobrien#ifdef HAVE_CONFIG_H
4538494Sobrien# include <config.h>
4638494Sobrien#endif /* HAVE_CONFIG_H */
4738494Sobrien#include <am_defs.h>
4838494Sobrien#include <amd.h>
4938494Sobrien
5038494Sobrien/* external definitions */
5138494Sobrienextern voidp nfsproc_null_2_svc(voidp, struct svc_req *);
5282794Sobrienextern nfsattrstat *nfsproc_getattr_2_svc(am_nfs_fh *, struct svc_req *);
5382794Sobrienextern nfsattrstat *nfsproc_setattr_2_svc(nfssattrargs *, struct svc_req *);
5438494Sobrienextern voidp nfsproc_root_2_svc(voidp, struct svc_req *);
5582794Sobrienextern nfsdiropres *nfsproc_lookup_2_svc(nfsdiropargs *, struct svc_req *);
5682794Sobrienextern nfsreadlinkres *nfsproc_readlink_2_svc(am_nfs_fh *, struct svc_req *);
5782794Sobrienextern nfsreadres *nfsproc_read_2_svc(nfsreadargs *, struct svc_req *);
5838494Sobrienextern voidp nfsproc_writecache_2_svc(voidp, struct svc_req *);
5982794Sobrienextern nfsattrstat *nfsproc_write_2_svc(nfswriteargs *, struct svc_req *);
6082794Sobrienextern nfsdiropres *nfsproc_create_2_svc(nfscreateargs *, struct svc_req *);
6182794Sobrienextern nfsstat *nfsproc_remove_2_svc(nfsdiropargs *, struct svc_req *);
6282794Sobrienextern nfsstat *nfsproc_rename_2_svc(nfsrenameargs *, struct svc_req *);
6382794Sobrienextern nfsstat *nfsproc_link_2_svc(nfslinkargs *, struct svc_req *);
6482794Sobrienextern nfsstat *nfsproc_symlink_2_svc(nfssymlinkargs *, struct svc_req *);
6582794Sobrienextern nfsdiropres *nfsproc_mkdir_2_svc(nfscreateargs *, struct svc_req *);
6682794Sobrienextern nfsstat *nfsproc_rmdir_2_svc(nfsdiropargs *, struct svc_req *);
6782794Sobrienextern nfsreaddirres *nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *);
6882794Sobrienextern nfsstatfsres *nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *);
6938494Sobrien
7038494Sobrien/* global variables */
71174313SobrienSVCXPRT *current_transp;
7238494Sobrien
7338494Sobrien/* typedefs */
7438494Sobrientypedef char *(*nfssvcproc_t)(voidp, struct svc_req *);
7538494Sobrien
7638494Sobrien
7738494Sobrienvoid
7838494Sobriennfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
7938494Sobrien{
8038494Sobrien  union {
8138494Sobrien    am_nfs_fh		nfsproc_getattr_2_arg;
8238494Sobrien    nfssattrargs	nfsproc_setattr_2_arg;
8338494Sobrien    nfsdiropargs	nfsproc_lookup_2_arg;
8438494Sobrien    am_nfs_fh		nfsproc_readlink_2_arg;
8538494Sobrien    nfsreadargs		nfsproc_read_2_arg;
8638494Sobrien    nfswriteargs	nfsproc_write_2_arg;
8738494Sobrien    nfscreateargs	nfsproc_create_2_arg;
8838494Sobrien    nfsdiropargs	nfsproc_remove_2_arg;
8938494Sobrien    nfsrenameargs	nfsproc_rename_2_arg;
9038494Sobrien    nfslinkargs		nfsproc_link_2_arg;
9138494Sobrien    nfssymlinkargs	nfsproc_symlink_2_arg;
9238494Sobrien    nfscreateargs	nfsproc_mkdir_2_arg;
9338494Sobrien    nfsdiropargs	fsproc_rmdir_2_arg;
9438494Sobrien    nfsreaddirargs	nfsproc_readdir_2_arg;
9538494Sobrien    am_nfs_fh		nfsproc_statfs_2_arg;
9638494Sobrien  } argument;
9738494Sobrien  char *result;
9838494Sobrien  xdrproc_t xdr_argument, xdr_result;
9938494Sobrien  nfssvcproc_t local;
100174313Sobrien
101174313Sobrien#ifdef HAVE_TRANSPORT_TYPE_TLI
102174313Sobrien  /*
103174313Sobrien   * On TLI systems we don't use an INET network type, but a "ticlts" (see
104174313Sobrien   * /etc/netconfig and conf/transp_tli.c:create_nfs_service).  This means
105174313Sobrien   * that packets could only come from the loopback interface, and we don't
106174313Sobrien   * need to check them and filter possibly spoofed packets.  Therefore we
107174313Sobrien   * only need to check if the UID caller is correct.
108174313Sobrien   */
109174313Sobrien# ifdef HAVE___RPC_GET_LOCAL_UID
110174313Sobrien  uid_t u;
111174313Sobrien  /* extern definition for an internal libnsl function */
112174313Sobrien  extern int __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid);
113174313Sobrien  if (__rpc_get_local_uid(transp, &u) >= 0  &&  u != 0) {
114174313Sobrien    plog(XLOG_WARNING, "ignoring request from UID %ld, must be 0", (long) u);
115174313Sobrien    return;
116174313Sobrien  }
117174313Sobrien# else /* not HAVE___RPC_GET_LOCAL_UID */
118174313Sobrien  dlog("cannot verify local uid for rpc request");
119174313Sobrien# endif /* HAVE___RPC_GET_LOCAL_UID */
120174313Sobrien#else /* not HAVE_TRANPORT_TYPE_TLI */
12151292Sobrien  struct sockaddr_in *sinp;
12251292Sobrien  char dq[20], dq2[28];
12351292Sobrien  sinp = amu_svc_getcaller(rqstp->rq_xprt);
124174313Sobrien# ifdef MNT2_NFS_OPT_RESVPORT
12551292Sobrien  /* Verify that the request comes from a reserved port */
126174313Sobrien  if (sinp &&
127174313Sobrien      ntohs(sinp->sin_port) >= IPPORT_RESERVED &&
128131702Smbr      !(gopt.flags & CFM_NFS_INSECURE_PORT)) {
12951292Sobrien    plog(XLOG_WARNING, "ignoring request from %s:%u, port not reserved",
130174313Sobrien	 inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
13151292Sobrien	 ntohs(sinp->sin_port));
13251292Sobrien    return;
13351292Sobrien  }
134174313Sobrien# endif /* MNT2_NFS_OPT_RESVPORT */
13551292Sobrien  /* if the address does not match, ignore the request */
136174313Sobrien  if (sinp && (sinp->sin_addr.s_addr != myipaddr.s_addr)) {
137174313Sobrien    if (gopt.flags & CFM_NFS_ANY_INTERFACE) {
138174313Sobrien      if (!is_interface_local(sinp->sin_addr.s_addr)) {
139174313Sobrien	plog(XLOG_WARNING, "ignoring request from %s:%u, not a local interface",
140174313Sobrien	     inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
141174313Sobrien	     ntohs(sinp->sin_port));
142174313Sobrien      }
143174313Sobrien    } else {
144174313Sobrien      plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s",
145174313Sobrien	   inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
146174313Sobrien	   ntohs(sinp->sin_port),
147174313Sobrien	   inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr));
148174313Sobrien      return;
149174313Sobrien    }
15051292Sobrien  }
151174313Sobrien#endif /* not HAVE_TRANPORT_TYPE_TLI */
15251292Sobrien
153174313Sobrien  current_transp = NULL;
15438494Sobrien
15538494Sobrien  switch (rqstp->rq_proc) {
15638494Sobrien
15738494Sobrien  case NFSPROC_NULL:
15838494Sobrien    xdr_argument = (xdrproc_t) xdr_void;
15938494Sobrien    xdr_result = (xdrproc_t) xdr_void;
16038494Sobrien    local = (nfssvcproc_t) nfsproc_null_2_svc;
16138494Sobrien    break;
16238494Sobrien
16338494Sobrien  case NFSPROC_GETATTR:
16438494Sobrien    xdr_argument = (xdrproc_t) xdr_nfs_fh;
16538494Sobrien    xdr_result = (xdrproc_t) xdr_attrstat;
16638494Sobrien    local = (nfssvcproc_t) nfsproc_getattr_2_svc;
16738494Sobrien    break;
16838494Sobrien
16938494Sobrien  case NFSPROC_SETATTR:
17038494Sobrien    xdr_argument = (xdrproc_t) xdr_sattrargs;
17138494Sobrien    xdr_result = (xdrproc_t) xdr_attrstat;
17238494Sobrien    local = (nfssvcproc_t) nfsproc_setattr_2_svc;
17338494Sobrien    break;
17438494Sobrien
17538494Sobrien  case NFSPROC_ROOT:
17638494Sobrien    xdr_argument = (xdrproc_t) xdr_void;
17738494Sobrien    xdr_result = (xdrproc_t) xdr_void;
17838494Sobrien    local = (nfssvcproc_t) nfsproc_root_2_svc;
17938494Sobrien    break;
18038494Sobrien
18138494Sobrien  case NFSPROC_LOOKUP:
18238494Sobrien    xdr_argument = (xdrproc_t) xdr_diropargs;
18338494Sobrien    xdr_result = (xdrproc_t) xdr_diropres;
18438494Sobrien    local = (nfssvcproc_t) nfsproc_lookup_2_svc;
18538494Sobrien    /*
18638494Sobrien     * Cheap way to pass transp down to amfs_auto_lookuppn so it can
18738494Sobrien     * be stored in the am_node structure and later used for
18838494Sobrien     * quick_reply().
18938494Sobrien     */
190174313Sobrien    current_transp = transp;
19138494Sobrien    break;
19238494Sobrien
19338494Sobrien  case NFSPROC_READLINK:
19438494Sobrien    xdr_argument = (xdrproc_t) xdr_nfs_fh;
19538494Sobrien    xdr_result = (xdrproc_t) xdr_readlinkres;
19638494Sobrien    local = (nfssvcproc_t) nfsproc_readlink_2_svc;
19738494Sobrien    break;
19838494Sobrien
19938494Sobrien  case NFSPROC_READ:
20038494Sobrien    xdr_argument = (xdrproc_t) xdr_readargs;
20138494Sobrien    xdr_result = (xdrproc_t) xdr_readres;
20238494Sobrien    local = (nfssvcproc_t) nfsproc_read_2_svc;
20338494Sobrien    break;
20438494Sobrien
20538494Sobrien  case NFSPROC_WRITECACHE:
20638494Sobrien    xdr_argument = (xdrproc_t) xdr_void;
20738494Sobrien    xdr_result = (xdrproc_t) xdr_void;
20838494Sobrien    local = (nfssvcproc_t) nfsproc_writecache_2_svc;
20938494Sobrien    break;
21038494Sobrien
21138494Sobrien  case NFSPROC_WRITE:
21238494Sobrien    xdr_argument = (xdrproc_t) xdr_writeargs;
21338494Sobrien    xdr_result = (xdrproc_t) xdr_attrstat;
21438494Sobrien    local = (nfssvcproc_t) nfsproc_write_2_svc;
21538494Sobrien    break;
21638494Sobrien
21738494Sobrien  case NFSPROC_CREATE:
21838494Sobrien    xdr_argument = (xdrproc_t) xdr_createargs;
21938494Sobrien    xdr_result = (xdrproc_t) xdr_diropres;
22038494Sobrien    local = (nfssvcproc_t) nfsproc_create_2_svc;
22138494Sobrien    break;
22238494Sobrien
22338494Sobrien  case NFSPROC_REMOVE:
22438494Sobrien    xdr_argument = (xdrproc_t) xdr_diropargs;
22538494Sobrien    xdr_result = (xdrproc_t) xdr_nfsstat;
22638494Sobrien    local = (nfssvcproc_t) nfsproc_remove_2_svc;
22738494Sobrien    break;
22838494Sobrien
22938494Sobrien  case NFSPROC_RENAME:
23038494Sobrien    xdr_argument = (xdrproc_t) xdr_renameargs;
23138494Sobrien    xdr_result = (xdrproc_t) xdr_nfsstat;
23238494Sobrien    local = (nfssvcproc_t) nfsproc_rename_2_svc;
23338494Sobrien    break;
23438494Sobrien
23538494Sobrien  case NFSPROC_LINK:
23638494Sobrien    xdr_argument = (xdrproc_t) xdr_linkargs;
23738494Sobrien    xdr_result = (xdrproc_t) xdr_nfsstat;
23838494Sobrien    local = (nfssvcproc_t) nfsproc_link_2_svc;
23938494Sobrien    break;
24038494Sobrien
24138494Sobrien  case NFSPROC_SYMLINK:
24238494Sobrien    xdr_argument = (xdrproc_t) xdr_symlinkargs;
24338494Sobrien    xdr_result = (xdrproc_t) xdr_nfsstat;
24438494Sobrien    local = (nfssvcproc_t) nfsproc_symlink_2_svc;
24538494Sobrien    break;
24638494Sobrien
24738494Sobrien  case NFSPROC_MKDIR:
24838494Sobrien    xdr_argument = (xdrproc_t) xdr_createargs;
24938494Sobrien    xdr_result = (xdrproc_t) xdr_diropres;
25038494Sobrien    local = (nfssvcproc_t) nfsproc_mkdir_2_svc;
25138494Sobrien    break;
25238494Sobrien
25338494Sobrien  case NFSPROC_RMDIR:
25438494Sobrien    xdr_argument = (xdrproc_t) xdr_diropargs;
25538494Sobrien    xdr_result = (xdrproc_t) xdr_nfsstat;
25638494Sobrien    local = (nfssvcproc_t) nfsproc_rmdir_2_svc;
25738494Sobrien    break;
25838494Sobrien
25938494Sobrien  case NFSPROC_READDIR:
26038494Sobrien    xdr_argument = (xdrproc_t) xdr_readdirargs;
26138494Sobrien    xdr_result = (xdrproc_t) xdr_readdirres;
26238494Sobrien    local = (nfssvcproc_t) nfsproc_readdir_2_svc;
26338494Sobrien    break;
26438494Sobrien
26538494Sobrien  case NFSPROC_STATFS:
26638494Sobrien    xdr_argument = (xdrproc_t) xdr_nfs_fh;
26738494Sobrien    xdr_result = (xdrproc_t) xdr_statfsres;
26838494Sobrien    local = (nfssvcproc_t) nfsproc_statfs_2_svc;
26938494Sobrien    break;
27038494Sobrien
27138494Sobrien  default:
27238494Sobrien    svcerr_noproc(transp);
27338494Sobrien    return;
27438494Sobrien  }
27538494Sobrien
27638494Sobrien  memset((char *) &argument, 0, sizeof(argument));
27738494Sobrien  if (!svc_getargs(transp,
27838494Sobrien		   (XDRPROC_T_TYPE) xdr_argument,
27938494Sobrien		   (SVC_IN_ARG_TYPE) &argument)) {
28038494Sobrien    plog(XLOG_ERROR,
28138494Sobrien	 "NFS xdr decode failed for %d %d %d",
28251292Sobrien	 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
28338494Sobrien    svcerr_decode(transp);
28438494Sobrien    return;
28538494Sobrien  }
28638494Sobrien  result = (*local) (&argument, rqstp);
28738494Sobrien
288174313Sobrien  current_transp = NULL;
28938494Sobrien
29038494Sobrien  if (result != NULL && !svc_sendreply(transp,
29138494Sobrien				       (XDRPROC_T_TYPE) xdr_result,
29238494Sobrien				       result)) {
29338494Sobrien    svcerr_systemerr(transp);
29438494Sobrien  }
29538494Sobrien  if (!svc_freeargs(transp,
29638494Sobrien		    (XDRPROC_T_TYPE) xdr_argument,
29738494Sobrien		    (SVC_IN_ARG_TYPE) & argument)) {
29838494Sobrien    plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_2");
29938494Sobrien    going_down(1);
30038494Sobrien  }
30138494Sobrien}
302