From 0ad4db4fad8df7ca518f0e0baea4f756bb00098a Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Mon, 11 Oct 2010 14:59:26 -0400 Subject: [PATCH] fresh git tree for public release we regretfully had to remove our git history for licensing reasons Signed-off-by: Casey Bodley --- README.html | 107 + build.vc10/.gitignore | 7 + build.vc10/daemon.vcxproj | 254 ++ build.vc10/daemon.vcxproj.filters | 160 + build.vc10/dll.vcxproj | 208 ++ build.vc10/dll.vcxproj.filters | 41 + build.vc10/env.props.example | 20 + build.vc10/libtirpc.vcxproj | 308 ++ build.vc10/libtirpc.vcxproj.filters | 358 ++ build.vc10/mount.vcxproj | 187 + build.vc10/mount.vcxproj.filters | 38 + build.vc10/ms-nfs41-client.sln | 76 + build.vc10/nfs41_driver.vcxproj | 148 + build.vc10/nfs41_driver.vcxproj.filters | 55 + build.vc10/nfs_install.vcxproj | 182 + build.vc10/nfs_install.vcxproj.filters | 35 + build.vc9/.gitignore | 6 + build.vc9/daemon.vcproj | 536 +++ build.vc9/dll.vcproj | 386 ++ build.vc9/env.vsprops.example | 28 + build.vc9/libtirpc.vcproj | 793 ++++ build.vc9/mount.vcproj | 362 ++ build.vc9/ms-nfs41-client.sln | 79 + build.vc9/nfs41_driver.vcproj | 167 + build.vc9/nfs_install.vcproj | 354 ++ daemon/callback_server.c | 381 ++ daemon/callback_xdr.c | 539 +++ daemon/daemon_debug.c | 440 +++ daemon/daemon_debug.h | 73 + daemon/from_kernel.h | 195 + daemon/getattr.c | 152 + daemon/list.h | 116 + daemon/lock.c | 252 ++ daemon/lookup.c | 500 +++ daemon/makefile | 8 + daemon/mount.c | 131 + daemon/name_cache.c | 1243 +++++++ daemon/name_cache.h | 99 + daemon/namespace.c | 458 +++ daemon/nfs41.h | 357 ++ daemon/nfs41_callback.h | 254 ++ daemon/nfs41_client.c | 437 +++ daemon/nfs41_compound.c | 333 ++ daemon/nfs41_compound.h | 82 + daemon/nfs41_const.h | 306 ++ daemon/nfs41_daemon.c | 217 ++ daemon/nfs41_ops.c | 1745 +++++++++ daemon/nfs41_ops.h | 1074 ++++++ daemon/nfs41_rpc.c | 298 ++ daemon/nfs41_server.c | 332 ++ daemon/nfs41_session.c | 385 ++ daemon/nfs41_superblock.c | 228 ++ daemon/nfs41_types.h | 185 + daemon/nfs41_xdr.c | 3124 ++++++++++++++++ daemon/nfs41_xdr.h | 33 + daemon/open.c | 445 +++ daemon/pnfs.h | 352 ++ daemon/pnfs_debug.c | 125 + daemon/pnfs_device.c | 376 ++ daemon/pnfs_io.c | 565 +++ daemon/pnfs_layout.c | 835 +++++ daemon/rbtree.c | 385 ++ daemon/rbtree.h | 159 + daemon/readdir.c | 627 ++++ daemon/readwrite.c | 307 ++ daemon/setattr.c | 491 +++ daemon/sources | 24 + daemon/upcall.c | 222 ++ daemon/upcall.h | 201 + daemon/util.c | 450 +++ daemon/util.h | 166 + daemon/volume.c | 86 + dirs | 1 + dll/dllmain.c | 76 + dll/makefile | 8 + dll/nfs41_np.c | 900 +++++ dll/nfs41_np.def | 17 + dll/nfs41_np.h | 52 + dll/options.c | 100 + dll/options.h | 84 + dll/sources | 21 + install.bat | 2 + install/nfs_install.c | 47 + install/nfsreginst.c | 652 ++++ install/nfsreginst.h | 98 + install/sources | 15 + libtirpc/.gitignore | 46 + libtirpc/AUTHORS | 3 + libtirpc/COPYING | 359 ++ libtirpc/ChangeLog | 206 ++ libtirpc/INSTALL | 251 ++ libtirpc/Makefile.am | 36 + libtirpc/NEWS | 3 + libtirpc/README | 44 + libtirpc/THANKS | 6 + libtirpc/TODO | 3 + libtirpc/VERSION | 7 + libtirpc/autogen.sh | 42 + libtirpc/bootstrap | 10 + libtirpc/configure.ac | 29 + libtirpc/dirs | 2 + libtirpc/doc/Makefile.am | 5 + libtirpc/doc/etc_netconfig | 19 + libtirpc/libtirpc.pc.in | 11 + libtirpc/libtirpc/libtirpc.def | 94 + libtirpc/libtirpc/libtirpc.rc | 61 + libtirpc/libtirpc/resource.h | 14 + libtirpc/man/Makefile.am | 9 + libtirpc/man/bindresvport.3t | 101 + libtirpc/man/des_crypt.3t | 129 + libtirpc/man/getnetconfig.3t | 220 ++ libtirpc/man/getnetpath.3t | 168 + libtirpc/man/getrpcent.3t | 106 + libtirpc/man/getrpcport.3t | 34 + libtirpc/man/netconfig.5 | 123 + libtirpc/man/publickey.3t | 52 + libtirpc/man/publickey.5 | 41 + libtirpc/man/rpc.3t | 515 +++ libtirpc/man/rpc.5 | 57 + libtirpc/man/rpc_clnt_auth.3t | 96 + libtirpc/man/rpc_clnt_calls.3t | 316 ++ libtirpc/man/rpc_clnt_create.3t | 514 +++ libtirpc/man/rpc_secure.3t | 279 ++ libtirpc/man/rpc_soc.3t | 1726 +++++++++ libtirpc/man/rpc_svc_calls.3t | 267 ++ libtirpc/man/rpc_svc_create.3t | 337 ++ libtirpc/man/rpc_svc_err.3t | 97 + libtirpc/man/rpc_svc_reg.3t | 183 + libtirpc/man/rpc_xdr.3t | 101 + libtirpc/man/rpcbind.3t | 194 + libtirpc/man/rtime.3t | 50 + libtirpc/src/Makefile.am | 95 + libtirpc/src/asprintf.c | 105 + libtirpc/src/auth_des.c | 499 +++ libtirpc/src/auth_gss.c | 633 ++++ libtirpc/src/auth_none.c | 177 + libtirpc/src/auth_sspi.c | 634 ++++ libtirpc/src/auth_time.c | 504 +++ libtirpc/src/auth_unix.c | 372 ++ libtirpc/src/authdes_prot.c | 86 + libtirpc/src/authgss_prot.c | 356 ++ libtirpc/src/authunix_prot.c | 67 + libtirpc/src/bindresvport.c | 274 ++ libtirpc/src/clnt_bcast.c | 707 ++++ libtirpc/src/clnt_dg.c | 845 +++++ libtirpc/src/clnt_generic.c | 453 +++ libtirpc/src/clnt_perror.c | 339 ++ libtirpc/src/clnt_raw.c | 306 ++ libtirpc/src/clnt_simple.c | 180 + libtirpc/src/clnt_vc.c | 1000 +++++ libtirpc/src/crypt_client.c | 101 + libtirpc/src/des_crypt.c | 155 + libtirpc/src/des_soft.c | 65 + libtirpc/src/epoll_sub.c | 62 + libtirpc/src/getnetconfig.c | 700 ++++ libtirpc/src/getnetpath.c | 264 ++ libtirpc/src/getpeereid.c | 62 + libtirpc/src/getpublickey.c | 175 + libtirpc/src/getrpcent.c | 311 ++ libtirpc/src/getrpcport.c | 67 + libtirpc/src/gettimeofday.c | 44 + libtirpc/src/key_call.c | 466 +++ libtirpc/src/key_prot_xdr.c | 173 + libtirpc/src/libtirpc.def | 4 + libtirpc/src/makefile | 8 + libtirpc/src/mt_misc.c | 180 + libtirpc/src/netname.c | 150 + libtirpc/src/netnamer.c | 327 ++ libtirpc/src/pmap_clnt.c | 111 + libtirpc/src/pmap_getmaps.c | 91 + libtirpc/src/pmap_getport.c | 109 + libtirpc/src/pmap_prot.c | 58 + libtirpc/src/pmap_prot2.c | 132 + libtirpc/src/pmap_rmt.c | 169 + libtirpc/src/rpc_callmsg.c | 197 + libtirpc/src/rpc_com.h | 100 + libtirpc/src/rpc_commondata.c | 39 + libtirpc/src/rpc_dtablesize.c | 62 + libtirpc/src/rpc_generic.c | 920 +++++ libtirpc/src/rpc_prot.c | 389 ++ libtirpc/src/rpc_soc.c | 642 ++++ libtirpc/src/rpcb_clnt.c | 1240 +++++++ libtirpc/src/rpcb_prot.c | 319 ++ libtirpc/src/rpcb_st_xdr.c | 265 ++ libtirpc/src/rpcdname.c | 78 + libtirpc/src/rtime.c | 154 + libtirpc/src/sources | 106 + libtirpc/src/svc.c | 803 ++++ libtirpc/src/svc_auth.c | 201 + libtirpc/src/svc_auth_des.c | 531 +++ libtirpc/src/svc_auth_gss.c | 590 +++ libtirpc/src/svc_auth_none.c | 74 + libtirpc/src/svc_auth_unix.c | 147 + libtirpc/src/svc_dg.c | 585 +++ libtirpc/src/svc_generic.c | 302 ++ libtirpc/src/svc_raw.c | 248 ++ libtirpc/src/svc_run.c | 91 + libtirpc/src/svc_simple.c | 303 ++ libtirpc/src/svc_vc.c | 827 +++++ libtirpc/src/winstubs.c | 12 + libtirpc/src/wintirpc.c | 200 + libtirpc/src/xdr.c | 872 +++++ libtirpc/src/xdr_array.c | 157 + libtirpc/src/xdr_float.c | 300 ++ libtirpc/src/xdr_mem.c | 253 ++ libtirpc/src/xdr_rec.c | 791 ++++ libtirpc/src/xdr_reference.c | 137 + libtirpc/src/xdr_sizeof.c | 157 + libtirpc/src/xdr_stdio.c | 188 + libtirpc/tirpc/fpmath.h | 63 + libtirpc/tirpc/getpeereid.h | 2 + libtirpc/tirpc/libc_private.h | 129 + libtirpc/tirpc/misc/event.h | 201 + libtirpc/tirpc/misc/queue.h | 6 + libtirpc/tirpc/misc/socket.h | 62 + libtirpc/tirpc/namespace.h | 33 + libtirpc/tirpc/netconfig.h | 95 + libtirpc/tirpc/nss_tls.h | 80 + libtirpc/tirpc/reentrant.h | 163 + libtirpc/tirpc/rpc/auth.h | 391 ++ libtirpc/tirpc/rpc/auth_des.h | 130 + libtirpc/tirpc/rpc/auth_gss.h | 131 + libtirpc/tirpc/rpc/auth_kerb.h | 140 + libtirpc/tirpc/rpc/auth_unix.h | 83 + libtirpc/tirpc/rpc/clnt.h | 558 +++ libtirpc/tirpc/rpc/clnt_soc.h | 122 + libtirpc/tirpc/rpc/clnt_stat.h | 83 + libtirpc/tirpc/rpc/des.h | 82 + libtirpc/tirpc/rpc/des_crypt.h | 105 + libtirpc/tirpc/rpc/nettype.h | 63 + libtirpc/tirpc/rpc/pmap_clnt.h | 85 + libtirpc/tirpc/rpc/pmap_prot.h | 106 + libtirpc/tirpc/rpc/pmap_rmt.h | 64 + libtirpc/tirpc/rpc/raw.h | 57 + libtirpc/tirpc/rpc/rpc.h | 113 + libtirpc/tirpc/rpc/rpc_com.h | 87 + libtirpc/tirpc/rpc/rpc_msg.h | 224 ++ libtirpc/tirpc/rpc/rpcb_clnt.h | 83 + libtirpc/tirpc/rpc/rpcb_prot.h | 803 ++++ libtirpc/tirpc/rpc/rpcb_prot.x | 553 +++ libtirpc/tirpc/rpc/rpcent.h | 68 + libtirpc/tirpc/rpc/svc.h | 438 +++ libtirpc/tirpc/rpc/svc_auth.h | 69 + libtirpc/tirpc/rpc/svc_dg.h | 50 + libtirpc/tirpc/rpc/svc_soc.h | 119 + libtirpc/tirpc/rpc/types.h | 138 + libtirpc/tirpc/rpc/xdr.h | 367 ++ libtirpc/tirpc/rpcsvc/crypt.h | 109 + libtirpc/tirpc/rpcsvc/crypt.x | 87 + libtirpc/tirpc/rpcsvc/nis.h | 29 + libtirpc/tirpc/spinlock.h | 73 + libtirpc/tirpc/sys/queue.h | 529 +++ libtirpc/tirpc/un-namespace.h | 153 + libtirpc/tirpc/wintirpc.h | 101 + mount/enum.c | 106 + mount/mount.c | 369 ++ mount/options.c | 230 ++ mount/options.h | 89 + mount/sources | 17 + nfs41rdr.inf | 63 + sys/makefile | 8 + sys/nfs41_debug.c | 685 ++++ sys/nfs41_debug.h | 101 + sys/nfs41_driver.c | 4499 +++++++++++++++++++++++ sys/nfs41_driver.h | 84 + sys/nfs41_driver.ini | 13 + sys/nfs41_driver.rc | 11 + sys/sources | 26 + sys/wmlkm.c | 51 + sys/wmlkm.h | 51 + uninstall.bat | 2 + 271 files changed, 71255 insertions(+) create mode 100644 README.html create mode 100644 build.vc10/.gitignore create mode 100644 build.vc10/daemon.vcxproj create mode 100644 build.vc10/daemon.vcxproj.filters create mode 100644 build.vc10/dll.vcxproj create mode 100644 build.vc10/dll.vcxproj.filters create mode 100644 build.vc10/env.props.example create mode 100644 build.vc10/libtirpc.vcxproj create mode 100644 build.vc10/libtirpc.vcxproj.filters create mode 100644 build.vc10/mount.vcxproj create mode 100644 build.vc10/mount.vcxproj.filters create mode 100644 build.vc10/ms-nfs41-client.sln create mode 100644 build.vc10/nfs41_driver.vcxproj create mode 100644 build.vc10/nfs41_driver.vcxproj.filters create mode 100644 build.vc10/nfs_install.vcxproj create mode 100644 build.vc10/nfs_install.vcxproj.filters create mode 100644 build.vc9/.gitignore create mode 100644 build.vc9/daemon.vcproj create mode 100644 build.vc9/dll.vcproj create mode 100644 build.vc9/env.vsprops.example create mode 100644 build.vc9/libtirpc.vcproj create mode 100644 build.vc9/mount.vcproj create mode 100644 build.vc9/ms-nfs41-client.sln create mode 100644 build.vc9/nfs41_driver.vcproj create mode 100644 build.vc9/nfs_install.vcproj create mode 100644 daemon/callback_server.c create mode 100644 daemon/callback_xdr.c create mode 100644 daemon/daemon_debug.c create mode 100644 daemon/daemon_debug.h create mode 100644 daemon/from_kernel.h create mode 100644 daemon/getattr.c create mode 100644 daemon/list.h create mode 100644 daemon/lock.c create mode 100644 daemon/lookup.c create mode 100644 daemon/makefile create mode 100644 daemon/mount.c create mode 100644 daemon/name_cache.c create mode 100644 daemon/name_cache.h create mode 100644 daemon/namespace.c create mode 100644 daemon/nfs41.h create mode 100644 daemon/nfs41_callback.h create mode 100644 daemon/nfs41_client.c create mode 100644 daemon/nfs41_compound.c create mode 100644 daemon/nfs41_compound.h create mode 100644 daemon/nfs41_const.h create mode 100644 daemon/nfs41_daemon.c create mode 100644 daemon/nfs41_ops.c create mode 100644 daemon/nfs41_ops.h create mode 100644 daemon/nfs41_rpc.c create mode 100644 daemon/nfs41_server.c create mode 100644 daemon/nfs41_session.c create mode 100644 daemon/nfs41_superblock.c create mode 100644 daemon/nfs41_types.h create mode 100644 daemon/nfs41_xdr.c create mode 100644 daemon/nfs41_xdr.h create mode 100644 daemon/open.c create mode 100644 daemon/pnfs.h create mode 100644 daemon/pnfs_debug.c create mode 100644 daemon/pnfs_device.c create mode 100644 daemon/pnfs_io.c create mode 100644 daemon/pnfs_layout.c create mode 100644 daemon/rbtree.c create mode 100644 daemon/rbtree.h create mode 100644 daemon/readdir.c create mode 100644 daemon/readwrite.c create mode 100644 daemon/setattr.c create mode 100644 daemon/sources create mode 100644 daemon/upcall.c create mode 100644 daemon/upcall.h create mode 100644 daemon/util.c create mode 100644 daemon/util.h create mode 100644 daemon/volume.c create mode 100644 dirs create mode 100644 dll/dllmain.c create mode 100644 dll/makefile create mode 100644 dll/nfs41_np.c create mode 100644 dll/nfs41_np.def create mode 100644 dll/nfs41_np.h create mode 100644 dll/options.c create mode 100644 dll/options.h create mode 100644 dll/sources create mode 100644 install.bat create mode 100644 install/nfs_install.c create mode 100644 install/nfsreginst.c create mode 100644 install/nfsreginst.h create mode 100644 install/sources create mode 100644 libtirpc/.gitignore create mode 100644 libtirpc/AUTHORS create mode 100644 libtirpc/COPYING create mode 100644 libtirpc/ChangeLog create mode 100644 libtirpc/INSTALL create mode 100644 libtirpc/Makefile.am create mode 100644 libtirpc/NEWS create mode 100644 libtirpc/README create mode 100644 libtirpc/THANKS create mode 100644 libtirpc/TODO create mode 100644 libtirpc/VERSION create mode 100644 libtirpc/autogen.sh create mode 100644 libtirpc/bootstrap create mode 100644 libtirpc/configure.ac create mode 100644 libtirpc/dirs create mode 100644 libtirpc/doc/Makefile.am create mode 100644 libtirpc/doc/etc_netconfig create mode 100644 libtirpc/libtirpc.pc.in create mode 100644 libtirpc/libtirpc/libtirpc.def create mode 100644 libtirpc/libtirpc/libtirpc.rc create mode 100644 libtirpc/libtirpc/resource.h create mode 100644 libtirpc/man/Makefile.am create mode 100644 libtirpc/man/bindresvport.3t create mode 100644 libtirpc/man/des_crypt.3t create mode 100644 libtirpc/man/getnetconfig.3t create mode 100644 libtirpc/man/getnetpath.3t create mode 100644 libtirpc/man/getrpcent.3t create mode 100644 libtirpc/man/getrpcport.3t create mode 100644 libtirpc/man/netconfig.5 create mode 100644 libtirpc/man/publickey.3t create mode 100644 libtirpc/man/publickey.5 create mode 100644 libtirpc/man/rpc.3t create mode 100644 libtirpc/man/rpc.5 create mode 100644 libtirpc/man/rpc_clnt_auth.3t create mode 100644 libtirpc/man/rpc_clnt_calls.3t create mode 100644 libtirpc/man/rpc_clnt_create.3t create mode 100644 libtirpc/man/rpc_secure.3t create mode 100644 libtirpc/man/rpc_soc.3t create mode 100644 libtirpc/man/rpc_svc_calls.3t create mode 100644 libtirpc/man/rpc_svc_create.3t create mode 100644 libtirpc/man/rpc_svc_err.3t create mode 100644 libtirpc/man/rpc_svc_reg.3t create mode 100644 libtirpc/man/rpc_xdr.3t create mode 100644 libtirpc/man/rpcbind.3t create mode 100644 libtirpc/man/rtime.3t create mode 100644 libtirpc/src/Makefile.am create mode 100644 libtirpc/src/asprintf.c create mode 100644 libtirpc/src/auth_des.c create mode 100644 libtirpc/src/auth_gss.c create mode 100644 libtirpc/src/auth_none.c create mode 100644 libtirpc/src/auth_sspi.c create mode 100644 libtirpc/src/auth_time.c create mode 100644 libtirpc/src/auth_unix.c create mode 100644 libtirpc/src/authdes_prot.c create mode 100644 libtirpc/src/authgss_prot.c create mode 100644 libtirpc/src/authunix_prot.c create mode 100644 libtirpc/src/bindresvport.c create mode 100644 libtirpc/src/clnt_bcast.c create mode 100644 libtirpc/src/clnt_dg.c create mode 100644 libtirpc/src/clnt_generic.c create mode 100644 libtirpc/src/clnt_perror.c create mode 100644 libtirpc/src/clnt_raw.c create mode 100644 libtirpc/src/clnt_simple.c create mode 100644 libtirpc/src/clnt_vc.c create mode 100644 libtirpc/src/crypt_client.c create mode 100644 libtirpc/src/des_crypt.c create mode 100644 libtirpc/src/des_soft.c create mode 100644 libtirpc/src/epoll_sub.c create mode 100644 libtirpc/src/getnetconfig.c create mode 100644 libtirpc/src/getnetpath.c create mode 100644 libtirpc/src/getpeereid.c create mode 100644 libtirpc/src/getpublickey.c create mode 100644 libtirpc/src/getrpcent.c create mode 100644 libtirpc/src/getrpcport.c create mode 100644 libtirpc/src/gettimeofday.c create mode 100644 libtirpc/src/key_call.c create mode 100644 libtirpc/src/key_prot_xdr.c create mode 100644 libtirpc/src/libtirpc.def create mode 100644 libtirpc/src/makefile create mode 100644 libtirpc/src/mt_misc.c create mode 100644 libtirpc/src/netname.c create mode 100644 libtirpc/src/netnamer.c create mode 100644 libtirpc/src/pmap_clnt.c create mode 100644 libtirpc/src/pmap_getmaps.c create mode 100644 libtirpc/src/pmap_getport.c create mode 100644 libtirpc/src/pmap_prot.c create mode 100644 libtirpc/src/pmap_prot2.c create mode 100644 libtirpc/src/pmap_rmt.c create mode 100644 libtirpc/src/rpc_callmsg.c create mode 100644 libtirpc/src/rpc_com.h create mode 100644 libtirpc/src/rpc_commondata.c create mode 100644 libtirpc/src/rpc_dtablesize.c create mode 100644 libtirpc/src/rpc_generic.c create mode 100644 libtirpc/src/rpc_prot.c create mode 100644 libtirpc/src/rpc_soc.c create mode 100644 libtirpc/src/rpcb_clnt.c create mode 100644 libtirpc/src/rpcb_prot.c create mode 100644 libtirpc/src/rpcb_st_xdr.c create mode 100644 libtirpc/src/rpcdname.c create mode 100644 libtirpc/src/rtime.c create mode 100644 libtirpc/src/sources create mode 100644 libtirpc/src/svc.c create mode 100644 libtirpc/src/svc_auth.c create mode 100644 libtirpc/src/svc_auth_des.c create mode 100644 libtirpc/src/svc_auth_gss.c create mode 100644 libtirpc/src/svc_auth_none.c create mode 100644 libtirpc/src/svc_auth_unix.c create mode 100644 libtirpc/src/svc_dg.c create mode 100644 libtirpc/src/svc_generic.c create mode 100644 libtirpc/src/svc_raw.c create mode 100644 libtirpc/src/svc_run.c create mode 100644 libtirpc/src/svc_simple.c create mode 100644 libtirpc/src/svc_vc.c create mode 100644 libtirpc/src/winstubs.c create mode 100644 libtirpc/src/wintirpc.c create mode 100644 libtirpc/src/xdr.c create mode 100644 libtirpc/src/xdr_array.c create mode 100644 libtirpc/src/xdr_float.c create mode 100644 libtirpc/src/xdr_mem.c create mode 100644 libtirpc/src/xdr_rec.c create mode 100644 libtirpc/src/xdr_reference.c create mode 100644 libtirpc/src/xdr_sizeof.c create mode 100644 libtirpc/src/xdr_stdio.c create mode 100644 libtirpc/tirpc/fpmath.h create mode 100644 libtirpc/tirpc/getpeereid.h create mode 100644 libtirpc/tirpc/libc_private.h create mode 100644 libtirpc/tirpc/misc/event.h create mode 100644 libtirpc/tirpc/misc/queue.h create mode 100644 libtirpc/tirpc/misc/socket.h create mode 100644 libtirpc/tirpc/namespace.h create mode 100644 libtirpc/tirpc/netconfig.h create mode 100644 libtirpc/tirpc/nss_tls.h create mode 100644 libtirpc/tirpc/reentrant.h create mode 100644 libtirpc/tirpc/rpc/auth.h create mode 100644 libtirpc/tirpc/rpc/auth_des.h create mode 100644 libtirpc/tirpc/rpc/auth_gss.h create mode 100644 libtirpc/tirpc/rpc/auth_kerb.h create mode 100644 libtirpc/tirpc/rpc/auth_unix.h create mode 100644 libtirpc/tirpc/rpc/clnt.h create mode 100644 libtirpc/tirpc/rpc/clnt_soc.h create mode 100644 libtirpc/tirpc/rpc/clnt_stat.h create mode 100644 libtirpc/tirpc/rpc/des.h create mode 100644 libtirpc/tirpc/rpc/des_crypt.h create mode 100644 libtirpc/tirpc/rpc/nettype.h create mode 100644 libtirpc/tirpc/rpc/pmap_clnt.h create mode 100644 libtirpc/tirpc/rpc/pmap_prot.h create mode 100644 libtirpc/tirpc/rpc/pmap_rmt.h create mode 100644 libtirpc/tirpc/rpc/raw.h create mode 100644 libtirpc/tirpc/rpc/rpc.h create mode 100644 libtirpc/tirpc/rpc/rpc_com.h create mode 100644 libtirpc/tirpc/rpc/rpc_msg.h create mode 100644 libtirpc/tirpc/rpc/rpcb_clnt.h create mode 100644 libtirpc/tirpc/rpc/rpcb_prot.h create mode 100644 libtirpc/tirpc/rpc/rpcb_prot.x create mode 100644 libtirpc/tirpc/rpc/rpcent.h create mode 100644 libtirpc/tirpc/rpc/svc.h create mode 100644 libtirpc/tirpc/rpc/svc_auth.h create mode 100644 libtirpc/tirpc/rpc/svc_dg.h create mode 100644 libtirpc/tirpc/rpc/svc_soc.h create mode 100644 libtirpc/tirpc/rpc/types.h create mode 100644 libtirpc/tirpc/rpc/xdr.h create mode 100644 libtirpc/tirpc/rpcsvc/crypt.h create mode 100644 libtirpc/tirpc/rpcsvc/crypt.x create mode 100644 libtirpc/tirpc/rpcsvc/nis.h create mode 100644 libtirpc/tirpc/spinlock.h create mode 100644 libtirpc/tirpc/sys/queue.h create mode 100644 libtirpc/tirpc/un-namespace.h create mode 100644 libtirpc/tirpc/wintirpc.h create mode 100644 mount/enum.c create mode 100644 mount/mount.c create mode 100644 mount/options.c create mode 100644 mount/options.h create mode 100644 mount/sources create mode 100644 nfs41rdr.inf create mode 100644 sys/makefile create mode 100644 sys/nfs41_debug.c create mode 100644 sys/nfs41_debug.h create mode 100644 sys/nfs41_driver.c create mode 100644 sys/nfs41_driver.h create mode 100644 sys/nfs41_driver.ini create mode 100644 sys/nfs41_driver.rc create mode 100644 sys/sources create mode 100644 sys/wmlkm.c create mode 100644 sys/wmlkm.h create mode 100644 uninstall.bat diff --git a/README.html b/README.html new file mode 100644 index 0000000..bd9a9a5 --- /dev/null +++ b/README.html @@ -0,0 +1,107 @@ + + + + + Windows NFS 4.1 Client Instructions + + + + + + +
+

Windows NFS 4.1 Client Instructions

+
+ +

1. Building

+

Requirements

+
    +
  • ms-nfs41-client source code: +
    > git clone git://citi.umich.edu/projects/ms-nfs41-client.git
  • +
  • Windows Driver Development Kit (WinDDK 6000 or later)
  • +
+

Instructions

+
    +
  1. Open the WinDDK build environment for the target platform.
  2. +
  3. Change directory to ms-nfs41-client and type build. The project should build without errors.
  4. +
+

2. Installation

+

Requirements

+
    +
  • ms-nfs41-client binaries: nfs41_driver.sys, nfs41_np.dll, libtirpc.dll, nfs_install.exe, nfsd.exe, nfs_mount.exe
  • +
  • ms-nfs41-client configuration files: nfs41rdr.inf, install.bat, uninstall.bat, etc_netconfig
  • +
  • a certificate for test signing (http://msdn.microsoft.com/en-us/library/aa906283.aspx)
  • +
+

Instructions

+
    +
  1. Copy or extract all ms-nfs41-client binaries and configuration files into a directory that's convenient for testing.
  2. +
  3. Open an Administrator command prompt in this directory.
  4. +
  5. Test sign nfs41_driver.sys.
  6. +
  7. Install the driver and update the registry: +
    > install.bat
  8. +
  9. Copy the libtirpc configuration: +
    > mkdir C:\etc +
    > copy etc_netconfig C:\etc\netconfig
  10. +
  11. Allow windows to load test-signed drivers: +
    > bcdedit /set testsigning on
  12. +
  13. Install the certificate used for test signing to the 'Trusted Root Certificate Authorities' store.
  14. +
  15. Open the Control Panel, navigate to User Accounts, and disable User Account Control (see 5. Known Issues).
  16. +
  17. Reboot.
  18. +
+

3. Mounting

+

Instructions

+
    +
  1. Run nfsd.exe
  2. +
  3. Open a command prompt and run nfs_mount.exe to mount a share: +
    > nfs_mount.exe Z: nfs.citi.umich.edu:\
  4. +
  5. You can later unmount with: +
    > nfs_mount.exe -d Z
  6. +
+

4. Connectathon

+

Requirements

+
    +
  • Cygwin, including packages gcc-core, make, sunrpc, time
  • +
  • ms-nfs41-client source code (ported tests are located in ms-nfs41-client\tests\cthon04)
  • +
+

Instructions

+
    +
  1. Copy ms-nfs41-client\tests\cthon04 into a directory that's convenient for testing.
  2. +
  3. Open a cygwin shell, and change directory to cthon04.
  4. +
  5. Run the test suite on a mounted directory: +
    > ./runtests -a -t z:/testdir
  6. +
+

5. Known Issues

+
    +
  • Mounts must be obtained through nfs_mount.exe, and not via 'net use' or 'Map Network Drive'.
  • +
  • When nfs_mount.exe is run without arguments, it does not properly list mounted drives.
  • +
  • If nfsd.exe is restarted while a drive is mapped, that drive needs to be remounted before further use.
  • +
  • Symbolic links are not supported. Connectathon's basic test8 will not pass.
  • +
  • Does not properly handle renaming a file on top of an existing open file- the existing file is removed on rename, and not preserved until last close.
  • +
+
+
+ + \ No newline at end of file diff --git a/build.vc10/.gitignore b/build.vc10/.gitignore new file mode 100644 index 0000000..550339d --- /dev/null +++ b/build.vc10/.gitignore @@ -0,0 +1,7 @@ +# exclude all build files by default +* + +# allow visual studio project and solution files +!*.vcxproj +!*.vcxproj.filters +!*.sln diff --git a/build.vc10/daemon.vcxproj b/build.vc10/daemon.vcxproj new file mode 100644 index 0000000..ba0e9cb --- /dev/null +++ b/build.vc10/daemon.vcxproj @@ -0,0 +1,254 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {D0D81A98-2946-4A16-A4A1-800387C3F3D1} + daemon + + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + MultiByte + true + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + nfsd + nfsd + nfsd + nfsd + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + Disabled + ..\sys;..\xdr;..\dll;..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) + true + + + EnableFastChecks + MultiThreadedDebugDLL + false + Level4 + EditAndContinue + CompileAsC + + + ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + MachineX86 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + Disabled + ..\sys;..\xdr;..\dll;..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) + true + + + EnableFastChecks + MultiThreadedDebugDLL + false + Level4 + ProgramDatabase + CompileAsC + + + ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + MachineX64 + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + MaxSpeed + true + ..\sys;..\xdr;..\dll;..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) + + + MultiThreadedDLL + true + false + Level4 + ProgramDatabase + CompileAsC + + + ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + true + MachineX86 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + MaxSpeed + true + ..\sys;..\xdr;..\dll;..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions) + + + MultiThreadedDLL + true + false + Level4 + ProgramDatabase + CompileAsC + + + ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + true + true + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {2d918a9b-de52-470a-93d5-78ea2c8113a1} + false + + + + + + \ No newline at end of file diff --git a/build.vc10/daemon.vcxproj.filters b/build.vc10/daemon.vcxproj.filters new file mode 100644 index 0000000..62ae369 --- /dev/null +++ b/build.vc10/daemon.vcxproj.filters @@ -0,0 +1,160 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {b39281cd-23c6-401e-844b-3d6c763da90b} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + diff --git a/build.vc10/dll.vcxproj b/build.vc10/dll.vcxproj new file mode 100644 index 0000000..1315b1c --- /dev/null +++ b/build.vc10/dll.vcxproj @@ -0,0 +1,208 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C} + dll + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + Disabled + ..\sys;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + true + + + EnableFastChecks + MultiThreadedDebugDLL + false + Level4 + EditAndContinue + CompileAsC + + + $(OutDir)nfs41_np.dll + ..\dll\nfs41_np.def + true + 0x1010000 + MachineX86 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + Disabled + ..\sys;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + true + + + EnableFastChecks + MultiThreadedDebugDLL + false + Level4 + ProgramDatabase + CompileAsC + + + $(OutDir)nfs41_np.dll + ..\dll\nfs41_np.def + true + 0x1010000 + MachineX64 + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + MaxSpeed + true + ..\sys;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + + + MultiThreadedDLL + true + false + Level4 + ProgramDatabase + CompileAsC + + + $(OutDir)nfs41_np.dll + ..\dll\nfs41_np.def + true + true + true + 0x1010000 + MachineX86 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + MaxSpeed + true + ..\sys;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + + + MultiThreadedDLL + true + false + Level4 + ProgramDatabase + CompileAsC + + + $(OutDir)nfs41_np.dll + ..\dll\nfs41_np.def + true + true + true + 0x1010000 + MachineX64 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.vc10/dll.vcxproj.filters b/build.vc10/dll.vcxproj.filters new file mode 100644 index 0000000..4936e2f --- /dev/null +++ b/build.vc10/dll.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/build.vc10/env.props.example b/build.vc10/env.props.example new file mode 100644 index 0000000..54a10fd --- /dev/null +++ b/build.vc10/env.props.example @@ -0,0 +1,20 @@ + + + + C:\WinDDK\7600.16385.0 + + + <_ProjectFileVersion>10.0.30319.1 + <_PropertySheetDisplayName>ddk_env + + + + $(WDKPATH)\inc\ddk;$(WDKPATH)\inc\api;$(WDKPATH)\inc\crt;%(AdditionalIncludeDirectories) + + + + + $(WDKPATH) + + + \ No newline at end of file diff --git a/build.vc10/libtirpc.vcxproj b/build.vc10/libtirpc.vcxproj new file mode 100644 index 0000000..1e5bbcc --- /dev/null +++ b/build.vc10/libtirpc.vcxproj @@ -0,0 +1,308 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2D918A9B-DE52-470A-93D5-78EA2C8113A1} + libtirpc + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + INET6;FD_SETSIZE=128;PORTMAP;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + ..\libtirpc\libtirpc\libtirpc.def + true + Windows + MachineX86 + + + + + X64 + + + Disabled + ..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + INET6;FD_SETSIZE=128;PORTMAP;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + ..\libtirpc\libtirpc\libtirpc.def + true + Windows + + + MachineX64 + + + + + MaxSpeed + true + ..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + INET6;FD_SETSIZE=128;PORTMAP;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + ..\libtirpc\libtirpc\libtirpc.def + true + Windows + true + true + MachineX86 + + + + + X64 + + + MaxSpeed + true + ..\libtirpc\tirpc;%(AdditionalIncludeDirectories) + INET6;FD_SETSIZE=128;PORTMAP;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + ..\libtirpc\libtirpc\libtirpc.def + true + Windows + true + true + + + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.vc10/libtirpc.vcxproj.filters b/build.vc10/libtirpc.vcxproj.filters new file mode 100644 index 0000000..d4485cc --- /dev/null +++ b/build.vc10/libtirpc.vcxproj.filters @@ -0,0 +1,358 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/build.vc10/mount.vcxproj b/build.vc10/mount.vcxproj new file mode 100644 index 0000000..51bd675 --- /dev/null +++ b/build.vc10/mount.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5AEA3497-6852-471B-A252-ADA60B22A342} + mount + + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + MultiByte + true + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + Disabled + ..\sys;%(AdditionalIncludeDirectories) + true + + + EnableFastChecks + MultiThreadedDebugDLL + Level4 + EditAndContinue + CompileAsC + + + mpr.lib;%(AdditionalDependencies) + true + MachineX86 + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + MaxSpeed + true + ..\sys;%(AdditionalIncludeDirectories) + + + MultiThreadedDLL + true + Level4 + ProgramDatabase + CompileAsC + + + mpr.lib;%(AdditionalDependencies) + true + true + true + MachineX86 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + Disabled + ..\sys;%(AdditionalIncludeDirectories) + true + + + EnableFastChecks + MultiThreadedDebugDLL + Level4 + ProgramDatabase + CompileAsC + + + mpr.lib;%(AdditionalDependencies) + true + MachineX64 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 %(AdditionalOptions) + MaxSpeed + true + ..\sys;%(AdditionalIncludeDirectories) + + + MultiThreadedDLL + true + Level4 + ProgramDatabase + CompileAsC + + + mpr.lib;%(AdditionalDependencies) + true + true + true + MachineX64 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.vc10/mount.vcxproj.filters b/build.vc10/mount.vcxproj.filters new file mode 100644 index 0000000..b745a21 --- /dev/null +++ b/build.vc10/mount.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/build.vc10/ms-nfs41-client.sln b/build.vc10/ms-nfs41-client.sln new file mode 100644 index 0000000..e8cef65 --- /dev/null +++ b/build.vc10/ms-nfs41-client.sln @@ -0,0 +1,76 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "daemon", "daemon.vcxproj", "{D0D81A98-2946-4A16-A4A1-800387C3F3D1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dll", "dll.vcxproj", "{372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nfs41_driver", "nfs41_driver.vcxproj", "{B64D3074-519F-476A-A3AA-DAD6554CBB68}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mount", "mount.vcxproj", "{5AEA3497-6852-471B-A252-ADA60B22A342}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtirpc", "libtirpc.vcxproj", "{2D918A9B-DE52-470A-93D5-78EA2C8113A1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nfs_install", "nfs_install.vcxproj", "{A453DC17-BE6B-4271-A020-66E054AB5908}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|Win32.ActiveCfg = Debug|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|Win32.Build.0 = Debug|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|x64.ActiveCfg = Debug|x64 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|x64.Build.0 = Debug|x64 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|Win32.ActiveCfg = Release|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|Win32.Build.0 = Release|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|x64.ActiveCfg = Release|x64 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|x64.Build.0 = Release|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|Win32.ActiveCfg = Debug|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|Win32.Build.0 = Debug|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|x64.ActiveCfg = Debug|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|x64.Build.0 = Debug|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|Win32.ActiveCfg = Release|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|Win32.Build.0 = Release|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|x64.ActiveCfg = Release|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|x64.Build.0 = Release|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|Win32.ActiveCfg = Debug|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|Win32.Build.0 = Debug|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|x64.ActiveCfg = Debug|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|x64.Build.0 = Debug|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|Win32.ActiveCfg = Release|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|Win32.Build.0 = Release|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|x64.ActiveCfg = Release|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|x64.Build.0 = Release|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|Win32.Build.0 = Debug|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|x64.ActiveCfg = Debug|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|x64.Build.0 = Debug|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|Win32.ActiveCfg = Release|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|Win32.Build.0 = Release|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|x64.ActiveCfg = Release|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|x64.Build.0 = Release|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|Win32.ActiveCfg = Debug|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|Win32.Build.0 = Debug|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|x64.ActiveCfg = Debug|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|x64.Build.0 = Debug|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|Win32.ActiveCfg = Release|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|Win32.Build.0 = Release|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|x64.ActiveCfg = Release|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|x64.Build.0 = Release|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|Win32.ActiveCfg = Debug|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|Win32.Build.0 = Debug|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|x64.ActiveCfg = Debug|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|x64.Build.0 = Debug|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|Win32.ActiveCfg = Release|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|Win32.Build.0 = Release|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|x64.ActiveCfg = Release|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build.vc10/nfs41_driver.vcxproj b/build.vc10/nfs41_driver.vcxproj new file mode 100644 index 0000000..4a0f569 --- /dev/null +++ b/build.vc10/nfs41_driver.vcxproj @@ -0,0 +1,148 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B64D3074-519F-476A-A3AA-DAD6554CBB68} + MakeFileProj + + + + Makefile + + + Makefile + + + Makefile + + + Makefile + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + C:\projects\ms-nfs41-client\sys\objchk_wlh_x86\ + C:\projects\ms-nfs41-client\sys\objchk_wlh_x86\ + call $(WDKPATH)\bin\setenv.bat $(WDKPATH) chk x86 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objchk_wlh_x86 +call $(WDKPATH)\bin\setenv.bat $(WDKPATH) chk x86 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objchk_wlh_x86 + C:\projects\ms-nfs41-client\sys\objchk_wlh_x86\i386\nfs41_driver.sys + WIN32;_CONSOLE;_X86_;_DDK_;_DEBUG;DBG=1;$(NMakePreprocessorDefinitions) + $(WDKPATH)\inc\ddk;$(WDKPATH)\inc\api;$(WDKPATH)\inc\crt;$(NMakeIncludeSearchPath) + $(NMakeForcedIncludes) + $(NMakeAssemblySearchPath) + $(NMakeForcedUsingAssemblies) + C:\projects\ms-nfs41-client\sys\objchk_wlh_amd64\ + C:\projects\ms-nfs41-client\sys\objchk_wlh_amd64\ + call $(WDKPATH)\bin\setenv.bat $(WDKPATH) chk x64 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objchk_wlh_amd64 +call $(WDKPATH)\bin\setenv.bat $(WDKPATH) chk x64 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objchk_wlh_amd64 + C:\projects\ms-nfs41-client\sys\objchk_wlh_amd64\amd64\nfs41_driver.sys + WIN32;_CONSOLE;_AMD64_;_DDK_;_DEBUG;DBG=1;$(NMakePreprocessorDefinitions) + $(WDKPATH)\inc\ddk;$(WDKPATH)\inc\api;$(WDKPATH)\inc\crt;$(NMakeIncludeSearchPath) + $(NMakeForcedIncludes) + $(NMakeAssemblySearchPath) + $(NMakeForcedUsingAssemblies) + C:\projects\ms-nfs41-client\sys\objfre_wlh_x86\ + C:\projects\ms-nfs41-client\sys\objfre_wlh_x86\ + call $(WDKPATH)\bin\setenv.bat $(WDKPATH) fre x86 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objfre_wlh_x86 +call $(WDKPATH)\bin\setenv.bat $(WDKPATH) fre x86 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objfre_wlh_x86 + C:\projects\ms-nfs41-client\sys\objfre_wlh_x86\i386\nfs41_driver.sys + WIN32;_CONSOLE;_X86_;_DDK_;_NDEBUG;DBG=0;$(NMakePreprocessorDefinitions) + $(WDKPATH)\inc\ddk;$(WDKPATH)\inc\api;$(WDKPATH)\inc\crt;$(NMakeIncludeSearchPath) + $(NMakeForcedIncludes) + $(NMakeAssemblySearchPath) + $(NMakeForcedUsingAssemblies) + C:\projects\ms-nfs41-client\sys\objfre_wlh_amd64\ + C:\projects\ms-nfs41-client\sys\objfre_wlh_amd64\ + call $(WDKPATH)\bin\setenv.bat $(WDKPATH) fre x64 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objfre_wlh_amd64 +call $(WDKPATH)\bin\setenv.bat $(WDKPATH) fre x64 wlh +cd /d C:\projects\ms-nfs41-client\sys +build + rmdir /s /q C:\projects\ms-nfs41-client\sys\objfre_wlh_amd64 + C:\projects\ms-nfs41-client\sys\objfre_wlh_amd64\amd64\nfs41_driver.sys + WIN32;_CONSOLE;_AMD64_;_DDK_;_NDEBUG;DBG=0;$(NMakePreprocessorDefinitions) + $(WDKPATH)\inc\ddk;$(WDKPATH)\inc\api;$(WDKPATH)\inc\crt;$(NMakeIncludeSearchPath) + $(NMakeForcedIncludes) + $(NMakeAssemblySearchPath) + $(NMakeForcedUsingAssemblies) + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.vc10/nfs41_driver.vcxproj.filters b/build.vc10/nfs41_driver.vcxproj.filters new file mode 100644 index 0000000..fc181db --- /dev/null +++ b/build.vc10/nfs41_driver.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + {5cb3db05-7cb6-47df-835b-1f900bc6588b} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {3eaffb55-1a2a-45b8-9ab0-1ae04813d050} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {b673e717-daca-4c21-8935-bee66da864fb} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source files + + + Source files + + + Source files + + + + + Resource files + + + Resource files + + + Resource files + + + + + Resource files + + + + + Header files + + + Header files + + + Header files + + + \ No newline at end of file diff --git a/build.vc10/nfs_install.vcxproj b/build.vc10/nfs_install.vcxproj new file mode 100644 index 0000000..56706d9 --- /dev/null +++ b/build.vc10/nfs_install.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A453DC17-BE6B-4271-A020-66E054AB5908} + nfs_install + + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + MultiByte + true + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4201 /wd4214 %(AdditionalOptions) + Disabled + ..\sys;%(AdditionalIncludeDirectories) + true + + + EnableFastChecks + MultiThreadedDebugDLL + Level3 + EditAndContinue + CompileAsC + + + true + MachineX86 + + + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4201 /wd4214 %(AdditionalOptions) + MaxSpeed + true + ..\sys;%(AdditionalIncludeDirectories) + + + MultiThreadedDLL + true + Level3 + ProgramDatabase + CompileAsC + + + true + true + true + MachineX86 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4201 /wd4214 %(AdditionalOptions) + Disabled + ..\sys;%(AdditionalIncludeDirectories) + true + + + EnableFastChecks + MultiThreadedDebugDLL + Level3 + ProgramDatabase + CompileAsC + + + true + MachineX64 + + + + + X64 + + + /Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4201 /wd4214 %(AdditionalOptions) + MaxSpeed + true + ..\sys;%(AdditionalIncludeDirectories) + + + MultiThreadedDLL + true + Level3 + ProgramDatabase + CompileAsC + + + true + true + true + MachineX64 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.vc10/nfs_install.vcxproj.filters b/build.vc10/nfs_install.vcxproj.filters new file mode 100644 index 0000000..e54eb5d --- /dev/null +++ b/build.vc10/nfs_install.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/build.vc9/.gitignore b/build.vc9/.gitignore new file mode 100644 index 0000000..9efd899 --- /dev/null +++ b/build.vc9/.gitignore @@ -0,0 +1,6 @@ +# exclude all build files by default +* + +# allow visual studio project and solution files +!*.vcproj +!*.sln diff --git a/build.vc9/daemon.vcproj b/build.vc9/daemon.vcproj new file mode 100644 index 0000000..974c7c0 --- /dev/null +++ b/build.vc9/daemon.vcproj @@ -0,0 +1,536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.vc9/dll.vcproj b/build.vc9/dll.vcproj new file mode 100644 index 0000000..188b2b8 --- /dev/null +++ b/build.vc9/dll.vcproj @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.vc9/env.vsprops.example b/build.vc9/env.vsprops.example new file mode 100644 index 0000000..f7db359 --- /dev/null +++ b/build.vc9/env.vsprops.example @@ -0,0 +1,28 @@ + + + + + + diff --git a/build.vc9/libtirpc.vcproj b/build.vc9/libtirpc.vcproj new file mode 100644 index 0000000..fd6ec09 --- /dev/null +++ b/build.vc9/libtirpc.vcproj @@ -0,0 +1,793 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.vc9/mount.vcproj b/build.vc9/mount.vcproj new file mode 100644 index 0000000..7ebdecc --- /dev/null +++ b/build.vc9/mount.vcproj @@ -0,0 +1,362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.vc9/ms-nfs41-client.sln b/build.vc9/ms-nfs41-client.sln new file mode 100644 index 0000000..9c6de20 --- /dev/null +++ b/build.vc9/ms-nfs41-client.sln @@ -0,0 +1,79 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "daemon", "daemon.vcproj", "{D0D81A98-2946-4A16-A4A1-800387C3F3D1}" + ProjectSection(ProjectDependencies) = postProject + {2D918A9B-DE52-470A-93D5-78EA2C8113A1} = {2D918A9B-DE52-470A-93D5-78EA2C8113A1} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dll", "dll.vcproj", "{372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nfs41_driver", "nfs41_driver.vcproj", "{B64D3074-519F-476A-A3AA-DAD6554CBB68}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mount", "mount.vcproj", "{5AEA3497-6852-471B-A252-ADA60B22A342}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtirpc", "libtirpc.vcproj", "{2D918A9B-DE52-470A-93D5-78EA2C8113A1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nfs_install", "nfs_install.vcproj", "{A453DC17-BE6B-4271-A020-66E054AB5908}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|Win32.ActiveCfg = Debug|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|Win32.Build.0 = Debug|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|x64.ActiveCfg = Debug|x64 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Debug|x64.Build.0 = Debug|x64 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|Win32.ActiveCfg = Release|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|Win32.Build.0 = Release|Win32 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|x64.ActiveCfg = Release|x64 + {D0D81A98-2946-4A16-A4A1-800387C3F3D1}.Release|x64.Build.0 = Release|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|Win32.ActiveCfg = Debug|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|Win32.Build.0 = Debug|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|x64.ActiveCfg = Debug|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Debug|x64.Build.0 = Debug|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|Win32.ActiveCfg = Release|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|Win32.Build.0 = Release|Win32 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|x64.ActiveCfg = Release|x64 + {372D9D02-CDC5-43AE-BB0A-FB57CEFC639C}.Release|x64.Build.0 = Release|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|Win32.ActiveCfg = Debug|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|Win32.Build.0 = Debug|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|x64.ActiveCfg = Debug|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Debug|x64.Build.0 = Debug|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|Win32.ActiveCfg = Release|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|Win32.Build.0 = Release|Win32 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|x64.ActiveCfg = Release|x64 + {B64D3074-519F-476A-A3AA-DAD6554CBB68}.Release|x64.Build.0 = Release|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|Win32.ActiveCfg = Debug|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|Win32.Build.0 = Debug|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|x64.ActiveCfg = Debug|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Debug|x64.Build.0 = Debug|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|Win32.ActiveCfg = Release|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|Win32.Build.0 = Release|Win32 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|x64.ActiveCfg = Release|x64 + {5AEA3497-6852-471B-A252-ADA60B22A342}.Release|x64.Build.0 = Release|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|Win32.ActiveCfg = Debug|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|Win32.Build.0 = Debug|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|x64.ActiveCfg = Debug|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Debug|x64.Build.0 = Debug|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|Win32.ActiveCfg = Release|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|Win32.Build.0 = Release|Win32 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|x64.ActiveCfg = Release|x64 + {2D918A9B-DE52-470A-93D5-78EA2C8113A1}.Release|x64.Build.0 = Release|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|Win32.ActiveCfg = Debug|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|Win32.Build.0 = Debug|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|x64.ActiveCfg = Debug|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Debug|x64.Build.0 = Debug|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|Win32.ActiveCfg = Release|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|Win32.Build.0 = Release|Win32 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|x64.ActiveCfg = Release|x64 + {A453DC17-BE6B-4271-A020-66E054AB5908}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build.vc9/nfs41_driver.vcproj b/build.vc9/nfs41_driver.vcproj new file mode 100644 index 0000000..ae89fdb --- /dev/null +++ b/build.vc9/nfs41_driver.vcproj @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.vc9/nfs_install.vcproj b/build.vc9/nfs_install.vcproj new file mode 100644 index 0000000..b73165c --- /dev/null +++ b/build.vc9/nfs_install.vcproj @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/callback_server.c b/daemon/callback_server.c new file mode 100644 index 0000000..66fe9b5 --- /dev/null +++ b/daemon/callback_server.c @@ -0,0 +1,381 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ +#include +#include + +#include "nfs41.h" +#include "nfs41_ops.h" +#include "nfs41_callback.h" +#include "daemon_debug.h" + +#define CBSLVL 2 /* dprintf level for callback server logging */ + + +static const char g_server_tag[] = "ms-nfs41-callback"; + + +/* OP_CB_LAYOUTRECALL */ +static enum_t handle_cb_layoutrecall( + IN nfs41_rpc_clnt *rpc_clnt, + IN struct cb_layoutrecall_args *args, + OUT struct cb_layoutrecall_res *res) +{ + enum pnfs_status status; + /* forgetful model for layout recalls; return NOMATCHING_LAYOUT + * and flag the layout(s) to prevent further use */ + res->status = NFS4ERR_NOMATCHING_LAYOUT; + + dprintf(CBSLVL, " OP_CB_LAYOUTRECALL { %s, %s, recall %u } %s\n", + pnfs_layout_type_string(args->type), + pnfs_iomode_string(args->iomode), args->recall.type, + nfs_error_string(res->status)); + + status = pnfs_file_layout_recall(rpc_clnt->client->layouts, args); + if (status) + eprintf("pnfs_file_layout_recall() failed with %s\n", + pnfs_error_string(status)); + + return res->status; +} + +/* OP_CB_RECALL_SLOT */ +static enum_t handle_cb_recall_slot( + IN struct cb_recall_slot_args *args, + OUT struct cb_recall_slot_res *res) +{ + res->status = NFS4_OK; + + dprintf(CBSLVL, " OP_CB_RECALL_SLOT { %u } %s\n", + args->target_highest_slotid, nfs_error_string(res->status)); + return res->status; +} + +/* OP_CB_SEQUENCE */ +static enum_t handle_cb_sequence( + IN nfs41_rpc_clnt *rpc_clnt, + IN struct cb_sequence_args *args, + OUT struct cb_sequence_res *res) +{ + nfs41_cb_session *cb_session = &rpc_clnt->client->session->cb_session; + uint32_t status = NFS4_OK; + res->status = NFS4_OK; + + if (!cb_session->cb_is_valid_state) { + memcpy(cb_session->cb_sessionid, args->sessionid, NFS4_SESSIONID_SIZE); + if (args->sequenceid != 1) { + eprintf("[cb] 1st seq#=%d is not 1\n", args->sequenceid); + res->status = NFS4ERR_SEQ_MISORDERED; + goto out; + } + cb_session->cb_is_valid_state = TRUE; + } else { + if (memcmp(cb_session->cb_sessionid, args->sessionid, + NFS4_SESSIONID_SIZE)) { + eprintf("[cb] received sessionid doesn't match saved info\n"); + print_hexbuf(1, (unsigned char *)"received sessionid", + (unsigned char *)args->sessionid, NFS4_SESSIONID_SIZE); + print_hexbuf(1, (unsigned char *)"saved sessionid", + cb_session->cb_sessionid, NFS4_SESSIONID_SIZE); + res->status = NFS4ERR_BADSESSION; + goto out; + } + } + + /* 20.9.3.: If the difference between csa_sequenceid and the client's + * cachedsequence ID at the slot ID is two (2) or more, or if + * csa_sequenceid is less than the cached sequence ID (accounting for + * wraparound of the unsigned sequence ID value), then the client + * MUST return NFS4ERR_SEQ_MISORDERED. + */ + if (args->sequenceid < cb_session->cb_seqnum || + (args->sequenceid - cb_session->cb_seqnum >= 2)) { + eprintf("[cb] bad received seq#=%d, expected=%d\n", + args->sequenceid, cb_session->cb_seqnum+1); + res->status = NFS4ERR_SEQ_MISORDERED; + goto out; + } + + /* we only support 1 slot for the back channel so slotid MUST be 0 */ + if (args->slotid != 0) { + eprintf("[cb] received unexpected slotid=%d\n", args->slotid); + res->status = NFS4ERR_BADSLOT; + goto out; + } + if (args->highest_slotid != 0) { + eprintf("[cb] received unexpected highest_slotid=%d\n", + args->highest_slotid); + res->status = NFS4ERR_BAD_HIGH_SLOT; + goto out; + } + + if (args->sequenceid == cb_session->cb_seqnum) { + // check if the request is same as the original, if different need + // to return NFS4ERR_SEQ_FALSE_RETRY + if (!cb_session->cb_cache_this) { + res->status = NFS4_OK; + status = NFS4ERR_RETRY_UNCACHED_REP; + goto out; + } else { + res->status = NFS4ERR_REP_TOO_BIG_TO_CACHE; + goto out; + } + } + if (cb_session->cb_seqnum + 1 == 0) + cb_session->cb_seqnum = 0; + else + cb_session->cb_seqnum = args->sequenceid; + cb_session->cb_cache_this = args->cachethis; + + memcpy(res->ok.sessionid, args->sessionid, NFS4_SESSIONID_SIZE); + res->ok.sequenceid = args->sequenceid; + res->ok.slotid = args->slotid; + res->ok.highest_slotid = args->highest_slotid; + res->ok.target_highest_slotid = args->highest_slotid; + +out: + dprintf(CBSLVL, " OP_CB_SEQUENCE { seqid %u, slot %u, cachethis %d } " + "%s\n", args->sequenceid, args->slotid, args->cachethis, + nfs_error_string(res->status)); + return status; +} + +/* OP_CB_RECALL */ +typedef struct _nfs41_cb_recall { + nfs41_rpc_clnt *rpc_clnt; + struct cb_recall_args *args; +} nfs41_cb_recall; + +static unsigned int WINAPI _handle_cb_recall(void *args) +{ + nfs41_cb_recall *cb_args = (nfs41_cb_recall *)args; + nfs41_path_fh path_fh; + + dprintf(1, "_handle_cb_recall: start\n"); + print_hexbuf(3, (unsigned char *)"_handle_cb_recall: fh ", + cb_args->args->fh.fh, cb_args->args->fh.len); + print_hexbuf(3, (unsigned char *)"_handle_cb_recall: stateid ", + cb_args->args->stateid.other, 12); + ZeroMemory(&path_fh, sizeof(nfs41_path_fh)); + memcpy(&path_fh.fh, &cb_args->args->fh, sizeof(nfs41_fh)); + path_fh.fh.superblock = NULL; + path_fh.path = NULL; + path_fh.name.len = 0; + dprintf(1, "_handle_cb_recall: sending nfs41_delegreturn\n"); + nfs41_delegreturn(cb_args->rpc_clnt->client->session, &path_fh, + &cb_args->args->stateid); + free(cb_args); + dprintf(1, "_handle_cb_recall: end\n"); + return 1; +} + +static enum_t handle_cb_recall( + IN nfs41_rpc_clnt *rpc_clnt, + IN struct cb_recall_args *args, + OUT struct cb_recall_res *res) +{ + nfs41_cb_recall *cb_args; + res->status = NFS4_OK; + + dprintf(CBSLVL, "OP_CB_RECALL\n"); + cb_args = calloc(1, sizeof(nfs41_cb_recall)); + if (cb_args == NULL) { + res->status = NFS4ERR_RESOURCE; + goto out; + } + cb_args->rpc_clnt = rpc_clnt; + cb_args->args = args; + _beginthreadex(NULL, 0, _handle_cb_recall, cb_args, 0, NULL); +out: + return res->status; +} + +/* CB_COMPOUND */ +static void handle_cb_compound(nfs41_rpc_clnt *rpc_clnt, cb_req *req, struct cb_compound_res **reply) +{ + struct cb_compound_args args = { 0 }; + struct cb_compound_res *res = NULL; + struct cb_argop *argop; + struct cb_resop *resop; + XDR *xdr = (XDR*)req->xdr; + uint32_t i, status = NFS4_OK; + + dprintf(CBSLVL, "--> handle_compound()\n"); + + /* decode the arguments */ + proc_cb_compound_args(xdr, &args); + dprintf(CBSLVL, "CB_COMPOUND('%s', %u)\n", args.tag.str, args.argarray_count); + if (args.minorversion != 1) { + status = NFS4ERR_MINOR_VERS_MISMATCH; //XXXXX + eprintf("args.minorversion %u != 1\n", args.minorversion); + goto out; + } + + /* allocate the compound results */ + res = calloc(1, sizeof(struct cb_compound_res)); + if (res == NULL) { + status = NFS4ERR_RESOURCE; + goto out; + } + res->status = NFS4_OK; + StringCchCopyA(res->tag.str, CB_COMPOUND_MAX_TAG, g_server_tag); + res->tag.str[CB_COMPOUND_MAX_TAG-1] = 0; + res->tag.len = (uint32_t)strlen(res->tag.str); + res->resarray = calloc(args.argarray_count, sizeof(struct cb_resop)); + if (res->resarray == NULL) { + res->status = NFS4ERR_RESOURCE; + goto out; + } + + /* handle each operation in the compound */ + for (i = 0; i < args.argarray_count && res->status == NFS4_OK; i++) { + argop = &args.argarray[i]; + resop = &res->resarray[i]; + + /* 20.9.3: The error NFS4ERR_SEQUENCE_POS MUST be returned + * when CB_SEQUENCE is found in any position in a CB_COMPOUND + * beyond the first. If any other operation is in the first + * position of CB_COMPOUND, NFS4ERR_OP_NOT_IN_SESSION MUST + * be returned. + */ + if (i == 0 && argop->opnum != OP_CB_SEQUENCE) { + res->status = NFS4ERR_OP_NOT_IN_SESSION; + goto out; + } + if (i != 0 && argop->opnum == OP_CB_SEQUENCE) { + res->status = NFS4ERR_SEQUENCE_POS; + goto out; + } + resop->opnum = argop->opnum; + if (status == NFS4ERR_RETRY_UNCACHED_REP) { + res->status = status; + break; + } + + switch (argop->opnum) { + case OP_CB_LAYOUTRECALL: + dprintf(1, "OP_CB_LAYOUTRECALL\n"); + res->status = handle_cb_layoutrecall(rpc_clnt, + &argop->args.layoutrecall, &resop->res.layoutrecall); + break; + case OP_CB_RECALL_SLOT: + dprintf(1, "OP_CB_RECALL_SLOT\n"); + res->status = handle_cb_recall_slot(&argop->args.recall_slot, + &resop->res.recall_slot); + break; + case OP_CB_SEQUENCE: + dprintf(1, "OP_CB_SEQUENCE\n"); + status = handle_cb_sequence(rpc_clnt, &argop->args.sequence, + &resop->res.sequence); + if (status == NFS4_OK) + res->status = resop->res.sequence.status; + break; + case OP_CB_GETATTR: + dprintf(1, "OP_CB_GETATTR\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_RECALL: + dprintf(1, "OP_CB_RECALL\n"); + res->status = handle_cb_recall(rpc_clnt, + &argop->args.recall, &resop->res.recall); + break; + case OP_CB_NOTIFY: + dprintf(1, "OP_CB_NOTIFY\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_PUSH_DELEG: + dprintf(1, "OP_CB_PUSH_DELEG\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_RECALL_ANY: + dprintf(1, "OP_CB_RECALL_ANY\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_RECALLABLE_OBJ_AVAIL: + dprintf(1, "OP_CB_RECALLABLE_OBJ_AVAIL\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_WANTS_CANCELLED: + dprintf(1, "OP_CB_WANTS_CANCELLED\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_NOTIFY_LOCK: + dprintf(1, "OP_CB_NOTIFY_LOCK\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_NOTIFY_DEVICEID: + dprintf(1, "OP_CB_NOTIFY_DEVICEID\n"); + res->status = NFS4ERR_NOTSUPP; + break; + case OP_CB_ILLEGAL: + dprintf(1, "OP_CB_ILLEGAL\n"); + res->status = NFS4ERR_NOTSUPP; + break; + default: + eprintf("operation %u not supported\n", argop->opnum); + res->status = NFS4ERR_NOTSUPP; + goto out; + } + + res->resarray_count++; + } +out: + /* free the arguments */ + xdr->x_op = XDR_FREE; + proc_cb_compound_args(xdr, &args); + + *reply = res; + dprintf(CBSLVL, "<-- handle_compound() returning %s (%u results)\n", + nfs_error_string(res->status), res->resarray_count); +} + +int nfs41_handle_callback(void *rpc_clnt, void *cb, struct cb_compound_res **reply) +{ + nfs41_rpc_clnt *rpc = (nfs41_rpc_clnt *)rpc_clnt; + cb_req *request = (cb_req *)cb; + uint32_t status = 0; + + dprintf(1, "nfs41_handle_callback: received call\n"); + if (request->rq_prog != NFS41_RPC_CBPROGRAM) { + eprintf("invalid rpc program %u\n", request->rq_prog); + status = 2; + goto out; + } + + switch (request->rq_proc) { + case CB_NULL: + dprintf(1, "CB_NULL\n"); + break; + + case CB_COMPOUND: + dprintf(1, "CB_COMPOUND\n"); + handle_cb_compound(rpc, request, reply); + break; + + default: + dprintf(1, "invalid rpc procedure %u\n", request->rq_proc); + status = 3; + goto out; + } +out: + return status; +} \ No newline at end of file diff --git a/daemon/callback_xdr.c b/daemon/callback_xdr.c new file mode 100644 index 0000000..215b717 --- /dev/null +++ b/daemon/callback_xdr.c @@ -0,0 +1,539 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include "nfs41_callback.h" + +#include "nfs41_ops.h" +#include "daemon_debug.h" + +#define CBXLVL 2 /* dprintf level for callback xdr logging */ +#define CBX_ERR(msg) dprintf((CBXLVL), __FUNCTION__ ": failed at " msg "\n") + + +/* common types */ +static bool_t common_stateid(XDR *xdr, stateid4 *stateid) +{ + return xdr_u_int32_t(xdr, &stateid->seqid) + && xdr_opaque(xdr, (char*)stateid->other, 12); +} + +static bool_t common_fh(XDR *xdr, nfs41_fh *fh) +{ + return xdr_u_int32_t(xdr, &fh->len) + && fh->len <= NFS4_FHSIZE + && xdr_opaque(xdr, (char*)fh->fh, fh->len); +} + +static bool_t common_fsid(XDR *xdr, nfs41_fsid *fsid) +{ + return xdr_u_int64_t(xdr, &fsid->major) + && xdr_u_int64_t(xdr, &fsid->minor); +} + +/* OP_CB_LAYOUTRECALL */ +static bool_t op_cb_layoutrecall_file(XDR *xdr, struct cb_recall_file *args) +{ + bool_t result; + + result = common_fh(xdr, &args->fh); + if (!result) { CBX_ERR("layoutrecall_file.fh"); goto out; } + + result = xdr_u_int64_t(xdr, &args->offset); + if (!result) { CBX_ERR("layoutrecall_file.offset"); goto out; } + + result = xdr_u_int64_t(xdr, &args->length); + if (!result) { CBX_ERR("layoutrecall_file.length"); goto out; } + + result = common_stateid(xdr, &args->stateid); + if (!result) { CBX_ERR("layoutrecall_file.stateid"); goto out; } +out: + return result; +} + +static bool_t op_cb_layoutrecall_fsid(XDR *xdr, union cb_recall_file_args *args) +{ + bool_t result; + + result = common_fsid(xdr, &args->fsid); + if (!result) { CBX_ERR("layoutrecall_fsid.fsid"); goto out; } +out: + return result; +} + +static const struct xdr_discrim cb_layoutrecall_discrim[] = { + { PNFS_RETURN_FILE, (xdrproc_t)op_cb_layoutrecall_file }, + { PNFS_RETURN_FSID, (xdrproc_t)op_cb_layoutrecall_fsid }, + { PNFS_RETURN_ALL, (xdrproc_t)xdr_void }, + { 0, NULL_xdrproc_t } +}; + +static bool_t op_cb_layoutrecall_args(XDR *xdr, struct cb_layoutrecall_args *args) +{ + bool_t result; + + result = xdr_enum(xdr, (enum_t*)&args->type); + if (!result) { CBX_ERR("layoutrecall_args.type"); goto out; } + + result = xdr_enum(xdr, (enum_t*)&args->iomode); + if (!result) { CBX_ERR("layoutrecall_args.iomode"); goto out; } + + result = xdr_bool(xdr, &args->changed); + if (!result) { CBX_ERR("layoutrecall_args.changed"); goto out; } + + result = xdr_union(xdr, (enum_t*)&args->recall.type, + (char*)&args->recall.args, cb_layoutrecall_discrim, NULL_xdrproc_t); + if (!result) { CBX_ERR("layoutrecall_args.recall"); goto out; } +out: + return result; +} + +static bool_t op_cb_layoutrecall_res(XDR *xdr, struct cb_layoutrecall_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("layoutrecall_res.status"); goto out; } +out: + return result; +} + + +/* OP_CB_RECALL_SLOT */ +static bool_t op_cb_recall_slot_args(XDR *xdr, struct cb_recall_slot_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("recall_slot.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_recall_slot_res(XDR *xdr, struct cb_recall_slot_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("recall_slot.status"); goto out; } +out: + return result; +} + + +/* OP_CB_SEQUENCE */ +static bool_t op_cb_sequence_ref(XDR *xdr, struct cb_sequence_ref *args) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &args->sequenceid); + if (!result) { CBX_ERR("sequence_ref.sequenceid"); goto out; } + + result = xdr_u_int32_t(xdr, &args->slotid); + if (!result) { CBX_ERR("sequence_ref.slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_sequence_ref_list(XDR *xdr, struct cb_sequence_ref_list *args) +{ + bool_t result; + + result = xdr_opaque(xdr, args->sessionid, NFS4_SESSIONID_SIZE); + if (!result) { CBX_ERR("sequence_ref_list.sessionid"); goto out; } + + result = xdr_array(xdr, (char**)&args->calls, &args->call_count, + 64, sizeof(struct cb_sequence_ref), (xdrproc_t)op_cb_sequence_ref); + if (!result) { CBX_ERR("sequence_ref_list.calls"); goto out; } +out: + return result; +} + +static bool_t op_cb_sequence_args(XDR *xdr, struct cb_sequence_args *args) +{ + bool_t result; + + dprintf(1, "decoding sequence args\n"); + result = xdr_opaque(xdr, args->sessionid, NFS4_SESSIONID_SIZE); + if (!result) { CBX_ERR("sequence_args.sessionid"); goto out; } + + result = xdr_u_int32_t(xdr, &args->sequenceid); + if (!result) { CBX_ERR("sequence_args.sequenceid"); goto out; } + + result = xdr_u_int32_t(xdr, &args->slotid); + if (!result) { CBX_ERR("sequence_args.slotid"); goto out; } + + result = xdr_u_int32_t(xdr, &args->highest_slotid); + if (!result) { CBX_ERR("sequence_args.highest_slotid"); goto out; } + + result = xdr_bool(xdr, &args->cachethis); + if (!result) { CBX_ERR("sequence_args.cachethis"); goto out; } + + result = xdr_array(xdr, (char**)&args->ref_lists, + &args->ref_list_count, 64, sizeof(struct cb_sequence_ref_list), + (xdrproc_t)op_cb_sequence_ref_list); + if (!result) { CBX_ERR("sequence_args.ref_lists"); goto out; } +out: + return result; +} + +static bool_t op_cb_sequence_res_ok(XDR *xdr, struct cb_sequence_res_ok *res) +{ + bool_t result; + + result = xdr_opaque(xdr, res->sessionid, NFS4_SESSIONID_SIZE); + if (!result) { CBX_ERR("sequence_res.sessionid"); goto out; } + + result = xdr_u_int32_t(xdr, &res->sequenceid); + if (!result) { CBX_ERR("sequence_res.sequenceid"); goto out; } + + result = xdr_u_int32_t(xdr, &res->slotid); + if (!result) { CBX_ERR("sequence_res.slotid"); goto out; } + + result = xdr_u_int32_t(xdr, &res->highest_slotid); + if (!result) { CBX_ERR("sequence_res.highest_slotid"); goto out; } + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("sequence_res.target_highest_slotid"); goto out; } +out: + return result; +} + +static const struct xdr_discrim cb_sequence_res_discrim[] = { + { NFS4_OK, (xdrproc_t)op_cb_sequence_res_ok }, + { 0, NULL_xdrproc_t } +}; + +static bool_t op_cb_sequence_res(XDR *xdr, struct cb_sequence_res *res) +{ + bool_t result; + + result = xdr_union(xdr, &res->status, (char*)&res->ok, + cb_sequence_res_discrim, (xdrproc_t)xdr_void); + if (!result) { CBX_ERR("seq:argop.args"); goto out; } +out: + return result; +} + +/* OP_CB_GETATTR */ +static bool_t op_cb_getattr_args(XDR *xdr, struct cb_getattr_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("getattr.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_getattr_res(XDR *xdr, struct cb_getattr_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("getattr.status"); goto out; } +out: + return result; +} + +/* OP_CB_RECALL */ +static bool_t op_cb_recall_args(XDR *xdr, struct cb_recall_args *args) +{ + bool_t result; + + dprintf(1, "decoding recall args\n"); + result = common_stateid(xdr, &args->stateid); + if (!result) { CBX_ERR("recall.stateid"); goto out; } + + result = xdr_bool(xdr, &args->truncate); + if (!result) { CBX_ERR("recall.truncate"); goto out; } + + result = common_fh(xdr, &args->fh); + if (!result) { CBX_ERR("recall.fh"); goto out; } +out: + return result; +} + +static bool_t op_cb_recall_res(XDR *xdr, struct cb_recall_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("recall.status"); goto out; } +out: + return result; +} + +/* OP_CB_NOTIFY */ +static bool_t op_cb_notify_args(XDR *xdr, struct cb_notify_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("notify.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_notify_res(XDR *xdr, struct cb_notify_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("notify.status"); goto out; } +out: + return result; +} + +/* OP_CB_PUSH_DELEG */ +static bool_t op_cb_push_deleg_args(XDR *xdr, struct cb_push_deleg_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("push_deleg.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_push_deleg_res(XDR *xdr, struct cb_push_deleg_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("push_deleg.status"); goto out; } +out: + return result; +} + +/* OP_CB_RECALL_ANY */ +static bool_t op_cb_recall_any_args(XDR *xdr, struct cb_recall_any_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("recall_any.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_recall_any_res(XDR *xdr, struct cb_recall_any_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("recall_any.status"); goto out; } +out: + return result; +} + +/* OP_CB_RECALLABLE_OBJ_AVAIL */ +static bool_t op_cb_recallable_obj_avail_args(XDR *xdr, struct cb_recallable_obj_avail_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("recallable_obj_avail.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_recallable_obj_avail_res(XDR *xdr, struct cb_recallable_obj_avail_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("recallable_obj_avail.status"); goto out; } +out: + return result; +} + +/* OP_CB_WANTS_CANCELLED */ +static bool_t op_cb_wants_cancelled_args(XDR *xdr, struct cb_wants_cancelled_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("wants_cancelled.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_wants_cancelled_res(XDR *xdr, struct cb_wants_cancelled_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("wants_cancelled.status"); goto out; } +out: + return result; +} + +/* OP_CB_NOTIFY_LOCK */ +static bool_t op_cb_notify_lock_args(XDR *xdr, struct cb_notify_lock_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("notify_lock.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_notify_lock_res(XDR *xdr, struct cb_notify_lock_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("notify_lock.status"); goto out; } +out: + return result; +} + +/* OP_CB_NOTIFY_DEVICEID */ +static bool_t op_cb_notify_deviceid_args(XDR *xdr, struct cb_notify_deviceid_args *res) +{ + bool_t result; + + result = xdr_u_int32_t(xdr, &res->target_highest_slotid); + if (!result) { CBX_ERR("notify_deviceid.target_highest_slotid"); goto out; } +out: + return result; +} + +static bool_t op_cb_notify_deviceid_res(XDR *xdr, struct cb_notify_deviceid_res *res) +{ + bool_t result; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("notify_deviceid.status"); goto out; } +out: + return result; +} + +/* CB_COMPOUND */ +static bool_t cb_compound_tag(XDR *xdr, struct cb_compound_tag *args) +{ + return xdr_u_int32_t(xdr, &args->len) + && args->len <= CB_COMPOUND_MAX_TAG + && xdr_opaque(xdr, args->str, args->len); +} + +static const struct xdr_discrim cb_argop_discrim[] = { + { OP_CB_LAYOUTRECALL, (xdrproc_t)op_cb_layoutrecall_args }, + { OP_CB_RECALL_SLOT, (xdrproc_t)op_cb_recall_slot_args }, + { OP_CB_SEQUENCE, (xdrproc_t)op_cb_sequence_args }, + { OP_CB_GETATTR, (xdrproc_t)op_cb_getattr_args }, + { OP_CB_RECALL, (xdrproc_t)op_cb_recall_args }, + { OP_CB_NOTIFY, (xdrproc_t)op_cb_notify_args }, + { OP_CB_PUSH_DELEG, (xdrproc_t)op_cb_push_deleg_args }, + { OP_CB_RECALL_ANY, (xdrproc_t)op_cb_recall_any_args }, + { OP_CB_RECALLABLE_OBJ_AVAIL, (xdrproc_t)op_cb_recallable_obj_avail_args }, + { OP_CB_WANTS_CANCELLED, (xdrproc_t)op_cb_wants_cancelled_args }, + { OP_CB_NOTIFY_LOCK, (xdrproc_t)op_cb_notify_lock_args }, + { OP_CB_NOTIFY_DEVICEID, (xdrproc_t)op_cb_notify_deviceid_args }, + { OP_CB_ILLEGAL, NULL_xdrproc_t }, +}; + +static bool_t cb_compound_argop(XDR *xdr, struct cb_argop *args) +{ + bool_t result; + + result = xdr_union(xdr, &args->opnum, (char*)&args->args, + cb_argop_discrim, NULL_xdrproc_t); + if (!result) { CBX_ERR("cmb:argop.args"); goto out; } +out: + return result; +} + +bool_t proc_cb_compound_args(XDR *xdr, struct cb_compound_args *args) +{ + bool_t result; + + result = cb_compound_tag(xdr, &args->tag); + if (!result) { CBX_ERR("compound.tag"); goto out; } + + result = xdr_u_int32_t(xdr, &args->minorversion); + if (!result) { CBX_ERR("compound.minorversion"); goto out; } + + /* "superfluous in NFSv4.1 and MUST be ignored by the client" */ + result = xdr_u_int32_t(xdr, &args->callback_ident); + if (!result) { CBX_ERR("compound.callback_ident"); goto out; } + + result = xdr_array(xdr, (char**)&args->argarray, + &args->argarray_count, CB_COMPOUND_MAX_OPERATIONS, + sizeof(struct cb_argop), (xdrproc_t)cb_compound_argop); + if (!result) { CBX_ERR("compound.argarray"); goto out; } +out: + return result; +} + +static const struct xdr_discrim cb_resop_discrim[] = { + { OP_CB_LAYOUTRECALL, (xdrproc_t)op_cb_layoutrecall_res }, + { OP_CB_RECALL_SLOT, (xdrproc_t)op_cb_recall_slot_res }, + { OP_CB_SEQUENCE, (xdrproc_t)op_cb_sequence_res }, + { OP_CB_GETATTR, (xdrproc_t)op_cb_getattr_res }, + { OP_CB_RECALL, (xdrproc_t)op_cb_recall_res }, + { OP_CB_NOTIFY, (xdrproc_t)op_cb_notify_res }, + { OP_CB_PUSH_DELEG, (xdrproc_t)op_cb_push_deleg_res }, + { OP_CB_RECALL_ANY, (xdrproc_t)op_cb_recall_any_res }, + { OP_CB_RECALLABLE_OBJ_AVAIL, (xdrproc_t)op_cb_recallable_obj_avail_res }, + { OP_CB_WANTS_CANCELLED, (xdrproc_t)op_cb_wants_cancelled_res }, + { OP_CB_NOTIFY_LOCK, (xdrproc_t)op_cb_notify_lock_res }, + { OP_CB_NOTIFY_DEVICEID, (xdrproc_t)op_cb_notify_deviceid_res }, + { OP_CB_ILLEGAL, NULL_xdrproc_t }, +}; + +static bool_t cb_compound_resop(XDR *xdr, struct cb_resop *res) +{ + bool_t result; + + result = xdr_union(xdr, &res->opnum, (char*)&res->res, + cb_resop_discrim, NULL_xdrproc_t); + if (!result) { CBX_ERR("resop.res"); goto out; } +out: + return result; +} + +bool_t proc_cb_compound_res(XDR *xdr, struct cb_compound_res *res) +{ + bool_t result; + + if (res == NULL) + return TRUE; + + result = xdr_enum(xdr, &res->status); + if (!result) { CBX_ERR("compound_res.status"); goto out; } + + result = cb_compound_tag(xdr, &res->tag); + if (!result) { CBX_ERR("compound_res.tag"); goto out; } + + result = xdr_array(xdr, (char**)&res->resarray, + &res->resarray_count, CB_COMPOUND_MAX_OPERATIONS, + sizeof(struct cb_resop), (xdrproc_t)cb_compound_resop); + if (!result) { CBX_ERR("compound_res.resarray"); goto out; } +out: + free(res->resarray); + free(res); + + return result; +} diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c new file mode 100644 index 0000000..aa28004 --- /dev/null +++ b/daemon/daemon_debug.c @@ -0,0 +1,440 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "daemon_debug.h" +#include "from_kernel.h" +#include "nfs41_driver.h" +#include "nfs41_ops.h" + + +static int g_debug_level = DEFAULT_DEBUG_LEVEL; + +void set_debug_level(int level) { g_debug_level = level; } + +void dprintf(int level, LPCSTR format, ...) +{ + if (level <= g_debug_level) { + va_list args; + va_start(args, format); + printf("%04x: ", GetCurrentThreadId()); + vprintf(format, args); + va_end(args); + } +} + +void eprintf(LPCSTR format, ...) +{ + va_list args; + va_start(args, format); + fprintf(stderr, "%04x: ", GetCurrentThreadId()); + vfprintf(stderr, format, args); + va_end(args); +} + +void print_hexbuf(int level, unsigned char *title, unsigned char *buf, int len) +{ + int j, k; + if (level > g_debug_level) return; + printf("%s", title); + for(j = 0, k = 0; j < len; j++, k++) { + printf("%02x '%c' ", buf[j], isascii(buf[j])? buf[j]:' '); + if (((k+1) % 10 == 0 && k > 0)) { + printf("\n"); + } + } + printf("\n"); +} + +void print_create_attributes(int level, DWORD create_opts) { + if (level > g_debug_level) return; + printf("create attributes: "); + if (create_opts & FILE_DIRECTORY_FILE) + printf("DIRECTORY_FILE "); + if (create_opts & FILE_NON_DIRECTORY_FILE) + printf("NON_DIRECTORY_FILE "); + if (create_opts & FILE_WRITE_THROUGH) + printf("WRITE_THROUGH "); + if (create_opts & FILE_SEQUENTIAL_ONLY) + printf("SEQUENTIAL_ONLY "); + if (create_opts & FILE_RANDOM_ACCESS) + printf("RANDOM_ACCESS "); + if (create_opts & FILE_NO_INTERMEDIATE_BUFFERING) + printf("NO_INTERMEDIATE_BUFFERING "); + if (create_opts & FILE_SYNCHRONOUS_IO_ALERT) + printf("SYNCHRONOUS_IO_ALERT "); + if (create_opts & FILE_SYNCHRONOUS_IO_NONALERT) + printf("SYNCHRONOUS_IO_NONALERT "); + if (create_opts & FILE_CREATE_TREE_CONNECTION) + printf("CREATE_TREE_CONNECTION "); + if (create_opts & FILE_COMPLETE_IF_OPLOCKED) + printf("COMPLETE_IF_OPLOCKED "); + if (create_opts & FILE_NO_EA_KNOWLEDGE) + printf("NO_EA_KNOWLEDGE "); + if (create_opts & FILE_OPEN_REPARSE_POINT) + printf("OPEN_REPARSE_POINT "); + if (create_opts & FILE_DELETE_ON_CLOSE) + printf("DELETE_ON_CLOSE "); + if (create_opts & FILE_OPEN_BY_FILE_ID) + printf("OPEN_BY_FILE_ID "); + if (create_opts & FILE_OPEN_FOR_BACKUP_INTENT) + printf("OPEN_FOR_BACKUP_INTENT "); + if (create_opts & FILE_RESERVE_OPFILTER) + printf("RESERVE_OPFILTER"); + printf("\n"); +} + +void print_disposition(int level, DWORD disposition) { + if (level > g_debug_level) return; + printf("userland disposition = "); + if (disposition == FILE_SUPERSEDE) + printf("FILE_SUPERSEDE\n"); + else if (disposition == FILE_CREATE) + printf("FILE_CREATE\n"); + else if (disposition == FILE_OPEN) + printf("FILE_OPEN\n"); + else if (disposition == FILE_OPEN_IF) + printf("FILE_OPEN_IF\n"); + else if (disposition == FILE_OVERWRITE) + printf("FILE_OVERWRITE\n"); + else if (disposition == FILE_OVERWRITE_IF) + printf("FILE_OVERWRITE_IF\n"); +} + +void print_access_mask(int level, DWORD access_mask) { + if (level > g_debug_level) return; + printf("access mask: "); + if (access_mask & FILE_READ_DATA) + printf("READ "); + if (access_mask & STANDARD_RIGHTS_READ) + printf("READ_ACL "); + if (access_mask & FILE_READ_ATTRIBUTES) + printf("READ_ATTR "); + if (access_mask & FILE_READ_EA) + printf("READ_EA "); + if (access_mask & FILE_WRITE_DATA) + printf("WRITE "); + if (access_mask & STANDARD_RIGHTS_WRITE) + printf("WRITE_ACL "); + if (access_mask & FILE_WRITE_ATTRIBUTES) + printf("WRITE_ATTR "); + if (access_mask & FILE_WRITE_EA) + printf("WRITE_EA "); + if (access_mask & FILE_APPEND_DATA) + printf("APPEND "); + if (access_mask & FILE_EXECUTE) + printf("EXECUTE "); + if (access_mask & FILE_LIST_DIRECTORY) + printf("LIST "); + if (access_mask & FILE_TRAVERSE) + printf("TRAVERSE "); + if (access_mask & SYNCHRONIZE) + printf("SYNC "); + if (access_mask & FILE_DELETE_CHILD) + printf("DELETE_CHILD"); + printf("\n"); +} + +void print_share_mode(int level, DWORD mode) +{ + if (level > g_debug_level) return; + printf("share mode: "); + if (mode & FILE_SHARE_READ) + printf("READ "); + if (mode & FILE_SHARE_WRITE) + printf("WRITE "); + if (mode & FILE_SHARE_DELETE) + printf("DELETE"); + printf("\n"); +} + +void print_file_id_both_dir_info(int level, FILE_ID_BOTH_DIR_INFO *pboth_dir_info) +{ + if (level > g_debug_level) return; + printf("FILE_ID_BOTH_DIR_INFO %p %d\n", pboth_dir_info, sizeof(unsigned char *)); + printf("\tNextEntryOffset=%ld %d %d\n", pboth_dir_info->NextEntryOffset, sizeof(pboth_dir_info->NextEntryOffset), sizeof(DWORD)); + printf("\tFileIndex=%ld %d\n", pboth_dir_info->FileIndex, sizeof(pboth_dir_info->FileIndex)); + printf("\tCreationTime=0x%x %d\n", pboth_dir_info->CreationTime.QuadPart, sizeof(pboth_dir_info->CreationTime)); + printf("\tLastAccessTime=0x%x %d\n", pboth_dir_info->LastAccessTime.QuadPart, sizeof(pboth_dir_info->LastAccessTime)); + printf("\tLastWriteTime=0x%x %d\n", pboth_dir_info->LastWriteTime.QuadPart, sizeof(pboth_dir_info->LastWriteTime)); + printf("\tChangeTime=0x%x %d\n", pboth_dir_info->ChangeTime.QuadPart, sizeof(pboth_dir_info->ChangeTime)); + printf("\tEndOfFile=0x%x %d\n", pboth_dir_info->EndOfFile.QuadPart, sizeof(pboth_dir_info->EndOfFile)); + printf("\tAllocationSize=0x%x %d\n", pboth_dir_info->AllocationSize.QuadPart, sizeof(pboth_dir_info->AllocationSize)); + printf("\tFileAttributes=%ld %d\n", pboth_dir_info->FileAttributes, sizeof(pboth_dir_info->FileAttributes)); + printf("\tFileNameLength=%ld %d\n", pboth_dir_info->FileNameLength, sizeof(pboth_dir_info->FileNameLength)); + printf("\tEaSize=%ld %d\n", pboth_dir_info->EaSize, sizeof(pboth_dir_info->EaSize)); + printf("\tShortNameLength=%d %d\n", pboth_dir_info->ShortNameLength, sizeof(pboth_dir_info->ShortNameLength)); + printf("\tShortName='%S' %d\n", pboth_dir_info->ShortName, sizeof(pboth_dir_info->ShortName)); + printf("\tFileId=0x%x %d\n", pboth_dir_info->FileId.QuadPart, sizeof(pboth_dir_info->FileId)); + printf("\tFileName='%S' %p\n", pboth_dir_info->FileName, pboth_dir_info->FileName); +} + +void print_opcode(int level, DWORD opcode) +{ + dprintf(level, (LPCSTR)opcode2string(opcode)); +} + +const char* opcode2string(DWORD opcode) +{ + switch(opcode) { + case NFS41_SHUTDOWN: return "NFS41_SHUTDOWN"; + case NFS41_MOUNT: return "NFS41_MOUNT"; + case NFS41_UNMOUNT: return "NFS41_UNMOUNT"; + case NFS41_OPEN: return "NFS41_OPEN"; + case NFS41_CLOSE: return "NFS41_CLOSE"; + case NFS41_READ: return "NFS41_READ"; + case NFS41_WRITE: return "NFS41_WRITE"; + case NFS41_LOCK: return "NFS41_LOCK"; + case NFS41_UNLOCK: return "NFS41_UNLOCK"; + case NFS41_DIR_QUERY: return "NFS41_DIR_QUERY"; + case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY"; + case NFS41_FILE_SET: return "NFS41_FILE_SET"; + case NFS41_EA_SET: return "NFS41_EA_SET"; + case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY"; + default: return "UNKNOWN"; + } +} + +const char* nfs_opnum_to_string(int opnum) +{ + switch (opnum) + { + case OP_ACCESS: return "ACCESS"; + case OP_CLOSE: return "CLOSE"; + case OP_COMMIT: return "COMMIT"; + case OP_CREATE: return "CREATE"; + case OP_DELEGPURGE: return "DELEGPURGE"; + case OP_DELEGRETURN: return "DELEGRETURN"; + case OP_GETATTR: return "GETATTR"; + case OP_GETFH: return "GETFH"; + case OP_LINK: return "LINK"; + case OP_LOCK: return "LOCK"; + case OP_LOCKT: return "LOCKT"; + case OP_LOCKU: return "LOCKU"; + case OP_LOOKUP: return "LOOKUP"; + case OP_LOOKUPP: return "LOOKUPP"; + case OP_NVERIFY: return "NVERIFY"; + case OP_OPEN: return "OPEN"; + case OP_OPENATTR: return "OPENATTR"; + case OP_OPEN_CONFIRM: return "OPEN_CONFIRM"; + case OP_OPEN_DOWNGRADE: return "OPEN_DOWNGRADE"; + case OP_PUTFH: return "PUTFH"; + case OP_PUTPUBFH: return "PUTPUBFH"; + case OP_PUTROOTFH: return "PUTROOTFH"; + case OP_READ: return "READ"; + case OP_READDIR: return "READDIR"; + case OP_READLINK: return "READLINK"; + case OP_REMOVE: return "REMOVE"; + case OP_RENAME: return "RENAME"; + case OP_RENEW: return "RENEW"; + case OP_RESTOREFH: return "RESTOREFH"; + case OP_SAVEFH: return "SAVEFH"; + case OP_SECINFO: return "SECINFO"; + case OP_SETATTR: return "SETATTR"; + case OP_SETCLIENTID: return "SETCLIENTID"; + case OP_SETCLIENTID_CONFIRM: return "SETCLIENTID_CONFIRM"; + case OP_VERIFY: return "VERIFY"; + case OP_WRITE: return "WRITE"; + case OP_RELEASE_LOCKOWNER: return "RELEASE_LOCKOWNER"; + case OP_BACKCHANNEL_CTL: return "BACKCHANNEL_CTL"; + case OP_BIND_CONN_TO_SESSION: return "BIND_CONN_TO_SESSION"; + case OP_EXCHANGE_ID: return "EXCHANGE_ID"; + case OP_CREATE_SESSION: return "CREATE_SESSION"; + case OP_DESTROY_SESSION: return "DESTROY_SESSION"; + case OP_FREE_STATEID: return "FREE_STATEID"; + case OP_GET_DIR_DELEGATION: return "GET_DIR_DELEGATION"; + case OP_GETDEVICEINFO: return "GETDEVICEINFO"; + case OP_GETDEVICELIST: return "GETDEVICELIST"; + case OP_LAYOUTCOMMIT: return "LAYOUTCOMMIT"; + case OP_LAYOUTGET: return "LAYOUTGET"; + case OP_LAYOUTRETURN: return "LAYOUTRETURN"; + case OP_SECINFO_NO_NAME: return "SECINFO_NO_NAME"; + case OP_SEQUENCE: return "SEQUENCE"; + case OP_SET_SSV: return "SET_SSV"; + case OP_TEST_STATEID: return "TEST_STATEID"; + case OP_WANT_DELEGATION: return "WANT_DELEGATION"; + case OP_DESTROY_CLIENTID: return "DESTROY_CLIENTID"; + case OP_RECLAIM_COMPLETE: return "RECLAIM_COMPLETE"; + case OP_ILLEGAL: return "ILLEGAL"; + default: return "invalid nfs opnum"; + } +} + +const char* nfs_error_string(int status) +{ + switch (status) + { + case NFS4_OK: return "NFS4_OK"; + case NFS4ERR_PERM: return "NFS4ERR_PERM"; + case NFS4ERR_NOENT: return "NFS4ERR_NOENT"; + case NFS4ERR_IO: return "NFS4ERR_IO"; + case NFS4ERR_NXIO: return "NFS4ERR_NXIO"; + case NFS4ERR_ACCESS: return "NFS4ERR_ACCESS"; + case NFS4ERR_EXIST: return "NFS4ERR_EXIST"; + case NFS4ERR_XDEV: return "NFS4ERR_XDEV"; + case NFS4ERR_NOTDIR: return "NFS4ERR_NOTDIR"; + case NFS4ERR_ISDIR: return "NFS4ERR_ISDIR"; + case NFS4ERR_INVAL: return "NFS4ERR_INVAL"; + case NFS4ERR_FBIG: return "NFS4ERR_FBIG"; + case NFS4ERR_NOSPC: return "NFS4ERR_NOSPC"; + case NFS4ERR_ROFS: return "NFS4ERR_ROFS"; + case NFS4ERR_MLINK: return "NFS4ERR_MLINK"; + case NFS4ERR_NAMETOOLONG: return "NFS4ERR_NAMETOOLONG"; + case NFS4ERR_NOTEMPTY: return "NFS4ERR_NOTEMPTY"; + case NFS4ERR_DQUOT: return "NFS4ERR_DQUOT"; + case NFS4ERR_STALE: return "NFS4ERR_STALE"; + case NFS4ERR_BADHANDLE: return "NFS4ERR_BADHANDLE"; + case NFS4ERR_BAD_COOKIE: return "NFS4ERR_BAD_COOKIE"; + case NFS4ERR_NOTSUPP: return "NFS4ERR_NOTSUPP"; + case NFS4ERR_TOOSMALL: return "NFS4ERR_TOOSMALL"; + case NFS4ERR_SERVERFAULT: return "NFS4ERR_SERVERFAULT"; + case NFS4ERR_BADTYPE: return "NFS4ERR_BADTYPE"; + case NFS4ERR_DELAY: return "NFS4ERR_DELAY"; + case NFS4ERR_SAME: return "NFS4ERR_SAME"; + case NFS4ERR_DENIED: return "NFS4ERR_DENIED"; + case NFS4ERR_EXPIRED: return "NFS4ERR_EXPIRED"; + case NFS4ERR_LOCKED: return "NFS4ERR_LOCKED"; + case NFS4ERR_GRACE: return "NFS4ERR_GRACE"; + case NFS4ERR_FHEXPIRED: return "NFS4ERR_FHEXPIRED"; + case NFS4ERR_SHARE_DENIED: return "NFS4ERR_SHARE_DENIED"; + case NFS4ERR_WRONGSEC: return "NFS4ERR_WRONGSEC"; + case NFS4ERR_CLID_INUSE: return "NFS4ERR_CLID_INUSE"; + case NFS4ERR_RESOURCE: return "NFS4ERR_RESOURCE"; + case NFS4ERR_MOVED: return "NFS4ERR_MOVED"; + case NFS4ERR_NOFILEHANDLE: return "NFS4ERR_NOFILEHANDLE"; + case NFS4ERR_MINOR_VERS_MISMATCH: return "NFS4ERR_MINOR_VERS_MISMATCH"; + case NFS4ERR_STALE_CLIENTID: return "NFS4ERR_STALE_CLIENTID"; + case NFS4ERR_STALE_STATEID: return "NFS4ERR_STALE_STATEID"; + case NFS4ERR_OLD_STATEID: return "NFS4ERR_OLD_STATEID"; + case NFS4ERR_BAD_STATEID: return "NFS4ERR_BAD_STATEID"; + case NFS4ERR_BAD_SEQID: return "NFS4ERR_BAD_SEQID"; + case NFS4ERR_NOT_SAME: return "NFS4ERR_NOT_SAME"; + case NFS4ERR_LOCK_RANGE: return "NFS4ERR_LOCK_RANGE"; + case NFS4ERR_SYMLINK: return "NFS4ERR_SYMLINK"; + case NFS4ERR_RESTOREFH: return "NFS4ERR_RESTOREFH"; + case NFS4ERR_LEASE_MOVED: return "NFS4ERR_LEASE_MOVED"; + case NFS4ERR_ATTRNOTSUPP: return "NFS4ERR_ATTRNOTSUPP"; + case NFS4ERR_NO_GRACE: return "NFS4ERR_NO_GRACE"; + case NFS4ERR_RECLAIM_BAD: return "NFS4ERR_RECLAIM_BAD"; + case NFS4ERR_RECLAIM_CONFLICT: return "NFS4ERR_RECLAIM_CONFLICT"; + case NFS4ERR_BADXDR: return "NFS4ERR_BADXDR"; + case NFS4ERR_LOCKS_HELD: return "NFS4ERR_LOCKS_HELD"; + case NFS4ERR_OPENMODE: return "NFS4ERR_OPENMODE"; + case NFS4ERR_BADOWNER: return "NFS4ERR_BADOWNER"; + case NFS4ERR_BADCHAR: return "NFS4ERR_BADCHAR"; + case NFS4ERR_BADNAME: return "NFS4ERR_BADNAME"; + case NFS4ERR_BAD_RANGE: return "NFS4ERR_BAD_RANGE"; + case NFS4ERR_LOCK_NOTSUPP: return "NFS4ERR_LOCK_NOTSUPP"; + case NFS4ERR_OP_ILLEGAL: return "NFS4ERR_OP_ILLEGAL"; + case NFS4ERR_DEADLOCK: return "NFS4ERR_DEADLOCK"; + case NFS4ERR_FILE_OPEN: return "NFS4ERR_FILE_OPEN"; + case NFS4ERR_ADMIN_REVOKED: return "NFS4ERR_ADMIN_REVOKED"; + case NFS4ERR_CB_PATH_DOWN: return "NFS4ERR_CB_PATH_DOWN"; + case NFS4ERR_BADIOMODE: return "NFS4ERR_BADIOMODE"; + case NFS4ERR_BADLAYOUT: return "NFS4ERR_BADLAYOUT"; + case NFS4ERR_BAD_SESSION_DIGEST: return "NFS4ERR_BAD_SESSION_DIGEST"; + case NFS4ERR_BADSESSION: return "NFS4ERR_BADSESSION"; + case NFS4ERR_BADSLOT: return "NFS4ERR_BADSLOT"; + case NFS4ERR_COMPLETE_ALREADY: return "NFS4ERR_COMPLETE_ALREADY"; + case NFS4ERR_CONN_NOT_BOUND_TO_SESSION: return "NFS4ERR_CONN_NOT_BOUND_TO_SESSION"; + case NFS4ERR_DELEG_ALREADY_WANTED: return "NFS4ERR_DELEG_ALREADY_WANTED"; + case NFS4ERR_BACK_CHAN_BUSY: return "NFS4ERR_BACK_CHAN_BUSY"; + case NFS4ERR_LAYOUTTRYLATER: return "NFS4ERR_LAYOUTTRYLATER"; + case NFS4ERR_LAYOUTUNAVAILABLE: return "NFS4ERR_LAYOUTUNAVAILABLE"; + case NFS4ERR_NOMATCHING_LAYOUT: return "NFS4ERR_NOMATCHING_LAYOUT"; + case NFS4ERR_RECALLCONFLICT: return "NFS4ERR_RECALLCONFLICT"; + case NFS4ERR_UNKNOWN_LAYOUTTYPE: return "NFS4ERR_UNKNOWN_LAYOUTTYPE"; + case NFS4ERR_SEQ_MISORDERED: return "NFS4ERR_SEQ_MISORDERED"; + case NFS4ERR_SEQUENCE_POS: return "NFS4ERR_SEQUENCE_POS"; + case NFS4ERR_REQ_TOO_BIG: return "NFS4ERR_REQ_TOO_BIG"; + case NFS4ERR_REP_TOO_BIG: return "NFS4ERR_REP_TOO_BIG"; + case NFS4ERR_REP_TOO_BIG_TO_CACHE: return "NFS4ERR_REP_TOO_BIG_TO_CACHE"; + case NFS4ERR_RETRY_UNCACHED_REP: return "NFS4ERR_RETRY_UNCACHED_REP"; + case NFS4ERR_UNSAFE_COMPOUND: return "NFS4ERR_UNSAFE_COMPOUND"; + case NFS4ERR_TOO_MANY_OPS: return "NFS4ERR_TOO_MANY_OPS"; + case NFS4ERR_OP_NOT_IN_SESSION: return "NFS4ERR_OP_NOT_IN_SESSION"; + case NFS4ERR_HASH_ALG_UNSUPP: return "NFS4ERR_HASH_ALG_UNSUPP"; + case NFS4ERR_CLIENTID_BUSY: return "NFS4ERR_CLIENTID_BUSY"; + case NFS4ERR_PNFS_IO_HOLE: return "NFS4ERR_PNFS_IO_HOLE"; + case NFS4ERR_SEQ_FALSE_RETRY: return "NFS4ERR_SEQ_FALSE_RETRY"; + case NFS4ERR_BAD_HIGH_SLOT: return "NFS4ERR_BAD_HIGH_SLOT"; + case NFS4ERR_DEADSESSION: return "NFS4ERR_DEADSESSION"; + case NFS4ERR_ENCR_ALG_UNSUPP: return "NFS4ERR_ENCR_ALG_UNSUPP"; + case NFS4ERR_PNFS_NO_LAYOUT: return "NFS4ERR_PNFS_NO_LAYOUT"; + case NFS4ERR_NOT_ONLY_OP: return "NFS4ERR_NOT_ONLY_OP"; + case NFS4ERR_WRONG_CRED: return "NFS4ERR_WRONG_CRED"; + case NFS4ERR_WRONG_TYPE: return "NFS4ERR_WRONG_TYPE"; + case NFS4ERR_DIRDELEG_UNAVAIL: return "NFS4ERR_DIRDELEG_UNAVAIL"; + case NFS4ERR_REJECT_DELEG: return "NFS4ERR_REJECT_DELEG"; + case NFS4ERR_RETURNCONFLICT: return "NFS4ERR_RETURNCONFLICT"; + case NFS4ERR_DELEG_REVOKED: return "NFS4ERR_DELEG_REVOKED"; + default: return "invalid nfs error code"; + } +} + +void print_condwait_status(int level, int status) +{ + if (level > g_debug_level) return; + switch(status) { + case WAIT_ABANDONED: printf("WAIT_ABANDONED\n"); break; + case WAIT_OBJECT_0: printf("WAIT_OBJECT_0\n"); break; + case WAIT_TIMEOUT: printf("WAIT_TIMEOUT\n"); break; + case WAIT_FAILED: printf("WAIT_FAILED %d\n", GetLastError()); + default: printf("unknown status =%d\n", status); + } +} + +void print_sr_status_flags(int level, int flags) +{ + if (level > g_debug_level) return; + printf("%04x: sr_status_flags: ", GetCurrentThreadId()); + if (flags & SEQ4_STATUS_CB_PATH_DOWN) + printf("SEQ4_STATUS_CB_PATH_DOWN "); + if (flags & SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING) + printf("SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING "); + if (flags & SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED) + printf("SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED "); + if (flags & SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED) + printf("SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED "); + if (flags & SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED) + printf("SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED "); + if (flags & SEQ4_STATUS_ADMIN_STATE_REVOKED) + printf("SEQ4_STATUS_ADMIN_STATE_REVOKED "); + if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) + printf("SEQ4_STATUS_RECALLABLE_STATE_REVOKED "); + if (flags & SEQ4_STATUS_LEASE_MOVED) + printf("SEQ4_STATUS_LEASE_MOVED "); + if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) + printf("SEQ4_STATUS_RESTART_RECLAIM_NEEDED "); + if (flags & SEQ4_STATUS_CB_PATH_DOWN_SESSION) + printf("SEQ4_STATUS_CB_PATH_DOWN_SESSION "); + if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT) + printf("SEQ4_STATUS_BACKCHANNEL_FAULT "); + if (flags & SEQ4_STATUS_DEVID_CHANGED) + printf("SEQ4_STATUS_DEVID_CHANGED "); + if (flags & SEQ4_STATUS_DEVID_DELETED) + printf("SEQ4_STATUS_DEVID_DELETED "); + printf("\n"); +} diff --git a/daemon/daemon_debug.h b/daemon/daemon_debug.h new file mode 100644 index 0000000..4b875b1 --- /dev/null +++ b/daemon/daemon_debug.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef _DAEMON_DEBUG_ +#define _DAEMON_DEBUG_ + +#ifdef _DEBUG +/* use visual studio's debug heap */ +# define _CRTDBG_MAP_ALLOC +# include +# include +#else +# include +#endif + +#define DEFAULT_DEBUG_LEVEL 1 + + +/* daemon_debug.h */ +void set_debug_level(int level); +void dprintf(int level, LPCSTR format, ...); +void eprintf(LPCSTR format, ...); + +void print_hexbuf(int level, unsigned char *title, unsigned char *buf, int len); +void print_create_attributes(int level, DWORD create_opts); +void print_disposition(int level, DWORD disposition); +void print_access_mask(int level, DWORD access_mask); +void print_share_mode(int level, DWORD mode); +void print_file_id_both_dir_info(int level, FILE_ID_BOTH_DIR_INFO *p); +void print_opcode(int level, DWORD opcode); +const char* opcode2string(DWORD opcode); +const char* nfs_opnum_to_string(int opnum); +const char* nfs_error_string(int status); +void print_condwait_status(int level, int status); +void print_sr_status_flags(int level, int flags); + + +/* pnfs_debug.c */ +enum pnfs_status; +enum pnfs_layout_type; +enum pnfs_iomode; +struct __pnfs_file_layout; +struct __pnfs_file_device; + +const char* pnfs_error_string(enum pnfs_status status); +const char* pnfs_layout_type_string(enum pnfs_layout_type type); +const char* pnfs_iomode_string(enum pnfs_iomode iomode); + +void dprint_deviceid(int level, const char *title, const unsigned char *deviceid); +void dprint_layout(int level, const struct __pnfs_file_layout *layout); +void dprint_device(int level, const struct __pnfs_file_device *device); + +#endif diff --git a/daemon/from_kernel.h b/daemon/from_kernel.h new file mode 100644 index 0000000..9658dd4 --- /dev/null +++ b/daemon/from_kernel.h @@ -0,0 +1,195 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef _NFS41_DAEMON_ +#define _NFS41_DAEMON_ + +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_COPY_STRUCTURED_STORAGE 0x00000041 +#define FILE_STRUCTURED_STORAGE 0x00000441 + +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, // 2 + FileBothDirectoryInformation, // 3 + FileBasicInformation, // 4 + FileStandardInformation, // 5 + FileInternalInformation, // 6 + FileEaInformation, // 7 + FileAccessInformation, // 8 + FileNameInformation, // 9 + FileRenameInformation, // 10 + FileLinkInformation, // 11 + FileNamesInformation, // 12 + FileDispositionInformation, // 13 + FilePositionInformation, // 14 + FileFullEaInformation, // 15 + FileModeInformation, // 16 + FileAlignmentInformation, // 17 + FileAllInformation, // 18 + FileAllocationInformation, // 19 + FileEndOfFileInformation, // 20 + FileAlternateNameInformation, // 21 + FileStreamInformation, // 22 + FilePipeInformation, // 23 + FilePipeLocalInformation, // 24 + FilePipeRemoteInformation, // 25 + FileMailslotQueryInformation, // 26 + FileMailslotSetInformation, // 27 + FileCompressionInformation, // 28 + FileObjectIdInformation, // 29 + FileCompletionInformation, // 30 + FileMoveClusterInformation, // 31 + FileQuotaInformation, // 32 + FileReparsePointInformation, // 33 + FileNetworkOpenInformation, // 34 + FileAttributeTagInformation, // 35 + FileTrackingInformation, // 36 + FileIdBothDirectoryInformation, // 37 + FileIdFullDirectoryInformation, // 38 + FileValidDataLengthInformation, // 39 + FileShortNameInformation, // 40 + FileIoCompletionNotificationInformation, // 41 + FileIoStatusBlockRangeInformation, // 42 + FileIoPriorityHintInformation, // 43 + FileSfioReserveInformation, // 44 + FileSfioVolumeInformation, // 45 + FileHardLinkInformation, // 46 + FileProcessIdsUsingFileInformation, // 47 + FileNormalizedNameInformation, // 48 + FileNetworkPhysicalNameInformation, // 49 + FileIdGlobalTxDirectoryInformation, // 50 + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + + +/* kernel structures for QueryDirectory results */ +typedef struct _FILE_NAMES_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; + +typedef struct _FILE_DIRECTORY_INFO { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFO, *PFILE_DIRECTORY_INFO; + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +typedef struct _FILE_FULL_DIR_INFO { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFO, *PFILE_FULL_DIR_INFO; + +typedef struct _FILE_ID_FULL_DIR_INFO { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFO, *PFILE_ID_FULL_DIR_INFO; + +typedef struct _FILE_LINK_INFORMATION { + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; + +#endif diff --git a/daemon/getattr.c b/daemon/getattr.c new file mode 100644 index 0000000..8e99e85 --- /dev/null +++ b/daemon/getattr.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include "from_kernel.h" +#include "daemon_debug.h" +#include "nfs41_ops.h" +#include "name_cache.h" +#include "upcall.h" +#include "util.h" + + +int nfs41_cached_getattr( + IN nfs41_session *session, + IN nfs41_path_fh *file, + OUT nfs41_file_info *info) +{ + int status; + + /* first look for cached attributes */ + status = nfs41_attr_cache_lookup(session_name_cache(session), + file->fh.fileid, info); + + if (status) { + /* fetch attributes from the server */ + bitmap4 attr_request; + init_getattr_request(&attr_request); + + status = nfs41_getattr(session, file, &attr_request, info); + if (status) { + eprintf("nfs41_getattr() failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + } + } + return status; +} + +int parse_getattr(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + getattr_upcall_args *args = &upcall->args.getattr; + + status = safe_read(&buffer, &length, &args->query_class, sizeof(args->query_class)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->buf_len, sizeof(args->buf_len)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); +out: + if (status) + eprintf("parsing NFS41_FILE_QUERY failed with %d\n", status); + else + dprintf(1, "parsing NFS41_FILE_QUERY: info_class=%d buf_len=%d " + "root=0x%p open_state=0x%p\n", + args->query_class, args->buf_len, args->root, args->state); + return status; +} + +int handle_getattr(nfs41_upcall *upcall) +{ + int status; + getattr_upcall_args *args = &upcall->args.getattr; + nfs41_open_state *state = args->state; + nfs41_file_info info; + + ZeroMemory(&info, sizeof(info)); + + status = nfs41_cached_getattr(state->session, &state->file, &info); + if (status) { + eprintf("nfs41_cached_getattr() failed with %d\n", status); + goto out; + } + + switch (args->query_class) { + case FileBasicInformation: + nfs_to_basic_info(&info, &args->basic_info); + break; + case FileStandardInformation: + nfs_to_standard_info(&info, &args->std_info); + break; + case FileAttributeTagInformation: + args->tag_info.FileAttributes = nfs_file_info_to_attributes(&info); + args->tag_info.ReparseTag = 0; + break; + default: + eprintf("unhandled file query class %d\n", args->query_class); + status = ERROR_INVALID_PARAMETER; + break; + } +out: + return status; +} + +int marshall_getattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + int status; + getattr_upcall_args *args = &upcall->args.getattr; + uint32_t info_len; + + switch (args->query_class) { + case FileBasicInformation: + info_len = sizeof(args->basic_info); + status = safe_write(&buffer, length, &info_len, sizeof(info_len)); + if (status) goto out; + status = safe_write(&buffer, length, &args->basic_info, info_len); + if (status) goto out; + break; + case FileStandardInformation: + info_len = sizeof(args->std_info); + status = safe_write(&buffer, length, &info_len, sizeof(info_len)); + if (status) goto out; + status = safe_write(&buffer, length, &args->std_info, info_len); + if (status) goto out; + break; + case FileAttributeTagInformation: + info_len = sizeof(args->tag_info); + status = safe_write(&buffer, length, &info_len, sizeof(info_len)); + if (status) goto out; + status = safe_write(&buffer, length, &args->tag_info, info_len); + if (status) goto out; + break; + default: + eprintf("unknown file query class %d\n", args->query_class); + status = 103; + goto out; + } +out: + return status; +} diff --git a/daemon/list.h b/daemon/list.h new file mode 100644 index 0000000..29acf6f --- /dev/null +++ b/daemon/list.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef NFS41_LIST_H +#define NFS41_LIST_H + + +/* doubly-linked list */ +struct list_entry { + struct list_entry *prev; + struct list_entry *next; +}; + + +#define list_container(entry, type, field) \ + ((type*)((const char*)(entry) - (const char*)(&((type*)0)->field))) + +#define list_for_each(entry, head) \ + for (entry = (head)->next; entry != (head); entry = entry->next) + +#define list_for_each_tmp(entry, tmp, head) \ + for (entry = (head)->next, tmp = entry->next; entry != (head); \ + entry = tmp, tmp = entry->next) + +#define list_for_each_reverse(entry, head) \ + for (entry = (head)->prev; entry != (head); entry = entry->prev) + +#define list_for_each_reverse_tmp(entry, tmp, head) \ + for (entry = (head)->next, tmp = entry->next; entry != (head); \ + entry = tmp, tmp = entry->next) + + +static void list_init( + struct list_entry *head) +{ + head->prev = head; + head->next = head; +} + +static int list_empty( + struct list_entry *head) +{ + return head->next == head; +} + +static void list_add( + struct list_entry *entry, + struct list_entry *prev, + struct list_entry *next) +{ + /* assert(prev->next == next && next->prev == prev); */ + entry->prev = prev; + entry->next = next; + prev->next = entry; + next->prev = entry; +} + +static void list_add_head( + struct list_entry *head, + struct list_entry *entry) +{ + list_add(entry, head, head->next); +} + +static void list_add_tail( + struct list_entry *head, + struct list_entry *entry) +{ + list_add(entry, head->prev, head); +} + +static void list_remove( + struct list_entry *entry) +{ + if (!list_empty(entry)) { + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + list_init(entry); + } +} + +typedef int (*list_compare_fn)(const struct list_entry*, const void*); + +static struct list_entry* list_search( + const struct list_entry *head, + const void *value, + list_compare_fn compare) +{ + struct list_entry *entry; + list_for_each(entry, head) + if (compare(entry, value) == 0) + return entry; + return NULL; +} + +#endif /* !NFS41_LIST_H */ diff --git a/daemon/lock.c b/daemon/lock.c new file mode 100644 index 0000000..52e8d76 --- /dev/null +++ b/daemon/lock.c @@ -0,0 +1,252 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "daemon_debug.h" +#include "nfs41_ops.h" +#include "upcall.h" +#include "util.h" + + +#define LKLVL 2 /* dprintf level for lock logging */ + + +stateid4* nfs41_lock_stateid_copy( + IN nfs41_lock_state *lock_state, + IN OUT stateid4 *dest) +{ + stateid4 *result; + AcquireSRWLockShared(&lock_state->lock); + if (lock_state->initialized) { + memcpy(dest, &lock_state->stateid, sizeof(stateid4)); + result = dest; + dprintf(LKLVL, "nfs41_lock_stateid_copy: copying existing stateid " + "with seqid=%u\n", result->seqid); + } else { + result = NULL; + dprintf(LKLVL, "nfs41_lock_stateid_copy: no existing lock state\n"); + } + ReleaseSRWLockShared(&lock_state->lock); + return result; +} + +static void update_last_lock_state( + OUT nfs41_lock_state *lock_state, + IN stateid4 *stateid) +{ + /* update the lock state if the seqid is more recent */ + AcquireSRWLockShared(&lock_state->lock); + if (stateid->seqid > lock_state->stateid.seqid) { + ReleaseSRWLockShared(&lock_state->lock); + + AcquireSRWLockExclusive(&lock_state->lock); + if (stateid->seqid > lock_state->stateid.seqid) { + if (lock_state->initialized) { + /* if the lock state already existed, update the seqid only; + * assume that stateid->other remains unchanged */ + dprintf(LKLVL, "update_last_lock_state: setting seqid=%u " + "(was %u)\n", stateid->seqid, lock_state->stateid.seqid); + lock_state->stateid.seqid = stateid->seqid; + } else { + /* copy the entire stateid and mark as initialized */ + dprintf(LKLVL, "update_last_lock_state: stateid " + "initialized with seqid=%u\n", stateid->seqid); + memcpy(&lock_state->stateid, stateid, sizeof(stateid4)); + lock_state->initialized = 1; + } + } + ReleaseSRWLockExclusive(&lock_state->lock); + } else { + dprintf(LKLVL, "update_last_lock_state: discarding seqid=%u " + "(already %u)\n", stateid->seqid, lock_state->stateid.seqid); + ReleaseSRWLockShared(&lock_state->lock); + } +} + + +/* NFS41_LOCK */ +int parse_lock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + lock_upcall_args *args = &upcall->args.lock; + + status = safe_read(&buffer, &length, &args->state, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->offset, sizeof(LONGLONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->length, sizeof(LONGLONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->exclusive, sizeof(BOOLEAN)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->blocking, sizeof(BOOLEAN)); + if (status) goto out; +out: + if (status) + eprintf("parsing NFS41_LOCK failed with %d\n", status); + else + dprintf(1, "parsing NFS41_LOCK: state=%p root=%p offset=0x%llx " + "length=0x%llx exclusive=%u blocking=%u\n", + args->state, args->root, args->offset, args->length, + args->exclusive, args->blocking); + return status; +} + +static __inline uint32_t get_lock_type(BOOLEAN exclusive, BOOLEAN blocking) +{ + return blocking == 0 + ? ( exclusive == 0 ? READ_LT : WRITE_LT ) + : ( exclusive == 0 ? READW_LT : WRITEW_LT ); +} + +int handle_lock(nfs41_upcall *upcall) +{ + int status; + lock_upcall_args *args = &upcall->args.lock; + nfs41_open_state *state = args->state; + const uint32_t type = get_lock_type(args->exclusive, args->blocking); + stateid4 stateid, *prev_stateid; + + prev_stateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + + status = nfs41_lock(state->session, state, prev_stateid, + type, args->offset, args->length, &stateid); + if (status) { + dprintf(LKLVL, "nfs41_lock failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out; + } + + update_last_lock_state(&state->last_lock, &stateid); +out: + return status; +} + +int marshall_lock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + return NO_ERROR; +} + +int cancel_lock(IN nfs41_upcall *upcall) +{ + int status = NO_ERROR; + lock_upcall_args *args = &upcall->args.lock; + nfs41_open_state *state = args->state; + stateid4 stateid, *prev_stateid; + + dprintf(1, "--> cancel_lock()\n"); + + if (upcall->status) + goto out; + + prev_stateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + + status = nfs41_unlock(state->session, state, + prev_stateid, args->offset, args->length); + if (status) { + dprintf(LKLVL, "cancel_lock: nfs41_unlock() failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out; + } + + update_last_lock_state(&state->last_lock, &stateid); +out: + dprintf(1, "<-- cancel_lock() returning %d\n", status); + return status; +} + + +/* NFS41_UNLOCK */ +int parse_unlock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + unlock_upcall_args *args = &upcall->args.unlock; + + status = safe_read(&buffer, &length, &args->state, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->count, sizeof(ULONG)); + if (status) goto out; + + args->buf = buffer; + args->buf_len = length; +out: + if (status) + eprintf("parsing NFS41_UNLOCK failed with %d\n", status); + else + dprintf(1, "parsing NFS41_UNLOCK: state=%p root=%p count=%u\n", + args->state, args->root, args->count); + return status; +} + +int handle_unlock(nfs41_upcall *upcall) +{ + int status; + unlock_upcall_args *args = &upcall->args.unlock; + nfs41_open_state *state = args->state; + stateid4 stateid; + uint32_t i, nsuccess = 0; + unsigned char *buf = args->buf; + uint32_t buf_len = args->buf_len; + uint64_t offset; + uint64_t length; + + if (nfs41_lock_stateid_copy(&state->last_lock, &stateid) == NULL) { + eprintf("attempt to unlock a file with no lock state\n"); + status = ERROR_NOT_LOCKED; + goto out; + } + + status = NO_ERROR; + for (i = 0; i < args->count; i++) { + if (safe_read(&buf, &buf_len, &offset, sizeof(LONGLONG))) break; + if (safe_read(&buf, &buf_len, &length, sizeof(LONGLONG))) break; + + status = nfs41_unlock(state->session, state, &stateid, offset, length); + if (status == NFS4_OK) { + nsuccess++; + } else { + dprintf(LKLVL, "nfs41_unlock failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + } + } + + if (nsuccess) { + update_last_lock_state(&state->last_lock, &stateid); + status = NO_ERROR; + } +out: + return status; +} + +int marshall_unlock(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + return NO_ERROR; +} \ No newline at end of file diff --git a/daemon/lookup.c b/daemon/lookup.c new file mode 100644 index 0000000..eea5468 --- /dev/null +++ b/daemon/lookup.c @@ -0,0 +1,500 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "nfs41_compound.h" +#include "nfs41_ops.h" +#include "name_cache.h" +#include "util.h" +#include "daemon_debug.h" + + +#define LULVL 2 /* dprintf level for lookup logging */ + + +#define MAX_LOOKUP_COMPONENTS 8 + +/* calculate how much space to allocate for rpc reply */ +#define MAX_LOOKUP_RES_SIZE 4 +#define MAX_GETFH_RES_SIZE (NFS4_FHSIZE + 8) +#define MAX_GETATTR_RES_SIZE 128 /* depends on what we request */ +#define MAX_COMPONENT_RES_SIZE \ + (MAX_LOOKUP_RES_SIZE + MAX_GETFH_RES_SIZE + MAX_GETATTR_RES_SIZE) +#define MAX_RPC_RES_SIZE(num_components) \ + (MAX_COMPONENT_RES_SIZE * ((num_components) + 1)) + + +/* map NFS4ERR_MOVED to an arbitrary windows error */ +#define ERROR_FILESYSTEM_ABSENT ERROR_DEVICE_REMOVED + +struct lookup_referral { + nfs41_path_fh parent; + nfs41_component name; +}; + + +typedef struct __nfs41_lookup_component_args { + nfs41_sequence_args sequence; + nfs41_putfh_args putfh; + nfs41_lookup_args lookup[MAX_LOOKUP_COMPONENTS]; + nfs41_getattr_args getrootattr; + nfs41_getattr_args getattr[MAX_LOOKUP_COMPONENTS]; + bitmap4 attr_request; +} nfs41_lookup_component_args; + +typedef struct __nfs41_lookup_component_res { + nfs41_sequence_res sequence; + nfs41_putfh_res putfh; + nfs41_lookup_res lookup[MAX_LOOKUP_COMPONENTS]; + nfs41_getfh_res getrootfh; + nfs41_getfh_res getfh[MAX_LOOKUP_COMPONENTS]; + nfs41_path_fh root; + nfs41_path_fh file[MAX_LOOKUP_COMPONENTS]; + nfs41_getattr_res getrootattr; + nfs41_getattr_res getattr[MAX_LOOKUP_COMPONENTS]; + nfs41_file_info rootinfo; + nfs41_file_info info[MAX_LOOKUP_COMPONENTS]; + struct lookup_referral *referral; +} nfs41_lookup_component_res; + + +static void init_component_args( + IN nfs41_lookup_component_args *args, + IN nfs41_lookup_component_res *res, + IN nfs41_abs_path *path, + IN struct lookup_referral *referral) +{ + uint32_t i; + + ZeroMemory(args, sizeof(nfs41_lookup_component_args)); + ZeroMemory(res, sizeof(nfs41_lookup_component_res)); + + args->attr_request.count = 2; + args->attr_request.arr[0] = FATTR4_WORD0_TYPE + | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE + | FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID; + args->attr_request.arr[1] = FATTR4_WORD1_MODE + | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_TIME_ACCESS + | FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_MODIFY; + + args->getrootattr.attr_request = &args->attr_request; + res->root.path = path; + res->getrootfh.fh = &res->root.fh; + res->getrootattr.info = &res->rootinfo; + res->getrootattr.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + res->referral = referral; + + for (i = 0; i < MAX_LOOKUP_COMPONENTS; i++) { + args->getattr[i].attr_request = &args->attr_request; + res->file[i].path = path; + args->lookup[i].name = &res->file[i].name; + res->getfh[i].fh = &res->file[i].fh; + res->getattr[i].info = &res->info[i]; + res->getattr[i].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + } +} + +static int lookup_rpc( + IN nfs41_session *session, + IN nfs41_path_fh *dir, + IN uint32_t component_count, + IN nfs41_lookup_component_args *args, + OUT nfs41_lookup_component_res *res) +{ + int status; + uint32_t i, buffer_size; + nfs41_compound compound; + nfs_argop4 argops[4+MAX_LOOKUP_COMPONENTS*3]; + nfs_resop4 resops[4+MAX_LOOKUP_COMPONENTS*3]; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &args->sequence, &res->sequence); + status = nfs41_session_sequence(&args->sequence, session, 0); + if (status) + goto out; + + if (dir == &res->root) { + compound_add_op(&compound, OP_PUTROOTFH, + NULL, &res->putfh); + compound_add_op(&compound, OP_GETFH, + NULL, &res->getrootfh); + compound_add_op(&compound, OP_GETATTR, + &args->getrootattr, &res->getrootattr); + } else { + args->putfh.file = dir; + compound_add_op(&compound, OP_PUTFH, + &args->putfh, &res->putfh); + } + + for (i = 0; i < component_count; i++) { + compound_add_op(&compound, OP_LOOKUP, + &args->lookup[i], &res->lookup[i]); + compound_add_op(&compound, OP_GETFH, + NULL, &res->getfh[i]); + compound_add_op(&compound, OP_GETATTR, + &args->getattr[i], &res->getattr[i]); + } + + buffer_size = MAX_RPC_RES_SIZE(component_count); + status = compound_encode_send_decode(session, &compound, 0, buffer_size); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +static int server_lookup( + IN nfs41_session *session, + IN nfs41_path_fh *dir, + IN const char *path, + IN const char *path_end, + IN uint32_t count, + IN nfs41_lookup_component_args *args, + IN nfs41_lookup_component_res *res, + OUT OPTIONAL nfs41_path_fh **parent_out, + OUT OPTIONAL nfs41_path_fh **target_out, + OUT OPTIONAL nfs41_file_info *info_out) +{ + nfs41_path_fh *file, *parent; + uint32_t i = 0; + int status; + + if (parent_out) *parent_out = NULL; + if (target_out) *target_out = NULL; + + lookup_rpc(session, dir, count, args, res); + + status = res->sequence.sr_status; if (status) goto out; + status = res->putfh.status; if (status) goto out; + status = res->getrootfh.status; if (status) goto out; + status = res->getrootattr.status; if (status) goto out; + + if (dir == &res->root) { + nfs41_component name = { 0 }; + + /* fill in the file handle's fileid and superblock */ + dir->fh.fileid = res->getrootattr.info->fileid; + status = nfs41_superblock_for_fh(session, + &res->getrootattr.info->fsid, NULL, dir); + if (status) + goto out; + + /* get the name of the parent (empty if its the root) */ + last_component(path, count ? args->lookup[0].name->name : path_end, &name); + + /* add the file handle and attributes to the name cache */ + memcpy(&res->getrootattr.info->attrmask, + &res->getrootattr.obj_attributes.attrmask, sizeof(bitmap4)); + nfs41_name_cache_insert(session_name_cache(session), + path, &name, &dir->fh, res->getrootattr.info, NULL); + } + file = dir; + + if (count == 0) { + if (target_out) + *target_out = dir; + if (info_out) + memcpy(info_out, res->getrootattr.info, sizeof(nfs41_file_info)); + } else if (count == 1) { + if (parent_out) + *parent_out = dir; + } + + for (i = 0; i < count; i++) { + status = res->lookup[i].status; if (status) break; + if (res->getfh[i].status == NFS4ERR_MOVED) { + /* save enough information to follow the referral */ + path_fh_copy(&res->referral->parent, file); + res->referral->name.name = args->lookup[i].name->name; + res->referral->name.len = args->lookup[i].name->len; + return ERROR_FILESYSTEM_ABSENT; + } + status = res->getfh[i].status; if (status) break; + status = res->getattr[i].status; if (status) break; + + parent = file; + file = &res->file[i]; + + /* fill in the file handle's fileid and superblock */ + file->fh.fileid = res->getattr[i].info->fileid; + status = nfs41_superblock_for_fh(session, + &res->getattr[i].info->fsid, &parent->fh, file); + if (status) + break; + + /* add the file handle and attributes to the name cache */ + memcpy(&res->getattr[i].info->attrmask, + &res->getattr[i].obj_attributes.attrmask, sizeof(bitmap4)); + nfs41_name_cache_insert(session_name_cache(session), + path, args->lookup[i].name, &res->file[i].fh, + res->getattr[i].info, NULL); + + if (i == count-1) { + if (target_out) + *target_out = file; + if (info_out) + memcpy(info_out, res->getattr[i].info, sizeof(nfs41_file_info)); + } else if (i == count-2) { + if (parent_out) + *parent_out = file; + } + } +out: + status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); + + /* use PATH_NOT_FOUND for all but the last name */ + if (status == ERROR_FILE_NOT_FOUND && i != count-1) + status = ERROR_PATH_NOT_FOUND; + return status; +} + +static uint32_t max_lookup_components( + IN const nfs41_session *session) +{ + const uint32_t comps = (session->fore_chan_attrs.ca_maxoperations - 4) / 3; + return min(comps, MAX_LOOKUP_COMPONENTS); +} + +static uint32_t get_component_array( + IN OUT const char **path_pos, + IN const char *path_end, + IN uint32_t max_components, + OUT nfs41_path_fh *components, + OUT uint32_t *component_count) +{ + uint32_t i; + + for (i = 0; i < max_components; i++) { + if (!next_component(*path_pos, path_end, &components[i].name)) + break; + *path_pos = components[i].name.name + components[i].name.len; + } + + *component_count = i; + return i; +} + +static int server_lookup_loop( + IN nfs41_session *session, + IN OPTIONAL nfs41_path_fh *parent_in, + IN nfs41_abs_path *path, + IN const char *path_pos, + IN struct lookup_referral *referral, + OUT OPTIONAL nfs41_path_fh *parent_out, + OUT OPTIONAL nfs41_path_fh *target_out, + OUT OPTIONAL nfs41_file_info *info_out) +{ + nfs41_lookup_component_args args; + nfs41_lookup_component_res res; + nfs41_path_fh *dir, *parent, *target; + const char *path_end; + const uint32_t max_components = max_lookup_components(session); + uint32_t count; + int status = NO_ERROR; + + init_component_args(&args, &res, path, referral); + parent = NULL; + target = NULL; + + path_end = path->path + path->len; + dir = parent_in ? parent_in : &res.root; + + while (get_component_array(&path_pos, path_end, + max_components, res.file, &count)) { + + status = server_lookup(session, dir, path->path, path_end, count, + &args, &res, &parent, &target, info_out); + + if (status == ERROR_FILE_NOT_FOUND && is_last_component(path_pos, path_end)) + goto out_parent; + if (status) + goto out; + + dir = target; + } + + if (dir == &res.root && (target_out || info_out)) { + /* didn't get any components, so we just need the root */ + status = server_lookup(session, dir, path->path, path_end, + 0, &args, &res, &parent, &target, info_out); + if (status) + goto out; + } + + if (target_out && target) fh_copy(&target_out->fh, &target->fh); +out_parent: + if (parent_out && parent) fh_copy(&parent_out->fh, &parent->fh); +out: + return status; +} + + +static void referral_locations_free( + IN fs_locations4 *locations) +{ + uint32_t i; + if (locations->locations) { + for (i = 0; i < locations->location_count; i++) + free(locations->locations[i].servers); + free(locations->locations); + } +} + +static int referral_resolve( + IN nfs41_root *root, + IN nfs41_session *session_in, + IN struct lookup_referral *referral, + OUT nfs41_abs_path *path_out, + OUT nfs41_session **session_out) +{ + char rest_of_path[NFS41_MAX_PATH_LEN]; + fs_locations4 locations = { 0 }; + const fs_location4 *location; + nfs41_client *client; + int status; + + /* get fs_locations */ + status = nfs41_fs_locations(session_in, &referral->parent, + &referral->name, &locations); + if (status) { + eprintf("nfs41_fs_locations() failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_PATH_NOT_FOUND); + goto out; + } + + /* mount the first location available */ + status = nfs41_root_mount_referral(root, &locations, &location, &client); + if (status) { + eprintf("nfs41_root_mount_referral() failed with %d\n", + status); + goto out; + } + + /* format a new path from that location's root */ + StringCchCopyA(rest_of_path, NFS41_MAX_PATH_LEN, + referral->name.name + referral->name.len); + + AcquireSRWLockExclusive(&path_out->lock); + abs_path_copy(path_out, &location->path); + StringCchCatA(path_out->path, NFS41_MAX_PATH_LEN, rest_of_path); + path_out->len += (unsigned short)strlen(rest_of_path); + ReleaseSRWLockExclusive(&path_out->lock); + + if (session_out) *session_out = client->session; +out: + referral_locations_free(&locations); + return status; +} + +int nfs41_lookup( + IN nfs41_root *root, + IN nfs41_session *session, + IN OUT nfs41_abs_path *path_inout, + OUT OPTIONAL nfs41_path_fh *parent_out, + OUT OPTIONAL nfs41_path_fh *target_out, + OUT OPTIONAL nfs41_file_info *info_out, + OUT nfs41_session **session_out) +{ + nfs41_abs_path path; + struct nfs41_name_cache *cache = session_name_cache(session); + nfs41_path_fh parent, target, *server_start; + const char *path_pos, *path_end; + struct lookup_referral referral; + int status; + + if (session_out) *session_out = session; + + InitializeSRWLock(&path.lock); + + /* to avoid holding this lock over multiple rpcs, + * make a copy of the path and use that instead */ + AcquireSRWLockShared(&path_inout->lock); + abs_path_copy(&path, path_inout); + ReleaseSRWLockShared(&path_inout->lock); + + path_pos = path.path; + path_end = path.path + path.len; + + dprintf(LULVL, "--> nfs41_lookup('%s')\n", path.path); + + if (parent_out == NULL) parent_out = &parent; + if (target_out == NULL) target_out = ⌖ + parent_out->fh.len = target_out->fh.len = 0; + + status = nfs41_name_cache_lookup(cache, + path_pos, path_end, &path_pos, + &parent_out->fh, &target_out->fh, info_out); + if (status == NO_ERROR) + goto out; + + if (target_out->fh.len) { + /* start where the name cache left off */ + if (target_out != &target) { + /* must make a copy for server_start, because + * server_lookup_loop() will overwrite target_out */ + path_fh_copy(&target, target_out); + } + server_start = ⌖ + } else { + /* start with PUTROOTFH */ + server_start = NULL; + } + + status = server_lookup_loop(session, server_start, + &path, path_pos, &referral, parent_out, target_out, info_out); + + if (status == ERROR_FILESYSTEM_ABSENT) { + nfs41_session *new_session; + + /* create a session to the referred server and + * reformat the path relative to that server's root */ + status = referral_resolve(root, session, + &referral, path_inout, &new_session); + if (status) { + eprintf("referral_resolve() failed with %d\n", status); + goto out; + } + + /* update the positions of the parent and target components */ + last_component(path_inout->path, path_inout->path + path_inout->len, + &target_out->name); + last_component(path_inout->path, target_out->name.name, + &parent_out->name); + + if (session_out) *session_out = new_session; + + /* look up the new path */ + status = nfs41_lookup(root, new_session, path_inout, + parent_out, target_out, info_out, session_out); + } +out: + dprintf(LULVL, "<-- nfs41_lookup() returning %d\n", status); + return status; +} diff --git a/daemon/makefile b/daemon/makefile new file mode 100644 index 0000000..66f1c8e --- /dev/null +++ b/daemon/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def + diff --git a/daemon/mount.c b/daemon/mount.c new file mode 100644 index 0000000..a0c7457 --- /dev/null +++ b/daemon/mount.c @@ -0,0 +1,131 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "daemon_debug.h" +#include "nfs41_ops.h" +#include "upcall.h" +#include "util.h" + +/* NFS41_MOUNT */ +int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + mount_upcall_args *args = &upcall->args.mount; + + status = get_name(&buffer, &length, args->srv_name); + if(status) goto out; + ZeroMemory(&args->path, sizeof(nfs41_abs_path)); + status = get_abs_path(&buffer, &length, &args->path); +out: + if (status) + eprintf("parsing of NFS41_MOUNT failed with %d\n", status); + else + dprintf(1, "parsing NFS14_MOUNT: srv_name=%s root=%s\n", + args->srv_name, args->path.path); + return status; +} + +int handle_mount(nfs41_upcall *upcall) +{ + int status; + mount_upcall_args *args = &upcall->args.mount; + multi_addr4 addrs; + const unsigned short port = 2049; + nfs41_root *root; + nfs41_client *client; + + // resolve hostname,port + status = nfs41_server_resolve(args->srv_name, port, &addrs); + if (status) { + eprintf("nfs41_server_resolve() failed with %d\n", status); + goto out; + } + // create root + status = nfs41_root_create(args->srv_name, port, &args->path, + NFS41_MAX_FILEIO_SIZE + WRITE_OVERHEAD, + NFS41_MAX_FILEIO_SIZE + READ_OVERHEAD, &root); + if (status) { + eprintf("nfs41_rpc_clnt_create failed %d\n", status); + goto out; + } + // add a mount + status = nfs41_root_mount_addrs(root, &addrs, 0, 0, &client); + if (status) { + eprintf("nfs41_root_mount() failed with %d\n", status); + goto out_err; + } + // look up the mount path, and fail if it doesn't exist + status = nfs41_lookup(root, client->session, + &args->path, NULL, NULL, NULL, NULL); + if (status) { + eprintf("nfs41_lookup('%s') failed with %d\n", + args->path.path, status); + goto out_err; + } + + args->root = root; +out: + return status; + +out_err: + nfs41_root_free(root); + goto out; +} + +int marshall_mount(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + mount_upcall_args *args = &upcall->args.mount; + dprintf(2, "NFS41_MOUNT: writing pointer to nfs41_root %p\n", args->root); + return safe_write(&buffer, length, &args->root, sizeof(args->root)); +} + + +/* NFS41_UNMOUNT */ +int parse_unmount(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + unmount_upcall_args *args = &upcall->args.unmount; + + status = safe_read(&buffer, &length, &args->root, sizeof(nfs41_session *)); + if (status) + eprintf("parsing NFS41_UNMOUNT failed with %d\n", status); + else + dprintf(1, "parsing NFS41_UNMOUNT: unmount root=%p\n", args->root); + return status; +} + +int handle_unmount(nfs41_upcall *upcall) +{ + int status = NO_ERROR; + unmount_upcall_args *args = &upcall->args.unmount; + nfs41_root_free(args->root); + return status; +} + +int marshall_unmount(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + return NO_ERROR; +} diff --git a/daemon/name_cache.c b/daemon/name_cache.c new file mode 100644 index 0000000..5971a53 --- /dev/null +++ b/daemon/name_cache.c @@ -0,0 +1,1243 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ +#include +#include +#include + +#include "nfs41_ops.h" +#include "nfs41_compound.h" +#include "name_cache.h" +#include "util.h" +#include "rbtree.h" +#include "daemon_debug.h" + + +/* dprintf levels for name cache logging */ +enum { + NCLVL1 = 2, + NCLVL2 +}; + +#define NAME_CACHE_EXPIRATION 20 /* TODO: get from configuration */ + +/* allow up to 128K of memory for name and attribute cache entries */ +#define NAME_CACHE_MAX_SIZE 131072 + + +/* attribute cache */ +struct attr_cache_entry { + struct rb_node rbnode; + struct list_entry free_entry; + uint64_t change; + uint64_t size; + uint64_t fileid; + int64_t time_access_s; + int64_t time_create_s; + int64_t time_modify_s; + uint32_t time_access_ns; + uint32_t time_create_ns; + uint32_t time_modify_ns; + uint32_t numlinks; + uint32_t mode; + unsigned short ref_count; + unsigned char type; + unsigned char invalidated; +}; +#define ATTR_ENTRY_SIZE sizeof(struct attr_cache_entry) + +struct attr_cache { + struct rb_root root; + struct attr_cache_entry *pool; + struct list_entry free_entries; +}; + + +/* attr_cache_entry */ +#define attr_entry(pos) list_container(pos, struct attr_cache_entry, free_entry) + +static int attr_cache_entry_create( + IN struct attr_cache *cache, + IN uint64_t fileid, + OUT struct attr_cache_entry **entry_out) +{ + struct attr_cache_entry *entry; + int status = NO_ERROR; + + /* get the next entry from free_entries and remove it */ + if (list_empty(&cache->free_entries)) { + status = ERROR_OUTOFMEMORY; + goto out; + } + entry = attr_entry(cache->free_entries.next); + list_remove(&entry->free_entry); + + entry->fileid = fileid; + *entry_out = entry; +out: + return status; +} + +static __inline void attr_cache_entry_free( + IN struct attr_cache *cache, + IN struct attr_cache_entry *entry) +{ + dprintf(NCLVL1, "attr_cache_entry_free(%llu)\n", entry->fileid); + rb_erase(&entry->rbnode, &cache->root); + /* add it back to free_entries */ + list_add_tail(&cache->free_entries, &entry->free_entry); +} + +static __inline void attr_cache_entry_ref( + IN struct attr_cache *cache, + IN struct attr_cache_entry *entry) +{ + const uint32_t previous = entry->ref_count++; + dprintf(NCLVL2, "attr_cache_entry_ref(%llu) %u -> %u\n", + entry->fileid, previous, entry->ref_count); +} + +static __inline void attr_cache_entry_deref( + IN struct attr_cache *cache, + IN struct attr_cache_entry *entry) +{ + const uint32_t previous = entry->ref_count--; + dprintf(NCLVL2, "attr_cache_entry_deref(%llu) %u -> %u\n", + entry->fileid, previous, entry->ref_count); + + if (entry->ref_count == 0) + attr_cache_entry_free(cache, entry); +} + +/* attr_cache */ +static int attr_cache_init( + IN struct attr_cache *cache, + IN uint32_t max_entries) +{ + uint32_t i; + int status = NO_ERROR; + + /* allocate a pool of entries */ + cache->pool = calloc(max_entries, ATTR_ENTRY_SIZE); + if (cache->pool == NULL) { + status = GetLastError(); + goto out; + } + + /* initialize the list of free entries */ + list_init(&cache->free_entries); + for (i = 0; i < max_entries; i++) { + list_init(&cache->pool[i].free_entry); + list_add_tail(&cache->free_entries, &cache->pool[i].free_entry); + } +out: + return status; +} + +static void attr_cache_free( + IN struct attr_cache *cache) +{ + /* free the pool */ + free(cache->pool); + cache->pool = NULL; + list_init(&cache->free_entries); +} + +static struct attr_cache_entry* attr_cache_search( + IN struct attr_cache *cache, + IN uint64_t fileid) +{ + struct rb_node *node; + struct attr_cache_entry *entry; + + dprintf(NCLVL2, "--> attr_cache_search(%llu)\n", fileid); + + entry = NULL; + node = cache->root.rb_node; + + while (node) { + entry = rb_entry(node, struct attr_cache_entry, rbnode); + + if (fileid < entry->fileid) + node = node->rb_left; + else if (fileid > entry->fileid) + node = node->rb_right; + else { + dprintf(NCLVL2, "<-- attr_cache_search() " + "found existing entry 0x%p\n", entry); + goto out_success; + } + } + entry = NULL; + dprintf(NCLVL2, "<-- attr_cache_search() returning NULL\n"); + +out_success: + return entry; +} + +static int attr_cache_insert( + IN struct attr_cache *cache, + IN struct attr_cache_entry *entry) +{ + int status = NO_ERROR; + struct rb_node **node, *prev; + struct attr_cache_entry *current; + + dprintf(NCLVL2, "--> attr_cache_insert(%llu)\n", entry->fileid); + + node = &cache->root.rb_node; + prev = NULL; + + while (*node) { + current = rb_entry(*node, struct attr_cache_entry, rbnode); + + prev = *node; + if (entry->fileid < current->fileid) + node = &(*node)->rb_left; + else if (entry->fileid > current->fileid) + node = &(*node)->rb_right; + else { + status = ERROR_FILE_EXISTS; + goto out; + } + } + + rb_link_node(&entry->rbnode, prev, node); + rb_insert_color(&entry->rbnode, &cache->root); +out: + dprintf(NCLVL2, "<-- attr_cache_insert() returning %d\n", status); + return status; +} + +static int attr_cache_find_or_create( + IN struct attr_cache *cache, + IN uint64_t fileid, + OUT struct attr_cache_entry **entry_out) +{ + struct attr_cache_entry *entry; + int status = NO_ERROR; + + dprintf(NCLVL1, "--> attr_cache_find_or_create(%llu)\n", fileid); + + /* look for an existing entry */ + entry = attr_cache_search(cache, fileid); + if (entry == NULL) { + /* create and insert */ + status = attr_cache_entry_create(cache, fileid, &entry); + if (status) + goto out; + + status = attr_cache_insert(cache, entry); + if (status) + goto out_err_free; + } + + /* take a reference on success */ + attr_cache_entry_ref(cache, entry); + +out: + *entry_out = entry; + dprintf(NCLVL1, "<-- attr_cache_find_or_create() returning %d\n", + status); + return status; + +out_err_free: + attr_cache_entry_free(cache, entry); + entry = NULL; + goto out; +} + +static void attr_cache_update( + IN struct attr_cache_entry *entry, + IN const nfs41_file_info *info) +{ + /* update the attributes present in mask */ + if (info->attrmask.count >= 1) { + if (info->attrmask.arr[0] & FATTR4_WORD0_TYPE) + entry->type = info->type & NFS_FTYPE_MASK; + if (info->attrmask.arr[0] & FATTR4_WORD0_CHANGE) { + entry->change = info->change; + /* revalidate whenever we get a change attribute */ + entry->invalidated = 0; + } + if (info->attrmask.arr[0] & FATTR4_WORD0_SIZE) + entry->size = info->size; + } + if (info->attrmask.count >= 2) { + if (info->attrmask.arr[1] & FATTR4_WORD1_MODE) + entry->mode = info->mode; + if (info->attrmask.arr[1] & FATTR4_WORD1_NUMLINKS) + entry->numlinks = info->numlinks; + if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS) { + entry->time_access_s = info->time_access.seconds; + entry->time_access_ns = info->time_access.nseconds; + } + if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_CREATE) { + entry->time_create_s = info->time_create.seconds; + entry->time_create_ns = info->time_create.nseconds; + } + if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_MODIFY) { + entry->time_modify_s = info->time_modify.seconds; + entry->time_modify_ns = info->time_modify.nseconds; + } + } +} + +static void copy_attrs( + OUT nfs41_file_info *dst, + IN const struct attr_cache_entry *src) +{ + dst->change = src->change; + dst->size = src->size; + dst->time_access.seconds = src->time_access_s; + dst->time_access.nseconds = src->time_access_ns; + dst->time_create.seconds = src->time_create_s; + dst->time_create.nseconds = src->time_create_ns; + dst->time_modify.seconds = src->time_modify_s; + dst->time_modify.nseconds = src->time_modify_ns; + dst->type = src->type; + dst->numlinks = src->numlinks; + dst->mode = src->mode; +} + + +/* name cache */ +struct name_cache_entry { + char component[NFS41_MAX_COMPONENT_SIZE]; + nfs41_fh fh; + struct rb_node rbnode; + struct rb_root rbchildren; + struct attr_cache_entry *attributes; + struct name_cache_entry *parent; + struct list_entry exp_entry; + time_t expiration; + unsigned short component_len; +}; +#define NAME_ENTRY_SIZE sizeof(struct name_cache_entry) + +struct nfs41_name_cache { + struct name_cache_entry *root; + struct name_cache_entry *pool; + struct attr_cache attributes; + struct list_entry exp_entries; /* list of entries by expiry */ + uint32_t expiration; + uint32_t entries; + uint32_t max_entries; + SRWLOCK lock; +}; + + +/* internal name cache functions used by the public name cache interface; + * these functions expect the caller to hold a lock on the cache */ + +#define name_entry(pos) list_container(pos, struct name_cache_entry, exp_entry) + +static __inline bool_t name_cache_enabled( + IN struct nfs41_name_cache *cache) +{ + return cache->expiration > 0; +} + +static __inline void name_cache_entry_rename( + OUT struct name_cache_entry *entry, + IN const nfs41_component *component) +{ + StringCchCopyNA(entry->component, NFS41_MAX_COMPONENT_LEN, + component->name, component->len); + entry->component_len = component->len; +} + +static __inline void name_cache_remove( + IN struct name_cache_entry *entry, + IN struct name_cache_entry *parent) +{ + rb_erase(&entry->rbnode, &parent->rbchildren); + entry->parent = NULL; +} + +static void name_cache_unlink_children_recursive( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *parent); + +static __inline void name_cache_unlink( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *entry) +{ + /* remove the entry from the tree */ + if (entry->parent) + name_cache_remove(entry, entry->parent); + else if (entry == cache->root) + cache->root = NULL; + + /* unlink all of its children */ + name_cache_unlink_children_recursive(cache, entry); + /* release the cached attributes */ + if (entry->attributes) { + attr_cache_entry_deref(&cache->attributes, entry->attributes); + entry->attributes = NULL; + } + /* move it to the end of exp_entries for scavenging */ + list_remove(&entry->exp_entry); + list_add_tail(&cache->exp_entries, &entry->exp_entry); +} + +static void name_cache_unlink_children_recursive( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *parent) +{ + struct name_cache_entry *entry; + struct rb_node *node = rb_first(&parent->rbchildren); + + while (node) { + entry = rb_entry(node, struct name_cache_entry, rbnode); + node = rb_next(node); + name_cache_unlink(cache, entry); + } +} + +static int name_cache_entry_create( + IN struct nfs41_name_cache *cache, + IN const nfs41_component *component, + IN uint64_t fileid, + OUT struct name_cache_entry **entry_out) +{ + int status = NO_ERROR; + struct name_cache_entry *entry; + + if (cache->entries >= cache->max_entries) { + /* scavenge the oldest entry */ + entry = name_entry(cache->exp_entries.prev); + name_cache_unlink(cache, entry); + + dprintf(NCLVL2, "name_cache_entry_create('%s') scavenged 0x%p\n", + component->name, entry); + } else { + /* take the next entry in the pool and add it to exp_entries */ + entry = &cache->pool[cache->entries++]; + list_init(&entry->exp_entry); + list_add_tail(&cache->exp_entries, &entry->exp_entry); + } + + name_cache_entry_rename(entry, component); + + status = attr_cache_find_or_create(&cache->attributes, + fileid, &entry->attributes); + if (status) + goto out; + + *entry_out = entry; +out: + return status; +} + +static __inline void name_cache_entry_refresh( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *entry) +{ + /* update the expiration timer */ + entry->expiration = time(NULL) + cache->expiration; + /* move the entry to the front of cache->exp_entries */ + list_remove(&entry->exp_entry); + list_add_head(&cache->exp_entries, &entry->exp_entry); +} + +static void name_cache_entry_update( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *entry, + IN const nfs41_fh *fh, + IN const nfs41_file_info *info) +{ + fh_copy(&entry->fh, fh); + attr_cache_update(entry->attributes, info); + name_cache_entry_refresh(cache, entry); +} + +static int name_cache_entry_changed( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *entry, + IN const change_info4 *cinfo) +{ + if (cinfo->after == entry->attributes->change || + (cinfo->atomic && cinfo->before == entry->attributes->change)) { + entry->attributes->change = cinfo->after; + name_cache_entry_refresh(cache, entry); + dprintf(NCLVL1, "name_cache_entry_changed('%s') has not changed. " + "updated change=%llu\n", entry->component, + entry->attributes->change); + return FALSE; + } else { + dprintf(NCLVL1, "name_cache_entry_changed('%s') has changed: was %llu, " + "got before=%llu\n", entry->component, + entry->attributes->change, cinfo->before); + return TRUE; + } +} + +static __inline void name_cache_entry_invalidate( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *entry) +{ + dprintf(NCLVL1, "name_cache_entry_invalidate('%s')\n", entry->component); + + /* flag attributes so that entry_has_expired() will return true + * if another entry attempts to use them */ + entry->attributes->invalidated = 1; + + name_cache_unlink(cache, entry); +} + +static struct name_cache_entry* name_cache_search( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *parent, + IN const nfs41_component *component) +{ + char dbg_name[NFS41_MAX_COMPONENT_LEN]; + struct rb_node *node; + struct name_cache_entry *entry; + int result; + + StringCchCopyNA(dbg_name, NFS41_MAX_COMPONENT_LEN, + component->name, component->len); + dprintf(NCLVL2, "--> name_cache_search('%s' under '%s')\n", + dbg_name, parent->component); + + entry = NULL; + node = parent->rbchildren.rb_node; + + while (node) { + entry = rb_entry(node, struct name_cache_entry, rbnode); + + result = strncmp(component->name, entry->component, + max(component->len, entry->component_len)); + if (result < 0) + node = node->rb_left; + else if (result > 0) + node = node->rb_right; + else { + dprintf(NCLVL2, "<-- name_cache_search() " + "found existing entry 0x%p\n", entry); + goto out_success; + } + } + entry = NULL; + dprintf(NCLVL2, "<-- name_cache_search() returning NULL\n"); + +out_success: + return entry; +} + +static __inline int entry_has_expired( + IN struct name_cache_entry *entry) +{ + /* invalidated by another entry or timer expired */ + const int expired = entry->attributes->invalidated + || time(NULL) > entry->expiration; + + if (expired) + dprintf(NCLVL2, "entry_has_expired('%s')\n", entry->component); + return expired; +} + +static int name_cache_lookup( + IN struct nfs41_name_cache *cache, + IN bool_t skip_expired, + IN const char *path, + IN const char *path_end, + OUT OPTIONAL const char **remaining_path_out, + OUT OPTIONAL struct name_cache_entry **parent_out, + OUT OPTIONAL struct name_cache_entry **target_out) +{ + struct name_cache_entry *parent, *target, *tmp; + nfs41_component component; + const char *path_pos; + int status = NO_ERROR; + + dprintf(NCLVL1, "--> name_cache_lookup('%s')\n", path); + + parent = NULL; + target = cache->root; + component.name = path_pos = path; + + if (target == NULL || (skip_expired && entry_has_expired(target))) { + target = NULL; + status = ERROR_PATH_NOT_FOUND; + goto out; + } + + while (next_component(path_pos, path_end, &component)) { + tmp = name_cache_search(cache, target, &component); + if (tmp == NULL || (skip_expired && entry_has_expired(tmp))) { + if (is_last_component(component.name, path_end)) + status = ERROR_FILE_NOT_FOUND; + else + status = ERROR_PATH_NOT_FOUND; + break; + } + parent = target; + target = tmp; + path_pos = component.name + component.len; + } +out: + if (remaining_path_out) *remaining_path_out = component.name; + if (parent_out) *parent_out = parent; + if (target_out) *target_out = target; + dprintf(NCLVL1, "<-- name_cache_lookup() returning %d\n", status); + return status; +} + +static int name_cache_insert( + IN struct name_cache_entry *entry, + IN struct name_cache_entry *parent) +{ + int result, status = NO_ERROR; + struct rb_node **node, *prev; + struct name_cache_entry *current; + + dprintf(NCLVL2, "--> name_cache_insert('%s')\n", entry->component); + + node = &parent->rbchildren.rb_node; + prev = NULL; + + while (*node) { + current = rb_entry(*node, struct name_cache_entry, rbnode); + + result = strcmp(entry->component, current->component); + + prev = *node; + if (result < 0) + node = &(*node)->rb_left; + else if (result > 0) + node = &(*node)->rb_right; + else { + status = ERROR_FILE_EXISTS; + goto out; + } + } + current = NULL; + + rb_link_node(&entry->rbnode, prev, node); + rb_insert_color(&entry->rbnode, &parent->rbchildren); + entry->parent = parent; + +out: + dprintf(NCLVL2, "<-- name_cache_insert() returning %u\n", status); + return status; +} + +static int name_cache_entry_find_or_create( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *parent, + IN const nfs41_component *component, + IN uint64_t fileid, + OUT struct name_cache_entry **target_out) +{ + char dbg_name[NFS41_MAX_COMPONENT_LEN]; + int status = NO_ERROR; + + StringCchCopyNA(dbg_name, NFS41_MAX_COMPONENT_LEN, + component->name, component->len); + dprintf(NCLVL1, "--> name_cache_entry_find_or_create(" + "'%s' under '%s')\n", dbg_name, parent->component); + + *target_out = name_cache_search(cache, parent, component); + if (*target_out) + goto out; + + status = name_cache_entry_create(cache, component, fileid, target_out); + if (status) + goto out; + + status = name_cache_insert(*target_out, parent); + if (status) + goto out_err; + +out: + dprintf(NCLVL1, "<-- name_cache_entry_find_or_create() returning %d\n", + status); + return status; + +out_err: + *target_out = NULL; + goto out; +} + +static int name_cache_find_or_create( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const char *path_end, + IN const uint64_t fileid, + OUT struct name_cache_entry **target_out) +{ + struct name_cache_entry *parent; + const char *path_pos; + nfs41_component component; + int status = NO_ERROR; + + dprintf(NCLVL1, "--> name_cache_find_or_create('%s')\n", path); + + status = name_cache_lookup(cache, 0, path, path_end, + &path_pos, &parent, target_out); + if (status != ERROR_FILE_NOT_FOUND) + goto out; + + component.name = path_pos; + component.len = (unsigned short)(path_end - path_pos); + + status = name_cache_entry_find_or_create(cache, + *target_out, &component, fileid, target_out); +out: + dprintf(NCLVL1, "<-- name_cache_find_or_create() returning 0x%p\n", + *target_out); + return status; +} + +static void name_cache_rename( + IN struct nfs41_name_cache *cache, + IN struct name_cache_entry *src_dir, + IN struct name_cache_entry *src, + IN struct name_cache_entry *dst_dir, + IN const nfs41_component *component, + OUT struct name_cache_entry **dst_out) +{ + struct name_cache_entry *existing; + + name_cache_remove(src, src_dir); + + name_cache_entry_rename(src, component); + + existing = name_cache_search(cache, dst_dir, component); + if (existing) + name_cache_unlink(cache, existing); + + name_cache_insert(src, dst_dir); +} + + +/* public name cache interface, declared in name_cache.h */ + +/* assuming no hard links, calculate how many entries will fit in the cache */ +#define SIZE_PER_ENTRY (ATTR_ENTRY_SIZE + NAME_ENTRY_SIZE) +#define NAME_CACHE_MAX_ENTRIES (NAME_CACHE_MAX_SIZE / SIZE_PER_ENTRY) + +int nfs41_name_cache_create( + OUT struct nfs41_name_cache **cache_out) +{ + struct nfs41_name_cache *cache; + int status = NO_ERROR; + + dprintf(NCLVL1, "nfs41_name_cache_create()\n"); + + /* allocate the cache */ + cache = calloc(1, sizeof(struct nfs41_name_cache)); + if (cache == NULL) { + status = GetLastError(); + goto out; + } + + list_init(&cache->exp_entries); + cache->expiration = NAME_CACHE_EXPIRATION; + cache->max_entries = NAME_CACHE_MAX_ENTRIES; + InitializeSRWLock(&cache->lock); + + /* allocate a pool of entries */ + cache->pool = calloc(cache->max_entries, NAME_ENTRY_SIZE); + if (cache->pool == NULL) { + status = GetLastError(); + goto out_err_cache; + } + + /* initialize the attribute cache */ + status = attr_cache_init(&cache->attributes, cache->max_entries); + if (status) + goto out_err_pool; + + *cache_out = cache; +out: + return status; + +out_err_pool: + free(cache->pool); +out_err_cache: + free(cache); + goto out; +} + +int nfs41_name_cache_free( + IN struct nfs41_name_cache **cache_out) +{ + struct nfs41_name_cache *cache = *cache_out; + int status = NO_ERROR; + + dprintf(NCLVL1, "nfs41_name_cache_free()\n"); + + /* free the attribute cache */ + attr_cache_free(&cache->attributes); + + /* free the name entry pool */ + free(cache->pool); + free(cache); + *cache_out = NULL; + return status; +} + +static __inline void copy_fh( + OUT nfs41_fh *dst, + IN OPTIONAL const struct name_cache_entry *src) +{ + if (src) + fh_copy(dst, &src->fh); + else + dst->len = 0; +} + +int nfs41_name_cache_lookup( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const char *path_end, + OUT OPTIONAL const char **remaining_path_out, + OUT OPTIONAL nfs41_fh *parent_out, + OUT OPTIONAL nfs41_fh *target_out, + OUT OPTIONAL nfs41_file_info *info_out) +{ + struct name_cache_entry *parent, *target; + const char *path_pos = path; + int status; + + AcquireSRWLockShared(&cache->lock); + + if (!name_cache_enabled(cache)) { + status = ERROR_NOT_SUPPORTED; + goto out_unlock; + } + + status = name_cache_lookup(cache, 1, path, path_end, + &path_pos, &parent, &target); + + if (parent_out) copy_fh(parent_out, parent); + if (target_out) copy_fh(target_out, target); + if (info_out && target) copy_attrs(info_out, target->attributes); + +out_unlock: + ReleaseSRWLockShared(&cache->lock); + if (remaining_path_out) *remaining_path_out = path_pos; + return status; +} + +int nfs41_attr_cache_lookup( + IN struct nfs41_name_cache *cache, + IN uint64_t fileid, + OUT nfs41_file_info *info_out) +{ + struct attr_cache_entry *entry; + int status = NO_ERROR; + + dprintf(NCLVL1, "--> nfs41_attr_cache_lookup(%llu)\n", fileid); + + AcquireSRWLockShared(&cache->lock); + + if (!name_cache_enabled(cache)) { + status = ERROR_NOT_SUPPORTED; + goto out_unlock; + } + + entry = attr_cache_search(&cache->attributes, fileid); + if (entry == NULL) { + status = ERROR_FILE_NOT_FOUND; + goto out_unlock; + } + + copy_attrs(info_out, entry); + +out_unlock: + ReleaseSRWLockShared(&cache->lock); + + dprintf(NCLVL1, "<-- nfs41_attr_cache_lookup() returning %d\n", status); + return status; +} + +int nfs41_attr_cache_update( + IN struct nfs41_name_cache *cache, + IN uint64_t fileid, + IN const nfs41_file_info *info) +{ + struct attr_cache_entry *entry; + int status = NO_ERROR; + + dprintf(NCLVL1, "--> nfs41_attr_cache_update(%llu)\n", fileid); + + AcquireSRWLockExclusive(&cache->lock); + + if (!name_cache_enabled(cache)) { + status = ERROR_NOT_SUPPORTED; + goto out_unlock; + } + + entry = attr_cache_search(&cache->attributes, fileid); + if (entry == NULL) { + status = ERROR_FILE_NOT_FOUND; + goto out_unlock; + } + + attr_cache_update(entry, info); + +out_unlock: + ReleaseSRWLockExclusive(&cache->lock); + + dprintf(NCLVL1, "<-- nfs41_attr_cache_update() returning %d\n", status); + return status; +} + +int nfs41_name_cache_insert( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const nfs41_component *name, + IN const nfs41_fh *fh, + IN const nfs41_file_info *info, + IN OPTIONAL const change_info4 *cinfo) +{ + char dbg_path[NFS41_MAX_PATH_LEN]; + struct name_cache_entry *grandparent, *parent, *target; + int status; + + StringCchCopyNA(dbg_path, NFS41_MAX_PATH_LEN, path, + name->name + name->len - path); + dprintf(NCLVL1, "--> nfs41_name_cache_insert('%s')\n", dbg_path); + + AcquireSRWLockExclusive(&cache->lock); + + if (!name_cache_enabled(cache)) { + status = ERROR_NOT_SUPPORTED; + goto out_unlock; + } + + /* an empty path or component implies the root entry */ + if (path == NULL || name == NULL || name->len == 0) { + /* create the root entry if it doesn't exist */ + if (cache->root == NULL) { + const nfs41_component name = { "ROOT", 4 }; + status = name_cache_entry_create(cache, + &name, fh->fileid, &cache->root); + if (status) + goto out_unlock; + } + + name_cache_entry_update(cache, cache->root, fh, info); + status = NO_ERROR; + goto out_unlock; + } + + status = name_cache_lookup(cache, 0, path, name->name, + NULL, &grandparent, &parent); + if (status) + goto out_unlock; + + if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) { + name_cache_entry_invalidate(cache, parent); + goto out_unlock; + } + + status = name_cache_entry_find_or_create(cache, + parent, name, fh->fileid, &target); + if (status) + goto out_unlock; + + name_cache_entry_update(cache, target, fh, info); + +out_unlock: + ReleaseSRWLockExclusive(&cache->lock); + + dprintf(NCLVL1, "<-- nfs41_name_cache_insert() returning %d\n", + status); + return status; +} + +int nfs41_name_cache_remove( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const nfs41_component *name, + IN const change_info4 *cinfo) +{ + struct name_cache_entry *parent, *target; + int status; + + dprintf(NCLVL1, "--> nfs41_name_cache_remove('%s')\n", path); + + AcquireSRWLockExclusive(&cache->lock); + + if (!name_cache_enabled(cache)) { + status = ERROR_NOT_SUPPORTED; + goto out_unlock; + } + + status = name_cache_lookup(cache, 0, path, + name->name + name->len, NULL, &parent, &target); + if (status == ERROR_PATH_NOT_FOUND) + goto out_unlock; + + if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) { + name_cache_entry_invalidate(cache, parent); + goto out_unlock; + } + + if (status == ERROR_FILE_NOT_FOUND) + goto out_unlock; + + target->attributes->numlinks--; + name_cache_unlink(cache, target); + +out_unlock: + ReleaseSRWLockExclusive(&cache->lock); + + dprintf(NCLVL1, "<-- nfs41_name_cache_remove() returning %d\n", status); + return status; +} + +int nfs41_name_cache_rename( + IN struct nfs41_name_cache *cache, + IN const char *src_path, + IN const nfs41_component *src_name, + IN const change_info4 *src_cinfo, + IN const char *dst_path, + IN const nfs41_component *dst_name, + IN const change_info4 *dst_cinfo) +{ + struct name_cache_entry *src_parent, *target; + struct name_cache_entry *dst_parent; + int status = NO_ERROR; + + dprintf(NCLVL1, "--> nfs41_name_cache_rename('%s' to '%s')\n", + src_path, dst_path); + + AcquireSRWLockExclusive(&cache->lock); + + if (!name_cache_enabled(cache)) { + status = ERROR_NOT_SUPPORTED; + goto out_unlock; + } + + /* get src_parent and target */ + status = name_cache_lookup(cache, 0, src_path, + src_name->name + src_name->len, NULL, &src_parent, &target); + if (status) + goto out_unlock; + + /* get dst_parent */ + status = name_cache_lookup(cache, 0, dst_path, + dst_name->name, NULL, NULL, &dst_parent); + if (status) { + status = ERROR_PATH_NOT_FOUND; + goto out_unlock; + } + + if (name_cache_entry_changed(cache, dst_parent, dst_cinfo)) { + name_cache_unlink(cache, target); + name_cache_entry_invalidate(cache, dst_parent); + } else + name_cache_rename(cache, src_parent, target, + dst_parent, dst_name, &target); + + if (dst_parent != src_parent + && name_cache_entry_changed(cache, src_parent, src_cinfo)) + name_cache_entry_invalidate(cache, src_parent); + +out_unlock: + ReleaseSRWLockExclusive(&cache->lock); + + dprintf(NCLVL1, "<-- nfs41_name_cache_rename() returning %d\n", status); + return status; +} + +/* nfs41_name_cache_resolve_fh() */ + +#define MAX_PUTFH_PER_COMPOUND 16 + +static bool_t get_path_fhs( + IN struct nfs41_name_cache *cache, + IN nfs41_abs_path *path, + IN OUT const char **path_pos, + IN uint32_t max_components, + OUT nfs41_path_fh *files, + OUT uint32_t *count) +{ + struct name_cache_entry *target; + const char *path_end = path->path + path->len; + nfs41_component *name; + uint32_t i; + int status; + + *count = 0; + + AcquireSRWLockShared(&cache->lock); + + /* look up the parent of the first component */ + status = name_cache_lookup(cache, 1, path->path, *path_pos, + NULL, NULL, &target); + if (status) + goto out_unlock; + + for (i = 0; i < max_components; i++) { + files[i].path = path; + name = &files[i].name; + + if (!next_component(*path_pos, path_end, name)) + break; + *path_pos = name->name + name->len; + + target = name_cache_search(cache, target, name); + if (target == NULL || entry_has_expired(target)) { + if (is_last_component(name->name, path_end)) + status = ERROR_FILE_NOT_FOUND; + else + status = ERROR_PATH_NOT_FOUND; + goto out_unlock; + } + /* make copies for use outside of cache->lock */ + fh_copy(&files[i].fh, &target->fh); + (*count)++; + } + +out_unlock: + ReleaseSRWLockShared(&cache->lock); + return *count && status == 0; +} + +static int rpc_array_putfh( + IN nfs41_session *session, + IN nfs41_path_fh *files, + IN uint32_t count, + OUT uint32_t *valid_out) +{ + nfs41_compound compound; + nfs_argop4 argops[1+MAX_PUTFH_PER_COMPOUND]; + nfs_resop4 resops[1+MAX_PUTFH_PER_COMPOUND]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args[MAX_PUTFH_PER_COMPOUND]; + nfs41_putfh_res putfh_res[MAX_PUTFH_PER_COMPOUND]; + uint32_t i; + int status; + + *valid_out = 0; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + ZeroMemory(&sequence_res, sizeof(sequence_res)); + ZeroMemory(putfh_res, sizeof(putfh_res)); + + for (i = 0; i < count; i++){ + compound_add_op(&compound, OP_PUTFH, &putfh_args[i], &putfh_res[i]); + putfh_args[i].file = &files[i]; + putfh_args[i].in_recovery = 1; + } + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) goto out; + + status = sequence_res.sr_status; + if (status) goto out; + + for (i = 0; i < count; i++) { + status = putfh_res[i].status; + if (status) break; + } + *valid_out = i; +out: + return status; +} + +static int delete_stale_component( + IN struct nfs41_name_cache *cache, + IN nfs41_session *session, + IN const nfs41_abs_path *path, + IN const nfs41_component *component) +{ + struct name_cache_entry *target; + int status; + + dprintf(NCLVL1, "--> delete_stale_component('%s')\n", + component->name); + + AcquireSRWLockExclusive(&cache->lock); + + status = name_cache_lookup(cache, 0, path->path, + component->name + component->len, NULL, NULL, &target); + if (status == NO_ERROR) + name_cache_unlink(cache, target); + + ReleaseSRWLockExclusive(&cache->lock); + + dprintf(NCLVL1, "<-- delete_stale_component() returning %d\n", status); + return status; +} + +static __inline uint32_t max_putfh_components( + IN const nfs41_session *session) +{ + const uint32_t comps = session->fore_chan_attrs.ca_maxoperations - 1; + return min(comps, MAX_PUTFH_PER_COMPOUND); +} + +int nfs41_name_cache_remove_stale( + IN struct nfs41_name_cache *cache, + IN nfs41_session *session, + IN nfs41_abs_path *path) +{ + nfs41_path_fh files[MAX_PUTFH_PER_COMPOUND]; + const char *path_pos = path->path; + const char* const path_end = path->path + path->len; + const uint32_t max_components = max_putfh_components(session); + uint32_t count, index; + int status = NO_ERROR; + + AcquireSRWLockShared(&cache->lock); + + /* if there's no cache, don't check any components */ + if (!name_cache_enabled(cache)) + path_pos = path_end; + + ReleaseSRWLockShared(&cache->lock); + + /* hold a lock on the path to protect against rename */ + AcquireSRWLockShared(&path->lock); + + while (get_path_fhs(cache, path, &path_pos, max_components, files, &count)) { + status = rpc_array_putfh(session, files, count, &index); + + if (status == NFS4ERR_STALE || status == NFS4ERR_FHEXPIRED) { + status = delete_stale_component(cache, + session, path, &files[index].name); + break; + } + if (status) { + status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); + break; + } + } + + ReleaseSRWLockShared(&path->lock); + + return status; +} \ No newline at end of file diff --git a/daemon/name_cache.h b/daemon/name_cache.h new file mode 100644 index 0000000..ca1a3ec --- /dev/null +++ b/daemon/name_cache.h @@ -0,0 +1,99 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_DAEMON_NAME_CACHE_H__ +#define __NFS41_DAEMON_NAME_CACHE_H__ + +#include "nfs41.h" + + +static __inline struct nfs41_name_cache* client_name_cache( + IN nfs41_client *client) +{ + return client_server(client)->name_cache; +} + +static __inline struct nfs41_name_cache* session_name_cache( + IN nfs41_session *session) +{ + return client_name_cache(session->client); +} + + +/* attribute cache */ +int nfs41_attr_cache_lookup( + IN struct nfs41_name_cache *cache, + IN uint64_t fileid, + OUT nfs41_file_info *info_out); + +int nfs41_attr_cache_update( + IN struct nfs41_name_cache *cache, + IN uint64_t fileid, + IN const nfs41_file_info *info); + + +/* name cache */ +int nfs41_name_cache_create( + OUT struct nfs41_name_cache **cache_out); + +int nfs41_name_cache_free( + IN OUT struct nfs41_name_cache **cache_out); + +int nfs41_name_cache_lookup( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const char *path_end, + OUT OPTIONAL const char **remaining_path_out, + OUT OPTIONAL nfs41_fh *parent_out, + OUT OPTIONAL nfs41_fh *target_out, + OUT OPTIONAL nfs41_file_info *info_out); + +int nfs41_name_cache_insert( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const nfs41_component *name, + IN const nfs41_fh *fh, + IN const nfs41_file_info *info, + IN OPTIONAL const change_info4 *cinfo); + +int nfs41_name_cache_remove( + IN struct nfs41_name_cache *cache, + IN const char *path, + IN const nfs41_component *name, + IN const change_info4 *cinfo); + +int nfs41_name_cache_rename( + IN struct nfs41_name_cache *cache, + IN const char *src_path, + IN const nfs41_component *src_name, + IN const change_info4 *src_cinfo, + IN const char *dst_path, + IN const nfs41_component *dst_name, + IN const change_info4 *dst_cinfo); + +int nfs41_name_cache_remove_stale( + IN struct nfs41_name_cache *cache, + IN nfs41_session *session, + IN nfs41_abs_path *path); + +#endif /* !__NFS41_DAEMON_NAME_CACHE_H__ */ diff --git a/daemon/namespace.c b/daemon/namespace.c new file mode 100644 index 0000000..9ca46d0 --- /dev/null +++ b/daemon/namespace.c @@ -0,0 +1,458 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "nfs41_ops.h" +#include "util.h" +#include "daemon_debug.h" + + +#define NSLVL 2 /* dprintf level for namespace logging */ + + +#define client_entry(pos) list_container(pos, nfs41_client, root_entry) + + +/* nfs41_root */ +int nfs41_root_create( + IN const char *hostname, + IN unsigned short port, + IN const nfs41_abs_path *path, + IN uint32_t wsize, + IN uint32_t rsize, + OUT nfs41_root **root_out) +{ + int status = NO_ERROR; + nfs41_root *root; + + dprintf(NSLVL, "--> nfs41_root_create(%s:%u:%s)\n", + hostname, port, path); + + root = calloc(1, sizeof(nfs41_root)); + if (root == NULL) { + status = GetLastError(); + goto out; + } + + list_init(&root->clients); + root->port = port; + root->wsize = wsize; + root->rsize = rsize; + InitializeCriticalSection(&root->lock); + + /* generate a unique client_owner */ + status = nfs41_client_owner(&root->client_owner); + if (status) { + eprintf("nfs41_client_owner() failed with %d\n", status); + goto out; + } + + *root_out = root; +out: + dprintf(NSLVL, "<-- nfs41_root_create() returning %d\n", status); + return status; +} + +void nfs41_root_free( + IN nfs41_root *root) +{ + struct list_entry *entry, *tmp; + + dprintf(NSLVL, "--> nfs41_root_free()\n"); + + /* free clients */ + list_for_each_tmp(entry, tmp, &root->clients) + nfs41_client_free(client_entry(entry)); + free(root); + + dprintf(NSLVL, "<-- nfs41_root_free()\n"); +} + +/* root_client_find_addrs() */ +struct cl_addr_info { + const multi_addr4 *addrs; + uint32_t roles; +}; + +static int cl_addr_compare( + IN const struct list_entry *entry, + IN const void *value) +{ + nfs41_client *client = client_entry(entry); + const struct cl_addr_info *info = (const struct cl_addr_info*)value; + uint32_t i, roles; + + /* match any of the desired roles */ + AcquireSRWLockShared(&client->exid_lock); + roles = info->roles & client->roles; + ReleaseSRWLockShared(&client->exid_lock); + + if (roles == 0) + return ERROR_FILE_NOT_FOUND; + + /* match any address in 'addrs' with any address in client->rpc->addrs */ + for (i = 0; i < info->addrs->count; i++) + if (multi_addr_find(&client->rpc->addrs, &info->addrs->arr[i], NULL)) + return NO_ERROR; + + return ERROR_FILE_NOT_FOUND; +} + +static int root_client_find_addrs( + IN nfs41_root *root, + IN const multi_addr4 *addrs, + IN bool_t is_data, + OUT nfs41_client **client_out) +{ + struct cl_addr_info info; + struct list_entry *entry; + int status; + + dprintf(NSLVL, "--> root_client_find_addrs()\n"); + + info.addrs = addrs; + info.roles = nfs41_exchange_id_flags(is_data) & EXCHGID4_FLAG_MASK_PNFS; + + entry = list_search(&root->clients, &info, cl_addr_compare); + if (entry) { + *client_out = client_entry(entry); + status = NO_ERROR; + dprintf(NSLVL, "<-- root_client_find_addrs() returning 0x%p\n", + *client_out); + } else { + status = ERROR_FILE_NOT_FOUND; + dprintf(NSLVL, "<-- root_client_find_addrs() failed with %d\n", + status); + } + return status; +} + +/* root_client_find() */ +struct cl_exid_info { + const nfs41_exchange_id_res *exchangeid; + uint32_t roles; +}; + +static int cl_exid_compare( + IN const struct list_entry *entry, + IN const void *value) +{ + nfs41_client *client = client_entry(entry); + const struct cl_exid_info *info = (const struct cl_exid_info*)value; + int status = ERROR_FILE_NOT_FOUND; + + AcquireSRWLockShared(&client->exid_lock); + + /* match any of the desired roles */ + if ((info->roles & client->roles) == 0) + goto out; + /* match clientid */ + if (info->exchangeid->clientid != client->clnt_id) + goto out; + /* match server_owner.major_id */ + if (strncmp(info->exchangeid->server_owner.so_major_id, + client->server->owner, NFS4_OPAQUE_LIMIT) != 0) + goto out; + /* match server_scope */ + if (strncmp(info->exchangeid->server_scope, + client->server->scope, NFS4_OPAQUE_LIMIT) != 0) + goto out; + + status = NO_ERROR; +out: + ReleaseSRWLockShared(&client->exid_lock); + return status; +} + +static int root_client_find( + IN nfs41_root *root, + IN const nfs41_exchange_id_res *exchangeid, + IN bool_t is_data, + OUT nfs41_client **client_out) +{ + struct cl_exid_info info; + struct list_entry *entry; + int status; + + dprintf(NSLVL, "--> root_client_find()\n"); + + info.exchangeid = exchangeid; + info.roles = nfs41_exchange_id_flags(is_data) & EXCHGID4_FLAG_MASK_PNFS; + + entry = list_search(&root->clients, &info, cl_exid_compare); + if (entry) { + *client_out = client_entry(entry); + status = NO_ERROR; + dprintf(NSLVL, "<-- root_client_find() returning 0x%p\n", + *client_out); + } else { + status = ERROR_FILE_NOT_FOUND; + dprintf(NSLVL, "<-- root_client_find() failed with %d\n", + status); + } + return status; +} + +static int session_get_lease( + IN nfs41_session *session, + IN OPTIONAL uint32_t lease_time) +{ + bool_t use_mds_lease; + int status; + + /* http://tools.ietf.org/html/rfc5661#section-13.1.1 + * 13.1.1. Sessions Considerations for Data Servers: + * If the reply to EXCHANGE_ID has just the EXCHGID4_FLAG_USE_PNFS_DS role + * set, then (as noted in Section 13.6) the client will not be able to + * determine the data server's lease_time attribute because GETATTR will + * not be permitted. Instead, the rule is that any time a client + * receives a layout referring it to a data server that returns just the + * EXCHGID4_FLAG_USE_PNFS_DS role, the client MAY assume that the + * lease_time attribute from the metadata server that returned the + * layout applies to the data server. */ + AcquireSRWLockShared(&session->client->exid_lock); + use_mds_lease = session->client->roles == EXCHGID4_FLAG_USE_PNFS_DS; + ReleaseSRWLockShared(&session->client->exid_lock); + + if (!use_mds_lease) { + /* the client is allowed to GETATTR, so query the lease_time */ + nfs41_file_info info = { 0 }; + bitmap4 attr_request = { 1, { FATTR4_WORD0_LEASE_TIME, 0, 0 } }; + + status = nfs41_getattr(session, NULL, &attr_request, &info); + if (status) { + eprintf("nfs41_getattr() failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out; + } + lease_time = info.lease_time; + } + + status = nfs41_session_set_lease(session, lease_time); + if (status) { + eprintf("nfs41_session_set_lease() failed %d\n", status); + goto out; + } +out: + return status; +} + +static int root_client_create( + IN nfs41_root *root, + IN nfs41_rpc_clnt *rpc, + IN bool_t is_data, + IN OPTIONAL uint32_t lease_time, + IN const nfs41_exchange_id_res *exchangeid, + OUT nfs41_client **client_out) +{ + nfs41_client *client; + nfs41_session *session; + int status; + + /* create client (transfers ownership of rpc to client) */ + status = nfs41_client_create(rpc, &root->client_owner, + is_data, exchangeid, &client); + if (status) { + eprintf("nfs41_client_create() failed with %d\n", status); + goto out; + } + rpc->client = client; + + /* create session (and client takes ownership) */ + status = nfs41_session_create(client, &session); + if (status) { + eprintf("nfs41_session_create failed %d\n", status); + goto out_err; + } + + if (!is_data) { + /* send RECLAIM_COMPLETE, but don't fail on ERR_NOTSUPP */ + status = nfs41_reclaim_complete(session); + if (status && status != NFS4ERR_NOTSUPP) { + eprintf("nfs41_reclaim_complete() failed with %s\n", + nfs_error_string(status)); + status = ERROR_BAD_NETPATH; + goto out_err; + } + } + + /* get least time and start session renewal thread */ + status = session_get_lease(session, lease_time); + if (status) + goto out_err; + + *client_out = client; +out: + return status; + +out_err: + nfs41_client_free(client); + goto out; +} + +int nfs41_root_mount_addrs( + IN nfs41_root *root, + IN const multi_addr4 *addrs, + IN bool_t is_data, + IN OPTIONAL uint32_t lease_time, + OUT nfs41_client **client_out) +{ + nfs41_exchange_id_res exchangeid; + nfs41_rpc_clnt *rpc; + nfs41_client *client, *existing; + int status; + + dprintf(NSLVL, "--> nfs41_root_mount_addrs()\n"); + + /* look for an existing client that matches the address and role */ + EnterCriticalSection(&root->lock); + status = root_client_find_addrs(root, addrs, is_data, &client); + LeaveCriticalSection(&root->lock); + + if (status == NO_ERROR) + goto out; + + /* create an rpc client */ + status = nfs41_rpc_clnt_create(addrs, root->wsize, root->rsize, !is_data, &rpc); + if (status) { + eprintf("nfs41_rpc_clnt_create() failed %d\n", status); + goto out; + } + + /* get a clientid with exchangeid */ + ZeroMemory(&exchangeid, sizeof(exchangeid)); + status = nfs41_exchange_id(rpc, &root->client_owner, + nfs41_exchange_id_flags(is_data), &exchangeid); + if (status) { + eprintf("nfs41_exchange_id() failed %s\n", + nfs_error_string(status)); + status = ERROR_BAD_NET_RESP; + goto out_free_rpc; + } + + /* attempt to match existing clients by the exchangeid response */ + EnterCriticalSection(&root->lock); + status = root_client_find(root, &exchangeid, is_data, &client); + LeaveCriticalSection(&root->lock); + + if (status == NO_ERROR) + goto out_free_rpc; + + /* create a client for this clientid */ + status = root_client_create(root, rpc, is_data, + lease_time, &exchangeid, &client); + if (status) { + eprintf("nfs41_client_create() failed %d\n", status); + goto out; + } + + /* because we don't hold the root's lock over session creation, + * we could end up creating multiple clients with the same + * server and roles */ + EnterCriticalSection(&root->lock); + status = root_client_find(root, &exchangeid, is_data, &existing); + + if (status) { + dprintf(NSLVL, "caching new client 0x%p\n", client); + + /* the client is not a duplicate, so add it to the list */ + list_add_tail(&root->clients, &client->root_entry); + status = NO_ERROR; + } else { + dprintf(NSLVL, "created a duplicate client 0x%p! using " + "existing client 0x%p instead\n", client, existing); + + /* a matching client has been created in parallel, so free + * the one we created and use the existing client instead */ + nfs41_client_free(client); + client = existing; + } + LeaveCriticalSection(&root->lock); + +out: + if (status == NO_ERROR) + *client_out = client; + dprintf(NSLVL, "<-- nfs41_root_mount_addrs() returning %d\n", status); + return status; + +out_free_rpc: + nfs41_rpc_clnt_free(rpc); + goto out; +} + + +/* http://tools.ietf.org/html/rfc5661#section-11.9 + * 11.9. The Attribute fs_locations + * An entry in the server array is a UTF-8 string and represents one of a + * traditional DNS host name, IPv4 address, IPv6 address, or a zero-length + * string. An IPv4 or IPv6 address is represented as a universal address + * (see Section 3.3.9 and [15]), minus the netid, and either with or without + * the trailing ".p1.p2" suffix that represents the port number. If the + * suffix is omitted, then the default port, 2049, SHOULD be assumed. A + * zero-length string SHOULD be used to indicate the current address being + * used for the RPC call. */ +static int referral_mount_location( + IN nfs41_root *root, + IN const fs_location4 *loc, + OUT nfs41_client **client_out) +{ + multi_addr4 addrs; + int status = ERROR_BAD_NET_NAME; + uint32_t i; + + /* create a client and session for the first available server */ + for (i = 0; i < loc->server_count; i++) { + /* XXX: only deals with 'address' as a hostname with default port */ + status = nfs41_server_resolve(loc->servers[i].address, 2049, &addrs); + if (status) continue; + + status = nfs41_root_mount_addrs(root, &addrs, 0, 0, client_out); + if (status == NO_ERROR) + break; + } + return status; +} + +int nfs41_root_mount_referral( + IN nfs41_root *root, + IN const fs_locations4 *locations, + OUT const fs_location4 **loc_out, + OUT nfs41_client **client_out) +{ + int status = ERROR_BAD_NET_NAME; + uint32_t i; + + /* establish a mount to the first available location */ + for (i = 0; i < locations->location_count; i++) { + status = referral_mount_location(root, + &locations->locations[i], client_out); + if (status == NO_ERROR) { + *loc_out = &locations->locations[i]; + break; + } + } + return status; +} diff --git a/daemon/nfs41.h b/daemon/nfs41.h new file mode 100644 index 0000000..d385b7c --- /dev/null +++ b/daemon/nfs41.h @@ -0,0 +1,357 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41__ +#define __NFS41__ + +#include "nfs41_types.h" +#include "list.h" + + +struct __nfs41_session; +struct __nfs41_client; +struct __rpc_client; + +typedef struct __nfs41_superblock { + nfs41_fsid fsid; + bitmap4 supported_attrs; + uint64_t maxread; + uint64_t maxwrite; + uint32_t layout_types; + struct list_entry entry; /* position in nfs41_server.superblocks */ + + SRWLOCK lock; +} nfs41_superblock; + +typedef struct __nfs41_superblock_list { + struct list_entry head; + SRWLOCK lock; +} nfs41_superblock_list; + +struct server_addrs { + multi_addr4 addrs; /* list of addrs we've used with this server */ + uint32_t next_index; + SRWLOCK lock; +}; + +typedef struct __nfs41_server { + char scope[NFS4_OPAQUE_LIMIT]; /* server_scope from exchangeid */ + char owner[NFS4_OPAQUE_LIMIT]; /* server_owner.major_id from exchangeid */ + struct server_addrs addrs; + nfs41_superblock_list superblocks; + struct nfs41_name_cache *name_cache; + struct list_entry entry; /* position in global server list */ + LONG ref_count; +} nfs41_server; + +typedef struct __nfs41_lock_state { + bool_t initialized; + stateid4 stateid; + SRWLOCK lock; +} nfs41_lock_state; + +typedef struct __nfs41_open_state { + nfs41_abs_path path; + nfs41_path_fh parent; + nfs41_path_fh file; + struct __nfs41_session *session; + uint32_t type; + bool_t do_close; + stateid4 stateid; + state_owner4 owner; + nfs41_lock_state last_lock; + struct __pnfs_file_layout *layout; + SRWLOCK lock; +} nfs41_open_state; + +typedef struct __nfs41_rpc_clnt { + struct __rpc_client *rpc; + SRWLOCK lock; + HANDLE cond; + struct __nfs41_client *client; + multi_addr4 addrs; + uint32_t addr_index; /* index of addr we're using */ + uint32_t wsize; + uint32_t rsize; + uint32_t version; + bool_t is_valid_session; + bool_t in_recovery; +} nfs41_rpc_clnt; + +typedef struct __nfs41_client { + nfs41_server *server; + client_owner4 owner; + uint64_t clnt_id; + uint32_t seq_id; + uint32_t roles; + SRWLOCK exid_lock; + struct __nfs41_session *session; + SRWLOCK session_lock; + nfs41_rpc_clnt *rpc; + bool_t is_data; + struct pnfs_file_layout_list *layouts; + struct pnfs_file_device_list *devices; + struct list_entry root_entry; /* position in nfs41_root.clients */ + HANDLE cond; + bool_t in_recovery; +} nfs41_client; + +#define NFS41_MAX_NUM_SLOTS NFS41_MAX_RPC_REQS +typedef struct __nfs41_slot_table { + uint32_t seq_nums[NFS41_MAX_NUM_SLOTS]; + uint32_t used_slots[NFS41_MAX_NUM_SLOTS]; + uint32_t max_slots; + uint32_t highest_used; + HANDLE lock; + HANDLE cond; +} nfs41_slot_table; + +typedef struct __nfs41_channel_attrs { + uint32_t ca_headerpadsize; + uint32_t ca_maxrequestsize; + uint32_t ca_maxresponsesize; + uint32_t ca_maxresponsesize_cached; + uint32_t ca_maxoperations; + uint32_t ca_maxrequests; + uint32_t *ca_rdma_ird; +} nfs41_channel_attrs; + +typedef struct __nfs41_cb_session { + unsigned char cb_sessionid[NFS4_SESSIONID_SIZE]; + uint32_t cb_seqnum; + uint32_t cb_slotid; + bool_t cb_is_valid_state; + bool_t cb_cache_this; +} nfs41_cb_session; + +typedef struct __nfs41_session { + nfs41_client *client; + unsigned char session_id[NFS4_SESSIONID_SIZE]; + nfs41_channel_attrs fore_chan_attrs; + nfs41_channel_attrs back_chan_attrs; + uint32_t lease_time; + nfs41_slot_table table; + // array of slots + HANDLE renew_thread; + bool_t isValidState; + uint32_t flags; + nfs41_cb_session cb_session; +} nfs41_session; + +typedef struct __nfs41_root { + client_owner4 client_owner; + CRITICAL_SECTION lock; + struct list_entry clients; + uint32_t wsize; + uint32_t rsize; + unsigned short port; +} nfs41_root; + + +/* nfs41_namespace.c */ +int nfs41_root_create( + IN const char *hostname, + IN unsigned short port, + IN const nfs41_abs_path *path, + IN uint32_t wsize, + IN uint32_t rsize, + OUT nfs41_root **root_out); + +void nfs41_root_free( + IN nfs41_root *root); + +int nfs41_root_mount_addrs( + IN nfs41_root *root, + IN const multi_addr4 *addrs, + IN bool_t is_data, + IN OPTIONAL uint32_t lease_time, + OUT nfs41_client **client_out); + +int nfs41_root_mount_server( + IN nfs41_root *root, + IN nfs41_server *server, + IN bool_t is_data, + IN OPTIONAL uint32_t lease_time, + OUT nfs41_client **client_out); + +int nfs41_root_mount_referral( + IN nfs41_root *root, + IN const fs_locations4 *locations, + OUT const fs_location4 **loc_out, + OUT nfs41_client **client_out); + +static __inline nfs41_session* nfs41_root_session( + IN nfs41_root *root) +{ + nfs41_client *client; + /* return a session for the server at the root of the namespace. + * because we created it on mount, it's the first one in the list */ + EnterCriticalSection(&root->lock); + client = list_container(root->clients.next, nfs41_client, root_entry); + LeaveCriticalSection(&root->lock); + return client->session; +} + + +/* nfs41_session.c */ +int nfs41_session_create( + IN nfs41_client *client, + IN nfs41_session **session_out); + +int nfs41_session_renew( + IN nfs41_session *session); + +int nfs41_session_set_lease( + IN nfs41_session *session, + IN uint32_t lease_time); + +void nfs41_session_free( + IN nfs41_session *session); + +int nfs41_session_bump_seq( + IN nfs41_session *session, + IN uint32_t slotid); + +int nfs41_session_free_slot( + IN nfs41_session *session, + IN uint32_t slotid); + +int nfs41_session_get_slot( + IN nfs41_session *session, + OUT uint32_t *slot, + OUT uint32_t *seq, + OUT uint32_t *highest); + +struct __nfs41_sequence_args; +int nfs41_session_sequence( + struct __nfs41_sequence_args *args, + nfs41_session *session, + bool_t cachethis); + + +/* nfs41_server.c */ +void nfs41_server_list_init(); + +int nfs41_server_resolve( + IN const char *hostname, + IN unsigned short port, + OUT multi_addr4 *addrs); + +int nfs41_server_find_or_create( + IN const char *server_owner_major_id, + IN const char *server_scope, + IN const netaddr4 *addr, + OUT nfs41_server **server_out); + +void nfs41_server_ref( + IN nfs41_server *server); + +void nfs41_server_deref( + IN nfs41_server *server); + +void nfs41_server_addrs( + IN nfs41_server *server, + OUT multi_addr4 *addrs); + + +/* nfs41_client.c */ +int nfs41_client_owner( + OUT client_owner4 *owner); + +uint32_t nfs41_exchange_id_flags( + IN bool_t is_data); + +struct __nfs41_exchange_id_res; + +int nfs41_client_create( + IN nfs41_rpc_clnt *rpc, + IN const client_owner4 *owner, + IN bool_t is_data, + IN const struct __nfs41_exchange_id_res *exchangeid, + OUT nfs41_client **client_out); + +int nfs41_client_renew( + IN nfs41_client *client); + +void nfs41_client_free( + IN nfs41_client *client); + +static __inline nfs41_server* client_server( + IN nfs41_client *client) +{ + /* the client's server could change during nfs41_client_renew(), + * so access to client->server must be protected */ + nfs41_server *server; + AcquireSRWLockShared(&client->exid_lock); + server = client->server; + ReleaseSRWLockShared(&client->exid_lock); + return server; +} + + +/* nfs41_superblock.c */ +int nfs41_superblock_for_fh( + IN nfs41_session *session, + IN const nfs41_fsid *fsid, + IN const nfs41_fh *parent OPTIONAL, + OUT nfs41_path_fh *file); + +void nfs41_superblock_list_init( + IN nfs41_superblock_list *superblocks); + +void nfs41_superblock_list_free( + IN nfs41_superblock_list *superblocks); + + +/* nfs41_rpc.c */ +int nfs41_rpc_clnt_create( + IN const multi_addr4 *addrs, + IN uint32_t wsize, + IN uint32_t rsize, + IN bool_t needcb, + OUT nfs41_rpc_clnt **rpc_out); + +void nfs41_rpc_clnt_free( + IN nfs41_rpc_clnt *rpc); + +int nfs41_send_compound( + IN nfs41_rpc_clnt *rpc, + IN char *inbuf, + OUT char *outbuf); + +static __inline netaddr4* nfs41_rpc_netaddr( + IN nfs41_rpc_clnt *rpc) +{ + uint32_t id; + AcquireSRWLockShared(&rpc->lock); + /* only addr_index needs to be protected, as rpc->addrs is write-once */ + id = rpc->addr_index; + ReleaseSRWLockShared(&rpc->lock); + + /* return the netaddr used to create the rpc client */ + return &rpc->addrs.arr[id]; +} + +bool_t nfs41_renew_in_progress(nfs41_client *client, bool_t *value); + +#endif /* __NFS41__ */ diff --git a/daemon/nfs41_callback.h b/daemon/nfs41_callback.h new file mode 100644 index 0000000..becabb5 --- /dev/null +++ b/daemon/nfs41_callback.h @@ -0,0 +1,254 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_CALLBACK_H__ +#define __NFS41_CALLBACK_H__ + +//#include "nfs41.h" +#include "wintirpc.h" +#include "rpc/rpc.h" +#include "nfs41_types.h" + + +enum nfs41_callback_proc { + CB_NULL = 0, + CB_COMPOUND = 1, +}; + +enum nfs41_callback_op { + OP_CB_GETATTR = 3, + OP_CB_RECALL = 4, + OP_CB_LAYOUTRECALL = 5, + OP_CB_NOTIFY = 6, + OP_CB_PUSH_DELEG = 7, + OP_CB_RECALL_ANY = 8, + OP_CB_RECALLABLE_OBJ_AVAIL = 9, + OP_CB_RECALL_SLOT = 10, + OP_CB_SEQUENCE = 11, + OP_CB_WANTS_CANCELLED = 12, + OP_CB_NOTIFY_LOCK = 13, + OP_CB_NOTIFY_DEVICEID = 14, + OP_CB_ILLEGAL = 10044 +}; + +int nfs41_handle_callback(void *, void *, void *); + +/* OP_CB_LAYOUTRECALL */ +struct cb_recall_file { + nfs41_fh fh; + uint64_t offset; + uint64_t length; + stateid4 stateid; +}; +union cb_recall_file_args { + struct cb_recall_file file; + nfs41_fsid fsid; +}; +struct cb_recall { + enum pnfs_return_type type; + union cb_recall_file_args args; +}; +struct cb_layoutrecall_args { + enum pnfs_layout_type type; + enum pnfs_iomode iomode; + bool_t changed; + struct cb_recall recall; +}; + +struct cb_layoutrecall_res { + enum_t status; +}; + +/* OP_CB_RECALL_SLOT */ +struct cb_recall_slot_args { + uint32_t target_highest_slotid; +}; + +struct cb_recall_slot_res { + enum_t status; +}; + +/* OP_CB_SEQUENCE */ +struct cb_sequence_ref { + uint32_t sequenceid; + uint32_t slotid; +}; +struct cb_sequence_ref_list { + char sessionid[NFS4_SESSIONID_SIZE]; + struct cb_sequence_ref *calls; + uint32_t call_count; +}; +struct cb_sequence_args { + char sessionid[NFS4_SESSIONID_SIZE]; + uint32_t sequenceid; + uint32_t slotid; + uint32_t highest_slotid; + bool_t cachethis; + struct cb_sequence_ref_list *ref_lists; + uint32_t ref_list_count; +}; + +struct cb_sequence_res_ok { + char sessionid[NFS4_SESSIONID_SIZE]; + uint32_t sequenceid; + uint32_t slotid; + uint32_t highest_slotid; + uint32_t target_highest_slotid; +}; +struct cb_sequence_res { + enum_t status; + struct cb_sequence_res_ok ok; +}; + +/* OP_CB_GETATTR */ +struct cb_getattr_args { + uint32_t target_highest_slotid; +}; + +struct cb_getattr_res { + enum_t status; +}; + +/* OP_CB_RECALL */ +struct cb_recall_args { + stateid4 stateid; + bool_t truncate; + nfs41_fh fh; +}; + +struct cb_recall_res { + enum_t status; +}; + +/* OP_CB_NOTIFY */ +struct cb_notify_args { + uint32_t target_highest_slotid; +}; + +struct cb_notify_res { + enum_t status; +}; + +/* OP_CB_PUSH_DELEG */ +struct cb_push_deleg_args { + uint32_t target_highest_slotid; +}; + +struct cb_push_deleg_res { + enum_t status; +}; + +/* OP_CB_RECALL_ANY */ +struct cb_recall_any_args { + uint32_t target_highest_slotid; +}; + +struct cb_recall_any_res { + enum_t status; +}; + +/* OP_CB_RECALLABLE_OBJ_AVAIL */ +struct cb_recallable_obj_avail_args { + uint32_t target_highest_slotid; +}; + +struct cb_recallable_obj_avail_res { + enum_t status; +}; + +/* OP_CB_WANTS_CANCELLED */ +struct cb_wants_cancelled_args { + uint32_t target_highest_slotid; +}; + +struct cb_wants_cancelled_res { + enum_t status; +}; + +/* OP_CB_NOTIFY_LOCK */ +struct cb_notify_lock_args { + uint32_t target_highest_slotid; +}; + +struct cb_notify_lock_res { + enum_t status; +}; + +/* OP_CB_NOTIFY_DEVICEID */ +struct cb_notify_deviceid_args { + uint32_t target_highest_slotid; +}; + +struct cb_notify_deviceid_res { + enum_t status; +}; + +/* CB_COMPOUND */ +#define CB_COMPOUND_MAX_TAG 64 +#define CB_COMPOUND_MAX_OPERATIONS 16 + +union cb_op_args { + struct cb_layoutrecall_args layoutrecall; + struct cb_recall_slot_args recall_slot; + struct cb_sequence_args sequence; + struct cb_recall_args recall; +}; +struct cb_argop { + enum_t opnum; + union cb_op_args args; +}; +struct cb_compound_tag { + char str[CB_COMPOUND_MAX_TAG]; + uint32_t len; +}; +struct cb_compound_args { + struct cb_compound_tag tag; + uint32_t minorversion; + uint32_t callback_ident; /* client MUST ignore */ + struct cb_argop *argarray; + uint32_t argarray_count; /* <= CB_COMPOUND_MAX_OPERATIONS */ +}; + +union cb_op_res { + struct cb_layoutrecall_res layoutrecall; + struct cb_recall_slot_res recall_slot; + struct cb_sequence_res sequence; + struct cb_recall_res recall; +}; +struct cb_resop { + enum_t opnum; + union cb_op_res res; +}; +struct cb_compound_res { + enum_t status; + struct cb_compound_tag tag; + struct cb_resop *resarray; + uint32_t resarray_count; /* <= CB_COMPOUND_MAX_OPERATIONS */ +}; + + + +/* callback_xdr.c */ +bool_t proc_cb_compound_args(XDR *xdr, struct cb_compound_args *args); +bool_t proc_cb_compound_res(XDR *xdr, struct cb_compound_res *res); +#endif /* !__NFS41_CALLBACK_H__ */ diff --git a/daemon/nfs41_client.c b/daemon/nfs41_client.c new file mode 100644 index 0000000..87ea2e6 --- /dev/null +++ b/daemon/nfs41_client.c @@ -0,0 +1,437 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include +#include /* for GetAdaptersAddresses() */ + +#include "rbtree.h" +#include "daemon_debug.h" +#include "nfs41_ops.h" + + +uint32_t nfs41_exchange_id_flags( + IN bool_t is_data) +{ + uint32_t flags = EXCHGID4_FLAG_SUPP_MOVED_REFER; + if (is_data) + flags |= EXCHGID4_FLAG_USE_PNFS_DS; + else + flags |= EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS; + return flags; +} + +static int pnfs_client_init( + IN nfs41_client *client) +{ + enum pnfs_status pnfsstat; + int status = NO_ERROR; + + /* initialize the pnfs layout and device lists for metadata clients */ + pnfsstat = pnfs_file_layout_list_create(&client->layouts); + if (pnfsstat) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto out; + } + pnfsstat = pnfs_file_device_list_create(&client->devices); + if (pnfsstat) { + status = ERROR_NOT_ENOUGH_MEMORY; + goto out_err_layouts; + } +out: + return status; + +out_err_layouts: + pnfs_file_layout_list_free(client->layouts); + client->layouts = NULL; + goto out; +} + +static void update_server( + IN nfs41_client *client, + IN const char *server_scope, + IN const server_owner4 *owner) +{ + nfs41_server *server; + int status; + + /* find a server matching the owner.major_id and scope */ + status = nfs41_server_find_or_create(owner->so_major_id, + server_scope, nfs41_rpc_netaddr(client->rpc), &server); + + if (status == NO_ERROR) { + /* if the server is the same, we now have an extra reference. if + * the servers are different, we still need to deref the old server. + * so both cases can be treated the same */ + if (client->server) + nfs41_server_deref(client->server); + client->server = server; + } +} + +static void update_exchangeid_res( + IN nfs41_client *client, + IN const nfs41_exchange_id_res *exchangeid) +{ + update_server(client, exchangeid->server_scope, &exchangeid->server_owner); + client->clnt_id = exchangeid->clientid; + client->seq_id = exchangeid->sequenceid; + client->roles = exchangeid->flags & EXCHGID4_FLAG_MASK_PNFS; +} + +int nfs41_client_create( + IN nfs41_rpc_clnt *rpc, + IN const client_owner4 *owner, + IN bool_t is_data, + IN const nfs41_exchange_id_res *exchangeid, + OUT nfs41_client **client_out) +{ + int status; + nfs41_client *client; + + client = calloc(1, sizeof(nfs41_client)); + if (client == NULL) { + status = GetLastError(); + goto out_err_rpc; + } + + client->cond = CreateEvent(NULL, TRUE, FALSE, "client_recovery_cond"); + if (client->cond == NULL) { + status = GetLastError(); + eprintf("CreateEvent failed %d\n", status); + goto out_err_rpc; + } + + memcpy(&client->owner, owner, sizeof(client_owner4)); + client->rpc = rpc; + client->is_data = is_data; + update_exchangeid_res(client, exchangeid); + + //initialize a lock used to protect access to client id and client id seq# + InitializeSRWLock(&client->exid_lock); + + status = pnfs_client_init(client); + if (status) { + eprintf("pnfs_client_init() failed with %d\n", status); + goto out_err_client; + } + *client_out = client; +out: + return status; +out_err_client: + nfs41_client_free(client); /* also calls nfs41_rpc_clnt_free() */ + goto out; +out_err_rpc: + nfs41_rpc_clnt_free(rpc); + goto out; +} + +static void dprint_roles( + IN int level, + IN uint32_t roles) +{ + dprintf(level, "roles: %s%s%s\n", + (roles & EXCHGID4_FLAG_USE_NON_PNFS) ? "USE_NON_PNFS " : "", + (roles & EXCHGID4_FLAG_USE_PNFS_MDS) ? "USE_PNFS_MDS " : "", + (roles & EXCHGID4_FLAG_USE_PNFS_DS) ? "USE_PNFS_DS" : ""); +} + +int nfs41_client_renew( + IN nfs41_client *client) +{ + nfs41_exchange_id_res exchangeid; + int status; + + ZeroMemory(&exchangeid, sizeof(exchangeid)); + + status = nfs41_exchange_id(client->rpc, &client->owner, + nfs41_exchange_id_flags(client->is_data), &exchangeid); + if (status) { + eprintf("nfs41_exchange_id() failed with %d\n", status); + status = ERROR_BAD_NET_RESP; + goto out; + } + + if (client->is_data) { /* require USE_PNFS_DS */ + if ((exchangeid.flags & EXCHGID4_FLAG_USE_PNFS_DS) == 0) { + eprintf("client expected USE_PNFS_DS\n"); + status = ERROR_BAD_NET_RESP; + goto out; + } + } else { /* require USE_NON_PNFS or USE_PNFS_MDS */ + if ((exchangeid.flags & EXCHGID4_FLAG_USE_NON_PNFS) == 0 && + (exchangeid.flags & EXCHGID4_FLAG_USE_PNFS_MDS) == 0) { + eprintf("client expected USE_NON_PNFS OR USE_PNFS_MDS\n"); + status = ERROR_BAD_NET_RESP; + goto out; + } + } + + dprint_roles(2, exchangeid.flags); + + AcquireSRWLockExclusive(&client->exid_lock); + update_exchangeid_res(client, &exchangeid); + ReleaseSRWLockExclusive(&client->exid_lock); +out: + return status; +} + +bool_t nfs41_renew_in_progress(nfs41_client *client, bool_t *value) +{ + bool_t status = FALSE; + if (value) { + dprintf(1, "nfs41_renew_in_progress: setting value %d\n", *value); + AcquireSRWLockExclusive(&client->exid_lock); + client->in_recovery = *value; + if (!client->in_recovery) + SetEvent(client->cond); + ReleaseSRWLockExclusive(&client->exid_lock); + } else { + AcquireSRWLockShared(&client->exid_lock); + status = client->in_recovery; + ReleaseSRWLockShared(&client->exid_lock); + dprintf(1, "nfs41_renew_in_progress: returning value %d\n", status); + } + return status; +} + +void nfs41_client_free( + IN nfs41_client *client) +{ + dprintf(2, "nfs41_client_free(%llu)\n", client->clnt_id); + if (client->session) nfs41_session_free(client->session); + if (client->server) nfs41_server_deref(client->server); + nfs41_rpc_clnt_free(client->rpc); + if (client->layouts) pnfs_file_layout_list_free(client->layouts); + if (client->devices) pnfs_file_device_list_free(client->devices); + CloseHandle(client->cond); + free(client); +} + + +/* client_owner generation + * we choose to use MAC addresses to generate a client_owner value that + * is unique to a machine and persists over restarts. because the client + * can have multiple network adapters/addresses, we take each adapter into + * account. the specification suggests that "for privacy reasons, it is + * best to perform some one-way function," so we apply an md5 hash to the + * sorted list of MAC addresses */ + +/* References: + * RFC 5661: 2.4. Client Identifiers and Client Owners + * http://tools.ietf.org/html/rfc5661#section-2.4 + * + * MSDN: GetAdaptersAddresses Function + * http://msdn.microsoft.com/en-us/library/aa365915%28VS.85%29.aspx + * + * MSDN: Example C Program: Creating an MD5 Hash from File Content + * http://msdn.microsoft.com/en-us/library/aa382380%28VS.85%29.aspx */ + + +/* use an rbtree to sort mac address entries */ +struct mac_entry { + struct rb_node rbnode; + PBYTE address; + ULONG length; +}; + +static void mac_entry_insert( + IN struct rb_root *root, + IN PBYTE address, + IN ULONG length) +{ + struct rb_node **node, *prev; + struct mac_entry *entry; + int diff; + + node = &root->rb_node; + prev = NULL; + + while (*node) { + entry = rb_entry(*node, struct mac_entry, rbnode); + prev = *node; + + diff = length - entry->length; + if (diff == 0) + diff = memcmp(address, entry->address, length); + + if (diff < 0) + node = &(*node)->rb_left; + else if (diff > 0) + node = &(*node)->rb_right; + else + return; + } + + entry = calloc(1, sizeof(struct mac_entry)); + if (entry) { + entry->address = address; + entry->length = length; + + rb_link_node(&entry->rbnode, prev, node); + rb_insert_color(&entry->rbnode, root); + } +} + +static int adapter_valid( + IN const IP_ADAPTER_ADDRESSES *addr) +{ + /* ignore generic interfaces whose address is not unique */ + switch (addr->IfType) { + case IF_TYPE_SOFTWARE_LOOPBACK: + case IF_TYPE_TUNNEL: + return 0; + } + /* must have an address */ + if (addr->PhysicalAddressLength == 0) + return 0; + /* must support ip */ + return addr->Ipv4Enabled || addr->Ipv6Enabled; +} + +static DWORD hash_mac_addrs( + IN HCRYPTHASH hash) +{ + PIP_ADAPTER_ADDRESSES addr, addrs = NULL; + struct rb_root rbtree = { NULL }; + struct rb_node *node; + struct mac_entry *entry; + ULONG len; + DWORD status; + + /* start with enough room for DEFAULT_MINIMUM_ENTITIES */ + len = DEFAULT_MINIMUM_ENTITIES * sizeof(IP_ADAPTER_ADDRESSES); + + do { + PIP_ADAPTER_ADDRESSES tmp; + /* reallocate the buffer until we can fit all of it */ + tmp = realloc(addrs, len); + if (tmp == NULL) { + status = GetLastError(); + goto out; + } + addrs = tmp; + status = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME | + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_UNICAST, + NULL, addrs, &len); + } while (status == ERROR_BUFFER_OVERFLOW); + + if (status) { + eprintf("GetAdaptersAddresses() failed with %d\n", status); + goto out; + } + + /* get the mac address of each adapter */ + for (addr = addrs; addr; addr = addr->Next) + if (adapter_valid(addr)) + mac_entry_insert(&rbtree, addr->PhysicalAddress, + addr->PhysicalAddressLength); + + /* require at least one valid address */ + node = rb_first(&rbtree); + if (node == NULL) { + status = ERROR_FILE_NOT_FOUND; + eprintf("GetAdaptersAddresses() did not return " + "any valid mac addresses, failing with %d.\n", status); + goto out; + } + + while (node) { + entry = rb_entry(node, struct mac_entry, rbnode); + node = rb_next(node); + rb_erase(&entry->rbnode, &rbtree); + + if (!CryptHashData(hash, entry->address, entry->length, 0)) { + status = GetLastError(); + eprintf("CryptHashData() failed with %d\n", status); + /* don't break here, we need to free the rest */ + } + free(entry); + } +out: + free(addrs); + return status; +} + +int nfs41_client_owner( + OUT client_owner4 *owner) +{ + HCRYPTPROV context; + HCRYPTHASH hash; + PBYTE buffer; + DWORD length; + const time_t time_created = time(NULL); + int status; + + /* owner.verifier = "time created" */ + ZeroMemory(owner->co_verifier, sizeof(owner->co_verifier)); + memcpy(owner->co_verifier, &time_created, sizeof(time_created)); + + /* set up the md5 hash generator */ + if (!CryptAcquireContext(&context, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + status = GetLastError(); + eprintf("CryptAcquireContext() failed with %d\n", status); + goto out; + } + if (!CryptCreateHash(context, CALG_MD5, 0, 0, &hash)) { + status = GetLastError(); + eprintf("CryptCreateHash() failed with %d\n", status); + goto out_context; + } + + /* add the mac address from each applicable adapter to the hash */ + status = hash_mac_addrs(hash); + if (status) { + eprintf("hash_mac_addrs() failed with %d\n", status); + goto out_hash; + } + + /* extract the hash size (should always be 16 for md5) */ + buffer = (PBYTE)&owner->co_ownerid_len; + length = (DWORD)sizeof(DWORD); + if (!CryptGetHashParam(hash, HP_HASHSIZE, buffer, &length, 0)) { + status = GetLastError(); + eprintf("CryptGetHashParam(size) failed with %d\n", status); + goto out_hash; + } + /* extract the hash buffer */ + buffer = owner->co_ownerid; + length = owner->co_ownerid_len; + if (!CryptGetHashParam(hash, HP_HASHVAL, buffer, &length, 0)) { + status = GetLastError(); + eprintf("CryptGetHashParam(val) failed with %d\n", status); + goto out_hash; + } + +out_hash: + CryptDestroyHash(hash); +out_context: + CryptReleaseContext(context, 0); +out: + return status; +} diff --git a/daemon/nfs41_compound.c b/daemon/nfs41_compound.c new file mode 100644 index 0000000..15fe128 --- /dev/null +++ b/daemon/nfs41_compound.c @@ -0,0 +1,333 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "nfs41_compound.h" +#include "nfs41_xdr.h" +#include "nfs41_ops.h" +#include "name_cache.h" +#include "daemon_debug.h" + +#define BUF_SIZE 1024 + + +int compound_error(int status) +{ + if (status != NFS4_OK) + dprintf(1, "COMPOUND failed with status %d.\n", status); + return status; +} + +static void compound_args_init( + nfs41_compound_args *compound, + nfs_argop4 *argarray) +{ + compound->tag_len = 8; + memcpy(compound->tag, "ms-nfs41", 8); + compound->minorversion = 1; + compound->argarray_count = 0; + compound->argarray = argarray; +} + +static void compound_args_add_op( + nfs41_compound_args *compound, + uint32_t opnum, + void *arg) +{ + const uint32_t i = compound->argarray_count++; + compound->argarray[i].op = opnum; + compound->argarray[i].arg = arg; +} + +static void compound_res_init( + nfs41_compound_res *compound, + nfs_resop4 *resarray) +{ + ZeroMemory(compound, sizeof(nfs41_compound_res)); + compound->tag_len = NFS4_OPAQUE_LIMIT; + compound->resarray_count = 0; + compound->resarray = resarray; +} + +static void compound_res_add_op( + nfs41_compound_res *compound, + void *res) +{ + compound->resarray[compound->resarray_count++].res = res; +} + +void compound_init( + nfs41_compound *compound, + nfs_argop4 *argops, + nfs_resop4 *resops) +{ + compound_args_init(&compound->args, argops); + compound_res_init(&compound->res, resops); +} + +void compound_add_op( + nfs41_compound *compound, + uint32_t opnum, + void *arg, + void *res) +{ + compound_args_add_op(&compound->args, opnum, arg); + compound_res_add_op(&compound->res, res); +} + +/* Due to the possibility of replays, we might get a response to a different + * call than the one we're expecting. If we don't have a way to check for + * this, we'll likely crash trying to decode into the wrong structures. + * This function copies the number of operations and all of the operation + * numbers from the compound arguments into the response, so we can verify + * them on decode and fail before doing any damage. */ +static void set_expected_res( + nfs41_compound *compound) +{ + uint32_t i; + compound->res.resarray_count = compound->args.argarray_count; + for (i = 0; i < compound->res.resarray_count; i++) + compound->res.resarray[i].op = compound->args.argarray[i].op; +} + +int check_renew_in_progress( + IN nfs41_session *session) +{ + int status = 0; + bool_t one = 1, zero = 0;; + while (nfs41_renew_in_progress(session->client, NULL)) { + status = WaitForSingleObject(session->client->cond, INFINITE); + if (status != WAIT_OBJECT_0) { + dprintf(1, "nfs41_renew_in_progress: WaitForSingleObject failed\n"); + print_condwait_status(1, status); + status = ERROR_LOCK_VIOLATION; + goto out; + } + nfs41_renew_in_progress(session->client, &zero); + status = 1; + } + nfs41_renew_in_progress(session->client, &one); +out: + return status; +} +int compound_encode_send_decode( + nfs41_session *session, + nfs41_compound *compound, + uint32_t bufsize_in, + uint32_t bufsize_out) +{ + int status, retry_count = 0, delayby = 0; + nfs41_sequence_args *args = + (nfs41_sequence_args *)compound->args.argarray[0].arg; + bool_t zero = 0; + +retry: + /* send compound */ + retry_count++; + set_expected_res(compound); + status = nfs41_send_compound(session->client->rpc, + (char *)&compound->args, (char *)&compound->res); + + if (status) { + eprintf("nfs41_send_compound failed %d for seqid=%d, slotid=%d\n", + status, args->sa_sequenceid, args->sa_slotid); + status = NFS4ERR_IO; + goto out_free_slot; + } else { + // bump sequence number if sequence op succeeded + if (compound->res.resarray_count > 0 && + compound->res.resarray[0].op == OP_SEQUENCE) { + nfs41_sequence_res *seq = + (nfs41_sequence_res *)compound->res.resarray[0].res; + if (seq->sr_status == NFS4_OK) { + // returned slotid must be the same we sent + status = NFS4ERR_IO; + if (seq->sr_resok4.sr_slotid != args->sa_slotid) { + eprintf("[session] sr_slotid=%d != sa_slotid=%d\n", + seq->sr_resok4.sr_slotid, args->sa_slotid); + goto out_free_slot; + } + // returned sessionid must be the same we sent + if (memcmp(seq->sr_resok4.sr_sessionid, args->sa_sessionid, + NFS4_SESSIONID_SIZE)) { + eprintf("[session] sr_sessionid != sa_sessionid\n"); + print_hexbuf(1, (unsigned char *)"sr_sessionid", + seq->sr_resok4.sr_sessionid, NFS4_SESSIONID_SIZE); + print_hexbuf(1, (unsigned char *)"sa_sessionid", + args->sa_sessionid, NFS4_SESSIONID_SIZE); + goto out_free_slot; + } + if (seq->sr_resok4.sr_status_flags) + print_sr_status_flags(1, seq->sr_resok4.sr_status_flags); + + status = nfs41_session_bump_seq(session, args->sa_slotid); + if (status) + goto out_free_slot; + } + } + } + + if (compound->res.status != NFS4_OK) + dprintf(1, "\n################ %s ################\n\n", + nfs_error_string(compound->res.status)); + if (compound->res.status != NFS4_OK && + compound->args.argarray[0].op == OP_DESTROY_SESSION) { + dprintf(1, "OP_DESTROY_SESSION ignoring errors\n"); + compound->res.status = NFS4_OK; + } + + switch (compound->res.status) { + case NFS4_OK: + break; + + case NFS4ERR_STALE_CLIENTID: + //try to create a new client + status = check_renew_in_progress(session); + if (status == ERROR_LOCK_VIOLATION) + goto out_free_slot; + else if (status == 1) + goto do_retry; + status = nfs41_client_renew(session->client); + if (status) { + eprintf("nfs41_exchange_id() failed with %d\n", status); + status = ERROR_BAD_NET_RESP; + goto out; + } + //fallthru and reestablish the session + case NFS4ERR_BADSESSION: + //try to create a new session + if (compound->res.status == NFS4ERR_BADSESSION) { + status = check_renew_in_progress(session); + if (status == ERROR_LOCK_VIOLATION) + goto out_free_slot; + else if (status == 1) + goto do_retry; + } + status = nfs41_session_renew(session); + if (status == NFS4ERR_STALE_CLIENTID) { + status = nfs41_client_renew(session->client); + if (status) { + eprintf("nfs41_exchange_id() failed with %d\n", status); + status = ERROR_BAD_NET_RESP; + goto out; + } + status = nfs41_session_renew(session); + if (status) { + eprintf("after reestablishing clientid: nfs41_session_renew() " + "failed with %d\n", status); + status = ERROR_BAD_NET_RESP; + goto out; + } + } else if (status && status != NFS4ERR_STALE_CLIENTID) { + eprintf("nfs41_session_renew: failed with %d\n", status); + goto out; + } + if (nfs41_renew_in_progress(session->client, NULL)) + nfs41_renew_in_progress(session->client, &zero); + goto do_retry; + + case NFS4ERR_GRACE: + case NFS4ERR_DELAY: +#define RETRY_INDEFINITELY +#ifndef RETRY_INDEFINITELY +#define NUMBER_2_RETRY 19 +#endif + +#ifndef RETRY_INDEFINITELY + if (retry_count < NUMBER_2_RETRY) { +#endif + if (compound->args.argarray[0].op == OP_SEQUENCE) { + nfs41_sequence_args *seq = (nfs41_sequence_args*) + compound->args.argarray[0].arg; + nfs41_session_free_slot(session, seq->sa_slotid); + } + if (compound->res.status == NFS4ERR_GRACE) + delayby = 5000; + else + delayby = 500*retry_count; + dprintf(1, "Compound returned %s: sleeping for %ums..\n", + (compound->res.status==NFS4ERR_GRACE)?"NFS4ERR_GRACE":"NFS4ERR_DELAY", + delayby); + Sleep(delayby); + dprintf(1, "Attempting to resend compound.\n"); + goto do_retry; +#ifndef RETRY_INDEFINITELY + } +#endif + break; + + case NFS4ERR_FHEXPIRED: /* TODO: recover expired volatile filehandles */ + status = NFS4ERR_STALE; /* for now, treat them as ERR_STALE */ + /* no break */ + case NFS4ERR_STALE: + { + nfs_argop4 *argarray = compound->args.argarray; + struct nfs41_name_cache *name_cache = + session_name_cache(session); + nfs41_putfh_args *putfh; + uint32_t i, start = 0; + + /* NFS4ERR_STALE generally comes from a PUTFH operation. in + * this case, remove its filehandle from the name cache. but + * because COMPOUNDs are not atomic, a file can be removed + * between PUTFH and the operation that uses it. in this + * case, we can't tell which PUTFH operation is to blame, so + * we must invalidate filehandles of all PUTFH operations in + * the COMPOUND */ + + if (argarray[compound->res.resarray_count-1].op == OP_PUTFH) + start = compound->res.resarray_count-1; + + for (i = start; i < compound->res.resarray_count; i++) { + if (argarray[i].op == OP_PUTFH) { + putfh = (nfs41_putfh_args*)argarray[i].arg; + + if (!putfh->in_recovery) + nfs41_name_cache_remove_stale(name_cache, + session, putfh->file->path); + } + } + } + break; + } +out_free_slot: + if (compound->args.argarray[0].op == OP_SEQUENCE) { + nfs41_sequence_args *seq = (nfs41_sequence_args *)compound->args.argarray[0].arg; + nfs41_session_free_slot(session, seq->sa_slotid); + } +out: + return status; + +do_retry: + if (compound->res.resarray[0].op == OP_SEQUENCE) { + nfs41_sequence_args *seq = (nfs41_sequence_args*) + compound->args.argarray[0].arg; + status = nfs41_session_get_slot(session, &seq->sa_slotid, + &seq->sa_sequenceid, &seq->sa_highest_slotid); + if (status) + goto out; + } + goto retry; +} diff --git a/daemon/nfs41_compound.h b/daemon/nfs41_compound.h new file mode 100644 index 0000000..b8c3377 --- /dev/null +++ b/daemon/nfs41_compound.h @@ -0,0 +1,82 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_DAEMON_COMPOUND_H__ +#define __NFS41_DAEMON_COMPOUND_H__ + +#include "nfs41.h" + + +/* COMPOUND */ +typedef struct __nfs_argop4 { + uint32_t op; + void *arg; +} nfs_argop4; + +typedef struct __nfs41_compound_args { + uint32_t tag_len; + unsigned char tag[NFS4_OPAQUE_LIMIT]; + uint32_t minorversion; + uint32_t argarray_count; + nfs_argop4 *argarray; /* <> */ +} nfs41_compound_args; + +typedef struct __nfs_resop4 { + uint32_t op; + void *res; +} nfs_resop4; + +typedef struct __nfs41_compound_res { + uint32_t status; + uint32_t tag_len; + unsigned char tag[NFS4_OPAQUE_LIMIT]; + uint32_t resarray_count; + nfs_resop4 *resarray; /* <> */ +} nfs41_compound_res; + +typedef struct __nfs41_compound { + nfs41_compound_args args; + nfs41_compound_res res; +} nfs41_compound; + + +int compound_error(int status); + +void compound_init( + nfs41_compound *compound, + nfs_argop4 *argops, + nfs_resop4 *resops); + +void compound_add_op( + nfs41_compound *compound, + uint32_t opnum, + void *arg, + void *res); + +int compound_encode_send_decode( + nfs41_session *session, + nfs41_compound *compound, + uint32_t bufsize_in, + uint32_t bufsize_out); + +#endif /* __NFS41_DAEMON_COMPOUND_H__ */ diff --git a/daemon/nfs41_const.h b/daemon/nfs41_const.h new file mode 100644 index 0000000..0201269 --- /dev/null +++ b/daemon/nfs41_const.h @@ -0,0 +1,306 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_NFS_CONST_H__ +#define __NFS41_NFS_CONST_H__ + + +/* + * Sizes + */ +#define NFS4_FHSIZE 128 +#define NFS4_VERIFIER_SIZE 8 +#define NFS4_OPAQUE_LIMIT 1024 +#define NFS4_SESSIONID_SIZE 16 + +#define NFS41_MAX_FILEIO_SIZE (1024 * 1024) +#define NFS41_MAX_SERVER_CACHE 1024 +#define NFS41_MAX_RPC_REQS 128 + +#define NFS41_MAX_COMPONENT_SIZE 64 + +#define UPCALL_BUF_SIZE 1024 + +/* see MaximumComponentNameLength in FileFsAttributeInformation + * in nfs41_driver.c:nfs41_QueryVolumeInformation() */ +#define NFS41_MAX_COMPONENT_LEN 64 +#define NFS41_MAX_PATH_LEN MAX_PATH + +#define NFS41_HOSTNAME_LEN 64 +#define NFS41_ADDRS_PER_SERVER 4 + +/* max length of ipv6 address 48 + * sizeof(".255.255") + 8 */ +#define NFS41_UNIVERSAL_ADDR_LEN 56 + +/* "udp" "tcp" "udp6" "tcp6" */ +#define NFS41_NETWORK_ID_LEN 4 + + +/* 424 bytes: max rpc header for reply with data */ +/* 32 bytes: max COMPOUND response */ +/* 40 bytes: max SEQUENCE response */ +/* 4 bytes: max PUTFH response */ +/* 12 bytes: max READ response */ +#define READ_OVERHEAD 512 + +/* 840 bytes: max rpc header for call */ +/* 32 bytes: max COMPOUND request */ +/* 32 bytes: max SEQUENCE request */ +/* 132 bytes: max PUTFH request */ +/* 32 bytes: max WRITE request */ +#define WRITE_OVERHEAD 1068 + + +#define NFS41_RPC_PROGRAM 100003 +#define NFS41_RPC_VERSION 4 +#define NFS41_RPC_CBPROGRAM 0x2358 + + +/* + * Error status + */ +enum nfsstat4 { + NFS4_OK = 0, /* everything is okay */ + NFS4ERR_PERM = 1, /* caller not privileged */ + NFS4ERR_NOENT = 2, /* no such file/directory */ + NFS4ERR_IO = 5, /* hard I/O error */ + NFS4ERR_NXIO = 6, /* no such device */ + NFS4ERR_ACCESS = 13, /* access denied */ + NFS4ERR_EXIST = 17, /* file already exists */ + NFS4ERR_XDEV = 18, /* different filesystems */ + + NFS4ERR_NOTDIR = 20, /* should be a directory */ + NFS4ERR_ISDIR = 21, /* should not be directory */ + NFS4ERR_INVAL = 22, /* invalid argument */ + NFS4ERR_FBIG = 27, /* file exceeds server max */ + NFS4ERR_NOSPC = 28, /* no space on filesystem */ + NFS4ERR_ROFS = 30, /* read-only filesystem */ + NFS4ERR_MLINK = 31, /* too many hard links */ + NFS4ERR_NAMETOOLONG = 63, /* name exceeds server max */ + NFS4ERR_NOTEMPTY = 66, /* directory not empty */ + NFS4ERR_DQUOT = 69, /* hard quota limit reached*/ + NFS4ERR_STALE = 70, /* file no longer exists */ + NFS4ERR_BADHANDLE = 10001, /* Illegal filehandle */ + NFS4ERR_BAD_COOKIE = 10003, /* READDIR cookie is stale */ + NFS4ERR_NOTSUPP = 10004, /* operation not supported */ + NFS4ERR_TOOSMALL = 10005, /* response limit exceeded */ + NFS4ERR_SERVERFAULT = 10006, /* undefined server error */ + NFS4ERR_BADTYPE = 10007, /* type invalid for CREATE */ + NFS4ERR_DELAY = 10008, /* file "busy" - retry */ + NFS4ERR_SAME = 10009, /* nverify says attrs same */ + NFS4ERR_DENIED = 10010, /* lock unavailable */ + NFS4ERR_EXPIRED = 10011, /* lock lease expired */ + NFS4ERR_LOCKED = 10012, /* I/O failed due to lock */ + NFS4ERR_GRACE = 10013, /* in grace period */ + NFS4ERR_FHEXPIRED = 10014, /* filehandle expired */ + NFS4ERR_SHARE_DENIED = 10015, /* share reserve denied */ + NFS4ERR_WRONGSEC = 10016, /* wrong security flavor */ + NFS4ERR_CLID_INUSE = 10017, /* clientid in use */ + + /* NFS4ERR_RESOURCE is not a valid error in NFSv4.1 */ + NFS4ERR_RESOURCE = 10018, /* resource exhaustion */ + NFS4ERR_MOVED = 10019, /* filesystem relocated */ + NFS4ERR_NOFILEHANDLE = 10020, /* current FH is not set */ + NFS4ERR_MINOR_VERS_MISMATCH = 10021, /* minor vers not supp */ + NFS4ERR_STALE_CLIENTID = 10022, /* server has rebooted */ + NFS4ERR_STALE_STATEID = 10023, /* server has rebooted */ + NFS4ERR_OLD_STATEID = 10024, /* state is out of sync */ + NFS4ERR_BAD_STATEID = 10025, /* incorrect stateid */ + NFS4ERR_BAD_SEQID = 10026, /* request is out of seq. */ + NFS4ERR_NOT_SAME = 10027, /* verify - attrs not same */ + NFS4ERR_LOCK_RANGE = 10028, /* overlapping lock range */ + NFS4ERR_SYMLINK = 10029, /* should be file/directory*/ + NFS4ERR_RESTOREFH = 10030, /* no saved filehandle */ + NFS4ERR_LEASE_MOVED = 10031, /* some filesystem moved */ + NFS4ERR_ATTRNOTSUPP = 10032, /* recommended attr not sup*/ + NFS4ERR_NO_GRACE = 10033, /* reclaim outside of grace*/ + NFS4ERR_RECLAIM_BAD = 10034, /* reclaim error at server */ + NFS4ERR_RECLAIM_CONFLICT = 10035, /* conflict on reclaim */ + NFS4ERR_BADXDR = 10036, /* XDR decode failed */ + NFS4ERR_LOCKS_HELD = 10037, /* file locks held at CLOSE*/ + NFS4ERR_OPENMODE = 10038, /* conflict in OPEN and I/O*/ + NFS4ERR_BADOWNER = 10039, /* owner translation bad */ + NFS4ERR_BADCHAR = 10040, /* utf-8 char not supported*/ + NFS4ERR_BADNAME = 10041, /* name not supported */ + NFS4ERR_BAD_RANGE = 10042, /* lock range not supported*/ + NFS4ERR_LOCK_NOTSUPP = 10043, /* no atomic up/downgrade */ + NFS4ERR_OP_ILLEGAL = 10044, /* undefined operation */ + NFS4ERR_DEADLOCK = 10045, /* file locking deadlock */ + NFS4ERR_FILE_OPEN = 10046, /* open file blocks op. */ + NFS4ERR_ADMIN_REVOKED = 10047, /* lockowner state revoked */ + NFS4ERR_CB_PATH_DOWN = 10048, /* callback path down */ + + /* NFSv4.1 errors start here. */ + NFS4ERR_BADIOMODE = 10049, + NFS4ERR_BADLAYOUT = 10050, + NFS4ERR_BAD_SESSION_DIGEST = 10051, + NFS4ERR_BADSESSION = 10052, + NFS4ERR_BADSLOT = 10053, + NFS4ERR_COMPLETE_ALREADY = 10054, + NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055, + NFS4ERR_DELEG_ALREADY_WANTED = 10056, + NFS4ERR_BACK_CHAN_BUSY = 10057, /*backchan reqs outstanding*/ + NFS4ERR_LAYOUTTRYLATER = 10058, + NFS4ERR_LAYOUTUNAVAILABLE = 10059, + NFS4ERR_NOMATCHING_LAYOUT = 10060, + NFS4ERR_RECALLCONFLICT = 10061, + NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062, + NFS4ERR_SEQ_MISORDERED = 10063, /* unexpected seq.ID in req*/ + NFS4ERR_SEQUENCE_POS = 10064, /* [CB_]SEQ. op not 1st op */ + NFS4ERR_REQ_TOO_BIG = 10065, /* request too big */ + NFS4ERR_REP_TOO_BIG = 10066, /* reply too big */ + NFS4ERR_REP_TOO_BIG_TO_CACHE = 10067, /* rep. not all cached */ + NFS4ERR_RETRY_UNCACHED_REP = 10068, /* retry & rep. uncached */ + NFS4ERR_UNSAFE_COMPOUND = 10069, /* retry/recovery too hard */ + NFS4ERR_TOO_MANY_OPS = 10070, /*too many ops in [CB_]COMP*/ + NFS4ERR_OP_NOT_IN_SESSION = 10071, /* op needs [CB_]SEQ. op */ + NFS4ERR_HASH_ALG_UNSUPP = 10072, /* hash alg. not supp. */ + /* Error 10073 is unused. */ + NFS4ERR_CLIENTID_BUSY = 10074, /* clientid has state */ + NFS4ERR_PNFS_IO_HOLE = 10075, /* IO to _SPARSE file hole */ + NFS4ERR_SEQ_FALSE_RETRY = 10076, /* Retry != original req. */ + NFS4ERR_BAD_HIGH_SLOT = 10077, /* req has bad highest_slot*/ + NFS4ERR_DEADSESSION = 10078, /*new req sent to dead sess*/ + NFS4ERR_ENCR_ALG_UNSUPP = 10079, /* encr alg. not supp. */ + NFS4ERR_PNFS_NO_LAYOUT = 10080, /* I/O without a layout */ + NFS4ERR_NOT_ONLY_OP = 10081, /* addl ops not allowed */ + NFS4ERR_WRONG_CRED = 10082, /* op done by wrong cred */ + NFS4ERR_WRONG_TYPE = 10083, /* op on wrong type object */ + NFS4ERR_DIRDELEG_UNAVAIL = 10084, /* delegation not avail. */ + NFS4ERR_REJECT_DELEG = 10085, /* cb rejected delegation */ + NFS4ERR_RETURNCONFLICT = 10086, /* layout get before return*/ + NFS4ERR_DELEG_REVOKED = 10087 /* deleg./layout revoked */ +}; + +#define MAKE_WORD0(XXX) (1 << XXX) +#define MAKE_WORD1(XXX) (1 << (XXX-32)) +#define MAKE_WORD2(XXX) (1 << (XXX-64)) + +enum { +/* + * Mandatory Attributes + */ + FATTR4_WORD0_SUPPORTED_ATTRS = MAKE_WORD0(0), + FATTR4_WORD0_TYPE = MAKE_WORD0(1), + FATTR4_WORD0_FH_EXPIRE_TYPE = MAKE_WORD0(2), + FATTR4_WORD0_CHANGE = MAKE_WORD0(3), + FATTR4_WORD0_SIZE = MAKE_WORD0(4), + FATTR4_WORD0_LINK_SUPPORT = MAKE_WORD0(5), + FATTR4_WORD0_SYMLINK_SUPPORT = MAKE_WORD0(6), + FATTR4_WORD0_NAMED_ATTR = MAKE_WORD0(7), + FATTR4_WORD0_FSID = MAKE_WORD0(8), + FATTR4_WORD0_UNIQUE_HANDLES = MAKE_WORD0(9), + FATTR4_WORD0_LEASE_TIME = MAKE_WORD0(10), + FATTR4_WORD0_RDATTR_ERROR = MAKE_WORD0(11), + FATTR4_WORD0_FILEHANDLE = MAKE_WORD0(19), + FATTR4_WORD2_SUPPATTR_EXCLCREAT = MAKE_WORD2(75), + +/* + * Recommended Attributes + */ + FATTR4_WORD0_ACL = MAKE_WORD0(12), + FATTR4_WORD0_ACLSUPPORT = MAKE_WORD0(13), + FATTR4_WORD0_ARCHIVE = MAKE_WORD0(14), + FATTR4_WORD0_CANSETTIME = MAKE_WORD0(15), + FATTR4_WORD0_CASE_INSENSITIVE = MAKE_WORD0(16), + FATTR4_WORD0_CASE_PRESERVING = MAKE_WORD0(17), + FATTR4_WORD0_CHOWN_RESTRICTED = MAKE_WORD0(18), + FATTR4_WORD0_FILEID = MAKE_WORD0(20), + FATTR4_WORD0_FILES_AVAIL = MAKE_WORD0(21), + FATTR4_WORD0_FILES_FREE = MAKE_WORD0(22), + FATTR4_WORD0_FILES_TOTAL = MAKE_WORD0(23), + FATTR4_WORD0_FS_LOCATIONS = MAKE_WORD0(24), + FATTR4_WORD0_HIDDEN = MAKE_WORD0(25), + FATTR4_WORD0_HOMOGENEOUS = MAKE_WORD0(26), + FATTR4_WORD0_MAXFILESIZE = MAKE_WORD0(27), + FATTR4_WORD0_MAXLINK = MAKE_WORD0(28), + FATTR4_WORD0_MAXNAME = MAKE_WORD0(29), + FATTR4_WORD0_MAXREAD = MAKE_WORD0(30), + FATTR4_WORD0_MAXWRITE = MAKE_WORD0(31), + FATTR4_WORD1_MIMETYPE = MAKE_WORD1(32), + FATTR4_WORD1_MODE = MAKE_WORD1(33), + FATTR4_WORD1_NO_TRUNC = MAKE_WORD1(34), + FATTR4_WORD1_NUMLINKS = MAKE_WORD1(35), + FATTR4_WORD1_OWNER = MAKE_WORD1(36), + FATTR4_WORD1_OWNER_GROUP = MAKE_WORD1(37), + FATTR4_WORD1_QUOTA_AVAIL_HARD = MAKE_WORD1(38), + FATTR4_WORD1_QUOTA_AVAIL_SOFT = MAKE_WORD1(39), + FATTR4_WORD1_QUOTA_USED = MAKE_WORD1(40), + FATTR4_WORD1_RAWDEV = MAKE_WORD1(41), + FATTR4_WORD1_SPACE_AVAIL = MAKE_WORD1(42), + FATTR4_WORD1_SPACE_FREE = MAKE_WORD1(43), + FATTR4_WORD1_SPACE_TOTAL = MAKE_WORD1(44), + FATTR4_WORD1_SPACE_USED = MAKE_WORD1(45), + FATTR4_WORD1_SYSTEM = MAKE_WORD1(46), + FATTR4_WORD1_TIME_ACCESS = MAKE_WORD1(47), + FATTR4_WORD1_TIME_ACCESS_SET = MAKE_WORD1(48), + FATTR4_WORD1_TIME_BACKUP = MAKE_WORD1(49), + FATTR4_WORD1_TIME_CREATE = MAKE_WORD1(50), + FATTR4_WORD1_TIME_DELTA = MAKE_WORD1(51), + FATTR4_WORD1_TIME_METADATA = MAKE_WORD1(52), + FATTR4_WORD1_TIME_MODIFY = MAKE_WORD1(53), + FATTR4_WORD1_TIME_MODIFY_SET = MAKE_WORD1(54), + FATTR4_WORD1_MOUNTED_ON_FILEID = MAKE_WORD1(55), + FATTR4_WORD1_DIR_NOTIF_DELAY = MAKE_WORD1(56), + FATTR4_WORD1_DIRENT_NOTIF_DELAY = MAKE_WORD1(57), + FATTR4_WORD1_DACL = MAKE_WORD1(58), + FATTR4_WORD1_SACL = MAKE_WORD1(59), + FATTR4_WORD1_CHANGE_POLICY = MAKE_WORD1(60), + FATTR4_WORD1_FS_STATUS = MAKE_WORD1(61), + FATTR4_WORD1_FS_LAYOUT_TYPE = MAKE_WORD1(62), + FATTR4_WORD1_LAYOUT_HINT = MAKE_WORD1(63), + FATTR4_WORD2_LAYOUT_TYPE = MAKE_WORD2(64), + FATTR4_WORD2_LAYOUT_BLKSIZE = MAKE_WORD2(65), + FATTR4_WORD2_LAYOUT_ALIGNMENT = MAKE_WORD2(66), + FATTR4_WORD2_FS_LOCATIONS_INFO = MAKE_WORD2(67), + FATTR4_WORD2_MDSTHRESHOLD = MAKE_WORD2(68), + FATTR4_WORD2_RETENTION_GET = MAKE_WORD2(69), + FATTR4_WORD2_RETENTION_SET = MAKE_WORD2(70), + FATTR4_WORD2_RETENTEVT_GET = MAKE_WORD2(71), + FATTR4_WORD2_RETENTEVT_SET = MAKE_WORD2(72), + FATTR4_WORD2_RETENTION_HOLD = MAKE_WORD2(73), + FATTR4_WORD2_MODE_SET_MASKED = MAKE_WORD2(74), + FATTR4_WORD2_FS_CHARSET_CAP = MAKE_WORD2(76), +}; + +/* + * File types + */ +enum nfs_ftype4 { + NF4REG = 1, /* Regular File */ + NF4DIR = 2, /* Directory */ + NF4BLK = 3, /* Special File - block device */ + NF4CHR = 4, /* Special File - character device */ + NF4LNK = 5, /* Symbolic Link */ + NF4SOCK = 6, /* Special File - socket */ + NF4FIFO = 7, /* Special File - fifo */ + NF4ATTRDIR = 8, /* Attribute Directory */ + NF4NAMEDATTR = 9, /* Named Attribute */ + + NFS_FTYPE_MASK = 0xF +}; + +#define CREATE_SESSION4_FLAG_CONN_BACK_CHAN 0x00000002; + +#endif /* !__NFS41_NFS_CONST_H__ */ diff --git a/daemon/nfs41_daemon.c b/daemon/nfs41_daemon.c new file mode 100644 index 0000000..26da5f5 --- /dev/null +++ b/daemon/nfs41_daemon.c @@ -0,0 +1,217 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include + +#include + +#include "nfs41_driver.h" /* for NFS41_USER_DEVICE_NAME_A */ +#include "nfs41_np.h" /* for NFS41NP_SHARED_MEMORY */ + +#include "daemon_debug.h" +#include "upcall.h" +#include "util.h" + + +#define MAX_NUM_THREADS 128 +BOOLEAN CREATED_SESSION = FALSE; + +typedef struct _nfs41_process_thread { + HANDLE handle; + uint32_t tid; +} nfs41_process_thread; + +DWORD InitSharedMemory( + OUT PHANDLE phMutex) +{ + DWORD status = NO_ERROR; + + *phMutex = CreateMutex(NULL, FALSE, TEXT(NFS41NP_MUTEX_NAME)); + if (*phMutex == NULL) { + status = GetLastError(); + eprintf("CreateMutex failed with %d\n", status); + } + return status; +} + +static unsigned int WINAPI thread_main(void *args) +{ + DWORD status = 0; + HANDLE pipe; + // buffer used to process upcall, assumed to be fixed size. + // if we ever need to handle non-cached IO, need to make it dynamic + unsigned char outbuf[UPCALL_BUF_SIZE]; + // buffer used to send downcall content, need to dynamically allocated + // as we don't know the length of the buffer (ie. size of directory listing + unsigned char *inbuf = NULL; + DWORD inbuf_len, outbuf_len; + nfs41_upcall upcall; + + pipe = CreateFile(NFS41_USER_DEVICE_NAME_A, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + 0, NULL); + if (pipe == INVALID_HANDLE_VALUE) + { + eprintf("Unable to open upcall pipe %d\n", GetLastError()); + return GetLastError(); + } + + while(1) { + status = DeviceIoControl(pipe, IOCTL_NFS41_READ, NULL, 0, + outbuf, UPCALL_BUF_SIZE, (LPDWORD)&outbuf_len, NULL); + if (!status) { + eprintf("IOCTL_NFS41_READ failed %d\n", GetLastError()); + continue; + } + + status = upcall_parse(outbuf, (uint32_t)outbuf_len, &upcall); + if (status) + goto write_downcall; + +#if 1 //AGLO: this is just a placeholder for a real solution. I know this variable needs a lock in a + //normal case. However, this does not prevent us from receiving an upcall for an old mount + //that was not reestablished. It will only work for erroring requests until the 1st mount upcall. + if (!CREATED_SESSION && (upcall.opcode != NFS41_MOUNT && upcall.opcode != NFS41_SHUTDOWN)) { + eprintf("nfs41_daemon restarted and does not have a valid session established\n"); + upcall.status = 116; + goto write_downcall; + } +#endif + + if (upcall.opcode == NFS41_SHUTDOWN) { + printf("Shutting down..\n"); + exit(0); + } + + status = upcall_handle(&upcall); + +#if 1 //AGLO: place holder for a real solution + if (upcall.opcode == NFS41_MOUNT && upcall.status == NO_ERROR) + CREATED_SESSION = 1; +#endif + +write_downcall: + dprintf(1, "writing downcall: xid=%d opcode=%s status=%d " + "get_last_error=%d\n", upcall.xid, opcode2string(upcall.opcode), + upcall.status, upcall.last_error); + + if (upcall.opcode == NFS41_DIR_QUERY) + inbuf_len = UPCALL_BUF_SIZE + upcall.args.readdir.query_reply_len; + else + inbuf_len = UPCALL_BUF_SIZE; + + inbuf = malloc(inbuf_len); + status = upcall_marshall(&upcall, inbuf, (uint32_t)inbuf_len, (uint32_t*)&outbuf_len); + + dprintf(2, "making a downcall: outbuf_len %ld\n", outbuf_len); + status = DeviceIoControl(pipe, IOCTL_NFS41_WRITE, + inbuf, inbuf_len, NULL, 0, (LPDWORD)&outbuf_len, NULL); + free(inbuf); + if (!status) { + eprintf("IOCTL_NFS41_WRITE failed with %d xid=%d opcode=%s\n", + GetLastError(), upcall.xid, opcode2string(upcall.opcode)); + status = upcall_cancel(&upcall); + continue; + } + dprintf(3, "downcall returned %d\n", status); + printf("\n"); + } + CloseHandle(pipe); + + return GetLastError(); +} + +void __cdecl _tmain(int argc, TCHAR *argv[]) +{ + DWORD status = 0, len; + // handles related to shared memory + HANDLE hSharedMemoryMutex; + // handle to our drivers + HANDLE pipe; + nfs41_process_thread tids[MAX_NUM_THREADS]; + int i; + + if (argc > 2) { + const char *process = strip_path(argv[0], NULL); + printf("Usage: %s [#debug level]\n", process); + } else if (argc == 2) { + set_debug_level(_ttoi(argv[1])); + } + +#ifdef _DEBUG + /* dump memory leaks to stderr on exit; this requires the debug heap, + /* available only when built in debug mode under visual studio -cbodley */ + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + dprintf(1, "debug mode. dumping memory leaks to stderr on exit.\n"); +#endif + + nfs41_server_list_init(); + + pipe = CreateFile(NFS41_USER_DEVICE_NAME_A, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + 0, NULL); + if (pipe == INVALID_HANDLE_VALUE) + { + eprintf("Unable to open upcall pipe %d\n", GetLastError()); + return; + } + + status = InitSharedMemory(&hSharedMemoryMutex); + if (status) + goto quit_pipe; + + dprintf(1, "starting nfs41 mini redirector\n"); + status = DeviceIoControl(pipe, IOCTL_NFS41_START, + NULL, 0, NULL, 0, (LPDWORD)&len, NULL); + if (!status) { + eprintf("IOCTL_NFS41_START failed with %d\n", + GetLastError()); + goto quit; + } + + for (i = 0; i < MAX_NUM_THREADS; i++) { + tids[i].handle = (HANDLE)_beginthreadex(NULL, 0, thread_main, + NULL, 0, &tids[i].tid); + if (tids[i].handle == INVALID_HANDLE_VALUE) { + status = GetLastError(); + eprintf("_beginthreadex failed %d\n", status); + goto quit_pipe; + } + } + //This can be changed to waiting on an array of handles and using waitformultipleobjects + dprintf(1, "Parent waiting for children threads\n"); + for (i = 0; i < MAX_NUM_THREADS; i++) + WaitForSingleObject(tids[i].handle, INFINITE ); + dprintf(1, "Parent woke up!!!!\n"); + +quit: + CloseHandle(hSharedMemoryMutex); +quit_pipe: + CloseHandle(pipe); + return; +} diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c new file mode 100644 index 0000000..4815859 --- /dev/null +++ b/daemon/nfs41_ops.c @@ -0,0 +1,1745 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include + +#include "nfs41_ops.h" +#include "nfs41_compound.h" +#include "nfs41_xdr.h" +#include "name_cache.h" +#include "daemon_debug.h" +#include "util.h" + +#define BUF_SIZE 1024 + + +int nfs41_exchange_id( + IN nfs41_rpc_clnt *rpc, + IN client_owner4 *owner, + IN uint32_t flags_in, + OUT nfs41_exchange_id_res *res_out) +{ + int status = 0; + nfs41_exchange_id_args ex_id; + + nfs41_compound_args compound_args; + nfs_argop4 argop; + nfs41_compound_res compound_res; + nfs_resop4 resop; + + /* set compound_args.tag, compound_args.tag_len */ + compound_args.tag_len = 8; + memcpy(compound_args.tag, "ms-nfs41", 8); + compound_args.minorversion = 1; + compound_args.argarray_count = 1; + compound_args.argarray = &argop; + argop.op = OP_EXCHANGE_ID; + argop.arg = &ex_id; + + compound_res.resarray_count = 1; + compound_res.resarray = &resop; + compound_res.resarray[0].op = compound_args.argarray[0].op; + resop.res = res_out; + + ex_id.eia_clientowner = owner; + ex_id.eia_flags = flags_in; + ex_id.eia_state_protect.spa_how = SP4_NONE; + ex_id.eia_client_impl_id = NULL; + + res_out->server_owner.so_major_id_len = NFS4_OPAQUE_LIMIT; + res_out->server_scope_len = NFS4_OPAQUE_LIMIT; + status = nfs41_send_compound(rpc, (char *)&compound_args, + (char *)&compound_res); + if (status) + goto out; + + compound_error(status = compound_res.status); +out: + return status; +} + +// AGLO: 10/07/2009 we might want lookup these values from the registry +static int set_fore_channel_attrs( + IN nfs41_rpc_clnt *rpc, + IN uint32_t max_req, + OUT nfs41_channel_attrs *attrs) +{ + attrs->ca_headerpadsize = 0; + attrs->ca_maxrequestsize = rpc->wsize; + attrs->ca_maxresponsesize = rpc->rsize; + attrs->ca_maxresponsesize_cached = NFS41_MAX_SERVER_CACHE; + attrs->ca_maxoperations = 0xffffffff; + attrs->ca_maxrequests = max_req; + attrs->ca_rdma_ird = NULL; + return 0; +} + +// AGLO: 10/07/2009 we might want lookup these values from the registry +static int set_back_channel_attrs( + IN nfs41_rpc_clnt *rpc, + IN uint32_t max_req, + OUT nfs41_channel_attrs *attrs) +{ + attrs->ca_headerpadsize = 0; + attrs->ca_maxrequestsize = rpc->wsize; + attrs->ca_maxresponsesize = rpc->rsize; + attrs->ca_maxresponsesize_cached = 0; + attrs->ca_maxoperations = 0xffffffff; + attrs->ca_maxrequests = max_req; + attrs->ca_rdma_ird = NULL; + return 0; +} + +int nfs41_create_session(nfs41_client *clnt, nfs41_session *session) +{ + int status = 0; + nfs41_create_session_args req; + nfs41_create_session_res reply; + + nfs41_compound_args compound_args; + nfs_argop4 argop; + nfs41_compound_res compound_res; + nfs_resop4 resop; + + dprintf(2, "nfs41_create_session begin\n"); + /* set compound_args.tag, compound_args.tag_len */ + compound_args.tag_len = 8; + memcpy(compound_args.tag, "ms-nfs41", 8); + compound_args.minorversion = 1; + compound_args.argarray_count = 1; + compound_args.argarray = &argop; + argop.op = OP_CREATE_SESSION; + argop.arg = &req; + + compound_res.resarray_count = 1; + compound_res.resarray = &resop; + resop.res = &reply; + + ZeroMemory(&req, sizeof(req)); + AcquireSRWLockShared(&clnt->exid_lock); + req.csa_clientid = clnt->clnt_id; + req.csa_sequence = clnt->seq_id; + ReleaseSRWLockShared(&clnt->exid_lock); + req.csa_flags = session->flags; + req.csa_cb_program = NFS41_RPC_CBPROGRAM; + + // ca_maxrequests should be gotten from the rpc layer + set_fore_channel_attrs(clnt->rpc, + NFS41_MAX_RPC_REQS, &req.csa_fore_chan_attrs); + set_back_channel_attrs(clnt->rpc, + 1, &req.csa_back_chan_attrs); + + ZeroMemory(&reply, sizeof(nfs41_create_session_res)); + reply.csr_sessionid = session->session_id; + reply.csr_fore_chan_attrs = &session->fore_chan_attrs; + reply.csr_back_chan_attrs = &session->back_chan_attrs; + compound_res.resarray[0].op = compound_args.argarray[0].op; + + status = nfs41_send_compound(clnt->rpc, (char *)&compound_args, + (char *)&compound_res); + if (status) + goto out; + + if (compound_error(status = compound_res.status)) + goto out; + + print_hexbuf(1, (unsigned char *)"session id: ", session->session_id, NFS4_SESSIONID_SIZE); + // check that csa_sequence is same as csr_sequence + if (reply.csr_sequence != clnt->seq_id) { + eprintf("ERROR: CREATE_SESSION: csa_sequence %d != " + "csr_sequence %d\n", clnt->seq_id, reply.csr_sequence); + status = NFS4ERR_SEQ_MISORDERED; + goto out; + } else clnt->seq_id++; + + if (reply.csr_flags != req.csa_flags) + eprintf("WARNING: requested session flags %x received %x\n", + req.csa_flags, reply.csr_flags); + else + dprintf(1, "session flags %x\n", reply.csr_flags); + + dprintf(1, "session fore_chan_attrs:\n" + " %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n %-32s%d\n", + "headerpadsize", session->fore_chan_attrs.ca_headerpadsize, + "maxrequestsize", session->fore_chan_attrs.ca_maxrequestsize, + "maxresponsesize", session->fore_chan_attrs.ca_maxresponsesize, + "maxresponsesize_cached", session->fore_chan_attrs.ca_maxresponsesize_cached, + "maxoperations", session->fore_chan_attrs.ca_maxoperations, + "maxrequests", session->fore_chan_attrs.ca_maxrequests); + dprintf(1, "client supports %d max rpc slots, but server has %d\n", + session->table.max_slots, session->fore_chan_attrs.ca_maxrequests); + /* use the server's ca_maxrequests unless it's bigger than our array */ + session->table.max_slots = min(session->table.max_slots, + session->fore_chan_attrs.ca_maxrequests); + status = 0; +out: + return status; +} + +enum nfsstat4 nfs41_bind_conn_to_session( + IN nfs41_rpc_clnt *rpc, + IN const unsigned char *sessionid, + IN enum channel_dir_from_client4 dir) +{ + int status; + nfs41_compound compound; + nfs41_compound_args *compound_args = &compound.args; + nfs41_compound_res *compound_res = &compound.res; + nfs_argop4 argop; + nfs_resop4 resop; + nfs41_bind_conn_to_session_args bind_args; + nfs41_bind_conn_to_session_res bind_res; + + compound_init(&compound, &argop, &resop); + + compound_add_op(&compound, OP_BIND_CONN_TO_SESSION, &bind_args, &bind_res); + bind_args.sessionid = (unsigned char *)sessionid; + bind_args.dir = dir; + ZeroMemory(&bind_res, sizeof(bind_res)); + + status = nfs41_send_compound(rpc, + (char*)&compound_args, (char*)&compound_res); + if (status) + goto out; + + compound_error(status = compound.res.status); + +out: + return status; +} + +int nfs41_destroy_session( + IN nfs41_session *session) +{ + int status; + nfs41_compound compound; + nfs_argop4 argop; + nfs_resop4 resop; + nfs41_destroy_session_args ds_args; + nfs41_destroy_session_res ds_res; + + compound_init(&compound, &argop, &resop); + + compound_add_op(&compound, OP_DESTROY_SESSION, &ds_args, &ds_res); + ds_args.dsa_sessionid = session->session_id; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + status = compound.res.status; + if (status) + eprintf("%s failed with status %d.\n", + nfs_opnum_to_string(OP_DESTROY_SESSION), status); +out: + return status; +} + +enum nfsstat4 nfs41_reclaim_complete( + IN nfs41_session *session) +{ + enum nfsstat4 status = NFS4_OK; + nfs41_compound compound; + nfs_argop4 argops[2]; + nfs_resop4 resops[2]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_reclaim_complete_res reclaim_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_RECLAIM_COMPLETE, NULL, &reclaim_res); + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +int nfs41_open( + IN nfs41_session *session, + IN uint32_t allow, + IN uint32_t deny, + IN uint32_t create, + IN uint32_t mode, + IN OUT nfs41_open_state *state, + OUT nfs41_file_info *info) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[8]; + nfs_resop4 resops[8]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_op_open_args open_args; + nfs41_op_open_res open_res; + nfs41_getfh_res getfh_res; + bitmap4 attr_request; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res, pgetattr_res; + nfs41_savefh_res savefh_res; + nfs41_restorefh_res restorefh_res; + nfs41_file_info dir_info; + + init_getattr_request(&attr_request); + attr_request.arr[0] |= FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = &state->parent; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); + + compound_add_op(&compound, OP_OPEN, &open_args, &open_res); + open_args.seqid = 0; +#ifdef DISABLE_FILE_DELEGATIONS + open_args.share_access = allow | OPEN4_SHARE_ACCESS_WANT_NO_DELEG; +#else + open_args.share_access = allow; +#endif + open_args.share_deny = deny; + open_args.owner = &state->owner; + open_args.openhow.opentype = create; + open_args.openhow.how.mode = UNCHECKED4; + open_args.openhow.how.u.createattrs.info.attrmask.count = 2; + open_args.openhow.how.u.createattrs.info.attrmask.arr[0] = FATTR4_WORD0_SIZE; + open_args.openhow.how.u.createattrs.info.attrmask.arr[1] = FATTR4_WORD1_MODE; + open_args.openhow.how.u.createattrs.info.mode = mode; + open_args.openhow.how.u.createattrs.info.size = 0; + open_args.claim.claim = CLAIM_NULL; + open_args.claim.u.null.filename = &state->file.name; + open_res.resok4.stateid = &state->stateid; + + compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); + getfh_res.fh = &state->file.fh; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = info; + + compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &pgetattr_res); + getattr_args.attr_request = &attr_request; + pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + pgetattr_res.info = &dir_info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* fill in the file handle's fileid and superblock */ + state->file.fh.fileid = info->fileid; + status = nfs41_superblock_for_fh(session, + &info->fsid, &state->parent.fh, &state->file); + if (status) + goto out; + + /* update the attributes of the parent directory */ + memcpy(&dir_info.attrmask, &pgetattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + state->parent.fh.fileid, &dir_info); + + /* add the file handle and attributes to the name cache */ + memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + AcquireSRWLockShared(&state->path.lock); + nfs41_name_cache_insert(session_name_cache(session), + state->path.path, &state->file.name, &state->file.fh, + info, &open_res.resok4.cinfo); + ReleaseSRWLockShared(&state->path.lock); + +#ifdef RETURN_DELEG_ON_OPEN + /* if the server gave us a delegation, return it immediately */ + if (open_res.resok4.delegation_type == OPEN_DELEGATE_READ || + open_res.resok4.delegation_type == OPEN_DELEGATE_WRITE) { + nfs41_delegreturn(session, &state->file, + &open_res.resok4.deleg_stateid); + } +#endif +out: + return status; +} + +int nfs41_create( + IN nfs41_session *session, + IN uint32_t type, + IN uint32_t mode, + IN nfs41_path_fh *parent, + OUT nfs41_path_fh *file) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[8]; + nfs_resop4 resops[8]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_create_args create_args; + nfs41_create_res create_res; + nfs41_getfh_res getfh_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res, pgetattr_res; + bitmap4 attr_request; + nfs41_file_info file_info, dir_info; + nfs41_savefh_res savefh_res; + nfs41_restorefh_res restorefh_res; + + init_getattr_request(&attr_request); + attr_request.arr[0] |= FATTR4_WORD0_FILEID; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = parent; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); + + compound_add_op(&compound, OP_CREATE, &create_args, &create_res); + create_args.objtype.type = type; + create_args.name = &file->name; + create_args.createattrs.info.attrmask.count = 2; + create_args.createattrs.info.attrmask.arr[0] = 0; + create_args.createattrs.info.attrmask.arr[1] = FATTR4_WORD1_MODE; + create_args.createattrs.info.mode = mode; //511; // 0777 + + compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); + getfh_res.fh = &file->fh; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &file_info; + + compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &pgetattr_res); + getattr_args.attr_request = &attr_request; + pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + pgetattr_res.info = &dir_info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* fill in the file handle's fileid and superblock */ + file->fh.fileid = file_info.fileid; + file->fh.superblock = parent->fh.superblock; + + /* update the attributes of the parent directory */ + memcpy(&dir_info.attrmask, &pgetattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + parent->fh.fileid, &dir_info); + + /* add the new file handle and attributes to the name cache */ + memcpy(&file_info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + AcquireSRWLockShared(&file->path->lock); + nfs41_name_cache_insert(session_name_cache(session), + file->path->path, &file->name, &file->fh, + &file_info, &create_res.cinfo); + ReleaseSRWLockShared(&file->path->lock); +out: + return status; +} + +int nfs41_close( + IN nfs41_session *session, + IN nfs41_open_state *state) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_op_close_args close_args; + nfs41_op_close_res close_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res; + bitmap4 attr_request; + nfs41_file_info info; + + init_getattr_request(&attr_request); + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = &state->file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_CLOSE, &close_args, &close_res); + close_args.open_stateid = &state->stateid; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* update the attributes of the parent directory */ + memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + state->file.fh.fileid, &info); + +out: + return status; +} + +int nfs41_write( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN unsigned char *data, + IN uint32_t data_len, + IN uint64_t offset, + IN enum stable_how4 stable, + OUT uint32_t *bytes_written, + OUT nfs41_write_verf *verf) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_write_args write_args; + nfs41_write_res write_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res = {0}; + bitmap4 attr_request; + nfs41_file_info info; + + init_getattr_request(&attr_request); + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_WRITE, &write_args, &write_res); + write_args.stateid = stateid; + write_args.offset = offset; + write_args.stable = stable; + write_args.data_len = data_len; + write_args.data = data; + write_res.resok4.verf = verf; + + if (stable != UNSTABLE4) { + /* if the write is stable, we can't rely on COMMIT to update + * the attribute cache, so we do the GETATTR here */ + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + } + + status = compound_encode_send_decode(session, &compound, data_len, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + if (stable != UNSTABLE4) { + /* update the attribute cache */ + memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + file->fh.fileid, &info); + } + + *bytes_written = write_res.resok4.count; +out: + return status; +} + +int nfs41_read( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN uint64_t offset, + IN uint32_t count, + OUT unsigned char *data_out, + OUT uint32_t *data_len_out, + OUT bool_t *eof_out) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_read_args read_args; + nfs41_read_res read_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_READ, &read_args, &read_res); + read_args.stateid = stateid; + read_args.offset = offset; + read_args.count = count; + read_res.resok4.data_len = count; + read_res.resok4.data = data_out; + + status = compound_encode_send_decode(session, &compound, 0, count); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + *data_len_out = read_res.resok4.data_len; + *eof_out = read_res.resok4.eof; +out: + return status; +} + +int nfs41_commit( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN uint64_t offset, + IN uint32_t count, + IN bool_t do_getattr) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_commit_args commit_args; + nfs41_commit_res commit_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res = {0}; + bitmap4 attr_request; + nfs41_file_info info; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_COMMIT, &commit_args, &commit_res); + commit_args.offset = offset; + commit_args.count = count; + + /* send a GETATTR request to update the attribute cache, + * but not if we're talking to a data server! */ + if (do_getattr) { + init_getattr_request(&attr_request); + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + } + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + if (do_getattr) { + /* update the attribute cache */ + memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + file->fh.fileid, &info); + } +out: + return status; +} + +int nfs41_lock( + IN nfs41_session *session, + IN nfs41_open_state *open_state, + IN stateid4 *lock_state OPTIONAL, + IN uint32_t type, + IN uint64_t offset, + IN uint64_t length, + OUT stateid4 *stateid_out) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_lock_args lock_args; + nfs41_lock_res lock_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = &open_state->file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LOCK, &lock_args, &lock_res); + lock_args.locktype = type; + lock_args.reclaim = 0; + lock_args.offset = offset; + lock_args.length = length; + if (lock_state) { + lock_args.locker.new_lock_owner = 0; + lock_args.locker.u.lock_owner.lock_stateid = lock_state; + lock_args.locker.u.lock_owner.lock_seqid = 0; /* ignored */ + } else { + lock_args.locker.new_lock_owner = 1; + lock_args.locker.u.open_owner.open_seqid = 0; /* ignored */ + lock_args.locker.u.open_owner.open_stateid = &open_state->stateid; + lock_args.locker.u.open_owner.lock_seqid = 0; /* ignored */ + lock_args.locker.u.open_owner.lock_owner = &open_state->owner; + } + lock_res.u.resok4.lock_stateid = stateid_out; + lock_res.u.denied.owner.owner_len = NFS4_OPAQUE_LIMIT; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +int nfs41_test_lock( + IN nfs41_session *session, + IN nfs41_open_state *state, + IN uint32_t type, + IN uint64_t offset, + IN uint64_t length) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_lockt_args lockt_args; + nfs41_lockt_res lockt_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = &state->file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LOCKT, &lockt_args, &lockt_res); + lockt_args.locktype = type; + lockt_args.offset = offset; + lockt_args.length = length; + lockt_args.owner = &state->owner; + lockt_res.denied.owner.owner_len = NFS4_OPAQUE_LIMIT; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +int nfs41_unlock( + IN nfs41_session *session, + IN nfs41_open_state *open_state, + IN OUT stateid4 *lock_state, + IN uint64_t offset, + IN uint64_t length) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_locku_args locku_args; + nfs41_locku_res locku_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = &open_state->file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LOCKU, &locku_args, &locku_res); + /* 18.12.3: the server MUST accept any legal value for locktype */ + locku_args.locktype = READ_LT; + locku_args.offset = offset; + locku_args.length = length; + locku_args.lock_stateid = lock_state; + locku_res.lock_stateid = lock_state; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +int nfs41_readdir( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN bitmap4 *attr_request, + IN nfs41_readdir_cookie *cookie, + OUT unsigned char *entries, + IN OUT uint32_t *entries_len, + OUT bool_t *eof_out) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_readdir_args readdir_args; + nfs41_readdir_res readdir_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_READDIR, &readdir_args, &readdir_res); + readdir_args.cookie.cookie = cookie->cookie; + memcpy(readdir_args.cookie.verf, cookie->verf, NFS4_VERIFIER_SIZE); + readdir_args.dircount = *entries_len; + readdir_args.maxcount = *entries_len + sizeof(nfs41_readdir_res); + readdir_args.attr_request = attr_request; + readdir_res.reply.entries_len = *entries_len; + readdir_res.reply.entries = entries; + ZeroMemory(entries, readdir_args.dircount); + + status = compound_encode_send_decode(session, &compound, + 0, readdir_args.maxcount); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + *entries_len = readdir_res.reply.entries_len; + *eof_out = readdir_res.reply.eof; + memcpy(cookie->verf, readdir_res.cookieverf, NFS4_VERIFIER_SIZE); +out: + return status; +} + +void init_getattr_request(bitmap4 *attr_request) +{ + attr_request->count = 2; + attr_request->arr[0] = FATTR4_WORD0_TYPE | + FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE; + attr_request->arr[1] = FATTR4_WORD1_NUMLINKS | + FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_CREATE | + FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_MODE; + attr_request->arr[2] = 0; +} + +int nfs41_getattr( + IN nfs41_session *session, + IN OPTIONAL nfs41_path_fh *file, + IN bitmap4 *attr_request, + OUT nfs41_file_info *info) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + if (file) { + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + } else { + compound_add_op(&compound, OP_PUTROOTFH, NULL, &putfh_res); + } + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + if (file) { + /* update the name cache with whatever attributes we got */ + memcpy(&info->attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + file->fh.fileid, info); + } +out: + return status; +} + +int nfs41_remove( + IN nfs41_session *session, + IN nfs41_path_fh *parent, + IN const nfs41_component *target) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_remove_args remove_args; + nfs41_remove_res remove_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res; + bitmap4 attr_request; + nfs41_file_info info; + + init_getattr_request(&attr_request); + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = parent; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_REMOVE, &remove_args, &remove_res); + remove_args.target = target; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* update the attributes of the parent directory */ + memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + parent->fh.fileid, &info); + + /* remove the target file from the cache */ + AcquireSRWLockShared(&parent->path->lock); + nfs41_name_cache_remove(session_name_cache(session), + parent->path->path, target, &remove_res.cinfo); + ReleaseSRWLockShared(&parent->path->lock); +out: + return status; +} + +int nfs41_rename( + IN nfs41_session *session, + IN nfs41_path_fh *src_dir, + IN const nfs41_component *src_name, + IN nfs41_path_fh *dst_dir, + IN const nfs41_component *dst_name) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[8]; + nfs_resop4 resops[8]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args src_putfh_args; + nfs41_putfh_res src_putfh_res; + nfs41_savefh_res savefh_res; + nfs41_putfh_args dst_putfh_args; + nfs41_putfh_res dst_putfh_res; + nfs41_rename_args rename_args; + nfs41_rename_res rename_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res src_getattr_res, dst_getattr_res; + nfs41_file_info src_info, dst_info; + bitmap4 attr_request; + nfs41_restorefh_res restorefh_res; + + init_getattr_request(&attr_request); + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &src_putfh_args, &src_putfh_res); + src_putfh_args.file = src_dir; + src_putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); + + compound_add_op(&compound, OP_PUTFH, &dst_putfh_args, &dst_putfh_res); + dst_putfh_args.file = dst_dir; + dst_putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_RENAME, &rename_args, &rename_res); + rename_args.oldname = src_name; + rename_args.newname = dst_name; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &dst_getattr_res); + getattr_args.attr_request = &attr_request; + dst_getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + dst_getattr_res.info = &dst_info; + + compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &src_getattr_res); + src_getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + src_getattr_res.info = &src_info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* update the attributes of the source directory */ + memcpy(&src_info.attrmask, &src_getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + src_dir->fh.fileid, &src_info); + + /* update the attributes of the destination directory */ + memcpy(&dst_info.attrmask, &dst_getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + dst_dir->fh.fileid, &dst_info); + + if (src_dir->path == dst_dir->path) { + /* source and destination are the same, only lock it once */ + AcquireSRWLockShared(&src_dir->path->lock); + } else if (src_dir->path < dst_dir->path) { + /* lock the lowest memory address first */ + AcquireSRWLockShared(&src_dir->path->lock); + AcquireSRWLockShared(&dst_dir->path->lock); + } else { + AcquireSRWLockShared(&dst_dir->path->lock); + AcquireSRWLockShared(&src_dir->path->lock); + } + + /* move/rename the target file's name cache entry */ + nfs41_name_cache_rename(session_name_cache(session), + src_dir->path->path, src_name, &rename_res.source_cinfo, + dst_dir->path->path, dst_name, &rename_res.target_cinfo); + + if (src_dir->path == dst_dir->path) { + ReleaseSRWLockShared(&src_dir->path->lock); + } else { + ReleaseSRWLockShared(&src_dir->path->lock); + ReleaseSRWLockShared(&dst_dir->path->lock); + } +out: + return status; +} + +int nfs41_setattr( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN nfs41_file_info *info) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_setattr_args setattr_args; + nfs41_setattr_res setattr_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_SETATTR, &setattr_args, &setattr_res); + setattr_args.stateid = stateid; + setattr_args.info = info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + memcpy(&info->attrmask, &setattr_res.attrsset, sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + file->fh.fileid, info); +out: + return status; +} + +int nfs41_link( + IN nfs41_session *session, + IN nfs41_path_fh *src, + IN nfs41_path_fh *dst_dir, + IN const nfs41_component *target) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[8]; + nfs_resop4 resops[8]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args[2]; + nfs41_putfh_res putfh_res[2]; + nfs41_savefh_res savefh_res; + nfs41_link_args link_args; + nfs41_link_res link_res; + nfs41_restorefh_res restorefh_res; + nfs41_getattr_args getattr_args, pgetattr_args; + nfs41_getattr_res getattr_res, pgetattr_res; + nfs41_file_info info, dir_info; + bitmap4 dir_attr_request; + + ZeroMemory(&info, sizeof(info)); + info.attrmask.count = 2; + info.attrmask.arr[1] = FATTR4_WORD1_NUMLINKS; + init_getattr_request(&dir_attr_request); + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 1); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]); + putfh_args[0].file = src; + putfh_args[0].in_recovery = 0; + + compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); + + compound_add_op(&compound, OP_PUTFH, &putfh_args[1], &putfh_res[1]); + putfh_args[1].file = dst_dir; + putfh_args[1].in_recovery = 0; + + compound_add_op(&compound, OP_LINK, &link_args, &link_res); + link_args.newname = target; + + compound_add_op(&compound, OP_GETATTR, &pgetattr_args, &pgetattr_res); + pgetattr_args.attr_request = &dir_attr_request; + pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + pgetattr_res.info = &dir_info; + + compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &info.attrmask; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* update the attributes of the destination directory */ + memcpy(&dir_info.attrmask, &pgetattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + dst_dir->fh.fileid, &dir_info); + + /* update the attributes of the source file */ + memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + src->fh.fileid, &info); +out: + return status; +} + +int nfs41_readlink( + IN nfs41_session *session, + IN nfs41_path_fh *file, + OUT nfs41_abs_path *link_out) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_readlink_res readlink_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_READLINK, NULL, &readlink_res); + readlink_res.link_len = NFS4_OPAQUE_LIMIT; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + if (readlink_res.link_len >= NFS41_MAX_PATH_LEN) { + status = NFS4ERR_REP_TOO_BIG; + goto out; + } + AcquireSRWLockExclusive(&link_out->lock); + link_out->len = (unsigned short)readlink_res.link_len; + memcpy(link_out->path, readlink_res.link, readlink_res.link_len); + ReleaseSRWLockExclusive(&link_out->lock); +out: + return status; +} + +int nfs41_access( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN uint32_t requested, + OUT uint32_t *supported OPTIONAL, + OUT uint32_t *access OPTIONAL) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_access_args access_args; + nfs41_access_res access_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_ACCESS, &access_args, &access_res); + access_args.access = requested; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + if (supported) + *supported = access_res.supported; + if (access) + *access = access_res.access; +out: + return status; +} + +int nfs41_send_sequence( + IN nfs41_session *session) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[1]; + nfs_resop4 resops[1]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; +out: + return status; +} + +int nfs41_delegreturn( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_delegreturn_args dr_args; + nfs41_delegreturn_res dr_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_DELEGRETURN, &dr_args, &dr_res); + dr_args.stateid = stateid; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +enum nfsstat4 nfs41_fs_locations( + IN nfs41_session *session, + IN nfs41_path_fh *parent, + IN const nfs41_component *name, + OUT fs_locations4 *locations) +{ + enum nfsstat4 status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + nfs41_lookup_args lookup_args; + nfs41_lookup_res lookup_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res; + bitmap4 attr_request = { 1, { FATTR4_WORD0_FS_LOCATIONS } }; + nfs41_file_info info; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = parent; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res); + lookup_args.name = name; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + info.fs_locations = locations; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + +enum nfsstat4 pnfs_rpc_layoutget( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length, + OUT pnfs_file_layout *layout) +{ + enum nfsstat4 status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + pnfs_layoutget_args layoutget_args; + pnfs_layoutget_res layoutget_res; + uint32_t i; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LAYOUTGET, &layoutget_args, &layoutget_res); + layoutget_args.signal_layout_avail = 0; + layoutget_args.layout_type = PNFS_LAYOUTTYPE_FILE; + layoutget_args.iomode = iomode; + layoutget_args.offset = offset; + layoutget_args.minlength = layoutget_args.length = length; + layoutget_args.stateid = state; + layoutget_args.maxcount = session->fore_chan_attrs.ca_maxresponsesize - READ_OVERHEAD; + layoutget_res.u.res_ok.layout = layout; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* point each file handle to the meta server's superblock */ + for (i = 0; i < layout->filehandles.count; i++) + layout->filehandles.arr[i].fh.superblock = file->fh.superblock; +out: + return status; +} + +enum nfsstat4 pnfs_rpc_layoutcommit( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN uint64_t offset, + IN uint64_t length, + IN OPTIONAL uint64_t *new_last_offset, + IN OPTIONAL nfstime4 *new_time_modify) +{ + enum nfsstat4 status; + nfs41_compound compound; + nfs_argop4 argops[4]; + nfs_resop4 resops[4]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + pnfs_layoutcommit_args lc_args; + pnfs_layoutcommit_res lc_res; + nfs41_getattr_args getattr_args; + nfs41_getattr_res getattr_res; + nfs41_file_info info; + bitmap4 attr_request; + + init_getattr_request(&attr_request); + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LAYOUTCOMMIT, &lc_args, &lc_res); + lc_args.offset = offset; + lc_args.length = length; + lc_args.stateid = stateid; + lc_args.new_time = new_time_modify; + lc_args.new_offset = new_last_offset; + + compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); + getattr_args.attr_request = &attr_request; + getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res.info = &info; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + /* update the attribute cache */ + memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + sizeof(bitmap4)); + nfs41_attr_cache_update(session_name_cache(session), + file->fh.fileid, &info); +out: + return status; +} + +enum nfsstat4 pnfs_rpc_layoutreturn( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN pnfs_file_layout *layout) +{ + enum nfsstat4 status; + nfs41_compound compound; + nfs_argop4 argops[3]; + nfs_resop4 resops[3]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_putfh_args putfh_args; + nfs41_putfh_res putfh_res; + pnfs_layoutreturn_args layoutreturn_args; + pnfs_layoutreturn_res layoutreturn_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_PUTFH, &putfh_args, &putfh_res); + putfh_args.file = file; + putfh_args.in_recovery = 0; + + compound_add_op(&compound, OP_LAYOUTRETURN, &layoutreturn_args, &layoutreturn_res); + layoutreturn_args.reclaim = 0; + layoutreturn_args.type = layout->layout.type; + layoutreturn_args.iomode = layout->layout.iomode; + layoutreturn_args.return_type = PNFS_RETURN_FILE; + layoutreturn_args.offset = layout->layout.offset; + layoutreturn_args.length = layout->layout.length; + layoutreturn_args.stateid = &layout->layout.state; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + if (compound_error(status = compound.res.status)) + goto out; + + if (layoutreturn_res.stateid_present) { + /* update the layout seqid */ + layout->layout.state.seqid = layoutreturn_res.stateid.seqid; + } else { + /* 12.5.3. Layout Stateid: Once a client has no more layouts on a file, + * the layout stateid is no longer valid and MUST NOT be used. */ + ZeroMemory(&layout->layout.state, sizeof(stateid4)); + } +out: + return status; +} + +enum nfsstat4 pnfs_rpc_getdeviceinfo( + IN nfs41_session *session, + IN unsigned char *deviceid, + OUT pnfs_file_device *device) +{ + enum nfsstat4 status; + nfs41_compound compound; + nfs_argop4 argops[2]; + nfs_resop4 resops[2]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + pnfs_getdeviceinfo_args getdeviceinfo_args; + pnfs_getdeviceinfo_res getdeviceinfo_res; + + compound_init(&compound, argops, resops); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_GETDEVICEINFO, + &getdeviceinfo_args, &getdeviceinfo_res); + getdeviceinfo_args.deviceid = deviceid; + getdeviceinfo_args.layout_type = PNFS_LAYOUTTYPE_FILE; + getdeviceinfo_args.maxcount = NFS41_MAX_SERVER_CACHE; /* XXX */ + getdeviceinfo_args.notify_types.count = 0; + getdeviceinfo_res.u.res_ok.device = device; + + status = compound_encode_send_decode(session, &compound, 0, 0); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h new file mode 100644 index 0000000..280d764 --- /dev/null +++ b/daemon/nfs41_ops.h @@ -0,0 +1,1074 @@ +/* Copyright (c) 2010 +* The Regents of the University of Michigan +* All Rights Reserved +* +* Permission is granted to use, copy and redistribute this software +* for noncommercial education and research purposes, so long as no +* fee is charged, and so long as the name of the University of Michigan +* is not used in any advertising or publicity pertaining to the use +* or distribution of this software without specific, written prior +* authorization. Permission to modify or otherwise create derivative +* works of this software is not granted. +* +* This software is provided as is, without representation or warranty +* of any kind either express or implied, including without limitation +* the implied warranties of merchantability, fitness for a particular +* purpose, or noninfringement. The Regents of the University of +* Michigan shall not be liable for any damages, including special, +* indirect, incidental, or consequential damages, with respect to any +* claim arising out of or in connection with the use of the software, +* even if it has been or is hereafter advised of the possibility of +* such damages. +*/ + +#ifndef __NFS41_NFS_OPS_H__ +#define __NFS41_NFS_OPS_H__ + +#include "nfs41.h" +#include "pnfs.h" + + +/* Operation arrays */ +enum nfs_opnum4 { + OP_ACCESS = 3, + OP_CLOSE = 4, + OP_COMMIT = 5, + OP_CREATE = 6, + OP_DELEGPURGE = 7, + OP_DELEGRETURN = 8, + OP_GETATTR = 9, + OP_GETFH = 10, + OP_LINK = 11, + OP_LOCK = 12, + OP_LOCKT = 13, + OP_LOCKU = 14, + OP_LOOKUP = 15, + OP_LOOKUPP = 16, + OP_NVERIFY = 17, + OP_OPEN = 18, + OP_OPENATTR = 19, + OP_OPEN_CONFIRM = 20, /* Mandatory not-to-implement */ + OP_OPEN_DOWNGRADE = 21, + OP_PUTFH = 22, + OP_PUTPUBFH = 23, + OP_PUTROOTFH = 24, + OP_READ = 25, + OP_READDIR = 26, + OP_READLINK = 27, + OP_REMOVE = 28, + OP_RENAME = 29, + OP_RENEW = 30, /* Mandatory not-to-implement */ + OP_RESTOREFH = 31, + OP_SAVEFH = 32, + OP_SECINFO = 33, + OP_SETATTR = 34, + OP_SETCLIENTID = 35, /* Mandatory not-to-implement */ + OP_SETCLIENTID_CONFIRM = 36, /* Mandatory not-to-implement */ + OP_VERIFY = 37, + OP_WRITE = 38, + OP_RELEASE_LOCKOWNER = 39, /* Mandatory not-to-implement */ + + /* new operations for NFSv4.1 */ + OP_BACKCHANNEL_CTL = 40, + OP_BIND_CONN_TO_SESSION = 41, + OP_EXCHANGE_ID = 42, + OP_CREATE_SESSION = 43, + OP_DESTROY_SESSION = 44, + OP_FREE_STATEID = 45, + OP_GET_DIR_DELEGATION = 46, + OP_GETDEVICEINFO = 47, + OP_GETDEVICELIST = 48, + OP_LAYOUTCOMMIT = 49, + OP_LAYOUTGET = 50, + OP_LAYOUTRETURN = 51, + OP_SECINFO_NO_NAME = 52, + OP_SEQUENCE = 53, + OP_SET_SSV = 54, + OP_TEST_STATEID = 55, + OP_WANT_DELEGATION = 56, + OP_DESTROY_CLIENTID = 57, + OP_RECLAIM_COMPLETE = 58, + OP_ILLEGAL = 10044 +}; + + +/* OP_EXCHANGE_ID */ +enum { + EXCHGID4_FLAG_SUPP_MOVED_REFER = 0x00000001, + EXCHGID4_FLAG_SUPP_MOVED_MIGR = 0x00000002, + + EXCHGID4_FLAG_BIND_PRINC_STATEID = 0x00000100, + + EXCHGID4_FLAG_USE_NON_PNFS = 0x00010000, + EXCHGID4_FLAG_USE_PNFS_MDS = 0x00020000, + EXCHGID4_FLAG_USE_PNFS_DS = 0x00040000, + + EXCHGID4_FLAG_MASK_PNFS = 0x00070000, + + EXCHGID4_FLAG_UPD_CONFIRMED_REC_A = 0x40000000, + EXCHGID4_FLAG_CONFIRMED_R = 0x80000000 +}; + +typedef enum { + SP4_NONE = 0, + SP4_MACH_CRED = 1, + SP4_SSV = 2 +} state_protect_how4; + +typedef struct __state_protect4_a { + state_protect_how4 spa_how; +} state_protect4_a; + +typedef struct __nfs41_exchange_id_args { + client_owner4 *eia_clientowner; + uint32_t eia_flags; + state_protect4_a eia_state_protect; + nfs_impl_id4 *eia_client_impl_id; /* <1> */ +} nfs41_exchange_id_args; + +typedef struct __state_protect4_r { + state_protect_how4 spr_how; +} state_protect4_r; + +typedef struct __nfs41_exchange_id_res { + uint32_t status; + uint64_t clientid; + uint32_t sequenceid; + uint32_t flags; + state_protect4_r state_protect; + server_owner4 server_owner; + uint32_t server_scope_len; + char server_scope[NFS4_OPAQUE_LIMIT]; +} nfs41_exchange_id_res; + + +/* OP_CREATE_SESSION */ +typedef struct __nfs41_create_session_args { + uint64_t csa_clientid; + uint32_t csa_sequence; + uint32_t csa_flags; + nfs41_channel_attrs csa_fore_chan_attrs; + nfs41_channel_attrs csa_back_chan_attrs; + uint32_t csa_cb_program; +} nfs41_create_session_args; + +typedef struct __nfs41_create_session_res { + unsigned char *csr_sessionid; + uint32_t csr_sequence; + uint32_t csr_flags; + nfs41_channel_attrs *csr_fore_chan_attrs; + nfs41_channel_attrs *csr_back_chan_attrs; +} nfs41_create_session_res; + + +/* OP_BIND_CONN_TO_SESSION */ +enum channel_dir_from_client4 { + CDFC4_FORE = 0x1, + CDFC4_BACK = 0x2, + CDFC4_FORE_OR_BOTH = 0x3, + CDFC4_BACK_OR_BOTH = 0x7 +}; + +enum channel_dir_from_server4 { + CDFS4_FORE = 0x1, + CDFS4_BACK = 0x2, + CDFS4_BOTH = 0x3 +}; + +typedef struct __nfs41_bind_conn_to_session_args { + unsigned char *sessionid; + enum channel_dir_from_client4 dir; +} nfs41_bind_conn_to_session_args; + +typedef struct __nfs41_bind_conn_to_session_res { + enum nfsstat4 status; + /* case NFS4_OK: */ + enum channel_dir_from_server4 dir; +} nfs41_bind_conn_to_session_res; + + +/* OP_DESTROY_SESSION */ +typedef struct __nfs41_destroy_session_args { + unsigned char *dsa_sessionid; +} nfs41_destroy_session_args; + +typedef struct __nfs41_destroy_session_res { + uint32_t dsr_status; +} nfs41_destroy_session_res; + + +/* OP_SEQUENCE */ +typedef struct __nfs41_sequence_args { + unsigned char *sa_sessionid; + uint32_t sa_sequenceid; + uint32_t sa_slotid; + uint32_t sa_highest_slotid; + bool_t sa_cachethis; +} nfs41_sequence_args; + +enum { + SEQ4_STATUS_CB_PATH_DOWN = 0x00000001, + SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING = 0x00000002, + SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED = 0x00000004, + SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED = 0x00000008, + SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED = 0x00000010, + SEQ4_STATUS_ADMIN_STATE_REVOKED = 0x00000020, + SEQ4_STATUS_RECALLABLE_STATE_REVOKED = 0x00000040, + SEQ4_STATUS_LEASE_MOVED = 0x00000080, + SEQ4_STATUS_RESTART_RECLAIM_NEEDED = 0x00000100, + SEQ4_STATUS_CB_PATH_DOWN_SESSION = 0x00000200, + SEQ4_STATUS_BACKCHANNEL_FAULT = 0x00000400, + SEQ4_STATUS_DEVID_CHANGED = 0x00000800, + SEQ4_STATUS_DEVID_DELETED = 0x00001000 +}; + +typedef struct __nfs41_sequence_res_ok { + unsigned char sr_sessionid[NFS4_SESSIONID_SIZE]; + uint32_t sr_sequenceid; + uint32_t sr_slotid; + uint32_t sr_highest_slotid; + uint32_t sr_target_highest_slotid; + uint32_t sr_status_flags; +} nfs41_sequence_res_ok; + +typedef struct __nfs41_sequence_res { + uint32_t sr_status; + /* case NFS4_OK: */ + nfs41_sequence_res_ok sr_resok4; +} nfs41_sequence_res; + + +/* OP_RECLAIM_COMPLETE */ +typedef struct __nfs41_reclaim_complete_res { + enum nfsstat4 status; +} nfs41_reclaim_complete_res; + + +/* OP_ACCESS */ +enum { + ACCESS4_READ = 0x00000001, + ACCESS4_LOOKUP = 0x00000002, + ACCESS4_MODIFY = 0x00000004, + ACCESS4_EXTEND = 0x00000008, + ACCESS4_DELETE = 0x00000010, + ACCESS4_EXECUTE = 0x00000020 +}; + +typedef struct __nfs41_access_args { + uint32_t access; +} nfs41_access_args; + +typedef struct __nfs41_access_res { + uint32_t status; + /* case NFS4_OK: */ + uint32_t supported; + uint32_t access; +} nfs41_access_res; + + +/* OP_CLOSE */ +typedef struct __nfs41_op_close_args { +// uint32_t seqid; // not used, always 0 + stateid4 *open_stateid; /* -> nfs41_op_open_res_ok.stateid */ +} nfs41_op_close_args; + +typedef struct __nfs41_op_close_res { + uint32_t status; + /* case NFS4_OK: */ + stateid4 open_stateid; +} nfs41_op_close_res; + + +/* OP_COMMIT */ +typedef struct __nfs41_commit_args { + uint64_t offset; + uint32_t count; +} nfs41_commit_args; + +typedef struct __nfs41_commit_res { + uint32_t status; + unsigned char writeverf[NFS4_VERIFIER_SIZE]; +} nfs41_commit_res; + + +/* OP_CREATE */ +typedef struct __specdata4 { + uint32_t specdata1; + uint32_t specdata2; +} specdata4; + +typedef struct __createtype4 { + uint32_t type; + union { + /* case NF4LNK: */ + struct __create_type_lnk { + uint32_t linkdata_len; + char linkdata[NFS4_OPAQUE_LIMIT]; + } lnk; + /* case NF4BLK, NF4CHR: */ + specdata4 devdata; + } u; +} createtype4; + +typedef struct __createattrs4 { + nfs41_file_info info; +} createattrs4; + +typedef struct __nfs41_create_args { + createtype4 objtype; + const nfs41_component *name; + createattrs4 createattrs; +} nfs41_create_args; + +typedef struct __nfs41_create_res { + uint32_t status; + /* case NFS4_OK: */ + change_info4 cinfo; + bitmap4 attrset; +} nfs41_create_res; + + +/* OP_DELEGRETURN */ +typedef struct __nfs41_delegreturn_args { + stateid4 *stateid; +} nfs41_delegreturn_args; + +typedef struct __nfs41_delegreturn_res { + uint32_t status; +} nfs41_delegreturn_res; + + +/* OP_LINK */ +typedef struct __nfs41_link_args { + const nfs41_component *newname; +} nfs41_link_args; + +typedef struct __nfs41_link_res { + uint32_t status; + /* case NFS4_OK */ + change_info4 cinfo; +} nfs41_link_res; + + +/* OP_LOCK */ +enum { + READ_LT = 1, + WRITE_LT = 2, + READW_LT = 3, /* blocking read */ + WRITEW_LT = 4 /* blocking write */ +}; + +typedef struct __open_to_lock_owner4 { + uint32_t open_seqid; + stateid4 *open_stateid; + uint32_t lock_seqid; + state_owner4 *lock_owner; +} open_to_lock_owner4; + +typedef struct __exist_lock_owner4 { + stateid4 *lock_stateid; + uint32_t lock_seqid; +} exist_lock_owner4; + +typedef struct __locker4 { + bool_t new_lock_owner; + union { + /* case TRUE: */ + open_to_lock_owner4 open_owner; + /* case FALSE: */ + exist_lock_owner4 lock_owner; + } u; +} locker4; + +typedef struct __nfs41_lock_args { + uint32_t locktype; + bool_t reclaim; + uint64_t offset; + uint64_t length; + locker4 locker; +} nfs41_lock_args; + +typedef struct __lock_res_denied { + uint64_t offset; + uint64_t length; + uint32_t locktype; + state_owner4 owner; +} lock_res_denied; + +typedef struct __lock_res_ok { + stateid4 *lock_stateid; +} lock_res_ok; + +typedef struct __nfs41_lock_res { + uint32_t status; + union { + /* case NFS4_OK: */ + lock_res_ok resok4; + /* case NFS4ERR_DENIED: */ + lock_res_denied denied; + /* default: void; */ + } u; +} nfs41_lock_res; + + +/* OP_LOCKT */ +typedef struct __nfs41_lockt_args { + uint32_t locktype; + uint64_t offset; + uint64_t length; + state_owner4 *owner; +} nfs41_lockt_args; + +typedef struct __nfs41_lockt_res { + uint32_t status; + /* case NFS4ERR_DENIED: */ + lock_res_denied denied; + /* default: void; */ +} nfs41_lockt_res; + + +/* OP_LOCKU */ +typedef struct __nfs41_locku_args { + uint32_t locktype; + uint32_t seqid; + stateid4 *lock_stateid; + uint64_t offset; + uint64_t length; +} nfs41_locku_args; + +typedef struct __nfs41_locku_res { + uint32_t status; + /* case NFS4_OK: */ + stateid4 *lock_stateid; +} nfs41_locku_res; + + +/* OP_LOOKUP */ +typedef struct __nfs41_lookup_args { + const nfs41_component *name; +} nfs41_lookup_args; + +typedef struct __nfs41_lookup_res { + uint32_t status; +} nfs41_lookup_res; + + +/* OP_GETFH */ +typedef struct __nfs41_getfh_res { + uint32_t status; + /* case NFS4_OK: */ + nfs41_fh *fh; +} nfs41_getfh_res; + + +/* OP_PUTFH */ +typedef struct __nfs41_putfh_args { + nfs41_path_fh *file; + bool_t in_recovery; +} nfs41_putfh_args; + +typedef struct __nfs41_putfh_res { + uint32_t status; +} nfs41_putfh_res; + + +/* OP_PUTROOTFH */ +typedef struct __nfs41_putrootfh_res { + uint32_t status; +} nfs41_putrootfh_res; + + +/* OP_GETATTR */ +typedef struct __nfs41_getattr_args { + bitmap4 *attr_request; +} nfs41_getattr_args; + +typedef struct __nfs41_getattr_res { + uint32_t status; + /* case NFS4_OK: */ + fattr4 obj_attributes; + nfs41_file_info *info; +} nfs41_getattr_res; + + +/* OP_OPEN */ +enum createmode4 { + UNCHECKED4 = 0, + GUARDED4 = 1, + EXCLUSIVE4 = 2, + EXCLUSIVE4_1 = 3 +}; + +typedef struct __creatverfattr { + unsigned char cva_verf[NFS4_VERIFIER_SIZE]; + fattr4 cva_attrs; +} creatverfattr; + +typedef struct __createhow4 { + uint32_t mode; + union { + /* case UNCHECKED4, GUARDED4: */ + createattrs4 createattrs; + /* case EXCLUSIVE4: */ + unsigned char createverf[NFS4_VERIFIER_SIZE]; + /* case EXCLUSIVE4_1: */ + creatverfattr ch_createboth; + } u; +} createhow4; + +enum opentype4 { + OPEN4_NOCREATE = 0, + OPEN4_CREATE = 1 +}; + +typedef struct __openflag4 { + uint32_t opentype; + /* case OPEN4_CREATE: */ + createhow4 how; +} openflag4; + +enum { + OPEN4_SHARE_ACCESS_READ = 0x00000001, + OPEN4_SHARE_ACCESS_WRITE = 0x00000002, + OPEN4_SHARE_ACCESS_BOTH = 0x00000003, + + OPEN4_SHARE_DENY_NONE = 0x00000000, + OPEN4_SHARE_DENY_READ = 0x00000001, + OPEN4_SHARE_DENY_WRITE = 0x00000002, + OPEN4_SHARE_DENY_BOTH = 0x00000003, + + OPEN4_SHARE_ACCESS_WANT_DELEG_MASK = 0xFF00, + OPEN4_SHARE_ACCESS_WANT_NO_PREFERENCE = 0x0000, + OPEN4_SHARE_ACCESS_WANT_READ_DELEG = 0x0100, + OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG = 0x0200, + OPEN4_SHARE_ACCESS_WANT_ANY_DELEG = 0x0300, + OPEN4_SHARE_ACCESS_WANT_NO_DELEG = 0x0400, + OPEN4_SHARE_ACCESS_WANT_CANCEL = 0x0500, + + OPEN4_SHARE_ACCESS_WANT_SIGNAL_DELEG_WHEN_RESRC_AVAIL = 0x10000, + OPEN4_SHARE_ACCESS_WANT_PUSH_DELEG_WHEN_UNCONTENDED = 0x20000 +}; + +enum open_delegation_type4 { + OPEN_DELEGATE_NONE = 0, + OPEN_DELEGATE_READ = 1, + OPEN_DELEGATE_WRITE = 2, + OPEN_DELEGATE_NONE_EXT = 3 +}; + +enum open_claim_type4 { + CLAIM_NULL = 0, + CLAIM_PREVIOUS = 1, + CLAIM_DELEGATE_CUR = 2, + CLAIM_DELEGATE_PREV = 3, + CLAIM_FH = 4, + CLAIM_DELEG_CUR_FH = 5, + CLAIM_DELEG_PREV_FH = 6 +}; + +enum why_no_delegation4 { + WND4_NOT_WANTED = 0, + WND4_CONTENTION = 1, + WND4_RESOURCE = 2, + WND4_NOT_SUPP_FTYPE = 3, + WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4, + WND4_NOT_SUPP_UPGRADE = 5, + WND4_NOT_SUPP_DOWNGRADE = 6, + WND4_CANCELED = 7, + WND4_IS_DIR = 8 +}; + +typedef struct __open_claim4 { + uint32_t claim; + union { + /* case CLAIM_NULL: */ + struct __open_claim_null { + const nfs41_component *filename; + } null; + } u; +} open_claim4; + +typedef struct __nfs41_op_open_args { + uint32_t seqid; + uint32_t share_access; + uint32_t share_deny; + state_owner4 *owner; + openflag4 openhow; + open_claim4 claim; +} nfs41_op_open_args; + +enum { + OPEN4_RESULT_CONFIRM = 0x00000002, + OPEN4_RESULT_LOCKTYPE_POSIX = 0x00000004, + OPEN4_RESULT_PRESERVE_UNLINKED = 0x00000008, + OPEN4_RESULT_MAY_NOTIFY_LOCK = 0x00000020 +}; + +typedef struct __nfs41_op_open_res_ok { + stateid4 *stateid; + change_info4 cinfo; + uint32_t rflags; + bitmap4 attrset; + uint32_t delegation_type; + stateid4 deleg_stateid; + uint32_t why_no_deleg; + uint32_t why_none_flag; +} nfs41_op_open_res_ok; + +typedef struct __nfs41_op_open_res { + uint32_t status; + /* case NFS4_OK: */ + nfs41_op_open_res_ok resok4; +} nfs41_op_open_res; + + +/* OP_READ */ +typedef struct __nfs41_read_args { + stateid4 *stateid; /* -> nfs41_op_open_res_ok.stateid */ + uint64_t offset; + uint32_t count; +} nfs41_read_args; + +typedef struct __nfs41_read_res_ok { + bool_t eof; + uint32_t data_len; + unsigned char *data; /* caller-allocated */ +} nfs41_read_res_ok; + +typedef struct __nfs41_read_res { + uint32_t status; + /* case NFS4_OK: */ + nfs41_read_res_ok resok4; +} nfs41_read_res; + + +/* OP_READDIR */ +typedef struct __nfs41_readdir_cookie { + uint64_t cookie; + unsigned char verf[NFS4_VERIFIER_SIZE]; +} nfs41_readdir_cookie; + +typedef struct __nfs41_readdir_args { + nfs41_readdir_cookie cookie; + uint32_t dircount; + uint32_t maxcount; + bitmap4 *attr_request; +} nfs41_readdir_args; + +typedef struct __nfs41_readdir_entry { + uint64_t cookie; + uint32_t name_len; + uint32_t next_entry_offset; + nfs41_file_info attr_info; + char name[1]; +} nfs41_readdir_entry; + +typedef struct __nfs41_readdir_list { + bool_t has_entries; + uint32_t entries_len; + unsigned char *entries; + bool_t eof; +} nfs41_readdir_list; + +typedef struct __nfs41_readdir_res { + uint32_t status; + /* case NFS4_OK: */ + unsigned char cookieverf[NFS4_VERIFIER_SIZE]; + nfs41_readdir_list reply; +} nfs41_readdir_res; + + +/* OP_READLINK */ +typedef struct __nfs41_readlink_res { + uint32_t status; + /* case NFS4_OK: */ + uint32_t link_len; + char link[NFS4_OPAQUE_LIMIT]; +} nfs41_readlink_res; + + +/* OP_REMOVE */ +typedef struct __nfs41_remove_args { + const nfs41_component *target; +} nfs41_remove_args; + +typedef struct __nfs41_remove_res { + uint32_t status; + /* case NFS4_OK: */ + change_info4 cinfo; +} nfs41_remove_res; + + +/* OP_RENAME */ +typedef struct __nfs41_rename_args { + const nfs41_component *oldname; + const nfs41_component *newname; +} nfs41_rename_args; + +typedef struct __nfs41_rename_res { + uint32_t status; + /* case NFS4_OK: */ + change_info4 source_cinfo; + change_info4 target_cinfo; +} nfs41_rename_res; + + +/* OP_RESTOREFH */ +/* OP_SAVEFH */ +typedef struct __nfs41_restorefh_savefh_res { + uint32_t status; +} nfs41_restorefh_res, nfs41_savefh_res; + + +/* OP_SETATTR */ +enum time_how4 { + SET_TO_SERVER_TIME4 = 0, + SET_TO_CLIENT_TIME4 = 1 +}; + +typedef struct __nfs41_setattr_args { + stateid4 *stateid; + nfs41_file_info *info; +} nfs41_setattr_args; + +typedef struct __nfs41_setattr_res { + uint32_t status; + bitmap4 attrsset; +} nfs41_setattr_res; + + +/* OP_WRITE */ +enum stable_how4 { + UNSTABLE4 = 0, + DATA_SYNC4 = 1, + FILE_SYNC4 = 2 +}; + +typedef struct __nfs41_write_verf { + unsigned char verf[NFS4_VERIFIER_SIZE]; + unsigned char expected[NFS4_VERIFIER_SIZE]; + enum stable_how4 committed; +} nfs41_write_verf; + +typedef struct __nfs41_write_args { + stateid4 *stateid; /* -> nfs41_op_open_res_ok.stateid */ + uint64_t offset; + uint32_t stable; /* stable_how4 */ + uint32_t data_len; + unsigned char *data; /* caller-allocated */ +} nfs41_write_args; + +typedef struct __nfs41_write_res_ok { + uint32_t count; + nfs41_write_verf *verf; +} nfs41_write_res_ok; + +typedef struct __nfs41_write_res { + uint32_t status; + /* case NFS4_OK: */ + nfs41_write_res_ok resok4; +} nfs41_write_res; + + +/* LAYOUTGET */ +typedef struct __pnfs_layoutget_args { + bool_t signal_layout_avail; + enum pnfs_layout_type layout_type; + enum pnfs_iomode iomode; + uint64_t offset; + uint64_t length; + uint64_t minlength; + stateid4 *stateid; + uint32_t maxcount; +} pnfs_layoutget_args; + +typedef struct __pnfs_layoutget_res_ok { + pnfs_file_layout *layout; +} pnfs_layoutget_res_ok; + +typedef struct __pnfs_layoutget_res { + enum nfsstat4 status; + union { + /* case NFS4_OK: */ + pnfs_layoutget_res_ok res_ok; + /* case NFS4ERR_LAYOUTTRYLATER: */ + bool_t will_signal_layout_avail; + /* default: void; */ + } u; +} pnfs_layoutget_res; + + +/* LAYOUTCOMMIT */ +typedef struct __pnfs_layoutcommit_args { + uint64_t offset; + uint64_t length; + stateid4 *stateid; + nfstime4 *new_time; + uint64_t *new_offset; +} pnfs_layoutcommit_args; + +typedef struct __pnfs_layoutcommit_res { + uint32_t status; + /* case NFS4_OK */ + bool_t has_new_size; + /* case TRUE */ + uint64_t new_size; +} pnfs_layoutcommit_res; + + +/* LAYOUTRETURN */ +typedef struct __pnfs_layoutreturn_args { + bool_t reclaim; + enum pnfs_layout_type type; + enum pnfs_iomode iomode; + enum pnfs_return_type return_type; + /* case LAYOUTRETURN4_FILE: */ + uint64_t offset; + uint64_t length; + stateid4 *stateid; +} pnfs_layoutreturn_args; + +typedef struct __pnfs_layoutreturn_res { + enum nfsstat4 status; + /* case NFS4_OK: */ + bool_t stateid_present; + /* case true: */ + stateid4 stateid; +} pnfs_layoutreturn_res; + + +/* GETDEVICEINFO */ +typedef struct __pnfs_getdeviceinfo_args { + unsigned char *deviceid; + enum pnfs_layout_type layout_type; + uint32_t maxcount; + bitmap4 notify_types; +} pnfs_getdeviceinfo_args; + +typedef struct __pnfs_getdeviceinfo_res_ok { + pnfs_file_device *device; + bitmap4 notification; +} pnfs_getdeviceinfo_res_ok; + +typedef struct __pnfs_getdeviceinfo_res { + enum nfsstat4 status; + union { + /* case NFS4_OK: */ + pnfs_getdeviceinfo_res_ok res_ok; + /* case NFS4ERR_TOOSMALL: */ + uint32_t mincount; + /* default: void; */ + } u; +} pnfs_getdeviceinfo_res; + + +/* nfs41_ops.c */ +int nfs41_exchange_id( + IN nfs41_rpc_clnt *rpc, + IN client_owner4 *owner, + IN uint32_t flags_in, + OUT nfs41_exchange_id_res *res_out); + +int nfs41_create_session( + IN nfs41_client *clnt, + OUT nfs41_session *session); + +enum nfsstat4 nfs41_bind_conn_to_session( + IN nfs41_rpc_clnt *rpc, + IN const unsigned char *sessionid, + IN enum channel_dir_from_client4 dir); + +int nfs41_destroy_session( + IN nfs41_session *session); + +int nfs41_send_sequence( + IN nfs41_session *session); + +enum nfsstat4 nfs41_reclaim_complete( + IN nfs41_session *session); + +int nfs41_lookup( + IN nfs41_root *root, + IN nfs41_session *session, + IN OUT nfs41_abs_path *path, + OUT OPTIONAL nfs41_path_fh *parent_out, + OUT OPTIONAL nfs41_path_fh *target_out, + OUT OPTIONAL nfs41_file_info *info_out, + OUT nfs41_session **session_out); + +int nfs41_open( + IN nfs41_session *session, + IN uint32_t allow, + IN uint32_t deny, + IN uint32_t create, + IN uint32_t mode, + IN OUT nfs41_open_state *state, + OUT nfs41_file_info *info); + +int nfs41_create( + IN nfs41_session *session, + IN uint32_t type, + IN uint32_t mode, + IN nfs41_path_fh *parent, + OUT nfs41_path_fh *file); + +int nfs41_close( + IN nfs41_session *session, + IN nfs41_open_state *state); + +int nfs41_write( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN unsigned char *data, + IN uint32_t data_len, + IN uint64_t offset, + IN enum stable_how4 stable, + OUT uint32_t *bytes_written, + OUT nfs41_write_verf *verf); + +int nfs41_read( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN uint64_t offset, + IN uint32_t count, + OUT unsigned char *data_out, + OUT uint32_t *data_len_out, + OUT bool_t *eof_out); + +int nfs41_commit( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN uint64_t offset, + IN uint32_t count, + IN bool_t do_getattr); + +int nfs41_lock( + IN nfs41_session *session, + IN nfs41_open_state *open_state, + IN stateid4 *lock_state OPTIONAL, + IN uint32_t type, + IN uint64_t offset, + IN uint64_t length, + OUT stateid4 *stateid_out); + +int nfs41_test_lock( + IN nfs41_session *session, + IN nfs41_open_state *state, + IN uint32_t type, + IN uint64_t offset, + IN uint64_t length); + +int nfs41_unlock( + IN nfs41_session *session, + IN nfs41_open_state *open_state, + IN OUT stateid4 *lock_state, + IN uint64_t offset, + IN uint64_t length); + +stateid4* nfs41_lock_stateid_copy( + IN nfs41_lock_state *lock_state, + IN OUT stateid4 *dest); + +int nfs41_readdir( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN bitmap4 *attr_request, + IN nfs41_readdir_cookie *cookie, + OUT unsigned char *entries, + IN OUT uint32_t *entries_len, + OUT bool_t *eof_out); + +void init_getattr_request( + OUT bitmap4 *attr_request); + +int nfs41_getattr( + IN nfs41_session *session, + IN OPTIONAL nfs41_path_fh *file, + IN bitmap4 *attr_request, + OUT nfs41_file_info *info); + +/* getattr.c */ +int nfs41_cached_getattr( + IN nfs41_session *session, + IN nfs41_path_fh *file, + OUT nfs41_file_info *info); + +int nfs41_remove( + IN nfs41_session *session, + IN nfs41_path_fh *parent, + IN const nfs41_component *target); + +int nfs41_rename( + IN nfs41_session *session, + IN nfs41_path_fh *src_dir, + IN const nfs41_component *src_name, + IN nfs41_path_fh *dst_dir, + IN const nfs41_component *dst_name); + +int nfs41_setattr( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN nfs41_file_info *info); + +int nfs41_link( + IN nfs41_session *session, + IN nfs41_path_fh *src, + IN nfs41_path_fh *dst_dir, + IN const nfs41_component *target); + +int nfs41_readlink( + IN nfs41_session *session, + IN nfs41_path_fh *file, + OUT nfs41_abs_path *link_out); + +int nfs41_access( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN uint32_t requested, + OUT uint32_t *supported OPTIONAL, + OUT uint32_t *access OPTIONAL); + +int nfs41_delegreturn( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid); + +enum nfsstat4 nfs41_fs_locations( + IN nfs41_session *session, + IN nfs41_path_fh *parent, + IN const nfs41_component *name, + OUT fs_locations4 *locations); + + +enum nfsstat4 pnfs_rpc_layoutget( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length, + OUT pnfs_file_layout *layout); + +enum nfsstat4 pnfs_rpc_layoutcommit( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN uint64_t offset, + IN uint64_t length, + IN OPTIONAL uint64_t *new_last_offset, + IN OPTIONAL nfstime4 *new_time_modify); + +enum nfsstat4 pnfs_rpc_layoutreturn( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN pnfs_file_layout *layout); + +enum nfsstat4 pnfs_rpc_getdeviceinfo( + IN nfs41_session *session, + IN unsigned char *deviceid, + OUT pnfs_file_device *device); + +#endif /* !__NFS41_NFS_OPS_H__ */ diff --git a/daemon/nfs41_rpc.c b/daemon/nfs41_rpc.c new file mode 100644 index 0000000..086d9bd --- /dev/null +++ b/daemon/nfs41_rpc.c @@ -0,0 +1,298 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include "nfs41.h" +#include "daemon_debug.h" +#include "nfs41_xdr.h" +#include "nfs41_callback.h" + +#include "rpc/rpc.h" + +static enum clnt_stat send_null(CLIENT *client) +{ + struct timeval timeout = {10, 0}; + + return clnt_call(client, 0, + (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_void, NULL, timeout); +} + +static int get_client_for_netaddr( + IN const netaddr4 *netaddr, + IN uint32_t wsize, + IN uint32_t rsize, + IN nfs41_rpc_clnt *rpc, + OUT CLIENT **client_out) +{ + int status = ERROR_NETWORK_UNREACHABLE; + struct netconfig *nconf; + struct netbuf *addr; + CLIENT *client; + + nconf = getnetconfigent(netaddr->netid); + if (nconf == NULL) + goto out; + + addr = uaddr2taddr(nconf, netaddr->uaddr); + if (addr == NULL) + goto out_free_conf; + + dprintf(1, "callback function %p args %p\n", nfs41_handle_callback, rpc); + client = clnt_tli_create(RPC_ANYFD, nconf, addr, + NFS41_RPC_PROGRAM, NFS41_RPC_VERSION, wsize, rsize, + rpc?proc_cb_compound_res:NULL, rpc?nfs41_handle_callback:NULL, rpc?rpc:NULL); + if (client) { + *client_out = client; + status = NO_ERROR; + goto out_free_addr; + } +out_free_addr: + freenetbuf(addr); +out_free_conf: + freenetconfigent(nconf); +out: + return status; +} + +static int get_client_for_multi_addr( + IN const multi_addr4 *addrs, + IN uint32_t wsize, + IN uint32_t rsize, + IN nfs41_rpc_clnt *rpc, + OUT CLIENT **client_out, + OUT uint32_t *addr_index) +{ + int status = ERROR_NETWORK_UNREACHABLE; + uint32_t i; + for (i = 0; i < addrs->count; i++) { + status = get_client_for_netaddr(&addrs->arr[i], + wsize, rsize, rpc, client_out); + if (status == NO_ERROR) { + *addr_index = i; + break; + } + } + return status; +} + +/* Returns a client structure and an associated lock */ +int nfs41_rpc_clnt_create( + IN const multi_addr4 *addrs, + IN uint32_t wsize, + IN uint32_t rsize, + bool_t needcb, + OUT nfs41_rpc_clnt **rpc_out) +{ + CLIENT *client; + nfs41_rpc_clnt *rpc; + uint32_t addr_index; + int status; + + rpc = calloc(1, sizeof(nfs41_rpc_clnt)); + if (rpc == NULL) { + status = GetLastError(); + goto out; + } + rpc->cond = CreateEvent(NULL, TRUE, FALSE, "rpc_recovery_cond"); + if (rpc->cond == NULL) { + status = GetLastError(); + fprintf(stderr, "CreateEvent failed %d\n", status); + goto out_free_rpc_clnt; + } + + status = get_client_for_multi_addr(addrs, + wsize, rsize, needcb?rpc:NULL, &client, &addr_index); + if (status) { + clnt_pcreateerror("connecting failed"); + goto out_free_rpc_clnt; + } + // XXX Pick credentials in better manner + client->cl_auth = authsys_create_default(); + if (client->cl_auth == NULL) { + // XXX log failure in auth creation somewhere + // XXX Better error return + status = ERROR_NETWORK_UNREACHABLE; + goto out_err_client; + } + if (send_null(client) != RPC_SUCCESS) { + // XXX Do what here? + dprintf(1, " send_null failed\n"); + status = ERROR_NETWORK_UNREACHABLE; + goto out_err_auth; + } + + rpc->rpc = client; + + /* keep a copy of the address and buffer sizes for reconnect */ + memcpy(&rpc->addrs, addrs, sizeof(multi_addr4)); + /* save the index of the address we connected to */ + rpc->addr_index = addr_index; + rpc->wsize = wsize; + rpc->rsize = rsize; + rpc->is_valid_session = TRUE; + + //initialize rpc client lock + InitializeSRWLock(&rpc->lock); + + *rpc_out = rpc; +out: + return status; +out_err_auth: + auth_destroy(client->cl_auth); +out_err_client: + CloseHandle(rpc->cond); + clnt_destroy(client); +out_free_rpc_clnt: + free(rpc); + goto out; +} + +/* Frees resources allocated in clnt_create */ +void nfs41_rpc_clnt_free( + IN nfs41_rpc_clnt *rpc) +{ + auth_destroy(rpc->rpc->cl_auth); + clnt_destroy(rpc->rpc); + CloseHandle(rpc->cond); + free(rpc); +} + +static bool_t rpc_renew_in_progress(nfs41_rpc_clnt *rpc, int *value) +{ + bool_t status = FALSE; + AcquireSRWLockExclusive(&rpc->lock); + if (value) { + dprintf(1, "nfs41_rpc_renew_in_progress: setting value %d\n", *value); + rpc->in_recovery = *value; + if (!rpc->in_recovery) + SetEvent(rpc->cond); + } else { + status = rpc->in_recovery; + dprintf(1, "nfs41_rpc_renew_in_progress: returning value %d\n", status); + } + ReleaseSRWLockExclusive(&rpc->lock); + return status; +} + +static bool_t rpc_should_retry(nfs41_rpc_clnt *rpc, uint32_t version) +{ + bool_t status = 0; + AcquireSRWLockExclusive(&rpc->lock); + if (rpc->version > version) + status = 1; + ReleaseSRWLockExclusive(&rpc->lock); + return status; +} + +static int rpc_reconnect( + IN nfs41_rpc_clnt *rpc) +{ + CLIENT *client = NULL; + uint32_t addr_index; + int status; + + AcquireSRWLockExclusive(&rpc->lock); + + status = get_client_for_multi_addr(&rpc->addrs, + rpc->wsize, rpc->rsize, rpc, &client, &addr_index); + if (status) + goto out_unlock; + + client->cl_auth = rpc->rpc->cl_auth; + if (send_null(client) != RPC_SUCCESS) + goto out_err_client; + + clnt_destroy(rpc->rpc); + rpc->rpc = client; + rpc->addr_index = addr_index; + rpc->version++; + dprintf(1, "nfs41_send_compound: reestablished RPC connection\n"); + +out_unlock: + ReleaseSRWLockExclusive(&rpc->lock); + return status; + +out_err_client: + clnt_destroy(client); + goto out_unlock; +} + +int nfs41_send_compound( + IN nfs41_rpc_clnt *rpc, + IN char *inbuf, + OUT char *outbuf) +{ + struct timeval timeout = {10, 0}; + enum clnt_stat rpc_status; + int status, count = 0, one = 1, zero = 0; + uint32_t version; + + try_again: + AcquireSRWLockShared(&rpc->lock); + version = rpc->version; + rpc_status = clnt_call(rpc->rpc, 1, + (xdrproc_t)nfs_encode_compound, inbuf, + (xdrproc_t)nfs_decode_compound, outbuf, + timeout); + ReleaseSRWLockShared(&rpc->lock); + + if (rpc_status != RPC_SUCCESS) { + eprintf("clnt_call returned rpc_status=%i\n", rpc_status); + switch(rpc_status) { + case RPC_CANTRECV: + case RPC_CANTSEND: + case RPC_TIMEDOUT: + if (!rpc->is_valid_session && ++count > 3) { + status = ERROR_NETWORK_UNREACHABLE; + break; + } + if (rpc_should_retry(rpc, version)) + goto try_again; + while (rpc_renew_in_progress(rpc, NULL)) { + status = WaitForSingleObject(rpc->cond, INFINITE); + if (status != WAIT_OBJECT_0) { + dprintf(1, "nfs41_rpc_renew_in_progress: WaitForSingleObject failed\n"); + print_condwait_status(1, status); + status = ERROR_LOCK_VIOLATION; + goto out; + } + rpc_renew_in_progress(rpc, &zero); + goto try_again; + } + rpc_renew_in_progress(rpc, &one); + if (rpc_reconnect(rpc)) + eprintf("Failed to reconnect!\n"); + rpc_renew_in_progress(rpc, &zero); + goto try_again; + default: + eprintf("UNHANDLED RPC_ERROR: %d\n", rpc_status); + status = ERROR_NETWORK_UNREACHABLE; + break; + } + goto out; + } + + status = 0; +out: + return status; +} diff --git a/daemon/nfs41_server.c b/daemon/nfs41_server.c new file mode 100644 index 0000000..236098f --- /dev/null +++ b/daemon/nfs41_server.c @@ -0,0 +1,332 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "wintirpc.h" +#include "rpc/rpc.h" + +#include "name_cache.h" +#include "daemon_debug.h" +#include "nfs41.h" +#include "util.h" + + +#define SRVLVL 2 /* dprintf level for server logging */ + + +/* nfs41_server_list */ +struct server_list { + struct list_entry head; + CRITICAL_SECTION lock; +}; +static struct server_list g_server_list; + +#define server_entry(pos) list_container(pos, nfs41_server, entry) + + +void nfs41_server_list_init() +{ + list_init(&g_server_list.head); + InitializeCriticalSection(&g_server_list.lock); +} + +/* http://tools.ietf.org/html/rfc5661#section-1.6 + * 1.6. General Definitions: Server Owner: + * "When the client has two connections each to a peer with the same major + * identifier, the client assumes that both peers are the same server (the + * server namespace is the same via each connection)" */ + +/* http://tools.ietf.org/html/rfc5661#section-2.10.4 + * 2.10.4. Server Scope + * "When the server scope values are the same, server owner value may be + * validly compared. In cases where the server scope values are different, + * server owner values are treated as different even if they contain all + * identical bytes." */ + +/* given these definitions, we require that both the server_owner.major_id + * and server_scope are identical when matching instances of nfs41_server */ + +struct server_info { + const char *scope; + const char *owner; +}; + +static int server_compare( + const struct list_entry *entry, + const void *value) +{ + const nfs41_server *server = server_entry(entry); + const struct server_info *info = (const struct server_info*)value; + const int diff = strncmp(server->scope, info->scope, NFS4_OPAQUE_LIMIT); + return diff ? diff : strncmp(server->owner, info->owner, NFS4_OPAQUE_LIMIT); +} + +static int server_entry_find( + IN struct server_list *servers, + IN const struct server_info *info, + OUT struct list_entry **entry_out) +{ + *entry_out = list_search(&servers->head, info, server_compare); + return *entry_out ? NO_ERROR : ERROR_FILE_NOT_FOUND; +} + +static int server_create( + IN const struct server_info *info, + OUT nfs41_server **server_out) +{ + int status = NO_ERROR; + nfs41_server *server; + + server = calloc(1, sizeof(nfs41_server)); + if (server == NULL) { + status = GetLastError(); + eprintf("failed to allocate server %s\n", info->owner); + goto out; + } + + StringCchCopyA(server->scope, NFS4_OPAQUE_LIMIT, info->scope); + StringCchCopyA(server->owner, NFS4_OPAQUE_LIMIT, info->owner); + InitializeSRWLock(&server->addrs.lock); + nfs41_superblock_list_init(&server->superblocks); + nfs41_name_cache_create(&server->name_cache); + *server_out = server; +out: + return status; +} + +static void server_free( + IN nfs41_server *server) +{ + dprintf(SRVLVL, "server_free(%s)\n", server->owner); + nfs41_superblock_list_free(&server->superblocks); + nfs41_name_cache_free(&server->name_cache); + free(server); +} + +static __inline void server_ref_locked( + IN nfs41_server *server) +{ + server->ref_count++; + dprintf(SRVLVL, "nfs41_server_ref(%s) count %d\n", + server->owner, server->ref_count); +} + +void nfs41_server_ref( + IN nfs41_server *server) +{ + EnterCriticalSection(&g_server_list.lock); + + server_ref_locked(server); + + LeaveCriticalSection(&g_server_list.lock); +} + +void nfs41_server_deref( + IN nfs41_server *server) +{ + EnterCriticalSection(&g_server_list.lock); + + server->ref_count--; + dprintf(SRVLVL, "nfs41_server_deref(%s) count %d\n", + server->owner, server->ref_count); + if (server->ref_count == 0) { + list_remove(&server->entry); + server_free(server); + } + + LeaveCriticalSection(&g_server_list.lock); +} + +static void server_addrs_add( + IN OUT struct server_addrs *addrs, + IN const netaddr4 *addr) +{ + /* we keep a list of addrs used to connect to each server. once it gets + * bigger than NFS41_ADDRS_PER_SERVER, overwrite the oldest addrs. use + * server_addrs.next_index to implement a circular array */ + + AcquireSRWLockExclusive(&addrs->lock); + + if (multi_addr_find(&addrs->addrs, addr, NULL)) { + dprintf(SRVLVL, "server_addrs_add() found existing addr '%s'.\n", + addr->uaddr); + } else { + /* overwrite the address at 'next_index' */ + StringCchCopyA(addrs->addrs.arr[addrs->next_index].netid, + NFS41_NETWORK_ID_LEN, addr->netid); + StringCchCopyA(addrs->addrs.arr[addrs->next_index].uaddr, + NFS41_UNIVERSAL_ADDR_LEN, addr->uaddr); + + /* increment/wrap next_index */ + addrs->next_index = (addrs->next_index + 1) % NFS41_ADDRS_PER_SERVER; + /* update addrs.count if necessary */ + if (addrs->addrs.count < addrs->next_index) + addrs->addrs.count = addrs->next_index; + + dprintf(SRVLVL, "server_addrs_add() added new addr '%s'.\n", + addr->uaddr); + } + ReleaseSRWLockExclusive(&addrs->lock); +} + +void nfs41_server_addrs( + IN nfs41_server *server, + OUT multi_addr4 *addrs) +{ + struct server_addrs *saddrs = &server->addrs; + uint32_t i, j; + + /* make a copy of the server's addrs, with most recent first */ + AcquireSRWLockShared(&saddrs->lock); + j = saddrs->next_index; + for (i = 0; i < saddrs->addrs.count; i++) { + /* decrement/wrap j */ + j = (NFS41_ADDRS_PER_SERVER + j - 1) % NFS41_ADDRS_PER_SERVER; + memcpy(&addrs->arr[i], &saddrs->addrs.arr[j], sizeof(netaddr4)); + } + ReleaseSRWLockShared(&saddrs->lock); +} + +int nfs41_server_find_or_create( + IN const char *server_owner_major_id, + IN const char *server_scope, + IN const netaddr4 *addr, + OUT nfs41_server **server_out) +{ + const struct server_info info = { server_scope, server_owner_major_id }; + struct list_entry *entry; + nfs41_server *server; + int status; + + dprintf(SRVLVL, "--> nfs41_server_find_or_create(%s)\n", info.owner); + + EnterCriticalSection(&g_server_list.lock); + + /* search for an existing server */ + status = server_entry_find(&g_server_list, &info, &entry); + if (status) { + /* create a new server */ + status = server_create(&info, &server); + if (status == NO_ERROR) { + /* add it to the list */ + list_add_tail(&g_server_list.head, &server->entry); + *server_out = server; + + dprintf(SRVLVL, "<-- nfs41_server_find_or_create() " + "returning new server %p\n", server); + } else { + dprintf(SRVLVL, "<-- nfs41_server_find_or_create() " + "returning %d\n", status); + } + } else { + server = server_entry(entry); + + dprintf(SRVLVL, "<-- nfs41_server_find_or_create() " + "returning existing server %p\n", server); + } + + if (server) { + /* register the address used to connect */ + server_addrs_add(&server->addrs, addr); + + server_ref_locked(server); + } + + *server_out = server; + LeaveCriticalSection(&g_server_list.lock); + return status; +} + +int nfs41_server_resolve( + IN const char *hostname, + IN unsigned short port, + OUT multi_addr4 *addrs) +{ + int status = ERROR_BAD_NET_NAME; + char service[16]; + struct addrinfo hints, *res, *info; + struct netconfig *nconf; + struct netbuf addr; + char *netid, *uaddr; + + dprintf(SRVLVL, "--> nfs41_server_resolve(%s:%u)\n", + hostname, port); + + addrs->count = 0; + + StringCchPrintfA(service, 16, "%u", port); + + /* request a list of tcp addrs for the given hostname,port */ + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(hostname, service, &hints, &res) != 0) + goto out; + + for (info = res; info != NULL; info = info->ai_next) { + /* find the appropriate entry in /etc/netconfig */ + switch (info->ai_family) { + case AF_INET: netid = "tcp"; break; + case AF_INET6: netid = "tcp6"; break; + default: continue; + } + + nconf = getnetconfigent(netid); + if (nconf == NULL) + continue; + + /* convert to a transport-independent universal address */ + addr.buf = info->ai_addr; + addr.maxlen = addr.len = (unsigned int)info->ai_addrlen; + + uaddr = taddr2uaddr(nconf, &addr); + freenetconfigent(nconf); + + if (uaddr == NULL) + continue; + + StringCchCopyA(addrs->arr[addrs->count].netid, + NFS41_NETWORK_ID_LEN+1, netid); + StringCchCopyA(addrs->arr[addrs->count].uaddr, + NFS41_UNIVERSAL_ADDR_LEN+1, uaddr); + freeuaddr(uaddr); + + status = NO_ERROR; + if (++addrs->count >= NFS41_ADDRS_PER_SERVER) + break; + } + freeaddrinfo(res); +out: + if (status) + dprintf(SRVLVL, "<-- nfs41_server_resolve(%s:%u) returning " + "error %d\n", hostname, port, status); + else + dprintf(SRVLVL, "<-- nfs41_server_resolve(%s:%u) returning " + "%s\n", hostname, port, addrs->arr[0].uaddr); + return status; +} diff --git a/daemon/nfs41_session.c b/daemon/nfs41_session.c new file mode 100644 index 0000000..a77e23a --- /dev/null +++ b/daemon/nfs41_session.c @@ -0,0 +1,385 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "daemon_debug.h" +#include "nfs41_ops.h" +#include "util.h" + + +/* session slot mechanism */ +static int init_slot_table(nfs41_slot_table *table) +{ + int i, status = 0; + + //initialize slot table lock + table->lock = CreateMutex(NULL, FALSE, "session_table_lock"); + if (table->lock == NULL) { + status = GetLastError(); + eprintf("CreateMutext failed %d\n", status); + goto out; + } + //initialize condition variable for slots + table->cond = CreateEvent(NULL, TRUE, FALSE, "session_table_cond"); + if (table->cond == NULL) { + status = GetLastError(); + eprintf("CreateEvent failed %d\n", status); + goto out_mutex; + } + + table->max_slots = NFS41_MAX_NUM_SLOTS; + for(i = 0; i < NFS41_MAX_NUM_SLOTS; i++) { + table->seq_nums[i] = 1; + table->used_slots[i] = 0; + } + table->highest_used = 0; +out: + return status; +out_mutex: + CloseHandle(table->lock); + goto out; +} + +static int reinit_slot_table(nfs41_slot_table *table) +{ + int i, status = 0; + + status = WaitForSingleObject(table->lock, INFINITE); + if (status != WAIT_OBJECT_0) { + dprintf(1, "nfs41_session_bump_seq: WaitForSingleObject failed\n"); + print_condwait_status(1, status); + status = ERROR_LOCK_VIOLATION; + goto out; + } + + table->max_slots = NFS41_MAX_NUM_SLOTS; + for(i = 0; i < NFS41_MAX_NUM_SLOTS; i++) { + table->seq_nums[i] = 1; + table->used_slots[i] = 0; + } + table->highest_used = 0; + SetEvent(table->cond); + ReleaseMutex(table->lock); +out: + return status; +} + +static void free_slot_table(nfs41_slot_table *table) +{ + CloseHandle(table->lock); + CloseHandle(table->cond); +} + +int nfs41_session_bump_seq( + IN nfs41_session *session, + IN uint32_t slotid) +{ + int status; + + AcquireSRWLockShared(&session->client->session_lock); + status = WaitForSingleObject(session->table.lock, INFINITE); + if (status != WAIT_OBJECT_0) { + dprintf(1, "nfs41_session_bump_seq: WaitForSingleObject failed\n"); + print_condwait_status(1, status); + status = ERROR_LOCK_VIOLATION; + goto out; + } + session->table.seq_nums[slotid]++; + ReleaseMutex(session->table.lock); +out: + ReleaseSRWLockShared(&session->client->session_lock); + return status; +} + +int nfs41_session_free_slot( + IN nfs41_session *session, + IN uint32_t slotid) +{ + int status, i; + + AcquireSRWLockShared(&session->client->session_lock); + status = WaitForSingleObject(session->table.lock, INFINITE); + if (status != WAIT_OBJECT_0) { + dprintf(1, "nfs41_session_free_slot: WaitForSingleObject failed\n"); + print_condwait_status(1, status); + status = ERROR_LOCK_VIOLATION; + goto out; + } + session->table.used_slots[slotid] = 0; + if (slotid == session->table.highest_used) { + session->table.highest_used = 0; + for (i = slotid; i > 0; i--) { + if (session->table.used_slots[i]) { + session->table.highest_used = i; + break; + } + } + } + dprintf(3, "freeing slot#=%d highest=%d\n", slotid, session->table.highest_used); + SetEvent(session->table.cond); + ReleaseMutex(session->table.lock); +out: + ReleaseSRWLockShared(&session->client->session_lock); + return status; +} + +int nfs41_session_get_slot( + IN nfs41_session *session, + OUT uint32_t *slot, + OUT uint32_t *seq, + OUT uint32_t *highest) +{ + uint32_t status = NO_ERROR; + uint32_t i; + + AcquireSRWLockShared(&session->client->session_lock); +look_for_slot: + status = WaitForSingleObject(session->table.lock, INFINITE); + if (status != WAIT_OBJECT_0) { + dprintf(1, "nfs41_session_get_slot: WaitForSingleObject failed\n"); + print_condwait_status(1, status); + status = ERROR_LOCK_VIOLATION; + goto out; + } + dprintf(3, "looking for a free slot in the slot table\n"); + *highest = session->table.highest_used; + for (i = 0; i < session->table.max_slots; i++) { + if (!session->table.used_slots[i]) { + session->table.used_slots[i] = 1; // mark slot used + *slot = i; // return slot number + *seq = session->table.seq_nums[i]; // return sequence number for the slot + //update highest_slot_used if needed + if (i > session->table.highest_used) + *highest = session->table.highest_used = i; + break; + } + } + if (i == session->table.max_slots) { + dprintf(1, "all (%d) slots are used. waiting for a free slot\n", session->table.max_slots); + ReleaseMutex(session->table.lock); + status = WaitForSingleObject(session->table.cond, INFINITE); + if (status == WAIT_OBJECT_0) { + dprintf(1, "received a signal to look for a free slot\n"); + ResetEvent(session->table.cond); + goto look_for_slot; + } + } + ReleaseMutex(session->table.lock); + dprintf(2, "session %p: using slot#=%d with seq#=%d highest=%d\n", session, *slot, *seq, *highest); +out: + ReleaseSRWLockShared(&session->client->session_lock); + return status; +} + +int nfs41_session_sequence( + nfs41_sequence_args *args, + nfs41_session *session, + bool_t cachethis) +{ + uint32_t status = NO_ERROR; + + status = nfs41_session_get_slot(session, &args->sa_slotid, + &args->sa_sequenceid, &args->sa_highest_slotid); + if (status) + goto out; + args->sa_sessionid = session->session_id; + args->sa_cachethis = cachethis; +out: + return status; +} + + +/* session renewal */ +static unsigned int WINAPI renew_session(void *args) +{ + int status = NO_ERROR; + nfs41_session *session = (nfs41_session *)args; + /* sleep for 2/3 of lease_time */ + const uint32_t sleep_time = (2 * session->lease_time*1000)/3; + + dprintf(1, "Creating renew_session thread: %p\n", session->renew_thread); + while(1) { + dprintf(1, "Going to sleep for %dmsecs\n", sleep_time); + Sleep(sleep_time); + status = nfs41_send_sequence(session); + if (status) + dprintf(1, "renewal thread: nfs41_send_sequence failed %d\n", status); + } + return status; +} + +/* session creation */ +static int session_alloc( + IN nfs41_client *client, + OUT nfs41_session **session_out) +{ + int status; + nfs41_session *session; + + session = calloc(1, sizeof(nfs41_session)); + if (session == NULL) { + status = GetLastError(); + goto out; + } + session->client = client; + session->renew_thread = INVALID_HANDLE_VALUE; + session->isValidState = FALSE; + + status = init_slot_table(&session->table); + if (status) { + eprintf("init_slot_table failed %d\n", status); + goto out_err_session; + } + + //initialize session lock + InitializeSRWLock(&client->session_lock); + + *session_out = session; +out: + return status; +out_err_session: + free(session); + goto out; +} + +int nfs41_session_create( + IN nfs41_client *client, + IN nfs41_session **session_out) +{ + nfs41_session *session; + int status; + + status = session_alloc(client, &session); + if (status) { + eprintf("session_alloc() failed with %d\n", status); + goto out; + } + + AcquireSRWLockShared(&client->exid_lock); + if (client->roles & (EXCHGID4_FLAG_USE_PNFS_MDS | + EXCHGID4_FLAG_USE_NON_PNFS)) + session->flags |= CREATE_SESSION4_FLAG_CONN_BACK_CHAN; + ReleaseSRWLockShared(&client->exid_lock); + + status = nfs41_create_session(client, session); + if (status) { + eprintf("nfs41_create_session failed %d\n", status); + status = ERROR_BAD_NET_RESP; + goto out_err; + } + + AcquireSRWLockExclusive(&session->client->session_lock); + client->session = session; + session->isValidState = TRUE; + ReleaseSRWLockExclusive(&session->client->session_lock); + *session_out = session; +out: + return status; + +out_err: + nfs41_session_free(session); + goto out; +} + +/* session renewal */ +int nfs41_session_renew( + IN nfs41_session *session) +{ + int status; + + AcquireSRWLockExclusive(&session->client->session_lock); + status = reinit_slot_table(&session->table); + if (status) { + eprintf("init_slot_table failed %d\n", status); + goto out_err_session; + } + status = nfs41_create_session(session->client, session); + if (status && status != NFS4ERR_STALE_CLIENTID) { + eprintf("nfs41_create_session failed %d\n", status); + status = ERROR_BAD_NET_RESP; + goto out_err_slot; + } + ReleaseSRWLockExclusive(&session->client->session_lock); +out: + return status; +out_err_slot: + free_slot_table(&session->table); +out_err_session: + ReleaseSRWLockExclusive(&session->client->session_lock); + free(session); + goto out; +} + +int nfs41_session_set_lease( + IN nfs41_session *session, + IN uint32_t lease_time) +{ + int status = NO_ERROR; + uint32_t thread_id; + + if (valid_handle(session->renew_thread)) { + eprintf("nfs41_session_set_lease(): session " + "renewal thread already started!\n"); + goto out; + } + + if (lease_time == 0) { + eprintf("nfs41_session_set_lease(): invalid lease_time=0\n"); + status = ERROR_INVALID_PARAMETER; + goto out; + } + + session->lease_time = lease_time; + session->renew_thread = (HANDLE)_beginthreadex(NULL, + 0, renew_session, session, 0, &thread_id); + if (!valid_handle(session->renew_thread)) { + status = GetLastError(); + eprintf("_beginthreadex failed %d\n", status); + goto out; + } +out: + return status; +} + +void nfs41_session_free( + IN nfs41_session *session) +{ + AcquireSRWLockExclusive(&session->client->session_lock); + if (valid_handle(session->renew_thread)) { + dprintf(1, "nfs41_session_free: terminating session renewal thread\n"); + if (!TerminateThread(session->renew_thread, NO_ERROR)) + eprintf("failed to terminate renewal thread %p\n", + session->renew_thread); + } + + if (session->isValidState) { + session->client->rpc->is_valid_session = FALSE; + nfs41_destroy_session(session); + } + free_slot_table(&session->table); + ReleaseSRWLockExclusive(&session->client->session_lock); + free(session); +} diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c new file mode 100644 index 0000000..38a13f9 --- /dev/null +++ b/daemon/nfs41_superblock.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "daemon_debug.h" +#include "nfs41.h" +#include "nfs41_ops.h" +#include "util.h" + + +#define SBLVL 3 /* dprintf level for superblock logging */ + + +static __inline int compare_fsid( + IN const nfs41_fsid *lhs, + IN const nfs41_fsid *rhs) +{ + if (lhs->major > rhs->major) return 1; + if (lhs->major < rhs->major) return -1; + if (lhs->minor > rhs->minor) return 1; + if (lhs->minor < rhs->minor) return -1; + return 0; +} + + +/* nfs41_superblock */ +static int superblock_create( + IN const nfs41_fsid *fsid, + OUT nfs41_superblock **superblock_out) +{ + int status = NO_ERROR; + nfs41_superblock *superblock; + + dprintf(SBLVL, "creating superblock for fsid(%llu,%llu)\n", + fsid->major, fsid->minor); + + superblock = calloc(1, sizeof(nfs41_superblock)); + if (superblock == NULL) { + status = GetLastError(); + eprintf("failed to allocate superblock " + "for fsid(%llu,%llu)\n", fsid->major, fsid->minor); + goto out; + } + + memcpy(&superblock->fsid, fsid, sizeof(nfs41_fsid)); + InitializeSRWLock(&superblock->lock); + + *superblock_out = superblock; +out: + return status; +} + +static void superblock_free( + IN nfs41_superblock *superblock) +{ + free(superblock); +} + +static int get_superblock_attrs( + IN nfs41_session *session, + IN nfs41_superblock *superblock, + IN nfs41_path_fh *file) +{ + int status; + bitmap4 attr_request; + nfs41_file_info info; + + attr_request.arr[0] = (uint32_t)(FATTR4_WORD0_SUPPORTED_ATTRS | + FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE); + attr_request.arr[1] = FATTR4_WORD1_FS_LAYOUT_TYPE; + attr_request.count = 2; + + ZeroMemory(&info, sizeof(info)); + info.supported_attrs = &superblock->supported_attrs; + + status = nfs41_getattr(session, file, &attr_request, &info); + if (status) { + eprintf("nfs41_getattr() failed with %s when " + "fetching attributes for fsid(%llu,%llu)\n", + nfs_error_string(status), + superblock->fsid.major, superblock->fsid.minor); + goto out; + } + + if (info.maxread) + superblock->maxread = info.maxread; + else + superblock->maxread = session->fore_chan_attrs.ca_maxresponsesize; + + if (info.maxwrite) + superblock->maxwrite = info.maxwrite; + else + superblock->maxwrite = session->fore_chan_attrs.ca_maxrequestsize; + + superblock->layout_types = info.fs_layout_types; + + dprintf(SBLVL, "attributes for fsid(%llu,%llu): " + "maxread=%llu, maxwrite=%llu, layout_types: 0x%X\n", + superblock->fsid.major, superblock->fsid.minor, + superblock->maxread, superblock->maxwrite, + superblock->layout_types); +out: + return status; +} + + +/* nfs41_superblock_list */ +#define superblock_entry(pos) list_container(pos, nfs41_superblock, entry) + +static int superblock_compare( + const struct list_entry *entry, + const void *value) +{ + const nfs41_superblock *superblock = superblock_entry(entry); + return compare_fsid(&superblock->fsid, (const nfs41_fsid*)value); +} + +static nfs41_superblock* find_superblock( + IN nfs41_superblock_list *superblocks, + IN const nfs41_fsid *fsid) +{ + struct list_entry *entry; + entry = list_search(&superblocks->head, fsid, superblock_compare); + return entry ? superblock_entry(entry) : NULL; +} + +void nfs41_superblock_list_init( + IN nfs41_superblock_list *superblocks) +{ + list_init(&superblocks->head); + InitializeSRWLock(&superblocks->lock); +} + +void nfs41_superblock_list_free( + IN nfs41_superblock_list *superblocks) +{ + struct list_entry *entry, *tmp; + + dprintf(SBLVL, "nfs41_superblock_list_free()\n"); + + list_for_each_tmp(entry, tmp, &superblocks->head) + superblock_free(superblock_entry(entry)); +} + + +int nfs41_superblock_for_fh( + IN nfs41_session *session, + IN const nfs41_fsid *fsid, + IN const nfs41_fh *parent OPTIONAL, + OUT nfs41_path_fh *file) +{ + int status = NFS4_OK; + nfs41_server *server = client_server(session->client); + nfs41_superblock_list *superblocks = &server->superblocks; + nfs41_superblock *superblock; + + dprintf(SBLVL, "--> nfs41_superblock_for_fh(fsid(%llu,%llu))\n", + fsid->major, fsid->minor); + + /* compare with the parent's fsid, and use that if it matches */ + if (parent && parent->superblock && + compare_fsid(fsid, &parent->superblock->fsid) == 0) { + file->fh.superblock = parent->superblock; + dprintf(SBLVL, "using superblock from parent\n"); + goto out; + } + + /* using a shared lock, search for an existing superblock */ + AcquireSRWLockShared(&superblocks->lock); + superblock = find_superblock(superblocks, fsid); + ReleaseSRWLockShared(&superblocks->lock); + + if (superblock) { + dprintf(SBLVL, "found existing superblock in server list " + "[shared lock]\n"); + } else { + AcquireSRWLockExclusive(&superblocks->lock); + /* must search again under an exclusive lock, in case another thread + * created it after our first search */ + superblock = find_superblock(superblocks, fsid); + if (superblock) { + dprintf(SBLVL, "found newly created superblock in server list " + "[exclusive lock]\n"); + } else { + /* create the superblock */ + status = superblock_create(fsid, &superblock); + if (status == NO_ERROR) /* add it to the list */ + list_add_tail(&superblocks->head, &superblock->entry); + } + ReleaseSRWLockExclusive(&superblocks->lock); + } + + if (status == NO_ERROR && superblock->supported_attrs.count == 0) { + /* exclusive lock on the superblock while fetching attributes */ + AcquireSRWLockExclusive(&superblock->lock); + if (superblock->supported_attrs.count == 0) + status = get_superblock_attrs(session, superblock, file); + ReleaseSRWLockExclusive(&superblock->lock); + } + + file->fh.superblock = superblock; +out: + dprintf(SBLVL, "<-- nfs41_superblock_for_fh() returning %p, status %d\n", + file->fh.superblock, status); + return status; +} diff --git a/daemon/nfs41_types.h b/daemon/nfs41_types.h new file mode 100644 index 0000000..b0e1fd4 --- /dev/null +++ b/daemon/nfs41_types.h @@ -0,0 +1,185 @@ +/* Copyright (c) 2010 +* The Regents of the University of Michigan +* All Rights Reserved +* +* Permission is granted to use, copy and redistribute this software +* for noncommercial education and research purposes, so long as no +* fee is charged, and so long as the name of the University of Michigan +* is not used in any advertising or publicity pertaining to the use +* or distribution of this software without specific, written prior +* authorization. Permission to modify or otherwise create derivative +* works of this software is not granted. +* +* This software is provided as is, without representation or warranty +* of any kind either express or implied, including without limitation +* the implied warranties of merchantability, fitness for a particular +* purpose, or noninfringement. The Regents of the University of +* Michigan shall not be liable for any damages, including special, +* indirect, incidental, or consequential damages, with respect to any +* claim arising out of or in connection with the use of the software, +* even if it has been or is hereafter advised of the possibility of +* such damages. +*/ + +#ifndef __NFS41_DAEMON_TYPES_H__ +#define __NFS41_DAEMON_TYPES_H__ + +#include "wintirpc.h" +#include "rpc/xdr.h" +#include "nfs41_const.h" + +typedef char* caddr_t; + +static const int64_t NFS4_INT64_MAX = 0x7fffffffffffffff; +static const uint64_t NFS4_UINT64_MAX = 0xffffffffffffffff; +static const int32_t NFS4_INT32_MAX = 0x7fffffff; +static const uint32_t NFS4_UINT32_MAX = 0xffffffff; + +static const uint64_t NFS4_MAXFILELEN = 0xffffffffffffffff; +static const uint64_t NFS4_MAXFILEOFF = 0xfffffffffffffffe; + + +/* common nfs types */ +typedef struct __nfs41_abs_path { + char path[NFS41_MAX_PATH_LEN]; + unsigned short len; + SRWLOCK lock; +} nfs41_abs_path; + +typedef struct __nfs41_component { + const char *name; + unsigned short len; +} nfs41_component; + +typedef struct __nfs41_fh { + unsigned char fh[NFS4_FHSIZE]; + uint32_t len; + uint64_t fileid; + struct __nfs41_superblock *superblock; +} nfs41_fh; + +typedef struct __nfs41_path_fh { + nfs41_abs_path *path; + nfs41_component name; + nfs41_fh fh; +} nfs41_path_fh; + +typedef struct __nfs41_fsid { + uint64_t major; + uint64_t minor; +} nfs41_fsid; + +typedef struct __netaddr4 { + char netid[NFS41_NETWORK_ID_LEN+1]; + char uaddr[NFS41_UNIVERSAL_ADDR_LEN+1]; +} netaddr4; + +typedef struct __multi_addr4 { + netaddr4 arr[NFS41_ADDRS_PER_SERVER]; + uint32_t count; +} multi_addr4; + +typedef struct __bitmap4 { + uint32_t count; + uint32_t arr[3]; +} bitmap4; + +typedef struct __nfstime4 { + int64_t seconds; + uint32_t nseconds; +} nfstime4; + +typedef struct __client_owner4 { + unsigned char co_verifier[NFS4_VERIFIER_SIZE]; + uint32_t co_ownerid_len; + unsigned char co_ownerid[NFS4_OPAQUE_LIMIT]; +} client_owner4; + +typedef struct __server_owner4 { + uint64_t so_minor_id; + uint32_t so_major_id_len; + char so_major_id[NFS4_OPAQUE_LIMIT]; +} server_owner4; + +typedef struct __state_owner4 { + uint32_t owner_len; + unsigned char owner[NFS4_OPAQUE_LIMIT]; +} state_owner4; + +typedef struct __nfs_impl_id4 { + uint32_t nii_domain_len; + unsigned char *nii_domain; + uint32_t nii_name_len; + unsigned char *nii_name; + nfstime4 nii_date; +} nfs_impl_id4; + +typedef struct __nfsace4 { + uint32_t acetype; + uint32_t aceflag; + uint32_t acemask; + unsigned char who[NFS4_OPAQUE_LIMIT]; +} nfsace4; + +typedef struct __stateid4 { + uint32_t seqid; + unsigned char other[12]; +} stateid4; + +typedef struct __fattr4 { + bitmap4 attrmask; + uint32_t attr_vals_len; + unsigned char attr_vals[NFS4_OPAQUE_LIMIT]; +} fattr4; + +typedef struct __change_info4 { + bool_t atomic; + uint64_t before; + uint64_t after; +} change_info4; + +typedef struct __fs_location_server { + /* 'address' represents one of a traditional DNS host name, + * IPv4 address, IPv6 address, or a zero-length string */ + char address[NFS41_HOSTNAME_LEN+1]; +} fs_location_server; + +typedef struct __fs_location4 { + nfs41_abs_path path; /* path to fs from referred server's root */ + fs_location_server *servers; + uint32_t server_count; +} fs_location4; + +typedef struct __fs_locations4 { + nfs41_abs_path path; /* path to fs from referring server's root */ + fs_location4 *locations; + uint32_t location_count; +} fs_locations4; + +typedef struct __nfs41_file_info { + nfs41_fsid fsid; + nfstime4 time_access; + nfstime4 time_create; + nfstime4 time_modify; + bitmap4 attrmask; + bitmap4 *supported_attrs; /* XXX: per-fs */ + uint64_t maxread; /* XXX: per-fs */ + uint64_t maxwrite; /* XXX: per-fs */ + uint64_t change; + uint64_t size; + uint64_t fileid; + uint64_t space_avail; /* XXX: per-fs */ + uint64_t space_free; /* XXX: per-fs */ + uint64_t space_total; /* XXX: per-fs */ + uint32_t type; + uint32_t numlinks; + uint32_t rdattr_error; + uint32_t mode; + uint32_t mode_mask; + fs_locations4 *fs_locations; /* XXX: per-fs */ + uint32_t lease_time; /* XXX: per-server */ + uint32_t fs_layout_types; /* pnfs, XXX: per-fs */ + bool_t hidden; +} nfs41_file_info; + +#endif /* !__NFS41_DAEMON_TYPES_H__ */ diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c new file mode 100644 index 0000000..2fd2634 --- /dev/null +++ b/daemon/nfs41_xdr.c @@ -0,0 +1,3124 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "nfs41_compound.h" +#include "nfs41_ops.h" +#include "nfs41_xdr.h" +#include "daemon_debug.h" + +static bool_t encode_file_attrs( + fattr4 *attrs, + nfs41_file_info *info); + +static __inline int unexpected_op(uint32_t op, uint32_t expected) +{ + if (op == expected) + return 0; + + eprintf("Op table mismatch. Got %s (%d), expected %s (%d).\n", + nfs_opnum_to_string(op), op, + nfs_opnum_to_string(expected), expected); + return 1; +} + +/* typedef uint32_t bitmap4<> */ +static bool_t xdr_bitmap4( + XDR *xdr, + bitmap4 *bitmap) +{ + uint32_t i; + + if (xdr->x_op == XDR_ENCODE) { + if (bitmap->count > 3) { + eprintf("encode_bitmap4: count (%d) must be <= 3\n", + bitmap->count); + return FALSE; + } + if (!xdr_u_int32_t(xdr, &bitmap->count)) + return FALSE; + + for (i = 0; i < bitmap->count; i++) + if (!xdr_u_int32_t(xdr, &bitmap->arr[i])) + return FALSE; + + } else if (xdr->x_op == XDR_DECODE) { + if (!xdr_u_int32_t(xdr, &bitmap->count)) + return FALSE; + if (bitmap->count > 3) { + eprintf("decode_bitmap4: count (%d) must be <= 3\n", + bitmap->count); + return FALSE; + } + + for (i = 0; i < bitmap->count; i++) + if (!xdr_u_int32_t(xdr, &bitmap->arr[i])) + return FALSE; + } else + return FALSE; + + return TRUE; +} + +/* nfstime4 */ +static bool_t xdr_nfstime4( + XDR *xdr, + nfstime4 *nt) +{ + if (!xdr_hyper(xdr, &nt->seconds)) + return FALSE; + + return xdr_u_int32_t(xdr, &nt->nseconds); +} + + +/* settime4 */ +static bool_t xdr_settime4( + XDR *xdr, + nfstime4 *nt) +{ + if (xdr->x_op == XDR_ENCODE) { + uint32_t send_value = SET_TO_CLIENT_TIME4; + if (!xdr_u_int32_t(xdr, &send_value)) + return FALSE; + } else if (xdr->x_op == XDR_DECODE) { + uint32_t ignored_value; + if (!xdr_u_int32_t(xdr, &ignored_value)) + return FALSE; + } else + return FALSE; + + return xdr_nfstime4(xdr, nt); +} + +/* stateid4 */ +static bool_t xdr_stateid4( + XDR *xdr, + stateid4 *si) +{ + if (!xdr_u_int32_t(xdr, &si->seqid)) + return FALSE; + + return xdr_opaque(xdr, (char *)si->other, 12); +} + +/* fattr4 */ +static bool_t xdr_fattr4( + XDR *xdr, + fattr4 *fattr) +{ + unsigned char *attr_vals = fattr->attr_vals; + + if (!xdr_bitmap4(xdr, &fattr->attrmask)) + return FALSE; + + return xdr_bytes(xdr, (char **)&attr_vals, &fattr->attr_vals_len, NFS4_OPAQUE_LIMIT); +} + +/* nfs41_fh */ +static bool_t xdr_fh( + XDR *xdr, + nfs41_fh *fh) +{ + unsigned char *pfh = fh->fh; + return xdr_bytes(xdr, (char **)&pfh, &fh->len, NFS4_FHSIZE); +} + +/* nfs41_fsid */ +static bool_t xdr_fsid( + XDR *xdr, + nfs41_fsid *fsid) +{ + if (!xdr_u_hyper(xdr, &fsid->major)) + return FALSE; + + return xdr_u_hyper(xdr, &fsid->minor); +} + + +/* nfs41_component */ +static bool_t encode_component( + XDR *xdr, + const nfs41_component *component) +{ + uint32_t len = component->len; + return xdr_bytes(xdr, (char **)&component->name, &len, NFS4_OPAQUE_LIMIT); +} + +static bool_t decode_component( + XDR *xdr, + nfs41_component *component) +{ + bool_t result; + uint32_t len; + + result = xdr_bytes(xdr, (char **)&component->name, &len, NFS4_OPAQUE_LIMIT); + component->len = (result == FALSE) ? 0 : (unsigned short)len; + return result; +} + + +/* state_owner4 */ +static bool_t xdr_state_owner4( + XDR *xdr, + state_owner4 *so) +{ + u_quad_t clientid = 0; + unsigned char *owner = so->owner; + + /* 18.16.3. "The client can set the clientid field to any value and + * the server MUST ignore it. Instead the server MUST derive the + * client ID from the session ID of the SEQUENCE operation of the + * COMPOUND request. */ + if (xdr->x_op == XDR_ENCODE) { + if (!xdr_u_hyper(xdr, &clientid)) /* clientid = 0 */ + return FALSE; + } else if (xdr->x_op == XDR_DECODE) { + if (!xdr_u_hyper(xdr, &clientid)) + return FALSE; + } else return FALSE; + + return xdr_bytes(xdr, (char **)&owner, &so->owner_len, NFS4_OPAQUE_LIMIT); +} + +static bool_t xdr_layout_types( + XDR *xdr, + uint32_t *layout_type) +{ + u_int32_t i, count, type; + + if (xdr->x_op != XDR_DECODE) { + eprintf("xdr_layout_types: xdr->x_op is not XDR_DECODE! " + "x_op %d not supported.\n", xdr->x_op); + return FALSE; + } + + *layout_type = 0; + + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + for (i = 0; i < count; i++) { + if (!xdr_u_int32_t(xdr, &type)) + return FALSE; + + *layout_type |= 1 << (type - 1); + } + return TRUE; +} + +/* pathname4 + * decode a variable array of components into a nfs41_abs_path */ +static bool_t decode_pathname4( + XDR *xdr, + nfs41_abs_path *path) +{ + char *pos; + u_int32_t i, count, len, remaining; + + /* decode the number of components */ + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + pos = (char *)path->path; + remaining = NFS41_MAX_PATH_LEN; + + /* decode each component */ + for (i = 0; i < count; i++) { + len = remaining; + if (!xdr_bytes(xdr, (char **)&pos, &len, NFS41_MAX_PATH_LEN)) + return FALSE; + remaining -= len; + pos += len; + + if (i < count-1) { /* add a \ between components */ + if (remaining < 1) + return FALSE; + *pos++ = '\\'; + remaining--; + } + } + path->len = (unsigned short)(NFS41_MAX_PATH_LEN - remaining); + return TRUE; +} + +/* fs_location4 */ +static bool_t decode_fs_location4( + XDR *xdr, + fs_location4 *location) +{ + fs_location_server *arr; + char *address; + u_int32_t i, count, len; + + /* decode the number of servers */ + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + /* allocate the fs_location_server array */ + if (count == 0) { + free(location->servers); + arr = NULL; + } else if (count != location->server_count) { + arr = realloc(location->servers, count * sizeof(fs_location_server)); + if (arr == NULL) + return FALSE; + ZeroMemory(arr, count * sizeof(fs_location_server)); + } else { + arr = location->servers; + } + + location->servers = arr; + location->server_count = count; + + for (i = 0; i < count; i++) { + len = NFS41_HOSTNAME_LEN; + address = arr[i].address; + if (!xdr_bytes(xdr, &address, &len, NFS41_HOSTNAME_LEN)) { + free(arr); + return FALSE; + } + arr[i].address[len] = '\0'; + } + + return decode_pathname4(xdr, &location->path); +} + +/* fs_locations4 */ +static bool_t decode_fs_locations4( + XDR *xdr, + fs_locations4 *locations) +{ + u_int32_t i, count; + fs_location4 *arr; + + if (!decode_pathname4(xdr, &locations->path)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + /* allocate the fs_location array */ + if (count == 0) { + free(locations->locations); + arr = NULL; + } else if (count != locations->location_count) { + arr = realloc(locations->locations, count * sizeof(fs_location4)); + if (arr == NULL) + return FALSE; + ZeroMemory(arr, count * sizeof(fs_location4)); + } else { + arr = locations->locations; + } + + locations->locations = arr; + locations->location_count = count; + + for (i = 0; i < count; i++) { + if (!decode_fs_location4(xdr, &arr[i])) { + free(arr); + return FALSE; + } + } + return TRUE; +} + +/* + * OP_EXCHANGE_ID + */ +static bool_t xdr_client_owner4( + XDR *xdr, + client_owner4 *co) +{ + unsigned char *co_ownerid = co->co_ownerid; + if (!xdr_opaque(xdr, (char *)&co->co_verifier[0], NFS4_VERIFIER_SIZE)) + return FALSE; + + return xdr_bytes(xdr, (char **)&co_ownerid, &co->co_ownerid_len, NFS4_OPAQUE_LIMIT); +} + +#if 0 +static bool_t encode_state_protect_ops4( + XDR *xdr, + state_protect_ops4 *spo) +{ + if (!xdr_bitmap4(xdr, &spo->spo_must_enforce)) + return FALSE; + + return xdr_bitmap4(xdr, &spo->spo_must_allow); +} + +static bool_t encode_ssv_sp_parms4( + XDR *xdr, + ssv_sp_parms4 *spp) +{ + if (!encode_state_protect_ops4(xdr, &spp->ssp_ops)) + return FALSE; + + if (!xdr_bytes(xdr, &spp->ssp_hash_algs, + &spp->ssp_hash_algs_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + if (!xdr_bytes(xdr, &spp->ssp_encr_algs, + &spp->ssp_encr_algs_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &spp->ssp_window)) + return FALSE; + + return xdr_u_int32_t(xdr, &spp->ssp_num_gss_handles); +} +#endif + +static bool_t xdr_state_protect4_a( + XDR *xdr, + state_protect4_a *spa) +{ + bool_t result = TRUE; + + if (!xdr_u_int32_t(xdr, (u_int32_t *)&spa->spa_how)) + return FALSE; + + switch (spa->spa_how) + { + case SP4_NONE: + break; +#if 0 + case SP4_MACH_CRED: + result = xdr_state_protect_ops4(xdr, &spa->u.spa_mach_ops); + break; + case SP4_SSV: + result = xdr_ssv_sp_parms4(xdr, &spa->u.spa_ssv_parms); + break; +#endif + default: + eprintf("encode_state_protect4_a: state protect " + "type %d not supported.\n", spa->spa_how); + result = FALSE; + break; + } + return result; +} + +static bool_t xdr_nfs_impl_id4( + XDR *xdr, + nfs_impl_id4 *nii) +{ + unsigned char *nii_domain = nii->nii_domain; + unsigned char *nii_name = nii->nii_name; + + if (!xdr_bytes(xdr, (char **)&nii_domain, &nii->nii_domain_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + if (!xdr_bytes(xdr, (char **)&nii_name, &nii->nii_name_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + return xdr_nfstime4(xdr, &nii->nii_date); +} + + +static bool_t encode_op_exchange_id( + XDR *xdr, + nfs_argop4 *argop) +{ + uint32_t zero = 0; + uint32_t one = 1; + + nfs41_exchange_id_args *args = (nfs41_exchange_id_args*)argop->arg; + + if (unexpected_op(argop->op, OP_EXCHANGE_ID)) + return FALSE; + + if (!xdr_client_owner4(xdr, args->eia_clientowner)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->eia_flags)) + return FALSE; + + if (!xdr_state_protect4_a(xdr, &args->eia_state_protect)) + return FALSE; + + if (args->eia_client_impl_id) + { + if (!xdr_u_int32_t(xdr, &one)) + return FALSE; + return xdr_nfs_impl_id4(xdr, args->eia_client_impl_id); + } + else + return xdr_u_int32_t(xdr, &zero); +} + +#if 0 + +static bool_t decode_state_protect_ops4( + XDR *xdr, + state_protect_ops4 *spo) +{ + if (!xdr_bitmap4(xdr, &spo->spo_must_enforce)) + return FALSE; + + return xdr_bitmap4(xdr, &spo->spo_must_allow); +} + +static bool_t decode_ssv_prot_info4( + XDR *xdr, + ssv_prot_info4 *spi) +{ +/* uint32_t i; */ + + if (!decode_state_protect_ops4(xdr, &spi->spi_ops)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &spi->spi_hash_alg)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &spi->spi_encr_alg)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &spi->spi_ssv_len)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &spi->spi_window)) + return FALSE; + +/* TODO: spi->spi_handles */ + return xdr_u_int32_t(xdr, 0); + /* + if (!xdr_u_int32_t(xdr, &spi->spi_handles.count)) + return FALSE; + + for (i = 0; i < spi->spi_handles.count; i++) + if (!xdr_opaque(xdr, &spi->spi_handles.arr[i]) + return FALSE; +*/ + return TRUE; +} +#endif + +static bool_t xdr_state_protect4_r( + XDR *xdr, + state_protect4_r *spr) +{ + bool_t result = TRUE; + + if (!xdr_u_int32_t(xdr, (uint32_t *)&spr->spr_how)) + return FALSE; + + switch (spr->spr_how) + { + case SP4_NONE: + break; +#if 0 + case SP4_MACH_CRED: + result = decode_state_protect_ops4(xdr, &spr->u.spr_mach_ops); + break; + case SP4_SSV: + result = decode_ssv_prot_info4(xdr, &spr->u.spr_ssv_info); + break; +#endif + default: + eprintf("decode_state_protect4_r: state protect " + "type %d not supported.\n", spr->spr_how); + result = FALSE; + break; + } + return result; +} + +static bool_t xdr_server_owner4( + XDR *xdr, + server_owner4 *so) +{ + char *so_major_id = so->so_major_id; + + if (!xdr_u_hyper(xdr, &so->so_minor_id)) + return FALSE; + + return xdr_bytes(xdr, (char **)&so_major_id, + &so->so_major_id_len, NFS4_OPAQUE_LIMIT); +} + +static bool_t decode_op_exchange_id( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_exchange_id_res *res = (nfs41_exchange_id_res*)resop->res; + char *server_scope = (char *)res->server_scope; + + if (unexpected_op(resop->op, OP_EXCHANGE_ID)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status != NFS4_OK) + return TRUE; + + if (!xdr_u_hyper(xdr, &res->clientid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->sequenceid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->flags)) + return FALSE; + + if (!xdr_state_protect4_r(xdr, &res->state_protect)) + return FALSE; + + if (!xdr_server_owner4(xdr, &res->server_owner)) + return FALSE; + + return xdr_bytes(xdr, &server_scope, + &res->server_scope_len, NFS4_OPAQUE_LIMIT); +} + +/* + * OP_CREATE_SESSION + */ +static bool_t xdr_channel_attrs4( + XDR *xdr, + nfs41_channel_attrs *attrs) +{ + uint32_t zero = 0; + uint32_t one = 1; + + /* count4 ca_headerpadsize */ + if (!xdr_u_int32_t(xdr, &attrs->ca_headerpadsize)) + return FALSE; + + /* count4 ca_maxrequestsize */ + if (!xdr_u_int32_t(xdr, &attrs->ca_maxrequestsize)) + return FALSE; + + /* count4 ca_maxresponsesize */ + if (!xdr_u_int32_t(xdr, &attrs->ca_maxresponsesize)) + return FALSE; + + /* count4 ca_maxresponsesize_cached */ + if (!xdr_u_int32_t(xdr, &attrs->ca_maxresponsesize_cached)) + return FALSE; + + /* count4 ca_maxoperations */ + if (!xdr_u_int32_t(xdr, &attrs->ca_maxoperations)) + return FALSE; + + /* count4 ca_maxrequests */ + if (!xdr_u_int32_t(xdr, &attrs->ca_maxrequests)) + return FALSE; + + if (xdr->x_op == XDR_ENCODE) { + /* uint32_t ca_rdma_ird<1> */ + if (attrs->ca_rdma_ird) + { + if (!xdr_u_int32_t(xdr, &one)) + return FALSE; + return xdr_u_int32_t(xdr, attrs->ca_rdma_ird); + } + else { + return xdr_u_int32_t(xdr, &zero); + } + } + else if (xdr->x_op == XDR_DECODE) { +#if 0 + u_int32_t count; + /* uint32_t ca_rdma_ird<1> */ + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + if (count > 1) + return FALSE; + if (count) + return xdr_u_int32_t(xdr, attrs->ca_rdma_ird); + else +#endif + return TRUE; + } + else { + eprintf("%s: xdr->x_op %d not supported.\n", + "xdr_channel_attrs4", xdr->x_op); + return FALSE; + } +} + + +static bool_t encode_op_create_session( + XDR *xdr, + nfs_argop4 *argop) +{ + uint32_t zero = 0; + nfs41_create_session_args *args = (nfs41_create_session_args*)argop->arg; + + if (unexpected_op(argop->op, OP_CREATE_SESSION)) + return FALSE; + + /* clientid4 csa_clientid */ + if (!xdr_u_hyper(xdr, &args->csa_clientid)) + return FALSE; + + /* sequenceid4 csa_sequence */ + if (!xdr_u_int32_t(xdr, &args->csa_sequence)) + return FALSE; + + /* TODO: uint32_t csa_flags = 0 */ + if (!xdr_u_int32_t(xdr, &args->csa_flags)) + return FALSE; + + /* channel_attrs4 csa_fore_chan_attrs */ + if (!xdr_channel_attrs4(xdr, &args->csa_fore_chan_attrs)) + return FALSE; + + /* channel_attrs4 csa_back_chan_attrs */ + if (!xdr_channel_attrs4(xdr, &args->csa_back_chan_attrs)) + return FALSE; + + /* TODO: uint32_t csa_cb_program = 1234 */ + if (!xdr_u_int32_t(xdr, &args->csa_cb_program)) + return FALSE; + + /* TODO: callback_sec_parms4 csa_sec_parms<> = {} */ + return xdr_u_int32_t(xdr, &zero); +} + +static bool_t decode_op_create_session( + XDR *xdr, + nfs_resop4 *resop) +{ + uint32_t opstatus; + nfs41_create_session_res *res = (nfs41_create_session_res*)resop->res; + + if (unexpected_op(resop->op, OP_CREATE_SESSION)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &opstatus)) + return FALSE; + + if (opstatus != NFS4_OK) + return TRUE; + + if (!xdr_opaque(xdr, (char *)res->csr_sessionid, NFS4_SESSIONID_SIZE)) + return FALSE; + + /* sequenceid4 csr_sequence */ + if (!xdr_u_int32_t(xdr, &res->csr_sequence)) + return FALSE; + + /* uint32_t csr_flags */ + if (!xdr_u_int32_t(xdr, &res->csr_flags)) + return FALSE; + + /* channel_attrs4 csr_fore_chan_attrs */ + if (!xdr_channel_attrs4(xdr, res->csr_fore_chan_attrs)) + return FALSE; + + /* channel_attrs4 csr_back_chan_attrs */ + return xdr_channel_attrs4(xdr, res->csr_back_chan_attrs); +} + + +/* + * OP_BIND_CONN_TO_SESSION + */ +static bool_t encode_op_bind_conn_to_session( + XDR *xdr, + nfs_argop4 *argop) +{ + uint32_t zero = 0; + + nfs41_bind_conn_to_session_args *args = + (nfs41_bind_conn_to_session_args*)argop->arg; + + if (unexpected_op(argop->op, OP_BIND_CONN_TO_SESSION)) + return FALSE; + + if (!xdr_opaque(xdr, (char *)args->sessionid, NFS4_SESSIONID_SIZE)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&args->dir)) + return FALSE; + + return xdr_u_int32_t(xdr, &zero); /* bctsa_use_conn_in_rdma_mode = false */ +} + +static bool_t decode_op_bind_conn_to_session( + XDR *xdr, + nfs_resop4 *resop) +{ + unsigned char sessionid_ignored[NFS4_SESSIONID_SIZE]; + nfs41_bind_conn_to_session_res *res = + (nfs41_bind_conn_to_session_res*)resop->res; + bool_t use_rdma_ignored; + + if (unexpected_op(resop->op, OP_BIND_CONN_TO_SESSION)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&res->status)) + return FALSE; + + if (res->status == NFS4_OK) { + if (!xdr_opaque(xdr, (char *)&sessionid_ignored, NFS4_SESSIONID_SIZE)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&res->dir)) + return FALSE; + + return xdr_bool(xdr, &use_rdma_ignored); + } + return TRUE; +} + + +/* + * OP_DESTROY_SESSION + */ +static bool_t encode_op_destroy_session( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_destroy_session_args *args = (nfs41_destroy_session_args*)argop->arg; + + if (unexpected_op(argop->op, OP_DESTROY_SESSION)) + return FALSE; + + return xdr_opaque(xdr, (char *)args->dsa_sessionid, NFS4_SESSIONID_SIZE); +} + +static bool_t decode_op_destroy_session( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_destroy_session_res *res = (nfs41_destroy_session_res*)resop->res; + + if (unexpected_op(resop->op, OP_DESTROY_SESSION)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->dsr_status); +} + + +/* + * OP_SEQUENCE + */ +static bool_t encode_op_sequence( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_sequence_args *args = (nfs41_sequence_args*)argop->arg; + + if (unexpected_op(argop->op, OP_SEQUENCE)) + return FALSE; + + if (!xdr_opaque(xdr, (char *)args->sa_sessionid, NFS4_SESSIONID_SIZE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->sa_sequenceid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->sa_slotid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->sa_highest_slotid)) + return FALSE; + + return xdr_bool(xdr, &args->sa_cachethis); +} + +static bool_t xdr_sequence_res_ok( + XDR *xdr, + nfs41_sequence_res_ok *res) +{ + if (!xdr_opaque(xdr, (char *)res->sr_sessionid, NFS4_SESSIONID_SIZE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->sr_sequenceid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->sr_slotid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->sr_highest_slotid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->sr_target_highest_slotid)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->sr_status_flags); +} + +static bool_t decode_op_sequence( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_sequence_res *res = (nfs41_sequence_res*)resop->res; + + if (unexpected_op(resop->op, OP_SEQUENCE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->sr_status)) + return FALSE; + + if (res->sr_status == NFS4_OK) + return xdr_sequence_res_ok(xdr, &res->sr_resok4); + + return TRUE; +} + + +/* + * OP_RECLAIM_COMPLETE + */ +static bool_t encode_op_reclaim_complete( + XDR *xdr, + nfs_argop4 *argop) +{ + bool_t zero = FALSE; + + if (unexpected_op(argop->op, OP_RECLAIM_COMPLETE)) + return FALSE; + + /* rca_one_fs = 0 indicates that the reclaim applies to all filesystems */ + return xdr_bool(xdr, &zero); +} + +static bool_t decode_op_reclaim_complete( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_reclaim_complete_res *res = (nfs41_reclaim_complete_res*)resop->res; + + if (unexpected_op(resop->op, OP_RECLAIM_COMPLETE)) + return FALSE; + + return xdr_enum(xdr, (enum_t *)&res->status); +} + + +/* + * OP_PUTFH + */ +static bool_t encode_op_putfh( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_putfh_args *args = (nfs41_putfh_args*)argop->arg; + + if (unexpected_op(argop->op, OP_PUTFH)) + return FALSE; + + return xdr_fh(xdr, &args->file->fh); +} + +static bool_t decode_op_putfh( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_putfh_res *res = (nfs41_putfh_res*)resop->res; + + if (unexpected_op(resop->op, OP_PUTFH)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + +/* + * OP_PUTROOTFH + */ +static bool_t encode_op_putrootfh( + XDR *xdr, + nfs_argop4* argop) +{ + if (unexpected_op(argop->op, OP_PUTROOTFH)) + return FALSE; + /* void */ + return TRUE; +} + +static bool_t decode_op_putrootfh( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_putrootfh_res *res = (nfs41_putrootfh_res*)resop->res; + + if (unexpected_op(resop->op, OP_PUTROOTFH)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + +/* + * OP_GETFH + */ +static bool_t encode_op_getfh( + XDR *xdr, + nfs_argop4 *argop) +{ + if (unexpected_op(argop->op, OP_GETFH)) + return FALSE; + + /* void */ + return TRUE; +} + +static bool_t decode_op_getfh( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_getfh_res *res = (nfs41_getfh_res*)resop->res; + + if (unexpected_op(resop->op, OP_GETFH)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_fh(xdr, res->fh); + + return TRUE; +} + + +/* + * OP_LOOKUP + */ +static bool_t encode_op_lookup( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_lookup_args *args = (nfs41_lookup_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LOOKUP)) + return FALSE; + + return encode_component(xdr, args->name); +} + +static bool_t decode_op_lookup( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_lookup_res *res = (nfs41_lookup_res*)resop->res; + + if (unexpected_op(resop->op, OP_LOOKUP)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + +/* + * OP_ACCESS + */ +static bool_t encode_op_access( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_access_args *args = (nfs41_access_args*)argop->arg; + + if (unexpected_op(argop->op, OP_ACCESS)) + return FALSE; + + return xdr_u_int32_t(xdr, &args->access); +} + +static bool_t decode_op_access( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_access_res *res = (nfs41_access_res*)resop->res; + + if (unexpected_op(resop->op, OP_ACCESS)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + { + if (!xdr_u_int32_t(xdr, &res->supported)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->access); + } + return TRUE; +} + + +/* + * OP_CLOSE + */ +static bool_t encode_op_close( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_op_close_args *args = (nfs41_op_close_args*)argop->arg; + uint32_t zero = 0; + + if (unexpected_op(argop->op, OP_CLOSE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &zero)) // This should be ignored by server + return FALSE; + + return xdr_stateid4(xdr, args->open_stateid); +} + +static bool_t decode_op_close( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_op_close_res *res = (nfs41_op_close_res*)resop->res; + + if (unexpected_op(resop->op, OP_CLOSE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_stateid4(xdr, &res->open_stateid); + + return TRUE; +} + + +/* + * OP_COMMIT + */ +static bool_t encode_op_commit( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_commit_args *args = (nfs41_commit_args*)argop->arg; + + if (unexpected_op(argop->op, OP_COMMIT)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + return xdr_u_int32_t(xdr, &args->count); +} + +static bool_t decode_op_commit( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_commit_res *res = (nfs41_commit_res*)resop->res; + + if (unexpected_op(resop->op, OP_COMMIT)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_opaque(xdr, (char *)res->writeverf, NFS4_VERIFIER_SIZE); + + return TRUE; +} + + +/* + * OP_CREATE + */ +static bool_t encode_createtype4( + XDR *xdr, + createtype4 *ct) +{ + bool_t result = TRUE; + char *linkdata; + + if (!xdr_u_int32_t(xdr, &ct->type)) + return FALSE; + + switch (ct->type) + { + case NF4LNK: + linkdata = ct->u.lnk.linkdata; + result = xdr_bytes(xdr, &linkdata, &ct->u.lnk.linkdata_len, + NFS4_OPAQUE_LIMIT); + break; + case NF4BLK: + case NF4CHR: + result = xdr_u_int32_t(xdr, &ct->u.devdata.specdata1); + if (result == TRUE) + result = xdr_u_int32_t(xdr, &ct->u.devdata.specdata2); + break; + default: + // Some types need no further action + break; + } + return result; +} + +static bool_t encode_createattrs4( + XDR *xdr, + createattrs4* createattrs) +{ + fattr4 attrs; + + /* encode attribute values from createattrs->info into attrs.attr_vals */ + attrs.attr_vals_len = NFS4_OPAQUE_LIMIT; + if (!encode_file_attrs(&attrs, &createattrs->info)) + return FALSE; + + return xdr_fattr4(xdr, &attrs); +} + +static bool_t encode_op_create( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_create_args *args = (nfs41_create_args*)argop->arg; + + if (unexpected_op(argop->op, OP_CREATE)) + return FALSE; + + if (!encode_createtype4(xdr, &args->objtype)) + return FALSE; + + if (!encode_component(xdr, args->name)) + return FALSE; + + return encode_createattrs4(xdr, &args->createattrs); +} + +static bool_t xdr_change_info4( + XDR *xdr, + change_info4 *cinfo) +{ + if (!xdr_bool(xdr, &cinfo->atomic)) + return FALSE; + + if (!xdr_u_hyper(xdr, &cinfo->before)) + return FALSE; + + return xdr_u_hyper(xdr, &cinfo->after); +} + +static bool_t decode_op_create( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_create_res *res = (nfs41_create_res*)resop->res; + + if (unexpected_op(resop->op, OP_CREATE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + { + if (!xdr_change_info4(xdr, &res->cinfo)) + return FALSE; + return xdr_bitmap4(xdr, &res->attrset); + } + return TRUE; +} + + +/* + * OP_LINK + */ +static bool_t encode_op_link( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_link_args *args = (nfs41_link_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LINK)) + return FALSE; + + return encode_component(xdr, args->newname); +} + +static bool_t decode_op_link( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_link_res *res = (nfs41_link_res*)resop->res; + + if (unexpected_op(resop->op, OP_LINK)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_change_info4(xdr, &res->cinfo); + + return TRUE; +} + + +/* + * OP_LOCK + */ +static bool_t xdr_locker4( + XDR *xdr, + locker4 *locker) +{ + if (xdr->x_op != XDR_ENCODE) { + eprintf("%s: xdr->x_op %d is not supported!\n", + "xdr_locker4", xdr->x_op); + return FALSE; + } + + if (!xdr_bool(xdr, &locker->new_lock_owner)) + return FALSE; + + if (locker->new_lock_owner) { + /* open_to_lock_owner4 open_owner */ + if (!xdr_u_int32_t(xdr, &locker->u.open_owner.open_seqid)) + return FALSE; + + if (!xdr_stateid4(xdr, locker->u.open_owner.open_stateid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &locker->u.open_owner.lock_seqid)) + return FALSE; + + return xdr_state_owner4(xdr, locker->u.open_owner.lock_owner); + } else { + /* exist_lock_owner4 lock_owner */ + if (!xdr_stateid4(xdr, locker->u.lock_owner.lock_stateid)) + return FALSE; + + return xdr_u_int32_t(xdr, &locker->u.lock_owner.lock_seqid); + } +} + +static bool_t encode_op_lock( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_lock_args *args = (nfs41_lock_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LOCK)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->locktype)) + return FALSE; + + if (!xdr_bool(xdr, &args->reclaim)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->length)) + return FALSE; + + return xdr_locker4(xdr, &args->locker); +} + +static bool_t decode_lock_res_denied( + XDR *xdr, + lock_res_denied *denied) +{ + if (!xdr_u_hyper(xdr, &denied->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &denied->length)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &denied->locktype)) + return FALSE; + + return xdr_state_owner4(xdr, &denied->owner); +} + +static bool_t decode_op_lock( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_lock_res *res = (nfs41_lock_res*)resop->res; + + if (unexpected_op(resop->op, OP_LOCK)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + switch (res->status) { + case NFS4_OK: + return xdr_stateid4(xdr, res->u.resok4.lock_stateid); + break; + case NFS4ERR_DENIED: + return decode_lock_res_denied(xdr, &res->u.denied); + break; + default: + break; + } + + return TRUE; +} + + +/* + * OP_LOCKT + */ +static bool_t encode_op_lockt( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_lockt_args *args = (nfs41_lockt_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LOCKT)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->locktype)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->length)) + return FALSE; + + return xdr_state_owner4(xdr, args->owner); +} + +static bool_t decode_op_lockt( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_lockt_res *res = (nfs41_lockt_res*)resop->res; + + if (unexpected_op(resop->op, OP_LOCKT)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4ERR_DENIED) + return decode_lock_res_denied(xdr, &res->denied); + + return TRUE; +} + + +/* + * OP_LOCKU + */ +static bool_t encode_op_locku( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_locku_args *args = (nfs41_locku_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LOCKU)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->locktype)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->seqid)) + return FALSE; + + if (!xdr_stateid4(xdr, args->lock_stateid)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + return xdr_u_hyper(xdr, &args->length); +} + +static bool_t decode_op_locku( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_locku_res *res = (nfs41_locku_res*)resop->res; + + if (unexpected_op(resop->op, OP_LOCKU)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_stateid4(xdr, res->lock_stateid); + + return TRUE; +} + + +/* + * OP_DELEGRETURN + */ +static bool_t encode_op_delegreturn( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_delegreturn_args *args = (nfs41_delegreturn_args*)argop->arg; + + if (unexpected_op(argop->op, OP_DELEGRETURN)) + return FALSE; + + return xdr_stateid4(xdr, args->stateid); +} + +static bool_t decode_op_delegreturn( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_delegreturn_res *res = (nfs41_delegreturn_res*)resop->res; + + if (unexpected_op(resop->op, OP_DELEGRETURN)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + +/* + * OP_GETATTR + */ +static bool_t encode_op_getattr( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_getattr_args *args = (nfs41_getattr_args*)argop->arg; + + if (unexpected_op(argop->op, OP_GETATTR)) + return FALSE; + + return xdr_bitmap4(xdr, args->attr_request); +} + +static bool_t decode_file_attrs( + XDR *xdr, + fattr4 *attrs, + nfs41_file_info *info) +{ + if (attrs->attrmask.count >= 1) { + if (attrs->attrmask.arr[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { + if (!xdr_bitmap4(xdr, info->supported_attrs)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_TYPE) { + if (!xdr_u_int32_t(xdr, &info->type)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_CHANGE) { + if (!xdr_u_hyper(xdr, &info->change)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_SIZE) { + if (!xdr_u_hyper(xdr, &info->size)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_FSID) { + if (!xdr_fsid(xdr, &info->fsid)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_LEASE_TIME) { + if (!xdr_u_int32_t(xdr, &info->lease_time)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_RDATTR_ERROR) { + if (!xdr_u_int32_t(xdr, &info->rdattr_error)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_FILEID) { + if (!xdr_u_hyper(xdr, &info->fileid)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_FS_LOCATIONS) { + if (!decode_fs_locations4(xdr, info->fs_locations)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_MAXREAD) { + if (!xdr_u_hyper(xdr, &info->maxread)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_MAXWRITE) { + if (!xdr_u_hyper(xdr, &info->maxwrite)) + return FALSE; + } + } + if (attrs->attrmask.count >= 2) { + if (attrs->attrmask.arr[1] & FATTR4_WORD1_MODE) { + if (!xdr_u_int32_t(xdr, &info->mode)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_NUMLINKS) { + if (!xdr_u_int32_t(xdr, &info->numlinks)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_SPACE_AVAIL) { + if (!xdr_u_hyper(xdr, &info->space_avail)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_SPACE_FREE) { + if (!xdr_u_hyper(xdr, &info->space_free)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_SPACE_TOTAL) { + if (!xdr_u_hyper(xdr, &info->space_total)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS) { + if (!xdr_nfstime4(xdr, &info->time_access)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_TIME_CREATE) { + if (!xdr_nfstime4(xdr, &info->time_create)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_TIME_MODIFY) { + if (!xdr_nfstime4(xdr, &info->time_modify)) + return FALSE; + } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_FS_LAYOUT_TYPE) { + if (!xdr_layout_types(xdr, &info->fs_layout_types)) + return FALSE; + } + } + return TRUE; +} + +static bool_t decode_op_getattr( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_getattr_res *res = (nfs41_getattr_res*)resop->res; + + if (unexpected_op(resop->op, OP_GETATTR)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + { + XDR attr_xdr; + + if (!xdr_fattr4(xdr, &res->obj_attributes)) + return FALSE; + xdrmem_create(&attr_xdr, (char *)res->obj_attributes.attr_vals, res->obj_attributes.attr_vals_len, XDR_DECODE); + return decode_file_attrs(&attr_xdr, &res->obj_attributes, res->info); + } + return TRUE; +} + + +/* + * OP_OPEN + */ +static bool_t encode_creatverfattr( + XDR *xdr, + creatverfattr *cva) +{ + if (!xdr_opaque(xdr, (char *)cva->cva_verf, NFS4_VERIFIER_SIZE)) + return FALSE; + + return xdr_fattr4(xdr, &cva->cva_attrs); +} + +static bool_t encode_createhow4( + XDR *xdr, + createhow4 *ch) +{ + bool_t result = TRUE; + + if (!xdr_u_int32_t(xdr, &ch->mode)) + return FALSE; + + switch (ch->mode) + { + case UNCHECKED4: + case GUARDED4: + result = encode_createattrs4(xdr, &ch->u.createattrs); + break; + case EXCLUSIVE4: + result = xdr_opaque(xdr, (char *)ch->u.createverf, NFS4_VERIFIER_SIZE); + break; + case EXCLUSIVE4_1: + result = encode_creatverfattr(xdr, &ch->u.ch_createboth); + break; + } + return result; +} + +static bool_t encode_openflag4( + XDR *xdr, + openflag4 *of) +{ + bool_t result = TRUE; + + if (!xdr_u_int32_t(xdr, &of->opentype)) + return FALSE; + + switch (of->opentype) + { + case OPEN4_CREATE: + result = encode_createhow4(xdr, &of->how); + break; + default: + break; + } + return result; +} + +static bool_t encode_open_claim4( + XDR *xdr, + open_claim4 *oc) +{ + bool_t result = TRUE; + + if (!xdr_u_int32_t(xdr, &oc->claim)) + return FALSE; + + switch (oc->claim) + { + case CLAIM_NULL: + result = encode_component(xdr, oc->u.null.filename); + break; + case CLAIM_FH: + /* use current file handle */ + break; + default: + eprintf("encode_open_claim4: unsupported claim %d.\n", + oc->claim); + result = FALSE; + break; + } + return result; +} + +static bool_t encode_op_open( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_op_open_args *args = (nfs41_op_open_args*)argop->arg; + + if (unexpected_op(argop->op, OP_OPEN)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->seqid)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->share_access)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->share_deny)) + return FALSE; + + if (!xdr_state_owner4(xdr, args->owner)) + return FALSE; + + if (!encode_openflag4(xdr, &args->openhow)) + return FALSE; + + return encode_open_claim4(xdr, &args->claim); +} + +static bool_t decode_open_none_delegation4( + XDR *xdr, + nfs41_op_open_res_ok *res) +{ + bool_t result = TRUE; + + if (!xdr_u_int32_t(xdr, &res->why_no_deleg)) + return FALSE; + switch (res->why_no_deleg) + { + case WND4_CONTENTION: + case WND4_RESOURCE: + result = xdr_u_int32_t(xdr, &res->why_none_flag); + break; + default: + break; + } + return result; +} + +static bool_t xdr_decode_nfsace4( + XDR *xdr, + nfsace4 *res) +{ + char *who = (char*)res->who; + uint32_t tmp; + + if (!xdr_u_int32_t(xdr, &tmp)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &tmp)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &tmp)) + return FALSE; + + return xdr_bytes(xdr, &who, &tmp, NFS4_OPAQUE_LIMIT); +} + +static bool_t decode_open_read_delegation4( + XDR *xdr, + nfs41_op_open_res_ok *res) +{ + bool_t tmp_bool; + nfsace4 tmp_nfsace; + + if (!xdr_stateid4(xdr, &res->deleg_stateid)) + return FALSE; + + if (!xdr_bool(xdr, &tmp_bool)) + return FALSE; + + return xdr_decode_nfsace4(xdr, &tmp_nfsace); +} + +static bool_t decode_modified_limit4( + XDR *xdr) +{ + uint32_t tmp; + + if (!xdr_u_int32_t(xdr, &tmp)) + return FALSE; + + return xdr_u_int32_t(xdr, &tmp); +} + +enum limit_by4 { + NFS_LIMIT_SIZE = 1, + NFS_LIMIT_BLOCKS = 2 +}; + +static bool_t decode_space_limit4( + XDR *xdr) +{ + uint32_t tmp_limitby; + uint64_t tmp_filesize; + + if (!xdr_u_int32_t(xdr, &tmp_limitby)) + return FALSE; + + switch (tmp_limitby) + { + case NFS_LIMIT_SIZE: + return xdr_u_hyper(xdr, &tmp_filesize); + break; + case NFS_LIMIT_BLOCKS: + return decode_modified_limit4(xdr); + break; + default: + eprintf("decode_space_limit4: limitby %d invalid\n", + tmp_limitby); + return FALSE; + break; + } +} + +static bool_t decode_open_write_delegation4( + XDR *xdr, + nfs41_op_open_res_ok *res) +{ + bool_t tmp_bool; + nfsace4 tmp_nfsace; + + if (!xdr_stateid4(xdr, &res->deleg_stateid)) + return FALSE; + + if (!xdr_bool(xdr, &tmp_bool)) + return FALSE; + + if (!decode_space_limit4(xdr)) + return FALSE; + + return xdr_decode_nfsace4(xdr, &tmp_nfsace); +} + +static bool_t decode_open_res_ok( + XDR *xdr, + nfs41_op_open_res_ok *res) +{ + bool_t result = TRUE; + + if (!xdr_stateid4(xdr, res->stateid)) + return FALSE; + + if (!xdr_change_info4(xdr, &res->cinfo)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->rflags)) + return FALSE; + + if (!xdr_bitmap4(xdr, &res->attrset)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->delegation_type)) + return FALSE; + + switch (res->delegation_type) + { + case OPEN_DELEGATE_NONE: + break; + case OPEN_DELEGATE_NONE_EXT: + result = decode_open_none_delegation4(xdr, res); + break; + case OPEN_DELEGATE_READ: + result = decode_open_read_delegation4(xdr, res); + break; + case OPEN_DELEGATE_WRITE: + result = decode_open_write_delegation4(xdr, res); + break; + default: + eprintf("decode_open_res_ok: delegation type %d not " + "supported.\n", res->delegation_type); + result = FALSE; + break; + } + return result; +} + +static bool_t decode_op_open( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_op_open_res *res = (nfs41_op_open_res*)resop->res; + + if (unexpected_op(resop->op, OP_OPEN)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return decode_open_res_ok(xdr, &res->resok4); + + return TRUE; +} + + +/* + * OP_READ + */ +static bool_t encode_op_read( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_read_args *args = (nfs41_read_args*)argop->arg; + + if (unexpected_op(argop->op, OP_READ)) + return FALSE; + + if (!xdr_stateid4(xdr, args->stateid)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + return xdr_u_int32_t(xdr, &args->count); +} + +static bool_t decode_read_res_ok( + XDR *xdr, + nfs41_read_res_ok *res) +{ + unsigned char *data = res->data; + + if (!xdr_bool(xdr, &res->eof)) + return FALSE; + + return xdr_bytes(xdr, (char **)&data, &res->data_len, NFS41_MAX_FILEIO_SIZE); +} + +static bool_t decode_op_read( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_read_res *res = (nfs41_read_res*)resop->res; + + if (unexpected_op(resop->op, OP_READ)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return decode_read_res_ok(xdr, &res->resok4); + + return TRUE; +} + + +/* + * OP_READDIR + */ +static bool_t encode_op_readdir( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_readdir_args *args = (nfs41_readdir_args*)argop->arg; + + if (unexpected_op(argop->op, OP_READDIR)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->cookie.cookie)) + return FALSE; + + if (!xdr_opaque(xdr, (char *)args->cookie.verf, NFS4_VERIFIER_SIZE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->dircount)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->maxcount)) + return FALSE; + + return xdr_bitmap4(xdr, args->attr_request); +} + +typedef struct __readdir_entry_iterator { + unsigned char *buf_pos; + uint32_t remaining_len; + uint32_t *last_entry_offset; + bool_t ignore_the_rest; + bool_t has_next_entry; +} readdir_entry_iterator; + +static bool_t decode_readdir_entry( + XDR *xdr, + readdir_entry_iterator *it) +{ + uint64_t cookie; + unsigned char name[NFS4_OPAQUE_LIMIT]; + unsigned char *nameptr = &name[0]; + uint32_t name_len, entry_len; + fattr4 attrs; + + /* decode into temporaries so we can determine if there's enough + * room in the buffer for this entry */ + name_len = NFS4_OPAQUE_LIMIT; + entry_len = (uint32_t)FIELD_OFFSET(nfs41_readdir_entry, name); + attrs.attr_vals_len = NFS4_OPAQUE_LIMIT; + + if (!xdr_u_hyper(xdr, &cookie)) + return FALSE; + + if (!xdr_bytes(xdr, (char **)&nameptr, &name_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + if (!xdr_fattr4(xdr, &attrs)) + return FALSE; + + if (!xdr_bool(xdr, &it->has_next_entry)) + return FALSE; + + if (it->ignore_the_rest) + return TRUE; + + name_len += 1; /* account for null terminator */ + if (entry_len + name_len <= it->remaining_len) + { + XDR fattr_xdr; + nfs41_readdir_entry *entry = (nfs41_readdir_entry*)it->buf_pos; + entry->cookie = cookie; + entry->name_len = name_len; + + if (it->has_next_entry) + entry->next_entry_offset = entry_len + name_len; + else + entry->next_entry_offset = 0; + + xdrmem_create(&fattr_xdr, (char *)attrs.attr_vals, attrs.attr_vals_len, XDR_DECODE); + if (!(decode_file_attrs(&fattr_xdr, &attrs, &entry->attr_info))) + entry->attr_info.rdattr_error = NFS4ERR_BADXDR; + StringCchCopyA(entry->name, name_len, (STRSAFE_LPCSTR)name); + + it->buf_pos += entry_len + name_len; + it->remaining_len -= entry_len + name_len; + it->last_entry_offset = &entry->next_entry_offset; + } + else if (it->last_entry_offset) + { + *(it->last_entry_offset) = 0; + it->ignore_the_rest = 1; + } + + return TRUE; +} + +static bool_t decode_readdir_list( + XDR *xdr, + nfs41_readdir_list *dirs) +{ + readdir_entry_iterator iter; + iter.buf_pos = dirs->entries; + iter.remaining_len = dirs->entries_len; + iter.last_entry_offset = NULL; + iter.ignore_the_rest = 0; + iter.has_next_entry = 0; + + if (!xdr_bool(xdr, &dirs->has_entries)) + return FALSE; + + if (dirs->has_entries) + { + do { + if (!decode_readdir_entry(xdr, &iter)) + return FALSE; + + } while (iter.has_next_entry); + } + dirs->entries_len -= iter.remaining_len; + + if (!xdr_bool(xdr, &dirs->eof)) + return FALSE; + + /* reset eof if we couldn't fit everything in the buffer */ + if (iter.ignore_the_rest) + dirs->eof = 0; + return TRUE; +} + +static bool_t decode_op_readdir( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_readdir_res *res = (nfs41_readdir_res*)resop->res; + + if (unexpected_op(resop->op, OP_READDIR)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) { + if (!xdr_opaque(xdr, (char *)res->cookieverf, NFS4_VERIFIER_SIZE)) + return FALSE; + return decode_readdir_list(xdr, &res->reply); + } + return TRUE; +} + + +/* + * OP_READLINK + */ +static bool_t encode_op_readlink( + XDR *xdr, + nfs_argop4 *argop) +{ + if (unexpected_op(argop->op, OP_READLINK)) + return FALSE; + + /* void */ + return TRUE; +} + +static bool_t decode_op_readlink( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_readlink_res *res = (nfs41_readlink_res*)resop->res; + + if (unexpected_op(resop->op, OP_READLINK)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) { + char *link = res->link; + return xdr_bytes(xdr, &link, &res->link_len, NFS4_OPAQUE_LIMIT); + } + + return TRUE; +} + + +/* + * OP_REMOVE + */ +static bool_t encode_op_remove( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_remove_args *args = (nfs41_remove_args*)argop->arg; + + if (unexpected_op(argop->op, OP_REMOVE)) + return FALSE; + + return encode_component(xdr, args->target); +} + +static bool_t decode_op_remove( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_remove_res *res = (nfs41_remove_res*)resop->res; + + if (unexpected_op(resop->op, OP_REMOVE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_change_info4(xdr, &res->cinfo); + + return TRUE; +} + + +/* + * OP_RENAME + */ +static bool_t encode_op_rename( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_rename_args *args = (nfs41_rename_args*)argop->arg; + + if (unexpected_op(argop->op, OP_RENAME)) + return FALSE; + + if (!encode_component(xdr, args->oldname)) + return FALSE; + + return encode_component(xdr, args->newname); +} + +static bool_t decode_op_rename( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_rename_res *res = (nfs41_rename_res*)resop->res; + + if (unexpected_op(resop->op, OP_RENAME)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + { + if (!xdr_change_info4(xdr, &res->source_cinfo)) + return FALSE; + return xdr_change_info4(xdr, &res->target_cinfo); + } + return TRUE; +} + + +/* + * OP_RESTOREFH + */ +static bool_t encode_op_restorefh( + XDR *xdr, + nfs_argop4 *argop) +{ + if (unexpected_op(argop->op, OP_RESTOREFH)) + return FALSE; + + /* void */ + return TRUE; +} + +static bool_t decode_op_restorefh( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_restorefh_res *res = (nfs41_restorefh_res*)resop->res; + + if (unexpected_op(resop->op, OP_RESTOREFH)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + +/* + * OP_SAVEFH + */ +static bool_t encode_op_savefh( + XDR *xdr, + nfs_argop4 *argop) +{ + if (unexpected_op(argop->op, OP_SAVEFH)) + return FALSE; + + /* void */ + return TRUE; +} + +static bool_t decode_op_savefh( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_savefh_res *res = (nfs41_savefh_res*)resop->res; + + if (unexpected_op(resop->op, OP_SAVEFH)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + +/* + * OP_SETATTR + */ +static bool_t encode_file_attrs( + fattr4 *attrs, + nfs41_file_info *info) +{ + uint32_t i; + XDR localxdr; + + xdrmem_create(&localxdr, (char *)attrs->attr_vals, NFS4_OPAQUE_LIMIT, XDR_ENCODE); + + attrs->attr_vals_len = 0; + ZeroMemory(&attrs->attrmask, sizeof(bitmap4)); + attrs->attrmask.count = info->attrmask.count; + + if (info->attrmask.count > 0) { + if (info->attrmask.arr[0] & FATTR4_WORD0_SIZE) { + if (!xdr_u_hyper(&localxdr, &info->size)) + return FALSE; + attrs->attrmask.arr[0] |= FATTR4_WORD0_SIZE; + } + if (info->attrmask.arr[0] & FATTR4_WORD0_HIDDEN) { + if (!xdr_bool(&localxdr, &info->hidden)) + return FALSE; + attrs->attrmask.arr[0] |= FATTR4_WORD0_HIDDEN; + } + } + if (info->attrmask.count > 1) { + if (info->attrmask.arr[1] & FATTR4_WORD1_MODE) { + if (!xdr_u_int32_t(&localxdr, &info->mode)) + return FALSE; + attrs->attrmask.arr[1] |= FATTR4_WORD1_MODE; + } + if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS_SET) { + if (!xdr_settime4(&localxdr, &info->time_access)) + return FALSE; + attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; + } + if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_CREATE) { + if (!xdr_nfstime4(&localxdr, &info->time_create)) + return FALSE; + attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE; + } + if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_MODIFY_SET) { + if (!xdr_settime4(&localxdr, &info->time_modify)) + return FALSE; + attrs->attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; + } + } + if (info->attrmask.count > 2) { + if (info->attrmask.arr[2] & FATTR4_WORD2_MODE_SET_MASKED) { + if (!xdr_u_int32_t(&localxdr, &info->mode)) + return FALSE; + if (!xdr_u_int32_t(&localxdr, &info->mode_mask)) + return FALSE; + attrs->attrmask.arr[2] |= FATTR4_WORD2_MODE_SET_MASKED; + } + } + + /* warn if we try to set attributes that aren't handled */ + for (i = 0; i < info->attrmask.count; i++) + if (attrs->attrmask.arr[i] != info->attrmask.arr[i]) + eprintf("encode_file_attrs() attempted to encode extra " + "attributes in arr[%d]: encoded %d, but wanted %d.\n", + i, attrs->attrmask.arr[i], info->attrmask.arr[i]); + + attrs->attr_vals_len = xdr_getpos(&localxdr); + return TRUE; +} + +static bool_t encode_op_setattr( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_setattr_args *args = (nfs41_setattr_args*)argop->arg; + fattr4 attrs; + + if (unexpected_op(argop->op, OP_SETATTR)) + return FALSE; + + if (!xdr_stateid4(xdr, args->stateid)) + return FALSE; + + /* encode attribute values from args->info into attrs.attr_vals */ + attrs.attr_vals_len = NFS4_OPAQUE_LIMIT; + if (!encode_file_attrs(&attrs, args->info)) + return FALSE; + + return xdr_fattr4(xdr, &attrs); +} + +static bool_t decode_op_setattr( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_setattr_res *res = (nfs41_setattr_res*)resop->res; + + if (unexpected_op(resop->op, OP_SETATTR)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_bitmap4(xdr, &res->attrsset); + + return TRUE; +} + + +/* + * OP_WRITE + */ +static bool_t encode_op_write( + XDR *xdr, + nfs_argop4 *argop) +{ + nfs41_write_args *args = (nfs41_write_args*)argop->arg; + unsigned char *data = args->data; + + if (unexpected_op(argop->op, OP_WRITE)) + return FALSE; + + if (!xdr_stateid4(xdr, args->stateid)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->stable)) + return FALSE; + + return xdr_bytes(xdr, (char **)&data, &args->data_len, NFS41_MAX_FILEIO_SIZE); +} + +static bool_t xdr_write_verf( + XDR *xdr, + nfs41_write_verf *verf) +{ + if (!xdr_enum(xdr, (enum_t *)&verf->committed)) + return FALSE; + + return xdr_opaque(xdr, (char *)verf->verf, NFS4_VERIFIER_SIZE); +} + +static bool_t xdr_write_res_ok( + XDR *xdr, + nfs41_write_res_ok *res) +{ + if (!xdr_u_int32_t(xdr, &res->count)) + return FALSE; + + return xdr_write_verf(xdr, res->verf); +} + +static bool_t decode_op_write( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_write_res *res = (nfs41_write_res*)resop->res; + + if (unexpected_op(resop->op, OP_WRITE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) + return xdr_write_res_ok(xdr, &res->resok4); + + return TRUE; +} + + +/* + * OP_GETDEVICEINFO + */ +static bool_t encode_op_getdeviceinfo( + XDR *xdr, + nfs_argop4 *argop) +{ + pnfs_getdeviceinfo_args *args = (pnfs_getdeviceinfo_args*)argop->arg; + + if (unexpected_op(argop->op, OP_GETDEVICEINFO)) + return FALSE; + + if (!xdr_opaque(xdr, (char *)args->deviceid, PNFS_DEVICEID_SIZE)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&args->layout_type)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->maxcount)) + return FALSE; + + return xdr_bitmap4(xdr, &args->notify_types); +} + +static bool_t xdr_stripe_indices( + XDR *xdr, + pnfs_stripe_indices *indices) +{ + uint32_t i, count; + + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + if (count && count != indices->count) { + uint32_t *tmp; + tmp = realloc(indices->arr, count * sizeof(uint32_t)); + if (tmp == NULL) + return FALSE; + indices->arr = tmp; + ZeroMemory(indices->arr, count * sizeof(uint32_t)); + indices->count = count; + } + + for (i = 0; i < indices->count; i++) { + if (!xdr_u_int32_t(xdr, &indices->arr[i])) + return FALSE; + } + return TRUE; +} + +static bool_t xdr_pnfs_addr( + XDR *xdr, + netaddr4 *addr) +{ + uint32_t len; + char *netid = addr->netid; + char *uaddr = addr->uaddr; + + if (xdr->x_op == XDR_ENCODE) + len = sizeof(addr->netid); + if (!xdr_bytes(xdr, &netid, &len, NFS41_NETWORK_ID_LEN)) + return FALSE; + + if (xdr->x_op == XDR_DECODE) { + if (len < NFS41_NETWORK_ID_LEN) + addr->netid[len] = 0; + else + addr->netid[NFS41_NETWORK_ID_LEN] = 0; + } + + if (xdr->x_op == XDR_ENCODE) + len = sizeof(addr->uaddr); + if (!xdr_bytes(xdr, &uaddr, &len, NFS41_UNIVERSAL_ADDR_LEN)) + return FALSE; + + if (xdr->x_op == XDR_DECODE){ + if (len < NFS41_UNIVERSAL_ADDR_LEN) + addr->uaddr[len] = 0; + else + addr->uaddr[NFS41_UNIVERSAL_ADDR_LEN] = 0; + } + + return TRUE; +} + +static bool_t xdr_multi_addr( + XDR *xdr, + multi_addr4 *list) +{ + netaddr4 dummy, *dest; + uint32_t i; + + if (!xdr_u_int32_t(xdr, &list->count)) + return FALSE; + + for (i = 0; i < list->count; i++) { + /* if there are too many addrs, decode the extras into 'dummy' */ + dest = i < NFS41_ADDRS_PER_SERVER ? &list->arr[i] : &dummy; + + if (!xdr_pnfs_addr(xdr, dest)) + return FALSE; + } + return TRUE; +} + +static bool_t xdr_data_server_list( + XDR *xdr, + pnfs_data_server_list *servers) +{ + uint32_t i, count; + + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + if (count && count != servers->count) { + pnfs_data_server *tmp; + /* clear data server clients; they're still cached with nfs41_root, + * so pnfs_data_server_client() will look them up again */ + for (i = 0; i < servers->count; i++) + servers->arr[i].client = NULL; + + tmp = realloc(servers->arr, count * sizeof(pnfs_data_server)); + if (tmp == NULL) + return FALSE; + servers->arr = tmp; + ZeroMemory(servers->arr, count * sizeof(pnfs_data_server)); + for (i = servers->count; i < count; i++) /* initialize new elements */ + InitializeSRWLock(&servers->arr[i].lock); + servers->count = count; + } + + for (i = 0; i < servers->count; i++) { + if (!xdr_multi_addr(xdr, &servers->arr[i].addrs)) + return FALSE; + } + return TRUE; +} + +static bool_t xdr_file_device( + XDR *xdr, + pnfs_file_device *device) +{ + if (!xdr_stripe_indices(xdr, &device->stripes)) + return FALSE; + + return xdr_data_server_list(xdr, &device->servers); +} + +static bool_t decode_getdeviceinfo_ok( + XDR *xdr, + pnfs_getdeviceinfo_res_ok *res_ok) +{ + u_int32_t len_ignored; + + if (!xdr_enum(xdr, (enum_t *)&res_ok->device->device.type)) + return FALSE; + + if (res_ok->device->device.type != PNFS_LAYOUTTYPE_FILE) + return FALSE; + + if (!xdr_u_int32_t(xdr, &len_ignored)) + return FALSE; + + if (!xdr_file_device(xdr, res_ok->device)) + return FALSE; + + return xdr_bitmap4(xdr, &res_ok->notification); +} + +static bool_t decode_op_getdeviceinfo( + XDR *xdr, + nfs_resop4 *resop) +{ + pnfs_getdeviceinfo_res *res = (pnfs_getdeviceinfo_res*)resop->res; + + if (unexpected_op(resop->op, OP_GETDEVICEINFO)) + return FALSE; + + if (!xdr_u_int32_t(xdr, (uint32_t *)&res->status)) + return FALSE; + + switch (res->status) { + case NFS4_OK: + return decode_getdeviceinfo_ok(xdr, &res->u.res_ok); + break; + case NFS4ERR_TOOSMALL: + { + uint32_t ignored; + return xdr_u_int32_t(xdr, &ignored); + } + break; + } + return TRUE; +} + + +/* + * OP_LAYOUTCOMMIT + */ +static bool_t encode_op_layoutcommit( + XDR *xdr, + nfs_argop4 *argop) +{ + pnfs_layoutcommit_args *args = (pnfs_layoutcommit_args*)argop->arg; + bool_t false_bool = FALSE; + bool_t true_bool = TRUE; + enum_t pnfs_layout = PNFS_LAYOUTTYPE_FILE; + uint32_t zero = 0; + + if (unexpected_op(argop->op, OP_LAYOUTCOMMIT)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->length)) + return FALSE; + + if (!xdr_bool(xdr, &false_bool)) /* loca_reclaim = 0 */ + return FALSE; + + if (!xdr_stateid4(xdr, args->stateid)) + return FALSE; + + /* loca_last_write_offset */ + if (args->new_offset) { + if (!xdr_bool(xdr, &true_bool)) + return FALSE; + + if (!xdr_u_hyper(xdr, args->new_offset)) + return FALSE; + } else { + if (!xdr_bool(xdr, &false_bool)) + return FALSE; + } + + /* loca_time_modify */ + if (args->new_time) { + if (!xdr_bool(xdr, &true_bool)) + return FALSE; + + if (!xdr_nfstime4(xdr, args->new_time)) + return FALSE; + } else { + if (!xdr_bool(xdr, &false_bool)) + return FALSE; + } + + /* loca_layoutupdate */ + if (!xdr_enum(xdr, &pnfs_layout)) + return FALSE; + + return xdr_u_int32_t(xdr, &zero); +} + +static bool_t decode_op_layoutcommit( + XDR *xdr, + nfs_resop4 *resop) +{ + pnfs_layoutcommit_res *res = (pnfs_layoutcommit_res*)resop->res; + + if (unexpected_op(resop->op, OP_LAYOUTCOMMIT)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (res->status == NFS4_OK) { + if (!xdr_bool(xdr, &res->has_new_size)) + return FALSE; + + if (res->has_new_size) + if (!xdr_u_hyper(xdr, &res->new_size)) + return FALSE; + } + return TRUE; +} + +/* + * OP_LAYOUTGET + */ +static bool_t encode_op_layoutget( + XDR *xdr, + nfs_argop4 *argop) +{ + pnfs_layoutget_args *args = (pnfs_layoutget_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LAYOUTGET)) + return FALSE; + + if (!xdr_bool(xdr, &args->signal_layout_avail)) + return FALSE; + + if (!xdr_u_int32_t(xdr, (u_int32_t *)&args->layout_type)) + return FALSE; + + if (!xdr_u_int32_t(xdr, (u_int32_t *)&args->iomode)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->length)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->minlength)) + return FALSE; + + if (!xdr_stateid4(xdr, args->stateid)) + return FALSE; + + return xdr_u_int32_t(xdr, &args->maxcount); +} + +static bool_t decode_layout( + XDR *xdr, + pnfs_layout *layout) +{ + uint32_t count; + + if (!xdr_bool(xdr, &layout->return_on_close)) + return FALSE; + + if (!xdr_stateid4(xdr, &layout->state)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + if (count != 1) { + eprintf("decode_layout: server returned a list of " + "%d layouts! only single layouts are supported!\n", count); + return FALSE; + } + + if (!xdr_u_hyper(xdr, &layout->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &layout->length)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&layout->iomode)) + return FALSE; + + return xdr_enum(xdr, (enum_t *)&layout->type); +} + +static bool_t decode_file_layout_handles( + XDR *xdr, + pnfs_file_layout_handles *handles) +{ + uint32_t i, count; + + if (!xdr_u_int32_t(xdr, &count)) + return FALSE; + + if (count && count != handles->count) { + nfs41_path_fh *tmp; + tmp = realloc(handles->arr, count * sizeof(nfs41_path_fh)); + if (tmp == NULL) + return FALSE; + handles->arr = tmp; + ZeroMemory(handles->arr, count * sizeof(nfs41_path_fh)); + handles->count = count; + } + + for (i = 0; i < handles->count; i++) { + if (!xdr_fh(xdr, &handles->arr[i].fh)) + return FALSE; + } + return TRUE; +} + +static bool_t decode_file_layout( + XDR *xdr, + pnfs_file_layout *layout) +{ + u_int32_t len_ignored; + + if (!decode_layout(xdr, &layout->layout)) + return FALSE; + + if (layout->layout.type != PNFS_LAYOUTTYPE_FILE) { + eprintf("%s: received non-FILE layout type, %d\n", + "decode_file_layout", layout->layout.type); + return FALSE; + } + + if (!xdr_u_int32_t(xdr, &len_ignored)) + return FALSE; + + if (!xdr_opaque(xdr, (char *)layout->deviceid, PNFS_DEVICEID_SIZE)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &layout->util)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &layout->first_index)) + return FALSE; + + if (!xdr_u_hyper(xdr, &layout->pattern_offset)) + return FALSE; + + return decode_file_layout_handles(xdr, &layout->filehandles); +} + +static bool_t decode_op_layoutget( + XDR *xdr, + nfs_resop4 *resop) +{ + pnfs_layoutget_res *res = (pnfs_layoutget_res*)resop->res; + + if (unexpected_op(resop->op, OP_LAYOUTGET)) + return FALSE; + + if (!xdr_u_int32_t(xdr, (uint32_t *)&res->status)) + return FALSE; + + switch (res->status) { + case NFS4_OK: + return decode_file_layout(xdr, res->u.res_ok.layout); + break; + case NFS4ERR_LAYOUTTRYLATER: + { + bool_t ignored; + return xdr_bool(xdr, &ignored); + } + break; + } + return TRUE; +} + + +/* + * OP_LAYOUTRETURN + */ +static bool_t encode_op_layoutreturn( + XDR *xdr, + nfs_argop4 *argop) +{ + pnfs_layoutreturn_args *args = (pnfs_layoutreturn_args*)argop->arg; + + if (unexpected_op(argop->op, OP_LAYOUTRETURN)) + return FALSE; + + if (!xdr_bool(xdr, &args->reclaim)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&args->type)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&args->iomode)) + return FALSE; + + if (!xdr_enum(xdr, (enum_t *)&args->return_type)) + return FALSE; + + if (args->return_type == PNFS_RETURN_FILE) { + u_int32_t zero = 0; + + if (!xdr_u_hyper(xdr, &args->offset)) + return FALSE; + + if (!xdr_u_hyper(xdr, &args->length)) + return FALSE; + + if (!xdr_stateid4(xdr, args->stateid)) + return FALSE; + + return xdr_u_int32_t(xdr, &zero); /* size of lrf_body is 0 */ + } else { + eprintf("%s: layout type (%d) is not PNFS_RETURN_FILE!\n", + "encode_op_layoutreturn", args->return_type); + return FALSE; + } +} + +static bool_t decode_op_layoutreturn( + XDR *xdr, + nfs_resop4 *resop) +{ + pnfs_layoutreturn_res *res = (pnfs_layoutreturn_res*)resop->res; + + if (unexpected_op(resop->op, OP_LAYOUTRETURN)) + return FALSE; + + if (!xdr_u_int32_t(xdr, (uint32_t *)&res->status)) + return FALSE; + + if (res->status == NFS4_OK) { + if (!xdr_bool(xdr, &res->stateid_present)) + return FALSE; + + if (res->stateid_present) + return xdr_stateid4(xdr, &res->stateid); + } + return TRUE; +} + + +/* op encode/decode table */ +typedef bool_t (*nfs_op_encode_proc)(XDR*, nfs_argop4*); +typedef bool_t (*nfs_op_decode_proc)(XDR*, nfs_resop4*); + +typedef struct __op_table_entry { + nfs_op_encode_proc encode; + nfs_op_decode_proc decode; +} op_table_entry; + +/* table of encode/decode functions, indexed by operation number */ +static const op_table_entry g_op_table[] = { + { NULL, NULL }, /* 0 unused */ + { NULL, NULL }, /* 1 unused */ + { NULL, NULL }, /* 2 unused */ + { encode_op_access, decode_op_access }, /* OP_ACCESS = 3 */ + { encode_op_close, decode_op_close }, /* OP_CLOSE = 4 */ + { encode_op_commit, decode_op_commit }, /* OP_COMMIT = 5 */ + { encode_op_create, decode_op_create }, /* OP_CREATE = 6 */ + { NULL, NULL }, /* OP_DELEGPURGE = 7 */ + { encode_op_delegreturn, decode_op_delegreturn }, /* OP_DELEGRETURN = 8 */ + { encode_op_getattr, decode_op_getattr }, /* OP_GETATTR = 9 */ + { encode_op_getfh, decode_op_getfh }, /* OP_GETFH = 10 */ + { encode_op_link, decode_op_link }, /* OP_LINK = 11 */ + { encode_op_lock, decode_op_lock }, /* OP_LOCK = 12 */ + { encode_op_lockt, decode_op_lockt }, /* OP_LOCKT = 13 */ + { encode_op_locku, decode_op_locku }, /* OP_LOCKU = 14 */ + { encode_op_lookup, decode_op_lookup }, /* OP_LOOKUP = 15 */ + { NULL, NULL }, /* OP_LOOKUPP = 16 */ + { NULL, NULL }, /* OP_NVERIFY = 17 */ + { encode_op_open, decode_op_open }, /* OP_OPEN = 18 */ + { NULL, NULL }, /* OP_OPENATTR = 19 */ + { NULL, NULL }, /* OP_OPEN_CONFIRM = 20 */ + { NULL, NULL }, /* OP_OPEN_DOWNGRADE = 21 */ + { encode_op_putfh, decode_op_putfh }, /* OP_PUTFH = 22 */ + { NULL, NULL }, /* OP_PUTPUBFH = 23 */ + { encode_op_putrootfh, decode_op_putrootfh }, /* OP_PUTROOTFH = 24 */ + { encode_op_read, decode_op_read }, /* OP_READ = 25 */ + { encode_op_readdir, decode_op_readdir }, /* OP_READDIR = 26 */ + { encode_op_readlink, decode_op_readlink }, /* OP_READLINK = 27 */ + { encode_op_remove, decode_op_remove }, /* OP_REMOVE = 28 */ + { encode_op_rename, decode_op_rename }, /* OP_RENAME = 29 */ + { NULL, NULL }, /* OP_RENEW = 30 */ + { encode_op_restorefh, decode_op_restorefh }, /* OP_RESTOREFH = 31 */ + { encode_op_savefh, decode_op_savefh }, /* OP_SAVEFH = 32 */ + { NULL, NULL }, /* OP_SECINFO = 33 */ + { encode_op_setattr, decode_op_setattr }, /* OP_SETATTR = 34 */ + { NULL, NULL }, /* OP_SETCLIENTID = 35 */ + { NULL, NULL }, /* OP_SETCLIENTID_CONFIRM = 36 */ + { NULL, NULL }, /* OP_VERIFY = 37 */ + { encode_op_write, decode_op_write }, /* OP_WRITE = 38 */ + { NULL, NULL }, /* OP_RELEASE_LOCKOWNER = 39 */ + { NULL, NULL }, /* OP_BACKCHANNEL_CTL = 40 */ + { NULL, NULL }, /* OP_BIND_CONN_TO_SESSION = 41 */ + { encode_op_exchange_id, decode_op_exchange_id }, /* OP_EXCHANGE_ID = 42 */ + { encode_op_create_session, decode_op_create_session }, /* OP_CREATE_SESSION = 43 */ + { encode_op_destroy_session, decode_op_destroy_session }, /* OP_DESTROY_SESSION = 44 */ + { NULL, NULL }, /* OP_FREE_STATEID = 45 */ + { NULL, NULL }, /* OP_GET_DIR_DELEGATION = 46 */ + { encode_op_getdeviceinfo, decode_op_getdeviceinfo }, /* OP_GETDEVICEINFO = 47 */ + { NULL, NULL }, /* OP_GETDEVICELIST = 48 */ + { encode_op_layoutcommit, decode_op_layoutcommit }, /* OP_LAYOUTCOMMIT = 49 */ + { encode_op_layoutget, decode_op_layoutget }, /* OP_LAYOUTGET = 50 */ + { encode_op_layoutreturn, decode_op_layoutreturn }, /* OP_LAYOUTRETURN = 51 */ + { NULL, NULL }, /* OP_SECINFO_NO_NAME = 52 */ + { encode_op_sequence, decode_op_sequence }, /* OP_SEQUENCE = 53 */ + { NULL, NULL }, /* OP_SET_SSV = 54 */ + { NULL, NULL }, /* OP_TEST_STATEID = 55 */ + { NULL, NULL }, /* OP_WANT_DELEGATION = 56 */ + { NULL, NULL }, /* OP_DESTROY_CLIENTID = 57 */ + { encode_op_reclaim_complete, decode_op_reclaim_complete }, /* OP_RECLAIM_COMPLETE = 58 */ +}; +static const uint32_t g_op_table_size = ARRAYSIZE(g_op_table); + +static const op_table_entry* op_table_find(uint32_t op) +{ + return op >= g_op_table_size ? NULL : &g_op_table[op]; +} + + +/* + * COMPOUND + */ +bool_t nfs_encode_compound( + XDR *xdr, + caddr_t *pargs) +{ + unsigned char *tag; + + nfs41_compound_args *args = (nfs41_compound_args*)pargs; + uint32_t i; + const op_table_entry *entry; + + tag = args->tag; + if (!xdr_bytes(xdr, (char **)&tag, &args->tag_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->minorversion)) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->argarray_count)) + return FALSE; + + for (i = 0; i < args->argarray_count; i++) + { + entry = op_table_find(args->argarray[i].op); + if (entry == NULL || entry->encode == NULL) + return FALSE; + + if (!xdr_u_int32_t(xdr, &args->argarray[i].op)) + return FALSE; + if (!entry->encode(xdr, &args->argarray[i])) + return FALSE; + } + return TRUE; +} + +bool_t nfs_decode_compound( + XDR *xdr, + caddr_t *pres) +{ + nfs41_compound_res *res = (nfs41_compound_res*)pres; + uint32_t i, expected_count, expected_op; + const op_table_entry *entry; + unsigned char *tag = res->tag; + + if (!xdr_u_int32_t(xdr, &res->status)) + return FALSE; + + if (!xdr_bytes(xdr, (char **)&tag, &res->tag_len, NFS4_OPAQUE_LIMIT)) + return FALSE; + + expected_count = res->resarray_count; + if (!xdr_u_int32_t(xdr, &res->resarray_count)) + return FALSE; + + /* validate the number of operations against what we sent */ + if (res->resarray_count > expected_count) { + eprintf("reply with %u operations, only sent %u!\n", + res->resarray_count, expected_count); + return FALSE; + } + + for (i = 0; i < res->resarray_count; i++) + { + expected_op = res->resarray[i].op; + if (!xdr_u_int32_t(xdr, &res->resarray[i].op)) + return FALSE; + + /* validate each operation number against what we sent */ + if (res->resarray[i].op != expected_op) { + eprintf("reply with %s in operation %u, expected %s!\n", + nfs_opnum_to_string(res->resarray[i].op), i+1, + nfs_opnum_to_string(expected_op)); + return FALSE; + } + + entry = op_table_find(res->resarray[i].op); + if (entry == NULL || entry->decode == NULL) + return FALSE; + if (!entry->decode(xdr, &res->resarray[i])) + return FALSE; + } + return TRUE; +} diff --git a/daemon/nfs41_xdr.h b/daemon/nfs41_xdr.h new file mode 100644 index 0000000..be53dab --- /dev/null +++ b/daemon/nfs41_xdr.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_NFS_XDR_H__ +#define __NFS41_NFS_XDR_H__ + +#include "nfs41_types.h" + +bool_t nfs_encode_compound(XDR *xdr, caddr_t *args); +bool_t nfs_decode_compound(XDR *xdr, caddr_t *res); + + +#endif /* !__NFS41_NFS_XDR_H__ */ diff --git a/daemon/open.c b/daemon/open.c new file mode 100644 index 0000000..667c77d --- /dev/null +++ b/daemon/open.c @@ -0,0 +1,445 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "nfs41_ops.h" +#include "from_kernel.h" +#include "daemon_debug.h" +#include "upcall.h" +#include "util.h" + + +static int create_open_state( + IN const nfs41_abs_path *path, + IN uint32_t open_owner_id, + OUT nfs41_open_state **state_out) +{ + int status; + nfs41_open_state *state; + + state = calloc(1, sizeof(nfs41_open_state)); + if (state == NULL) { + status = GetLastError(); + goto out; + } + + InitializeSRWLock(&state->path.lock); + abs_path_copy(&state->path, path); + path_fh_init(&state->file, &state->path); + path_fh_init(&state->parent, &state->path); + last_component(state->path.path, state->file.name.name, + &state->parent.name); + + StringCchPrintfA((LPSTR)state->owner.owner, NFS4_OPAQUE_LIMIT, + "%u", open_owner_id); + state->owner.owner_len = (uint32_t)strlen( + (const char*)state->owner.owner); + + *state_out = state; + status = NO_ERROR; +out: + return status; +} + +static void free_open_state( + IN nfs41_session *session, + IN nfs41_open_state *state) +{ + free(state); +} + + +/* NFS41_OPEN */ +int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + open_upcall_args *args = &upcall->args.open; + + ZeroMemory(&args->path, sizeof(nfs41_abs_path)); + status = get_abs_path(&buffer, &length, &args->path); + if (status) goto out; + status = safe_read(&buffer, &length, &args->access_mask, sizeof(ULONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->access_mode, sizeof(ULONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->file_attrs, sizeof(ULONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->create_opts, sizeof(ULONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->disposition, sizeof(ULONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->open_owner_id, sizeof(ULONG)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->mode, sizeof(DWORD)); +out: + if (status) + eprintf("parsing NFS41_OPEN failed with %d\n", status); + else { + dprintf(1, "parsing NFS41_OPEN: filename='%s' access mask=%d " + "access mode=%d\n\tfile attrs=0x%x create attrs=0x%x " + "(kernel) disposition=%d\n\tsession=%p open_owner_id=%d mode=%o\n", + args->path.path, args->access_mask, args->access_mode, args->file_attrs, + args->create_opts, args->disposition, args->root, args->open_owner_id, + args->mode); + print_disposition(2, args->disposition); + print_access_mask(2, args->access_mask); + print_share_mode(2, args->access_mode); + print_create_attributes(2, args->create_opts); + } + return status; +} + +static BOOLEAN do_lookup(uint32_t type, ULONG access_mask, ULONG disposition) +{ + if (type == NF4DIR) { + if (disposition == FILE_OPEN || disposition == FILE_OVERWRITE) { + dprintf(1, "Opening a directory\n"); + return TRUE; + } else { + dprintf(1, "Creating a directory\n"); + return FALSE; + } + } + + if ((access_mask & FILE_READ_DATA) || + (access_mask & FILE_WRITE_DATA) || + (access_mask & FILE_APPEND_DATA) || + (access_mask & FILE_EXECUTE)) + return FALSE; + else { + dprintf(1, "Open call that wants to manage attributes\n"); + return TRUE; + } +} + +static int map_disposition_2_nfsopen(ULONG disposition, int in_status, + uint32_t *create, uint32_t *last_error) +{ + int status = NO_ERROR; + if (disposition == FILE_SUPERSEDE) { + if (in_status == NFS4ERR_NOENT) { + *create = OPEN4_CREATE; + *last_error = ERROR_FILE_NOT_FOUND; + } + else // we need to truncate the file file then open it + *create = OPEN4_NOCREATE; + } else if (disposition == FILE_CREATE) { + // if lookup succeeded which means the file exist, return an error + if (!in_status) + status = ERROR_FILE_EXISTS; + else + *create = OPEN4_CREATE; + } else if (disposition == FILE_OPEN) { + if (in_status == NFS4ERR_NOENT) + status = ERROR_FILE_NOT_FOUND; + else + *create = OPEN4_NOCREATE; + } else if (disposition == FILE_OPEN_IF) { + if (in_status == NFS4ERR_NOENT) { + dprintf(1, "creating new file\n"); + *create = OPEN4_CREATE; + *last_error = ERROR_FILE_NOT_FOUND; + } else { + dprintf(1, "opening existing file\n"); + *create = OPEN4_NOCREATE; + } + } else if (disposition == FILE_OVERWRITE) { + if (in_status == NFS4ERR_NOENT) + status = ERROR_FILE_NOT_FOUND; + //truncate file + *create = OPEN4_CREATE; + } else if (disposition == FILE_OVERWRITE_IF) { + if (in_status == NFS4ERR_NOENT) + *last_error = ERROR_FILE_NOT_FOUND; + //truncate file + *create = OPEN4_CREATE; + } + return status; +} + +static int check_execute_access(nfs41_open_state *state) +{ + uint32_t supported, access; + int status = nfs41_access(state->session, &state->file, + ACCESS4_EXECUTE | ACCESS4_READ, &supported, &access); + if (status) { + dprintf(1, "nfs41_access() failed with %s\n", + nfs_error_string(status)); + status = ERROR_ACCESS_DENIED; + } else if ((supported & ACCESS4_EXECUTE) == 0) { + /* server can't verify execute access; + * for now, assume that read access is good enough */ + if ((supported & ACCESS4_READ) == 0 || (access & ACCESS4_READ) == 0) { + dprintf(2, "server can't verify execute access, and user does " + "not have read access\n"); + status = ERROR_ACCESS_DENIED; + } + } else if ((access & ACCESS4_EXECUTE) == 0) { + dprintf(2, "user does not have execute access to file\n"); + status = ERROR_ACCESS_DENIED; + } else + dprintf(2, "user has execute access to file\n"); + return status; +} + +int handle_open(nfs41_upcall *upcall) +{ + int status = 0; + open_upcall_args *args = &upcall->args.open; + nfs41_open_state *state; + bitmap4 attr_request; + nfs41_file_info info; + + init_getattr_request(&attr_request); + + status = create_open_state(&args->path, args->open_owner_id, &state); + if (status) { + eprintf("create_open_state(%u) failed with %d\n", + args->open_owner_id, status); + goto out; + } + + // first check if windows told us it's a directory + if (args->create_opts & FILE_DIRECTORY_FILE) + state->type = NF4DIR; + else + state->type = NF4REG; + + // always do a lookup + status = nfs41_lookup(args->root, nfs41_root_session(args->root), + &state->path, &state->parent, &state->file, &info, &state->session); + // now if file/dir exists, use type returned by lookup + if (status == NO_ERROR) { + if (info.type == NF4DIR) { + dprintf(2, "handle_nfs41_open: DIRECTORY\n"); + if (args->create_opts & FILE_NON_DIRECTORY_FILE) { + eprintf("trying to open directory %s as a file\n", + args->path.path); + status = ERROR_ACCESS_DENIED; + goto out_free_state; + } + } else if (info.type == NF4REG) { + dprintf(2, "handle nfs41_open: FILE\n"); + if (args->create_opts & FILE_DIRECTORY_FILE) { + eprintf("trying to open file %s as a directory\n", + args->path.path); +#ifdef NOTEPAD_OPEN_FILE_AS_DIRFILE_FIXED + status = ERROR_ACCESS_DENIED; + goto out_free_state; +#endif + } + } else + dprintf(2, "handle nfs41_open: is it SYMLINK?\n"); + state->type = info.type; + } else if (status != ERROR_FILE_NOT_FOUND) + goto out_free_state; + if (do_lookup(state->type, args->access_mask, args->disposition)) { + if (status) { + dprintf(1, "nfs41_lookup failed with %d\n", status); + goto out_free_state; + } + + nfs_to_basic_info(&info, &args->basic_info); + nfs_to_standard_info(&info, &args->std_info); + args->mode = info.mode; + args->changeattr = info.change; + } else { + uint32_t allow = 0, deny = 0, create = 0; + + map_access_2_allowdeny(args->access_mask, args->access_mode, &allow, &deny); + status = map_disposition_2_nfsopen(args->disposition, status, &create, &upcall->last_error); + if (status) + goto out_free_state; + + if (args->access_mask & FILE_EXECUTE && state->file.fh.len) { + status = check_execute_access(state); + if (status) + goto out_free_state; + } + + if (create == OPEN4_CREATE && (args->create_opts & FILE_DIRECTORY_FILE)) { + status = nfs41_create(state->session, NF4DIR, args->mode, + &state->parent, &state->file); + args->std_info.Directory = 1; + args->created = status == NFS4_OK; + } else { + status = nfs41_open(state->session, allow, deny, create, + args->mode, state, &info); + + if (status == NFS4_OK) { + nfs_to_basic_info(&info, &args->basic_info); + nfs_to_standard_info(&info, &args->std_info); + state->do_close = 1; + args->mode = info.mode; + } + } + if (status) { + dprintf(1, "%s failed with %s\n", (create == OPEN4_CREATE && + (args->create_opts & FILE_DIRECTORY_FILE))?"nfs41_create":"nfs41_open", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); + goto out_free_state; + } + } + args->state = state; +out: + return status; +out_free_state: + free(state); + goto out; +} + +int marshall_open(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + int status; + open_upcall_args *args = &upcall->args.open; + + status = safe_write(&buffer, length, &args->basic_info, sizeof(args->basic_info)); + if (status) goto out; + status = safe_write(&buffer, length, &args->std_info, sizeof(args->std_info)); + if (status) goto out; + status = safe_write(&buffer, length, &args->state, sizeof(args->state)); + if (status) goto out; + status = safe_write(&buffer, length, &args->mode, sizeof(args->mode)); + if (status) goto out; + status = safe_write(&buffer, length, &args->changeattr, sizeof(args->changeattr)); + dprintf(2, "NFS41_OPEN: passing open_state=0x%p mode %o changeattr 0x%x\n", + args->state, args->mode, args->changeattr); +out: + return status; +} + +int cancel_open(IN nfs41_upcall *upcall) +{ + int status = NFS4_OK; + open_upcall_args *args = &upcall->args.open; + nfs41_open_state *state = args->state; + + dprintf(1, "--> cancel_open('%s')\n", args->path.path); + + if (upcall->status) + goto out; /* if handle_open() failed, the state was already freed */ + + if (state->do_close) { + status = nfs41_close(state->session, state); + if (status) + dprintf(1, "cancel_open: nfs41_close() failed with %s\n", + nfs_error_string(status)); + } else if (args->created) { + const nfs41_component *name = &state->file.name; + status = nfs41_remove(state->session, &state->parent, name); + if (status) + dprintf(1, "cancel_open: nfs41_remove() failed with %s\n", + nfs_error_string(status)); + } + + free_open_state(state->session, state); +out: + status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR); + dprintf(1, "<-- cancel_open() returning %d\n", status); + return status; +} + + +/* NFS41_CLOSE */ +int parse_close(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + close_upcall_args *args = &upcall->args.close; + + status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->state, sizeof(nfs41_open_state *)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->remove, sizeof(BOOLEAN)); + if (status) goto out; + if (args->remove) { + ZeroMemory(&args->path, sizeof(nfs41_abs_path)); + status = get_abs_path(&buffer, &length, &args->path); + if (status) goto out; + status = safe_read(&buffer, &length, &args->renamed, sizeof(BOOLEAN)); + } +out: + if (status) + eprintf("parsing NFS41_CLOSE failed with %d\n", status); + else + dprintf(1, "parsing NFS41_CLOSE: close root=0x%p " + "open_state=0x%p remove=%d renamed=%d filename='%s'\n", + args->root, args->state, args->remove, args->renamed, + args->remove ? args->path.path : ""); + return status; +} + +int handle_close(nfs41_upcall *upcall) +{ + int status = NFS4_OK, rm_status = NFS4_OK; + close_upcall_args *args = &upcall->args.close; + nfs41_open_state *state = args->state; + + /* return associated file layouts if necessary */ + if (state->type == NF4REG) + pnfs_open_state_close(state->session, state, args->remove); + + if (args->remove) { + nfs41_component *name = &state->file.name; + + if (args->renamed) { + dprintf(1, "removing a renamed file %s\n", name->name); + create_silly_rename(&state->path, &state->file.fh, name); + } + + dprintf(1, "calling nfs41_remove for %s\n", name->name); + rm_status = nfs41_remove(state->session, &state->parent, name); + if (rm_status) { + dprintf(1, "nfs41_remove() failed with error %s.\n", + nfs_error_string(rm_status)); + rm_status = nfs_to_windows_error(rm_status, ERROR_INTERNAL_ERROR); + } + } + + if (state->do_close) { + status = nfs41_close(state->session, state); + if (status) { + dprintf(1, "nfs41_close() failed with error %s.\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR); + } + } + + if (args->state->type == NF4REG || !args->remove) + free_open_state(state->session, state); + if (status || !rm_status) + return status; + else + return rm_status; +} + +int marshall_close(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + return NO_ERROR; +} diff --git a/daemon/pnfs.h b/daemon/pnfs.h new file mode 100644 index 0000000..5f4259f --- /dev/null +++ b/daemon/pnfs.h @@ -0,0 +1,352 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __PNFS_H__ +#define __PNFS_H__ + +#include "nfs41_types.h" +#include "list.h" + + +/* preprocessor options */ +#ifndef PNFS_DISABLE + +# ifndef PNFS_DISABLE_READ +# define PNFS_ENABLE_READ +# endif +# ifndef PNFS_DISABLE_WRITE +# define PNFS_ENABLE_WRITE +# endif + +# define PNFS_THREADING +# define PNFS_THREAD_BY_SERVER + +#endif + + +/* forward declarations from nfs41.h */ +struct __nfs41_client; +struct __nfs41_session; +struct __nfs41_open_state; +struct __nfs41_root; + + +/* pnfs error values, in order of increasing severity */ +enum pnfs_status { + PNFS_SUCCESS = 0, + PNFS_PENDING, + PNFS_READ_EOF, + PNFSERR_NOT_SUPPORTED, + PNFSERR_NOT_CONNECTED, + PNFSERR_IO, + PNFSERR_NO_DEVICE, + PNFSERR_NO_LAYOUT, + PNFSERR_INVALID_FH_LIST, + PNFSERR_INVALID_DS_INDEX, + PNFSERR_RESOURCES, + PNFSERR_LAYOUT_RECALLED, + PNFSERR_LAYOUT_CHANGED, +}; + +enum pnfs_layout_type { + PNFS_LAYOUTTYPE_FILE = 1, + PNFS_LAYOUTTYPE_OBJECT = 2, + PNFS_LAYOUTTYPE_BLOCK = 3 +}; + +enum pnfs_iomode { + PNFS_IOMODE_READ = 0x1, + PNFS_IOMODE_RW = 0x2, + PNFS_IOMODE_ANY = PNFS_IOMODE_READ | PNFS_IOMODE_RW +}; + +enum pnfs_layout_status { + /* LAYOUTGET was successful, and the layout has not been returned or + * otherwise revoked by the server */ + PNFS_LAYOUT_GRANTED = 0x01, + /* GETDEVICEINFO was successful, and we have a valid 'device' pointer */ + PNFS_LAYOUT_HAS_DEVICE = 0x02, + /* CB_LAYOUTRECALL indicated that the server has recalled this layout, + * and it should be returned on completion of any pending io */ + PNFS_LAYOUT_RECALLED = 0x04, + /* CB_LAYOUTRECALL indicated that the layout is changing, and "the client + * SHOULD NOT write and commit modified data to the storage devices!" */ + PNFS_LAYOUT_CHANGED = 0x08, + + /* a LAYOUTGET error indicated that this layout will never be granted */ + PNFS_LAYOUT_UNAVAILABLE = 0x10, + /* LAYOUTGET returned BADIOMODE, so a RW layout will never be granted */ + PNFS_LAYOUT_NOT_RW = 0x20, +}; + +enum pnfs_return_type { + PNFS_RETURN_FILE = 1, + PNFS_RETURN_FSID = 2, + PNFS_RETURN_ALL = 3 +}; + +#define NFL4_UFLG_MASK 0x0000003F +#define NFL4_UFLG_DENSE 0x00000001 +#define NFL4_UFLG_COMMIT_THRU_MDS 0x00000002 +#define NFL4_UFLG_STRIPE_UNIT_SIZE_MASK 0xFFFFFFC0 + +#define PNFS_DEVICEID_SIZE 16 + + +/* device */ +typedef struct __pnfs_device { + unsigned char deviceid[PNFS_DEVICEID_SIZE]; + enum pnfs_layout_type type; +} pnfs_device; + +typedef struct __pnfs_stripe_indices { + uint32_t count; + uint32_t *arr; +} pnfs_stripe_indices; + +typedef struct __pnfs_data_server { + struct __nfs41_client *client; + multi_addr4 addrs; + SRWLOCK lock; +} pnfs_data_server; + +typedef struct __pnfs_data_server_list { + uint32_t count; + pnfs_data_server *arr; +} pnfs_data_server_list; + +typedef struct __pnfs_file_device { + pnfs_device device; + pnfs_stripe_indices stripes; + pnfs_data_server_list servers; + struct list_entry entry; /* position in nfs41_client.devices */ + SRWLOCK lock; +} pnfs_file_device; + + +/* layout */ +typedef struct __pnfs_layout { + stateid4 state; + uint64_t offset; + uint64_t length; + enum pnfs_layout_type type; + enum pnfs_iomode iomode; + enum pnfs_layout_status status; + bool_t return_on_close; + uint32_t io_count; /* number of pending io operations */ + SRWLOCK lock; +} pnfs_layout; + +typedef struct __pnfs_file_layout_handles { + uint32_t count; + nfs41_path_fh *arr; +} pnfs_file_layout_handles; + +typedef struct __pnfs_file_layout { + pnfs_layout layout; + pnfs_file_layout_handles filehandles; + unsigned char deviceid[PNFS_DEVICEID_SIZE]; + struct list_entry entry; /* position in nfs41_client.layouts */ + pnfs_file_device *device; + nfs41_fh meta_fh; + uint64_t pattern_offset; + uint32_t first_index; + uint32_t util; +} pnfs_file_layout; + +typedef struct __pnfs_layout_recall { + enum pnfs_layout_type type; + enum pnfs_iomode iomode; + bool_t changed; + + enum pnfs_return_type recall; + union { + struct { + nfs41_fh fh; + stateid4 stateid; + } file; + nfs41_fsid fsid; + } args; +} pnfs_layout_recall; + + +/* io */ +typedef struct __pnfs_io_pattern { + struct __pnfs_io_thread *threads; + struct __nfs41_root *root; + nfs41_path_fh *meta_file; + stateid4 *stateid; + pnfs_file_layout *layout; + unsigned char *buffer; + uint64_t offset_start; + uint64_t offset_end; + uint32_t count; + uint32_t default_lease; +} pnfs_io_pattern; + +typedef struct __pnfs_io_thread { + pnfs_io_pattern *pattern; + uint64_t offset; + uint64_t offset_end; + uint32_t id; + enum stable_how4 stable; +} pnfs_io_thread; + +typedef struct __pnfs_io_unit { + nfs41_path_fh *file; + unsigned char *buffer; + uint64_t offset; + uint64_t length; + uint32_t stripeid; + uint32_t serverid; +} pnfs_io_unit; + +typedef uint32_t (WINAPI *pnfs_io_thread_fn)(void*); + + +/* pnfs_layout.c */ +struct pnfs_file_layout_list; +struct cb_layoutrecall_args; + +enum pnfs_status pnfs_file_layout_list_create( + OUT struct pnfs_file_layout_list **layouts_out); + +void pnfs_file_layout_list_free( + IN struct pnfs_file_layout_list *layouts); + +enum pnfs_status pnfs_open_state_layout( + IN struct pnfs_file_layout_list *layouts, + IN struct __nfs41_session *session, + IN struct __nfs41_open_state *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length, + OUT pnfs_file_layout **layout_out); + +void pnfs_open_state_close( + IN struct __nfs41_session *session, + IN struct __nfs41_open_state *state, + IN bool_t remove); + +enum pnfs_status pnfs_file_layout_recall( + IN struct pnfs_file_layout_list *layouts, + IN const struct cb_layoutrecall_args *recall); + +enum pnfs_status pnfs_layout_io_start( + IN pnfs_layout *layout); + +void pnfs_layout_io_finished( + IN pnfs_layout *layout); + + +__inline int is_dense( + IN const pnfs_file_layout *layout) +{ + return (layout->util & NFL4_UFLG_DENSE) != 0; +} +__inline int should_commit_to_mds( + IN const pnfs_file_layout *layout) +{ + return (layout->util & NFL4_UFLG_COMMIT_THRU_MDS) != 0; +} +__inline uint32_t layout_unit_size( + IN const pnfs_file_layout *layout) +{ + return layout->util & NFL4_UFLG_STRIPE_UNIT_SIZE_MASK; +} + + +/* pnfs_device.c */ +struct pnfs_file_device_list; + +enum pnfs_status pnfs_file_device_list_create( + OUT struct pnfs_file_device_list **devices_out); + +void pnfs_file_device_list_free( + IN struct pnfs_file_device_list *devices); + +enum pnfs_status pnfs_file_device_get( + IN struct __nfs41_session *session, + IN struct pnfs_file_device_list *devices, + IN unsigned char *deviceid, + OUT pnfs_file_device **device_out); + +enum pnfs_status pnfs_data_server_client( + IN struct __nfs41_root *root, + IN pnfs_data_server *server, + IN uint32_t default_lease, + OUT struct __nfs41_client **client_out); + +enum pnfs_status pnfs_file_device_io_unit( + IN pnfs_io_pattern *pattern, + IN uint64_t offset, + OUT pnfs_io_unit *io); + + +__inline uint64_t stripe_unit_number( + IN pnfs_file_layout *layout, + IN uint64_t offset, + IN uint32_t unit_size) +{ + const uint64_t relative_offset = offset - layout->pattern_offset; + return relative_offset / unit_size; +} +__inline uint32_t stripe_index( + IN pnfs_file_layout *layout, + IN uint64_t sui, + IN uint32_t stripe_count) +{ + return (sui + layout->first_index) % stripe_count; +} +__inline uint32_t data_server_index( + IN pnfs_file_device *device, + IN uint32_t stripeid) +{ + return device->stripes.arr[stripeid]; +} + + +/* pnfs_io.c */ +enum pnfs_status pnfs_read( + IN struct __nfs41_root *root, + IN struct __nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN pnfs_file_layout *layout, + IN uint64_t offset, + IN uint64_t length, + OUT unsigned char *buffer_out, + OUT ULONG *len_out); + +enum pnfs_status pnfs_write( + IN struct __nfs41_root *root, + IN struct __nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN pnfs_file_layout *layout, + IN uint64_t offset, + IN uint64_t length, + IN unsigned char *buffer, + OUT ULONG *len_out); + +#endif /* !__PNFS_H__ */ diff --git a/daemon/pnfs_debug.c b/daemon/pnfs_debug.c new file mode 100644 index 0000000..31ab324 --- /dev/null +++ b/daemon/pnfs_debug.c @@ -0,0 +1,125 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include "pnfs.h" +#include "daemon_debug.h" + + +const char* pnfs_error_string(enum pnfs_status status) +{ + switch (status) { + case PNFS_SUCCESS: return "PNFS_SUCCESS"; + case PNFS_PENDING: return "PNFS_PENDING"; + case PNFS_READ_EOF: return "PNFS_READ_EOF"; + case PNFSERR_NOT_SUPPORTED: return "PNFSERR_NOT_SUPPORTED"; + case PNFSERR_NOT_CONNECTED: return "PNFSERR_NOT_CONNECTED"; + case PNFSERR_IO: return "PNFSERR_IO"; + case PNFSERR_NO_DEVICE: return "PNFSERR_NO_DEVICE"; + case PNFSERR_NO_LAYOUT: return "PNFSERR_NO_LAYOUT"; + case PNFSERR_INVALID_FH_LIST: return "PNFSERR_INVALID_FH_LIST"; + case PNFSERR_INVALID_DS_INDEX: return "PNFSERR_INVALID_DS_INDEX"; + case PNFSERR_RESOURCES: return "PNFSERR_RESOURCES"; + case PNFSERR_LAYOUT_RECALLED: return "PNFSERR_LAYOUT_RECALLED"; + case PNFSERR_LAYOUT_CHANGED: return "PNFSERR_LAYOUT_CHANGED"; + default: return "Invalid pnfs status"; + } +} + +const char* pnfs_layout_type_string(enum pnfs_layout_type type) +{ + switch (type) { + case PNFS_LAYOUTTYPE_FILE: return "PNFS_LAYOUTTYPE_FILE"; + case PNFS_LAYOUTTYPE_OBJECT: return "PNFS_LAYOUTTYPE_OBJECT"; + case PNFS_LAYOUTTYPE_BLOCK: return "PNFS_LAYOUTTYPE_BLOCK"; + default: return "Invalid layout type"; + } +} + +const char* pnfs_iomode_string(enum pnfs_iomode iomode) +{ + switch (iomode) { + case PNFS_IOMODE_READ: return "PNFS_IOMODE_READ"; + case PNFS_IOMODE_RW: return "PNFS_IOMODE_RW"; + case PNFS_IOMODE_ANY: return "PNFS_IOMODE_ANY"; + default: return "Invalid io mode"; + } +} + +void dprint_deviceid( + IN int level, + IN const char *title, + IN const unsigned char *deviceid) +{ + /* deviceid is 16 bytes, so print it as 4 uints */ + uint32_t *p = (uint32_t*)deviceid; + dprintf(level, "%s%08X.%08X.%08X.%08X\n", + title, htonl(p[0]), htonl(p[1]), htonl(p[2]), htonl(p[3])); +} + +void dprint_layout( + IN int level, + IN const pnfs_file_layout *layout) +{ + dprintf(level, " type: %s\n", pnfs_layout_type_string(layout->layout.type)); + dprintf(level, " iomode: %s\n", pnfs_iomode_string(layout->layout.iomode)); + dprint_deviceid(level, " deviceid: ", layout->deviceid); + dprintf(level, " offset: %llu\n", layout->layout.offset); + dprintf(level, " length: %llu\n", layout->layout.length); + dprintf(level, " pattern_offset: %llu\n", layout->pattern_offset); + dprintf(level, " first_index: %u\n", layout->first_index); + dprintf(level, " dense: %u\n", is_dense(layout)); + dprintf(level, " commit_to_mds: %u\n", should_commit_to_mds(layout)); + dprintf(level, " stripe_unit_size: %u\n", layout_unit_size(layout)); + dprintf(level, " file handles: %u\n", layout->filehandles.count); +} + +#define MULTI_ADDR_BUFFER_LEN \ + (NFS41_ADDRS_PER_SERVER*(NFS41_UNIVERSAL_ADDR_LEN+1)+1) + +static void dprint_multi_addr( + IN int level, + IN uint32_t index, + IN const multi_addr4 *addrs) +{ + char buffer[MULTI_ADDR_BUFFER_LEN] = ""; + uint32_t i; + for (i = 0; i < addrs->count; i++) { + StringCchCatA(buffer, MULTI_ADDR_BUFFER_LEN, addrs->arr[i].uaddr); + StringCchCatA(buffer, MULTI_ADDR_BUFFER_LEN, " "); + } + dprintf(level, " servers[%d]: [ %s]\n", index, buffer); +} + +void dprint_device( + IN int level, + IN const pnfs_file_device *device) +{ + uint32_t i; + dprint_deviceid(level, " deviceid: ", device->device.deviceid); + dprintf(level, " type: %s\n", pnfs_layout_type_string(device->device.type)); + dprintf(level, " stripes: %u\n", device->stripes.count); + for (i = 0; i < device->servers.count; i++) + dprint_multi_addr(level, i, &device->servers.arr[i].addrs); +} diff --git a/daemon/pnfs_device.c b/daemon/pnfs_device.c new file mode 100644 index 0000000..5439703 --- /dev/null +++ b/daemon/pnfs_device.c @@ -0,0 +1,376 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "nfs41_ops.h" +#include "daemon_debug.h" + + +#define FDLVL 2 /* dprintf level for file device logging */ + + +/* pnfs_file_device_list */ +struct pnfs_file_device_list { + struct list_entry head; + CRITICAL_SECTION lock; +}; + +#define device_entry(pos) list_container(pos, pnfs_file_device, entry) + + +static enum pnfs_status file_device_create( + IN const unsigned char *deviceid, + OUT pnfs_file_device **device_out) +{ + enum pnfs_status status = PNFS_SUCCESS; + pnfs_file_device *device; + + device = calloc(1, sizeof(pnfs_file_device)); + if (device == NULL) { + status = PNFSERR_RESOURCES; + goto out; + } + + memcpy(device->device.deviceid, deviceid, PNFS_DEVICEID_SIZE); + InitializeSRWLock(&device->lock); + *device_out = device; +out: + return status; +} + +static void file_device_free( + IN pnfs_file_device *device) +{ + free(device->servers.arr); + free(device->stripes.arr); + free(device); +} + +static int deviceid_compare( + const struct list_entry *entry, + const void *deviceid) +{ + const pnfs_file_device *device = device_entry(entry); + return memcmp(device->device.deviceid, deviceid, PNFS_DEVICEID_SIZE); +} + +static enum pnfs_status file_device_entry_find( + IN struct pnfs_file_device_list *devices, + IN const unsigned char *deviceid, + OUT struct list_entry **entry_out) +{ + *entry_out = list_search(&devices->head, deviceid, deviceid_compare); + return *entry_out ? PNFS_SUCCESS : PNFSERR_NO_DEVICE; +} + +static enum pnfs_status file_device_find_or_create( + IN const unsigned char *deviceid, + IN struct pnfs_file_device_list *devices, + OUT pnfs_file_device **device_out) +{ + struct list_entry *entry; + enum pnfs_status status; + + dprintf(FDLVL, "--> pnfs_file_device_find_or_create()\n"); + + EnterCriticalSection(&devices->lock); + + /* search for an existing device */ + status = file_device_entry_find(devices, deviceid, &entry); + if (status) { + /* create a new device */ + pnfs_file_device *device; + status = file_device_create(deviceid, &device); + if (status == PNFS_SUCCESS) { + /* add it to the list */ + list_add_tail(&devices->head, &device->entry); + *device_out = device; + + dprintf(FDLVL, "<-- pnfs_file_device_find_or_create() " + "returning new device %p\n", device); + } else { + dprintf(FDLVL, "<-- pnfs_file_device_find_or_create() " + "returning %s\n", pnfs_error_string(status)); + } + } else { + *device_out = device_entry(entry); + + dprintf(FDLVL, "<-- pnfs_file_device_find_or_create() " + "returning existing device %p\n", *device_out); + } + + LeaveCriticalSection(&devices->lock); + return status; +} + + +enum pnfs_status pnfs_file_device_list_create( + OUT struct pnfs_file_device_list **devices_out) +{ + enum pnfs_status status = PNFS_SUCCESS; + struct pnfs_file_device_list *devices; + + devices = calloc(1, sizeof(struct pnfs_file_device_list)); + if (devices == NULL) { + status = PNFSERR_RESOURCES; + goto out; + } + + list_init(&devices->head); + InitializeCriticalSection(&devices->lock); + + *devices_out = devices; +out: + return status; +} + +void pnfs_file_device_list_free( + IN struct pnfs_file_device_list *devices) +{ + struct list_entry *entry, *tmp; + + EnterCriticalSection(&devices->lock); + + list_for_each_tmp(entry, tmp, &devices->head) + file_device_free(device_entry(entry)); + + LeaveCriticalSection(&devices->lock); + + free(devices); +} + + +/* pnfs_file_device */ +static enum pnfs_status file_device_status( + IN pnfs_file_device *device) +{ + return device->device.type == 0 ? PNFS_PENDING : PNFS_SUCCESS; +} + +enum pnfs_status pnfs_file_device_get( + IN nfs41_session *session, + IN struct pnfs_file_device_list *devices, + IN unsigned char *deviceid, + OUT pnfs_file_device **device_out) +{ + pnfs_file_device *device; + enum pnfs_status status; + enum nfsstat4 nfsstat; + + dprintf(FDLVL, "--> pnfs_file_device_get()\n"); + + status = file_device_find_or_create(deviceid, devices, &device); + if (status) + goto out; + + AcquireSRWLockShared(&device->lock); + status = file_device_status(device); + ReleaseSRWLockShared(&device->lock); + + if (status == PNFS_PENDING) { + AcquireSRWLockExclusive(&device->lock); + + status = file_device_status(device); + if (status == PNFS_PENDING) { + nfsstat = pnfs_rpc_getdeviceinfo(session, deviceid, device); + if (nfsstat == NFS4_OK) { + status = PNFS_SUCCESS; + + dprintf(FDLVL, "Received device info:\n"); + dprint_device(FDLVL, device); + } else { + status = PNFSERR_NO_DEVICE; + + eprintf("pnfs_rpc_getdeviceinfo() failed with %s\n", + nfs_error_string(nfsstat)); + } + } + + ReleaseSRWLockExclusive(&device->lock); + } + + *device_out = device; +out: + dprintf(FDLVL, "<-- pnfs_file_device_get() returning %s\n", + pnfs_error_string(status)); + return status; +} + +static enum pnfs_status data_client_status( + IN pnfs_data_server *server, + OUT nfs41_client **client_out) +{ + enum pnfs_status status = PNFSERR_NOT_CONNECTED; + + if (server->client) { + dprintf(FDLVL, "pnfs_data_server_client() returning " + "existing client %llu\n", server->client->clnt_id); + *client_out = server->client; + status = PNFS_SUCCESS; + } + return status; +} + +enum pnfs_status pnfs_data_server_client( + IN nfs41_root *root, + IN pnfs_data_server *server, + IN uint32_t default_lease, + OUT nfs41_client **client_out) +{ + int status; + enum pnfs_status pnfsstat; + + dprintf(FDLVL, "--> pnfs_data_server_client('%s')\n", + server->addrs.arr[0].uaddr); + + /* if we've already created the client, return it */ + AcquireSRWLockShared(&server->lock); + pnfsstat = data_client_status(server, client_out); + ReleaseSRWLockShared(&server->lock); + + if (pnfsstat) { + AcquireSRWLockExclusive(&server->lock); + + pnfsstat = data_client_status(server, client_out); + if (pnfsstat) { + status = nfs41_root_mount_addrs(root, &server->addrs, + 1, default_lease, &server->client); + if (status) { + dprintf(FDLVL, "data_client_create('%s') failed with %d\n", + server->addrs.arr[0].uaddr, status); + } else { + *client_out = server->client; + pnfsstat = PNFS_SUCCESS; + + dprintf(FDLVL, "pnfs_data_server_client() returning " + "new client %llu\n", server->client->clnt_id); + } + } + + ReleaseSRWLockExclusive(&server->lock); + } + return pnfsstat; +} + + +/* 13.4.2. Interpreting the File Layout Using Sparse Packing + * http://tools.ietf.org/html/rfc5661#section-13.4.2 */ + +static enum pnfs_status get_sparse_fh( + IN pnfs_io_pattern *pattern, + IN uint32_t stripeid, + OUT nfs41_path_fh **file_out) +{ + pnfs_file_layout *layout = pattern->layout; + const uint32_t filehandle_count = layout->filehandles.count; + const uint32_t server_count = layout->device->servers.count; + enum pnfs_status status = PNFS_SUCCESS; + + if (filehandle_count == server_count) { + const uint32_t serverid = data_server_index(layout->device, stripeid); + *file_out = &layout->filehandles.arr[serverid]; + } else if (filehandle_count == 1) { + *file_out = &layout->filehandles.arr[0]; + } else if (filehandle_count == 0) { + *file_out = pattern->meta_file; + } else { + eprintf("invalid sparse layout! has %u file handles " + "and %u servers\n", filehandle_count, server_count); + status = PNFSERR_INVALID_FH_LIST; + } + return status; +} + +/* 13.4.3. Interpreting the File Layout Using Dense Packing +* http://tools.ietf.org/html/rfc5661#section-13.4.3 */ + +static enum pnfs_status get_dense_fh( + IN pnfs_io_pattern *pattern, + IN uint32_t stripeid, + OUT nfs41_path_fh **file_out) +{ + pnfs_file_layout *layout = pattern->layout; + const uint32_t filehandle_count = layout->filehandles.count; + const uint32_t stripe_count = layout->device->stripes.count; + enum pnfs_status status = PNFS_SUCCESS; + + if (filehandle_count == stripe_count) { + *file_out = &layout->filehandles.arr[stripeid]; + } else { + eprintf("invalid dense layout! has %u file handles " + "and %u stripes\n", filehandle_count, stripe_count); + status = PNFSERR_INVALID_FH_LIST; + } + return status; +} + +static __inline uint64_t positive_remainder( + IN uint64_t dividend, + IN uint32_t divisor) +{ + const uint64_t remainder = dividend % divisor; + return remainder < divisor ? remainder : remainder + divisor; +} + +/* 13.4.4. Sparse and Dense Stripe Unit Packing + * http://tools.ietf.org/html/rfc5661#section-13.4.4 */ + +enum pnfs_status pnfs_file_device_io_unit( + IN pnfs_io_pattern *pattern, + IN uint64_t offset, + OUT pnfs_io_unit *io) +{ + pnfs_file_layout *layout = pattern->layout; + enum pnfs_status status = PNFS_SUCCESS; + + const uint32_t unit_size = layout_unit_size(layout); + const uint32_t stripe_count = layout->device->stripes.count; + const uint64_t sui = stripe_unit_number(layout, offset, unit_size); + const uint64_t offset_end = layout->pattern_offset + unit_size * (sui + 1); + + io->stripeid = stripe_index(layout, sui, stripe_count); + io->serverid = data_server_index(layout->device, io->stripeid); + + if (is_dense(layout)) { + const uint64_t rel_offset = offset - layout->pattern_offset; + const uint64_t remainder = positive_remainder(rel_offset, unit_size); + const uint32_t stride = unit_size * stripe_count; + + io->offset = (rel_offset / stride) * unit_size + remainder; + + status = get_dense_fh(pattern, io->stripeid, &io->file); + } else { + io->offset = offset; + + status = get_sparse_fh(pattern, io->stripeid, &io->file); + } + + io->buffer = pattern->buffer + offset - pattern->offset_start; + io->length = offset_end - offset; + if (offset + io->length > pattern->offset_end) + io->length = pattern->offset_end - offset; + return status; +} diff --git a/daemon/pnfs_io.c b/daemon/pnfs_io.c new file mode 100644 index 0000000..9b0bd67 --- /dev/null +++ b/daemon/pnfs_io.c @@ -0,0 +1,565 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "nfs41_ops.h" +#include "util.h" +#include "daemon_debug.h" + + +#define IOLVL 2 /* dprintf level for pnfs io logging */ + + +static uint32_t io_unit_count( + const pnfs_file_layout *layout, + uint64_t length) +{ + const uint32_t unit_size = layout_unit_size(layout); + return (uint32_t)(length / unit_size) + (length % unit_size ? 1 : 0); +} + +static enum pnfs_status pattern_init( + IN pnfs_io_pattern *pattern, + IN nfs41_root *root, + IN nfs41_path_fh *meta_file, + IN stateid4 *stateid, + IN pnfs_file_layout *layout, + IN unsigned char *buffer, + IN uint64_t offset, + IN uint64_t length, + IN uint32_t default_lease) +{ +#ifndef PNFS_THREAD_BY_SERVER + pnfs_io_unit io; +#endif + uint64_t pos; + uint32_t i; + enum pnfs_status status; + + /* take a reference on the layout so we don't return it during io */ + status = pnfs_layout_io_start(&layout->layout); + if (status) + goto out; + +#ifdef PNFS_THREAD_BY_SERVER + pattern->count = layout->device->servers.count; +#else + pattern->count = io_unit_count(layout, length); +#endif + pattern->threads = calloc(pattern->count, sizeof(pnfs_io_thread)); + if (pattern->threads == NULL) { + status = PNFSERR_RESOURCES; + free(pattern); + goto out; + } + + pattern->root = root; + pattern->meta_file = meta_file; + pattern->stateid = stateid; + pattern->layout = layout; + pattern->buffer = buffer; + pattern->offset_start = offset; + pattern->offset_end = offset + length; + pattern->default_lease = default_lease; + + pos = pattern->offset_start; + for (i = 0; i < pattern->count; i++) { + pattern->threads[i].pattern = pattern; + pattern->threads[i].stable = DATA_SYNC4; +#ifdef PNFS_THREAD_BY_SERVER + pattern->threads[i].offset = pattern->offset_start; + pattern->threads[i].offset_end = pattern->offset_end; + pattern->threads[i].id = i; +#else + pnfs_file_device_io_unit(pattern, pos, &io); + pattern->threads[i].offset = pos; + pattern->threads[i].offset_end = pos += io.length; + pattern->threads[i].id = io.stripeid; + + if (pattern->threads[i].offset > pattern->offset_end) + pattern->threads[i].offset = pattern->offset_end; + if (pattern->threads[i].offset_end > pattern->offset_end) + pattern->threads[i].offset_end = pattern->offset_end; + + dprintf(IOLVL, "io_unit(off=%llu end=%llu id=%u)\n", + pattern->threads[i].offset, + pattern->threads[i].offset_end, + pattern->threads[i].id); +#endif + } +out: + return status; +} + +static void pattern_free( + IN pnfs_io_pattern *pattern) +{ + /* inform the layout that our io is finished */ + pnfs_layout_io_finished(&pattern->layout->layout); + free(pattern->threads); +} + +static enum pnfs_status thread_next_unit( + IN pnfs_io_thread *thread, + OUT pnfs_io_unit *io) +{ + pnfs_io_pattern *pattern = thread->pattern; + pnfs_file_layout *layout = pattern->layout; + enum pnfs_status status = PNFS_SUCCESS; + + AcquireSRWLockShared(&layout->layout.lock); + + /* stop io if the layout is recalled */ + if (layout->layout.status & PNFS_LAYOUT_CHANGED) { + status = PNFSERR_LAYOUT_CHANGED; + goto out_unlock; + } + if (layout->layout.status & PNFS_LAYOUT_RECALLED) { + status = PNFSERR_LAYOUT_RECALLED; + goto out_unlock; + } + + /* loop until we find an io unit that matches this thread */ + while (thread->offset < thread->offset_end) { + pnfs_file_device_io_unit(pattern, thread->offset, io); + +#ifdef PNFS_THREAD_BY_SERVER + if (io->serverid == thread->id) { +#else + if (io->stripeid == thread->id) { +#endif + status = PNFS_PENDING; + break; + } + + thread->offset += io->length; + } +out_unlock: + ReleaseSRWLockShared(&layout->layout.lock); + return status; +} + +static enum pnfs_status thread_data_server( + IN pnfs_io_thread *thread, + OUT pnfs_data_server **server_out) +{ + pnfs_file_device *device = thread->pattern->layout->device; +#ifdef PNFS_THREAD_BY_SERVER + const uint32_t serverid = thread->id; +#else + const uint32_t serverid = data_server_index(device, thread->id); +#endif + + if (serverid >= device->servers.count) + return PNFSERR_INVALID_DS_INDEX; + + *server_out = &device->servers.arr[serverid]; + return PNFS_SUCCESS; +} + +static enum pnfs_status pattern_fork( + IN pnfs_io_pattern *pattern, + IN pnfs_io_thread_fn thread_fn) +{ + pnfs_io_unit io; +#ifdef PNFS_THREADING + HANDLE *threads; + uint32_t num_threads; +#endif + uint32_t i; + DWORD status; + enum pnfs_status pnfsstat = PNFS_SUCCESS; + + if (pattern->count == 0) + goto out; + +#ifdef PNFS_THREADING + /* create a thread for each unit that has actual io */ + threads = calloc(pattern->count, sizeof(HANDLE)); + if (threads == NULL) { + pnfsstat = PNFSERR_RESOURCES; + goto out; + } + + num_threads = 0; + for (i = 0; i < pattern->count; i++) { + if (thread_next_unit(&pattern->threads[i], &io) == PNFS_PENDING) { + threads[num_threads++] = (HANDLE)_beginthreadex(NULL, 0, + thread_fn, &pattern->threads[i], 0, NULL); + } + } + + if (num_threads) { /* wait on all threads to finish */ + status = WaitForMultipleObjects(num_threads, threads, TRUE, INFINITE); + if (status == WAIT_OBJECT_0) + status = NO_ERROR; + + for (i = 0; i < num_threads; i++) { + /* keep track of the most severe error returned by a thread */ + if (GetExitCodeThread(threads[i], &status)) + pnfsstat = max(pnfsstat, (enum pnfs_status)status); + + CloseHandle(threads[i]); + } + } + + free(threads); +#else + /* process each server that has actual io */ + for (i = 0; i < pattern->count; i++) { + if (thread_next_unit(&pattern->threads[i], &io) == PNFS_PENDING) { + /* keep track of the most severe error returned by a thread */ + status = thread_fn(&pattern->threads[i]); + pnfsstat = max(pnfsstat, (enum pnfs_status)status); + } + } +#endif +out: + return pnfsstat; +} + +static uint64_t pattern_bytes_transferred( + IN pnfs_io_pattern *pattern, + OUT OPTIONAL enum stable_how4 *stable) +{ + uint64_t lowest_offset = pattern->offset_end; + uint32_t i; + + if (stable) *stable = DATA_SYNC4; + + for (i = 0; i < pattern->count; i++) { + if (lowest_offset > pattern->threads[i].offset) + lowest_offset = pattern->threads[i].offset; + if (stable && pattern->threads[i].stable == UNSTABLE4) + *stable = UNSTABLE4; + } + + return lowest_offset - pattern->offset_start; +} + + +static enum pnfs_status map_ds_error( + IN enum nfsstat4 nfsstat, + IN pnfs_layout *layout) +{ + switch (nfsstat) { + case NO_ERROR: + return PNFS_SUCCESS; + + /* 13.11 Layout Revocation and Fencing + * http://tools.ietf.org/html/rfc5661#section-13.11 + * if we've been fenced, we'll either get ERR_STALE when we PUTFH + * something in layout.filehandles, or ERR_PNFS_NO_LAYOUT when + * attempting to READ or WRITE */ + case NFS4ERR_STALE: + case NFS4ERR_PNFS_NO_LAYOUT: + dprintf(IOLVL, "data server fencing detected!\n"); + + AcquireSRWLockExclusive(&layout->lock); + /* flag the layout for return once io is finished */ + layout->status |= PNFS_LAYOUT_RECALLED | PNFS_LAYOUT_CHANGED; + /* reset GRANTED so we know not to try LAYOUTRETURN */ + layout->status &= ~PNFS_LAYOUT_GRANTED; + ReleaseSRWLockExclusive(&layout->lock); + + /* return CHANGED to prevent any further use of the layout */ + return PNFSERR_LAYOUT_CHANGED; + + default: + return PNFSERR_IO; + } +} + +static uint32_t WINAPI file_layout_read_thread(void *args) +{ + pnfs_io_unit io; + pnfs_io_thread *thread = (pnfs_io_thread*)args; + pnfs_io_pattern *pattern = thread->pattern; + stateid4 *state = pattern->stateid; + pnfs_data_server *server; + nfs41_client *client; + uint32_t maxreadsize, bytes_read, total_read; + enum pnfs_status status; + enum nfsstat4 nfsstat; + bool_t eof; + + dprintf(IOLVL, "--> file_layout_read_thread(%u)\n", thread->id); + + /* get the data server for this thread */ + status = thread_data_server(thread, &server); + if (status) { + eprintf("thread_data_server() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + /* find or establish a client for this data server */ + status = pnfs_data_server_client(pattern->root, + server, pattern->default_lease, &client); + if (status) { + eprintf("pnfs_data_server_client() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + + total_read = 0; + while ((status = thread_next_unit(thread, &io)) == PNFS_PENDING) { + maxreadsize = max_read_size(client->session, &io.file->fh); + if (io.length > maxreadsize) + io.length = maxreadsize; + + nfsstat = nfs41_read(client->session, io.file, state, io.offset, + (uint32_t)io.length, io.buffer, &bytes_read, &eof); + if (nfsstat) { + eprintf("nfs41_read() failed with %s\n", + nfs_error_string(nfsstat)); + status = map_ds_error(nfsstat, &pattern->layout->layout); + break; + } + + total_read += bytes_read; + thread->offset += bytes_read; + + if (eof) { + dprintf(IOLVL, "read thread %u reached eof: offset %llu\n", + thread->id, thread->offset); + status = total_read ? PNFS_SUCCESS : PNFS_READ_EOF; + break; + } + } +out: + dprintf(IOLVL, "<-- file_layout_read_thread(%u) returning %s\n", + thread->id, pnfs_error_string(status)); + return status; +} + +static uint32_t WINAPI file_layout_write_thread(void *args) +{ + pnfs_io_unit io; + nfs41_write_verf verf; + pnfs_io_thread *thread = (pnfs_io_thread*)args; + pnfs_io_pattern *pattern = thread->pattern; + stateid4 *state = pattern->stateid; + pnfs_data_server *server; + pnfs_file_layout *layout = pattern->layout; + nfs41_client *client; + nfs41_path_fh *commit_file; + const uint64_t offset_start = thread->offset; + uint64_t commit_len; + uint32_t maxwritesize, bytes_written, total_written; + enum pnfs_status status; + enum nfsstat4 nfsstat; + + dprintf(IOLVL, "--> file_layout_write_thread(%u)\n", thread->id); + + /* get the data server for this thread */ + status = thread_data_server(thread, &server); + if (status) { + eprintf("thread_data_server() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + /* find or establish a client for this data server */ + status = pnfs_data_server_client(pattern->root, + server, pattern->default_lease, &client); + if (status) { + eprintf("pnfs_data_server_client() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + +retry_write: + thread->offset = offset_start; + thread->stable = DATA_SYNC4; + commit_file = NULL; + total_written = 0; + + while ((status = thread_next_unit(thread, &io)) == PNFS_PENDING) { + maxwritesize = max_write_size(client->session, &io.file->fh); + if (io.length > maxwritesize) + io.length = maxwritesize; + + nfsstat = nfs41_write(client->session, io.file, state, io.buffer, + (uint32_t)io.length, io.offset, UNSTABLE4, &bytes_written, &verf); + if (nfsstat) { + eprintf("nfs41_write() failed with %s\n", + nfs_error_string(nfsstat)); + status = map_ds_error(nfsstat, &layout->layout); + break; + } + if (!verify_write(&verf, &thread->stable)) + goto retry_write; + + total_written += bytes_written; + thread->offset += bytes_written; + commit_file = io.file; + } + + commit_len = thread->offset - pattern->offset_start; + /* nothing to commit */ + if (commit_len == 0) + goto out; + /* layout changed; redo all io against metadata server */ + if (status == PNFSERR_LAYOUT_CHANGED) + goto out; + /* XXX: commit offsets (and possibly fh) are different in dense layouts! */ + if (is_dense(layout)) + goto out; + /* the data is already in stable storage */ + if (thread->stable != UNSTABLE4) + goto out; + /* the metadata server expects us to commit there instead */ + if (should_commit_to_mds(layout)) + goto out; + + dprintf(1, "sending COMMIT to data server for offset=%d and len=%d\n", + pattern->offset_start, commit_len); + nfsstat = nfs41_commit(client->session, commit_file, + pattern->offset_start, (uint32_t)commit_len, 0); + + /* on successful commit, leave pnfs_status unchanged; if the layout + * was recalled, we still want to return the error */ + if (nfsstat == NFS4_OK) + thread->stable = DATA_SYNC4; + else + status = map_ds_error(nfsstat, &pattern->layout->layout); +out: + dprintf(IOLVL, "<-- file_layout_write_thread(%u) returning %s\n", + thread->id, pnfs_error_string(status)); + return status; +} + + +enum pnfs_status pnfs_read( + IN nfs41_root *root, + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN pnfs_file_layout *layout, + IN uint64_t offset, + IN uint64_t length, + OUT unsigned char *buffer_out, + OUT ULONG *len_out) +{ + pnfs_io_pattern pattern; + enum pnfs_status status; + + dprintf(IOLVL, "--> pnfs_read(%llu, %llu)\n", offset, length); + + *len_out = 0; + + status = pattern_init(&pattern, root, file, stateid, + layout, buffer_out, offset, length, session->lease_time); + if (status) { + eprintf("pattern_init() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + + status = pattern_fork(&pattern, file_layout_read_thread); + if (status != PNFS_SUCCESS && status != PNFS_READ_EOF) + goto out_free_pattern; + + *len_out = (ULONG)pattern_bytes_transferred(&pattern, NULL); + +out_free_pattern: + pattern_free(&pattern); +out: + dprintf(IOLVL, "<-- pnfs_read() returning %s\n", + pnfs_error_string(status)); + return status; +} + +enum pnfs_status pnfs_write( + IN nfs41_root *root, + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN stateid4 *stateid, + IN pnfs_file_layout *layout, + IN uint64_t offset, + IN uint64_t length, + IN unsigned char *buffer, + OUT ULONG *len_out) +{ + pnfs_io_pattern pattern; + uint64_t new_last_offset; + enum stable_how4 stable; + enum pnfs_status status; + enum nfsstat4 nfsstat; + + dprintf(IOLVL, "--> pnfs_write(%llu, %llu)\n", offset, length); + + *len_out = 0; + + status = pattern_init(&pattern, root, file, stateid, + layout, buffer, offset, length, session->lease_time); + if (status) { + eprintf("pattern_init() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + + status = pattern_fork(&pattern, file_layout_write_thread); + /* on layout recall, we still attempt to commit what we wrote */ + if (status != PNFS_SUCCESS && status != PNFSERR_LAYOUT_RECALLED) + goto out_free_pattern; + + *len_out = (ULONG)pattern_bytes_transferred(&pattern, &stable); + if (*len_out == 0) + goto out_free_pattern; + + if (stable == UNSTABLE4) { + /* not all data was committed, so commit to metadata server. + * pass do_getattr=0 to nfs41_commit() because we'll GETATTR + * after LAYOUTCOMMIT */ + dprintf(1, "sending COMMIT to meta server for offset=%d and len=%d\n", + offset, *len_out); + nfsstat = nfs41_commit(session, pattern.meta_file, offset, *len_out, 0); + if (nfsstat) { + dprintf(IOLVL, "nfs41_commit() failed with %s\n", + nfs_error_string(nfsstat)); + status = PNFSERR_IO; + goto out_free_pattern; + } + } + + /* send LAYOUTCOMMIT */ + new_last_offset = offset + *len_out - 1; + + nfsstat = pnfs_rpc_layoutcommit(session, pattern.meta_file, + &pattern.layout->layout.state, offset, *len_out, + &new_last_offset, NULL); + if (nfsstat) { + dprintf(IOLVL, "pnfs_rpc_layoutcommit() failed with %s\n", + nfs_error_string(nfsstat)); + /* acceptable failure? if COMMIT worked, return success */ + } + +out_free_pattern: + pattern_free(&pattern); +out: + dprintf(IOLVL, "<-- pnfs_write() returning %s\n", + pnfs_error_string(status)); + return status; +} diff --git a/daemon/pnfs_layout.c b/daemon/pnfs_layout.c new file mode 100644 index 0000000..137e004 --- /dev/null +++ b/daemon/pnfs_layout.c @@ -0,0 +1,835 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include + +#include "nfs41_ops.h" +#include "nfs41_callback.h" +#include "util.h" +#include "daemon_debug.h" + + +#define FLLVL 2 /* dprintf level for file layout logging */ + + +/* pnfs_file_layout_list */ +struct pnfs_file_layout_list { + struct list_entry head; + CRITICAL_SECTION lock; +}; + +#define layout_entry(pos) list_container(pos, pnfs_file_layout, entry) + +static enum pnfs_status layout_create( + IN const nfs41_fh *meta_fh, + OUT pnfs_file_layout **layout_out) +{ + pnfs_file_layout *layout; + enum pnfs_status status = PNFS_SUCCESS; + + layout = calloc(1, sizeof(pnfs_file_layout)); + if (layout == NULL) { + status = PNFSERR_RESOURCES; + goto out; + } + + layout->layout.type = PNFS_LAYOUTTYPE_FILE; + fh_copy(&layout->meta_fh, meta_fh); + InitializeSRWLock(&layout->layout.lock); + + *layout_out = layout; +out: + return status; +} + +static void layout_free( + IN pnfs_file_layout *layout) +{ + free(layout->filehandles.arr); + free(layout); +} + +static int layout_entry_compare( + IN const struct list_entry *entry, + IN const void *value) +{ + const pnfs_file_layout *layout = layout_entry(entry); + const nfs41_fh *meta_fh = (const nfs41_fh*)value; + const nfs41_fh *layout_fh = (const nfs41_fh*)&layout->meta_fh; + const uint32_t diff = layout_fh->len - meta_fh->len; + return diff ? diff : memcmp(layout_fh->fh, meta_fh->fh, meta_fh->len); +} + +static enum pnfs_status layout_entry_find( + IN struct pnfs_file_layout_list *layouts, + IN const nfs41_fh *meta_fh, + OUT struct list_entry **entry_out) +{ + *entry_out = list_search(&layouts->head, meta_fh, layout_entry_compare); + return *entry_out ? PNFS_SUCCESS : PNFSERR_NO_LAYOUT; +} + +enum pnfs_status pnfs_file_layout_list_create( + OUT struct pnfs_file_layout_list **layouts_out) +{ + struct pnfs_file_layout_list *layouts; + enum pnfs_status status = PNFS_SUCCESS; + + layouts = calloc(1, sizeof(struct pnfs_file_layout_list)); + if (layouts == NULL) { + status = PNFSERR_RESOURCES; + goto out; + } + list_init(&layouts->head); + InitializeCriticalSection(&layouts->lock); + *layouts_out = layouts; +out: + return status; +} + +void pnfs_file_layout_list_free( + IN struct pnfs_file_layout_list *layouts) +{ + struct list_entry *entry, *tmp; + + EnterCriticalSection(&layouts->lock); + + list_for_each_tmp(entry, tmp, &layouts->head) + layout_free(layout_entry(entry)); + + LeaveCriticalSection(&layouts->lock); + + free(layouts); +} + +static enum pnfs_status file_layout_find_or_create( + IN struct pnfs_file_layout_list *layouts, + IN const nfs41_fh *meta_fh, + OUT pnfs_file_layout **layout_out) +{ + struct list_entry *entry; + enum pnfs_status status; + + dprintf(FLLVL, "--> file_layout_find_or_create()\n"); + + EnterCriticalSection(&layouts->lock); + + /* search for an existing layout */ + status = layout_entry_find(layouts, meta_fh, &entry); + if (status) { + /* create a new layout */ + pnfs_file_layout *layout; + status = layout_create(meta_fh, &layout); + if (status == PNFS_SUCCESS) { + /* add it to the list */ + list_add_head(&layouts->head, &layout->entry); + *layout_out = layout; + + dprintf(FLLVL, "<-- file_layout_find_or_create() " + "returning new layout %p\n", layout); + } else { + dprintf(FLLVL, "<-- file_layout_find_or_create() " + "returning %s\n", pnfs_error_string(status)); + } + } else { + *layout_out = layout_entry(entry); + + dprintf(FLLVL, "<-- file_layout_find_or_create() " + "returning existing layout %p\n", *layout_out); + } + + LeaveCriticalSection(&layouts->lock); + return status; +} + +static enum pnfs_status file_layout_find_and_delete( + IN struct pnfs_file_layout_list *layouts, + IN const nfs41_fh *meta_fh) +{ + struct list_entry *entry; + enum pnfs_status status; + + dprintf(FLLVL, "--> file_layout_find_and_delete()\n"); + + EnterCriticalSection(&layouts->lock); + + status = layout_entry_find(layouts, meta_fh, &entry); + if (status == PNFS_SUCCESS) { + list_remove(entry); + layout_free(layout_entry(entry)); + } + + LeaveCriticalSection(&layouts->lock); + + dprintf(FLLVL, "<-- file_layout_find_and_delete() " + "returning %s\n", pnfs_error_string(status)); + return status; +} + + +/* pnfs_file_layout */ +static enum pnfs_status file_layout_fetch( + IN OUT pnfs_file_layout *layout, + IN nfs41_session *session, + IN nfs41_path_fh *meta_file, + IN stateid4 *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length) +{ + enum pnfs_status pnfsstat = PNFS_SUCCESS; + enum nfsstat4 nfsstat; + + dprintf(FLLVL, "--> file_layout_fetch(%s, seqid=%u)\n", + pnfs_iomode_string(iomode), layout->layout.state.seqid); + + nfsstat = pnfs_rpc_layoutget(session, meta_file, + state, iomode, offset, length, layout); + if (nfsstat) { + dprintf(FLLVL, "pnfs_rpc_layoutget() failed with %s\n", + nfs_error_string(nfsstat)); + pnfsstat = PNFSERR_NOT_SUPPORTED; + } + + switch (nfsstat) { + case NFS4_OK: + /* mark granted and clear other flags */ + layout->layout.status = PNFS_LAYOUT_GRANTED; + + dprintf(FLLVL, "Received layout:\n"); + dprint_layout(FLLVL, layout); + break; + + case NFS4ERR_BADIOMODE: + /* don't try RW again */ + if (iomode == PNFS_IOMODE_RW) + layout->layout.status |= PNFS_LAYOUT_NOT_RW; + break; + + case NFS4ERR_LAYOUTUNAVAILABLE: + case NFS4ERR_UNKNOWN_LAYOUTTYPE: + case NFS4ERR_BADLAYOUT: + /* don't try again at all */ + layout->layout.status |= PNFS_LAYOUT_UNAVAILABLE; + break; + } + + dprintf(FLLVL, "<-- file_layout_fetch() returning %s\n", + pnfs_error_string(pnfsstat)); + return pnfsstat; +} + +static bool_t layout_recalled( + IN const pnfs_layout *layout) +{ + return (layout->status & PNFS_LAYOUT_RECALLED) != 0; +} + +static bool_t layout_granted( + IN const pnfs_layout *layout) +{ + return (layout->status & PNFS_LAYOUT_GRANTED) != 0; +} + +static bool_t layout_not_rw( + IN const pnfs_layout *layout) +{ + return (layout->status & PNFS_LAYOUT_NOT_RW) != 0; +} + +static bool_t will_never_grant( + IN const pnfs_layout *layout, + IN enum pnfs_iomode iomode) +{ + return (layout->status & PNFS_LAYOUT_UNAVAILABLE) != 0 + || (iomode == PNFS_IOMODE_RW && layout_not_rw(layout)); +} + +static enum pnfs_status layout_grant_status( + IN const pnfs_layout *layout, + IN enum pnfs_iomode iomode) +{ + enum pnfs_status status = PNFS_PENDING; + + if (layout_recalled(layout)) { + /* don't use a recalled layout */ + status = PNFSERR_LAYOUT_RECALLED; + } else if (layout_granted(layout)) { + /* the layout is granted; use it if it's compatible */ + status = PNFS_SUCCESS; + } else if (will_never_grant(layout, iomode)) { + /* an error from LAYOUTGET indicated that the server + * won't ever grant this layout, so stop trying */ + status = PNFSERR_NOT_SUPPORTED; + } + return status; +} + +static enum pnfs_status file_layout_cache( + IN OUT pnfs_file_layout *layout, + IN nfs41_session *session, + IN nfs41_path_fh *meta_file, + IN stateid4 *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length) +{ + enum pnfs_status status; + + /* use a shared lock to see if it's already been granted */ + AcquireSRWLockShared(&layout->layout.lock); + status = layout_grant_status(&layout->layout, iomode); + ReleaseSRWLockShared(&layout->layout.lock); + + if (status == PNFS_PENDING) { + /* use an exclusive lock while attempting to get a new layout */ + AcquireSRWLockExclusive(&layout->layout.lock); + + status = layout_grant_status(&layout->layout, iomode); + if (status == PNFS_PENDING) { + /* if there's an existing layout stateid, use it */ + if (layout->layout.state.seqid) + state = &layout->layout.state; + + if (!layout_not_rw(&layout->layout)) { + /* try to get a RW layout first */ + status = file_layout_fetch(layout, session, + meta_file, state, PNFS_IOMODE_RW, offset, length); + } + + if (status && iomode == PNFS_IOMODE_READ) { + /* fall back on READ if necessary */ + status = file_layout_fetch(layout, session, + meta_file, state, iomode, offset, length); + } + } + + ReleaseSRWLockExclusive(&layout->layout.lock); + } + return status; +} + +static enum pnfs_status layout_compatible( + IN OUT pnfs_layout *layout, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length) +{ + enum pnfs_status status = PNFS_SUCCESS; + + AcquireSRWLockShared(&layout->lock); + + if (iomode == PNFS_IOMODE_RW && layout->iomode == PNFS_IOMODE_READ) { + status = PNFSERR_NOT_SUPPORTED; + goto out_unlock; + } + if (offset < layout->offset || + offset + length > layout->offset + layout->length) { + status = PNFSERR_NOT_SUPPORTED; + goto out_unlock; + } +out_unlock: + ReleaseSRWLockShared(&layout->lock); + return status; +} + +static enum pnfs_status file_device_status( + IN const pnfs_layout *layout) +{ + enum pnfs_status status = PNFS_PENDING; + + if (layout_recalled(layout)) { + /* don't fetch deviceinfo for a recalled layout */ + status = PNFSERR_LAYOUT_RECALLED; + } else if (layout->status & PNFS_LAYOUT_HAS_DEVICE) { + /* deviceinfo already cached */ + status = PNFS_SUCCESS; + } + return status; +} + +static enum pnfs_status file_layout_device( + IN OUT pnfs_file_layout *layout, + IN nfs41_session *session) +{ + enum pnfs_status status = PNFS_PENDING; + + /* use a shared lock to see if we already have a device */ + AcquireSRWLockShared(&layout->layout.lock); + status = file_device_status(&layout->layout); + ReleaseSRWLockShared(&layout->layout.lock); + + if (status == PNFS_PENDING) { + /* use an exclusive lock to look up device info */ + AcquireSRWLockExclusive(&layout->layout.lock); + + status = file_device_status(&layout->layout); + if (status == PNFS_PENDING) { + status = pnfs_file_device_get(session, session->client->devices, + layout->deviceid, &layout->device); + if (status == PNFS_SUCCESS) + layout->layout.status |= PNFS_LAYOUT_HAS_DEVICE; + } + + ReleaseSRWLockExclusive(&layout->layout.lock); + } + return status; +} + +static enum pnfs_status file_layout_get( + IN OUT pnfs_file_layout *layout, + IN nfs41_session *session, + IN nfs41_path_fh *meta_file, + IN stateid4 *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length) +{ + enum pnfs_status status; + + /* request a range for the entire file */ + status = file_layout_cache(layout, session, + meta_file, state, iomode, 0, NFS4_UINT64_MAX); + if (status) { + dprintf(FLLVL, "file_layout_cache() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + + /* fail if we don't get everything we asked for */ + status = layout_compatible(&layout->layout, iomode, offset, length); + if (status) { + dprintf(FLLVL, "file_layout_compatible() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + + /* make sure we have a device for the layout */ + status = file_layout_device(layout, session); + if (status) { + dprintf(FLLVL, "file_layout_device() failed with %s\n", + pnfs_error_string(status)); + goto out; + } +out: + return status; +} + +static enum pnfs_status layout_return_status( + IN const pnfs_file_layout *layout) +{ + return (layout->layout.status & PNFS_LAYOUT_GRANTED) == 0 + ? PNFS_SUCCESS : PNFS_PENDING; +} + +static enum pnfs_status file_layout_return( + IN nfs41_session *session, + IN nfs41_path_fh *file, + IN pnfs_file_layout *layout) +{ + enum pnfs_status status; + enum nfsstat4 nfsstat; + + dprintf(FLLVL, "--> file_layout_return()\n"); + + /* under shared lock, determine whether we need to return the layout */ + AcquireSRWLockShared(&layout->layout.lock); + status = layout_return_status(layout); + ReleaseSRWLockShared(&layout->layout.lock); + + if (status == PNFS_PENDING) { + /* under exclusive lock, return the layout and reset status flags */ + AcquireSRWLockExclusive(&layout->layout.lock); + + status = layout_return_status(layout); + if (status == PNFS_PENDING) { + /* reset the granted flag */ + layout->layout.status &= ~PNFS_LAYOUT_GRANTED; + + nfsstat = pnfs_rpc_layoutreturn(session, file, layout); + if (nfsstat) { + eprintf("pnfs_rpc_layoutreturn() failed with %s\n", + nfs_error_string(nfsstat)); + status = PNFSERR_NO_LAYOUT; + } else { + status = PNFS_SUCCESS; + } + } + + ReleaseSRWLockExclusive(&layout->layout.lock); + } + + dprintf(FLLVL, "<-- file_layout_return() returning %s\n", + pnfs_error_string(status)); + return status; +} + + +/* nfs41_open_state */ +static enum pnfs_status client_supports_pnfs( + IN nfs41_client *client) +{ + enum pnfs_status status; + AcquireSRWLockShared(&client->exid_lock); + status = client->roles & EXCHGID4_FLAG_USE_PNFS_MDS + ? PNFS_SUCCESS : PNFSERR_NOT_SUPPORTED; + ReleaseSRWLockShared(&client->exid_lock); + return status; +} + +static enum pnfs_status fs_supports_layout( + IN const nfs41_superblock *superblock, + IN enum pnfs_layout_type type) +{ + const uint32_t flag = 1 << (type - 1); + return (superblock->layout_types & flag) == 0 + ? PNFSERR_NOT_SUPPORTED : PNFS_SUCCESS; +} + +static enum pnfs_status open_state_layout_cached( + IN nfs41_open_state *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length, + OUT pnfs_file_layout **layout_out) +{ + enum pnfs_status status = PNFSERR_NO_LAYOUT; + + if (state->layout) { + status = PNFS_SUCCESS; + *layout_out = state->layout; + + dprintf(FLLVL, "pnfs_open_state_layout() found " + "cached layout %p\n", *layout_out); + } + return status; +} + +enum pnfs_status pnfs_open_state_layout( + IN struct pnfs_file_layout_list *layouts, + IN nfs41_session *session, + IN nfs41_open_state *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length, + OUT pnfs_file_layout **layout_out) +{ + pnfs_file_layout *layout; + enum pnfs_status status; + + dprintf(FLLVL, "--> pnfs_open_state_layout()\n"); + + status = client_supports_pnfs(session->client); + if (status) + goto out; + status = fs_supports_layout(state->file.fh.superblock, PNFS_LAYOUTTYPE_FILE); + if (status) + goto out; + + /* under shared lock, check open state for cached layouts */ + AcquireSRWLockShared(&state->lock); + status = open_state_layout_cached(state, iomode, offset, length, &layout); + ReleaseSRWLockShared(&state->lock); + + if (status) { + /* under exclusive lock, find or create a layout for this file */ + AcquireSRWLockExclusive(&state->lock); + + status = open_state_layout_cached(state, iomode, offset, length, &layout); + if (status) { + status = file_layout_find_or_create(layouts, &state->file.fh, &layout); + if (status == PNFS_SUCCESS) { + state->layout = layout; + + dprintf(FLLVL, "pnfs_open_state_layout() caching layout %p\n", + state->layout); + } + } + + ReleaseSRWLockExclusive(&state->lock); + + if (status) + goto out; + } + + /* make sure the layout can satisfy this request */ + status = file_layout_get(layout, session, &state->file, + &state->stateid, iomode, offset, length); + if (status) { + dprintf(FLLVL, "file_layout_get() failed with %s\n", + pnfs_error_string(status)); + goto out; + } + + *layout_out = layout; +out: + dprintf(FLLVL, "<-- pnfs_open_state_layout() returning %s\n", + pnfs_error_string(status)); + return status; +} + +void pnfs_open_state_close( + IN nfs41_session *session, + IN nfs41_open_state *state, + IN bool_t remove) +{ + pnfs_file_layout *layout; + bool_t return_on_close; + enum pnfs_status status; + + AcquireSRWLockExclusive(&state->lock); + layout = state->layout; + state->layout = NULL; + ReleaseSRWLockExclusive(&state->lock); + + if (layout) { + /* check if we need to return the layout on close */ + AcquireSRWLockShared(&layout->layout.lock); + return_on_close = layout->layout.return_on_close; + ReleaseSRWLockShared(&layout->layout.lock); + + if (return_on_close) { + status = file_layout_return(session, &state->file, layout); + if (status) + eprintf("file_layout_return() failed with %s\n", + pnfs_error_string(status)); + } + } + + if (remove && session->client->layouts) { + /* free the layout when the file is removed */ + file_layout_find_and_delete(session->client->layouts, &state->file.fh); + } +} + + +/* pnfs_layout_recall */ + +/* expects the caller to have an exclusive lock */ +static enum pnfs_status layout_recall_return( + IN pnfs_layout *layout) +{ + dprintf(FLLVL, "layout_recall_return() 'forgetting' layout\n"); + + /* since we're forgetful, we don't actually return the layout; + * just zero the stateid since it won't be valid anymore */ + ZeroMemory(&layout->state, sizeof(layout->state)); + layout->status = 0; + + return PNFS_SUCCESS; +} + +static enum pnfs_status file_layout_recall( + IN pnfs_file_layout *layout, + IN const struct cb_layoutrecall_args *recall) +{ + enum pnfs_status status = PNFS_SUCCESS; + + /* under an exclusive lock, flag the layout as recalled */ + AcquireSRWLockExclusive(&layout->layout.lock); + + if (layout->layout.io_count == 0) { + /* if there is no pending io, return the layout now */ + status = layout_recall_return(&layout->layout); + } else { + /* flag the layout as recalled so it can be returned after io */ + layout->layout.status |= PNFS_LAYOUT_RECALLED; + if (recall->changed) + layout->layout.status |= PNFS_LAYOUT_CHANGED; + } + + /* if we got a stateid, update the layout's seqid */ + if (recall->recall.type == PNFS_RETURN_FILE) + layout->layout.state.seqid = recall->recall.args.file.stateid.seqid; + + ReleaseSRWLockExclusive(&layout->layout.lock); + return status; +} + +static enum pnfs_status file_layout_recall_file( + IN struct pnfs_file_layout_list *layouts, + IN const struct cb_layoutrecall_args *recall) +{ + struct list_entry *entry; + enum pnfs_status status; + + dprintf(FLLVL, "--> file_layout_recall_file()\n"); + + EnterCriticalSection(&layouts->lock); + + status = layout_entry_find(layouts, &recall->recall.args.file.fh, &entry); + if (status == PNFS_SUCCESS) + status = file_layout_recall(layout_entry(entry), recall); + + LeaveCriticalSection(&layouts->lock); + + dprintf(FLLVL, "<-- file_layout_recall_file() returning %s\n", + pnfs_error_string(status)); + return status; +} + +static bool_t fsid_matches( + IN const nfs41_fsid *lhs, + IN const nfs41_fsid *rhs) +{ + return lhs->major == rhs->major + && lhs->minor == rhs->minor; +} + +static enum pnfs_status file_layout_recall_fsid( + IN struct pnfs_file_layout_list *layouts, + IN const struct cb_layoutrecall_args *recall) +{ + struct list_entry *entry; + pnfs_file_layout *layout; + nfs41_fh *fh; + enum pnfs_status status = PNFSERR_NO_LAYOUT; + + dprintf(FLLVL, "--> file_layout_recall_fsid(%llu, %llu)\n", + recall->recall.args.fsid.major, recall->recall.args.fsid.minor); + + EnterCriticalSection(&layouts->lock); + + list_for_each(entry, &layouts->head) { + layout = layout_entry(entry); + /* no locks needed to read layout.meta_fh or superblock.fsid, + * because they are only written once on creation */ + fh = &layout->meta_fh; + if (fsid_matches(&recall->recall.args.fsid, &fh->superblock->fsid)) + status = file_layout_recall(layout, recall); + } + + LeaveCriticalSection(&layouts->lock); + + dprintf(FLLVL, "<-- file_layout_recall_fsid() returning %s\n", + pnfs_error_string(status)); + return status; +} + +static enum pnfs_status file_layout_recall_all( + IN struct pnfs_file_layout_list *layouts, + IN const struct cb_layoutrecall_args *recall) +{ + struct list_entry *entry; + enum pnfs_status status = PNFSERR_NO_LAYOUT; + + dprintf(FLLVL, "--> file_layout_recall_all()\n"); + + EnterCriticalSection(&layouts->lock); + + list_for_each(entry, &layouts->head) + status = file_layout_recall(layout_entry(entry), recall); + + LeaveCriticalSection(&layouts->lock); + + dprintf(FLLVL, "<-- file_layout_recall_all() returning %s\n", + pnfs_error_string(status)); + return status; +} + +enum pnfs_status pnfs_file_layout_recall( + IN struct pnfs_file_layout_list *layouts, + IN const struct cb_layoutrecall_args *recall) +{ + enum pnfs_status status = PNFS_SUCCESS; + + dprintf(FLLVL, "--> pnfs_file_layout_recall(%u, %s, %u)\n", + recall->recall.type, pnfs_iomode_string(recall->iomode), + recall->changed); + + if (recall->type != PNFS_LAYOUTTYPE_FILE) { + dprintf(FLLVL, "invalid layout type %u (%s)!\n", + recall->type, pnfs_layout_type_string(recall->type)); + status = PNFSERR_NOT_SUPPORTED; + goto out; + } + + switch (recall->recall.type) { + case PNFS_RETURN_FILE: + status = file_layout_recall_file(layouts, recall); + break; + case PNFS_RETURN_FSID: + status = file_layout_recall_fsid(layouts, recall); + break; + case PNFS_RETURN_ALL: + status = file_layout_recall_all(layouts, recall); + break; + + default: + dprintf(FLLVL, "invalid return type %u!\n", recall->recall); + status = PNFSERR_NOT_SUPPORTED; + goto out; + } + + /* XXX: bulk layout recalls require invalidation of cached device info! + * see CB_LAYOUTRECALL: http://tools.ietf.org/html/rfc5661#section-20.3.3 */ +out: + dprintf(FLLVL, "<-- pnfs_file_layout_recall() returning %s\n", + pnfs_error_string(status)); + return status; +} + + +enum pnfs_status pnfs_layout_io_start( + IN pnfs_layout *layout) +{ + enum pnfs_status status = PNFS_SUCCESS; + + AcquireSRWLockExclusive(&layout->lock); + + if (layout_recalled(layout)) { + /* don't start any more io if the layout has been recalled */ + status = PNFSERR_LAYOUT_RECALLED; + dprintf(FLLVL, "pnfs_layout_io_start() failed, layout was recalled\n"); + } else { + /* take a reference on the layout, so that it won't be recalled + * until all io is finished */ + layout->io_count++; + dprintf(FLLVL, "pnfs_layout_io_start(): count -> %u\n", + layout->io_count); + } + + ReleaseSRWLockExclusive(&layout->lock); + return status; +} + +void pnfs_layout_io_finished( + IN pnfs_layout *layout) +{ + AcquireSRWLockExclusive(&layout->lock); + + /* return the reference to signify that an io request is finished */ + layout->io_count--; + dprintf(FLLVL, "pnfs_layout_io_finished() count -> %u\n", + layout->io_count); + + if (layout->io_count > 0) /* more io pending */ + goto out_unlock; + + /* once all io is finished, check for layout recalls */ + if (layout->status & PNFS_LAYOUT_RECALLED) + layout_recall_return(layout); + +out_unlock: + ReleaseSRWLockExclusive(&layout->lock); +} diff --git a/daemon/rbtree.c b/daemon/rbtree.c new file mode 100644 index 0000000..a080b5d --- /dev/null +++ b/daemon/rbtree.c @@ -0,0 +1,385 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/lib/rbtree.c +*/ + +#include "rbtree.h" + +#pragma warning(disable:4706) + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_right = right->rb_left)) + rb_set_parent(right->rb_left, node); + right->rb_left = node; + + rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_left = left->rb_right)) + rb_set_parent(left->rb_right, node); + left->rb_right = node; + + rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + rb_set_parent(node, left); +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = rb_parent(node)) && rb_is_red(parent)) + { + gparent = rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_right || rb_is_black(other->rb_right)) + { + rb_set_black(other->rb_left); + rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_left || rb_is_black(other->rb_left)) + { + rb_set_black(other->rb_right); + rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + rb_set_black(node); +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + + if (rb_parent(old)) { + if (rb_parent(old)->rb_left == old) + rb_parent(old)->rb_left = node; + else + rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (parent == old) { + parent = node; + } else { + if (child) + rb_set_parent(child, parent); + parent->rb_left = child; + + node->rb_right = old->rb_right; + rb_set_parent(old->rb_right, node); + } + + node->rb_parent_color = old->rb_parent_color; + node->rb_left = old->rb_left; + rb_set_parent(old->rb_left, node); + + goto color; + } + + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *rb_last(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *rb_next(const struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return (struct rb_node *)node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *rb_prev(const struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return (struct rb_node *)node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/daemon/rbtree.h b/daemon/rbtree.h new file mode 100644 index 0000000..2d5e360 --- /dev/null +++ b/daemon/rbtree.h @@ -0,0 +1,159 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include + +struct rb_node +{ + size_t rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +}; + +struct rb_root +{ + struct rb_node *rb_node; +}; + + +#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define rb_color(r) ((r)->rb_parent_color & 1) +#define rb_is_red(r) (!rb_color(r)) +#define rb_is_black(r) rb_color(r) +#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static __inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (size_t)p; +} +static __inline void rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT (struct rb_root) { NULL, } +#define rb_entry(ptr, type, member) CONTAINING_RECORD(ptr, type, member) + +#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(const struct rb_node *); +extern struct rb_node *rb_prev(const struct rb_node *); +extern struct rb_node *rb_first(const struct rb_root *); +extern struct rb_node *rb_last(const struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static __inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (size_t)parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/daemon/readdir.c b/daemon/readdir.c new file mode 100644 index 0000000..1c0ccaf --- /dev/null +++ b/daemon/readdir.c @@ -0,0 +1,627 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include "from_kernel.h" +#include "nfs41_ops.h" +#include "daemon_debug.h" +#include "upcall.h" +#include "util.h" + + +typedef union _FILE_DIR_INFO_UNION { + ULONG NextEntryOffset; + FILE_NAMES_INFORMATION fni; + FILE_DIRECTORY_INFO fdi; + FILE_FULL_DIR_INFO ffdi; + FILE_ID_FULL_DIR_INFO fifdi; + FILE_BOTH_DIR_INFORMATION fbdi; + FILE_ID_BOTH_DIR_INFO fibdi; +} FILE_DIR_INFO_UNION, *PFILE_DIR_INFO_UNION; + + +/* NFS41_DIR_QUERY */ +int parse_readdir(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + readdir_upcall_args *args = &upcall->args.readdir; + + status = safe_read(&buffer, &length, &args->query_class, sizeof(args->query_class)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->buf_len, sizeof(args->buf_len)); + if (status) goto out; + status = get_name(&buffer, &length, args->filter); + if (status) goto out; + status = safe_read(&buffer, &length, &args->initial, sizeof(args->initial)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->restart, sizeof(args->restart)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->single, sizeof(args->single)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->cookie, sizeof(args->cookie)); + if (status) goto out; + if (args->cookie == INVALID_HANDLE_VALUE) { + dprintf(1, "upcall passing empty cookie\n"); + args->cookie = NULL; + } +out: + if (status) + eprintf("parsing NFS41_DIR_QUERY failed with %d\n", status); + else + dprintf(1, "parsing NFS41_DIR_QUERY: info_class=%d buf_len=%d " + "filter='%s'\n\tInitial\\Restart\\Single %d\\%d\\%d " + "root=0x%p state=0x%p cookie=0x%p\n", + args->query_class, args->buf_len, args->filter, + args->initial, args->restart, args->single, + args->root, args->state, args->cookie); + return status; +} + +#define FILTER_STAR '*' +#define FILTER_QM '>' + +static __inline int readdir_has_wildcards( + const char *filter) +{ + return strchr(filter, FILTER_STAR) || strchr(filter, FILTER_QM); +} + +static __inline const char* skip_stars( + const char *filter) +{ + while (*filter == FILTER_STAR) + filter++; + return filter; +} + +static int readdir_filter( + const char *filter, + const char *name) +{ + const char *f = filter, *n = name; + + while (*f && *n) { + if (*f == FILTER_STAR) { + f = skip_stars(f); + if (*f == '\0') + return 1; + while (*n && !readdir_filter(f, n)) + n++; + } else if (*f == FILTER_QM || *f == *n) { + f++; + n++; + } else + return 0; + } + return *f == *n || *skip_stars(f) == '\0'; +} + +static uint32_t readdir_size_for_entry( + IN int query_class, + IN uint32_t wname_size) +{ + uint32_t needed = wname_size; + switch (query_class) + { + case FileDirectoryInformation: + needed += FIELD_OFFSET(FILE_DIRECTORY_INFO, FileName); + break; + case FileIdFullDirectoryInformation: + needed += FIELD_OFFSET(FILE_ID_FULL_DIR_INFO, FileName); + break; + case FileFullDirectoryInformation: + needed += FIELD_OFFSET(FILE_FULL_DIR_INFO, FileName); + break; + case FileIdBothDirectoryInformation: + needed += FIELD_OFFSET(FILE_ID_BOTH_DIR_INFO, FileName); + break; + case FileBothDirectoryInformation: + needed += FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName); + break; + case FileNamesInformation: + needed += FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName); + break; + default: + eprintf("unhandled dir query class %d\n", query_class); + return 0; + } + return needed; +} + +static void readdir_copy_dir_info( + IN nfs41_readdir_entry *entry, + IN PFILE_DIR_INFO_UNION info) +{ + info->fdi.FileIndex = 0; + nfs_time_to_file_time(&entry->attr_info.time_create, + &info->fdi.CreationTime); + nfs_time_to_file_time(&entry->attr_info.time_access, + &info->fdi.LastAccessTime); + nfs_time_to_file_time(&entry->attr_info.time_modify, + &info->fdi.LastWriteTime); + /* XXX: was using 'change' attr, but that wasn't giving a time */ + nfs_time_to_file_time(&entry->attr_info.time_modify, + &info->fdi.ChangeTime); + info->fdi.EndOfFile.QuadPart = + info->fdi.AllocationSize.QuadPart = + entry->attr_info.size; + info->fdi.FileAttributes = nfs_file_info_to_attributes( + &entry->attr_info); +} + +static void readdir_copy_shortname( + IN LPCWSTR name, + OUT LPWSTR name_out, + OUT CCHAR *name_size_out) +{ + /* GetShortPathName returns number of characters, not including \0 */ + *name_size_out = (CCHAR)GetShortPathNameW(name, name_out, 12); + if (*name_size_out) { + *name_size_out++; + *name_size_out *= sizeof(WCHAR); + } +} + +static void readdir_copy_full_dir_info( + IN nfs41_readdir_entry *entry, + IN PFILE_DIR_INFO_UNION info) +{ + readdir_copy_dir_info(entry, info); + info->fifdi.EaSize = 0; +} + +static void readdir_copy_both_dir_info( + IN nfs41_readdir_entry *entry, + IN LPWSTR wname, + IN PFILE_DIR_INFO_UNION info) +{ + readdir_copy_full_dir_info(entry, info); + readdir_copy_shortname(wname, info->fbdi.ShortName, + &info->fbdi.ShortNameLength); +} + +static void readdir_copy_filename( + IN LPCWSTR name, + IN uint32_t name_size, + OUT LPWSTR name_out, + OUT ULONG *name_size_out) +{ + *name_size_out = name_size; + memcpy(name_out, name, name_size); +} + +static int readdir_copy_entry( + IN readdir_upcall_args *args, + IN nfs41_readdir_entry *entry, + IN OUT unsigned char **dst_pos, + IN OUT uint32_t *dst_len) +{ + int status = 0; + WCHAR wname[NFS4_OPAQUE_LIMIT]; + uint32_t wname_len, wname_size, needed; + PFILE_DIR_INFO_UNION info; + + wname_len = MultiByteToWideChar(CP_UTF8, 0, + entry->name, entry->name_len, wname, NFS4_OPAQUE_LIMIT); + wname_size = (wname_len - 1) * sizeof(WCHAR); + + needed = readdir_size_for_entry(args->query_class, wname_size); + if (!needed || needed > *dst_len) { + status = -1; + goto out; + } + + info = (PFILE_DIR_INFO_UNION)*dst_pos; + info->NextEntryOffset = align8(needed); + *dst_pos += info->NextEntryOffset; + *dst_len -= info->NextEntryOffset; + + switch (args->query_class) + { + case FileNamesInformation: + info->fni.FileIndex = 0; + readdir_copy_filename(wname, wname_size, + info->fni.FileName, &info->fni.FileNameLength); + break; + case FileDirectoryInformation: + readdir_copy_dir_info(entry, info); + readdir_copy_filename(wname, wname_size, + info->fdi.FileName, &info->fdi.FileNameLength); + break; + case FileFullDirectoryInformation: + readdir_copy_full_dir_info(entry, info); + readdir_copy_filename(wname, wname_size, + info->ffdi.FileName, &info->ffdi.FileNameLength); + break; + case FileIdFullDirectoryInformation: + readdir_copy_full_dir_info(entry, info); + info->fibdi.FileId.QuadPart = (LONGLONG)entry->attr_info.fileid; + readdir_copy_filename(wname, wname_size, + info->fifdi.FileName, &info->fifdi.FileNameLength); + break; + case FileBothDirectoryInformation: + readdir_copy_both_dir_info(entry, wname, info); + readdir_copy_filename(wname, wname_size, + info->fbdi.FileName, &info->fbdi.FileNameLength); + break; + case FileIdBothDirectoryInformation: + readdir_copy_both_dir_info(entry, wname, info); + info->fibdi.FileId.QuadPart = (LONGLONG)entry->attr_info.fileid; + readdir_copy_filename(wname, wname_size, + info->fibdi.FileName, &info->fibdi.FileNameLength); + break; + default: + eprintf("unhandled dir query class %d\n", args->query_class); + status = -1; + break; + } +out: + return status; +} + +#define COOKIE_DOT ((uint64_t)-2) +#define COOKIE_DOTDOT ((uint64_t)-1) + +int readdir_add_dots( + IN readdir_upcall_args *args, + IN OUT unsigned char *entry_buf, + IN uint32_t entry_buf_len, + OUT uint32_t *len_out, + OUT uint32_t **last_offset) +{ + int status = 0; + const uint32_t entry_len = (uint32_t)FIELD_OFFSET(nfs41_readdir_entry, name); + nfs41_readdir_entry *entry; + nfs41_open_state *state = args->state; + + *len_out = 0; + *last_offset = NULL; + switch (args->cookie->cookie) { + case 0: + if (entry_buf_len < entry_len + 2) { + status = ERROR_BUFFER_OVERFLOW; + dprintf(1, "not enough room for '.' entry.\n"); + goto out; + } + + entry = (nfs41_readdir_entry*)entry_buf; + ZeroMemory(&entry->attr_info, sizeof(nfs41_file_info)); + + status = nfs41_cached_getattr(state->session, + &state->file, &entry->attr_info); + if (status) { + dprintf(1, "failed to add '.' entry.\n"); + goto out; + } + entry->cookie = COOKIE_DOT; + entry->name_len = 2; + StringCbCopyA(entry->name, entry->name_len, "."); + entry->next_entry_offset = entry_len + entry->name_len; + + entry_buf += entry->next_entry_offset; + entry_buf_len -= entry->next_entry_offset; + *len_out += entry->next_entry_offset; + *last_offset = &entry->next_entry_offset; + if (args->single) + break; + /* else no break! */ + case COOKIE_DOT: + if (entry_buf_len < entry_len + 3) { + status = ERROR_BUFFER_OVERFLOW; + dprintf(1, "not enough room for '..' entry.\n"); + goto out; + } + /* XXX: this skips '..' when listing root fh */ + if (state->file.name.len == 0) + break; + + entry = (nfs41_readdir_entry*)entry_buf; + ZeroMemory(&entry->attr_info, sizeof(nfs41_file_info)); + + status = nfs41_cached_getattr(state->session, + &state->parent, &entry->attr_info); + if (status) { + status = ERROR_FILE_NOT_FOUND; + dprintf(1, "failed to add '..' entry.\n"); + goto out; + } + entry->cookie = COOKIE_DOTDOT; + entry->name_len = 3; + StringCbCopyA(entry->name, entry->name_len, ".."); + entry->next_entry_offset = entry_len + entry->name_len; + + entry_buf += entry->next_entry_offset; + entry_buf_len -= entry->next_entry_offset; + *len_out += entry->next_entry_offset; + *last_offset = &entry->next_entry_offset; + break; + } + if (args->cookie->cookie == COOKIE_DOTDOT || + args->cookie->cookie == COOKIE_DOT) + ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie)); +out: + return status; +} + +static int single_lookup( + IN nfs41_root *root, + IN nfs41_session *session, + IN nfs41_path_fh *parent, + IN const char *filter, + IN bitmap4 *attr_request, + OUT nfs41_readdir_entry *entry) +{ + nfs41_abs_path path; + nfs41_path_fh file; + int status; + + entry->cookie = 0; + entry->name_len = (uint32_t)strlen(filter) + 1; + StringCbCopyA(entry->name, entry->name_len, filter); + entry->next_entry_offset = 0; + + /* format an absolute path 'parent\filter' */ + InitializeSRWLock(&path.lock); + abs_path_copy(&path, parent->path); + if (path.len + entry->name_len >= NFS41_MAX_PATH_LEN) { + status = ERROR_BUFFER_OVERFLOW; + goto out; + } + StringCchPrintfA(path.path + path.len, + NFS41_MAX_PATH_LEN - path.len, "\\%s", entry->name); + path.len += (unsigned short)entry->name_len; + + path_fh_init(&file, &path); + + status = nfs41_lookup(root, session, &path, + NULL, &file, &entry->attr_info, NULL); + if (status) { + dprintf(1, "nfs41_lookup failed with %s\n", nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out; + } +out: + return status; +} + +int handle_readdir(nfs41_upcall *upcall) +{ + int status; + readdir_upcall_args *args = &upcall->args.readdir; + nfs41_open_state *state = args->state; + unsigned char *entry_buf = NULL; + uint32_t entry_buf_len; + bitmap4 attr_request; + bool_t eof; + + dprintf(1, "-> handle_nfs41_dirquery(%s,%d,%d,%d)\n", + args->filter, args->initial, args->restart, args->single); + + args->buf = NULL; + args->query_reply_len = 0; + + if (args->cookie) { /* cookie exists */ + if (args->restart) { + dprintf(1, "restarting; clearing previous cookie (%d %p)\n", + args->cookie->cookie, args->cookie); + ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie)); + } else if (args->initial) { /* shouldn't happen */ + dprintf(1, "*** initial; clearing previous cookie (%d %p)!\n", + args->cookie->cookie, args->cookie); + ZeroMemory(args->cookie, sizeof(nfs41_readdir_cookie)); + } else + dprintf(1, "resuming enumeration with cookie %d.\n", + args->cookie->cookie); + } else { /* cookie is null */ + if (args->initial || args->restart) { + dprintf(1, "allocating memory for the 1st readdir cookie\n"); + args->cookie = calloc(1, sizeof(nfs41_readdir_cookie)); + if (args->cookie == NULL) { + status = GetLastError(); + goto out; + } + } else { + dprintf(1, "handle_nfs41_readdir: EOF\n"); + status = ERROR_NO_MORE_FILES; + goto out; + } + } + + entry_buf = malloc(args->buf_len); + if (entry_buf == NULL) { + status = GetLastError(); + goto out_free_cookie; + } +fetch_entries: + entry_buf_len = args->buf_len; + + init_getattr_request(&attr_request); + attr_request.arr[0] |= FATTR4_WORD0_RDATTR_ERROR; + + if (readdir_has_wildcards((const char*)args->filter)) { + /* use READDIR for wildcards */ + + uint32_t dots_len = 0; + uint32_t *dots_next_offset = NULL; + + if (args->filter[0] == '*' && args->filter[1] == '\0') { + status = readdir_add_dots(args, entry_buf, + entry_buf_len, &dots_len, &dots_next_offset); + if (status) + goto out_free_cookie; + entry_buf_len -= dots_len; + } + + if (dots_len && args->single) { + dprintf(2, "skipping nfs41_readdir because the single query " + "will use . or ..\n"); + entry_buf_len = 0; + eof = 0; + } else { + dprintf(2, "calling nfs41_readdir with cookie %d %p \n", + args->cookie->cookie, args->cookie); + status = nfs41_readdir(state->session, &state->file, + &attr_request, args->cookie, entry_buf + dots_len, + &entry_buf_len, &eof); + if (status) { + dprintf(1, "nfs41_readdir failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out_free_cookie; + } + } + + if (!entry_buf_len && dots_next_offset) + *dots_next_offset = 0; + entry_buf_len += dots_len; + } else { + /* use LOOKUP for single files */ + nfs41_readdir_entry *entry = (nfs41_readdir_entry*)entry_buf; + entry->cookie = 0; + entry->name_len = (uint32_t)strlen(args->filter) + 1; + StringCbCopyA(entry->name, entry->name_len, args->filter); + entry->next_entry_offset = 0; + + status = single_lookup(args->root, state->session, + &state->file, args->filter, &attr_request, entry); + if (status) { + dprintf(1, "single_lookup failed with %d\n", status); + goto out_free_cookie; + } + entry_buf_len = entry->name_len + + FIELD_OFFSET(nfs41_readdir_entry, name); + + eof = 1; + } + + status = args->initial ? ERROR_FILE_NOT_FOUND : ERROR_NO_MORE_FILES; + + if (entry_buf_len) { + unsigned char *entry_pos = entry_buf; + unsigned char *dst_pos; + uint32_t dst_len = args->buf_len; + nfs41_readdir_entry *entry; + PULONG offset, last_offset = NULL; + + if (args->buf == NULL) { + args->buf = malloc(args->buf_len); + if (args->buf == NULL) { + status = GetLastError(); + goto out_free_cookie; + } + } + dst_pos = args->buf; + + for (;;) { + entry = (nfs41_readdir_entry*)entry_pos; + offset = (PULONG)dst_pos; /* ULONG NextEntryOffset */ + + dprintf(2, "filter %s looking at %s with cookie %d\n", + args->filter, entry->name, entry->cookie); + if (readdir_filter((const char*)args->filter, entry->name)) { + if (readdir_copy_entry(args, entry, &dst_pos, &dst_len)) { + eof = 0; + dprintf(2, "not enough space to copy entry %s (cookie %d)\n", + entry->name, entry->cookie); + break; + } + last_offset = offset; + status = NO_ERROR; + } + args->cookie->cookie = entry->cookie; + + /* last entry we got from the server */ + if (!entry->next_entry_offset) + break; + + /* we found our single entry, but the server has more */ + if (args->single && last_offset) { + eof = 0; + break; + } + entry_pos += entry->next_entry_offset; + } + args->query_reply_len = args->buf_len - dst_len; + if (last_offset) { + *last_offset = 0; + } else if (!eof) { + dprintf(1, "no entries matched; fetch more\n"); + goto fetch_entries; + } + } + + if (eof) { + dprintf(1, "we don't need to save a cookie\n"); + goto out_free_cookie; + } else + dprintf(1, "saving cookie %d %p\n", args->cookie->cookie, args->cookie); + +out_free_entry: + free(entry_buf); +out: + dprintf(1, "<- handle_nfs41_dirquery(%s,%d,%d,%d) returning ", + args->filter, args->initial, args->restart, args->single); + if (status) { + switch (status) { + case ERROR_FILE_NOT_FOUND: + dprintf(1, "ERROR_FILE_NOT_FOUND.\n"); + break; + case ERROR_NO_MORE_FILES: + dprintf(1, "ERROR_NO_MORE_FILES.\n"); + break; + default: + dprintf(1, "error code %d.\n", status); + break; + } + free(args->buf); + args->buf = NULL; + } else { + dprintf(1, "success!\n"); + } + return status; +out_free_cookie: + free(args->cookie); + args->cookie = NULL; + goto out_free_entry; +} + +int marshall_readdir(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + int status; + readdir_upcall_args *args = &upcall->args.readdir; + + status = safe_write(&buffer, length, &args->query_reply_len, sizeof(args->query_reply_len)); + if (status) goto out; + status = safe_write(&buffer, length, args->buf, args->query_reply_len); + if (status) goto out; + status = safe_write(&buffer, length, &args->cookie, sizeof(args->cookie)); +out: + free(args->buf); + return status; +} diff --git a/daemon/readwrite.c b/daemon/readwrite.c new file mode 100644 index 0000000..9b520cb --- /dev/null +++ b/daemon/readwrite.c @@ -0,0 +1,307 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "nfs41_ops.h" +#include "name_cache.h" +#include "upcall.h" +#include "daemon_debug.h" +#include "util.h" + + +int parse_rw(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + readwrite_upcall_args *args = &upcall->args.rw; + + status = safe_read(&buffer, &length, &args->len, sizeof(args->len)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->offset, sizeof(args->offset)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->buffer, sizeof(args->buffer)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); +out: + if (status) + eprintf("parsing %s failed with %d\n", + opcode2string(upcall->opcode), status); + else + dprintf(1, "parsing %s len=%ld offset=%ld buf=%p root=%p " + "open_state=0x%p\n", opcode2string(upcall->opcode), args->len, + args->offset, args->buffer, args->root, args->state); + return status; +} + +/* NFS41_READ */ +static int read_from_mds( + IN nfs41_session *session, + IN stateid4 *stateid, + IN nfs41_path_fh *file, + IN uint64_t offset, + IN uint32_t length, + OUT unsigned char *buffer, + OUT ULONG *len_out) +{ + int status = 0; + bool_t eof; + unsigned char *p = buffer; + ULONG to_rcv = length, reloffset = 0, len = 0; + const uint32_t maxreadsize = max_read_size(session, &file->fh); + + if (to_rcv > maxreadsize) + dprintf(1, "handle_nfs41_read: reading %d in chunks of %d\n", + to_rcv, maxreadsize); + + while(to_rcv > 0) { + uint32_t bytes_read = 0, chunk = min(to_rcv, maxreadsize); + + status = nfs41_read(session, file, stateid, + offset + reloffset, chunk, p, &bytes_read, &eof); + if (status && !len) { + status = nfs_to_windows_error(status, ERROR_NET_WRITE_FAULT); + goto out; + } + p += bytes_read; + to_rcv -= bytes_read; + len += bytes_read; + offset += bytes_read; + if (status) { + status = NO_ERROR; + break; + } + if (eof) { + if (!len) + status = ERROR_HANDLE_EOF; + break; + } + } +out: + *len_out = len; + return status; +} + +static int read_from_pnfs( + IN nfs41_root *root, + IN nfs41_open_state *state, + IN stateid4 *stateid, + IN uint64_t offset, + IN uint32_t length, + OUT unsigned char *buffer, + OUT ULONG *len_out) +{ + pnfs_file_layout *layout; + enum pnfs_status pnfsstat; + int status = NO_ERROR; + + pnfsstat = pnfs_open_state_layout(state->session->client->layouts, + state->session, state, PNFS_IOMODE_READ, offset, length, &layout); + if (pnfsstat) { + status = ERROR_NOT_SUPPORTED; + goto out; + } + + pnfsstat = pnfs_read(root, state->session, &state->file, stateid, + layout, offset, length, buffer, len_out); + switch (pnfsstat) { + case PNFS_SUCCESS: + break; + case PNFS_READ_EOF: + status = ERROR_HANDLE_EOF; + break; + default: + status = ERROR_READ_FAULT; + break; + } +out: + return status; +} + +int handle_read(nfs41_upcall *upcall) +{ + stateid4 stateid, *pstateid; + readwrite_upcall_args *args = &upcall->args.rw; + nfs41_open_state *state = args->state; + ULONG pnfs_bytes_read = 0; + int status = NO_ERROR; + + pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + if (pstateid == NULL) + pstateid = &state->stateid; + +#ifdef PNFS_ENABLE_READ + status = read_from_pnfs(args->root, state, pstateid, + args->offset, args->len, args->buffer, &args->out_len); + + if (status == NO_ERROR || status == ERROR_HANDLE_EOF) + goto out; + + if (args->out_len) { + pnfs_bytes_read = args->out_len; + args->out_len = 0; + + args->offset += pnfs_bytes_read; + args->buffer += pnfs_bytes_read; + args->len -= pnfs_bytes_read; + } +#endif + + status = read_from_mds(state->session, pstateid, &state->file, + args->offset, args->len, args->buffer, &args->out_len); + + args->out_len += pnfs_bytes_read; +out: + return status; +} + +/* NFS41_WRITE */ +static int write_to_mds( + IN nfs41_session *session, + IN stateid4 *stateid, + IN nfs41_path_fh *file, + IN uint64_t offset, + IN uint32_t length, + IN unsigned char *buffer, + OUT ULONG *len_out) +{ + nfs41_write_verf verf; + enum stable_how4 stable, committed; + unsigned char *p; + const uint32_t maxwritesize = max_write_size(session, &file->fh); + uint32_t to_send, reloffset, len; + int status = 0; + +retry_write: + p = buffer; + to_send = length; + reloffset = 0; + len = 0; + stable = to_send <= maxwritesize ? DATA_SYNC4 : UNSTABLE4; + committed = DATA_SYNC4; + + if (to_send > maxwritesize) + dprintf(1, "handle_nfs41_write: writing %d in chunks of %d\n", + to_send, maxwritesize); + + while(to_send > 0) { + uint32_t bytes_written = 0, chunk = min(to_send, maxwritesize); + + status = nfs41_write(session, file, stateid, p, chunk, + offset + reloffset, stable, &bytes_written, &verf); + if (status && !len) + goto out; + p += bytes_written; + to_send -= bytes_written; + len += bytes_written; + reloffset += bytes_written; + if (status) { + status = 0; + break; + } + if (!verify_write(&verf, &committed)) + goto retry_write; + } + if (committed == UNSTABLE4) { + dprintf(1, "sending COMMIT for offset=%d and len=%d\n", offset, len); + status = nfs41_commit(session, file, offset, len, 1); + } +out: + *len_out = len; + return nfs_to_windows_error(status, ERROR_NET_WRITE_FAULT); +} + +static int write_to_pnfs( + IN nfs41_root *root, + IN nfs41_open_state *state, + IN stateid4 *stateid, + IN uint64_t offset, + IN uint32_t length, + IN unsigned char *buffer, + OUT ULONG *len_out) +{ + pnfs_file_layout *layout; + enum pnfs_status pnfsstat; + int status = NO_ERROR; + + pnfsstat = pnfs_open_state_layout(state->session->client->layouts, + state->session, state, PNFS_IOMODE_RW, offset, length, &layout); + if (pnfsstat) { + status = ERROR_NOT_SUPPORTED; + goto out; + } + + pnfsstat = pnfs_write(root, state->session, &state->file, stateid, + layout, offset, length, buffer, len_out); + if (pnfsstat) { + status = ERROR_WRITE_FAULT; + goto out; + } +out: + return status; +} + +int handle_write(nfs41_upcall *upcall) +{ + stateid4 stateid, *pstateid = NULL; + readwrite_upcall_args *args = &upcall->args.rw; + nfs41_open_state *state = args->state; + ULONG pnfs_bytes_written = 0; + int status; + + pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + if (pstateid == NULL) + pstateid = &state->stateid; + +#ifdef PNFS_ENABLE_WRITE + status = write_to_pnfs(args->root, args->state, pstateid, + args->offset, args->len, args->buffer, &args->out_len); + + if (status == NO_ERROR) + goto out; + + if (args->out_len) { + pnfs_bytes_written = args->out_len; + args->out_len = 0; + + args->offset += pnfs_bytes_written; + args->buffer += pnfs_bytes_written; + args->len -= pnfs_bytes_written; + } +#endif + + status = write_to_mds(state->session, pstateid, &state->file, + args->offset, args->len, args->buffer, &args->out_len); + + args->out_len += pnfs_bytes_written; +out: + return status; +} + +int marshall_rw(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + readwrite_upcall_args *args = &upcall->args.rw; + return safe_write(&buffer, length, &args->out_len, sizeof(args->out_len)); +} diff --git a/daemon/setattr.c b/daemon/setattr.c new file mode 100644 index 0000000..ad10a45 --- /dev/null +++ b/daemon/setattr.c @@ -0,0 +1,491 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "from_kernel.h" +#include "nfs41_ops.h" +#include "name_cache.h" +#include "upcall.h" +#include "util.h" +#include "daemon_debug.h" + + +int parse_setattr(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + setattr_upcall_args *args = &upcall->args.setattr; + + ZeroMemory(&args->path, sizeof(nfs41_abs_path)); + status = get_abs_path(&buffer, &length, &args->path); + if (status) goto out; + status = safe_read(&buffer, &length, &args->set_class, sizeof(args->set_class)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->buf_len, sizeof(args->buf_len)); + if (status) goto out; + args->buf = malloc(args->buf_len); + if (args->buf == NULL) { + status = GetLastError(); + goto out; + } + status = safe_read(&buffer, &length, args->buf, args->buf_len); + if (status) goto out_free; + status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); + if (status) goto out_free; + status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); + if (status) goto out_free; + status = safe_read(&buffer, &length, &args->open_owner_id, sizeof(ULONG)); + if (status) goto out_free; + status = safe_read(&buffer, &length, &args->access_mask, sizeof(ULONG)); + if (status) goto out_free; + status = safe_read(&buffer, &length, &args->access_mode, sizeof(ULONG)); +out: + if (status) + eprintf("parsing NFS41_FILE_SET failed with %d\n", status); + else + dprintf(1, "parsing NFS41_FILE_SET: filename='%s' info_class=%d " + "buf_len=%d root=%p open_state=%p\nopen_owner_id=%d " + "access_mask=%x access_mode=%x\n", args->path.path, args->set_class, + args->buf_len, args->root, args->state, args->open_owner_id, + args->access_mask, args->access_mode); + return status; +out_free: + free(args->buf); + goto out; +} + +static void remove_unsupported_attrs( + IN const bitmap4 *supported_attrs, + IN OUT bitmap4 *attrs) +{ + uint32_t i, count = 0; + dprintf(2, "remove_unsupported_attrs\n"); + for (i = 0; i < 3; i++) { + dprintf(2, "\tmask[%d] = %12u", i, attrs->arr[i]); + dprintf(2, " & %12u", supported_attrs->arr[i]); + + attrs->arr[i] &= supported_attrs->arr[i]; + if (attrs->arr[i]) + count = i+1; + + dprintf(2, " = %12d\n", attrs->arr[i]); + } + attrs->count = min(attrs->count, count); + dprintf(2, "\tcount = %d\n", attrs->count); +} + +static int handle_nfs41_setattr(setattr_upcall_args *args) +{ + int status; + PFILE_BASIC_INFO basic_info = (PFILE_BASIC_INFO)args->buf; + nfs41_open_state *state = args->state; + nfs41_superblock *superblock = state->file.fh.superblock; + stateid4 stateid, *pstateid; + nfs41_file_info info; + + pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + if (pstateid == NULL) + pstateid = &state->stateid; + + ZeroMemory(&info, sizeof(info)); + + /* hidden */ + info.hidden = basic_info->FileAttributes & FILE_ATTRIBUTE_HIDDEN ? 1 : 0; + info.attrmask.arr[0] |= FATTR4_WORD0_HIDDEN; + info.attrmask.count = 1; + /* time_create */ + if (basic_info->CreationTime.QuadPart > 0) { + file_time_to_nfs_time(&basic_info->CreationTime, &info.time_create); + info.attrmask.arr[1] |= FATTR4_WORD1_TIME_CREATE; + info.attrmask.count = 2; + } + /* time_access_set */ + if (basic_info->LastAccessTime.QuadPart > 0) { + file_time_to_nfs_time(&basic_info->LastAccessTime, &info.time_access); + info.attrmask.arr[1] |= FATTR4_WORD1_TIME_ACCESS_SET; + info.attrmask.count = 2; + } + /* time_modify_set */ + if (basic_info->LastWriteTime.QuadPart > 0) { + file_time_to_nfs_time(&basic_info->LastWriteTime, &info.time_modify); + info.attrmask.arr[1] |= FATTR4_WORD1_TIME_MODIFY_SET; + info.attrmask.count = 2; + } + /* mode */ + if (basic_info->FileAttributes & FILE_ATTRIBUTE_READONLY) { + info.mode = 0444; + info.attrmask.arr[1] |= FATTR4_WORD1_MODE; + info.attrmask.count = 2; + } + + AcquireSRWLockShared(&superblock->lock); + remove_unsupported_attrs(&superblock->supported_attrs, &info.attrmask); + ReleaseSRWLockShared(&superblock->lock); + + if (!info.attrmask.count) + return 0; + + status = nfs41_setattr(state->session, &state->file, pstateid, &info); + if (status) + dprintf(1, "nfs41_setattr() failed with error %s.\n", + nfs_error_string(status)); + + return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); +} + +static int handle_nfs41_remove(setattr_upcall_args *args) +{ + nfs41_open_state *state = args->state; + int status; + + status = nfs41_remove(state->session, &state->parent, + &state->file.name); + if (status) + dprintf(1, "nfs41_remove() failed with error %s.\n", + nfs_error_string(status)); + + return nfs_to_windows_error(status, ERROR_ACCESS_DENIED); +} + +static void open_state_rename( + OUT nfs41_open_state *state, + IN const nfs41_abs_path *path) +{ + AcquireSRWLockExclusive(&state->path.lock); + + abs_path_copy(&state->path, path); + last_component(state->path.path, state->path.path + state->path.len, + &state->file.name); + last_component(state->path.path, state->file.name.name, + &state->parent.name); + + ReleaseSRWLockExclusive(&state->path.lock); +} + +static int handle_nfs41_rename(setattr_upcall_args *args) +{ + nfs41_open_state *state = args->state; + PFILE_RENAME_INFO rename = (PFILE_RENAME_INFO)args->buf; + nfs41_abs_path dst_path; + nfs41_path_fh dst_dir; + nfs41_component dst_name, *src_name; + int status; + + ZeroMemory(&dst_path, sizeof(dst_path)); + src_name = &state->file.name; + + if (rename->FileNameLength == 0) { + /* start from state->path instead of args->path, in case we got + * the file from a referred server */ + AcquireSRWLockShared(&state->path.lock); + abs_path_copy(&args->path, &state->path); + ReleaseSRWLockShared(&state->path.lock); + + path_fh_init(&dst_dir, &args->path); + fh_copy(&dst_dir.fh, &state->parent.fh); + + create_silly_rename(&args->path, &state->file.fh, &dst_name); + dprintf(1, "silly rename: %s -> %s\n", src_name->name, dst_name.name); + + status = nfs41_rename(state->session, + &state->parent, src_name, + &dst_dir, &dst_name); + if (status) { + dprintf(1, "nfs41_rename() failed with error %s.\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_ACCESS_DENIED); + } else { + /* rename state->path on success */ + open_state_rename(state, &args->path); + } + goto out; + } + + dst_path.len = (unsigned short)WideCharToMultiByte(CP_UTF8, 0, + rename->FileName, rename->FileNameLength/sizeof(WCHAR), + dst_path.path, NFS41_MAX_PATH_LEN, NULL, NULL); + if (dst_path.len == 0) { + eprintf("WideCharToMultiByte failed to convert destination " + "filename %S.\n", rename->FileName); + status = ERROR_INVALID_PARAMETER; + goto out; + } + path_fh_init(&dst_dir, &dst_path); + + /* the destination path is absolute, so start from the root session */ + status = nfs41_lookup(args->root, nfs41_root_session(args->root), + &dst_path, &dst_dir, NULL, NULL, NULL); + + /* get the components after lookup in case a referral changed its path */ + last_component(dst_path.path, dst_path.path + dst_path.len, &dst_name); + last_component(dst_path.path, dst_name.name, &dst_dir.name); + + if (status == NO_ERROR) { + if (!rename->ReplaceIfExists) { + status = ERROR_FILE_EXISTS; + goto out; + } + } else if (status != ERROR_FILE_NOT_FOUND) { + dprintf(1, "nfs41_lookup('%s') failed to find destination " + "directory with %d\n", dst_path.path, status); + goto out; + } + + /* http://tools.ietf.org/html/rfc5661#section-18.26.3 + * "Source and target directories MUST reside on the same + * file system on the server." */ + if (state->parent.fh.superblock != dst_dir.fh.superblock) { + status = ERROR_NOT_SAME_DEVICE; + goto out; + } + + status = nfs41_rename(state->session, + &state->parent, src_name, + &dst_dir, &dst_name); + if (status) { + dprintf(1, "nfs41_rename() failed with error %s.\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_ACCESS_DENIED); + } else { + /* rename state->path on success */ + open_state_rename(state, &dst_path); + } +out: + return status; +} + +static int handle_nfs41_set_size(setattr_upcall_args *args) +{ + nfs41_open_state *state = args->state; + int status; + + /* note: this is called with either FILE_END_OF_FILE_INFO or + * FILE_ALLOCATION_INFO, both of which contain a single LARGE_INTEGER */ + PLARGE_INTEGER size = (PLARGE_INTEGER)args->buf; + stateid4 stateid, *pstateid; + nfs41_file_info info; + + pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + if (pstateid == NULL) + pstateid = &state->stateid; + + ZeroMemory(&info, sizeof(info)); + info.size = size->QuadPart; + + info.attrmask.count = 1; + info.attrmask.arr[0] = FATTR4_WORD0_SIZE; + + dprintf(2, "calling setattr() with size=%lld\n", info.size); + status = nfs41_setattr(state->session, &state->file, pstateid, &info); + if (status) + dprintf(1, "nfs41_setattr() failed with error %s.\n", + nfs_error_string(status)); + + return status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); +} + +int handle_nfs41_link(setattr_upcall_args *args) +{ + nfs41_open_state *state = args->state; + PFILE_LINK_INFORMATION link = (PFILE_LINK_INFORMATION)args->buf; + nfs41_abs_path dst_path; + nfs41_path_fh dst_dir; + nfs41_component dst_name; + int status; + + ZeroMemory(&dst_path, sizeof(dst_path)); + + dst_path.len = (unsigned short)WideCharToMultiByte(CP_UTF8, 0, + link->FileName, link->FileNameLength/sizeof(WCHAR), + dst_path.path, NFS41_MAX_PATH_LEN, NULL, NULL); + if (dst_path.len == 0) { + eprintf("WideCharToMultiByte failed to convert destination " + "filename %S.\n", link->FileName); + status = ERROR_INVALID_PARAMETER; + goto out; + } + path_fh_init(&dst_dir, &dst_path); + + /* the destination path is absolute, so start from the root session */ + status = nfs41_lookup(args->root, nfs41_root_session(args->root), + &dst_path, &dst_dir, NULL, NULL, NULL); + + /* get the components after lookup in case a referral changed its path */ + last_component(dst_path.path, dst_path.path + dst_path.len, &dst_name); + last_component(dst_path.path, dst_name.name, &dst_dir.name); + + if (status == NO_ERROR) { + if (!link->ReplaceIfExists) { + status = ERROR_FILE_EXISTS; + goto out; + } + } else if (status != ERROR_FILE_NOT_FOUND) { + dprintf(1, "nfs41_lookup('%s') failed to find destination " + "directory with %d\n", dst_path.path, status); + goto out; + } + + /* http://tools.ietf.org/html/rfc5661#section-18.9.3 + * "The existing file and the target directory must reside within + * the same file system on the server." */ + if (state->file.fh.superblock != dst_dir.fh.superblock) { + status = ERROR_NOT_SAME_DEVICE; + goto out; + } + + if (status == NO_ERROR) { + /* LINK will return NFS4ERR_EXIST if the target file exists, + * so we have to remove it ourselves */ + status = nfs41_remove(state->session, &dst_dir, &dst_name); + if (status) { + dprintf(1, "nfs41_remove() failed with error %s.\n", + nfs_error_string(status)); + status = ERROR_FILE_EXISTS; + goto out; + } + } + + status = nfs41_link(state->session, &state->file, &dst_dir, &dst_name); + if (status) { + dprintf(1, "nfs41_link() failed with error %s.\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_INVALID_PARAMETER); + } +out: + return status; +} + +int handle_setattr(nfs41_upcall *upcall) +{ + setattr_upcall_args *args = &upcall->args.setattr; + nfs41_open_state *state = args->state; + int status; + + switch (args->set_class) { + case FileAllocationInformation: + case FileEndOfFileInformation: + if (!state->do_close) { + // get a stateid + uint32_t allow = 0, deny = 0; + StringCchPrintfA((LPSTR)state->owner.owner, NFS4_OPAQUE_LIMIT, + "%u", args->open_owner_id); + state->owner.owner_len = (uint32_t)strlen( + (const char*)state->owner.owner); + map_access_2_allowdeny(args->access_mask, args->access_mode, &allow, &deny); + status = nfs41_open(state->session, allow, deny, + OPEN4_NOCREATE, 0, state, NULL); + if (status) { + dprintf(1, "nfs41_open() failed with %s\n", nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND); + goto out; + } + state->do_close = 1; + } + } + + switch (args->set_class) { + case FileBasicInformation: + status = handle_nfs41_setattr(args); + break; + case FileDispositionInformation: + status = handle_nfs41_remove(args); + break; + case FileRenameInformation: + status = handle_nfs41_rename(args); + break; + case FileAllocationInformation: + case FileEndOfFileInformation: + status = handle_nfs41_set_size(args); + break; + case FileLinkInformation: + status = handle_nfs41_link(args); + break; + default: + eprintf("unknown set_file information class %d\n", + args->set_class); + status = ERROR_NOT_SUPPORTED; + break; + } + +out: + free(args->buf); + return status; +} + +int marshall_setattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + return NO_ERROR; +} + +int parse_setexattr(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + setexattr_upcall_args *args = &upcall->args.setexattr; + + status = safe_read(&buffer, &length, &args->root, sizeof(args->root)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->state, sizeof(args->state)); + if (status) goto out; + status = safe_read(&buffer, &length, &args->mode, sizeof(args->mode)); +out: + if (status) + eprintf("parsing NFS41_EA_SET failed with %d\n", status); + else + dprintf(1, "parsing NFS41_EA_SET: root=%p open_state=%p mode=%o\n", + args->root, args->state, args->mode); + return status; +} + +int handle_setexattr(nfs41_upcall *upcall) +{ + int status; + setexattr_upcall_args *args = &upcall->args.setexattr; + nfs41_open_state *state = args->state; + stateid4 stateid, *pstateid; + nfs41_file_info info; + + pstateid = nfs41_lock_stateid_copy(&state->last_lock, &stateid); + if (pstateid == NULL) + pstateid = &state->stateid; + + ZeroMemory(&info, sizeof(info)); + + /* mode */ + info.mode = args->mode; + info.attrmask.arr[1] |= FATTR4_WORD1_MODE; + info.attrmask.count = 2; + + status = nfs41_setattr(state->session, &state->file, pstateid, &info); + if (status) + dprintf(1, "nfs41_setattr() failed with error %s.\n", + nfs_error_string(status)); + + return nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); +} + +int marshall_setexattr(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + return NO_ERROR; +} diff --git a/daemon/sources b/daemon/sources new file mode 100644 index 0000000..52bbdd4 --- /dev/null +++ b/daemon/sources @@ -0,0 +1,24 @@ +TARGETTYPE=PROGRAM +TARGETNAME=nfsd +SOURCES=nfs41_daemon.c daemon_debug.c nfs41_ops.c nfs41_compound.c nfs41_xdr.c \ + nfs41_server.c nfs41_client.c nfs41_superblock.c nfs41_session.c lookup.c \ + mount.c open.c readwrite.c lock.c readdir.c getattr.c setattr.c upcall.c \ + nfs41_rpc.c util.c pnfs_layout.c pnfs_device.c pnfs_debug.c pnfs_io.c \ + name_cache.c namespace.c rbtree.c volume.c callback_server.c callback_xdr.c +UMTYPE=console +USE_LIBCMT=1 +#USE_MSVCRT=1 +INCLUDES=..\sys;..\dll;..\libtirpc\tirpc +TARGETLIBS=$(SDK_LIB_PATH)\ws2_32.lib $(SDK_LIB_PATH)\iphlpapi.lib \ + ..\libtirpc\src\obj$(BUILD_ALT_DIR)\*\libtirpc.lib + +!IF 0 +/W3 is default level +bump to /Wall, but suppress warnings generated by system includes, +as well as the following warnings: +4100 - unused function call arguments (we have lots of stubs) +4127 - constant conditional (I like to use if(0) or if(1)) +4220 - varargs matching remaining parameters +4204 - nonstandard extension +!ENDIF +MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4711 /wd4220 /wd4204 diff --git a/daemon/upcall.c b/daemon/upcall.c new file mode 100644 index 0000000..f05413d --- /dev/null +++ b/daemon/upcall.c @@ -0,0 +1,222 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "upcall.h" +#include "daemon_debug.h" +#include "util.h" + + +int parse_mount(unsigned char*, uint32_t, nfs41_upcall*); +int handle_mount(nfs41_upcall*); +int marshall_mount(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_unmount(unsigned char*, uint32_t, nfs41_upcall*); +int handle_unmount(nfs41_upcall*); +int marshall_unmount(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_open(unsigned char*, uint32_t, nfs41_upcall*); +int handle_open(nfs41_upcall*); +int marshall_open(unsigned char*, uint32_t*, nfs41_upcall*); +int cancel_open(nfs41_upcall*); + +int parse_close(unsigned char*, uint32_t, nfs41_upcall*); +int handle_close(nfs41_upcall*); +int marshall_close(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_rw(unsigned char*, uint32_t, nfs41_upcall*); +int handle_read(nfs41_upcall*); +int handle_write(nfs41_upcall*); +int marshall_rw(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_lock(unsigned char*, uint32_t, nfs41_upcall*); +int handle_lock(nfs41_upcall*); +int marshall_lock(unsigned char*, uint32_t*, nfs41_upcall*); +int cancel_lock(nfs41_upcall*); + +int parse_unlock(unsigned char*, uint32_t, nfs41_upcall*); +int handle_unlock(nfs41_upcall*); +int marshall_unlock(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_readdir(unsigned char*, uint32_t, nfs41_upcall*); +int handle_readdir(nfs41_upcall*); +int marshall_readdir(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_getattr(unsigned char*, uint32_t, nfs41_upcall*); +int handle_getattr(nfs41_upcall*); +int marshall_getattr(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_setattr(unsigned char*, uint32_t, nfs41_upcall*); +int handle_setattr(nfs41_upcall*); +int marshall_setattr(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_setexattr(unsigned char*, uint32_t, nfs41_upcall*); +int handle_setexattr(nfs41_upcall*); +int marshall_setexattr(unsigned char*, uint32_t*, nfs41_upcall*); + +int parse_volume(unsigned char*, uint32_t, nfs41_upcall*); +int handle_volume(nfs41_upcall*); +int marshall_volume(unsigned char*, uint32_t*, nfs41_upcall*); + +static const nfs41_upcall_op g_upcall_op_table[] = { + { parse_mount, handle_mount, marshall_mount, NULL }, + { parse_unmount, handle_unmount, marshall_unmount, NULL }, + { parse_open, handle_open, marshall_open, cancel_open }, + { parse_close, handle_close, marshall_close, NULL }, + { parse_rw, handle_read, marshall_rw, NULL }, + { parse_rw, handle_write, marshall_rw, NULL }, + { parse_lock, handle_lock, marshall_lock, cancel_lock }, + { parse_unlock, handle_unlock, marshall_unlock, NULL }, + { parse_readdir, handle_readdir, marshall_readdir, NULL }, + { parse_getattr, handle_getattr, marshall_getattr, NULL }, + { parse_setattr, handle_setattr, marshall_setattr, NULL }, + { parse_setexattr, handle_setexattr, marshall_setexattr, NULL }, + { parse_volume, handle_volume, marshall_volume, NULL }, + { NULL, NULL, NULL, NULL }, /* NFS41_SHUTDOWN */ + { NULL, NULL, NULL, NULL }, /* INVALID_OPCODE */ +}; +static const uint32_t g_upcall_op_table_size = ARRAYSIZE(g_upcall_op_table); + + +int upcall_parse( + IN unsigned char *buffer, + IN uint32_t length, + OUT nfs41_upcall *upcall) +{ + int status; + const nfs41_upcall_op *op; + + ZeroMemory(upcall, sizeof(nfs41_upcall)); + if (!length) { + eprintf("empty upcall\n"); + upcall->status = status = 102; + goto out; + } + + dprintf(2, "received %d bytes upcall data: processing upcall\n", length); + print_hexbuf(3, (unsigned char *)"upcall buffer: ", buffer, length); + + /* parse common elements */ + status = safe_read(&buffer, &length, &upcall->xid, sizeof(uint32_t)); + if (status) goto out; + status = safe_read(&buffer, &length, &upcall->opcode, sizeof(uint32_t)); + if (status) goto out; + + dprintf(2, "xid=%d opcode=%s\n", upcall->xid, opcode2string(upcall->opcode)); + + if (upcall->opcode >= g_upcall_op_table_size) { + status = ERROR_NOT_SUPPORTED; + eprintf("unrecognized upcall opcode %d!\n", upcall->opcode); + goto out; + } + + /* parse the operation's arguments */ + op = &g_upcall_op_table[upcall->opcode]; + if (op->parse) { + status = op->parse(buffer, length, upcall); + if (status) { + eprintf("parsing of upcall '%s' failed with %d.\n", + opcode2string(upcall->opcode), status); + goto out; + } + } +out: + return status; +} + +int upcall_handle( + IN nfs41_upcall *upcall) +{ + int status = NO_ERROR; + const nfs41_upcall_op *op; + + op = &g_upcall_op_table[upcall->opcode]; + if (op->handle == NULL) { + status = ERROR_NOT_SUPPORTED; + eprintf("upcall '%s' missing handle function!\n", + opcode2string(upcall->opcode)); + goto out; + } + + upcall->status = op->handle(upcall); +out: + return status; +} + +int upcall_marshall( + IN nfs41_upcall *upcall, + OUT unsigned char *buffer, + IN uint32_t length, + OUT uint32_t *length_out) +{ + int status = NO_ERROR; + const nfs41_upcall_op *op; + unsigned char *orig_buf = buffer; + const uint32_t total = length, orig_len = length; + + /* marshall common elements */ +write_downcall: + length = orig_len; + buffer = orig_buf; + safe_write(&buffer, &length, &upcall->xid, sizeof(upcall->xid)); + safe_write(&buffer, &length, &upcall->opcode, sizeof(upcall->opcode)); + safe_write(&buffer, &length, &upcall->status, sizeof(upcall->status)); + safe_write(&buffer, &length, &upcall->last_error, sizeof(upcall->last_error)); + + if (upcall->status) + goto out; + + /* marshall the operation's results */ + op = &g_upcall_op_table[upcall->opcode]; + if (op->marshall == NULL) { + status = ERROR_NOT_SUPPORTED; + eprintf("upcall '%s' missing marshall function!\n", + opcode2string(upcall->opcode)); + upcall->status = status; + goto write_downcall; + } + + status = op->marshall(buffer, &length, upcall); + if (status) { + upcall->status = status; + goto write_downcall; + } +out: + *length_out = total - length; + return status; +} + +int upcall_cancel( + IN nfs41_upcall *upcall) +{ + int status = NO_ERROR; + const nfs41_upcall_op *op; + + op = &g_upcall_op_table[upcall->opcode]; + if (op->cancel) + status = op->cancel(upcall); + + return status; +} diff --git a/daemon/upcall.h b/daemon/upcall.h new file mode 100644 index 0000000..9058234 --- /dev/null +++ b/daemon/upcall.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_DAEMON_UPCALL_H__ +#define __NFS41_DAEMON_UPCALL_H__ + +#include "nfs41_ops.h" + + +/* structures for upcall arguments */ +typedef struct __mount_upcall_args { + char srv_name[UPCALL_BUF_SIZE]; + nfs41_abs_path path; + nfs41_root *root; +} mount_upcall_args; + +typedef struct __unmount_upcall_args { + nfs41_root *root; +} unmount_upcall_args; + +typedef struct __open_upcall_args { + nfs41_abs_path path; + FILE_BASIC_INFO basic_info; + FILE_STANDARD_INFO std_info; + nfs41_root *root; + nfs41_open_state *state; + ULONG access_mask; + ULONG access_mode; + ULONG file_attrs; + ULONG disposition; + ULONG create_opts; + ULONG open_owner_id; + DWORD mode; + LONGLONG changeattr; + BOOLEAN created; +} open_upcall_args; + +typedef struct __close_upcall_args { + nfs41_abs_path path; + nfs41_root *root; + nfs41_open_state *state; + BOOLEAN remove; + BOOLEAN renamed; +} close_upcall_args; + +typedef struct __readwrite_upcall_args { + nfs41_root *root; + nfs41_open_state *state; + unsigned char *buffer; + LONGLONG offset; + ULONG len; + ULONG out_len; +} readwrite_upcall_args; + +typedef struct __lock_upcall_args { + nfs41_open_state *state; + nfs41_root *root; + LONGLONG offset; + LONGLONG length; + BOOLEAN exclusive; + BOOLEAN blocking; +} lock_upcall_args; + +typedef struct __unlock_upcall_args { + nfs41_open_state *state; + nfs41_root *root; + uint32_t count; + unsigned char *buf; + uint32_t buf_len; +} unlock_upcall_args; + +typedef struct __getattr_upcall_args { + FILE_BASIC_INFO basic_info; + FILE_STANDARD_INFO std_info; + FILE_ATTRIBUTE_TAG_INFO tag_info; + nfs41_root *root; + nfs41_open_state *state; + int query_class; + int buf_len; + int query_reply_len; +} getattr_upcall_args; + +typedef struct __setattr_upcall_args { + nfs41_abs_path path; + nfs41_root *root; + nfs41_open_state *state; + unsigned char *buf; + uint32_t buf_len; + int set_class; + ULONG open_owner_id; + ULONG access_mask; + ULONG access_mode; +} setattr_upcall_args; + +typedef struct __setexattr_upcall_args { + nfs41_root *root; + nfs41_open_state *state; + uint32_t mode; +} setexattr_upcall_args; + +typedef struct __readdir_upcall_args { + char filter[UPCALL_BUF_SIZE]; + FILE_BASIC_INFO basic_info; + FILE_STANDARD_INFO std_info; + FILE_ATTRIBUTE_TAG_INFO tag_info; + nfs41_readdir_cookie *cookie; + nfs41_root *root; + nfs41_open_state *state; + unsigned char *buf; + int buf_len; + int query_class; + int query_reply_len; + BOOLEAN initial; + BOOLEAN restart; + BOOLEAN single; +} readdir_upcall_args; + +typedef struct __volume_upcall_args { + nfs41_root *root; + ULONGLONG total; + ULONGLONG user; + ULONGLONG avail; +} volume_upcall_args; + +typedef union __upcall_args { + mount_upcall_args mount; + unmount_upcall_args unmount; + open_upcall_args open; + close_upcall_args close; + readwrite_upcall_args rw; + lock_upcall_args lock; + unlock_upcall_args unlock; + getattr_upcall_args getattr; + setattr_upcall_args setattr; + setexattr_upcall_args setexattr; + readdir_upcall_args readdir; + volume_upcall_args volume; +} upcall_args; + +typedef struct __nfs41_upcall { + uint32_t xid; + uint32_t opcode; + uint32_t status; + uint32_t last_error; + upcall_args args; +} nfs41_upcall; + + +/* upcall operation interface */ +typedef int (*upcall_parse_proc)(unsigned char*, uint32_t, nfs41_upcall*); +typedef int (*upcall_handle_proc)(nfs41_upcall*); +typedef int (*upcall_marshall_proc)(unsigned char*, uint32_t*, nfs41_upcall*); +typedef int (*upcall_cancel_proc)(nfs41_upcall*); + +typedef struct __nfs41_upcall_op { + upcall_parse_proc parse; + upcall_handle_proc handle; + upcall_marshall_proc marshall; + upcall_cancel_proc cancel; +} nfs41_upcall_op; + + +/* upcall.c */ +int upcall_parse( + IN unsigned char *buffer, + IN uint32_t length, + OUT nfs41_upcall *upcall); + +int upcall_handle( + IN nfs41_upcall *upcall); + +int upcall_marshall( + IN nfs41_upcall *upcall, + OUT unsigned char *buffer, + IN uint32_t length, + OUT uint32_t *length_out); + +int upcall_cancel( + IN nfs41_upcall *upcall); + +#endif /* !__NFS41_DAEMON_UPCALL_H__ */ diff --git a/daemon/util.c b/daemon/util.c new file mode 100644 index 0000000..b5af0fd --- /dev/null +++ b/daemon/util.c @@ -0,0 +1,450 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include + +#include "daemon_debug.h" +#include "util.h" +#include "nfs41_ops.h" + + +int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len) +{ + if (*remaining < dest_len) + return ERROR_BUFFER_OVERFLOW; + + CopyMemory(dest, *pos, dest_len); + *pos += dest_len; + *remaining -= dest_len; + return 0; +} + +int safe_write(unsigned char **pos, uint32_t *remaining, void *src, uint32_t src_len) +{ + if (*remaining < src_len) + return ERROR_BUFFER_OVERFLOW; + + CopyMemory(*pos, src, src_len); + *pos += src_len; + *remaining -= src_len; + return 0; +} + +int wchar2asci(WCHAR *src, char **dest, int dest_len) +{ + int len = 0; + len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL); + if (*dest == NULL) { + *dest = malloc(len + 1); + if (*dest == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + } else if (len > dest_len) + return ERROR_BUFFER_OVERFLOW; + WideCharToMultiByte(CP_UTF8, 0, src, len, *dest, len + 1, NULL, NULL); + + return 0; +} + +int get_name(unsigned char **pos, uint32_t *remaining, char *out_name) +{ + WCHAR name[UPCALL_BUF_SIZE]; + int status, len = 0; + + status = safe_read(pos, remaining, &len, sizeof(USHORT)); + if (status) goto out; + status = safe_read(pos, remaining, name, len); + if (status) goto out; + + name[len/sizeof(WCHAR)] = L'\0'; + status = wchar2asci(name, &out_name, UPCALL_BUF_SIZE); +out: + return status; +} + +int get_abs_path(unsigned char **pos, uint32_t *remaining, nfs41_abs_path *path) +{ + int status = get_name(pos, remaining, path->path); + path->len = status ? 0 : (unsigned short)strlen(path->path); + return status; +} + +const char* strip_path( + IN const char *path, + OUT uint32_t *len_out) +{ + const char *name = strrchr(path, '\\'); + name = name ? name + 1 : path; + if (len_out) + *len_out = (uint32_t)strlen(name); + return name; +} + +uint32_t max_read_size( + IN const nfs41_session *session, + IN const nfs41_fh *fh) +{ + const uint32_t maxresponse = session->fore_chan_attrs.ca_maxresponsesize; + return (uint32_t)min(fh->superblock->maxread, maxresponse - READ_OVERHEAD); +} + +uint32_t max_write_size( + IN const nfs41_session *session, + IN const nfs41_fh *fh) +{ + const uint32_t maxrequest = session->fore_chan_attrs.ca_maxrequestsize; + return (uint32_t)min(fh->superblock->maxwrite, maxrequest - WRITE_OVERHEAD); +} + +bool_t verify_write( + IN nfs41_write_verf *verf, + IN OUT enum stable_how4 *stable) +{ + if (verf->committed != UNSTABLE4) { + *stable = verf->committed; + dprintf(3, "verify_write: committed to stable storage\n"); + return 1; + } + + if (*stable != UNSTABLE4) { + memcpy(verf->expected, verf->verf, NFS4_VERIFIER_SIZE); + *stable = UNSTABLE4; + dprintf(3, "verify_write: first unstable write, saving verifier\n"); + return 1; + } + + if (memcmp(verf->expected, verf->verf, NFS4_VERIFIER_SIZE) == 0) { + dprintf(3, "verify_write: verifier matches expected\n"); + return 1; + } + + dprintf(2, "verify_write: verifier changed; writes have been lost!\n"); + return 0; +} + +ULONG nfs_file_info_to_attributes( + IN const nfs41_file_info *info) +{ + ULONG attrs = 0; + if (info->type == NF4DIR) + attrs |= FILE_ATTRIBUTE_DIRECTORY; + else if (info->type != NF4REG) + dprintf(1, "unhandled file type %d, defaulting to NF4REG\n", + info->type); + + if (info->mode == 0444) /* XXX: 0444 for READONLY */ + attrs |= FILE_ATTRIBUTE_READONLY; + + /* TODO: FILE_ATTRIBUTE_HIDDEN */ + + // FILE_ATTRIBUTE_NORMAL attribute is only set if no other attributes are present. + // all other override this value. + return attrs ? attrs : FILE_ATTRIBUTE_NORMAL; +} + +void nfs_to_basic_info( + IN const nfs41_file_info *info, + OUT PFILE_BASIC_INFO basic_out) +{ + nfs_time_to_file_time(&info->time_create, &basic_out->CreationTime); + nfs_time_to_file_time(&info->time_access, &basic_out->LastAccessTime); + nfs_time_to_file_time(&info->time_modify, &basic_out->LastWriteTime); + /* XXX: was using 'change' attr, but that wasn't giving a time */ + nfs_time_to_file_time(&info->time_modify, &basic_out->ChangeTime); + basic_out->FileAttributes = nfs_file_info_to_attributes(info); +} + +void nfs_to_standard_info( + IN const nfs41_file_info *info, + OUT PFILE_STANDARD_INFO std_out) +{ + std_out->AllocationSize.QuadPart = + std_out->EndOfFile.QuadPart = (LONGLONG)info->size; + std_out->NumberOfLinks = info->numlinks; + std_out->DeletePending = FALSE; + std_out->Directory = info->type == NF4DIR ? TRUE : FALSE; +} + + +/* http://msdn.microsoft.com/en-us/library/ms724290%28VS.85%29.aspx: + * A file time is a 64-bit value that represents the number of + * 100-nanosecond intervals that have elapsed since 12:00 A.M. + * January 1, 1601 Coordinated Universal Time (UTC). */ +static __inline void get_file_epoch( + OUT PLARGE_INTEGER time_out) +{ + static const SYSTEMTIME jan_1_1970 = {1970, 1, 4, 1, 0, 0, 0, 0}; + SystemTimeToFileTime(&jan_1_1970, (LPFILETIME)time_out); +} + +void file_time_to_nfs_time( + IN const PLARGE_INTEGER file_time, + OUT nfstime4 *nfs_time) +{ + LARGE_INTEGER diff; + get_file_epoch(&diff); + diff.QuadPart = file_time->QuadPart - diff.QuadPart; + nfs_time->seconds = diff.QuadPart / 10000000; + nfs_time->nseconds = (uint32_t)((diff.QuadPart % 10000000)*100); +} + +void nfs_time_to_file_time( + IN const nfstime4 *nfs_time, + OUT PLARGE_INTEGER file_time) +{ + LARGE_INTEGER diff; + get_file_epoch(&diff); + file_time->QuadPart = diff.QuadPart + + nfs_time->seconds * 10000000 + + nfs_time->nseconds / 100; +} + +void get_file_time( + OUT PLARGE_INTEGER file_time) +{ + GetSystemTimeAsFileTime((LPFILETIME)file_time); +} + +void get_nfs_time( + OUT nfstime4 *nfs_time) +{ + LARGE_INTEGER file_time; + get_file_time(&file_time); + file_time_to_nfs_time(&file_time, nfs_time); +} + +void map_access_2_allowdeny(ULONG access_mask, ULONG access_mode, + uint32_t *allow, uint32_t *deny) +{ + if ((access_mask & FILE_WRITE_DATA) && + ((access_mask & FILE_READ_DATA) || + (access_mask & FILE_EXECUTE))) + *allow = OPEN4_SHARE_ACCESS_BOTH; + else if ((access_mask & FILE_READ_DATA) || + (access_mask & FILE_EXECUTE)) + *allow = OPEN4_SHARE_ACCESS_READ; + else if (access_mask & FILE_WRITE_DATA || + (access_mask & FILE_APPEND_DATA) || + (access_mask & FILE_WRITE_ATTRIBUTES)) + *allow = OPEN4_SHARE_ACCESS_WRITE; +#define FIX_ALLOW_DENY_WIN2NFS_CONVERSION +#ifdef FIX_ALLOW_DENY_WIN2NFS_CONVERSION + if ((access_mode & FILE_SHARE_READ) && + (access_mode & FILE_SHARE_WRITE)) + *deny = OPEN4_SHARE_DENY_NONE; + else if (access_mode & FILE_SHARE_READ) + *deny = OPEN4_SHARE_DENY_WRITE; + else if (access_mode & FILE_SHARE_WRITE) + *deny = OPEN4_SHARE_DENY_READ; + else + *deny = OPEN4_SHARE_DENY_BOTH; +#else + // AGLO: 11/13/2009. + // readonly file that is being opened for reading with a + // share read mode given above logic translates into deny + // write and linux server does not allow it. + *deny = OPEN4_SHARE_DENY_NONE; +#endif + +} + +bool_t multi_addr_find( + IN const multi_addr4 *addrs, + IN const netaddr4 *addr, + OUT OPTIONAL uint32_t *index_out) +{ + uint32_t i; + for (i = 0; i < addrs->count; i++) { + const netaddr4 *saddr = &addrs->arr[i]; + if (!strncmp(saddr->netid, addr->netid, NFS41_NETWORK_ID_LEN) && + !strncmp(saddr->uaddr, addr->uaddr, NFS41_UNIVERSAL_ADDR_LEN)) { + if (index_out) *index_out = i; + return 1; + } + } + return 0; +} + +int nfs_to_windows_error(int status, int default_error) +{ + /* make sure this is actually an nfs error */ + if (status < 0 || (status > 70 && status < 10001) || status > 10087) { + eprintf("nfs_to_windows_error called with non-nfs " + "error code %d; returning the error as is\n", status); + return status; + } + + switch (status) { + case NFS4_OK: return NO_ERROR; + case NFS4ERR_PERM: return ERROR_ACCESS_DENIED; + case NFS4ERR_NOENT: return ERROR_FILE_NOT_FOUND; + case NFS4ERR_IO: return ERROR_NET_WRITE_FAULT; + case NFS4ERR_ACCESS: return ERROR_ACCESS_DENIED; + case NFS4ERR_EXIST: return ERROR_FILE_EXISTS; + case NFS4ERR_XDEV: return ERROR_NOT_SAME_DEVICE; + case NFS4ERR_INVAL: return ERROR_INVALID_PARAMETER; + case NFS4ERR_FBIG: return ERROR_FILE_TOO_LARGE; + case NFS4ERR_NOSPC: return ERROR_DISK_FULL; + case NFS4ERR_ROFS: return ERROR_NETWORK_ACCESS_DENIED; + case NFS4ERR_MLINK: return ERROR_TOO_MANY_LINKS; + case NFS4ERR_NAMETOOLONG: return ERROR_FILENAME_EXCED_RANGE; + case NFS4ERR_STALE: return ERROR_NETNAME_DELETED; + case NFS4ERR_NOTEMPTY: return ERROR_NOT_EMPTY; + case NFS4ERR_DENIED: return ERROR_LOCK_FAILED; + case NFS4ERR_TOOSMALL: return ERROR_BUFFER_OVERFLOW; + case NFS4ERR_LOCKED: return ERROR_LOCK_VIOLATION; + case NFS4ERR_SHARE_DENIED: return ERROR_SHARING_VIOLATION; + case NFS4ERR_LOCK_RANGE: return ERROR_NOT_LOCKED; + case NFS4ERR_ATTRNOTSUPP: return ERROR_NOT_SUPPORTED; + case NFS4ERR_OPENMODE: return ERROR_ACCESS_DENIED; + case NFS4ERR_LOCK_NOTSUPP: return ERROR_ATOMIC_LOCKS_NOT_SUPPORTED; + + case NFS4ERR_BADCHAR: + case NFS4ERR_BADNAME: return ERROR_INVALID_NAME; + + case NFS4ERR_NOTDIR: + case NFS4ERR_ISDIR: + case NFS4ERR_SYMLINK: + case NFS4ERR_WRONG_TYPE: return ERROR_INVALID_PARAMETER; + + case NFS4ERR_OLD_STATEID: + case NFS4ERR_BAD_STATEID: + case NFS4ERR_ADMIN_REVOKED: return ERROR_FILE_INVALID; + + default: + dprintf(1, "nfs error %s not mapped to windows error; " + "returning default error %d\n", + nfs_error_string(status), default_error); + return default_error; + } +} + +bool_t next_component( + IN const char *path, + IN const char *path_end, + OUT nfs41_component *component) +{ + const char *component_end; + component->name = next_non_delimiter(path, path_end); + component_end = next_delimiter(component->name, path_end); + component->len = (unsigned short)(component_end - component->name); + return component->len > 0; +} + +bool_t last_component( + IN const char *path, + IN const char *path_end, + OUT nfs41_component *component) +{ + const char *component_end = prev_delimiter(path_end, path); + component->name = prev_non_delimiter(component_end, path); + component->name = prev_delimiter(component->name, path); + component->name = next_non_delimiter(component->name, component_end); + component->len = (unsigned short)(component_end - component->name); + return component->len > 0; +} + +bool_t is_last_component( + IN const char *path, + IN const char *path_end) +{ + path = next_delimiter(path, path_end); + return next_non_delimiter(path, path_end) == path_end; +} + +void abs_path_copy( + OUT nfs41_abs_path *dst, + IN const nfs41_abs_path *src) +{ + dst->len = src->len; + StringCchCopyNA(dst->path, NFS41_MAX_PATH_LEN, src->path, dst->len); +} + +void path_fh_init( + OUT nfs41_path_fh *file, + IN nfs41_abs_path *path) +{ + file->path = path; + last_component(path->path, path->path + path->len, &file->name); +} + +void fh_copy( + OUT nfs41_fh *dst, + IN const nfs41_fh *src) +{ + dst->fileid = src->fileid; + dst->superblock = src->superblock; + dst->len = src->len; + memcpy(dst->fh, src->fh, dst->len); +} + +void path_fh_copy( + OUT nfs41_path_fh *dst, + IN const nfs41_path_fh *src) +{ + dst->path = src->path; + if (dst->path) { + const size_t name_start = src->name.name - src->path->path; + dst->name.name = dst->path->path + name_start; + dst->name.len = src->name.len; + } else { + dst->name.name = NULL; + dst->name.len = 0; + } + fh_copy(&dst->fh, &src->fh); +} + +int create_silly_rename( + IN nfs41_abs_path *path, + IN const nfs41_fh *fh, + OUT nfs41_component *silly) +{ + const char *end = path->path + NFS41_MAX_PATH_LEN; + const unsigned short extra_len = 2 + 2*(unsigned short)fh->len; + char name[NFS41_MAX_COMPONENT_LEN+1]; + char *tmp; + uint32_t i; + int status = NO_ERROR; + + if (path->len + extra_len >= NFS41_MAX_PATH_LEN) { + status = ERROR_BUFFER_OVERFLOW; + goto out; + } + + last_component(path->path, path->path + path->len, silly); + StringCchCopyNA(name, NFS41_MAX_COMPONENT_LEN+1, silly->name, silly->len); + + tmp = (char*)silly->name; + StringCchPrintf(tmp, end - tmp, ".%s.", name); + tmp += silly->len + 2; + + for (i = 0; i < fh->len; i++, tmp += 2) + StringCchPrintf(tmp, end - tmp, "%02x", fh->fh[i]); + + path->len += extra_len; + silly->len += extra_len; +out: + return status; +} diff --git a/daemon/util.h b/daemon/util.h new file mode 100644 index 0000000..2a77d97 --- /dev/null +++ b/daemon/util.h @@ -0,0 +1,166 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_DAEMON_UTIL_H__ +#define __NFS41_DAEMON_UTIL_H__ + +#include "nfs41_types.h" + + +struct __nfs41_session; +struct __nfs41_write_verf; +enum stable_how4; + +int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len); +int safe_write(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len); +int get_name(unsigned char **pos, uint32_t *remaining, char *out_name); +int get_abs_path(unsigned char **pos, uint32_t *remaining, nfs41_abs_path *path); +int wchar2asci(WCHAR *src, char **dest, int dest_len); + +const char* strip_path( + IN const char *path, + OUT uint32_t *len_out OPTIONAL); + +uint32_t max_read_size( + IN const struct __nfs41_session *session, + IN const nfs41_fh *fh); +uint32_t max_write_size( + IN const struct __nfs41_session *session, + IN const nfs41_fh *fh); + +bool_t verify_write( + IN struct __nfs41_write_verf *verf, + IN OUT enum stable_how4 *stable); + +ULONG nfs_file_info_to_attributes( + IN const nfs41_file_info *info); +void nfs_to_basic_info( + IN const nfs41_file_info *info, + OUT PFILE_BASIC_INFO basic_out); +void nfs_to_standard_info( + IN const nfs41_file_info *info, + OUT PFILE_STANDARD_INFO std_out); + +void file_time_to_nfs_time( + IN const PLARGE_INTEGER file_time, + OUT nfstime4 *nfs_time); +void nfs_time_to_file_time( + IN const nfstime4 *nfs_time, + OUT PLARGE_INTEGER file_time); +void get_file_time( + OUT PLARGE_INTEGER file_time); +void get_nfs_time( + OUT nfstime4 *nfs_time); + +int create_silly_rename( + IN nfs41_abs_path *path, + IN const nfs41_fh *fh, + OUT nfs41_component *silly); + +void map_access_2_allowdeny( + IN ULONG access_mask, + IN ULONG access_mode, + OUT uint32_t *allow, + OUT uint32_t *deny); + +bool_t multi_addr_find( + IN const multi_addr4 *addrs, + IN const netaddr4 *addr, + OUT OPTIONAL uint32_t *index_out); + +/* nfs_to_windows_error + * Returns a windows ERROR_ code corresponding to the given NFS4ERR_ status. + * If the status is outside the range of valid NFS4ERR_ values, it is returned + * unchanged. Otherwise, if the status does not match a value in the mapping, + * a debug warning is generated and the default_error value is returned. + */ +int nfs_to_windows_error(int status, int default_error); + + +__inline uint32_t align8(uint32_t offset) { + return 8 + ((offset - 1) & ~7); +} +__inline uint32_t align4(uint32_t offset) { + return 4 + ((offset - 1) & ~3); +} + +/* path parsing */ +__inline int is_delimiter(char c) { + return c == '\\' || c == '/' || c == '\0'; +} +__inline const char* next_delimiter(const char *pos, const char *end) { + while (pos < end && !is_delimiter(*pos)) + pos++; + return pos; +} +__inline const char* prev_delimiter(const char *pos, const char *start) { + while (pos > start && !is_delimiter(*pos)) + pos--; + return pos; +} +__inline const char* next_non_delimiter(const char *pos, const char *end) { + while (pos < end && is_delimiter(*pos)) + pos++; + return pos; +} +__inline const char* prev_non_delimiter(const char *pos, const char *start) { + while (pos > start && is_delimiter(*pos)) + pos--; + return pos; +} + +bool_t next_component( + IN const char *path, + IN const char *path_end, + OUT nfs41_component *component); + +bool_t last_component( + IN const char *path, + IN const char *path_end, + OUT nfs41_component *component); + +bool_t is_last_component( + IN const char *path, + IN const char *path_end); + +void abs_path_copy( + OUT nfs41_abs_path *dst, + IN const nfs41_abs_path *src); + +void path_fh_init( + OUT nfs41_path_fh *file, + IN nfs41_abs_path *path); + +void fh_copy( + OUT nfs41_fh *dst, + IN const nfs41_fh *src); + +void path_fh_copy( + OUT nfs41_path_fh *dst, + IN const nfs41_path_fh *src); + +__inline int valid_handle(HANDLE handle) { + return handle != INVALID_HANDLE_VALUE && handle != 0; +} + +#endif /* !__NFS41_DAEMON_UTIL_H__ */ diff --git a/daemon/volume.c b/daemon/volume.c new file mode 100644 index 0000000..1e639a3 --- /dev/null +++ b/daemon/volume.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include + +#include "nfs41_ops.h" +#include "from_kernel.h" +#include "upcall.h" +#include "util.h" +#include "daemon_debug.h" + + +int parse_volume(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +{ + int status; + volume_upcall_args *args = &upcall->args.volume; + status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE)); + if (status) + eprintf("parsing NFS41_VOLUME_QUERY failed with %d\n", + status); + else + dprintf(1, "parsing NFS41_VOLUME_QUERY: root=0x%p\n", args->root); + return status; +} + +int handle_volume(nfs41_upcall *upcall) +{ + nfs41_file_info info = { 0 }; + bitmap4 attr_request = { 2, { 0, FATTR4_WORD1_SPACE_AVAIL | + FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL } }; + volume_upcall_args *args = &upcall->args.volume; + int status; + + /* query the space_ attributes of the root filesystem */ + status = nfs41_getattr(nfs41_root_session(args->root), + NULL, &attr_request, &info); + if (status) { + eprintf("nfs41_getattr() failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out; + } + + args->total = info.space_total; /* total disk space in bytes */ + args->user = info.space_avail; /* bytes available to this user */ + args->avail = info.space_free; /* free disk space in bytes */ + dprintf(2, "Volume: %llu user, %llu free of %llu total\n", + args->user, args->avail, args->total); +out: + return status; +} + +int marshall_volume(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +{ + int status; + volume_upcall_args *args = &upcall->args.volume; + + status = safe_write(&buffer, length, &args->total, sizeof(args->total)); + if (status) goto out; + status = safe_write(&buffer, length, &args->user, sizeof(args->user)); + if (status) goto out; + status = safe_write(&buffer, length, &args->avail, sizeof(args->avail)); +out: + return status; +} diff --git a/dirs b/dirs new file mode 100644 index 0000000..80ae0e3 --- /dev/null +++ b/dirs @@ -0,0 +1 @@ +DIRS = dll sys mount daemon libtirpc install diff --git a/dll/dllmain.c b/dll/dllmain.c new file mode 100644 index 0000000..04f429a --- /dev/null +++ b/dll/dllmain.c @@ -0,0 +1,76 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +/*++ + +Copyright (c) 1989-1999 Microsoft Corporation + +Module Name: + + dllmain.c + +Abstract: + + This module implements the initialization routines for network + provider interface + +Notes: + + This module has been built and tested only in UNICODE environment + +--*/ + +#include +#include + + +// NOTE: +// +// Function:` DllMain +// +// Return: TRUE => Success +// FALSE => Failure + +BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved) +{ + BOOL bStatus = TRUE; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + break; + + case DLL_PROCESS_DETACH: + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + default: + break; + } + + return(bStatus); +} diff --git a/dll/makefile b/dll/makefile new file mode 100644 index 0000000..66f1c8e --- /dev/null +++ b/dll/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def + diff --git a/dll/nfs41_np.c b/dll/nfs41_np.c new file mode 100644 index 0000000..78b2ac3 --- /dev/null +++ b/dll/nfs41_np.c @@ -0,0 +1,900 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include + +#include "nfs41_driver.h" +#include "nfs41_np.h" +#include "options.h" + +#ifdef DBG +#define DbgP(_x_) NFS41DbgPrint _x_ +#else +#define DbgP(_x_) +#endif +#define TRACE_TAG L"[NFS41_NP]" +#define WNNC_DRIVER( major, minor ) ( major * 0x00010000 + minor ) + + +ULONG _cdecl NFS41DbgPrint( __in LPTSTR Format, ... ) +{ + ULONG rc = 0; + TCHAR szbuffer[256]; + + va_list marker; + va_start( marker, Format ); + { + + //StringCchVPrintfW( szbuffer, 127, Format, marker ); + StringCchVPrintfW( szbuffer, 256, Format, marker ); + szbuffer[255] = (TCHAR)0; + OutputDebugString( TRACE_TAG ); + OutputDebugString( szbuffer ); + } + + return rc; +} + +int filter(unsigned int code) +{ + DbgP((L"####Got exception %u\n", code)); + return EXCEPTION_CONTINUE_SEARCH; +} + +DWORD +OpenSharedMemory( + PHANDLE phMutex, + PHANDLE phMemory, + PVOID *pMemory) +/*++ + +Routine Description: + + This routine opens the shared memory for exclusive manipulation + +Arguments: + + phMutex - the mutex handle + + phMemory - the memory handle + + pMemory - a ptr. to the shared memory which is set if successful + +Return Value: + + WN_SUCCESS -- if successful + +--*/ +{ + DWORD dwStatus; + + *phMutex = 0; + *phMemory = 0; + *pMemory = NULL; + + *phMutex = OpenMutex(SYNCHRONIZE, + FALSE, + TEXT(NFS41NP_MUTEX_NAME)); + + if (*phMutex == NULL) + { + dwStatus = GetLastError(); + DbgP((TEXT("OpenSharedMemory: OpenMutex failed\n"))); + goto OpenSharedMemoryAbort1; + } + + WaitForSingleObject(*phMutex, INFINITE); + + *phMemory = OpenFileMapping(FILE_MAP_WRITE, + FALSE, + TEXT(NFS41_USER_SHARED_MEMORY_NAME)); + if (*phMemory == NULL) + { + dwStatus = GetLastError(); + DbgP((TEXT("OpenSharedMemory: OpenFileMapping failed\n"))); + goto OpenSharedMemoryAbort2; + } + + *pMemory = MapViewOfFile(*phMemory, FILE_MAP_WRITE, 0, 0, 0); + if (*pMemory == NULL) + { + dwStatus = GetLastError(); + DbgP((TEXT("OpenSharedMemory: MapViewOfFile failed\n"))); + goto OpenSharedMemoryAbort3; + } + + return ERROR_SUCCESS; + +OpenSharedMemoryAbort3: + CloseHandle(*phMemory); + +OpenSharedMemoryAbort2: + ReleaseMutex(*phMutex); + CloseHandle(*phMutex); + *phMutex = NULL; + +OpenSharedMemoryAbort1: + DbgP((TEXT("OpenSharedMemory: return dwStatus: %d\n"), dwStatus)); + + return dwStatus; +} + +VOID +CloseSharedMemory( + PHANDLE hMutex, + PHANDLE hMemory, + PVOID *pMemory) +/*++ + +Routine Description: + + This routine relinquishes control of the shared memory after exclusive + manipulation + +Arguments: + + hMutex - the mutex handle + + hMemory - the memory handle + + pMemory - a ptr. to the shared memory which is set if successful + +Return Value: + +--*/ +{ + if (*pMemory) + { + UnmapViewOfFile(*pMemory); + *pMemory = NULL; + } + if (*hMemory) + { + CloseHandle(*hMemory); + *hMemory = 0; + } + if (*hMutex) + { + if (ReleaseMutex(*hMutex) == FALSE) + { + DbgP((TEXT("CloseSharedMemory: ReleaseMutex error: %d\n"), GetLastError())); + } + CloseHandle(*hMutex); + *hMutex = 0; + } +} + +static DWORD StoreConnectionInfo( + IN LPCWSTR LocalName, + IN LPCWSTR ConnectionName, + IN USHORT ConnectionNameLength, + IN LPNETRESOURCE lpNetResource) +{ + DWORD status; + HANDLE hMutex, hMemory; + PNFS41NP_SHARED_MEMORY pSharedMemory; + PNFS41NP_NETRESOURCE pNfs41NetResource; + INT Index; + BOOLEAN FreeEntryFound = FALSE; + + status = OpenSharedMemory(&hMutex, &hMemory, &(PVOID)pSharedMemory); + if (status) + goto out; + + DbgP((TEXT("StoreConnectionInfo: NextIndex %d, NumResources %d\n"), + pSharedMemory->NextAvailableIndex, + pSharedMemory->NumberOfResourcesInUse)); + + for (Index = 0; Index < pSharedMemory->NextAvailableIndex; Index++) + { + if (!pSharedMemory->NetResources[Index].InUse) + { + FreeEntryFound = TRUE; + DbgP((TEXT("Reusing existing index %d\n"), Index)); + break; + } + } + + if (!FreeEntryFound) + { + if (pSharedMemory->NextAvailableIndex >= NFS41NP_MAX_DEVICES) { + status = WN_NO_MORE_DEVICES; + goto out_close; + } + Index = pSharedMemory->NextAvailableIndex++; + DbgP((TEXT("Using new index %d\n"), Index)); + } + + pSharedMemory->NumberOfResourcesInUse += 1; + + pNfs41NetResource = &pSharedMemory->NetResources[Index]; + + pNfs41NetResource->InUse = TRUE; + pNfs41NetResource->dwScope = lpNetResource->dwScope; + pNfs41NetResource->dwType = lpNetResource->dwType; + pNfs41NetResource->dwDisplayType = lpNetResource->dwDisplayType; + pNfs41NetResource->dwUsage = RESOURCEUSAGE_CONNECTABLE; + pNfs41NetResource->LocalNameLength = (USHORT)(wcslen(LocalName) + 1) * sizeof(WCHAR); + pNfs41NetResource->RemoteNameLength = (USHORT)(wcslen(lpNetResource->lpRemoteName) + 1) * sizeof(WCHAR); + pNfs41NetResource->ConnectionNameLength = ConnectionNameLength; + + StringCchCopy(pNfs41NetResource->LocalName, + pNfs41NetResource->LocalNameLength, + LocalName); + StringCchCopy(pNfs41NetResource->RemoteName, + pNfs41NetResource->RemoteNameLength, + lpNetResource->lpRemoteName); + StringCchCopy(pNfs41NetResource->ConnectionName, + pNfs41NetResource->ConnectionNameLength, + ConnectionName); + + // TODO: copy mount options -cbodley + +out_close: + CloseSharedMemory(&hMutex, &hMemory, &(PVOID)pSharedMemory); +out: + return status; +} + +ULONG +SendTo_NFS41Driver( + IN ULONG IoctlCode, + IN PVOID InputDataBuf, + IN ULONG InputDataLen, + IN PVOID OutputDataBuf, + IN PULONG pOutputDataLen) +{ + HANDLE DeviceHandle; // The mini rdr device handle + BOOL rc = FALSE; + ULONG Status; + + Status = WN_SUCCESS; + DbgP((L"[aglo] calling CreateFile\n")); + DeviceHandle = CreateFile( + NFS41_USER_DEVICE_NAME, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + (LPSECURITY_ATTRIBUTES)NULL, + OPEN_EXISTING, + 0, + (HANDLE) NULL ); + + DbgP((L"[aglo] after CreateFile Device Handle\n")); + if ( INVALID_HANDLE_VALUE != DeviceHandle ) + { + __try { + DbgP((L"[aglo] calling DeviceIoControl\n")); + rc = DeviceIoControl( + DeviceHandle, + IoctlCode, + InputDataBuf, + InputDataLen, + OutputDataBuf, + *pOutputDataLen, + pOutputDataLen, + NULL ); + } __except(filter(GetExceptionCode())) { + DbgP((L"#### In except\n")); + } + DbgP((L"[aglo] returned from DeviceIoControl %08lx\n", rc)); + if ( !rc ) + { + DbgP((L"[aglo] SendTo_NFS41Driver: returning error from DeviceIoctl\n")); + Status = GetLastError( ); + } + else + { + DbgP((L"[aglo] SendTo_NFS41Driver: The DeviceIoctl call succeded\n")); + } + CloseHandle(DeviceHandle); + } + else + { + Status = GetLastError( ); + DbgP((L"[aglo] SendTo_NFS41Driver: error %08lx opening device \n", Status)); + } + DbgP((L"[aglo] returned from SendTo_NFS41Driver %08lx\n", Status)); + return Status; +} + +DWORD APIENTRY +NPGetCaps( + DWORD nIndex ) +{ + DWORD rc = 0; + + DbgP(( L"[aglo] GetNetCaps %d\n", nIndex )); + switch ( nIndex ) + { + case WNNC_SPEC_VERSION: + rc = WNNC_SPEC_VERSION51; + break; + + case WNNC_NET_TYPE: + rc = WNNC_NET_RDR2SAMPLE; + break; + + case WNNC_DRIVER_VERSION: + rc = WNNC_DRIVER(1, 0); + break; + + case WNNC_CONNECTION: + rc = WNNC_CON_GETCONNECTIONS | + WNNC_CON_CANCELCONNECTION | + WNNC_CON_ADDCONNECTION | + WNNC_CON_ADDCONNECTION3; + break; + + case WNNC_ENUMERATION: + rc = WNNC_ENUM_LOCAL; + break; + + case WNNC_START: + rc = 1; + break; + + case WNNC_USER: + case WNNC_DIALOG: + case WNNC_ADMIN: + default: + rc = 0; + break; + } + + return rc; +} + +DWORD APIENTRY +NPLogonNotify( + __in PLUID lpLogonId, + __in PCWSTR lpAuthentInfoType, + __in PVOID lpAuthentInfo, + __in PCWSTR lpPreviousAuthentInfoType, + __in PVOID lpPreviousAuthentInfo, + __in PWSTR lpStationName, + __in PVOID StationHandle, + __out PWSTR *lpLogonScript) +{ + *lpLogonScript = NULL; + DbgP(( L"[aglo] NPLogonNotify: returning WN_SUCCESS\n" )); + return WN_SUCCESS; +} + +DWORD APIENTRY +NPPasswordChangeNotify ( + __in LPCWSTR lpAuthentInfoType, + __in LPVOID lpAuthentInfo, + __in LPCWSTR lpPreviousAuthentInfoType, + __in LPVOID lpPreviousAuthentInfo, + __in LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo ) +{ + DbgP(( L"[aglo] NPPasswordChangeNotify: WN_NOT_SUPPORTED\n" )); + SetLastError( WN_NOT_SUPPORTED ); + return WN_NOT_SUPPORTED; +} + +DWORD APIENTRY +NPAddConnection( + __in LPNETRESOURCE lpNetResource, + __in_opt LPWSTR lpPassword, + __in_opt LPWSTR lpUserName ) +{ + return NPAddConnection3( NULL, lpNetResource, lpPassword, lpUserName, 0 ); +} + +DWORD APIENTRY +NPAddConnection3( + __in HWND hwndOwner, + __in LPNETRESOURCE lpNetResource, + __in_opt LPWSTR lpPassword, + __in_opt LPWSTR lpUserName, + __in DWORD dwFlags) +{ + DWORD Status; + WCHAR wszScratch[128]; + WCHAR LocalName[3]; + DWORD CopyBytes = 0; + CONNECTION_INFO Connection; + LPWSTR ConnectionName; + WCHAR ServerName[MAX_PATH]; + PWCHAR p; + DWORD i; + + DbgP(( L"[aglo] NPAddConnection3('%s', '%s')\n", + lpNetResource->lpLocalName, lpNetResource->lpRemoteName )); + + Status = InitializeConnectionInfo(&Connection, + (PMOUNT_OPTION_BUFFER)lpNetResource->lpComment, + &ConnectionName); + if (Status) { + DbgP(( L"InitializeConnectionInfo failed with %d\n", Status )); + goto out; + } + + // \device\miniredirector\;:\Server\Share + + // local name, must start with "X:" + if (lstrlen(lpNetResource->lpLocalName) < 2 || + lpNetResource->lpLocalName[1] != L':') { + Status = WN_BAD_LOCALNAME; + goto out; + } + + LocalName[0] = (WCHAR) toupper(lpNetResource->lpLocalName[0]); + LocalName[1] = L':'; + LocalName[2] = L'\0'; + StringCchCopyW( ConnectionName, MAX_PATH, NFS41_DEVICE_NAME ); + StringCchCatW( ConnectionName, MAX_PATH, L"\\;" ); + StringCchCatW( ConnectionName, MAX_PATH, LocalName ); + + // remote name, must start with "\\" + if (lpNetResource->lpRemoteName[0] == L'\0' || + lpNetResource->lpRemoteName[0] != L'\\' || + lpNetResource->lpRemoteName[1] != L'\\') { + Status = WN_BAD_NETNAME; + goto out; + } + + /* note: remotename comes as \\server but we need to add \server thus +1 pointer */ + p = lpNetResource->lpRemoteName + 1; + ServerName[0] = L'\\'; + i = 1; + for(;;) { + /* convert servername ending unix slash to windows slash */ + if (p[i] == L'/') + p[i] = L'\\'; + /* deal with servername ending with any slash */ + if (p[i] == L'\0') + p[i] = L'\\'; + ServerName[i] = p[i]; + if (p[i] == L'\\') break; + i++; + } + ServerName[i] = L'\0'; + StringCchCatW( ConnectionName, MAX_PATH, ServerName); + /* insert the "nfs4" in between the server name and the path, + * just to make sure all calls to our driver come thru this */ + StringCchCatW( ConnectionName, MAX_PATH, L"\\nfs4" ); + +#ifdef CONVERT_2_UNIX_SLASHES + /* convert all windows slashes to unix slashes */ + { + PWCHAR q = p; + DWORD j = 0; + for(;;) { + if(q[j] == L'\0') break; + if (q[j] == L'\\') q[j] = L'/'; + j++; + } + } +#else + /* convert all unix slashes to windows slashes */ + { + PWCHAR q = p; + DWORD j = 0; + for(;;) { + if(q[j] == L'\0') break; + if (q[j] == L'/') q[j] = L'\\'; + j++; + } + } +#endif + StringCchCatW( ConnectionName, MAX_PATH, &p[i]); + DbgP(( L"[aglo] Full Connect Name: %s\n", ConnectionName )); + DbgP(( L"[aglo] Full Connect Name Length: %d %d\n", + (wcslen(ConnectionName) + 1) * sizeof(WCHAR), + (lstrlen(ConnectionName) + 1) * sizeof(WCHAR))); + + if ( QueryDosDevice( LocalName, wszScratch, 128 ) + || GetLastError() != ERROR_FILE_NOT_FOUND) { + Status = WN_ALREADY_CONNECTED; + goto out; + } + + MarshalConnectionInfo(&Connection); + + Status = SendTo_NFS41Driver( IOCTL_NFS41_ADDCONN, + Connection.Buffer, Connection.BufferSize, + NULL, &CopyBytes ); + if (Status) { + DbgP(( L"[aglo] SendTo_NFS41Driver failed with %d\n", Status)); + Status = WN_BAD_NETNAME; + goto out; + } + + DbgP(( L"[aglo] calling DefineDosDevice\n")); + if ( !DefineDosDevice( DDD_RAW_TARGET_PATH | + DDD_NO_BROADCAST_SYSTEM, + lpNetResource->lpLocalName, + ConnectionName ) ) { + Status = GetLastError(); + DbgP(( L"[aglo] DefineDosDevice failed with %d\n", Status)); + goto out_delconn; + } + + // The connection was established and the local device mapping + // added. Include this in the list of mapped devices. + Status = StoreConnectionInfo(LocalName, ConnectionName, + Connection.Buffer->NameLength, lpNetResource); + if (Status) { + DbgP(( L"[aglo] StoreConnectionInfo failed with %d\n", Status)); + goto out_undefine; + } + +out: + FreeConnectionInfo(&Connection); + DbgP(( L"[aglo] NPAddConnection3: status %08X\n", Status)); + return Status; +out_undefine: + DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | + DDD_EXACT_MATCH_ON_REMOVE, LocalName, ConnectionName); +out_delconn: + SendTo_NFS41Driver(IOCTL_NFS41_DELCONN, ConnectionName, + Connection.Buffer->NameLength, NULL, &CopyBytes); + goto out; +} + +DWORD APIENTRY +NPCancelConnection( + __in LPWSTR lpName, + __in BOOL fForce ) +{ + DWORD Status = 0; + + HANDLE hMutex, hMemory; + PNFS41NP_SHARED_MEMORY pSharedMemory; + + DbgP((TEXT("NPCancelConnection\n"))); + DbgP((TEXT("NPCancelConnection: ConnectionName: %S\n"), lpName)); + + Status = OpenSharedMemory( &hMutex, + &hMemory, + (PVOID)&pSharedMemory); + + if (Status == WN_SUCCESS) + { + INT Index; + PNFS41NP_NETRESOURCE pNetResource; + Status = WN_NOT_CONNECTED; + + DbgP((TEXT("NPCancelConnection: NextIndex %d, NumResources %d\n"), + pSharedMemory->NextAvailableIndex, + pSharedMemory->NumberOfResourcesInUse)); + + for (Index = 0; Index < pSharedMemory->NextAvailableIndex; Index++) + { + pNetResource = &pSharedMemory->NetResources[Index]; + + if (pNetResource->InUse) + { + if ( ( (wcslen(lpName) + 1) * sizeof(WCHAR) == + pNetResource->LocalNameLength) + && ( !wcscmp(lpName, pNetResource->LocalName) )) + { + ULONG CopyBytes; + + DbgP((TEXT("NPCancelConnection: Connection Found:\n"))); + + CopyBytes = 0; + + Status = SendTo_NFS41Driver( IOCTL_NFS41_DELCONN, + pNetResource->ConnectionName, + pNetResource->ConnectionNameLength, + NULL, + &CopyBytes ); + + if (Status != WN_SUCCESS) + { + DbgP((TEXT("NPCancelConnection: SendToMiniRdr returned Status %lx\n"),Status)); + break; + } + + if (DefineDosDevice(DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE, + lpName, + pNetResource->ConnectionName) == FALSE) + { + DbgP((TEXT("RemoveDosDevice: DefineDosDevice error: %d\n"), GetLastError())); + Status = GetLastError(); + } + else + { + pNetResource->InUse = FALSE; + pSharedMemory->NumberOfResourcesInUse--; + + if (Index+1 == pSharedMemory->NextAvailableIndex) + pSharedMemory->NextAvailableIndex--; + } + break; + } + + DbgP((TEXT("NPCancelConnection: Name %S EntryName %S\n"), + lpName,pNetResource->LocalName)); + DbgP((TEXT("NPCancelConnection: Name Length %d Entry Name Length %d\n"), + pNetResource->LocalNameLength,pNetResource->LocalName)); + + } + } + + CloseSharedMemory( &hMutex, + &hMemory, + (PVOID)&pSharedMemory); + } + + return Status; +} + +DWORD APIENTRY +NPGetConnection( + __in LPWSTR lpLocalName, + __out_bcount(*lpBufferSize) LPWSTR lpRemoteName, + __inout LPDWORD lpBufferSize ) +{ + DWORD Status = 0; + + HANDLE hMutex, hMemory; + PNFS41NP_SHARED_MEMORY pSharedMemory; + + Status = OpenSharedMemory( &hMutex, + &hMemory, + (PVOID)&pSharedMemory); + + if (Status == WN_SUCCESS) + { + INT Index; + PNFS41NP_NETRESOURCE pNetResource; + Status = WN_NOT_CONNECTED; + + for (Index = 0; Index < pSharedMemory->NextAvailableIndex; Index++) + { + pNetResource = &pSharedMemory->NetResources[Index]; + + if (pNetResource->InUse) + { + if ( ( (wcslen(lpLocalName) + 1) * sizeof(WCHAR) == + pNetResource->LocalNameLength) + && ( !wcscmp(lpLocalName, pNetResource->LocalName) )) + { + if (*lpBufferSize < pNetResource->RemoteNameLength) + { + *lpBufferSize = pNetResource->RemoteNameLength; + Status = WN_MORE_DATA; + } + else + { + *lpBufferSize = pNetResource->RemoteNameLength; + CopyMemory( lpRemoteName, + pNetResource->RemoteName, + pNetResource->RemoteNameLength); + Status = WN_SUCCESS; + } + break; + } + } + } + + CloseSharedMemory( &hMutex, &hMemory, (PVOID)&pSharedMemory); + } + + return Status; +} + +DWORD APIENTRY +NPOpenEnum( + DWORD dwScope, + DWORD dwType, + DWORD dwUsage, + LPNETRESOURCE lpNetResource, + LPHANDLE lphEnum ) +{ + DWORD Status; + + DbgP((L"[aglo] NPOpenEnum\n")); + + *lphEnum = NULL; + + switch ( dwScope ) + { + case RESOURCE_CONNECTED: + { + *lphEnum = HeapAlloc( GetProcessHeap( ), HEAP_ZERO_MEMORY, sizeof( ULONG ) ); + + if (*lphEnum ) + { + Status = WN_SUCCESS; + } + else + { + Status = WN_OUT_OF_MEMORY; + } + break; + } + break; + + case RESOURCE_CONTEXT: + default: + Status = WN_NOT_SUPPORTED; + break; + } + + + DbgP((L"[aglo] NPOpenEnum returning Status %lx\n",Status)); + + return(Status); +} + +DWORD APIENTRY +NPEnumResource( + HANDLE hEnum, + LPDWORD lpcCount, + LPVOID lpBuffer, + LPDWORD lpBufferSize) +{ + DWORD Status = WN_SUCCESS; + ULONG EntriesCopied; + LPNETRESOURCE pNetResource; + ULONG SpaceNeeded = 0; + ULONG SpaceAvailable; + PWCHAR StringZone; + HANDLE hMutex, hMemory; + PNFS41NP_SHARED_MEMORY pSharedMemory; + PNFS41NP_NETRESOURCE pNfsNetResource; + INT Index = *(PULONG)hEnum; + + + DbgP((L"[aglo] NPEnumResource\n")); + + DbgP((L"[aglo] NPEnumResource Count Requested %d\n", *lpcCount)); + + pNetResource = (LPNETRESOURCE) lpBuffer; + SpaceAvailable = *lpBufferSize; + EntriesCopied = 0; + StringZone = (PWCHAR) ((PBYTE)lpBuffer + *lpBufferSize); + + Status = OpenSharedMemory( &hMutex, + &hMemory, + (PVOID)&pSharedMemory); + + if ( Status == WN_SUCCESS) + { + Status = WN_NO_MORE_ENTRIES; + for (Index = *(PULONG)hEnum; Index < pSharedMemory->NextAvailableIndex; Index++) + { + pNfsNetResource = &pSharedMemory->NetResources[Index]; + + if (pNfsNetResource->InUse) + { + SpaceNeeded = sizeof( NETRESOURCE ); + SpaceNeeded += pNfsNetResource->LocalNameLength; + SpaceNeeded += pNfsNetResource->RemoteNameLength; + SpaceNeeded += 5 * sizeof(WCHAR); // comment + SpaceNeeded += sizeof(NFS41_PROVIDER_NAME_U); // provider name + if ( SpaceNeeded > SpaceAvailable ) + { + Status = WN_MORE_DATA; + DbgP((L"[aglo] NPEnumResource More Data Needed - %d\n", SpaceNeeded)); + *lpBufferSize = SpaceNeeded; + break; + } + else + { + SpaceAvailable -= SpaceNeeded; + + pNetResource->dwScope = pNfsNetResource->dwScope; + pNetResource->dwType = pNfsNetResource->dwType; + pNetResource->dwDisplayType = pNfsNetResource->dwDisplayType; + pNetResource->dwUsage = pNfsNetResource->dwUsage; + + // setup string area at opposite end of buffer + SpaceNeeded -= sizeof( NETRESOURCE ); + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded ); + // copy local name + StringCchCopy( StringZone, + pNfsNetResource->LocalNameLength, + pNfsNetResource->LocalName ); + pNetResource->lpLocalName = StringZone; + StringZone += pNfsNetResource->LocalNameLength/sizeof(WCHAR); + // copy remote name + StringCchCopy( StringZone, + pNfsNetResource->RemoteNameLength, + pNfsNetResource->RemoteName ); + pNetResource->lpRemoteName = StringZone; + StringZone += pNfsNetResource->RemoteNameLength/sizeof(WCHAR); + // copy comment + pNetResource->lpComment = StringZone; + *StringZone++ = L'A'; + *StringZone++ = L'_'; + *StringZone++ = L'O'; + *StringZone++ = L'K'; + *StringZone++ = L'\0'; + // copy provider name + pNetResource->lpProvider = StringZone; + StringCbCopyW( StringZone, sizeof(NFS41_PROVIDER_NAME_U), NFS41_PROVIDER_NAME_U ); + StringZone += sizeof(NFS41_PROVIDER_NAME_U)/sizeof(WCHAR); + EntriesCopied++; + if(EntriesCopied >= *lpcCount) + { + Status = WN_SUCCESS; + break; + } + // set new bottom of string zone + StringZone = (PWCHAR)( (PBYTE) StringZone - SpaceNeeded ); + } + pNetResource++; + } + } + CloseSharedMemory( &hMutex, &hMemory, (PVOID*)&pSharedMemory); + } + + *lpcCount = EntriesCopied; + *(PULONG) hEnum = Index; + + DbgP((L"[aglo] NPEnumResource entries returned: %d\n", EntriesCopied)); + + return Status; +} + +DWORD APIENTRY +NPCloseEnum( + HANDLE hEnum ) +{ + DbgP((L"[aglo] NPCloseEnum\n")); + HeapFree( GetProcessHeap( ), 0, (PVOID) hEnum ); + return WN_SUCCESS; +} + +DWORD APIENTRY +NPGetResourceParent( + LPNETRESOURCE lpNetResource, + LPVOID lpBuffer, + LPDWORD lpBufferSize ) +{ + DbgP(( L"[aglo] NPGetResourceParent: WN_NOT_SUPPORTED\n" )); + return WN_NOT_SUPPORTED; +} + +DWORD APIENTRY +NPGetResourceInformation( + __in LPNETRESOURCE lpNetResource, + __out_bcount(*lpBufferSize) LPVOID lpBuffer, + __inout LPDWORD lpBufferSize, + __deref_out LPWSTR *lplpSystem ) +{ + DbgP(( L"[aglo] NPGetResourceInformation: WN_NOT_SUPPORTED\n" )); + return WN_NOT_SUPPORTED; +} + +DWORD APIENTRY +NPGetUniversalName( + LPCWSTR lpLocalPath, + DWORD dwInfoLevel, + LPVOID lpBuffer, + LPDWORD lpBufferSize ) +{ + DbgP(( L"[aglo] NPGetUniversalName: WN_NOT_SUPPORTED\n" )); + return WN_NOT_SUPPORTED; +} diff --git a/dll/nfs41_np.def b/dll/nfs41_np.def new file mode 100644 index 0000000..31cd2d0 --- /dev/null +++ b/dll/nfs41_np.def @@ -0,0 +1,17 @@ +SECTIONS .NFS41_NP READ WRITE SHARED + +EXPORTS + NPGetCaps @13 + NPAddConnection @17 + NPAddConnection3 @38 + NPCancelConnection @18 + NPGetConnection @12 + NPOpenEnum @33 + NPEnumResource @34 + NPCloseEnum @35 + NPGetUniversalName @40 + NPGetResourceParent @41 + NPGetResourceInformation @52 + NPLogonNotify @500 + NPPasswordChangeNotify @501 + diff --git a/dll/nfs41_np.h b/dll/nfs41_np.h new file mode 100644 index 0000000..00e3bc3 --- /dev/null +++ b/dll/nfs41_np.h @@ -0,0 +1,52 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_NP_H__ +#define __NFS41_NP_H__ + +#define NFS41NP_MUTEX_NAME "NFS41NPMUTEX" + +#define NFS41NP_MAX_DEVICES 26 + +typedef struct __NFS41NP_NETRESOURCE { + BOOL InUse; + USHORT LocalNameLength; + USHORT RemoteNameLength; + USHORT ConnectionNameLength; + DWORD dwScope; + DWORD dwType; + DWORD dwDisplayType; + DWORD dwUsage; + WCHAR LocalName[MAX_PATH]; + WCHAR RemoteName[MAX_PATH]; + WCHAR ConnectionName[MAX_PATH]; + WCHAR Options[MAX_PATH]; +} NFS41NP_NETRESOURCE, *PNFS41NP_NETRESOURCE; + +typedef struct __NFS41NP_SHARED_MEMORY { + INT NextAvailableIndex; + INT NumberOfResourcesInUse; + NFS41NP_NETRESOURCE NetResources[NFS41NP_MAX_DEVICES]; +} NFS41NP_SHARED_MEMORY, *PNFS41NP_SHARED_MEMORY; + +#endif /* !__NFS41_NP_H__ */ diff --git a/dll/options.c b/dll/options.c new file mode 100644 index 0000000..f8fadd1 --- /dev/null +++ b/dll/options.c @@ -0,0 +1,100 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include "options.h" + + +DWORD InitializeConnectionInfo( + IN OUT PCONNECTION_INFO Connection, + IN PMOUNT_OPTION_BUFFER Options, + OUT LPWSTR *ConnectionName) +{ + DWORD result = WN_SUCCESS; + SIZE_T size; + + /* verify that this is a mount options buffer */ + if (Options && + Options->Zero == 0 && + Options->Secret == MOUNT_OPTION_BUFFER_SECRET) + { + Connection->Options = Options; + size = MAX_CONNECTION_BUFFER_SIZE(Options->Length); + } + else + { + Connection->Options = NULL; + size = MAX_CONNECTION_BUFFER_SIZE(0); + } + + Connection->Buffer = LocalAlloc(LMEM_ZEROINIT, size); + if (Connection->Buffer) + *ConnectionName = (LPWSTR)Connection->Buffer->Buffer; + else + result = WN_OUT_OF_MEMORY; + + return result; +} + +static FORCEINLINE SIZE_T ConnectionBufferSize( + IN PCONNECTION_BUFFER Buffer) +{ + return sizeof(USHORT) + sizeof(USHORT) + sizeof(ULONG) + + Buffer->NameLength + Buffer->EaPadding + Buffer->EaLength; +} + +void MarshalConnectionInfo( + IN OUT PCONNECTION_INFO Connection) +{ + PCONNECTION_BUFFER Buffer = Connection->Buffer; + LPWSTR ConnectionName = (LPWSTR)Buffer->Buffer; + + Buffer->NameLength = (USHORT)(wcslen(ConnectionName) + 1) * sizeof(WCHAR); + + /* copy the EaBuffer after the end of ConnectionName */ + if (Connection->Options && Connection->Options->Length) + { + PBYTE ptr = Buffer->Buffer + Buffer->NameLength; + /* add padding so EaBuffer starts on a ULONG boundary */ + Buffer->EaPadding = (USHORT) + (sizeof(ULONG) - (SIZE_T)ptr % sizeof(ULONG)) % sizeof(ULONG); + Buffer->EaLength = Connection->Options->Length; + ptr += Buffer->EaPadding; + + RtlCopyMemory(ptr, Connection->Options->Buffer, Buffer->EaLength); + } + + Connection->BufferSize = (ULONG)ConnectionBufferSize(Buffer); +} + +void FreeConnectionInfo( + IN PCONNECTION_INFO Connection) +{ + if (Connection->Buffer) + { + LocalFree(Connection->Buffer); + Connection->Buffer = NULL; + } + Connection->Options = NULL; + Connection->BufferSize = 0; +} diff --git a/dll/options.h b/dll/options.h new file mode 100644 index 0000000..2df3f37 --- /dev/null +++ b/dll/options.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_NP_OPTIONS_H__ +#define __NFS41_NP_OPTIONS_H__ + + +#define MOUNT_OPTION_BUFFER_SECRET ('n4') + +/* MOUNT_OPTION_BUFFER + * The mount options buffer received by NPAddConnection3 + * via NETRESOURCE.lpComment. To avoid interpreting a normal + * comment string as mount options, a NULL and secret number + * are expected at the front. */ +typedef struct _MOUNT_OPTION_BUFFER { + USHORT Zero; /* = 0 */ + USHORT Secret; /* = 'n4' */ + ULONG Length; + BYTE Buffer[1]; +} MOUNT_OPTION_BUFFER, *PMOUNT_OPTION_BUFFER; + +/* CONNECTION_BUFFER + * The connection information as sent to the driver via + * IOCTL_NFS41_ADDCONN. The buffer contains the connection name + * followed by any extended attributes for mount options. */ +typedef struct _CONNECTION_BUFFER { + USHORT NameLength; /* length of connection filename */ + USHORT EaPadding; /* 0-3 bytes of padding to put EaBuffer + * on a ULONG boundary */ + ULONG EaLength; /* length of EaBuffer */ + BYTE Buffer[1]; +} CONNECTION_BUFFER, *PCONNECTION_BUFFER; + +/* CONNECTION_INFO + * Used in NPAddConnection3 to encapsulate the formation of + * the connection buffer. */ +typedef struct _CONNECTION_INFO { + PMOUNT_OPTION_BUFFER Options; + ULONG BufferSize; + PCONNECTION_BUFFER Buffer; +} CONNECTION_INFO, *PCONNECTION_INFO; + +#define MAX_CONNECTION_BUFFER_SIZE(EaSize) ( \ + sizeof(CONNECTION_BUFFER) + MAX_PATH + (EaSize) ) + + +/* options.c */ +DWORD InitializeConnectionInfo( + IN OUT PCONNECTION_INFO Connection, + IN PMOUNT_OPTION_BUFFER Options, + OUT LPWSTR *ConnectionName); + +void FreeConnectionInfo( + IN OUT PCONNECTION_INFO Connection); + +/* MarshallConnectionInfo + * Prepares the CONNECTION_BUFFER for transmission to the driver + * by copying the extended attributes into place and updating the + * lengths accordingly. */ +void MarshalConnectionInfo( + IN OUT PCONNECTION_INFO Connection); + + +#endif /* !__NFS41_NP_OPTIONS_H__ */ diff --git a/dll/sources b/dll/sources new file mode 100644 index 0000000..2bf234b --- /dev/null +++ b/dll/sources @@ -0,0 +1,21 @@ +TARGETTYPE=DYNLINK +TARGETNAME=nfs41_np +SOURCES=dllmain.c nfs41_np.c options.c +UMTYPE=console +UNICODE=1 +DLLBASE=0x1010000 +USE_NTDLL=1 +NET_C_DEFINES=-DUNICODE +INCLUDES=..\sys; \ + $(DDK_INC_PATH); +TARGETLIBS=$(DDK_LIB_PATH)\user32.lib $(DDK_LIB_PATH)\kernel32.lib +DLLDEF=nfs41_np.def + +!IF 0 +/W3 is default level +bump to /Wall, but suppress warnings generated by system includes, +as well as the following warnings: +4100 - unused function call arguments (we have lots of stubs) +4127 - constant conditional (I like to use if(0) or if(1)) +!ENDIF +MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4711 diff --git a/install.bat b/install.bat new file mode 100644 index 0000000..cd79372 --- /dev/null +++ b/install.bat @@ -0,0 +1,2 @@ +nfs_install.exe +rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 132 ./nfs41rdr.inf diff --git a/install/nfs_install.c b/install/nfs_install.c new file mode 100644 index 0000000..efccd61 --- /dev/null +++ b/install/nfs_install.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ +/* + * + * This file is just for prepending nfs41_driver to the + * correct regestry entry + * + */ + +#include + +#include "nfs41_driver.h" +#include "nfsreginst.h" + +void __cdecl _tmain(int argc, TCHAR *argv[]) +{ + if(argc == 1 || atoi(argv[1]) == 1) + { + RdrSetupProviderOrder(); + } + else + { + while( RdrRemoveProviderFromOrder() ) {}; + } + + return; +} diff --git a/install/nfsreginst.c b/install/nfsreginst.c new file mode 100644 index 0000000..c13a10c --- /dev/null +++ b/install/nfsreginst.c @@ -0,0 +1,652 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ +/*++ + +Module Name: + + nfsreginst.c + +--*/ + +#include "nfsreginst.h" + + + +REGENTRY ProviderOrderKeyValues[] = +{ + { TEXT("ProviderOrder"), REG_SZ, 0, 0 } +}; + +BOOL RdrSetupProviderOrder( void ) +{ + LPTSTR pOrderString = NULL; + ULONG_PTR len; + BOOL success = TRUE; + LPTSTR pNewOrderString; + + while( RdrRemoveProviderFromOrder() ) {}; + + len = RdrGetProviderOrderString( &pOrderString ) * sizeof(TCHAR); + if ( len > 0 && pOrderString ) + { + len += sizeof( PROVIDER_NAME ) + (2 * sizeof(TCHAR)); // add 2 for comma delimeter and null + pNewOrderString = malloc( len ); + if ( pNewOrderString ) + { + StringCbCopy( pNewOrderString, len, PROVIDER_NAME ); + StringCbCat( pNewOrderString, len, TEXT(",") ); + StringCbCat( pNewOrderString, len, pOrderString ); + success = RdrSetProviderOrderString( pNewOrderString ); + free( pNewOrderString ); + } + } + else + { + success = RdrSetProviderOrderString( PROVIDER_NAME ); + } + if ( pOrderString ) + { + free( pOrderString ); + } + + return success; +} + + +ULONG_PTR RdrGetProviderOrderString( __out LPTSTR *OrderString ) +{ + HKEY hOrderKey; + ULONG_PTR len = 0; + + if ( OpenKey( PROVIDER_ORDER_KEY, &hOrderKey ) ) + { + ReadRegistryKeyValues( hOrderKey, + sizeof(ProviderOrderKeyValues) / sizeof(REGENTRY), + ProviderOrderKeyValues); + + RegCloseKey(hOrderKey); + len = ProviderOrderKeyValues[0].dwLength / sizeof( TCHAR ) - 1; + *OrderString = (LPTSTR) ProviderOrderKeyValues[0].pvValue; + } + + return len; +} + + +BOOL RdrSetProviderOrderString( __in LPTSTR OrderString ) +{ + HKEY hOrderKey; + BOOL rc = FALSE; + + if ( CreateKey( PROVIDER_ORDER_KEY, &hOrderKey ) ) + { + ProviderOrderKeyValues[0].dwLength = ( lstrlen( OrderString ) + 1 ) * sizeof( TCHAR ); + ProviderOrderKeyValues[0].pvValue = OrderString; + WriteRegistryKeyValues( hOrderKey, + sizeof(ProviderOrderKeyValues) / sizeof(REGENTRY), + ProviderOrderKeyValues); + RegCloseKey(hOrderKey); + + rc = TRUE; + } + + return rc; +} + + +BOOL RdrRemoveProviderFromOrder( void ) +{ + LPTSTR pCompare, OrderString, pOrig, Provider = PROVIDER_NAME; + BOOL match = FALSE; + ULONG_PTR len = 0; + + len = RdrGetProviderOrderString( &pOrig ); + OrderString = pOrig; + if ( OrderString && Provider && *Provider ) + { + pCompare = Provider; + + while ( *OrderString ) + { + if ( toupper(*OrderString) != toupper(*pCompare++) ) + { + pCompare = Provider; + while ( ( *OrderString != TEXT(',') ) && ( *OrderString != TEXT('\0') ) ) + { + OrderString++; + } + } + if ( *OrderString != TEXT('\0') ) OrderString++; + if ( *pCompare == TEXT('\0') ) + { + if ( ( *OrderString == TEXT(',') ) || ( *OrderString == TEXT('\0') ) ) + { + LPTSTR pNewString; + pNewString = malloc( len ); //Yes, this is a little larger than necessary + //No, I don't care that much + StringCchCopy(pNewString, len, pOrig); + //if ((DWORD_PTR)OrderString - (DWORD_PTR)pOrig - (DWORD_PTR)pCompare + (DWORD_PTR)Provider == 0 ) OrderString += 1; + if ( *OrderString == TEXT(',') ) + { + StringCchCopy(pNewString + (DWORD_PTR)OrderString - (DWORD_PTR)pOrig - (DWORD_PTR)pCompare + (DWORD_PTR)Provider, len, OrderString + 1); + } + else + { + StringCchCopy(pNewString + (DWORD_PTR)OrderString - (DWORD_PTR)pOrig - (DWORD_PTR)pCompare + (DWORD_PTR)Provider - 1, len, OrderString); + } + match = RdrSetProviderOrderString( pNewString ); + free(pNewString); + break; + } + else // hmm, it's a substring of another provider name + { + while ( ( *OrderString != TEXT(',') ) && ( *OrderString != TEXT('\0') ) ) + { + OrderString++; + } + pCompare = Provider; + } + } + + } + } + free( pOrig ); + + return match; +} + +void +ReadRegistryKeyValues( + HKEY hCurrentKey, + DWORD NumberOfValues, + PREGENTRY pValues) +/*++ + +Routine Description: + + This routine reads a bunch of values associated with a given key. + +Arguments: + + hCurrentKey - the key + + NumberOfValues - the number of values + + pValues - the array of values + +Return Value: + + None + +--*/ +{ + // + // Iterate through table reading the values along the way + // + + DWORD i; + + for (i = 0; i < NumberOfValues; i++) + { + DWORD dwType; + LPTSTR pszKey; + + dwType = pValues[i].dwType; + pszKey = pValues[i].pszKey; + + switch (dwType) + { + case REG_SZ: + GetRegsz(hCurrentKey, pszKey, &pValues[i].pvValue, + &pValues[i].dwLength); + break; + + case REG_DWORD: + GetRegdw(hCurrentKey, pszKey, &pValues[i].pvValue, + &pValues[i].dwLength); + break; + + case REG_EXPAND_SZ: + GetRegesz(hCurrentKey, pszKey, &pValues[i].pvValue, + &pValues[i].dwLength); + break; + + case REG_MULTI_SZ: + GetRegmsz(hCurrentKey, pszKey, &pValues[i].pvValue, + &pValues[i].dwLength); + break; + + case REG_BINARY: + break; + + default: + break; + + } + } +} + +// +// Get a REG_SZ value and stick it in the table entry, along with the +// length +// + +BOOL GetRegsz(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD *pdwLength) +{ + BYTE achValue[1024]; + + DWORD dwLength; + LONG Status; + DWORD dwType = REG_SZ; + PBYTE pszValue = NULL; + + + + if ( (NULL == pszKey) || (NULL == ppvValue) || + (NULL == hKey) || (NULL == pdwLength)) + { + return FALSE; + } + +#ifdef _DEBUG + FillMemory(achValue, sizeof(achValue), 0xcd); +#endif + + dwLength = sizeof(achValue); + + + Status = RegGetValue( hKey, + NULL, + pszKey, + 0x0000002, //RRF_RD_REG_SZ + &dwType, + (PVOID) &achValue[0], + &dwLength); + + if ((ERROR_SUCCESS != Status) || (REG_SZ != dwType) ) + { + return FALSE; + } + + pszValue = malloc(dwLength); + + if (NULL == pszValue) + { + return FALSE; + } + + + CopyMemory(pszValue, achValue, dwLength); + + *ppvValue = pszValue; + *pdwLength = dwLength; + + return TRUE; +} + +// +// Get the value of a REG_EXPAND_SZ and its length +// + +BOOL GetRegesz(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD * pdwLength) +{ + BYTE achValue[1024]; + + DWORD dwLength; + LONG Status; + DWORD dwType = REG_EXPAND_SZ; + PBYTE pszValue = NULL; + + + if ( (NULL == pszKey) || (NULL == ppvValue) || + (NULL == hKey) || (NULL == pdwLength)) + { + return FALSE; + } + +#ifdef _DEBUG + FillMemory(achValue, sizeof(achValue), 0xcd); +#endif + + dwLength = sizeof(achValue); + + Status = RegQueryValueEx( hKey, + pszKey, + NULL, + &dwType, + (PUCHAR) &achValue[0], + &dwLength); + + if ((ERROR_SUCCESS != Status) || (REG_EXPAND_SZ != dwType)) + { + return FALSE; + } + + pszValue = malloc(dwLength); + + if (NULL == pszValue) + { + return FALSE; + } + + CopyMemory(pszValue, achValue, dwLength); + + *ppvValue = pszValue; + *pdwLength = dwLength; + + return TRUE; +} + + +// +// Get value and length of REG_MULTI_SZ +// + +BOOL GetRegmsz(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount( *pdwLength) PVOID * ppvValue, __out DWORD * pdwLength) +{ + //BYTE achValue[1024]; + BYTE achValue[2048]; // careful, some of these strings are quite long + + DWORD dwLength; + LONG Status; + DWORD dwType = REG_MULTI_SZ; + PBYTE pszValue = NULL; + + + if ( (NULL == pszKey) || (NULL == ppvValue) || + (NULL == hKey) || (NULL == pdwLength)) + { + return FALSE; + } + +#ifdef _DEBUG + FillMemory(achValue, sizeof(achValue), 0xcd); +#endif + + + dwLength = sizeof(achValue); + + + Status = RegQueryValueEx( hKey, + pszKey, + NULL, + &dwType, + (PUCHAR) &achValue[0], + &dwLength); + + if ((ERROR_SUCCESS != Status) || (REG_MULTI_SZ != dwType)) + { + return FALSE; + } + + pszValue = malloc(dwLength); + + if (NULL == pszValue) + { + return FALSE; + } + + CopyMemory(pszValue, achValue, dwLength); + + *ppvValue = pszValue; + *pdwLength = dwLength; + + return TRUE; +} + + +// +// Get value and length of REG_DWORD +// + + +BOOL GetRegdw(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD * pdwLength) +{ + DWORD dwValue = 0; + + DWORD dwLength; + LONG Status; + DWORD dwType = REG_DWORD; + + + + if ( (NULL == pszKey) || (NULL == ppvValue) || + (NULL == hKey) || (NULL == pdwLength) ) + { + return FALSE; + } + + dwLength = sizeof(dwValue); + + + Status = RegQueryValueEx( hKey, + pszKey, + NULL, + &dwType, + (PUCHAR) &dwValue, + &dwLength); + + if ((ERROR_SUCCESS != Status) || (REG_DWORD != dwType)) + { + return FALSE; + } + + *ppvValue = (PVOID) (ULONG_PTR) dwValue; + *pdwLength = dwLength; + + return TRUE; +} + + + +void +WriteRegistryKeyValues( + HKEY hCurrentKey, + DWORD NumberOfValues, + PREGENTRY pValues) +/*++ + +Routine Description: + + This routine reads a bunch of values associated with a given key. + +Arguments: + + hCurrentKey - the key + + NumberOfValues - the number of values + + pValues - the array of values + +Return Value: + + None + +--*/ +{ + DWORD i; + + + for (i = 0; i < NumberOfValues; i++) + { + DWORD dwType; + PVOID pvValue; + DWORD dwLength; + LPTSTR pszKey; + + pszKey = pValues[i].pszKey; + dwType = pValues[i].dwType; + dwLength = pValues[i].dwLength; + pvValue = pValues[i].pvValue; + + switch (dwType) + { + case REG_SZ: + AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue); + break; + + case REG_DWORD: + AddValue(hCurrentKey, pszKey, dwType, dwLength, &pvValue); + break; + + case REG_EXPAND_SZ: + AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue); + break; + + case REG_MULTI_SZ: + AddValue(hCurrentKey, pszKey, dwType, dwLength, pvValue); + break; + + case REG_BINARY: + // + // There are no binary values we need to copy. If we did, we'd + // put something here + // + + break; + + default: + break; + + } + } +} + +// +// Open a key so we can read the values +// + + +BOOL OpenKey( + __in LPTSTR pszKey, + __out PHKEY phKey) +/*++ + +Routine Description: + + This routine opens a registry key. + +Arguments: + + pszKey - the name of the key relative to HKEY_LOCAL_MACHINE + + phKey - the key handlle + +Return Value: + + TRUE if successful, otherwise FALSE + +--*/ +{ + HKEY hNewKey = 0; + DWORD Status; + + Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + pszKey, + 0, + KEY_QUERY_VALUE, + &hNewKey); + + if (ERROR_SUCCESS != Status) + { + *phKey = NULL; + return FALSE; + } + else + { + *phKey = hNewKey; + return TRUE; + } +} + + +BOOL CreateKey(__in LPTSTR pszKey, __out PHKEY phKey) +/*++ + +Routine Description: + + This routine creates a registry key. + +Arguments: + + pszKey - the name of the key relative to HKEY_LOCAL_MACHINE + + phKey - the key handlle + +Return Value: + + TRUE if successful, otherwise FALSE + +--*/ +{ + LONG Status; + DWORD Disposition; + + Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, + pszKey, + 0, + REG_NONE, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + NULL, + phKey, + &Disposition); + + if ( ERROR_SUCCESS == Status) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +// +// Add a value to the registry +// + + +BOOL AddValue(__in HKEY hKey, __in LPTSTR pszKey, __in DWORD dwType, __in DWORD dwLength, __in PVOID pvValue) +{ + + BOOL fSuccess = TRUE; + LONG Status = ERROR_SUCCESS; + + Status = RegSetValueEx( hKey, + pszKey, + 0, + dwType, + pvValue, + dwLength); + + + if (Status != ERROR_SUCCESS) + { + fSuccess = FALSE; + //RegCloseKey(hKey); + } + + return fSuccess; +} diff --git a/install/nfsreginst.h b/install/nfsreginst.h new file mode 100644 index 0000000..431fd4b --- /dev/null +++ b/install/nfsreginst.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ +/*++ + +Copyright (c) 1997 - 1999 Microsoft Corporation + +Module Name: + + srfunc.h + +Abstract: + +--*/ + +#include +#include +#include + +#include "nfs41_driver.h" + +typedef struct { + LPTSTR pszKey; + DWORD dwType; + DWORD dwLength; + PVOID pvValue; +} REGENTRY, *PREGENTRY; + +void +ReadRegistryKeyValues( + HKEY hKey, + DWORD Count, + PREGENTRY pValues); + +void +WriteRegistryKeyValues( + HKEY hKey, + DWORD Count, + PREGENTRY pValues); + + +// +// routines for manipulating registry key values +// + +BOOL GetRegsz(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD *pdwLength); + +BOOL GetRegesz(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD * pdwLength); + +BOOL GetRegmsz(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD * pdwLength); + +BOOL GetRegdw(__in HKEY hKey, __in LPTSTR pszKey, __deref_out_bcount(*pdwLength) PVOID * ppvValue, __out DWORD * pdwLength); + + +// +// routines for manipulating registry keys +// + +BOOL OpenKey( + __in LPTSTR pszKey, + __out PHKEY phKey); + +BOOL CreateKey(__in LPTSTR pszKey, __out PHKEY phKey); +BOOL AddValue(__in HKEY hKey, __in LPTSTR pszKey, __in DWORD dwType, __in DWORD dwLength, __in PVOID pvValue); + +BOOL RdrSetupProviderOrder( void ); +BOOL RdrRemoveProviderFromOrder( void ); + +ULONG_PTR RdrGetProviderOrderString( __out LPTSTR *OrderString ); +BOOL RdrSetProviderOrderString( __in LPTSTR OrderString ); + + +typedef BOOL (*ACTIONVECTOR) ( void ); + +#define RDRSERVICE TEXT("nfs41_driver") +#define PROVIDER_NAME RDRSERVICE + +#define PROVIDER_ORDER_KEY TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order") + diff --git a/install/sources b/install/sources new file mode 100644 index 0000000..041ce5b --- /dev/null +++ b/install/sources @@ -0,0 +1,15 @@ +TARGETTYPE=PROGRAM +TARGETNAME=nfs_install +SOURCES=nfs_install.c nfsreginst.c +UMTYPE=console +USE_MSVCRT=1 +INCLUDES=..\sys + +!IF 0 +/W3 is default level +bump to /Wall, but suppress warnings generated by system includes, +as well as the following warnings: +4100 - unused function call arguments (we have lots of stubs) +4127 - constant conditional (I like to use if(0) or if(1)) +!ENDIF +MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4201 /wd4214 diff --git a/libtirpc/.gitignore b/libtirpc/.gitignore new file mode 100644 index 0000000..f4a325a --- /dev/null +++ b/libtirpc/.gitignore @@ -0,0 +1,46 @@ +# files generated by autoconf, automake, autoheader and libtoolize +aclocal.m4 +autom4te.cache +compile +config.guess +config.log +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +Makefile.in +missing +config.h.in +# files generated by configure +confdefs.h +config.status +conftest +conftest.c +conftest.cpp +conftest.er1 +conftest.err +.deps +Makefile +config.h +stamp-h1 +libtirpc.pc +# file generated during compilation +*.o +.libs +lib*.a +src/libtirpc.la +src/libtirpc_la-*.lo +# generic editor backup et al +*~ +# cscope database files +cscope.* +# files generated by patches +*.patch +*.rej +*.orig +# files generated by debugging +.gdb_history +.gdbinit +core diff --git a/libtirpc/AUTHORS b/libtirpc/AUTHORS new file mode 100644 index 0000000..5cc9b78 --- /dev/null +++ b/libtirpc/AUTHORS @@ -0,0 +1,3 @@ +Gilles Quillard +Antoine Fraticelli + diff --git a/libtirpc/COPYING b/libtirpc/COPYING new file mode 100644 index 0000000..8b548d6 --- /dev/null +++ b/libtirpc/COPYING @@ -0,0 +1,359 @@ +Sun Industry Standards Source License 1.0 + +DEFINITIONS + +1.1. "Commercial Use" means distribution or otherwise +making the Original Code available to a third party. + +1.2. "Contributor Version" means the combination of the +Original Code, and the Modifications made by that particular +Contributor. + +1.3. "Electronic Distribution Mechanism" means a mechanism +generally accepted in the software development community for +the electronic transfer of data. + +1.4. "Executable" means Original Code in any form other +than Source Code. + +1.5. "Initial Developer" means the individual or entity +identified as the Initial Developer in the Source Code +notice required by 2 (Exhibit A) + +1.6. "Larger Work" means a work which combines Original +Code or portions thereof with code not governed by the terms +of this License. + +1.7. "License" means this document. + +1.8. "Licensable" means having the right to grant, to the +maximum extent possible, whether at the time of the initial +grant or subsequently acquired, any and all of the rights +conveyed herein. + +1.9. "Modifications" means any addition to or deletion from +the substance or structure of either the Original Code or +any previous Modifications. A Modification is: + +A. Any addition to or deletion from the contents of a file +containing Original Code or previous Modifications. + +B. Any new file that contains any part of the Original Code +or previous Modifications. . + +1.10. "Original Code" means Source Code of computer +software code which is described in the Source Code notice +required by Exhibit A as Original Code. + +1.11. "Patent Claims" means any patent claims, now owned or +hereafter acquired, including without limitation, method, +process, and apparatus claims, in any patent Licensable by +grantor. + +1.12. "Source Code" means the preferred form of the +Original Code for making modifications to it, including all +modules it contains, plus any associated interface +definition files, or scripts used to control compilation and +installation of an Executable. + +1.13. "Standards" means the standard identified in Exhibit +B or a subsequent version of such standard. + +1.14. "You" or "Your" means an individual or a legal entity +exercising rights under, and complying with all of the terms +of, this License or a future version of this License issued +under Section 6.1. For legal entities, "You" includes any +entity which controls, is controlled by, or is under common +control with You. For purposes of this definition, +"control" means (a) the power, direct or indirect, to cause +the direction or management of such entity, whether by +contract or otherwise, or (b) ownership of more than fifty +percent (50%) of the outstanding shares or beneficial +ownership of such entity. + +2.0 SOURCE CODE LICENSE + +2.1 The Initial Developer Grant: The Initial Developer +hereby grants You a world-wide, royalty-free, non-exclusive +license, subject to third party intellectual property +claims: + +a) under intellectual property rights (other than patent or +trademark) Licensable by Initial Developer to use, +reproduce, modify, display, perform, sub license and +distribute the Original Code (or portions thereof )with or +without Modifications, and/or as part of a Larger Work; and + +b) under Patents Claims infringed by the making, using or +selling of Original Code, to make, have made, use, practice, +sell, and offer for sale, and/or otherwise dispose of the +Original Code (or portions thereof). + +c) the licenses granted in this Section 2.1(a ) and (b) are +effective on the date Initial Developer first distributes +Original Code under the terms of this License. + +d) Notwithstanding Section 2.1(b )above, no patent license +is granted: 1) for code that You delete from the Original +Code; 2) separate from the Original Code; or 3) for +infringements caused by: i) the modification of the +Original Code or + +ii) the combination of the Original Code with other software +or devices, including but not limited to Modifications. + +3.0 DISTRIBUTION OBLIGATIONS + +3.1 Application of License. The Source Code version of +Original Code may be distributed only under the terms of +this License or a future version of this License released +under Section 6.1, and You must include a copy of this +License with every copy of the Source Code You distribute. +You may not offer or impose any terms on any Source Code +version that alters or restricts the applicable version of +this License or the recipient's rights hereunder. Your +license for shipment of the Contributor Version is +conditioned upon your full compliance with this Section. +The Modifications which you create must comply with all +requirements set out by the Standards body in effect 120 +days before You ship the Contributor Version. In the event +that the Modifications do not meet such requirements, You +agree to publish (i) any deviation from the Standards +protocol resulting from implementation of your Modifications +and (ii) a reference implementation of Your Modifications, +and to make any such deviation and reference implementation +available to all third parties under the same terms as the +license on a royalty free basis within thirty (30) days of +Your first customer shipment of Your Modifications. + +3.2 Required Notices. You must duplicate the notice in +Exhibit A in each file of the Source Code. If it is not +possible to put such notice in a particular Source Code file +due to its structure, then You must include such notice in a +location (such as a relevant directory ) where a user would +be likely to look for such a notice. If You created one or +more Modifications ) You may add your name as a Contributor +to the notice described in Exhibit A. You must also +duplicate this License in any documentation for the Source +Code where You describe recipients' rights or ownership +rights relating to Initial Code. You may choose to offer, +and to charge a fee for, warranty, support, indemnity or +liability obligations to one or more recipients of Your +version of the Code. However, You may do so only + +on Your own behalf, and not on behalf of the Initial +Developer. You must make it absolutely clear than any such +warranty, support, indemnity or liability obligation is +offered by You alone, and You hereby agree to indemnify the +Initial Developer for any liability incurred by the Initial +Developer as a result of warranty, support, indemnity or +liability terms You offer. + +3.3 Distribution of Executable Versions. You may distribute +Original Code in Executable and Source form only if the +requirements of Section 3.1 and 3.2 have been met for that +Original Code, and if You include a notice stating that the +Source Code version of the Original Code is available under +the terms of this License. The notice must be conspicuously +included in any notice in an Executable or Source versions, +related documentation or collateral in which You describe +recipients' rights relating to the Original Code. You may +distribute the Executable and Source versions of Your +version of the Code or ownership rights under a license of +Your choice, which may contain terms different from this +License, provided that You are in compliance with the terms +of this License. If You distribute the Executable and +Source versions under a different license You must make it +absolutely clear that any terms which differ from this +License are offered by You alone, not by the Initial +Developer . You hereby agree to indemnify the Initial +Developer for any liability incurred by the Initial +Developer as a result of any such terms You offer . + +3.4 Larger Works. You may create a Larger Work by combining +Original Code with other code not governed by the terms of +this License and distribute the Larger Work as a single +product. In such a case, You must make sure the +requirements of this License are fulfilled for the Original +Code. + +4.0 INABILITY TO COMPLY DUE TO STATUTE OR REGULATION + +If it is impossible for You to comply with any of the terms +of this License with respect to some or all of the Original +Code due to statute, judicial order, or regulation then You +must: + +a) comply with the terms of this License to the maximum +extent possible; and + +b) describe the limitations and the code they affect. Such +description must be included in the LEGAL file described in +Section 3.2 and must be included with all distributions of +the Source Code. Except to the extent prohibited by statute +or regulation, such description must be sufficiently +detailed for a recipient of ordinary skill to be able to +understand it. + +5.0 APPLICATION OF THIS LICENSE This License applies to code +to which the Initial Developer has attached the notice in +Exhibit A and to related Modifications as set out in Section +3.1. + +6.0 VERSIONS OF THE LICENSE + +6.1 New Versions. Sun Microsystems, Inc. Sun may publish +revised and/or new versions of the License from time to +time. Each version will be given a distinguishing version +number . + +6.2 Effect of New Versions. Once Original Code has been +published under a particular version of the License, You may +always continue to use it under the terms of that version. +You may also choose to use such Original Code under the +terms of any subsequent version of the License published by +Sun. No one other than Sun has the right to modify the +terms applicable to Original Code. + +7. DISCLAIMER OF W ARRANTY. ORIGINAL CODE IS PROVIDED +UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT +LIMITATION, WARRANTIES THAT THE ORIGINAL CODE IS FREE OF +DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR +NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE ORIGINAL CODE IS WITH YOU. SHOULD ANY +ORIGINAL CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE +INITIAL DEVELOPER )ASSUME THE COST OF ANY NECESSARY +SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF +WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO +USE OF ANY ORIGINAL CODE IS AUTHORIZED HEREUNDER EXCEPT +UNDER THIS DISCLAIMER. + +8.0 TERMINATION + +8.1 This License and the rights granted hereunder will +terminate automatically if You fail to comply with terms +herein and fail to cure such breach within 30 days of +becoming aware of the breach. All sublicenses to the +Original Code which are properly granted shall survive any +termination of this License. Provisions which, by their +nature, must remain in effect beyond the termination of this +License shall survive. + +8.2 .In the event of termination under Section 8.1 above, +all end user license agreements (excluding distributors and +resellers) which have been validly granted by You or any +distributor hereunder prior to termination shall survive +termination. + +9.0 LIMIT OF LIABILITY UNDER NO CIRCUMSTANCES AND UNDER NO +LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE) ,CONTRACT, +OR OTHER WISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER +CONTRIBUTOR, OR ANY DISTRIBUTOR OF ORIGINAL CODE, OR ANY +SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR +ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF GOOD WILL, WORK STOPPAGE, COMPUTER FAILURE OR +MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR +LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE +POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY +SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY +RESULTING FROM SUCH PARTYS NEGLIGENCE TO THE EXTENT +APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME +JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF +INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND +LIMITATION MAY NOT APPLY TO YOU. + +10.0 U .S. GOVERNMENT END USERS U.S. Government: If this +Software is being acquired by or on behalf of the U.S. +Government or by a U.S. Government prime contractor or +subcontractor (at any tier), then the Government's rights in +the Software and accompanying documentation shall be only as +set forth in this license; this is in accordance with 48 C.F +.R. 227.7201 through 227.7202-4 (for Department of Defense +(DoD) acquisitions )and with 48 C.F.R.2.101 and 12.212( for +non-DoD acquisitions). + +11.0 MISCELLANEOUS This License represents the complete +agreement concerning subject matter hereof. If any +provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to +make it enforceable. This License shall be governed by +California law provisions (except to the extent applicable +law, if any, provides otherwise), excluding its +conflict-of-law provisions. With respect to disputes in +which at least one party is a citizen of, or an entity +chartered or registered to do business in the United States +of America, any litigation relating to this License shall be +subject to the jurisdiction of the Federal Courts of the +Northern District of California, with venue lying in Santa +Clara County, California, with the losing party responsible +for costs, including without limitation, court costs and +reasonable attorneys fees and expenses. The application of +the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. Any law +or regulation which provides that the language of a contract +shall be construed against the drafter shall not apply to +this License. + +EXHIBIT A - Sun Standards + +"The contents of this file are subject to the Sun Standards +License Version 1.0 the (the "License";) You may not use +this file except in compliance with the License. You may +obtain a copy of the License at +_______________________________. + + Software distributed under the License is distributed on +an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either +express or implied. See the License for the specific +language governing rights and limitations under the License. + +The Original Code is Copyright 1998 by Sun Microsystems, Inc + +The Initial Developer of the Original Code is: Sun +Microsystems, Inc. + +Portions created by _____________________________ are +Copyright ______________________________. + +All Rights Reserved. + +Contributors: ______________________________________. + +EXHIBIT B - Sun Standards + +The Standard is defined as the following IETF RFCs: + +RFC1831: RPC: Remote Procedure Call Protocol Specification +Version 2 RFC1832: XDR: External Data REpresentation +Standard RFC1833: Binding Protocols for ONC RPC Version 2 +RFC2078: Generic Security Service Application Program +Interface, Version 2 RFC2203: RPCSEC_GSS Protocol +Specification RFC2695: Authentication Mechanisms for ONC RPC + +* + * Copyright (c) Copyright (c) Bull S.A. 2005 All Rights Reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + diff --git a/libtirpc/ChangeLog b/libtirpc/ChangeLog new file mode 100644 index 0000000..e9a2aa1 --- /dev/null +++ b/libtirpc/ChangeLog @@ -0,0 +1,206 @@ +2008-11-19 Steve Dickson + + * Version 0.1.10 released. + +commit 32ec5931e3debf208972d5146578f08dc113a9b6 +Merge: 338af7f... 92cf0dd... +Author: Steve Dickson +Date: Mon Nov 17 12:26:22 2008 -0500 + + Merge branch 'master' of git://git.infradead.org/~steved/libtirpc + +commit 92cf0dde310ca341a2f29ff66b19eeb9994a649a +Author: Ian Kent +Date: Tue Oct 28 11:19:07 2008 -0400 + + Fixed a warings the IPV6 client routines + + Signed-off-by: Steve Dickson + +commit 338af7f9f00e096b65a6d823f885c4eeaf1d1f8c +Author: Steve Dickson +Date: Mon Oct 27 12:46:54 2008 -0400 + + __rpc_taddr2uaddr_af() assumes the netbuf to always have a + non-zero data. This is a bad assumption and can lead to a + seg-fault. This patch adds a check for zero length and returns + NULL when found. + + Signed-off-by: Steve Dickson + +commit d9a5ae7079d001a9e3b9b384f9153f591a7158bd +Author: Olaf Kirch +Date: Tue Sep 30 15:10:43 2008 -0400 + + Fix __rpc_getconfip + + __rpc_getconfip is supposed to return the first netconf + entry supporting tcp or udp, respectively. The code will + currently return the *last* entry, plus it will leak + memory when there is more than one such entry. + + This patch fixes this issue. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit 6c487efe74adb5c29f7bee5bd51b3ebef4968f7d +Author: Olaf Kirch +Date: Tue Sep 30 15:09:06 2008 -0400 + + Fix getpeereid + + getpeereid fails because it uses an incorrect getsockopt call to obtain + the peer credentials on a AF_LOCAL socket. This in turn will cause all + RPC services to be registered with rpcbind to show up as having been + registered by "unknown". + + This has a serious impact on security - a service owned by "unknown" + can essentially be unregistered (and thus replaced) by anyone. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit 851b0f5c6dca22d634603f03f0a5e3e35c6db867 +Author: Olaf Kirch +Date: Tue Sep 30 15:08:07 2008 -0400 + + svc_getcaller_netbuf macro seems broken + + I haven't found any documentation, but the comment in the header + file seems to suggest that svc_getcaller_netbuf should return the + xp_rtaddr netbuf. Returning the address of the socket descripor + seems to be wrong at any rate. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit d94b92d5125242ce595c1baf42a1e6d1004b7756 +Author: Olaf Kirch +Date: Tue Sep 30 15:06:54 2008 -0400 + + Introduce __rpc_set_netbuf helper + + The RPC code contains a number of places where a netbuf + is initialized with some data. All the mem_alloc/memcpy + stuff is open-coded. Introduce a helper function and + convert the code. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit da5f9861ea3bae59c8eead26d38334721caa9f0a +Author: Olaf Kirch +Date: Tue Sep 30 15:05:20 2008 -0400 + + Kill map_ipv4_to_ipv6 + + After the change to svc_vc.c performed in the previous patch, + this function is no longer needed. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit 59c374c4b507aeca957ed0096d98006edf601375 +Author: Olaf Kirch +Date: Tue Sep 30 15:04:17 2008 -0400 + + Fix xp_raddr handling in svc_fd_create etc + + Currently svc_fd_create tries to do some clever tricks + with IPv4/v6 address mapping. + + This is broken for several reasons. + 1. We don't want IPv4 based transport to look like IPv6 + transports. Old applications compiled against tirpc + will expect AF_INET addresses, and are not equipped + to deal with AF_INET6. + 2. There's a buffer overflow. + memcpy(&sin6, &ss, sizeof(ss)); + copies a full struct sockaddr to a sockaddr_in6 on + the stack. Unlikely to be exploitable, but I wonder + if this ever worked.... + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit 628788c1cc84c86ee4cb36ee5d4fe8954e90fca5 +Author: Steve Dickson +Date: Tue Sep 16 11:32:31 2008 -0400 + + - Fixed version-info in src/Makefile.am to reflect the correct version + - Fixed some of warnings in: src/auth_time.c, src/clnt_dg.c and + src/clnt_raw.c + - Added some #ifdef NOTUSED around some code in src/rpbc_clnt.c + that was not being used... + + Signed-off-by: Steve Dickson + +commit 9e7ba0c7a02031294fefadfbca42b3dd5f2d841f +Author: Olaf Kirch +Date: Tue Sep 16 08:46:29 2008 -0400 + + Fix for taddr2addr conversion bug of local addresses + + When converting af_local socket addresses in taddr2uaddr, an incorrect + sizeof() would result in a truncated path string. As a result, + rpcbind will report the local /var/lib/rpcbind address to clients + as "/v" on a 32bit machine. + + Signed-off-by: okir@suse.de + Signed-off-by: Steve Dickson + +commit ea9f048761d0b9a2ab6310bffa07351f0b04d8c5 +Author: Olaf Kirch +Date: Tue Sep 2 12:11:15 2008 -0400 + + Always make IPv6 sockets V6ONLY + + Assume you have a netconfig file looking like this: + + udp tpi_clts v inet udp - - + udp6 tpi_clts v inet6 udp - - + ... + + a call to svc_tli_create(... &someaddr, "udp") will fail to create an + IPv6 server socket. The problem is that on Linux, passive IPv6 sockets + will also accept packets/connections from IPv4, and will simply map + the sender's address to an IPv6 mapped IPv4 address. So if you want to + bind both a UDPv4 and UDPv6 socket to the same port, this will fail with + EADDRINUSE. + + The way to avoid this behavior is to change the socket to V6ONLY, + which tells the kernel to avoid the autmatic mapping. + + The change proposed in the patch below does this. I *think* this is + a good place to do this, as it will also fix applications that do not + use svc_tli_create() - such as rpcbind, which creates the sockets on + its own using __rpc_nconf2fd. + + I think this also improves portability, as BSD code assumes BSD + behavior, where this mapping does not occur either. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +commit 95c8f7227e6b15f2e430d7b87dadc95b2acd4a61 +Author: Olaf Kirch +Date: Tue Sep 2 12:09:39 2008 -0400 + + Fix incorrect sizeof() in __rpc_getbroadifs + + __rpc_getbroadifs returns bad broadcast addresses on 32bit + machines because when copying the broadcast addresses, ite + applies the sizeof() operator to a pointer to a sockaddr, + rather than the sockaddr itself. + + Signed-off-by: Olaf Kirch + Signed-off-by: Steve Dickson + +2004-10-13 Antoine Fraticelli + + * Version 0.1 released. + +2005-01-07 Gilles Quillard + + * Version 0.1.5 Fix problems links to the use of Kerberos. diff --git a/libtirpc/INSTALL b/libtirpc/INSTALL new file mode 100644 index 0000000..3fc70ae --- /dev/null +++ b/libtirpc/INSTALL @@ -0,0 +1,251 @@ +Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + + +TI-RPC Library Quick Installation +================================= + + Without GSS API + +$ ./configure +$ make +# make install + + To enable utilization of RPCSEC via GSS API use following commands +but you need to install libgssapi from the CITI before + +$ ./configure --enable-gss +$ make +# make install + + Once installed, you can customize the /etc/netconfig configuration file +to configure the supported protocols. To support INET6 udp/tcp, uncomment +the udp6/tcp6 lines. + + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/libtirpc/Makefile.am b/libtirpc/Makefile.am new file mode 100644 index 0000000..7f5f37b --- /dev/null +++ b/libtirpc/Makefile.am @@ -0,0 +1,36 @@ +SUBDIRS = src man doc + +nobase_include_HEADERS = tirpc/netconfig.h \ + tirpc/rpcsvc/crypt.x \ + tirpc/rpcsvc/crypt.h \ + tirpc/rpc/xdr.h \ + tirpc/rpc/types.h \ + tirpc/rpc/svc_soc.h \ + tirpc/rpc/svc.h \ + tirpc/rpc/svc_dg.h \ + tirpc/rpc/svc_auth.h \ + tirpc/rpc/rpc_msg.h \ + tirpc/rpc/rpc.h \ + tirpc/rpc/rpcent.h \ + tirpc/rpc/rpc_com.h \ + tirpc/rpc/rpcb_prot.x \ + tirpc/rpc/rpcb_prot.h \ + tirpc/rpc/rpcb_clnt.h \ + tirpc/rpc/raw.h \ + tirpc/rpc/pmap_rmt.h \ + tirpc/rpc/pmap_prot.h \ + tirpc/rpc/pmap_clnt.h \ + tirpc/rpc/nettype.h \ + tirpc/rpc/des.h \ + tirpc/rpc/des_crypt.h \ + tirpc/rpc/clnt_stat.h \ + tirpc/rpc/clnt_soc.h \ + tirpc/rpc/clnt.h \ + tirpc/rpc/auth_unix.h \ + tirpc/rpc/auth_kerb.h \ + tirpc/rpc/auth.h \ + tirpc/rpc/auth_gss.h \ + tirpc/rpc/auth_des.h + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA = libtirpc.pc diff --git a/libtirpc/NEWS b/libtirpc/NEWS new file mode 100644 index 0000000..7eef517 --- /dev/null +++ b/libtirpc/NEWS @@ -0,0 +1,3 @@ +New in 0.1: +* Portage from FreeBSD 5.2.1 (security part to be completed) +* Use autoconf/automake diff --git a/libtirpc/README b/libtirpc/README new file mode 100644 index 0000000..3b10e0d --- /dev/null +++ b/libtirpc/README @@ -0,0 +1,44 @@ +LIBTIRPC 0.1 FROM SUN'S TIRPCSRC 2.3 29 Aug 1994 + +This package contains SunLib's implementation of transport-independent +RPC (TI-RPC) documentation. This library forms a piece of the base of Open Network +Computing (ONC), and is derived directly from the Solaris 2.3 source. + +TI-RPC is an enhanced version of TS-RPC that requires the UNIX System V +Transport Layer Interface (TLI) or an equivalent X/Open Transport Interface +(XTI). TI-RPC is on-the-wire compatible with the TS-RPC, which is supported +by almost 70 vendors on all major operating systems. TS-RPC source code +(RPCSRC 4.0) remains available from several internet sites. + +This release was a native source release, compatible for +building on Solaris 2.3. It had been ported from FreeBSD 5.2.1 to GNU/Linux +in 2004. + +Applications linked with this release's librpc must link with the United +States domestic version of libcrypt in order to resolve the cbc_crypt() and +ecb_crypt() functions. These routines are used with Secure RPC however all +RPC programs that link with this release's librpc will need to link with the +domestic libcrypt. + +WHAT'S NEW IN THIS RELEASE: TIRPCSRC 2.3 FROM SUN + +The previous release was TIRPCSRC 2.0. + +1. This release is based on Solaris 2.3. The previous release was + based on Solaris 2.0. This release contains a siginificant number of + bug fixes and other enhancements over TIRPCSRC 2.0. + +2. The RPC library is thread safe for all client-side interfaces + (clnt_create, clnt_call, etc.). The server-side interfaces + (svc_create, svc_run, etc.) are not thread safe in this release. The + server-side interfaces will be made thread safe in the next release of + TIRPCSRC. Please see the manual pages for details about which + interfaces are thread safe. + +3. As part of the work to make the RPC library thread-safe, rpcgen has + been enhanced to generate thread-safe RPC stubs (the -M option). Note + that this modifies the call-signature for the stub functions; the + procedure calling the RPC stub must now pass to the stub a pointer to + an allocated structure where results will be placed by the stub. See + the rpcgen manual page and the rpcgen Programming Guide for details. + diff --git a/libtirpc/THANKS b/libtirpc/THANKS new file mode 100644 index 0000000..cea8ee3 --- /dev/null +++ b/libtirpc/THANKS @@ -0,0 +1,6 @@ + Thanks to for + +Aurelien Charbon TI-RPC portage from NetBSD + +BSD Communauty TI-RPC improvement from Sun implementation + diff --git a/libtirpc/TODO b/libtirpc/TODO new file mode 100644 index 0000000..6f62665 --- /dev/null +++ b/libtirpc/TODO @@ -0,0 +1,3 @@ +* Support of DES & other security part +* Provide tests +* rpcgen command missing diff --git a/libtirpc/VERSION b/libtirpc/VERSION new file mode 100644 index 0000000..5ee5442 --- /dev/null +++ b/libtirpc/VERSION @@ -0,0 +1,7 @@ +# This file is used by configure to get version information +# +PKG_MAJOR=0 +PKG_MINOR=1 +PKG_REVISION=11 +PKG_BUILD=0 + diff --git a/libtirpc/autogen.sh b/libtirpc/autogen.sh new file mode 100644 index 0000000..1613b6d --- /dev/null +++ b/libtirpc/autogen.sh @@ -0,0 +1,42 @@ +#!/bin/sh -e + +echo -n cleaning up . + +# Clean up the generated crud +( + for FILE in compile config.guess config.sub depcomp install-sh ltmain.sh missing mkinstalldirs; do + if test -f $FILE; then + rm -f $FILE + fi + echo -n . + done +) + +for FILE in aclocal.m4 configure config.h.in; do + if test -f $FILE; then + rm -f $FILE + fi + echo -n . +done + +for DIR in autom4te.cache; do + if test -d $DIR; then + rm -rf $DIR + fi + echo -n . +done + +find . -type f -name 'Makefile.in' -print0 | xargs -r0 rm -f -- +find . -type f -name 'Makefile' -print0 | xargs -r0 rm -f -- + +echo ' done' + +if test x"${1}" = x"clean"; then + exit +fi + +aclocal +libtoolize --force --copy +autoheader +automake --add-missing --copy --gnu # -Wall +autoconf # -Wall diff --git a/libtirpc/bootstrap b/libtirpc/bootstrap new file mode 100644 index 0000000..dde1a77 --- /dev/null +++ b/libtirpc/bootstrap @@ -0,0 +1,10 @@ +[ -e Makefile ] && make clean +rm -rf autom4te.cache configure Makefile stamp-h1 +rm -rf src/Makefile src/.deps +rm -rf Makefile.in aclocal.m4 config.log config.h +rm -rf depcomp missing install-sh config.status +aclocal +autoheader +automake --gnu --add-missing -c +autoconf +rm -rf autom4te.cache config.log libtool stamp-h1* diff --git a/libtirpc/configure.ac b/libtirpc/configure.ac new file mode 100644 index 0000000..0f3ce42 --- /dev/null +++ b/libtirpc/configure.ac @@ -0,0 +1,29 @@ +AC_INIT(libtirpc, 0.2.1) +AM_INIT_AUTOMAKE(libtirpc, 0.2.1) +AM_MAINTAINER_MODE +AC_CONFIG_SRCDIR([src/auth_des.c]) + +AC_ARG_ENABLE(gss,[ --enable-gss Turn on gss api], [case "${enableval}" in + yes) gss=true ; AC_CHECK_LIB([gssapi],[gss_init_sec_context]) ;; + no) gss=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gss) ;; + esac],[gss=false]) +AM_CONDITIONAL(GSS, test x$gss = xtrue) +if test x$gss = xtrue; then + AC_DEFINE(HAVE_LIBGSSAPI, 1, []) + PKG_CHECK_MODULES(GSSGLUE, libgssglue, [], + AC_MSG_ERROR([Unable to locate information required to use libgssglue.])) +fi + +AC_PROG_CC +AM_CONFIG_HEADER(config.h) +AC_PROG_LIBTOOL +##AC_PROG_RANLIB +AC_HEADER_DIRENT +AC_PREFIX_DEFAULT(/usr) +AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h locale.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h]) +AC_CHECK_LIB([pthread], [pthread_create]) + + +AC_CONFIG_FILES([Makefile src/Makefile man/Makefile doc/Makefile]) +AC_OUTPUT(libtirpc.pc) diff --git a/libtirpc/dirs b/libtirpc/dirs new file mode 100644 index 0000000..14663d5 --- /dev/null +++ b/libtirpc/dirs @@ -0,0 +1,2 @@ +DIRS = src + diff --git a/libtirpc/doc/Makefile.am b/libtirpc/doc/Makefile.am new file mode 100644 index 0000000..cc4fa76 --- /dev/null +++ b/libtirpc/doc/Makefile.am @@ -0,0 +1,5 @@ + +install: install-am + $(mkinstalldirs) $(DESTDIR)/etc + cp -p ./etc_netconfig $(DESTDIR)/etc/netconfig + chmod 0644 $(DESTDIR)/etc/netconfig diff --git a/libtirpc/doc/etc_netconfig b/libtirpc/doc/etc_netconfig new file mode 100644 index 0000000..effc67e --- /dev/null +++ b/libtirpc/doc/etc_netconfig @@ -0,0 +1,19 @@ +# +# The network configuration file. This file is currently only used in +# conjunction with the TI-RPC code in the libtirpc library. +# +# Entries consist of: +# +# \ +# +# +# The and fields are always empty in this +# implementation. +# +udp tpi_clts v inet udp - - +tcp tpi_cots_ord v inet tcp - - +udp6 tpi_clts v inet6 udp - - +tcp6 tpi_cots_ord v inet6 tcp - - +rawip tpi_raw - inet - - - +local tpi_cots_ord - loopback - - - +unix tpi_cots_ord - loopback - - - diff --git a/libtirpc/libtirpc.pc.in b/libtirpc/libtirpc.pc.in new file mode 100644 index 0000000..ec4cf75 --- /dev/null +++ b/libtirpc/libtirpc.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libtirpc +Description: Transport Independent RPC Library +Requires: +Version: @PACKAGE_VERSION@ +Libs: -L@libdir@ -ltirpc +Cflags: -I@includedir@/tirpc diff --git a/libtirpc/libtirpc/libtirpc.def b/libtirpc/libtirpc/libtirpc.def new file mode 100644 index 0000000..ce2ff85 --- /dev/null +++ b/libtirpc/libtirpc/libtirpc.def @@ -0,0 +1,94 @@ +LIBRARY libtirpc +EXPORTS +authnone_create +authunix_create +authunix_create_default +clnt_create +clnt_broadcast +clnt_pcreateerror +clnt_perrno +clnt_perror +clnt_spcreateerror +clnt_sperrno +clnt_sperror +clnt_tli_create +clntraw_create +clnttcp_create +clntudp_bufcreate +clntudp_create +freenetbuf +freenetconfigent +freeuaddr +get_myaddress +getnetconfigent +pmap_getmaps +pmap_getport +pmap_rmtcall +pmap_set +pmap_unset +svc_getreq +svc_getreqset +svc_run +svc_sendreply +svcerr_auth +svcerr_decode +svcerr_noproc +svcerr_noprog +svcerr_progvers +svcerr_systemerr +svcerr_weakauth +svcraw_create +svctcp_create +svcudp_bufcreate +svcudp_create +taddr2uaddr +tsd_key_delete +uaddr2taddr +xdr_array +xdr_authunix_parms +xdr_bool +xdr_bytes +xdr_callhdr +xdr_callmsg +xdr_char +xdr_des_block +xdr_double +xdr_enum +xdr_float +xdr_free +xdr_hyper +xdr_int +xdr_long +xdr_netobj +xdr_opaque +xdr_opaque_auth +xdr_pmap +xdr_pmaplist +xdr_pmaplist_ptr +xdr_pointer +xdr_reference +xdr_replymsg +xdr_short +xdr_string +xdr_u_char +xdr_u_hyper +xdr_u_int +xdr_u_int32_t +xdr_u_int64_t +xdr_u_long +xdr_u_short +xdr_union +xdr_vector +xdr_void +xdr_wrapstring +xdrmem_create +xdrrec_create +xdrrec_endofrecord +xdrrec_eof +xdrrec_skiprecord +xdrstdio_create +xprt_register +xprt_unregister +svc_fdset DATA +rpc_createerr DATA +_null_auth DATA diff --git a/libtirpc/libtirpc/libtirpc.rc b/libtirpc/libtirpc/libtirpc.rc new file mode 100644 index 0000000..11c5d52 --- /dev/null +++ b/libtirpc/libtirpc/libtirpc.rc @@ -0,0 +1,61 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/libtirpc/libtirpc/resource.h b/libtirpc/libtirpc/resource.h new file mode 100644 index 0000000..0ac2506 --- /dev/null +++ b/libtirpc/libtirpc/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by tirpc.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/libtirpc/man/Makefile.am b/libtirpc/man/Makefile.am new file mode 100644 index 0000000..b84dd24 --- /dev/null +++ b/libtirpc/man/Makefile.am @@ -0,0 +1,9 @@ + +man5_MANS = netconfig.5 +man3_MANS = bindresvport.3t des_crypt.3t getnetconfig.3t getnetpath.3t \ + getrpcent.3t getrpcport.3t rpc.3t rpc_clnt_auth.3t rpc_clnt_calls.3t \ + rpc_clnt_create.3t rpc_secure.3t rpc_soc.3t rpc_svc_calls.3t \ + rpc_svc_create.3t rpc_svc_err.3t rpc_svc_reg.3t rpc_xdr.3t rtime.3t + +EXTRA_DIST = $(man5_MANS) $(man3_MANS) + diff --git a/libtirpc/man/bindresvport.3t b/libtirpc/man/bindresvport.3t new file mode 100644 index 0000000..6724663 --- /dev/null +++ b/libtirpc/man/bindresvport.3t @@ -0,0 +1,101 @@ +.\" @(#)bindresvport.3n 2.2 88/08/02 4.0 RPCSRC; from 1.7 88/03/14 SMI +.\" +.Dd November 22, 1987 +.Dt BINDRESVPORT 3 +.Os +.Sh NAME +.Nm bindresvport , +.Nm bindresvport_sa +.Nd bind a socket to a privileged IP port +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/types.h +.In rpc/rpc.h +.Ft int +.Fn bindresvport "int sd" "struct sockaddr_in *sin" +.Ft int +.Fn bindresvport_sa "int sd" "struct sockaddr *sa" +.Sh DESCRIPTION +The +.Fn bindresvport +and +.Fn bindresvport_sa +functions +are used to bind a socket descriptor to a privileged +.Tn IP +port, that is, a +port number in the range 0-1023. +.Pp +If +.Fa sin +is a pointer to a +.Ft "struct sockaddr_in" +then the appropriate fields in the structure should be defined. +Note that +.Fa sin->sin_family +must be initialized to the address family of the socket, passed by +.Fa sd . +If +.Fa sin->sin_port +is +.Sq 0 +then an anonymous port (in the range 600-1023) will be +chosen, and if +.Xr bind 2 +is successful, the +.Fa sin->sin_port +will be updated to contain the allocated port. +.Pp +If +.Fa sin +is the +.Dv NULL +pointer, +an anonymous port will be allocated (as above). +However, there is no way for +.Fn bindresvport +to return the allocated port in this case. +.Pp +Only root can bind to a privileged port; this call will fail for any +other users. +.Pp +Function prototype of +.Fn bindresvport +is biased to +.Dv AF_INET +socket. +The +.Fn bindresvport_sa +function +acts exactly the same, with more neutral function prototype. +Note that both functions behave exactly the same, and +both support +.Dv AF_INET6 +sockets as well as +.Dv AF_INET +sockets. +.Sh RETURN VALUES +.Rv -std bindresvport +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EPFNOSUPPORT +If second argument was supplied, +and address family did not match between arguments. +.El +.Pp +The +.Fn bindresvport +function +may also fail and set +.Va errno +for any of the errors specified for the calls +.Xr bind 2 , +.Xr getsockopt 2 , +or +.Xr setsockopt 2 . +.Sh SEE ALSO +.Xr bind 2 , +.Xr getsockopt 2 , +.Xr setsockopt 2 , +.Xr ip 4 diff --git a/libtirpc/man/des_crypt.3t b/libtirpc/man/des_crypt.3t new file mode 100644 index 0000000..b708f76 --- /dev/null +++ b/libtirpc/man/des_crypt.3t @@ -0,0 +1,129 @@ +.\" @(#)des_crypt.3 2.1 88/08/11 4.0 RPCSRC; from 1.16 88/03/02 SMI; +.\" +.Dd October 6, 1987 +.Dt DES_CRYPT 3 +.Os +.Sh NAME +.Nm des_crypt , ecb_crypt , cbc_crypt , des_setparity +.Nd "fast DES encryption" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/des_crypt.h +.Ft int +.Fn ecb_crypt "char *key" "char *data" "unsigned datalen" "unsigned mode" +.Ft int +.Fn cbc_crypt "char *key" "char *data" "unsigned datalen" "unsigned mode" "char *ivec" +.Ft void +.Fn des_setparity "char *key" +.Sh DESCRIPTION +The +.Fn ecb_crypt +and +.Fn cbc_crypt +functions +implement the +.Tn NBS +.Tn DES +(Data Encryption Standard). +These routines are faster and more general purpose than +.Xr crypt 3 . +They also are able to utilize +.Tn DES +hardware if it is available. +The +.Fn ecb_crypt +function +encrypts in +.Tn ECB +(Electronic Code Book) +mode, which encrypts blocks of data independently. +The +.Fn cbc_crypt +function +encrypts in +.Tn CBC +(Cipher Block Chaining) +mode, which chains together +successive blocks. +.Tn CBC +mode protects against insertions, deletions and +substitutions of blocks. +Also, regularities in the clear text will +not appear in the cipher text. +.Pp +Here is how to use these routines. +The first argument, +.Fa key , +is the 8-byte encryption key with parity. +To set the key's parity, which for +.Tn DES +is in the low bit of each byte, use +.Fn des_setparity . +The second argument, +.Fa data , +contains the data to be encrypted or decrypted. +The +third argument, +.Fa datalen , +is the length in bytes of +.Fa data , +which must be a multiple of 8. +The fourth argument, +.Fa mode , +is formed by +.Em OR Ns 'ing +together some things. +For the encryption direction +.Em OR +in either +.Dv DES_ENCRYPT +or +.Dv DES_DECRYPT . +For software versus hardware +encryption, +.Em OR +in either +.Dv DES_HW +or +.Dv DES_SW . +If +.Dv DES_HW +is specified, and there is no hardware, then the encryption is performed +in software and the routine returns +.Er DESERR_NOHWDEVICE . +For +.Fn cbc_crypt , +the +.Fa ivec +argument +is the 8-byte initialization +vector for the chaining. +It is updated to the next initialization +vector upon return. +.Sh ERRORS +.Bl -tag -width [DESERR_NOHWDEVICE] -compact +.It Bq Er DESERR_NONE +No error. +.It Bq Er DESERR_NOHWDEVICE +Encryption succeeded, but done in software instead of the requested hardware. +.It Bq Er DESERR_HWERR +An error occurred in the hardware or driver. +.It Bq Er DESERR_BADPARAM +Bad argument to routine. +.El +.Pp +Given a result status +.Va stat , +the macro +.Fn DES_FAILED stat +is false only for the first two statuses. +.Sh SEE ALSO +.\" .Xr des 1 , +.Xr crypt 3 +.Sh RESTRICTIONS +These routines are not available in RPCSRC 4.0. +This information is provided to describe the +.Tn DES +interface expected by +Secure RPC. diff --git a/libtirpc/man/getnetconfig.3t b/libtirpc/man/getnetconfig.3t new file mode 100644 index 0000000..fbaa14d --- /dev/null +++ b/libtirpc/man/getnetconfig.3t @@ -0,0 +1,220 @@ +.\" @(#)getnetconfig.3n 1.28 93/06/02 SMI; from SVr4 +.\" Copyright 1989 AT&T +.Dd April 22, 2000 +.Dt GETNETCONFIG 3 +.Os +.Sh NAME +.Nm getnetconfig , +.Nm setnetconfig , +.Nm endnetconfig , +.Nm getnetconfigent , +.Nm freenetconfigent , +.Nm nc_perror , +.Nm nc_sperror +.Nd get network configuration database entry +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In netconfig.h +.Ft "struct netconfig *" +.Fn getnetconfig "void *handlep" +.Ft "void *" +.Fn setnetconfig "void" +.Ft int +.Fn endnetconfig "void *handlep" +.Ft "struct netconfig *" +.Fn getnetconfigent "const char *netid" +.Ft void +.Fn freenetconfigent "struct netconfig *netconfigp" +.Ft void +.Fn nc_perror "const char *msg" +.Ft "char *" +.Fn nc_sperror "void" +.Sh DESCRIPTION +The library routines described on this page +provide the application access to +the system network configuration database, +.Pa /etc/netconfig . +The +.Fn getnetconfig +function +returns a pointer to the +current entry in the +netconfig +database, formatted as a +.Ft "struct netconfig" . +Successive calls will return successive netconfig +entries in the netconfig database. +The +.Fn getnetconfig +function +can be used to search the entire netconfig +file. +The +.Fn getnetconfig +function +returns +.Dv NULL +at the end of the file. +The +.Fa handlep +argument +is the handle obtained through +.Fn setnetconfig . +.Pp +A call to +.Fn setnetconfig +has the effect of +.Dq binding +to or +.Dq rewinding +the netconfig database. +The +.Fn setnetconfig +function +must be called before the first call to +.Fn getnetconfig +and may be called at any other time. +The +.Fn setnetconfig +function +need not be called before a call to +.Fn getnetconfigent . +The +.Fn setnetconfig +function +returns a unique handle to be used by +.Fn getnetconfig . +.Pp +The +.Fn endnetconfig +function +should be called when processing is complete to release resources for reuse. +The +.Fa handlep +argument +is the handle obtained through +.Fn setnetconfig . +Programmers should be aware, however, that the last call to +.Fn endnetconfig +frees all memory allocated by +.Fn getnetconfig +for the +.Ft "struct netconfig" +data structure. +The +.Fn endnetconfig +function +may not be called before +.Fn setnetconfig . +.Pp +The +.Fn getnetconfigent +function +returns a pointer +to the netconfig structure corresponding +to +.Fa netid . +It returns +.Dv NULL +if +.Fa netid +is invalid +(that is, does not name an entry in the netconfig database). +.Pp +The +.Fn freenetconfigent +function +frees the netconfig structure pointed to by +.Fa netconfigp +(previously returned by +.Fn getnetconfigent ) . +.Pp +The +.Fn nc_perror +function +prints a message to the standard error indicating why any of the +above routines failed. +The message is prepended with the string +.Fa msg +and a colon. +A newline character is appended at the end of the message. +.Pp +The +.Fn nc_sperror +function +is similar to +.Fn nc_perror +but instead of sending the message +to the standard error, will return a pointer to a string that +contains the error message. +.Pp +The +.Fn nc_perror +and +.Fn nc_sperror +functions +can also be used with the +.Ev NETPATH +access routines defined in +.Xr getnetpath 3 . +.Sh RETURN VALUES +The +.Fn setnetconfig +function +returns a unique handle to be used by +.Fn getnetconfig . +In the case of an error, +.Fn setnetconfig +returns +.Dv NULL +and +.Fn nc_perror +or +.Fn nc_sperror +can be used to print the reason for failure. +.Pp +The +.Fn getnetconfig +function +returns a pointer to the current entry in the netconfig +database, formatted as a +.Ft "struct netconfig" . +The +.Fn getnetconfig +function +returns +.Dv NULL +at the end of the file, or upon failure. +.Pp +The +.Fn endnetconfig +function +returns 0 on success and \-1 on failure +(for example, if +.Fn setnetconfig +was not called previously). +.Pp +On success, +.Fn getnetconfigent +returns a pointer to the +.Ft "struct netconfig" +structure corresponding to +.Fa netid ; +otherwise it returns +.Dv NULL . +.Pp +The +.Fn nc_sperror +function +returns a pointer to a buffer which contains the error message string. +This buffer is overwritten on each call. +In multithreaded applications, this buffer is +implemented as thread-specific data. +.Sh FILES +.Bl -tag -width /etc/netconfig -compact +.It Pa /etc/netconfig +.El +.Sh SEE ALSO +.Xr getnetpath 3 , +.Xr netconfig 5 diff --git a/libtirpc/man/getnetpath.3t b/libtirpc/man/getnetpath.3t new file mode 100644 index 0000000..b3712ad --- /dev/null +++ b/libtirpc/man/getnetpath.3t @@ -0,0 +1,168 @@ +.\" @(#)getnetpath.3n 1.26 93/05/07 SMI; from SVr4 +.\" Copyright 1989 AT&T +.Dd April 22, 2000 +.Dt GETNETPATH 3 +.Os +.Sh NAME +.Nm getnetpath , +.Nm setnetpath , +.Nm endnetpath +.Nd get +.Pa /etc/netconfig +entry corresponding to +.Ev NETPATH +component +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In netconfig.h +.Ft "struct netconfig *" +.Fn getnetpath "void *handlep" +.Ft "void *" +.Fn setnetpath "void" +.Ft int +.Fn endnetpath "void *handlep" +.Sh DESCRIPTION +The routines described in this page provide the application access to the system +network configuration database, +.Pa /etc/netconfig , +as it is +.Dq filtered +by the +.Ev NETPATH +environment variable (see +.Xr environ 7 ) . +See +.Xr getnetconfig 3 +for other routines that also access the +network configuration database directly. +The +.Ev NETPATH +variable is a list of colon-separated network identifiers. +.Pp +The +.Fn getnetpath +function +returns a pointer to the +netconfig database entry corresponding to the first valid +.Ev NETPATH +component. +The netconfig entry is formatted as a +.Ft "struct netconfig" . +On each subsequent call, +.Fn getnetpath +returns a pointer to the netconfig entry that corresponds to the next +valid +.Ev NETPATH +component. +The +.Fn getnetpath +function +can thus be used to search the netconfig database for all networks +included in the +.Ev NETPATH +variable. +When +.Ev NETPATH +has been exhausted, +.Fn getnetpath +returns +.Dv NULL . +.Pp +A call to +.Fn setnetpath +.Dq binds +to or +.Dq rewinds +.Ev NETPATH . +The +.Fn setnetpath +function +must be called before the first call to +.Fn getnetpath +and may be called at any other time. +It returns a handle that is used by +.Fn getnetpath . +.Pp +The +.Fn getnetpath +function +silently ignores invalid +.Ev NETPATH +components. +A +.Ev NETPATH +component is invalid if there is no corresponding +entry in the netconfig database. +.Pp +If the +.Ev NETPATH +variable is unset, +.Fn getnetpath +behaves as if +.Ev NETPATH +were set to the sequence of +.Dq default +or +.Dq visible +networks in the netconfig database, in the +order in which they are listed. +.\"This proviso holds also for this +.\"whole manpage. +.Pp +The +.Fn endnetpath +function +may be called to +.Dq unbind +from +.Ev NETPATH +when processing is complete, releasing resources for reuse. +Programmers should be aware, however, that +.Fn endnetpath +frees all memory allocated by +.Fn getnetpath +for the struct netconfig data structure. +.Sh RETURN VALUES +The +.Fn setnetpath +function +returns a handle that is used by +.Fn getnetpath . +In case of an error, +.Fn setnetpath +returns +.Dv NULL . +.Pp +The +.Fn endnetpath +function +returns 0 on success and \-1 on failure +(for example, if +.Fn setnetpath +was not called previously). +The +.Fn nc_perror +or +.Fn nc_sperror +function +can be used to print out the reason for failure. +See +.Xr getnetconfig 3 . +.Pp +When first called, +.Fn getnetpath +returns a pointer to the netconfig database entry corresponding to the first +valid +.Ev NETPATH +component. +When +.Ev NETPATH +has been exhausted, +.Fn getnetpath +returns +.Dv NULL . +.Sh SEE ALSO +.Xr getnetconfig 3 , +.Xr netconfig 5 , +.Xr environ 7 diff --git a/libtirpc/man/getrpcent.3t b/libtirpc/man/getrpcent.3t new file mode 100644 index 0000000..261a8f4 --- /dev/null +++ b/libtirpc/man/getrpcent.3t @@ -0,0 +1,106 @@ +.\" @(#)getrpcent.3n 2.2 88/08/02 4.0 RPCSRC; from 1.11 88/03/14 SMI +.\" +.Dd December 14, 1987 +.Dt GETRPCENT 3 +.Os +.Sh NAME +.Nm getrpcent , +.Nm getrpcbyname , +.Nm getrpcbynumber , +.Nm endrpcent , +.Nm setrpcent +.Nd get RPC entry +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft struct rpcent * +.Fn getrpcent void +.Ft struct rpcent * +.Fn getrpcbyname "char *name" +.Ft struct rpcent * +.Fn getrpcbynumber "int number" +.Ft void +.Fn setrpcent "int stayopen" +.Ft void +.Fn endrpcent void +.Sh DESCRIPTION +The +.Fn getrpcent , +.Fn getrpcbyname , +and +.Fn getrpcbynumber +functions +each return a pointer to an object with the +following structure +containing the broken-out +fields of a line in the rpc program number data base, +.Pa /etc/rpc : +.Bd -literal +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + long r_number; /* rpc program number */ +}; +.Ed +.Pp +The members of this structure are: +.Bl -tag -width r_aliases -offset indent +.It Va r_name +The name of the server for this rpc program. +.It Va r_aliases +A zero terminated list of alternate names for the rpc program. +.It Va r_number +The rpc program number for this service. +.El +.Pp +The +.Fn getrpcent +function +reads the next line of the file, opening the file if necessary. +.Pp +The +.Fn setrpcent +function +opens and rewinds the file. If the +.Fa stayopen +flag is non-zero, +the net data base will not be closed after each call to +.Fn getrpcent +(either directly, or indirectly through one of +the other +.Dq getrpc +calls). +.Pp +The +.Fn endrpcent +function +closes the file. +.Pp +The +.Fn getrpcbyname +and +.Fn getrpcbynumber +functions +sequentially search from the beginning +of the file until a matching rpc program name or +program number is found, or until end-of-file is encountered. +.Sh FILES +.Bl -tag -width /etc/rpc -compact +.It Pa /etc/rpc +.El +.Sh SEE ALSO +.Xr rpc 5 , +.Xr rpcinfo 8 , +.Xr ypserv 8 +.Sh DIAGNOSTICS +A +.Dv NULL +pointer is returned on +.Dv EOF +or error. +.Sh BUGS +All information +is contained in a static area +so it must be copied if it is +to be saved. diff --git a/libtirpc/man/getrpcport.3t b/libtirpc/man/getrpcport.3t new file mode 100644 index 0000000..8a072c7 --- /dev/null +++ b/libtirpc/man/getrpcport.3t @@ -0,0 +1,34 @@ +.\" @(#)getrpcport.3r 2.2 88/08/02 4.0 RPCSRC; from 1.12 88/02/26 SMI +.\" +.Dd October 6, 1987 +.Dt GETRPCPORT 3 +.Os +.Sh NAME +.Nm getrpcport +.Nd get RPC port number +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Ft int +.Fn getrpcport "char *host" "int prognum" "int versnum" "int proto" +.Sh DESCRIPTION +The +.Fn getrpcport +function +returns the port number for version +.Fa versnum +of the RPC program +.Fa prognum +running on +.Fa host +and using protocol +.Fa proto . +It returns 0 if it cannot contact the portmapper, or if +.Fa prognum +is not registered. If +.Fa prognum +is registered but not with version +.Fa versnum , +it will still return a port number (for some version of the program) +indicating that the program is indeed registered. +The version mismatch will be detected upon the first call to the service. diff --git a/libtirpc/man/netconfig.5 b/libtirpc/man/netconfig.5 new file mode 100644 index 0000000..e8dcbb2 --- /dev/null +++ b/libtirpc/man/netconfig.5 @@ -0,0 +1,123 @@ +.Dd November 17, 2000 +.Dt NETCONFIG 5 +.Os +.Sh NAME +.Nm netconfig +.Nd network configuration data base +.Sh SYNOPSIS +.Pa /etc/netconfig +.Sh DESCRIPTION +The +.Nm +file defines a list of +.Dq transport names , +describing their semantics and protocol. +In +.Fx , +this file is only used by the RPC library code. +.Pp +Entries have the following format: +.Pp +.Ar network_id semantics flags family protoname device libraries +.Pp +Entries consist of the following fields: +.Bl -tag -width network_id +.It Ar network_id +The name of the transport described. +.It Ar semantics +Describes the semantics of the transport. +This can be one of: +.Bl -tag -width tpi_cots_ord -offset indent +.It Sy tpi_clts +Connectionless transport. +.It Sy tpi_cots +Connection-oriented transport +.It Sy tpi_cots_ord +Connection-oriented, ordered transport. +.It Sy tpi_raw +A raw connection. +.El +.It Ar flags +This field is either blank (specified by +.Dq Li - ) , +or contains a +.Dq Li v , +meaning visible to the +.Xr getnetconfig 3 +function. +.It Ar family +The protocol family of the transport. +This is currently one of: +.Bl -tag -width loopback -offset indent +.It Sy inet6 +The IPv6 +.Pq Dv PF_INET6 +family of protocols. +.It Sy inet +The IPv4 +.Pq Dv PF_INET +family of protocols. +.It Sy loopback +The +.Dv PF_LOCAL +protocol family. +.El +.It Ar protoname +The name of the protocol used for this transport. +Can currently be either +.Sy udp , +.Sy tcp +or empty. +.It Ar device +This field is always empty in +.Fx . +.It Ar libraries +This field is always empty in +.Fx . +.El +.Pp +The order of entries in this file will determine which transport will +be preferred by the RPC library code, given a match on a specified +network type. +For example, if a sample network config file would look like this: +.Bd -literal -offset indent +udp6 tpi_clts v inet6 udp - - +tcp6 tpi_cots_ord v inet6 tcp - - +udp tpi_clts v inet udp - - +tcp tpi_cots_ord v inet tcp - - +rawip tpi_raw - inet - - - +local tpi_cots_ord - loopback - - - +.Ed +.Pp +then using the network type +.Sy udp +in calls to the RPC library function (see +.Xr rpc 3 ) +will make the code first try +.Sy udp6 , +and then +.Sy udp . +.Pp +.Xr getnetconfig 3 +and associated functions will parse this file and return structures of +the following format: +.Bd -literal +struct netconfig { + char *nc_netid; /* Network ID */ + unsigned long nc_semantics; /* Semantics (see below) */ + unsigned long nc_flag; /* Flags (see below) */ + char *nc_protofmly; /* Protocol family */ + char *nc_proto; /* Protocol name */ + char *nc_device; /* Network device pathname (unused) */ + unsigned long nc_nlookups; /* Number of lookup libs (unused) */ + char **nc_lookups; /* Names of the libraries (unused) */ + unsigned long nc_unused[9]; /* reserved */ +}; +.Ed +.Sh FILES +.Bl -tag -width /etc/netconfig -compact +.It Pa /etc/netconfig +.El +.Sh SEE ALSO +.Xr getnetconfig 3 , +.Xr getnetpath 3 diff --git a/libtirpc/man/publickey.3t b/libtirpc/man/publickey.3t new file mode 100644 index 0000000..0d4b13f --- /dev/null +++ b/libtirpc/man/publickey.3t @@ -0,0 +1,52 @@ +.\" @(#)publickey.3r 2.1 88/08/07 4.0 RPCSRC +.\" +.Dd October 6, 1987 +.Dt PUBLICKEY 3 +.Os +.Sh NAME +.Nm publickey , getpublickey , getsecretkey +.Nd "get public or secret key" +.Sh LIBRARY +.Lb librpcsvc +.Sh SYNOPSIS +.In rpc/rpc.h +.In rpc/key_prot.h +.Ft int +.Fo getpublickey +.Fa "char netname[MAXNETNAMELEN+1]" +.Fa "char publickey[HEXKEYBYTES+1]" +.Fc +.Ft int +.Fo getsecretkey +.Fa "char netname[MAXNETNAMELEN+1]" +.Fa "char secretkey[HEXKEYBYTES+1]" +.Fa "char *passwd" +.Fc +.Sh DESCRIPTION +These routines are used to get public and secret keys from the +.Tn YP +database. +The +.Fn getsecretkey +function +has an extra argument, +.Fa passwd , +which is used to decrypt the encrypted secret key stored in the database. +Both routines return 1 if they are successful in finding the key, 0 otherwise. +The keys are returned as +.Dv NULL Ns \-terminated , +hexadecimal strings. +If the password supplied to +.Fn getsecretkey +fails to decrypt the secret key, the routine will return 1 but the +.Fa secretkey +argument will be a +.Dv NULL +string +.Pq Dq . +.Sh SEE ALSO +.Xr publickey 5 +.Pp +.%T "RPC Programmer's Manual" +in +.Pa /usr/share/doc/psd/23.rpc . diff --git a/libtirpc/man/publickey.5 b/libtirpc/man/publickey.5 new file mode 100644 index 0000000..e0a03f7 --- /dev/null +++ b/libtirpc/man/publickey.5 @@ -0,0 +1,41 @@ +.\" @(#)publickey.5 2.1 88/08/07 4.0 RPCSRC; from 1.6 88/02/29 SMI; +.Dd October 19, 1987 +.Dt PUBLICKEY 5 +.Os +.Sh NAME +.Nm publickey +.Nd "public key database" +.Sh SYNOPSIS +.Pa /etc/publickey +.Sh DESCRIPTION +.Pa /etc/publickey +is the public key database used for secure +RPC (Remote Procedure Calls). +Each entry in +the database consists of a network user +name (which may either refer to +a user or a hostname), followed by the user's +public key (in hex +notation), a colon, and then the user's +secret key encrypted with +its login password (also in hex notation). +.Pp +This file is altered either by the user through the +.Xr chkey 1 +command or by the system administrator through the +.Xr newkey 8 +command. +The file +.Pa /etc/publickey +should only contain data on the +.Tn NIS +master machine, where it +is converted into the +.Tn NIS +database +.Pa publickey.byname . +.Sh SEE ALSO +.Xr chkey 1 , +.Xr publickey 3 , +.Xr newkey 8 , +.Xr ypupdated 8 diff --git a/libtirpc/man/rpc.3t b/libtirpc/man/rpc.3t new file mode 100644 index 0000000..b2927b1 --- /dev/null +++ b/libtirpc/man/rpc.3t @@ -0,0 +1,515 @@ +.\" @(#)rpc.3n 1.31 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.Dd May 7, 1993 +.Dt RPC 3 +.Os +.Sh NAME +.Nm rpc +.Nd library routines for remote procedure calls +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.In netconfig.h +.Sh DESCRIPTION +These +routines allow C language programs to make procedure +calls on other machines across a network. +First, the client sends a request to the server. +On receipt of the request, the server calls a dispatch routine +to perform the requested service, and then sends back a reply. +.Pp +All +RPC routines require the header +.In rpc/rpc.h . +Routines that take a +.Vt "struct netconfig" +also require that +.In netconfig.h +be included. +.Sh Nettype +Some of the high-level +RPC interface routines take a +.Fa nettype +string as one of the arguments +(for example, +.Fn clnt_create , +.Fn svc_create , +.Fn rpc_reg , +.Fn rpc_call ) . +This string defines a class of transports which can be used +for a particular application. +.Pp +The +.Fa nettype +argument +can be one of the following: +.Bl -tag -width datagram_v +.It netpath +Choose from the transports which have been +indicated by their token names in the +.Ev NETPATH +environment variable. +.Ev NETPATH +is unset or +.Dv NULL , +it defaults to +.Qq visible . +.Qq netpath +is the default +.Fa nettype . +.It visible +Choose the transports which have the visible flag (v) +set in the +.Pa /etc/netconfig +file. +.It circuit_v +This is same as +.Qq visible +except that it chooses only the connection oriented transports +(semantics +.Qq tpi_cots +or +.Qq tpi_cots_ord ) +from the entries in the +.Pa /etc/netconfig +file. +.It datagram_v +This is same as +.Qq visible +except that it chooses only the connectionless datagram transports +(semantics +.Qq tpi_clts ) +from the entries in the +.Pa /etc/netconfig +file. +.It circuit_n +This is same as +.Qq netpath +except that it chooses only the connection oriented datagram transports +(semantics +.Qq tpi_cots +or +.Qq tpi_cots_ord ) . +.It datagram_n +This is same as +.Qq netpath +except that it chooses only the connectionless datagram transports +(semantics +.Qq tpi_clts ) . +.It udp +This refers to Internet UDP, both version 4 and 6. +.It tcp +This refers to Internet TCP, both version 4 and 6. +.El +.Pp +If +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +The transports are tried in left to right order in the +.Ev NETPATH +variable or in top to down order in the +.Pa /etc/netconfig +file. +.Sh Derived Types +The derived types used in the RPC interfaces are defined as follows: +.Bd -literal + typedef u_int32_t rpcprog_t; + typedef u_int32_t rpcvers_t; + typedef u_int32_t rpcproc_t; + typedef u_int32_t rpcprot_t; + typedef u_int32_t rpcport_t; + typedef int32_t rpc_inline_t; +.Ed +.Sh "Data Structures" +Some of the data structures used by the +RPC package are shown below. +.Sh "The AUTH Structure" +.Bd -literal +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + u_int oa_length; /* not to exceed MAX_AUTH_BYTES */ +}; + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + struct auth_ops { + void (*ah_nextverf)(\|); + int (*ah_marshal)(\|); /* nextverf & serialize */ + int (*ah_validate)(\|); /* validate verifier */ + int (*ah_refresh)(\|); /* refresh credentials */ + void (*ah_destroy)(\|); /* destroy this structure */ + } *ah_ops; + caddr_t ah_private; +} AUTH; +.Ed +.Sh "The CLIENT Structure" +.Bd -literal +/* + * Client rpc handle. + * Created by individual implementations. + * Client is responsible for initializing auth. + */ + +typedef struct { + AUTH *cl_auth; /* authenticator */ + struct clnt_ops { + enum clnt_stat (*cl_call)(); /* call remote procedure */ + void (*cl_abort)(); /* abort a call */ + void (*cl_geterr)(); /* get specific error code */ + bool_t (*cl_freeres)(); /* frees results */ + void (*cl_destroy)(); /* destroy this structure */ + bool_t (*cl_control)(); /* the ioctl() of rpc */ + } *cl_ops; + caddr_t cl_private; /* private stuff */ + char *cl_netid; /* network identifier */ + char *cl_tp; /* device name */ +} CLIENT; +.Ed +.Sh "The SVCXPRT structure" +.Bd -literal +enum xprt_stat { + XPRT_DIED, + XPRT_MOREREQS, + XPRT_IDLE +}; + +/* + * Server side transport handle + */ +typedef struct { + int xp_fd; /* file descriptor for the server handle */ + u_short xp_port; /* obsolete */ + const struct xp_ops { + bool_t (*xp_recv)(); /* receive incoming requests */ + enum xprt_stat (*xp_stat)(); /* get transport status */ + bool_t (*xp_getargs)(); /* get arguments */ + bool_t (*xp_reply)(); /* send reply */ + bool_t (*xp_freeargs)(); /* free mem allocated for args */ + void (*xp_destroy)(); /* destroy this struct */ + } *xp_ops; + int xp_addrlen; /* length of remote addr. Obsolete */ + struct sockaddr_in xp_raddr; /* Obsolete */ + const struct xp_ops2 { + bool_t (*xp_control)(); /* catch-all function */ + } *xp_ops2; + char *xp_tp; /* transport provider device name */ + char *xp_netid; /* network identifier */ + struct netbuf xp_ltaddr; /* local transport address */ + struct netbuf xp_rtaddr; /* remote transport address */ + struct opaque_auth xp_verf; /* raw response verifier */ + caddr_t xp_p1; /* private: for use by svc ops */ + caddr_t xp_p2; /* private: for use by svc ops */ + caddr_t xp_p3; /* private: for use by svc lib */ + int xp_type /* transport type */ +} SVCXPRT; +.Ed +.Sh "The svc_reg structure" +.Bd -literal +struct svc_req { + rpcprog_t rq_prog; /* service program number */ + rpcvers_t rq_vers; /* service protocol version */ + rpcproc_t rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked cred */ + SVCXPRT *rq_xprt; /* associated transport */ +}; +.Ed +.Sh "The XDR structure" +.Bd -literal +/* + * XDR operations. + * XDR_ENCODE causes the type to be encoded into the stream. + * XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { + XDR_ENCODE=0, + XDR_DECODE=1, + XDR_FREE=2 +}; +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT (4) +#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / + BYTES_PER_XDR_UNIT) \e * BYTES_PER_XDR_UNIT) + +/* + * A xdrproc_t exists for each data type which is to be encoded or + * decoded. The second argument to the xdrproc_t is a pointer to + * an opaque pointer. The opaque pointer generally points to a + * structure of the data type to be decoded. If this points to 0, + * then the type routines should allocate dynamic storage of the + * appropriate size and return it. + * bool_t (*xdrproc_t)(XDR *, caddr_t *); + */ +typedef bool_t (*xdrproc_t)(); + +/* + * The XDR handle. + * Contains operation which is being applied to the stream, + * an operations vector for the particular implementation + */ +typedef struct { + enum xdr_op x_op; /* operation; fast additional param */ + struct xdr_ops { + bool_t (*x_getlong)(); /* get a long from underlying stream */ + bool_t (*x_putlong)(); /* put a long to underlying stream */ + bool_t (*x_getbytes)(); /* get bytes from underlying stream */ + bool_t (*x_putbytes)(); /* put bytes to underlying stream */ + u_int (*x_getpostn)(); /* returns bytes off from beginning */ + bool_t (*x_setpostn)(); /* lets you reposition the stream */ + long * (*x_inline)(); /* buf quick ptr to buffered data */ + void (*x_destroy)(); /* free privates of this xdr_stream */ + } *x_ops; + caddr_t x_public; /* users' data */ + caddr_t x_private; /* pointer to private data */ + caddr_t x_base; /* private used for position info */ + u_int x_handy; /* extra private word */ +} XDR; + +/* + * The netbuf structure. This structure is defined in on SysV + * systems, but NetBSD / FreeBSD do not use XTI. + * + * Usually, buf will point to a struct sockaddr, and len and maxlen + * will contain the length and maximum length of that socket address, + * respectively. + */ +struct netbuf { + unsigned int maxlen; + unsigned int len; + void *buf; +}; + +/* + * The format of the address and options arguments of the XTI t_bind call. + * Only provided for compatibility, it should not be used other than + * as an argument to svc_tli_create(). + */ + +struct t_bind { + struct netbuf addr; + unsigned int qlen; +}; +.Ed +.Sh "Index to Routines" +The following table lists RPC routines and the manual reference +pages on which they are described: +.Pp +.Bl -tag -width "authunix_create_default()" -compact +.It Em "RPC Routine" +.Em "Manual Reference Page" +.Pp +.It Fn auth_destroy +.Xr rpc_clnt_auth 3 +.It Fn authdes_create +.Xr rpc_soc 3 +.It Fn authnone_create +.Xr rpc_clnt_auth 3 +.It Fn authsys_create +.Xr rpc_clnt_auth 3 +.It Fn authsys_create_default +.Xr rpc_clnt_auth 3 +.It Fn authunix_create +.Xr rpc_soc 3 +.It Fn authunix_create_default +.Xr rpc_soc 3 +.It Fn callrpc +.Xr rpc_soc 3 +.It Fn clnt_broadcast +.Xr rpc_soc 3 +.It Fn clnt_call +.Xr rpc_clnt_calls 3 +.It Fn clnt_control +.Xr rpc_clnt_create 3 +.It Fn clnt_create +.Xr rpc_clnt_create 3 +.It Fn clnt_create_timed +.Xr rpc_clnt_create 3 +.It Fn clnt_create_vers +.Xr rpc_clnt_create 3 +.It Fn clnt_create_vers_timed +.Xr rpc_clnt_create 3 +.It Fn clnt_destroy +.Xr rpc_clnt_create 3 +.It Fn clnt_dg_create +.Xr rpc_clnt_create 3 +.It Fn clnt_freeres +.Xr rpc_clnt_calls 3 +.It Fn clnt_geterr +.Xr rpc_clnt_calls 3 +.It Fn clnt_pcreateerror +.Xr rpc_clnt_create 3 +.It Fn clnt_perrno +.Xr rpc_clnt_calls 3 +.It Fn clnt_perror +.Xr rpc_clnt_calls 3 +.It Fn clnt_raw_create +.Xr rpc_clnt_create 3 +.It Fn clnt_spcreateerror +.Xr rpc_clnt_create 3 +.It Fn clnt_sperrno +.Xr rpc_clnt_calls 3 +.It Fn clnt_sperror +.Xr rpc_clnt_calls 3 +.It Fn clnt_tli_create +.Xr rpc_clnt_create 3 +.It Fn clnt_tp_create +.Xr rpc_clnt_create 3 +.It Fn clnt_tp_create_timed +.Xr rpc_clnt_create 3 +.It Fn clnt_udpcreate +.Xr rpc_soc 3 +.It Fn clnt_vc_create +.Xr rpc_clnt_create 3 +.It Fn clntraw_create +.Xr rpc_soc 3 +.It Fn clnttcp_create +.Xr rpc_soc 3 +.It Fn clntudp_bufcreate +.Xr rpc_soc 3 +.It Fn get_myaddress +.Xr rpc_soc 3 +.It Fn pmap_getmaps +.Xr rpc_soc 3 +.It Fn pmap_getport +.Xr rpc_soc 3 +.It Fn pmap_rmtcall +.Xr rpc_soc 3 +.It Fn pmap_set +.Xr rpc_soc 3 +.It Fn pmap_unset +.Xr rpc_soc 3 +.It Fn registerrpc +.Xr rpc_soc 3 +.It Fn rpc_broadcast +.Xr rpc_clnt_calls 3 +.It Fn rpc_broadcast_exp +.Xr rpc_clnt_calls 3 +.It Fn rpc_call +.Xr rpc_clnt_calls 3 +.It Fn rpc_reg +.Xr rpc_svc_calls 3 +.It Fn svc_create +.Xr rpc_svc_create 3 +.It Fn svc_destroy +.Xr rpc_svc_create 3 +.It Fn svc_dg_create +.Xr rpc_svc_create 3 +.It Fn svc_dg_enablecache +.Xr rpc_svc_calls 3 +.It Fn svc_fd_create +.Xr rpc_svc_create 3 +.It Fn svc_fds +.Xr rpc_soc 3 +.It Fn svc_freeargs +.Xr rpc_svc_reg 3 +.It Fn svc_getargs +.Xr rpc_svc_reg 3 +.It Fn svc_getcaller +.Xr rpc_soc 3 +.It Fn svc_getreq +.Xr rpc_soc 3 +.It Fn svc_getreqset +.Xr rpc_svc_calls 3 +.It Fn svc_getrpccaller +.Xr rpc_svc_calls 3 +.It Fn svc_kerb_reg +.Xr kerberos_rpc 3 +.It Fn svc_raw_create +.Xr rpc_svc_create 3 +.It Fn svc_reg +.Xr rpc_svc_calls 3 +.It Fn svc_register +.Xr rpc_soc 3 +.It Fn svc_run +.Xr rpc_svc_reg 3 +.It Fn svc_sendreply +.Xr rpc_svc_reg 3 +.It Fn svc_tli_create +.Xr rpc_svc_create 3 +.It Fn svc_tp_create +.Xr rpc_svc_create 3 +.It Fn svc_unreg +.Xr rpc_svc_calls 3 +.It Fn svc_unregister +.Xr rpc_soc 3 +.It Fn svc_vc_create +.Xr rpc_svc_create 3 +.It Fn svcerr_auth +.Xr rpc_svc_err 3 +.It Fn svcerr_decode +.Xr rpc_svc_err 3 +.It Fn svcerr_noproc +.Xr rpc_svc_err 3 +.It Fn svcerr_noprog +.Xr rpc_svc_err 3 +.It Fn svcerr_progvers +.Xr rpc_svc_err 3 +.It Fn svcerr_systemerr +.Xr rpc_svc_err 3 +.It Fn svcerr_weakauth +.Xr rpc_svc_err 3 +.It Fn svcfd_create +.Xr rpc_soc 3 +.It Fn svcraw_create +.Xr rpc_soc 3 +.It Fn svctcp_create +.Xr rpc_soc 3 +.It Fn svcudp_bufcreate +.Xr rpc_soc 3 +.It Fn svcudp_create +.Xr rpc_soc 3 +.It Fn xdr_accepted_reply +.Xr rpc_xdr 3 +.It Fn xdr_authsys_parms +.Xr rpc_xdr 3 +.It Fn xdr_authunix_parms +.Xr rpc_soc 3 +.It Fn xdr_callhdr +.Xr rpc_xdr 3 +.It Fn xdr_callmsg +.Xr rpc_xdr 3 +.It Fn xdr_opaque_auth +.Xr rpc_xdr 3 +.It Fn xdr_rejected_reply +.Xr rpc_xdr 3 +.It Fn xdr_replymsg +.Xr rpc_xdr 3 +.It Fn xprt_register +.Xr rpc_svc_calls 3 +.It Fn xprt_unregister +.Xr rpc_svc_calls 3 +.El +.Sh FILES +.Bl -tag -width /etc/netconfig +.It Pa /etc/netconfig +.El +.Sh SEE ALSO +.Xr getnetconfig 3 , +.Xr getnetpath 3 , +.Xr rpcbind 3 , +.Xr rpc_clnt_auth 3 , +.Xr rpc_clnt_calls 3 , +.Xr rpc_clnt_create 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 , +.Xr rpc_xdr 3 , +.Xr xdr 3 , +.Xr netconfig 5 diff --git a/libtirpc/man/rpc.5 b/libtirpc/man/rpc.5 new file mode 100644 index 0000000..385c637 --- /dev/null +++ b/libtirpc/man/rpc.5 @@ -0,0 +1,57 @@ +.\" @(#)rpc.4 1.17 93/08/30 SMI; from SVr4 +.\" Copyright 1989 AT&T +.Dd December 10, 1991 +.Dt RPC 5 +.Os +.Sh NAME +.Nm rpc +.Nd rpc program number data base +.Sh SYNOPSIS +.Pa /etc/rpc +.Sh DESCRIPTION +The +.Nm +file contains user readable names that +can be used in place of RPC program numbers. +For each RPC program a single line should be present +with the following information: +.Pp +.Bl -enum -compact +.It +name of the RPC program +.It +RPC program number +.It +aliases +.El +.Pp +Items are separated by any number of blanks and/or +tab characters. +A hash +.Pq Dq Li # +indicates the beginning of a comment; characters up to the end of +the line are not interpreted by routines which search the file. +.Sh EXAMPLES +Below is an example of an RPC database: +.Bd -literal +# +# rpc +# +rpcbind 100000 portmap sunrpc portmapper +rusersd 100002 rusers +nfs 100003 nfsprog +mountd 100005 mount showmount +walld 100008 rwall shutdown +sprayd 100012 spray +llockmgr 100020 +nlockmgr 100021 +status 100024 +bootparam 100026 +keyserv 100029 keyserver +.Ed +.Sh FILES +.Bl -tag -width /etc/nsswitch.conf -compact +.It Pa /etc/nsswitch.conf +.El +.Sh SEE ALSO +.Xr getrpcent 3 diff --git a/libtirpc/man/rpc_clnt_auth.3t b/libtirpc/man/rpc_clnt_auth.3t new file mode 100644 index 0000000..ee8fd1d --- /dev/null +++ b/libtirpc/man/rpc_clnt_auth.3t @@ -0,0 +1,96 @@ +.\" @(#)rpc_clnt_auth.3n 1.21 93/05/07 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_clnt_auth 1.4 89/07/20 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_clnt_auth.3,v 1.1 2000/06/03 09:29:50 fvdl Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpc_clnt_auth.3,v 1.5 2002/12/19 09:40:23 ru Exp $ +.Dd May 7, 1993 +.Dt RPC_CLNT_AUTH 3 +.Os +.Sh NAME +.Nm auth_destroy , +.Nm authnone_create , +.Nm authsys_create , +.Nm authsys_create_default +.Nd library routines for client side remote procedure call authentication +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft "void" +.Fn auth_destroy "AUTH *auth" +.Ft "AUTH *" +.Fn authnone_create "void" +.Ft "AUTH *" +.Fn authsys_create "const char *host" "const uid_t uid" "const gid_t gid" "const int len" "const gid_t *aup_gids" +.Ft "AUTH *" +.Fn authsys_create_default "void" +.Sh DESCRIPTION +These routines are part of the +RPC library that allows C language programs to make procedure +calls on other machines across the network, +with desired authentication. +.Pp +These routines are normally called after creating the +.Vt CLIENT +handle. +The +.Va cl_auth +field of the +.Vt CLIENT +structure should be initialized by the +.Vt AUTH +structure returned by some of the following routines. +The client's authentication information +is passed to the server when the +RPC +call is made. +.Pp +Only the +.Dv NULL +and the +.Dv SYS +style of authentication is discussed here. +.Sh Routines +.Bl -tag -width authsys_create_default() +.It Fn auth_destroy +A function macro that destroys the authentication +information associated with +.Fa auth . +Destruction usually involves deallocation +of private data structures. +The use of +.Fa auth +is undefined after calling +.Fn auth_destroy . +.It Fn authnone_create +Create and return an RPC +authentication handle that passes nonusable +authentication information with each remote procedure call. +This is the default authentication used by RPC. +.It Fn authsys_create +Create and return an RPC authentication handle that contains +.Dv AUTH_SYS +authentication information. +The +.Fa host +argument +is the name of the machine on which the information was +created; +.Fa uid +is the user's user ID; +.Fa gid +is the user's current group ID; +.Fa len +and +.Fa aup_gids +refer to a counted array of groups to which the user belongs. +.It Fn authsys_create_default +Call +.Fn authsys_create +with the appropriate arguments. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_clnt_calls 3 , +.Xr rpc_clnt_create 3 diff --git a/libtirpc/man/rpc_clnt_calls.3t b/libtirpc/man/rpc_clnt_calls.3t new file mode 100644 index 0000000..38b29d5 --- /dev/null +++ b/libtirpc/man/rpc_clnt_calls.3t @@ -0,0 +1,316 @@ +.\" @(#)rpc_clnt_calls.3n 1.30 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_clnt_calls 1.4 89/07/20 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD: src/lib/libc/rpc/rpc_clnt_calls.3,v 1.7 2002/12/19 09:40:23 ru Exp $ +.Dd May 7, 1993 +.Dt RPC_CLNT_CALLS 3 +.Os +.Sh NAME +.Nm rpc_clnt_calls , +.Nm clnt_call , +.Nm clnt_freeres , +.Nm clnt_geterr , +.Nm clnt_perrno , +.Nm clnt_perror , +.Nm clnt_sperrno , +.Nm clnt_sperror , +.Nm rpc_broadcast , +.Nm rpc_broadcast_exp , +.Nm rpc_call +.Nd library routines for client side calls +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft "enum clnt_stat" +.Fn clnt_call "CLIENT *clnt" "const rpcproc_t procnum" "const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "caddr_t out" "const struct timeval tout" +.Ft bool_t +.Fn clnt_freeres "CLIENT *clnt" "const xdrproc_t outproc" "caddr_t out" +.Ft void +.Fn clnt_geterr "const CLIENT * clnt" "struct rpc_err * errp" +.Ft void +.Fn clnt_perrno "const enum clnt_stat stat" +.Ft void +.Fn clnt_perror "CLIENT *clnt" "const char *s" +.Ft "char *" +.Fn clnt_sperrno "const enum clnt_stat stat" +.Ft "char *" +.Fn clnt_sperror "CLIENT *clnt" "const char * s" +.Ft "enum clnt_stat" +.Fo rpc_broadcast +.Fa "const rpcprog_t prognum" "const rpcvers_t versnum" +.Fa "const rpcproc_t procnum" "const xdrproc_t inproc" +.Fa "const caddr_t in" "const xdrproc_t outproc" "caddr_t out" +.Fa "const resultproc_t eachresult" "const char *nettype" +.Fc +.Ft "enum clnt_stat" +.Fo rpc_broadcast_exp +.Fa "const rpcprog_t prognum" "const rpcvers_t versnum" +.Fa "const rpcproc_t procnum" "const xdrproc_t xargs" +.Fa "caddr_t argsp" "const xdrproc_t xresults" +.Fa "caddr_t resultsp" "const resultproc_t eachresult" +.Fa "const int inittime" "const int waittime" +.Fa "const char * nettype" +.Fc +.Ft "enum clnt_stat" +.Fo rpc_call +.Fa "const char *host" "const rpcprog_t prognum" +.Fa "const rpcvers_t versnum" "const rpcproc_t procnum" +.Fa "const xdrproc_t inproc" "const char *in" +.Fa "const xdrproc_t outproc" "char *out" "const char *nettype" +.Fc +.Sh DESCRIPTION +RPC library routines allow C language programs to make procedure +calls on other machines across the network. +First, the client calls a procedure to send a request to the server. +Upon receipt of the request, the server calls a dispatch routine +to perform the requested service, and then sends back a reply. +.Pp +The +.Fn clnt_call , +.Fn rpc_call , +and +.Fn rpc_broadcast +routines handle the client side of the procedure call. +The remaining routines deal with error handling in the case of errors. +.Pp +Some of the routines take a +.Vt CLIENT +handle as one of the arguments. +A +.Vt CLIENT +handle can be created by an RPC creation routine such as +.Fn clnt_create +(see +.Xr rpc_clnt_create 3 ) . +.Pp +These routines are safe for use in multithreaded applications. +.Vt CLIENT +handles can be shared between threads, however in this implementation +requests by different threads are serialized (that is, the first request will +receive its results before the second request is sent). +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt CLIENT +data structure. +.Bl -tag -width XXXXX +.It Fn clnt_call +A function macro that calls the remote procedure +.Fa procnum +associated with the client handle, +.Fa clnt , +which is obtained with an RPC +client creation routine such as +.Fn clnt_create +(see +.Xr rpc_clnt_create 3 ) . +The +.Fa inproc +argument +is the XDR function used to encode the procedure's arguments, and +.Fa outproc +is the XDR function used to decode the procedure's results; +.Fa in +is the address of the procedure's argument(s), and +.Fa out +is the address of where to place the result(s). +The +.Fa tout +argument +is the time allowed for results to be returned, which is overridden by +a time-out set explicitly through +.Fn clnt_control , +see +.Xr rpc_clnt_create 3 . +If the remote call succeeds, the status returned is +.Dv RPC_SUCCESS , +otherwise an appropriate status is returned. +.It Fn clnt_freeres +A function macro that frees any data allocated by the +RPC/XDR system when it decoded the results of an RPC call. +The +.Fa out +argument +is the address of the results, and +.Fa outproc +is the XDR routine describing the results. +This routine returns 1 if the results were successfully freed, +and 0 otherwise. +.It Fn clnt_geterr +A function macro that copies the error structure out of the client +handle to the structure at address +.Fa errp . +.It Fn clnt_perrno +Print a message to standard error corresponding +to the condition indicated by +.Fa stat . +A newline is appended. +Normally used after a procedure call fails for a routine +for which a client handle is not needed, for instance +.Fn rpc_call . +.It Fn clnt_perror +Print a message to the standard error indicating why an +RPC call failed; +.Fa clnt +is the handle used to do the call. +The message is prepended with string +.Fa s +and a colon. +A newline is appended. +Normally used after a remote procedure call fails +for a routine which requires a client handle, +for instance +.Fn clnt_call . +.It Fn clnt_sperrno +Take the same arguments as +.Fn clnt_perrno , +but instead of sending a message to the standard error +indicating why an RPC +call failed, return a pointer to a string which contains the message. +The +.Fn clnt_sperrno +function +is normally used instead of +.Fn clnt_perrno +when the program does not have a standard error (as a program +running as a server quite likely does not), or if the programmer +does not want the message to be output with +.Fn printf +(see +.Xr printf 3 ) , +or if a message format different than that supported by +.Fn clnt_perrno +is to be used. +Note: +unlike +.Fn clnt_sperror +and +.Fn clnt_spcreateerror +(see +.Xr rpc_clnt_create 3 ) , +.Fn clnt_sperrno +does not return pointer to static data so the +result will not get overwritten on each call. +.It Fn clnt_sperror +Like +.Fn clnt_perror , +except that (like +.Fn clnt_sperrno ) +it returns a string instead of printing to standard error. +However, +.Fn clnt_sperror +does not append a newline at the end of the message. +Warning: +returns pointer to a buffer that is overwritten +on each call. +.It Fn rpc_broadcast +Like +.Fn rpc_call , +except the call message is broadcast to +all the connectionless transports specified by +.Fa nettype . +If +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +Each time it receives a response, +this routine calls +.Fn eachresult , +whose form is: +.Ft bool_t +.Fn eachresult "caddr_t out" "const struct netbuf * addr" "const struct netconfig * netconf" +where +.Fa out +is the same as +.Fa out +passed to +.Fn rpc_broadcast , +except that the remote procedure's output is decoded there; +.Fa addr +points to the address of the machine that sent the results, and +.Fa netconf +is the netconfig structure of the transport on which the remote +server responded. +If +.Fn eachresult +returns 0, +.Fn rpc_broadcast +waits for more replies; +otherwise it returns with appropriate status. +Warning: +broadcast file descriptors are limited in size to the +maximum transfer size of that transport. +For Ethernet, this value is 1500 bytes. +The +.Fn rpc_broadcast +function +uses +.Dv AUTH_SYS +credentials by default (see +.Xr rpc_clnt_auth 3 ) . +.It Fn rpc_broadcast_exp +Like +.Fn rpc_broadcast , +except that the initial timeout, +.Fa inittime +and the maximum timeout, +.Fa waittime +are specified in milliseconds. +The +.Fa inittime +argument +is the initial time that +.Fn rpc_broadcast_exp +waits before resending the request. +After the first resend, the re-transmission interval +increases exponentially until it exceeds +.Fa waittime . +.It Fn rpc_call +Call the remote procedure associated with +.Fa prognum , +.Fa versnum , +and +.Fa procnum +on the machine, +.Fa host . +The +.Fa inproc +argument +is used to encode the procedure's arguments, and +.Fa outproc +is used to decode the procedure's results; +.Fa in +is the address of the procedure's argument(s), and +.Fa out +is the address of where to place the result(s). +The +.Fa nettype +argument +can be any of the values listed on +.Xr rpc 3 . +This routine returns +.Dv RPC_SUCCESS +if it succeeds, +or an appropriate status is returned. +Use the +.Fn clnt_perrno +routine to translate failure status into error messages. +Warning: +.Fn rpc_call +uses the first available transport belonging +to the class +.Fa nettype , +on which it can create a connection. +You do not have control of timeouts or authentication +using this routine. +.El +.Sh SEE ALSO +.Xr printf 3 , +.Xr rpc 3 , +.Xr rpc_clnt_auth 3 , +.Xr rpc_clnt_create 3 diff --git a/libtirpc/man/rpc_clnt_create.3t b/libtirpc/man/rpc_clnt_create.3t new file mode 100644 index 0000000..acdbab4 --- /dev/null +++ b/libtirpc/man/rpc_clnt_create.3t @@ -0,0 +1,514 @@ +.\" @(#)rpc_clnt_create.3n 1.36 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_clnt_create 1.5 89/07/24 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_clnt_create.3,v 1.2 2000/06/20 00:53:08 fvdl Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpc_clnt_create.3,v 1.12 2003/09/14 13:41:56 ru Exp $ +.Dd May 7, 1993 +.Dt RPC_CLNT_CREATE 3 +.Os +.Sh NAME +.Nm rpc_clnt_create , +.Nm clnt_control , +.Nm clnt_create , +.Nm clnt_create_timed , +.Nm clnt_create_vers , +.Nm clnt_create_vers_timed , +.Nm clnt_destroy , +.Nm clnt_dg_create , +.Nm clnt_pcreateerror , +.Nm clnt_raw_create , +.Nm clnt_spcreateerror , +.Nm clnt_tli_create , +.Nm clnt_tp_create , +.Nm clnt_tp_create_timed , +.Nm clnt_vc_create , +.Nm rpc_createerr +.Nd "library routines for dealing with creation and manipulation of" +.Vt CLIENT +handles +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft bool_t +.Fn clnt_control "CLIENT *clnt" "const u_int req" "char *info" +.Ft "CLIENT *" +.Fn clnt_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" +.Ft "CLIENT *" +.Fn clnt_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" "const struct timeval *timeout" +.Ft "CLIENT *" +.Fn clnt_create_vers "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "const char *nettype" +.Ft "CLIENT *" +.Fn clnt_create_vers_timed "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "char *nettype" "const struct timeval *timeout" +.Ft void +.Fn clnt_destroy "CLIENT *clnt" +.Ft "CLIENT *" +.Fn clnt_dg_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" +.Ft void +.Fn clnt_pcreateerror "const char *s" +.Ft "char *" +.Fn clnt_spcreateerror "const char *s" +.Ft "CLIENT *" +.Fn clnt_raw_create "const rpcprog_t prognum" "const rpcvers_t versnum" +.Ft "CLIENT *" +.Fn clnt_tli_create "const int fildes" "const struct netconfig *netconf" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" +.Ft "CLIENT *" +.Fn clnt_tp_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Ft "CLIENT *" +.Fn clnt_tp_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct timeval *timeout" +.Ft "CLIENT *" +.Fn clnt_vc_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "u_int sendsz" "u_int recvsz" +.Sh DESCRIPTION +RPC library routines allow C language programs to make procedure +calls on other machines across the network. +First a +.Vt CLIENT +handle is created and then the client calls a procedure to send a +request to the server. +On receipt of the request, the server calls a dispatch routine +to perform the requested service, and then sends a reply. +.Sh Routines +.Bl -tag -width YYYYYYY +.It Fn clnt_control +A function macro to change or retrieve various information +about a client object. +The +.Fa req +argument +indicates the type of operation, and +.Fa info +is a pointer to the information. +For both connectionless and connection-oriented transports, +the supported values of +.Fa req +and their argument types and what they do are: +.Bl -column "CLSET_FD_NCLOSE" "struct timeval *" "set total timeout" +.It Dv CLSET_TIMEOUT Ta "struct timeval *" Ta "set total timeout" +.It Dv CLGET_TIMEOUT Ta "struct timeval *" Ta "get total timeout" +.El +.Pp +Note: +if you set the timeout using +.Fn clnt_control , +the timeout argument passed by +.Fn clnt_call +is ignored in all subsequent calls. +.Pp +Note: +If you set the timeout value to 0, +.Fn clnt_control +immediately returns an error +.Pq Dv RPC_TIMEDOUT . +Set the timeout argument to 0 for batching calls. +.Bl -column CLSET_FD_NCLOSE "struct timeval *" "do not close fd on destroy" +.It Dv CLGET_SVC_ADDR Ta "struct netbuf *" Ta "get servers address" +.It Dv CLGET_FD Ta "int *" Ta "get fd from handle" +.It Dv CLSET_FD_CLOSE Ta "void" Ta "close fd on destroy" +.It Dv CLSET_FD_NCLOSE Ta void Ta "don't close fd on destroy" +.It Dv CLGET_VERS Ta "u_int32_t *" Ta "get RPC program version" +.It Dv CLSET_VERS Ta "u_int32_t *" Ta "set RPC program version" +.It Dv CLGET_XID Ta "u_int32_t *" Ta "get XID of previous call" +.It Dv CLSET_XID Ta "u_int32_t *" Ta "set XID of next call" +.El +.Pp +The following operations are valid for connectionless transports only: +.Bl -column CLSET_RETRY_TIMEOUT "struct timeval *" "set total timeout" +.It Dv CLSET_RETRY_TIMEOUT Ta "struct timeval *" Ta "set the retry timeout" +.It Dv CLGET_RETRY_TIMEOUT Ta "struct timeval *" Ta "get the retry timeout" +.It Dv CLSET_CONNECT Ta Vt "int *" Ta use Xr connect 2 +.El +.Pp +The retry timeout is the time that RPC +waits for the server to reply before retransmitting the request. +The +.Fn clnt_control +function +returns +.Dv TRUE +on success and +.Dv FALSE +on failure. +.It Fn clnt_create +Generic client creation routine for program +.Fa prognum +and version +.Fa versnum . +The +.Fa host +argument +identifies the name of the remote host where the server +is located. +The +.Fa nettype +argument +indicates the class of transport protocol to use. +The transports are tried in left to right order in +.Ev NETPATH +environment variable or in top to bottom order in +the netconfig database. +The +.Fn clnt_create +function +tries all the transports of the +.Fa nettype +class available from the +.Ev NETPATH +environment variable and the netconfig database, +and chooses the first successful one. +A default timeout is set and can be modified using +.Fn clnt_control . +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +.Pp +Note: +.Fn clnt_create +returns a valid client handle even +if the particular version number supplied to +.Fn clnt_create +is not registered with the +.Xr rpcbind 8 +service. +This mismatch will be discovered by a +.Fn clnt_call +later (see +.Xr rpc_clnt_calls 3 ) . +.It Fn clnt_create_timed +Generic client creation routine which is similar to +.Fn clnt_create +but which also has the additional argument +.Fa timeout +that specifies the maximum amount of time allowed for +each transport class tried. +In all other respects, the +.Fn clnt_create_timed +call behaves exactly like the +.Fn clnt_create +call. +.It Fn clnt_create_vers +Generic client creation routine which is similar to +.Fn clnt_create +but which also checks for the +version availability. +The +.Fa host +argument +identifies the name of the remote host where the server +is located. +The +.Fa nettype +argument +indicates the class transport protocols to be used. +If the routine is successful it returns a client handle created for +the highest version between +.Fa vers_low +and +.Fa vers_high +that is supported by the server. +The +.Fa vers_outp +argument +is set to this value. +That is, after a successful return +.Fa vers_low +<= +.Fa *vers_outp +<= +.Fa vers_high . +If no version between +.Fa vers_low +and +.Fa vers_high +is supported by the server then the routine fails and returns +.Dv NULL . +A default timeout is set and can be modified using +.Fn clnt_control . +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +Note: +.Fn clnt_create +returns a valid client handle even +if the particular version number supplied to +.Fn clnt_create +is not registered with the +.Xr rpcbind 8 +service. +This mismatch will be discovered by a +.Fn clnt_call +later (see +.Xr rpc_clnt_calls 3 ) . +However, +.Fn clnt_create_vers +does this for you and returns a valid handle +only if a version within +the range supplied is supported by the server. +.It Fn clnt_create_vers_timed +Generic client creation routine which is similar to +.Fn clnt_create_vers +but which also has the additional argument +.Fa timeout +that specifies the maximum amount of time allowed for +each transport class tried. +In all other respects, the +.Fn clnt_create_vers_timed +call behaves exactly like the +.Fn clnt_create_vers +call. +.It Fn clnt_destroy +A function macro that destroys the client's RPC handle. +Destruction usually involves deallocation +of private data structures, including +.Fa clnt +itself. +Use of +.Fa clnt +is undefined after calling +.Fn clnt_destroy . +If the RPC library opened the associated file descriptor, or +.Dv CLSET_FD_CLOSE +was set using +.Fn clnt_control , +the file descriptor will be closed. +The caller should call +.Fn auth_destroy "clnt->cl_auth" +(before calling +.Fn clnt_destroy ) +to destroy the associated +.Vt AUTH +structure (see +.Xr rpc_clnt_auth 3 ) . +.It Fn clnt_dg_create +This routine creates an RPC client for the remote program +.Fa prognum +and version +.Fa versnum ; +the client uses a connectionless transport. +The remote program is located at address +.Fa svcaddr . +The +.Fa fildes +argument +is an open and bound file descriptor. +This routine will resend the call message in intervals of +15 seconds until a response is received or until the +call times out. +The total time for the call to time out is specified by +.Fn clnt_call +(see +.Fn clnt_call +in +.Xr rpc_clnt_calls 3 ) . +The retry time out and the total time out periods can +be changed using +.Fn clnt_control . +The user may set the size of the send and receive +buffers with the +.Fa sendsz +and +.Fa recvsz +arguments; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails. +.It Fn clnt_pcreateerror +Print a message to standard error indicating +why a client RPC handle could not be created. +The message is prepended with the string +.Fa s +and a colon, and appended with a newline. +.It Fn clnt_spcreateerror +Like +.Fn clnt_pcreateerror , +except that it returns a string +instead of printing to the standard error. +A newline is not appended to the message in this case. +Warning: +returns a pointer to a buffer that is overwritten +on each call. +.It Fn clnt_raw_create +This routine creates an RPC +client handle for the remote program +.Fa prognum +and version +.Fa versnum . +The transport used to pass messages to the service is +a buffer within the process's address space, +so the corresponding RPC +server should live in the same address space; +(see +.Fn svc_raw_create +in +.Xr rpc_svc_create 3 ) . +This allows simulation of RPC and measurement of +RPC overheads, such as round trip times, +without any kernel or networking interference. +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_raw_create +function +should be called after +.Fn svc_raw_create . +.It Fn clnt_tli_create +This routine creates an RPC +client handle for the remote program +.Fa prognum +and version +.Fa versnum . +The remote program is located at address +.Fa svcaddr . +If +.Fa svcaddr +is +.Dv NULL +and it is connection-oriented, it is assumed that the file descriptor +is connected. +For connectionless transports, if +.Fa svcaddr +is +.Dv NULL , +.Dv RPC_UNKNOWNADDR +error is set. +The +.Fa fildes +argument +is a file descriptor which may be open, bound and connected. +If it is +.Dv RPC_ANYFD , +it opens a file descriptor on the transport specified by +.Fa netconf . +If +.Fa fildes +is +.Dv RPC_ANYFD +and +.Fa netconf +is +.Dv NULL , +a +.Dv RPC_UNKNOWNPROTO +error is set. +If +.Fa fildes +is unbound, then it will attempt to bind the descriptor. +The user may specify the size of the buffers with the +.Fa sendsz +and +.Fa recvsz +arguments; +values of 0 choose suitable defaults. +Depending upon the type of the transport (connection-oriented +or connectionless), +.Fn clnt_tli_create +calls appropriate client creation routines. +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +The remote rpcbind +service (see +.Xr rpcbind 8 ) +is not consulted for the address of the remote +service. +.It Fn clnt_tp_create +Like +.Fn clnt_create +except +.Fn clnt_tp_create +tries only one transport specified through +.Fa netconf . +The +.Fn clnt_tp_create +function +creates a client handle for the program +.Fa prognum , +the version +.Fa versnum , +and for the transport specified by +.Fa netconf . +Default options are set, +which can be changed using +.Fn clnt_control +calls. +The remote rpcbind service on the host +.Fa host +is consulted for the address of the remote service. +This routine returns +.Dv NULL +if it fails. +The +.Fn clnt_pcreateerror +routine can be used to print the reason for failure. +.It Fn clnt_tp_create_timed +Like +.Fn clnt_tp_create +except +.Fn clnt_tp_create_timed +has the extra argument +.Fa timeout +which specifies the maximum time allowed for +the creation attempt to succeed. +In all other respects, the +.Fn clnt_tp_create_timed +call behaves exactly like the +.Fn clnt_tp_create +call. +.It Fn clnt_vc_create +This routine creates an RPC +client for the remote program +.Fa prognum +and version +.Fa versnum ; +the client uses a connection-oriented transport. +The remote program is located at address +.Fa svcaddr . +The +.Fa fildes +argument +is an open and bound file descriptor. +The user may specify the size of the send and receive buffers +with the +.Fa sendsz +and +.Fa recvsz +arguments; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails. +The address +.Fa svcaddr +should not be +.Dv NULL +and should point to the actual address of the remote program. +The +.Fn clnt_vc_create +function +does not consult the remote rpcbind service for this information. +.It Xo +.Vt "struct rpc_createerr" Va rpc_createerr ; +.Xc +A global variable whose value is set by any RPC +client handle creation routine +that fails. +It is used by the routine +.Fn clnt_pcreateerror +to print the reason for the failure. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_clnt_auth 3 , +.Xr rpc_clnt_calls 3 , +.Xr rpcbind 8 diff --git a/libtirpc/man/rpc_secure.3t b/libtirpc/man/rpc_secure.3t new file mode 100644 index 0000000..7969a91 --- /dev/null +++ b/libtirpc/man/rpc_secure.3t @@ -0,0 +1,279 @@ +.\" @(#)rpc_secure.3n 2.1 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.\" $FreeBSD: src/lib/libc/rpc/rpc_secure.3,v 1.14 2002/12/19 09:40:23 ru Exp $ +.\" +.Dd February 16, 1988 +.Dt RPC 3 +.Os +.Sh NAME +.Nm rpc_secure +.Nd library routines for secure remote procedure calls +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft AUTH * +.Fo authdes_create +.Fa "char *name" +.Fa "unsigned window" +.Fa "struct sockaddr *addr" +.Fa "des_block *ckey" +.Fc +.Ft int +.Fn authdes_getucred "struct authdes_cred *adc" "uid_t *uid" "gid_t *gid" "int *grouplen" "gid_t *groups" +.Ft int +.Fn getnetname "char *name" +.Ft int +.Fn host2netname "char *name" "const char *host" "const char *domain" +.Ft int +.Fn key_decryptsession "const char *remotename" "des_block *deskey" +.Ft int +.Fn key_encryptsession "const char *remotename" "des_block *deskey" +.Ft int +.Fn key_gendes "des_block *deskey" +.Ft int +.Fn key_setsecret "const char *key" +.Ft int +.Fn netname2host "char *name" "char *host" "int hostlen" +.Ft int +.Fn netname2user "char *name" "uid_t *uidp" "gid_t *gidp" "int *gidlenp" "gid_t *gidlist" +.Ft int +.Fn user2netname "char *name" "const uid_t uid" "const char *domain" +.Sh DESCRIPTION +These routines are part of the +.Tn RPC +library. They implement +.Tn DES +Authentication. See +.Xr rpc 3 +for further details about +.Tn RPC . +.Pp +The +.Fn authdes_create +is the first of two routines which interface to the +.Tn RPC +secure authentication system, known as +.Tn DES +authentication. +The second is +.Fn authdes_getucred , +below. +.Pp +Note: the keyserver daemon +.Xr keyserv 8 +must be running for the +.Tn DES +authentication system to work. +.Pp +The +.Fn authdes_create +function, +used on the client side, returns an authentication handle that +will enable the use of the secure authentication system. +The first argument +.Fa name +is the network name, or +.Fa netname , +of the owner of the server process. +This field usually +represents a +.Fa hostname +derived from the utility routine +.Fn host2netname , +but could also represent a user name using +.Fn user2netname . +The second field is window on the validity of +the client credential, given in seconds. A small +window is more secure than a large one, but choosing +too small of a window will increase the frequency of +resynchronizations because of clock drift. +The third +argument +.Fa addr +is optional. If it is +.Dv NULL , +then the authentication system will assume +that the local clock is always in sync with the server's +clock, and will not attempt resynchronizations. +If an address +is supplied, however, then the system will use the address +for consulting the remote time service whenever +resynchronization +is required. +This argument is usually the +address of the +.Tn RPC +server itself. +The final argument +.Fa ckey +is also optional. If it is +.Dv NULL , +then the authentication system will +generate a random +.Tn DES +key to be used for the encryption of credentials. +If it is supplied, however, then it will be used instead. +.Pp +The +.Fn authdes_getucred +function, +the second of the two +.Tn DES +authentication routines, +is used on the server side for converting a +.Tn DES +credential, which is +operating system independent, into a +.Ux +credential. +This routine differs from utility routine +.Fn netname2user +in that +.Fn authdes_getucred +pulls its information from a cache, and does not have to do a +Yellow Pages lookup every time it is called to get its information. +.Pp +The +.Fn getnetname +function +installs the unique, operating-system independent netname of +the +caller in the fixed-length array +.Fa name . +Returns +.Dv TRUE +if it succeeds and +.Dv FALSE +if it fails. +.Pp +The +.Fn host2netname +function +converts from a domain-specific hostname to an +operating-system independent netname. +Returns +.Dv TRUE +if it succeeds and +.Dv FALSE +if it fails. +Inverse of +.Fn netname2host . +.Pp +The +.Fn key_decryptsession +function +is an interface to the keyserver daemon, which is associated +with +.Tn RPC Ns 's +secure authentication system +.Tn ( DES +authentication). +User programs rarely need to call it, or its associated routines +.Fn key_encryptsession , +.Fn key_gendes +and +.Fn key_setsecret . +System commands such as +.Xr login 1 +and the +.Tn RPC +library are the main clients of these four routines. +.Pp +The +.Fn key_decryptsession +function +takes a server netname and a +.Tn DES +key, and decrypts the key by +using the public key of the server and the secret key +associated with the effective uid of the calling process. It +is the inverse of +.Fn key_encryptsession . +.Pp +The +.Fn key_encryptsession +function +is a keyserver interface routine. +It +takes a server netname and a des key, and encrypts +it using the public key of the server and the secret key +associated with the effective uid of the calling process. It +is the inverse of +.Fn key_decryptsession . +.Pp +The +.Fn key_gendes +function +is a keyserver interface routine. +It +is used to ask the keyserver for a secure conversation key. +Choosing one +.Qq random +is usually not good enough, +because +the common ways of choosing random numbers, such as using the +current time, are very easy to guess. +.Pp +The +.Fn key_setsecret +function +is a keyserver interface routine. +It is used to set the key for +the effective +.Fa uid +of the calling process. +.Pp +The +.Fn netname2host +function +converts from an operating-system independent netname to a +domain-specific hostname. +Returns +.Dv TRUE +if it succeeds and +.Dv FALSE +if it fails. Inverse of +.Fn host2netname . +.Pp +The +.Fn netname2user +function +converts from an operating-system independent netname to a +domain-specific user ID. +Returns +.Dv TRUE +if it succeeds and +.Dv FALSE +if it fails. +Inverse of +.Fn user2netname . +.Pp +The +.Fn user2netname +function +converts from a domain-specific username to an operating-system +independent netname. +Returns +.Dv TRUE +if it succeeds and +.Dv FALSE +if it fails. +Inverse of +.Fn netname2user . +.Sh SEE ALSO +.Xr rpc 3 , +.Xr xdr 3 , +.Xr keyserv 8 +.Pp +The following manuals: +.Rs +.%B Remote Procedure Calls: Protocol Specification +.Re +.Rs +.%B Remote Procedure Call Programming Guide +.Re +.Rs +.%B Rpcgen Programming Guide +.Re +.Rs +.%B RPC: Remote Procedure Call Protocol Specification +.%O RFC1050, Sun Microsystems Inc., USC-ISI +.Re diff --git a/libtirpc/man/rpc_soc.3t b/libtirpc/man/rpc_soc.3t new file mode 100644 index 0000000..59058c0 --- /dev/null +++ b/libtirpc/man/rpc_soc.3t @@ -0,0 +1,1726 @@ +.\" @(#)rpc.3n 2.4 88/08/08 4.0 RPCSRC; from 1.19 88/06/24 SMI +.\" $NetBSD: rpc_soc.3,v 1.2 2000/06/07 13:39:43 simonb Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpc_soc.3,v 1.12 2003/02/06 11:04:47 charnier Exp $ +.\" +.Dd February 16, 1988 +.Dt RPC_SOC 3 +.Os +.Sh NAME +.Nm rpc_soc , +.Nm auth_destroy , +.Nm authnone_create , +.Nm authunix_create , +.Nm authunix_create_default , +.Nm callrpc , +.Nm clnt_broadcast , +.Nm clnt_call , +.Nm clnt_control , +.Nm clnt_create , +.Nm clnt_destroy , +.Nm clnt_freeres , +.Nm clnt_geterr , +.Nm clnt_pcreateerror , +.Nm clnt_perrno , +.Nm clnt_perror , +.Nm clnt_spcreateerror , +.Nm clnt_sperrno , +.Nm clnt_sperror , +.Nm clntraw_create , +.Nm clnttcp_create , +.Nm clntudp_bufcreate , +.Nm clntudp_create , +.Nm clntunix_create , +.Nm get_myaddress , +.Nm pmap_getmaps , +.Nm pmap_getport , +.Nm pmap_rmtcall , +.Nm pmap_set , +.Nm pmap_unset , +.Nm registerrpc , +.Nm rpc_createerr , +.Nm svc_destroy , +.Nm svc_fds , +.Nm svc_fdset , +.Nm svc_getargs , +.Nm svc_getcaller , +.Nm svc_getreq , +.Nm svc_getreqset , +.Nm svc_register , +.Nm svc_run , +.Nm svc_sendreply , +.Nm svc_unregister , +.Nm svcerr_auth , +.Nm svcerr_decode , +.Nm svcerr_noproc , +.Nm svcerr_noprog , +.Nm svcerr_progvers , +.Nm svcerr_systemerr , +.Nm svcerr_weakauth , +.Nm svcfd_create , +.Nm svcunixfd_create , +.Nm svcraw_create , +.Nm svcunix_create , +.Nm xdr_accepted_reply , +.Nm xdr_authunix_parms , +.Nm xdr_callhdr , +.Nm xdr_callmsg , +.Nm xdr_opaque_auth , +.Nm xdr_pmap , +.Nm xdr_pmaplist , +.Nm xdr_rejected_reply , +.Nm xdr_replymsg , +.Nm xprt_register , +.Nm xprt_unregister +.Nd "library routines for remote procedure calls" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Pp +See +.Sx DESCRIPTION +for function declarations. +.Sh DESCRIPTION +.Bf -symbolic +The +.Fn svc_* +and +.Fn clnt_* +functions described in this page are the old, TS-RPC +interface to the XDR and RPC library, and exist for backward compatibility. +The new interface is described in the pages +referenced from +.Xr rpc 3 . +.Ef +.Pp +These routines allow C programs to make procedure +calls on other machines across the network. +First, the client calls a procedure to send a +data packet to the server. +Upon receipt of the packet, the server calls a dispatch routine +to perform the requested service, and then sends back a +reply. +Finally, the procedure call returns to the client. +.Pp +Routines that are used for Secure +.Tn RPC ( DES +authentication) are described in +.Xr rpc_secure 3 . +Secure +.Tn RPC +can be used only if +.Tn DES +encryption is available. +.Bl -tag -width indent -compact +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn auth_destroy "AUTH *auth" +.Xc +.Pp +A macro that destroys the authentication information associated with +.Fa auth . +Destruction usually involves deallocation of private data +structures. +The use of +.Fa auth +is undefined after calling +.Fn auth_destroy . +.Pp +.It Xo +.Ft "AUTH *" +.Xc +.It Xo +.Fn authnone_create +.Xc +.Pp +Create and return an +.Tn RPC +authentication handle that passes nonusable authentication +information with each remote procedure call. +This is the +default authentication used by +.Tn RPC . +.Pp +.It Xo +.Ft "AUTH *" +.Xc +.It Xo +.Fn authunix_create "char *host" "int uid" "int gid" "int len" "int *aup_gids" +.Xc +.Pp +Create and return an +.Tn RPC +authentication handle that contains +.Ux +authentication information. +The +.Fa host +argument +is the name of the machine on which the information was +created; +.Fa uid +is the user's user ID; +.Fa gid +is the user's current group ID; +.Fa len +and +.Fa aup_gids +refer to a counted array of groups to which the user belongs. +It is easy to impersonate a user. +.Pp +.It Xo +.Ft "AUTH *" +.Xc +.It Xo +.Fn authunix_create_default +.Xc +.Pp +Calls +.Fn authunix_create +with the appropriate arguments. +.Pp +.It Xo +.Ft int +.Fo callrpc +.Fa "char *host" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "u_long procnum" +.Fa "xdrproc_t inproc" +.Fa "void *in" +.Fa "xdrproc_t outproc" +.Fa "void *out" +.Fc +.Xc +.Pp +Call the remote procedure associated with +.Fa prognum , +.Fa versnum , +and +.Fa procnum +on the machine +.Fa host . +The +.Fa in +argument +is the address of the procedure's argument(s), and +.Fa out +is the address of where to place the result(s); +.Fa inproc +is used to encode the procedure's arguments, and +.Fa outproc +is used to decode the procedure's results. +This routine returns zero if it succeeds, or the value of +.Vt "enum clnt_stat" +cast to an integer if it fails. +The routine +.Fn clnt_perrno +is handy for translating failure statuses into messages. +.Pp +Warning: calling remote procedures with this routine +uses +.Tn UDP/IP +as a transport; see +.Fn clntudp_create +for restrictions. +You do not have control of timeouts or authentication using +this routine. +.Pp +.It Xo +.Ft "enum clnt_stat" +.Xc +.It Xo +.Fo clnt_broadcast +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "u_long procnum" +.Fa "xdrproc_t inproc" +.Fa "char *in" +.Fa "xdrproc_t outproc" +.Fa "char *out" +.Fa "bool_t (*eachresult)(caddr_t, struct sockaddr_in *)" +.Fc +.Xc +.Pp +Like +.Fn callrpc , +except the call message is broadcast to all locally +connected broadcast nets. +Each time it receives a +response, this routine calls +.Fn eachresult , +whose form is: +.Bd -ragged -offset indent +.Ft bool_t +.Fn eachresult "caddr_t out" "struct sockaddr_in *addr" +.Ed +.Pp +where +.Fa out +is the same as +.Fa out +passed to +.Fn clnt_broadcast , +except that the remote procedure's output is decoded there; +.Fa addr +points to the address of the machine that sent the results. +If +.Fn eachresult +returns zero, +.Fn clnt_broadcast +waits for more replies; otherwise it returns with appropriate +status. +.Pp +Warning: broadcast sockets are limited in size to the +maximum transfer unit of the data link. +For ethernet, +this value is 1500 bytes. +.Pp +.It Xo +.Ft "enum clnt_stat" +.Xc +.It Xo +.Fo clnt_call +.Fa "CLIENT *clnt" +.Fa "u_long procnum" +.Fa "xdrproc_t inproc" +.Fa "char *in" +.Fa "xdrproc_t outproc" +.Fa "char *out" +.Fa "struct timeval tout" +.Fc +.Xc +.Pp +A macro that calls the remote procedure +.Fa procnum +associated with the client handle, +.Fa clnt , +which is obtained with an +.Tn RPC +client creation routine such as +.Fn clnt_create . +The +.Fa in +argument +is the address of the procedure's argument(s), and +.Fa out +is the address of where to place the result(s); +.Fa inproc +is used to encode the procedure's arguments, and +.Fa outproc +is used to decode the procedure's results; +.Fa tout +is the time allowed for results to come back. +.Pp +.It Xo +.Ft void +.Fn clnt_destroy "CLIENT *clnt" +.Xc +.Pp +A macro that destroys the client's +.Tn RPC +handle. +Destruction usually involves deallocation +of private data structures, including +.Fa clnt +itself. +Use of +.Fa clnt +is undefined after calling +.Fn clnt_destroy . +If the +.Tn RPC +library opened the associated socket, it will close it also. +Otherwise, the socket remains open. +.Pp +.It Xo +.Ft CLIENT * +.Xc +.It Xo +.Fn clnt_create "char *host" "u_long prog" "u_long vers" "char *proto" +.Xc +.Pp +Generic client creation routine. +The +.Fa host +argument +identifies the name of the remote host where the server +is located. +The +.Fa proto +argument +indicates which kind of transport protocol to use. +The +currently supported values for this field are +.Qq Li udp +and +.Qq Li tcp . +Default timeouts are set, but can be modified using +.Fn clnt_control . +.Pp +Warning: Using +.Tn UDP +has its shortcomings. +Since +.Tn UDP Ns \-based +.Tn RPC +messages can only hold up to 8 Kbytes of encoded data, +this transport cannot be used for procedures that take +large arguments or return huge results. +.Pp +.It Xo +.Ft bool_t +.Xc +.It Xo +.Fn clnt_control "CLIENT *cl" "u_int req" "char *info" +.Xc +.Pp +A macro used to change or retrieve various information +about a client object. +The +.Fa req +argument +indicates the type of operation, and +.Fa info +is a pointer to the information. +For both +.Tn UDP +and +.Tn TCP , +the supported values of +.Fa req +and their argument types and what they do are: +.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in" +.It Dv CLSET_TIMEOUT Ta Xo +.Vt "struct timeval" Ta "set total timeout" +.Xc +.It Dv CLGET_TIMEOUT Ta Xo +.Vt "struct timeval" Ta "get total timeout" +.Xc +.El +.Pp +Note: if you set the timeout using +.Fn clnt_control , +the timeout argument passed to +.Fn clnt_call +will be ignored in all future calls. +.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in" +.It Dv CLGET_SERVER_ADDR Ta Xo +.Vt "struct sockaddr_in" Ta "get server's address" +.Xc +.El +.Pp +The following operations are valid for +.Tn UDP +only: +.Bl -column "CLSET_RETRY_TIMEOUT" "struct sockaddr_in" +.It Dv CLSET_RETRY_TIMEOUT Ta Xo +.Vt "struct timeval" Ta "set the retry timeout" +.Xc +.It Dv CLGET_RETRY_TIMEOUT Ta Xo +.Vt "struct timeval" Ta "get the retry timeout" +.Xc +.El +.Pp +The retry timeout is the time that +.Tn "UDP RPC" +waits for the server to reply before +retransmitting the request. +.Pp +.It Xo +.Ft bool_t +.Fn clnt_freeres "CLIENT *clnt" "xdrproc_t outproc" "char *out" +.Xc +.Pp +A macro that frees any data allocated by the +.Tn RPC/XDR +system when it decoded the results of an +.Tn RPC +call. +The +.Fa out +argument +is the address of the results, and +.Fa outproc +is the +.Tn XDR +routine describing the results. +This routine returns one if the results were successfully +freed, +and zero otherwise. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn clnt_geterr "CLIENT *clnt" "struct rpc_err *errp" +.Xc +.Pp +A macro that copies the error structure out of the client +handle +to the structure at address +.Fa errp . +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn clnt_pcreateerror "char *s" +.Xc +.Pp +prints a message to standard error indicating +why a client +.Tn RPC +handle could not be created. +The message is prepended with string +.Fa s +and a colon. +A newline is appended at the end of the message. +Used when a +.Fn clnt_create , +.Fn clntraw_create , +.Fn clnttcp_create , +or +.Fn clntudp_create +call fails. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn clnt_perrno "enum clnt_stat stat" +.Xc +.Pp +Print a message to standard error corresponding +to the condition indicated by +.Fa stat . +A newline is appended at the end of the message. +Used after +.Fn callrpc . +.Pp +.It Xo +.Ft void +.Fn clnt_perror "CLIENT *clnt" "char *s" +.Xc +.Pp +Print a message to standard error indicating why an +.Tn RPC +call failed; +.Fa clnt +is the handle used to do the call. +The message is prepended with string +.Fa s +and a colon. +A newline is appended at the end of the message. +Used after +.Fn clnt_call . +.Pp +.It Xo +.Ft "char *" +.Xc +.It Xo +.Fn clnt_spcreateerror "char *s" +.Xc +.Pp +Like +.Fn clnt_pcreateerror , +except that it returns a string +instead of printing to the standard error. +.Pp +Bugs: returns pointer to static data that is overwritten +on each call. +.Pp +.It Xo +.Ft "char *" +.Xc +.It Xo +.Fn clnt_sperrno "enum clnt_stat stat" +.Xc +.Pp +Take the same arguments as +.Fn clnt_perrno , +but instead of sending a message to the standard error +indicating why an +.Tn RPC +call failed, return a pointer to a string which contains +the message. +.Pp +The +.Fn clnt_sperrno +function +is used instead of +.Fn clnt_perrno +if the program does not have a standard error (as a program +running as a server quite likely does not), or if the +programmer +does not want the message to be output with +.Fn printf , +or if a message format different from that supported by +.Fn clnt_perrno +is to be used. +.Pp +Note: unlike +.Fn clnt_sperror +and +.Fn clnt_spcreateerror , +.Fn clnt_sperrno +returns pointer to static data, but the +result will not get overwritten on each call. +.Pp +.It Xo +.Ft "char *" +.Xc +.It Xo +.Fn clnt_sperror "CLIENT *rpch" "char *s" +.Xc +.Pp +Like +.Fn clnt_perror , +except that (like +.Fn clnt_sperrno ) +it returns a string instead of printing to standard error. +.Pp +Bugs: returns pointer to static data that is overwritten +on each call. +.Pp +.It Xo +.Ft "CLIENT *" +.Xc +.It Xo +.Fn clntraw_create "u_long prognum" "u_long versnum" +.Xc +.Pp +This routine creates a toy +.Tn RPC +client for the remote program +.Fa prognum , +version +.Fa versnum . +The transport used to pass messages to the service is +actually a buffer within the process's address space, so the +corresponding +.Tn RPC +server should live in the same address space; see +.Fn svcraw_create . +This allows simulation of +.Tn RPC +and acquisition of +.Tn RPC +overheads, such as round trip times, without any +kernel interference. +This routine returns +.Dv NULL +if it fails. +.Pp +.It Xo +.Ft "CLIENT *" +.Xc +.It Xo +.Fo clnttcp_create +.Fa "struct sockaddr_in *addr" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "int *sockp" +.Fa "u_int sendsz" +.Fa "u_int recvsz" +.Fc +.Xc +.Pp +This routine creates an +.Tn RPC +client for the remote program +.Fa prognum , +version +.Fa versnum ; +the client uses +.Tn TCP/IP +as a transport. +The remote program is located at Internet +address +.Fa addr . +If +.Fa addr\->sin_port +is zero, then it is set to the actual port that the remote +program is listening on (the remote +.Xr rpcbind 8 +service is consulted for this information). +The +.Fa sockp +argument +is a socket; if it is +.Dv RPC_ANYSOCK , +then this routine opens a new one and sets +.Fa sockp . +Since +.Tn TCP Ns \-based +.Tn RPC +uses buffered +.Tn I/O , +the user may specify the size of the send and receive buffers +with the +.Fa sendsz +and +.Fa recvsz +arguments; +values of zero choose suitable defaults. +This routine returns +.Dv NULL +if it fails. +.Pp +.It Xo +.Ft "CLIENT *" +.Xc +.It Xo +.Fo clntudp_create +.Fa "struct sockaddr_in *addr" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "struct timeval wait" +.Fa "int *sockp" +.Fc +.Xc +.Pp +This routine creates an +.Tn RPC +client for the remote program +.Fa prognum , +version +.Fa versnum ; +the client uses +.Tn UDP/IP +as a transport. +The remote program is located at Internet +address +.Fa addr . +If +.Fa addr\->sin_port +is zero, then it is set to actual port that the remote +program is listening on (the remote +.Xr rpcbind 8 +service is consulted for this information). +The +.Fa sockp +argument +is a socket; if it is +.Dv RPC_ANYSOCK , +then this routine opens a new one and sets +.Fa sockp . +The +.Tn UDP +transport resends the call message in intervals of +.Fa wait +time until a response is received or until the call times +out. +The total time for the call to time out is specified by +.Fn clnt_call . +.Pp +Warning: since +.Tn UDP Ns \-based +.Tn RPC +messages can only hold up to 8 Kbytes +of encoded data, this transport cannot be used for procedures +that take large arguments or return huge results. +.Pp +.It Xo +.Ft "CLIENT *" +.Xc +.It Xo +.Fo clntudp_bufcreate +.Fa "struct sockaddr_in *addr" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "struct timeval wait" +.Fa "int *sockp" +.Fa "unsigned int sendsize" +.Fa "unsigned int recosize" +.Fc +.Xc +.Pp +This routine creates an +.Tn RPC +client for the remote program +.Fa prognum , +on +.Fa versnum ; +the client uses +.Tn UDP/IP +as a transport. +The remote program is located at Internet +address +.Fa addr . +If +.Fa addr\->sin_port +is zero, then it is set to actual port that the remote +program is listening on (the remote +.Xr rpcbind 8 +service is consulted for this information). +The +.Fa sockp +argument +is a socket; if it is +.Dv RPC_ANYSOCK , +then this routine opens a new one and sets +.Fa sockp . +The +.Tn UDP +transport resends the call message in intervals of +.Fa wait +time until a response is received or until the call times +out. +The total time for the call to time out is specified by +.Fn clnt_call . +.Pp +This allows the user to specify the maximum packet size +for sending and receiving +.Tn UDP Ns \-based +.Tn RPC +messages. +.Pp +.It Xo +.Ft "CLIENT *" +.Xc +.It Xo +.Fo clntunix_create +.Fa "struct sockaddr_un *raddr" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "int *sockp" +.Fa "u_int sendsz" +.Fa "u_int recvsz" +.Fc +.Xc +.Pp +This routine creates an +.Tn RPC +client for the local +program +.Fa prognum , +version +.Fa versnum ; +the client uses +.Ux Ns -domain +sockets as a transport. +The local program is located at the +.Fa *raddr . +The +.Fa sockp +argument +is a socket; if it is +.Dv RPC_ANYSOCK , +then this routine opens a new one and sets +.Fa sockp . +Since +.Ux Ns -based +.Tn RPC +uses buffered +.Tn I/O , +the user may specify the size of the send and receive buffers +with the +.Fa sendsz +and +.Fa recvsz +arguments; +values of zero choose suitable defaults. +This routine returns +.Dv NULL +if it fails. +.Pp +.It Xo +.Ft int +.Xc +.It Xo +.Fn get_myaddress "struct sockaddr_in *addr" +.Xc +.Pp +Stuff the machine's +.Tn IP +address into +.Fa addr , +without consulting the library routines that deal with +.Pa /etc/hosts . +The port number is always set to +.Fn htons PMAPPORT . +Returns zero on success, non-zero on failure. +.Pp +.It Xo +.Ft "struct pmaplist *" +.Xc +.It Xo +.Fn pmap_getmaps "struct sockaddr_in *addr" +.Xc +.Pp +A user interface to the +.Xr rpcbind 8 +service, which returns a list of the current +.Tn RPC +program\-to\-port mappings +on the host located at +.Tn IP +address +.Fa addr . +This routine can return +.Dv NULL . +The command +.Dq Nm rpcinfo Fl p +uses this routine. +.Pp +.It Xo +.Ft u_short +.Xc +.It Xo +.Fo pmap_getport +.Fa "struct sockaddr_in *addr" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "u_long protocol" +.Fc +.Xc +.Pp +A user interface to the +.Xr rpcbind 8 +service, which returns the port number +on which waits a service that supports program number +.Fa prognum , +version +.Fa versnum , +and speaks the transport protocol associated with +.Fa protocol . +The value of +.Fa protocol +is most likely +.Dv IPPROTO_UDP +or +.Dv IPPROTO_TCP . +A return value of zero means that the mapping does not exist +or that +the +.Tn RPC +system failed to contact the remote +.Xr rpcbind 8 +service. +In the latter case, the global variable +.Va rpc_createerr +contains the +.Tn RPC +status. +.Pp +.It Xo +.Ft "enum clnt_stat" +.Xc +.It Xo +.Fo pmap_rmtcall +.Fa "struct sockaddr_in *addr" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "u_long procnum" +.Fa "xdrproc_t inproc" +.Fa "char *in" +.Fa "xdrproc_t outproc" +.Fa "char *out" +.Fa "struct timeval tout" +.Fa "u_long *portp" +.Fc +.Xc +.Pp +A user interface to the +.Xr rpcbind 8 +service, which instructs +.Xr rpcbind 8 +on the host at +.Tn IP +address +.Fa addr +to make an +.Tn RPC +call on your behalf to a procedure on that host. +The +.Fa portp +argument +will be modified to the program's port number if the +procedure +succeeds. +The definitions of other arguments are discussed +in +.Fn callrpc +and +.Fn clnt_call . +This procedure should be used for a +.Dq ping +and nothing +else. +See also +.Fn clnt_broadcast . +.Pp +.It Xo +.Ft bool_t +.Fn pmap_set "u_long prognum" "u_long versnum" "u_long protocol" "u_short port" +.Xc +.Pp +A user interface to the +.Xr rpcbind 8 +service, which establishes a mapping between the triple +.Pq Fa prognum , versnum , protocol +and +.Fa port +on the machine's +.Xr rpcbind 8 +service. +The value of +.Fa protocol +is most likely +.Dv IPPROTO_UDP +or +.Dv IPPROTO_TCP . +This routine returns one if it succeeds, zero otherwise. +Automatically done by +.Fn svc_register . +.Pp +.It Xo +.Ft bool_t +.Fn pmap_unset "u_long prognum" "u_long versnum" +.Xc +.Pp +A user interface to the +.Xr rpcbind 8 +service, which destroys all mapping between the triple +.Pq Fa prognum , versnum , * +and +.Fa ports +on the machine's +.Xr rpcbind 8 +service. +This routine returns one if it succeeds, zero +otherwise. +.Pp +.It Xo +.Ft bool_t +.Fo registerrpc +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "u_long procnum" +.Fa "char *(*procname)(void)" +.Fa "xdrproc_t inproc" +.Fa "xdrproc_t outproc" +.Fc +.Xc +.Pp +Register procedure +.Fa procname +with the +.Tn RPC +service package. +If a request arrives for program +.Fa prognum , +version +.Fa versnum , +and procedure +.Fa procnum , +.Fa procname +is called with a pointer to its argument(s); +.Fa progname +should return a pointer to its static result(s); +.Fa inproc +is used to decode the arguments while +.Fa outproc +is used to encode the results. +This routine returns zero if the registration succeeded, \-1 +otherwise. +.Pp +Warning: remote procedures registered in this form +are accessed using the +.Tn UDP/IP +transport; see +.Fn svcudp_create +for restrictions. +.Pp +.It Xo +.Vt "struct rpc_createerr" rpc_createerr ; +.Xc +.Pp +A global variable whose value is set by any +.Tn RPC +client creation routine +that does not succeed. +Use the routine +.Fn clnt_pcreateerror +to print the reason why. +.Pp +.It Xo +.Ft bool_t +.Fn svc_destroy "SVCXPRT * xprt" +.Xc +.Pp +A macro that destroys the +.Tn RPC +service transport handle, +.Fa xprt . +Destruction usually involves deallocation +of private data structures, including +.Fa xprt +itself. +Use of +.Fa xprt +is undefined after calling this routine. +.Pp +.It Xo +.Vt fd_set svc_fdset ; +.Xc +.Pp +A global variable reflecting the +.Tn RPC +service side's +read file descriptor bit mask; it is suitable as a template argument +to the +.Xr select 2 +system call. +This is only of interest +if a service implementor does not call +.Fn svc_run , +but rather does his own asynchronous event processing. +This variable is read\-only (do not pass its address to +.Xr select 2 ! ) , +yet it may change after calls to +.Fn svc_getreqset +or any creation routines. +As well, note that if the process has descriptor limits +which are extended beyond +.Dv FD_SETSIZE , +this variable will only be usable for the first +.Dv FD_SETSIZE +descriptors. +.Pp +.It Xo +.Vt int svc_fds ; +.Xc +.Pp +Similar to +.Va svc_fdset , +but limited to 32 descriptors. +This +interface is obsoleted by +.Va svc_fdset . +.Pp +.It Xo +.Ft bool_t +.Fn svc_freeargs "SVCXPRT *xprt" "xdrproc_t inproc" "char *in" +.Xc +.Pp +A macro that frees any data allocated by the +.Tn RPC/XDR +system when it decoded the arguments to a service procedure +using +.Fn svc_getargs . +This routine returns 1 if the results were successfully +freed, +and zero otherwise. +.Pp +.It Xo +.Ft bool_t +.Fn svc_getargs "SVCXPRT *xprt" "xdrproc_t inproc" "char *in" +.Xc +.Pp +A macro that decodes the arguments of an +.Tn RPC +request +associated with the +.Tn RPC +service transport handle, +.Fa xprt . +The +.Fa in +argument +is the address where the arguments will be placed; +.Fa inproc +is the +.Tn XDR +routine used to decode the arguments. +This routine returns one if decoding succeeds, and zero +otherwise. +.Pp +.It Xo +.Ft "struct sockaddr_in *" +.Xc +.It Xo +.Fn svc_getcaller "SVCXPRT *xprt" +.Xc +.Pp +The approved way of getting the network address of the caller +of a procedure associated with the +.Tn RPC +service transport handle, +.Fa xprt . +.Pp +.It Xo +.Ft void +.Fn svc_getreqset "fd_set *rdfds" +.Xc +.Pp +This routine is only of interest if a service implementor +does not call +.Fn svc_run , +but instead implements custom asynchronous event processing. +It is called when the +.Xr select 2 +system call has determined that an +.Tn RPC +request has arrived on some +.Tn RPC +socket(s); +.Fa rdfds +is the resultant read file descriptor bit mask. +The routine returns when all sockets associated with the +value of +.Fa rdfds +have been serviced. +.Pp +.It Xo +.Ft void +.Fn svc_getreq "int rdfds" +.Xc +.Pp +Similar to +.Fn svc_getreqset , +but limited to 32 descriptors. +This interface is obsoleted by +.Fn svc_getreqset . +.Pp +.It Xo +.Ft bool_t +.Fo svc_register +.Fa "SVCXPRT *xprt" +.Fa "u_long prognum" +.Fa "u_long versnum" +.Fa "void (*dispatch)(struct svc_req *, SVCXPRT *)" +.Fa "int protocol" +.Fc +.Xc +.Pp +Associates +.Fa prognum +and +.Fa versnum +with the service dispatch procedure, +.Fn dispatch . +If +.Fa protocol +is zero, the service is not registered with the +.Xr rpcbind 8 +service. +If +.Fa protocol +is non-zero, then a mapping of the triple +.Pq Fa prognum , versnum , protocol +to +.Fa xprt\->xp_port +is established with the local +.Xr rpcbind 8 +service (generally +.Fa protocol +is zero, +.Dv IPPROTO_UDP +or +.Dv IPPROTO_TCP ) . +The procedure +.Fn dispatch +has the following form: +.Bd -ragged -offset indent +.Ft bool_t +.Fn dispatch "struct svc_req *request" "SVCXPRT *xprt" +.Ed +.Pp +The +.Fn svc_register +routine returns one if it succeeds, and zero otherwise. +.Pp +.It Xo +.Fn svc_run +.Xc +.Pp +This routine never returns. +It waits for +.Tn RPC +requests to arrive, and calls the appropriate service +procedure using +.Fn svc_getreq +when one arrives. +This procedure is usually waiting for a +.Xr select 2 +system call to return. +.Pp +.It Xo +.Ft bool_t +.Fn svc_sendreply "SVCXPRT *xprt" "xdrproc_t outproc" "char *out" +.Xc +.Pp +Called by an +.Tn RPC +service's dispatch routine to send the results of a +remote procedure call. +The +.Fa xprt +argument +is the request's associated transport handle; +.Fa outproc +is the +.Tn XDR +routine which is used to encode the results; and +.Fa out +is the address of the results. +This routine returns one if it succeeds, zero otherwise. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svc_unregister "u_long prognum" "u_long versnum" +.Xc +.Pp +Remove all mapping of the double +.Pq Fa prognum , versnum +to dispatch routines, and of the triple +.Pq Fa prognum , versnum , * +to port number. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_auth "SVCXPRT *xprt" "enum auth_stat why" +.Xc +.Pp +Called by a service dispatch routine that refuses to perform +a remote procedure call due to an authentication error. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_decode "SVCXPRT *xprt" +.Xc +.Pp +Called by a service dispatch routine that cannot successfully +decode its arguments. +See also +.Fn svc_getargs . +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_noproc "SVCXPRT *xprt" +.Xc +.Pp +Called by a service dispatch routine that does not implement +the procedure number that the caller requests. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_noprog "SVCXPRT *xprt" +.Xc +.Pp +Called when the desired program is not registered with the +.Tn RPC +package. +Service implementors usually do not need this routine. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_progvers "SVCXPRT *xprt" "u_long low_vers" "u_long high_vers" +.Xc +.Pp +Called when the desired version of a program is not registered +with the +.Tn RPC +package. +Service implementors usually do not need this routine. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_systemerr "SVCXPRT *xprt" +.Xc +.Pp +Called by a service dispatch routine when it detects a system +error +not covered by any particular protocol. +For example, if a service can no longer allocate storage, +it may call this routine. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn svcerr_weakauth "SVCXPRT *xprt" +.Xc +.Pp +Called by a service dispatch routine that refuses to perform +a remote procedure call due to insufficient +authentication arguments. +The routine calls +.Fn svcerr_auth xprt AUTH_TOOWEAK . +.Pp +.It Xo +.Ft "SVCXPRT *" +.Xc +.It Xo +.Fn svcraw_create void +.Xc +.Pp +This routine creates a toy +.Tn RPC +service transport, to which it returns a pointer. +The transport +is really a buffer within the process's address space, +so the corresponding +.Tn RPC +client should live in the same +address space; +see +.Fn clntraw_create . +This routine allows simulation of +.Tn RPC +and acquisition of +.Tn RPC +overheads (such as round trip times), without any kernel +interference. +This routine returns +.Dv NULL +if it fails. +.Pp +.It Xo +.Ft "SVCXPRT *" +.Xc +.It Xo +.Fn svctcp_create "int sock" "u_int send_buf_size" "u_int recv_buf_size" +.Xc +.Pp +This routine creates a +.Tn TCP/IP Ns \-based +.Tn RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.Fa sock , +which may be +.Dv RPC_ANYSOCK , +in which case a new socket is created. +If the socket is not bound to a local +.Tn TCP +port, then this routine binds it to an arbitrary port. +Upon completion, +.Fa xprt\->xp_fd +is the transport's socket descriptor, and +.Fa xprt\->xp_port +is the transport's port number. +This routine returns +.Dv NULL +if it fails. +Since +.Tn TCP Ns \-based +.Tn RPC +uses buffered +.Tn I/O , +users may specify the size of buffers; values of zero +choose suitable defaults. +.Pp +.It Xo +.Ft "SVCXPRT *" +.Xc +.It Xo +.Fn svcunix_create "int sock" "u_int send_buf_size" "u_int recv_buf_size" "char *path" +.Xc +.Pp +This routine creates a +.Ux Ns -based +.Tn RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.Fa sock , +which may be +.Dv RPC_ANYSOCK , +in which case a new socket is created. +The +.Fa *path +argument +is a variable-length file system pathname of +at most 104 characters. +This file is +.Em not +removed when the socket is closed. +The +.Xr unlink 2 +system call must be used to remove the file. +Upon completion, +.Fa xprt\->xp_fd +is the transport's socket descriptor. +This routine returns +.Dv NULL +if it fails. +Since +.Ux Ns -based +.Tn RPC +uses buffered +.Tn I/O , +users may specify the size of buffers; values of zero +choose suitable defaults. +.Pp +.It Xo +.Ft "SVCXPRT *" +.Xc +.It Xo +.Fn svcunixfd_create "int fd" "u_int sendsize" "u_int recvsize" +.Xc +.Pp +Create a service on top of any open descriptor. +The +.Fa sendsize +and +.Fa recvsize +arguments +indicate sizes for the send and receive buffers. +If they are +zero, a reasonable default is chosen. +.Pp +.It Xo +.Ft "SVCXPRT *" +.Xc +.It Xo +.Fn svcfd_create "int fd" "u_int sendsize" "u_int recvsize" +.Xc +.Pp +Create a service on top of any open descriptor. +Typically, +this +descriptor is a connected socket for a stream protocol such +as +.Tn TCP . +The +.Fa sendsize +and +.Fa recvsize +arguments +indicate sizes for the send and receive buffers. +If they are +zero, a reasonable default is chosen. +.Pp +.It Xo +.Ft "SVCXPRT *" +.Xc +.It Xo +.Fn svcudp_bufcreate "int sock" "u_int sendsize" "u_int recvsize" +.Xc +.Pp +This routine creates a +.Tn UDP/IP Ns \-based +.Tn RPC +service transport, to which it returns a pointer. +The transport is associated with the socket +.Fa sock , +which may be +.Dv RPC_ANYSOCK , +in which case a new socket is created. +If the socket is not bound to a local +.Tn UDP +port, then this routine binds it to an arbitrary port. +Upon +completion, +.Fa xprt\->xp_fd +is the transport's socket descriptor, and +.Fa xprt\->xp_port +is the transport's port number. +This routine returns +.Dv NULL +if it fails. +.Pp +This allows the user to specify the maximum packet size for sending and +receiving +.Tn UDP Ns \-based +.Tn RPC +messages. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_accepted_reply "XDR *xdrs" "struct accepted_reply *ar" +.Xc +.Pp +Used for encoding +.Tn RPC +reply messages. +This routine is useful for users who +wish to generate +.Tn RPC Ns \-style +messages without using the +.Tn RPC +package. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_authunix_parms "XDR *xdrs" "struct authunix_parms *aupp" +.Xc +.Pp +Used for describing +.Ux +credentials. +This routine is useful for users +who wish to generate these credentials without using the +.Tn RPC +authentication package. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Ft bool_t +.Fn xdr_callhdr "XDR *xdrs" "struct rpc_msg *chdr" +.Xc +.Pp +Used for describing +.Tn RPC +call header messages. +This routine is useful for users who wish to generate +.Tn RPC Ns \-style +messages without using the +.Tn RPC +package. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_callmsg "XDR *xdrs" "struct rpc_msg *cmsg" +.Xc +.Pp +Used for describing +.Tn RPC +call messages. +This routine is useful for users who wish to generate +.Tn RPC Ns \-style +messages without using the +.Tn RPC +package. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_opaque_auth "XDR *xdrs" "struct opaque_auth *ap" +.Xc +.Pp +Used for describing +.Tn RPC +authentication information messages. +This routine is useful for users who wish to generate +.Tn RPC Ns \-style +messages without using the +.Tn RPC +package. +.Pp +.It Xo +.Vt struct pmap ; +.Xc +.It Xo +.Ft bool_t +.Fn xdr_pmap "XDR *xdrs" "struct pmap *regs" +.Xc +.Pp +Used for describing arguments to various +.Xr rpcbind 8 +procedures, externally. +This routine is useful for users who wish to generate +these arguments without using the +.Fn pmap_* +interface. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_pmaplist "XDR *xdrs" "struct pmaplist **rp" +.Xc +.Pp +Used for describing a list of port mappings, externally. +This routine is useful for users who wish to generate +these arguments without using the +.Fn pmap_* +interface. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_rejected_reply "XDR *xdrs" "struct rejected_reply *rr" +.Xc +.Pp +Used for describing +.Tn RPC +reply messages. +This routine is useful for users who wish to generate +.Tn RPC Ns \-style +messages without using the +.Tn RPC +package. +.Pp +.It Xo +.Ft bool_t +.Fn xdr_replymsg "XDR *xdrs" "struct rpc_msg *rmsg" +.Xc +.Pp +Used for describing +.Tn RPC +reply messages. +This routine is useful for users who wish to generate +.Tn RPC +style messages without using the +.Tn RPC +package. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn xprt_register "SVCXPRT *xprt" +.Xc +.Pp +After +.Tn RPC +service transport handles are created, +they should register themselves with the +.Tn RPC +service package. +This routine modifies the global variable +.Va svc_fds . +Service implementors usually do not need this routine. +.Pp +.It Xo +.Ft void +.Xc +.It Xo +.Fn xprt_unregister "SVCXPRT *xprt" +.Xc +.Pp +Before an +.Tn RPC +service transport handle is destroyed, +it should unregister itself with the +.Tn RPC +service package. +This routine modifies the global variable +.Va svc_fds . +Service implementors usually do not need this routine. +.El +.Sh SEE ALSO +.Xr rpc_secure 3 , +.Xr xdr 3 +.Rs +.%T "Remote Procedure Calls: Protocol Specification" +.Re +.Rs +.%T "Remote Procedure Call Programming Guide" +.Re +.Rs +.%T "rpcgen Programming Guide" +.Re +.Rs +.%T "RPC: Remote Procedure Call Protocol Specification" +.%O RFC1050 +.%Q "Sun Microsystems, Inc., USC-ISI" +.Re diff --git a/libtirpc/man/rpc_svc_calls.3t b/libtirpc/man/rpc_svc_calls.3t new file mode 100644 index 0000000..582b45d --- /dev/null +++ b/libtirpc/man/rpc_svc_calls.3t @@ -0,0 +1,267 @@ +.\" @(#)rpc_svc_calls.3n 1.28 93/05/10 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_calls 1.5 89/07/25 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_svc_calls.3,v 1.1 2000/06/02 23:11:13 fvdl Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpc_svc_calls.3,v 1.8 2003/09/08 19:57:15 ru Exp $ +.Dd May 3, 1993 +.Dt RPC_SVC_CALLS 3 +.Os +.Sh NAME +.Nm svc_dg_enablecache , +.Nm svc_exit , +.Nm svc_fdset , +.Nm svc_freeargs , +.Nm svc_getargs , +.Nm svc_getreq_common , +.Nm svc_getreq_poll , +.Nm svc_getreqset , +.Nm svc_getrpccaller , +.Nm svc_pollset , +.Nm svc_run , +.Nm svc_sendreply +.Nd library routines for RPC servers +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft int +.Fn svc_dg_enablecache "SVCXPRT *xprt" "const unsigned cache_size" +.Ft void +.Fn svc_exit "void" +.Ft bool_t +.Fn svc_freeargs "const SVCXPRT *xprt" "const xdrproc_t inproc" "caddr_t in" +.Ft bool_t +.Fn svc_getargs "const SVCXPRT *xprt" "const xdrproc_t inproc" "caddr_t in" +.Ft void +.Fn svc_getreq_common "const int fd" +.Ft void +.Fn svc_getreq_poll "struct pollfd *pfdp" "const int pollretval" +.Ft void +.Fn svc_getreqset "fd_set * rdfds" +.Ft "struct netbuf *" +.Fn svc_getrpccaller "const SVCXPRT *xprt" +.Ft "struct cmsgcred *" +.Fn __svc_getcallercreds "const SVCXPRT *xprt" +.Vt struct pollfd svc_pollset[FD_SETSIZE]; +.Ft void +.Fn svc_run "void" +.Ft bool_t +.Fn svc_sendreply "SVCXPRT *xprt" "xdrproc_t outproc" "char *out" +.Sh DESCRIPTION +These routines are part of the +RPC +library which allows C language programs to make procedure +calls on other machines across the network. +.Pp +These routines are associated with the server side of the +RPC mechanism. +Some of them are called by the server side dispatch function, +while others +(such as +.Fn svc_run ) +are called when the server is initiated. +.\" .Pp +.\" In the current implementation, the service transport handle, +.\" .Dv SVCXPRT , +.\" contains a single data area for decoding arguments and encoding results. +.\" Therefore, this structure cannot be freely shared between threads that call +.\" functions that do this. +.\" Routines on this page that are affected by this +.\" restriction are marked as unsafe for MT applications. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width __svc_getcallercreds() +.It Fn svc_dg_enablecache +This function allocates a duplicate request cache for the +service endpoint +.Fa xprt , +large enough to hold +.Fa cache_size +entries. +Once enabled, there is no way to disable caching. +This routine returns 0 if space necessary for a cache of the given size +was successfully allocated, and 1 otherwise. +.It Fn svc_exit +This function, when called by any of the RPC server procedure or +otherwise, causes +.Fn svc_run +to return. +.Pp +As currently implemented, +.Fn svc_exit +zeroes the +.Va svc_fdset +global variable. +If RPC server activity is to be resumed, +services must be reregistered with the RPC library +either through one of the +.Xr rpc_svc_create 3 +functions, or using +.Fn xprt_register . +The +.Fn svc_exit +function +has global scope and ends all RPC server activity. +.It Xo +.Vt fd_set Va svc_fdset +.Xc +A global variable reflecting the +RPC server's read file descriptor bit mask; it is suitable as an argument +to the +.Xr select 2 +system call. +This is only of interest +if service implementors do not call +.Fn svc_run , +but rather do their own asynchronous event processing. +This variable is read-only (do not pass its address to +.Xr select 2 ! ) , +yet it may change after calls to +.Fn svc_getreqset +or any creation routines. +.It Fn svc_freeargs +A function macro that frees any data allocated by the +RPC/XDR system when it decoded the arguments to a service procedure +using +.Fn svc_getargs . +This routine returns +.Dv TRUE +if the results were successfully +freed, and +.Dv FALSE +otherwise. +.It Fn svc_getargs +A function macro that decodes the arguments of an +RPC request associated with the RPC +service transport handle +.Fa xprt . +The +.Fa in +argument +is the address where the arguments will be placed; +.Fa inproc +is the XDR +routine used to decode the arguments. +This routine returns +.Dv TRUE +if decoding succeeds, and +.Dv FALSE +otherwise. +.It Fn svc_getreq_common +This routine is called to handle a request on the given +file descriptor. +.It Fn svc_getreq_poll +This routine is only of interest if a service implementor +does not call +.Fn svc_run , +but instead implements custom asynchronous event processing. +It is called when +.Xr poll 2 +has determined that an RPC request has arrived on some RPC +file descriptors; +.Fa pollretval +is the return value from +.Xr poll 2 +and +.Fa pfdp +is the array of +.Vt pollfd +structures on which the +.Xr poll 2 +was done. +It is assumed to be an array large enough to +contain the maximal number of descriptors allowed. +.It Fn svc_getreqset +This routine is only of interest if a service implementor +does not call +.Fn svc_run , +but instead implements custom asynchronous event processing. +It is called when +.Xr poll 2 +has determined that an RPC +request has arrived on some RPC file descriptors; +.Fa rdfds +is the resultant read file descriptor bit mask. +The routine returns when all file descriptors +associated with the value of +.Fa rdfds +have been serviced. +.It Fn svc_getrpccaller +The approved way of getting the network address of the caller +of a procedure associated with the +RPC service transport handle +.Fa xprt . +.It Fn __svc_getcallercreds +.Em Warning : +this macro is specific to +.Fx +and thus not portable. +This macro returns a pointer to a +.Vt cmsgcred +structure, defined in +.In sys/socket.h , +identifying the calling client. +This only works if the client is +calling the server over an +.Dv AF_LOCAL +socket. +.It Xo +.Vt struct pollfd Va svc_pollset[FD_SETSIZE] ; +.Xc +.Va svc_pollset +is an array of +.Vt pollfd +structures derived from +.Va svc_fdset[] . +It is suitable as an argument to the +.Xr poll 2 +system call. +The derivation of +.Va svc_pollset +from +.Va svc_fdset +is made in the current implementation in +.Fn svc_run . +Service implementors who do not call +.Fn svc_run +and who wish to use this array must perform this derivation themselves. +.It Fn svc_run +This routine never returns. +It waits for RPC +requests to arrive, and calls the appropriate service +procedure using +.Fn svc_getreq_poll +when one arrives. +This procedure is usually waiting for the +.Xr poll 2 +system call to return. +.It Fn svc_sendreply +Called by an RPC service's dispatch routine to send the results of a +remote procedure call. +The +.Fa xprt +argument +is the request's associated transport handle; +.Fa outproc +is the XDR +routine which is used to encode the results; and +.Fa out +is the address of the results. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +otherwise. +.El +.Sh SEE ALSO +.Xr poll 2 , +.Xr select 2 , +.Xr rpc 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 diff --git a/libtirpc/man/rpc_svc_create.3t b/libtirpc/man/rpc_svc_create.3t new file mode 100644 index 0000000..d47be2b --- /dev/null +++ b/libtirpc/man/rpc_svc_create.3t @@ -0,0 +1,337 @@ +.\" @(#)rpc_svc_create.3n 1.26 93/08/26 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_create 1.3 89/06/28 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD: src/lib/libc/rpc/rpc_svc_create.3,v 1.7 2003/09/08 19:57:15 ru Exp $ +.Dd May 3, 1993 +.Dt RPC_SVC_CREATE 3 +.Os +.Sh NAME +.Nm rpc_svc_create , +.Nm svc_control , +.Nm svc_create , +.Nm svc_destroy , +.Nm svc_dg_create , +.Nm svc_fd_create , +.Nm svc_raw_create , +.Nm svc_tli_create , +.Nm svc_tp_create , +.Nm svc_vc_create +.Nd library routines for the creation of server handles +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft bool_t +.Fn svc_control "SVCXPRT *svc" "const u_int req" "void *info" +.Ft int +.Fn svc_create "void (*dispatch)(struct svc_req *, SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" +.Ft SVCXPRT * +.Fn svc_dg_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Ft void +.Fn svc_destroy "SVCXPRT *xprt" +.Ft "SVCXPRT *" +.Fn svc_fd_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Ft "SVCXPRT *" +.Fn svc_raw_create "void" +.Ft "SVCXPRT *" +.Fn svc_tli_create "const int fildes" "const struct netconfig *netconf" "const struct t_bind *bindaddr" "const u_int sendsz" "const u_int recvsz" +.Ft "SVCXPRT *" +.Fn svc_tp_create "void (*dispatch)(struct svc_req *, SVCXPRT *)" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Ft "SVCXPRT *" +.Fn svc_vc_create "const int fildes" "const u_int sendsz" "const u_int recvsz" +.Sh DESCRIPTION +These routines are part of the RPC +library which allows C language programs to make procedure +calls on servers across the network. +These routines deal with the creation of service handles. +Once the handle is created, the server can be invoked by calling +.Fn svc_run . +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn svc_control +A function to change or retrieve various information +about a service object. +The +.Fa req +argument +indicates the type of operation and +.Fa info +is a pointer to the information. +The supported values of +.Fa req , +their argument types, and what they do are: +.Bl -tag -width SVCGET_XID +.It Dv SVCGET_VERSQUIET +If a request is received for a program number +served by this server but the version number +is outside the range registered with the server, +an +.Dv RPC_PROGVERSMISMATCH +error will normally +be returned. +The +.Fa info +argument +should be a pointer to an +integer. +Upon successful completion of the +.Dv SVCGET_VERSQUIET +request, +.Fa *info +contains an +integer which describes the server's current +behavior: 0 indicates normal server behavior +(that is, an +.Dv RPC_PROGVERSMISMATCH +error +will be returned); 1 indicates that the out of +range request will be silently ignored. +.It Dv SVCSET_VERSQUIET +If a request is received for a program number +served by this server but the version number +is outside the range registered with the server, +an +.Dv RPC_PROGVERSMISMATCH +error will normally +be returned. +It is sometimes desirable to +change this behavior. +The +.Fa info +argument +should be a +pointer to an integer which is either 0 +(indicating normal server behavior - an +.Dv RPC_PROGVERSMISMATCH +error will be returned), +or 1 (indicating that the out of range request +should be silently ignored). +.El +.It Fn svc_create +The +.Fn svc_create +function +creates server handles for all the transports +belonging to the class +.Fa nettype . +The +.Fa nettype +argument +defines a class of transports which can be used +for a particular application. +The transports are tried in left to right order in +.Ev NETPATH +variable or in top to bottom order in the netconfig database. +If +.Fa nettype +is +.Dv NULL , +it defaults to +.Qq netpath . +.Pp +The +.Fn svc_create +function +registers itself with the rpcbind +service (see +.Xr rpcbind 8 ) . +The +.Fa dispatch +function +is called when there is a remote procedure call for the given +.Fa prognum +and +.Fa versnum ; +this requires calling +.Fn svc_run +(see +.Fn svc_run +in +.Xr rpc_svc_reg 3 ) . +If +.Fn svc_create +succeeds, it returns the number of server +handles it created, +otherwise it returns 0 and an error message is logged. +.It Fn svc_destroy +A function macro that destroys the RPC +service handle +.Fa xprt . +Destruction usually involves deallocation +of private data structures, +including +.Fa xprt +itself. +Use of +.Fa xprt +is undefined after calling this routine. +.It Fn svc_dg_create +This routine creates a connectionless RPC +service handle, and returns a pointer to it. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +The +.Fa sendsz +and +.Fa recvsz +arguments +are arguments used to specify the size of the buffers. +If they are 0, suitable defaults are chosen. +The file descriptor +.Fa fildes +should be open and bound. +The server is not registered with +.Xr rpcbind 8 . +.Pp +Warning: +since connectionless-based RPC +messages can only hold limited amount of encoded data, +this transport cannot be used for procedures +that take large arguments or return huge results. +.It Fn svc_fd_create +This routine creates a service on top of an open and bound file descriptor, +and returns the handle to it. +Typically, this descriptor is a connected file descriptor for a +connection-oriented transport. +The +.Fa sendsz +and +.Fa recvsz +arguments +indicate sizes for the send and receive buffers. +If they are 0, reasonable defaults are chosen. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.It Fn svc_raw_create +This routine creates an RPC +service handle and returns a pointer to it. +The transport is really a buffer within the process's +address space, so the corresponding RPC +client should live in the same address space; +(see +.Fn clnt_raw_create +in +.Xr rpc_clnt_create 3 ) . +This routine allows simulation of RPC and acquisition of +RPC overheads (such as round trip times), +without any kernel and networking interference. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +.Pp +Note: +.Fn svc_run +should not be called when the raw interface is being used. +.It Fn svc_tli_create +This routine creates an RPC +server handle, and returns a pointer to it. +The +.Fa fildes +argument +is the file descriptor on which the service is listening. +If +.Fa fildes +is +.Dv RPC_ANYFD , +it opens a file descriptor on the transport specified by +.Fa netconf . +If the file descriptor is unbound and +.Fa bindaddr +is not +.Dv NULL , +.Fa fildes +is bound to the address specified by +.Fa bindaddr , +otherwise +.Fa fildes +is bound to a default address chosen by the transport. +.Pp +Note: the +.Vt t_bind +structure comes from the TLI/XTI SysV interface, which +.Nx +does not use. +The structure is defined in +.In rpc/types.h +for compatibility as: +.Bd -literal +struct t_bind { + struct netbuf addr; /* network address, see rpc(3) */ + unsigned int qlen; /* queue length (for listen(2)) */ +}; +.Ed +.Pp +In the case where the default address is chosen, +the number of outstanding connect requests is set to 8 +for connection-oriented transports. +The user may specify the size of the send and receive buffers +with the arguments +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +This routine returns +.Dv NULL +if it fails, +and an error message is logged. +The server is not registered with the +.Xr rpcbind 8 +service. +.It Fn svc_tp_create +The +.Fn svc_tp_create +function +creates a server handle for the network +specified by +.Fa netconf , +and registers itself with the rpcbind service. +The +.Fa dispatch +function +is called when there is a remote procedure call +for the given +.Fa prognum +and +.Fa versnum ; +this requires calling +.Fn svc_run . +The +.Fn svc_tp_create +function +returns the service handle if it succeeds, +otherwise a +.Dv NULL +is returned and an error message is logged. +.It Fn svc_vc_create +This routine creates a connection-oriented RPC +service and returns a pointer to it. +This routine returns +.Dv NULL +if it fails, and an error message is logged. +The users may specify the size of the send and receive buffers +with the arguments +.Fa sendsz +and +.Fa recvsz ; +values of 0 choose suitable defaults. +The file descriptor +.Fa fildes +should be open and bound. +The server is not registered with the +.Xr rpcbind 8 +service. +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_err 3 , +.Xr rpc_svc_reg 3 , +.Xr rpcbind 8 diff --git a/libtirpc/man/rpc_svc_err.3t b/libtirpc/man/rpc_svc_err.3t new file mode 100644 index 0000000..49139cb --- /dev/null +++ b/libtirpc/man/rpc_svc_err.3t @@ -0,0 +1,97 @@ +.\" @(#)rpc_svc_err.3n 1.23 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_err 1.4 89/06/28 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_svc_err.3,v 1.1 2000/06/02 23:11:14 fvdl Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpc_svc_err.3,v 1.4 2002/12/19 09:40:23 ru Exp $ +.Dd May 3, 1993 +.Dt RPC_SVC_ERR 3 +.Os +.Sh NAME +.Nm rpc_svc_err , +.Nm svcerr_auth , +.Nm svcerr_decode , +.Nm svcerr_noproc , +.Nm svcerr_noprog , +.Nm svcerr_progvers , +.Nm svcerr_systemerr , +.Nm svcerr_weakauth +.Nd library routines for server side remote procedure call errors +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft void +.Fn svcerr_auth "SVCXPRT *xprt" "enum auth_stat why" +.Ft void +.Fn svcerr_decode "SVCXPRT *xprt" +.Ft void +.Fn svcerr_noproc "SVCXPRT *xprt" +.Ft void +.Fn svcerr_noprog "SVCXPRT *xprt" +.Ft void +.Fn svcerr_progvers "SVCXPRT *xprt" "rpcvers_t low_vers" "rpcvers_t high_vers" +.Ft void +.Fn svcerr_systemerr "SVCXPRT *xprt" +.Ft void +.Fn svcerr_weakauth "SVCXPRT *xprt" +.Sh DESCRIPTION +These routines are part of the RPC +library which allows C language programs to make procedure +calls on other machines across the network. +.Pp +These routines can be called by the server side +dispatch function if there is any error in the +transaction with the client. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn svcerr_auth +Called by a service dispatch routine that refuses to perform +a remote procedure call due to an authentication error. +.It Fn svcerr_decode +Called by a service dispatch routine that cannot successfully +decode the remote arguments +(see +.Fn svc_getargs +in +.Xr rpc_svc_reg 3 ) . +.It Fn svcerr_noproc +Called by a service dispatch routine that does not implement +the procedure number that the caller requests. +.It Fn svcerr_noprog +Called when the desired program is not registered with the +RPC package. +Service implementors usually do not need this routine. +.It Fn svcerr_progvers +Called when the desired version of a program is not registered with the +RPC package. +The +.Fa low_vers +argument +is the lowest version number, +and +.Fa high_vers +is the highest version number. +Service implementors usually do not need this routine. +.It Fn svcerr_systemerr +Called by a service dispatch routine when it detects a system +error not covered by any particular protocol. +For example, if a service can no longer allocate storage, +it may call this routine. +.It Fn svcerr_weakauth +Called by a service dispatch routine that refuses to perform +a remote procedure call due to insufficient (but correct) +authentication arguments. +The routine calls +.Fn svcerr_auth "xprt" "AUTH_TOOWEAK" . +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_reg 3 diff --git a/libtirpc/man/rpc_svc_reg.3t b/libtirpc/man/rpc_svc_reg.3t new file mode 100644 index 0000000..56dd530 --- /dev/null +++ b/libtirpc/man/rpc_svc_reg.3t @@ -0,0 +1,183 @@ +.\" @(#)rpc_svc_reg.3n 1.32 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_svc_call 1.6 89/07/20 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $NetBSD: rpc_svc_reg.3,v 1.1 2000/06/02 23:11:14 fvdl Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpc_svc_reg.3,v 1.5 2002/12/19 09:40:23 ru Exp $ +.Dd May 3, 1993 +.Dt RPC_SVC_REG 3 +.Os +.Sh NAME +.Nm rpc_svc_reg , +.Nm rpc_reg , +.Nm svc_reg , +.Nm svc_unreg , +.Nm svc_auth_reg , +.Nm xprt_register , +.Nm xprt_unregister +.Nd library routines for registering servers +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft int +.Fn rpc_reg "rpcprog_t prognum" "rpcvers_t versnum" "rpcproc_t procnum" "char *(*procname)()" "xdrproc_t inproc" "xdrproc_t outproc" "char *nettype" +.Ft bool_t +.Fn svc_reg "SVCXPRT *xprt" "const rpcprog_t prognum" "const rpcvers_t versnum" "void (*dispatch)(struct svc_req *, SVCXPRT *)" "const struct netconfig *netconf" +.Ft void +.Fn svc_unreg "const rpcprog_t prognum" "const rpcvers_t versnum" +.Ft int +.Fn svc_auth_reg "int cred_flavor" "enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *)" +.Ft void +.Fn xprt_register "SVCXPRT *xprt" +.Ft void +.Fn xprt_unregister "SVCXPRT *xprt" +.Sh DESCRIPTION +These routines are a part of the RPC +library which allows the RPC +servers to register themselves with rpcbind +(see +.Xr rpcbind 8 ) , +and associate the given program and version +number with the dispatch function. +When the RPC server receives a RPC request, the library invokes the +dispatch routine with the appropriate arguments. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt SVCXPRT +data structure. +.Bl -tag -width XXXXX +.It Fn rpc_reg +Register program +.Fa prognum , +procedure +.Fa procname , +and version +.Fa versnum +with the RPC +service package. +If a request arrives for program +.Fa prognum , +version +.Fa versnum , +and procedure +.Fa procnum , +.Fa procname +is called with a pointer to its argument(s); +.Fa procname +should return a pointer to its static result(s); +.Fa inproc +is the XDR function used to decode the arguments while +.Fa outproc +is the XDR function used to encode the results. +Procedures are registered on all available transports of the class +.Fa nettype . +See +.Xr rpc 3 . +This routine returns 0 if the registration succeeded, +\-1 otherwise. +.It Fn svc_reg +Associates +.Fa prognum +and +.Fa versnum +with the service dispatch procedure, +.Fa dispatch . +If +.Fa netconf +is +.Dv NULL , +the service is not registered with the +.Xr rpcbind 8 +service. +If +.Fa netconf +is non-zero, +then a mapping of the triple +.Bq Fa prognum , versnum , netconf->nc_netid +to +.Fa xprt->xp_ltaddr +is established with the local rpcbind +service. +.Pp +The +.Fn svc_reg +routine returns 1 if it succeeds, +and 0 otherwise. +.It Fn svc_unreg +Remove from the rpcbind +service, all mappings of the triple +.Bq Fa prognum , versnum , No all-transports +to network address +and all mappings within the RPC service package +of the double +.Bq Fa prognum , versnum +to dispatch routines. +.It Fn svc_auth_reg +Registers the service authentication routine +.Fa handler +with the dispatch mechanism so that it can be +invoked to authenticate RPC requests received +with authentication type +.Fa cred_flavor . +This interface allows developers to add new authentication +types to their RPC applications without needing to modify +the libraries. +Service implementors usually do not need this routine. +.Pp +Typical service application would call +.Fn svc_auth_reg +after registering the service and prior to calling +.Fn svc_run . +When needed to process an RPC credential of type +.Fa cred_flavor , +the +.Fa handler +procedure will be called with two arguments, +.Fa "struct svc_req *rqst" +and +.Fa "struct rpc_msg *msg" , +and is expected to return a valid +.Vt "enum auth_stat" +value. +There is no provision to change or delete an authentication handler +once registered. +.Pp +The +.Fn svc_auth_reg +routine returns 0 if the registration is successful, +1 if +.Fa cred_flavor +already has an authentication handler registered for it, +and \-1 otherwise. +.It Fn xprt_register +After RPC service transport handle +.Fa xprt +is created, it is registered with the RPC +service package. +This routine modifies the global variable +.Va svc_fdset +(see +.Xr rpc_svc_calls 3 ) . +Service implementors usually do not need this routine. +.It Fn xprt_unregister +Before an RPC service transport handle +.Fa xprt +is destroyed, it unregisters itself with the +RPC service package. +This routine modifies the global variable +.Va svc_fdset +(see +.Xr rpc_svc_calls 3 ) . +Service implementors usually do not need this routine. +.El +.Sh SEE ALSO +.Xr select 2 , +.Xr rpc 3 , +.Xr rpcbind 3 , +.Xr rpc_svc_calls 3 , +.Xr rpc_svc_create 3 , +.Xr rpc_svc_err 3 , +.Xr rpcbind 8 diff --git a/libtirpc/man/rpc_xdr.3t b/libtirpc/man/rpc_xdr.3t new file mode 100644 index 0000000..feb708b --- /dev/null +++ b/libtirpc/man/rpc_xdr.3t @@ -0,0 +1,101 @@ +.\" @(#)rpc_xdr.3n 1.24 93/08/31 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" @(#)rpc_xdr.new 1.1 89/04/06 SMI; +.\" Copyright (c) 1988 Sun Microsystems, Inc. - All Rights Reserved. +.\" $FreeBSD: src/lib/libc/rpc/rpc_xdr.3,v 1.3 2001/10/03 16:47:56 bde Exp $ +.Dd May 3, 1993 +.Dt RPC_XDR 3 +.Os +.Sh NAME +.Nm xdr_accepted_reply , +.Nm xdr_authsys_parms , +.Nm xdr_callhdr , +.Nm xdr_callmsg , +.Nm xdr_opaque_auth , +.Nm xdr_rejected_reply , +.Nm xdr_replymsg +.Nd XDR library routines for remote procedure calls +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft bool_t +.Fn xdr_accepted_reply "XDR *xdrs" "struct accepted_reply *ar" +.Ft bool_t +.Fn xdr_authsys_parms "XDR *xdrs" "struct authsys_parms *aupp" +.Ft bool_t +.Fn xdr_callhdr "XDR *xdrs" "struct rpc_msg *chdr" +.Ft bool_t +.Fn xdr_callmsg "XDR *xdrs" "struct rpc_msg *cmsg" +.Ft bool_t +.Fn xdr_opaque_auth "XDR *xdrs" "struct opaque_auth *ap" +.Ft bool_t +.Fn xdr_rejected_reply "XDR *xdrs" "struct rejected_reply *rr" +.Ft bool_t +.Fn xdr_replymsg "XDR *xdrs" "struct rpc_msg *rmsg" +.Sh DESCRIPTION +These routines are used for describing the +RPC messages in XDR language. +They should normally be used by those who do not +want to use the RPC +package directly. +These routines return +.Dv TRUE +if they succeed, +.Dv FALSE +otherwise. +.Sh Routines +See +.Xr rpc 3 +for the definition of the +.Vt XDR +data structure. +.Bl -tag -width XXXXX +.It Fn xdr_accepted_reply +Used to translate between RPC +reply messages and their external representation. +It includes the status of the RPC +call in the XDR language format. +In the case of success, it also includes the call results. +.It Fn xdr_authsys_parms +Used for describing +.Ux +operating system credentials. +It includes machine-name, uid, gid list, etc. +.It Fn xdr_callhdr +Used for describing +RPC +call header messages. +It encodes the static part of the call message header in the +XDR language format. +It includes information such as transaction +ID, RPC version number, program and version number. +.It Fn xdr_callmsg +Used for describing +RPC call messages. +This includes all the RPC +call information such as transaction +ID, RPC version number, program number, version number, +authentication information, etc. +This is normally used by servers to determine information about the client +RPC call. +.It Fn xdr_opaque_auth +Used for describing RPC +opaque authentication information messages. +.It Fn xdr_rejected_reply +Used for describing RPC reply messages. +It encodes the rejected RPC message in the XDR language format. +The message could be rejected either because of version +number mis-match or because of authentication errors. +.It Fn xdr_replymsg +Used for describing RPC +reply messages. +It translates between the +RPC reply message and its external representation. +This reply could be either an acceptance, +rejection or +.Dv NULL . +.El +.Sh SEE ALSO +.Xr rpc 3 , +.Xr xdr 3 diff --git a/libtirpc/man/rpcbind.3t b/libtirpc/man/rpcbind.3t new file mode 100644 index 0000000..99b03cf --- /dev/null +++ b/libtirpc/man/rpcbind.3t @@ -0,0 +1,194 @@ +.\" @(#)rpcbind.3n 1.25 93/05/07 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" Copyright (c) 1988 Sun Microsystem's, Inc. - All Right's Reserved. +.\" $NetBSD: rpcbind.3,v 1.2 2000/06/03 18:47:28 fvdl Exp $ +.\" $FreeBSD: src/lib/libc/rpc/rpcbind.3,v 1.5 2002/12/19 09:40:23 ru Exp $ +.Dd May 7, 1993 +.Dt RPCBIND 3 +.Os +.Sh NAME +.Nm rpcb_getmaps , +.Nm rpcb_getaddr , +.Nm rpcb_gettime , +.Nm rpcb_rmtcall , +.Nm rpcb_set , +.Nm rpcb_unset +.Nd library routines for RPC bind service +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In rpc/rpc.h +.Ft "rpcblist *" +.Fn rpcb_getmaps "const struct netconfig *netconf" "const char *host" +.Ft bool_t +.Fn rpcb_getaddr "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "struct netbuf *svcaddr" "const char *host" +.Ft bool_t +.Fn rpcb_gettime "const char *host" "time_t * timep" +.Ft "enum clnt_stat" +.Fn rpcb_rmtcall "const struct netconfig *netconf" "const char *host" "const rpcprog_t prognum, const rpcvers_t versnum" "const rpcproc_t procnum, const xdrproc_t inproc" "const caddr_t in" "const xdrproc_t outproc" "const caddr_t out" "const struct timeval tout, const struct netbuf *svcaddr" +.Ft bool_t +.Fn rpcb_set "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct netbuf *svcaddr" +.Ft bool_t +.Fn rpcb_unset "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" +.Sh DESCRIPTION +These routines allow client C programs to make procedure +calls to the RPC binder service. +(see +.Xr rpcbind 8 ) +maintains a list of mappings between programs +and their universal addresses. +.Sh Routines +.Bl -tag -width XXXXX +.It Fn rpcb_getmaps +An interface to the rpcbind service, +which returns a list of the current +RPC program-to-address mappings on +.Fa host . +It uses the transport specified through +.Fa netconf +to contact the remote rpcbind +service on +.Fa host . +This routine will return +.Dv NULL , +if the remote rpcbind could not be contacted. +.It Fn rpcb_getaddr +An interface to the rpcbind +service, which finds the address of the service on +.Fa host +that is registered with program number +.Fa prognum , +version +.Fa versnum , +and speaks the transport protocol associated with +.Fa netconf . +The address found is returned in +.Fa svcaddr . +The +.Fa svcaddr +argument +should be preallocated. +This routine returns +.Dv TRUE +if it succeeds. +A return value of +.Dv FALSE +means that the mapping does not exist +or that the RPC +system failed to contact the remote +rpcbind service. +In the latter case, the global variable +.Va rpc_createerr +(see +.Xr rpc_clnt_create 3 ) +contains the +RPC status. +.It Fn rpcb_gettime +This routine returns the time on +.Fa host +in +.Fa timep . +If +.Fa host +is +.Dv NULL , +.Fn rpcb_gettime +returns the time on its own machine. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +if it fails. +The +.Fn rpcb_gettime +function +can be used to synchronize the time between the +client and the remote server. +.It Fn rpcb_rmtcall +An interface to the rpcbind service, which instructs +rpcbind on +.Fa host +to make an RPC +call on your behalf to a procedure on that host. +The +.Fn netconfig +structure should correspond to a connectionless transport. +The +.Fa svcaddr +argument +will be modified to the server's address if the procedure succeeds +(see +.Fn rpc_call +and +.Fn clnt_call +in +.Xr rpc_clnt_calls 3 +for the definitions of other arguments). +.Pp +This procedure should normally be used for a +.Dq ping +and nothing else. +This routine allows programs to do lookup and call, all in one step. +.Pp +Note: Even if the server is not running +.Fn rpcb_rmtcall +does not return any error messages to the caller. +In such a case, the caller times out. +.Pp +Note: +.Fn rpcb_rmtcall +is only available for connectionless transports. +.It Fn rpcb_set +An interface to the rpcbind +service, which establishes a mapping between the triple +.Bq Fa prognum , versnum , netconf->nc_netid +and +.Fa svcaddr +on the machine's rpcbind +service. +The value of +.Fa nc_netid +must correspond to a network identifier that is defined by the +netconfig database. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +otherwise. +(See also +.Fn svc_reg +in +.Xr rpc_svc_calls 3 . ) +If there already exists such an entry with rpcbind, +.Fn rpcb_set +will fail. +.It Fn rpcb_unset +An interface to the rpcbind +service, which destroys the mapping between the triple +.Bq Fa prognum , versnum , netconf->nc_netid +and the address on the machine's rpcbind +service. +If +.Fa netconf +is +.Dv NULL , +.Fn rpcb_unset +destroys all mapping between the triple +.Bq Fa prognum , versnum , No all-transports +and the addresses on the machine's rpcbind service. +This routine returns +.Dv TRUE +if it succeeds, +.Dv FALSE +otherwise. +Only the owner of the service or the super-user can destroy the mapping. +(See also +.Fn svc_unreg +in +.Xr rpc_svc_calls 3 . ) +.El +.Sh SEE ALSO +.Xr rpc_clnt_calls 3 , +.Xr rpc_svc_calls 3 , +.Xr rpcbind 8 , +.Xr rpcinfo 8 diff --git a/libtirpc/man/rtime.3t b/libtirpc/man/rtime.3t new file mode 100644 index 0000000..6e61350 --- /dev/null +++ b/libtirpc/man/rtime.3t @@ -0,0 +1,50 @@ +.\" @(#)rtime.3n 2.1 88/08/08 4.0 RPCSRC; from 1.5 88/02/08 SMI +.\" $FreeBSD: src/lib/libc/rpc/rtime.3,v 1.8 2002/12/19 09:40:23 ru Exp $ +.\" +.Dd November 22, 1987 +.Dt RTIME 3 +.Os +.Sh NAME +.Nm rtime +.Nd "get remote time" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/types.h +.In sys/time.h +.In netinet/in.h +.Ft int +.Fo rtime +.Fa "struct sockaddr_in *addrp" +.Fa "struct timeval *timep" +.Fa "struct timeval *timeout" +.Fc +.Sh DESCRIPTION +The +.Fn rtime +function +consults the Internet Time Server at the address pointed to by +.Fa addrp +and returns the remote time in the +.Vt timeval +struct pointed to by +.Fa timep . +Normally, the +.Tn UDP +protocol is used when consulting the Time Server. +The +.Fa timeout +argument specifies how long the +routine should wait before giving +up when waiting for a reply. +If +.Fa timeout +is specified as +.Dv NULL , +however, the routine will instead use +.Tn TCP +and block until a reply is received from the time server. +.Sh RETURN VALUES +.Rv -std rtime +.Sh SEE ALSO +.Xr timed 8 diff --git a/libtirpc/src/Makefile.am b/libtirpc/src/Makefile.am new file mode 100644 index 0000000..7b002da --- /dev/null +++ b/libtirpc/src/Makefile.am @@ -0,0 +1,95 @@ +## Process this file with automake to create Makefile.in. + +## NOTE: this file doesn't really try to be complete. In particular +## `make dist' won't work at all. We're just aiming to get the +## program built. We also don't bother trying to assemble code, or +## anything like that. + + +INCLUDES = -I$(top_srcdir)/tirpc -DPORTMAP -DINET6 -DVERSION="\"$(VERSION)\"" \ + -D_GNU_SOURCE -Wall -pipe + +lib_LTLIBRARIES = libtirpc.la + +# +# Set the library version information +# +# According to the libtool manual: +# +# "This flag accepts an argument of the form current[:revision[:age]]. +# +# If either revision or age are omitted, they default to 0. Also note that +# age must be less than or equal to the current interface number. +# +# Here are a set of rules to help you update your library version information: +# +# 1. Start with version information of 0:0:0 for each libtool library. +# 2. Update the version information only immediately before a public +# release of your software. More frequent updates are unnecessary, +# and only guarantee that the current interface number gets larger faster. +# 3. If the library source code has changed at all since the last update, +# then increment revision (c:r:a becomes c:r+1:a). +# 4. If any interfaces have been added, removed, or changed since the last +# update, increment current, and set revision to 0. +# 5. If any interfaces have been added since the last public release, +# then increment age. +# 6. If any interfaces have been removed since the last public release, +# then set age to 0. +# +# _Never_ try to set the interface numbers so that they correspond to the +# release number of your package. This is an abuse that only fosters +# misunderstanding of the purpose of library versions." +# +libtirpc_la_LDFLAGS = -lnsl -lpthread -version-info 1:10:0 + +libtirpc_la_SOURCES = auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \ + clnt_dg.c clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c \ + clnt_vc.c rpc_dtablesize.c getnetconfig.c getnetpath.c getrpcent.c \ + getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \ + pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \ + rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \ + rpcb_st_xdr.c svc.c svc_auth.c svc_dg.c svc_auth_unix.c svc_generic.c \ + svc_raw.c svc_run.c svc_simple.c svc_vc.c getpeereid.c \ + auth_time.c auth_des.c authdes_prot.c + +## XDR +libtirpc_la_SOURCES += xdr.c xdr_rec.c xdr_array.c xdr_float.c xdr_mem.c xdr_reference.c xdr_stdio.c + +## Secure-RPC +if GSS + libtirpc_la_SOURCES += auth_gss.c authgss_prot.c svc_auth_gss.c \ + svc_auth_none.c + libtirpc_la_LDFLAGS += $(GSSGLUE_LIBS) + libtirpc_la_CFLAGS = -DHAVE_RPCSEC_GSS $(GSSGLUE_CFLAGS) +endif + +## libtirpc_a_SOURCES += key_call.c key_prot_xdr.c getpublickey.c +## libtirpc_a_SOURCES += netname.c netnamer.c rpcdname.c \ +## libtirpc_a_SOURCES += rtime.c \ +## auth_time.c auth_des.c authdes_prot.c + +if GSS +$(libtirpc_la_OBJECTS) :auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \ + clnt_dg.c clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c \ + clnt_vc.c rpc_dtablesize.c getnetconfig.c getnetpath.c getrpcent.c \ + getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \ + pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \ + rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \ + rpcb_st_xdr.c svc.c svc_auth.c svc_dg.c svc_auth_unix.c svc_generic.c \ + svc_raw.c svc_run.c svc_simple.c svc_vc.c \ + xdr.c xdr_rec.c xdr_array.c xdr_float.c xdr_mem.c xdr_reference.c xdr_stdio.c \ + auth_gss.c authgss_prot.c svc_auth_gss.c getpeereid.c \ + auth_time.c auth_des.c authdes_prot.c svc_auth_none.c + +else +$(libtirpc_la_OBJECTS) :auth_none.c auth_unix.c authunix_prot.c bindresvport.c clnt_bcast.c \ + clnt_dg.c clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c \ + clnt_vc.c rpc_dtablesize.c getnetconfig.c getnetpath.c getrpcent.c \ + getrpcport.c mt_misc.c pmap_clnt.c pmap_getmaps.c pmap_getport.c \ + pmap_prot.c pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c \ + rpc_callmsg.c rpc_generic.c rpc_soc.c rpcb_clnt.c rpcb_prot.c \ + rpcb_st_xdr.c svc.c svc_auth.c svc_dg.c svc_auth_unix.c svc_generic.c \ + svc_raw.c svc_run.c svc_simple.c svc_vc.c \ + xdr.c xdr_rec.c xdr_array.c xdr_float.c xdr_mem.c xdr_reference.c xdr_stdio.c \ + getpeereid.c auth_time.c auth_des.c authdes_prot.c +endif diff --git a/libtirpc/src/asprintf.c b/libtirpc/src/asprintf.c new file mode 100644 index 0000000..c5daed6 --- /dev/null +++ b/libtirpc/src/asprintf.c @@ -0,0 +1,105 @@ +/* Copyright (c) 2004 Darren Tucker. + * + * Based originally on asprintf.c from OpenBSD: + * Copyright (c) 1997 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +//extern int vsnprintf(); +#include +#include +#include + +/* Include vasprintf() if not on your OS. */ +#ifndef HAVE_VASPRINTF + +#include +#include +#include +#include + +#ifndef VA_COPY +# ifdef HAVE_VA_COPY +# define VA_COPY(dest, src) va_copy(dest, src) +# else +# ifdef HAVE___VA_COPY +# define VA_COPY(dest, src) __va_copy(dest, src) +# else +# define VA_COPY(dest, src) (dest) = (src) +# endif +# endif +#endif + +#define INIT_SZ 128 + +int +vasprintf(char **str, const char *fmt, va_list ap) +{ + int ret = -1; + va_list ap2; + char *string, *newstr; + size_t len; + + VA_COPY(ap2, ap); + if ((string = malloc(INIT_SZ)) == NULL) + goto fail; + + ret = _vsnprintf(string, INIT_SZ, fmt, ap2); + if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */ + *str = string; + } else if (ret == INT_MAX || ret < 0) { /* Bad length */ + goto fail; + } else { /* bigger than initial, realloc allowing for nul */ + len = (size_t)ret + 1; + if ((newstr = realloc(string, len)) == NULL) { + free(string); + goto fail; + } else { + va_end(ap2); + VA_COPY(ap2, ap); + ret = _vsnprintf(newstr, len, fmt, ap2); + if (ret >= 0 && (size_t)ret < len) { + *str = newstr; + } else { /* failed with realloc'ed string, give up */ + free(newstr); + goto fail; + } + } + } + va_end(ap2); + return (ret); + +fail: + *str = NULL; + errno = ENOMEM; + va_end(ap2); + return (-1); +} +#endif + +/* Include asprintf() if not on your OS. */ +#ifndef HAVE_ASPRINTF +int asprintf(char **str, const char *fmt, ...) +{ + va_list ap; + int ret; + + *str = NULL; + va_start(ap, fmt); + ret = vasprintf(str, fmt, ap); + va_end(ap); + + return ret; +} +#endif diff --git a/libtirpc/src/auth_des.c b/libtirpc/src/auth_des.c new file mode 100644 index 0000000..b515a0c --- /dev/null +++ b/libtirpc/src/auth_des.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* + * auth_des.c, client-side implementation of DES authentication + */ + +#include +//#include +#include +//#include +#include +#include +#include +//#include +//#include +#include +//#include +#include +#include +#include +#include +#include +//#include +#undef NIS +#include + +#if defined(LIBC_SCCS) && !defined(lint) +#endif +//#include + +#define USEC_PER_SEC 1000000 +#define RTIME_TIMEOUT 5 /* seconds to wait for sync */ + +#define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private +#define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type)) +#define FREE(ptr, size) mem_free((char *)(ptr), (int) size) +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); +extern int key_encryptsession_pk(); + +extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, + char **, char **); + +/* + * DES authenticator operations vector + */ +static void authdes_nextverf(AUTH *); +static bool_t authdes_marshal(AUTH *, XDR *); +static bool_t authdes_validate(AUTH *, struct opaque_auth *); +static bool_t authdes_refresh(AUTH *, void *); +static void authdes_destroy(AUTH *); + +static struct auth_ops *authdes_ops(void); + +/* + * This struct is pointed to by the ah_private field of an "AUTH *" + */ +struct ad_private { + char *ad_fullname; /* client's full name */ + u_int ad_fullnamelen; /* length of name, rounded up */ + char *ad_servername; /* server's full name */ + u_int ad_servernamelen; /* length of name, rounded up */ + u_int ad_window; /* client specified window */ + bool_t ad_dosync; /* synchronize? */ + struct netbuf ad_syncaddr; /* remote host to synch with */ + char *ad_timehost; /* remote host to synch with */ + struct timeval ad_timediff; /* server's time - client's time */ + u_int ad_nickname; /* server's nickname for client */ + struct authdes_cred ad_cred; /* storage for credential */ + struct authdes_verf ad_verf; /* storage for verifier */ + struct timeval ad_timestamp; /* timestamp sent */ + des_block ad_xkey; /* encrypted conversation key */ + u_char ad_pkey[1024]; /* Server's actual public key */ + char *ad_netid; /* Timehost netid */ + char *ad_uaddr; /* Timehost uaddr */ + nis_server *ad_nis_srvr; /* NIS+ server struct */ +}; + +AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *, + const des_block *, nis_server *); + +/* + * documented version of authdes_seccreate + */ +/* + servername: network name of server + win: time to live + timehost: optional hostname to sync with + ckey: optional conversation key to use +*/ + +AUTH * +authdes_seccreate(const char *servername, const u_int win, + const char *timehost, const des_block *ckey) +{ + u_char pkey_data[1024]; + netobj pkey; + AUTH *dummy; + + if (! getpublickey(servername, (char *) pkey_data)) { + //syslog(LOG_ERR, + // "authdes_seccreate: no public key found for %s", + // servername); + return (NULL); + } + + pkey.n_bytes = (char *) pkey_data; + pkey.n_len = (u_int)strlen((char *)pkey_data) + 1; + dummy = authdes_pk_seccreate(servername, &pkey, win, timehost, + ckey, NULL); + return (dummy); +} + +/* + * Slightly modified version of authdessec_create which takes the public key + * of the server principal as an argument. This spares us a call to + * getpublickey() which in the nameserver context can cause a deadlock. + */ +AUTH * +authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window, + const char *timehost, const des_block *ckey, nis_server *srvr) +{ + AUTH *auth; + struct ad_private *ad; + char namebuf[MAXNETNAMELEN+1]; + + /* + * Allocate everything now + */ + auth = ALLOC(AUTH); + if (auth == NULL) { + //syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); + return (NULL); + } + ad = ALLOC(struct ad_private); + if (ad == NULL) { + //syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); + goto failed; + } + ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ + ad->ad_timehost = NULL; + ad->ad_netid = NULL; + ad->ad_uaddr = NULL; + ad->ad_nis_srvr = NULL; + ad->ad_timediff.tv_sec = 0; + ad->ad_timediff.tv_usec = 0; + memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len); + if (!getnetname(namebuf)) + goto failed; + ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf)); + ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); + ad->ad_servernamelen = strlen(servername); + ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); + + if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { + //syslog(LOG_ERR, "authdes_seccreate: out of memory"); + goto failed; + } + if (timehost != NULL) { + ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); + if (ad->ad_timehost == NULL) { + //syslog(LOG_ERR, "authdes_seccreate: out of memory"); + goto failed; + } + memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); + ad->ad_dosync = TRUE; + } else if (srvr != NULL) { + ad->ad_nis_srvr = srvr; /* transient */ + ad->ad_dosync = TRUE; + } else { + ad->ad_dosync = FALSE; + } + memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1); + memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1); + ad->ad_window = window; + if (ckey == NULL) { + if (key_gendes(&auth->ah_key) < 0) { + //syslog(LOG_ERR, + // "authdes_seccreate: keyserv(1m) is unable to generate session key"); + goto failed; + } + } else { + auth->ah_key = *ckey; + } + + /* + * Set up auth handle + */ + auth->ah_cred.oa_flavor = AUTH_DES; + auth->ah_verf.oa_flavor = AUTH_DES; + auth->ah_ops = authdes_ops(); + auth->ah_private = (caddr_t)ad; + + if (!authdes_refresh(auth, NULL)) { + goto failed; + } + ad->ad_nis_srvr = NULL; /* not needed any longer */ + return (auth); + +failed: + if (auth) + FREE(auth, sizeof (AUTH)); + if (ad) { + if (ad->ad_fullname) + FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); + if (ad->ad_servername) + FREE(ad->ad_servername, ad->ad_servernamelen + 1); + if (ad->ad_timehost) + FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); + if (ad->ad_netid) + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); + if (ad->ad_uaddr) + FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); + FREE(ad, sizeof (struct ad_private)); + } + return (NULL); +} + +/* + * Implement the five authentication operations + */ + + +/* + * 1. Next Verifier + */ +/*ARGSUSED*/ +static void +authdes_nextverf(AUTH *auth) +{ + /* what the heck am I supposed to do??? */ +} + + +/* + * 2. Marshal + */ +static bool_t +authdes_marshal(AUTH *auth, XDR *xdrs) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_cred *cred = &ad->ad_cred; + struct authdes_verf *verf = &ad->ad_verf; + des_block cryptbuf[2]; + des_block ivec; + int status; + int len; + rpc_inline_t *ixdr; + + /* + * Figure out the "time", accounting for any time difference + * with the server if necessary. + */ + (void) gettimeofday(&ad->ad_timestamp, (struct timezone *)NULL); + ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; + ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; + while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) { + ad->ad_timestamp.tv_usec -= USEC_PER_SEC; + ad->ad_timestamp.tv_sec++; + } + + /* + * XDR the timestamp and possibly some other things, then + * encrypt them. + */ + ixdr = (rpc_inline_t *)cryptbuf; + IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec); + IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec); + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + IXDR_PUT_U_INT32(ixdr, ad->ad_window); + IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1); + ivec.key.high = ivec.key.low = 0; + status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf, + (u_int) 2 * sizeof (des_block), + DES_ENCRYPT | DES_HW, (char *)&ivec); + } else { + status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, + (u_int) sizeof (des_block), + DES_ENCRYPT | DES_HW); + } + if (DES_FAILED(status)) { + //syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); + return (FALSE); + } + ad->ad_verf.adv_xtimestamp = cryptbuf[0]; + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; + ad->ad_verf.adv_winverf = cryptbuf[1].key.low; + } else { + ad->ad_cred.adc_nickname = ad->ad_nickname; + ad->ad_verf.adv_winverf = 0; + } + + /* + * Serialize the credential and verifier into opaque + * authentication data. + */ + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); + } else { + len = (1 + 1)*BYTES_PER_XDR_UNIT; + } + + if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); + } else { + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); + } + ATTEMPT(xdr_authdes_cred(xdrs, cred)); + + len = (2 + 1)*BYTES_PER_XDR_UNIT; + if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); + } else { + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); + } + ATTEMPT(xdr_authdes_verf(xdrs, verf)); + return (TRUE); +} + + +/* + * 3. Validate + */ +static bool_t +authdes_validate(AUTH *auth, struct opaque_auth *rverf) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_verf verf; + int status; + uint32_t *ixdr; + des_block buf; + + if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { + return (FALSE); + } +/* LINTED pointer alignment */ + ixdr = (uint32_t *)rverf->oa_base; + buf.key.high = (uint32_t)*ixdr++; + buf.key.low = (uint32_t)*ixdr++; + verf.adv_int_u = (uint32_t)*ixdr++; + + /* + * Decrypt the timestamp + */ + status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, + (u_int)sizeof (des_block), DES_DECRYPT | DES_HW); + + if (DES_FAILED(status)) { + //syslog(LOG_ERR, "authdes_validate: DES decryption failure"); + return (FALSE); + } + + /* + * xdr the decrypted timestamp + */ +/* LINTED pointer alignment */ + ixdr = (uint32_t *)buf.c; + verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; + verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); + + /* + * validate + */ + if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, + sizeof(struct timeval)) != 0) { + //syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); + return (FALSE); + } + + /* + * We have a nickname now, let's use it + */ + ad->ad_nickname = verf.adv_nickname; + ad->ad_cred.adc_namekind = ADN_NICKNAME; + return (TRUE); +} + +/* + * 4. Refresh + */ +/*ARGSUSED*/ +static bool_t +authdes_refresh(AUTH *auth, void *dummy) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_cred *cred = &ad->ad_cred; + int ok; + netobj pkey; + + if (ad->ad_dosync) { +#if 1 // WINDOWS + ok = 1; +#else + ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, + ad->ad_timehost, &(ad->ad_uaddr), + &(ad->ad_netid)); +#endif + if (! ok) { + /* + * Hope the clocks are synced! + */ + ad->ad_dosync = 0; + //syslog(LOG_DEBUG, + // "authdes_refresh: unable to synchronize clock"); + } + } + ad->ad_xkey = auth->ah_key; + pkey.n_bytes = (char *)(ad->ad_pkey); + pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1; + if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { + //syslog(LOG_INFO, + // "authdes_refresh: keyserv(1m) is unable to encrypt session key"); + return (FALSE); + } + cred->adc_fullname.key = ad->ad_xkey; + cred->adc_namekind = ADN_FULLNAME; + cred->adc_fullname.name = ad->ad_fullname; + return (TRUE); +} + + +/* + * 5. Destroy + */ +static void +authdes_destroy(AUTH *auth) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + + FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); + FREE(ad->ad_servername, ad->ad_servernamelen + 1); + if (ad->ad_timehost) + FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); + if (ad->ad_netid) + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); + if (ad->ad_uaddr) + FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); + FREE(ad, sizeof (struct ad_private)); + FREE(auth, sizeof(AUTH)); +} + +static struct auth_ops * +authdes_ops(void) +{ + static struct auth_ops ops; + extern mutex_t authdes_ops_lock; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&authdes_ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authdes_nextverf; + ops.ah_marshal = authdes_marshal; + ops.ah_validate = authdes_validate; + ops.ah_refresh = authdes_refresh; + ops.ah_destroy = authdes_destroy; + } + mutex_unlock(&authdes_ops_lock); + return (&ops); +} diff --git a/libtirpc/src/auth_gss.c b/libtirpc/src/auth_gss.c new file mode 100644 index 0000000..89d4628 --- /dev/null +++ b/libtirpc/src/auth_gss.c @@ -0,0 +1,633 @@ +/* + auth_gss.c + + RPCSEC_GSS client routines. + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void authgss_nextverf(); +static bool_t authgss_marshal(); +static bool_t authgss_refresh(); +static bool_t authgss_validate(); +static void authgss_destroy(); +static void authgss_destroy_context(); +static bool_t authgss_wrap(); +static bool_t authgss_unwrap(); + + +/* + * from mit-krb5-1.2.1 mechglue/mglueP.h: + * Array of context IDs typed by mechanism OID + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +static struct auth_ops authgss_ops = { + authgss_nextverf, + authgss_marshal, + authgss_validate, + authgss_refresh, + authgss_destroy, + authgss_wrap, + authgss_unwrap +}; + +#ifdef DEBUG + +/* useful as i add more mechanisms */ +void +print_rpc_gss_sec(struct rpc_gss_sec *ptr) +{ +int i; +char *p; + + log_debug("rpc_gss_sec:"); + if(ptr->mech == NULL) + log_debug("NULL gss_OID mech"); + else { + fprintf(stderr, " mechanism_OID: {"); + p = (char *)ptr->mech->elements; + for (i=0; i < ptr->mech->length; i++) + /* First byte of OIDs encoded to save a byte */ + if (i == 0) { + int first, second; + if (*p < 40) { + first = 0; + second = *p; + } + else if (40 <= *p && *p < 80) { + first = 1; + second = *p - 40; + } + else if (80 <= *p && *p < 127) { + first = 2; + second = *p - 80; + } + else { + /* Invalid value! */ + first = -1; + second = -1; + } + fprintf(stderr, " %u %u", first, second); + p++; + } + else { + fprintf(stderr, " %u", (unsigned char)*p++); + } + fprintf(stderr, " }\n"); + } + fprintf(stderr, " qop: %d\n", ptr->qop); + fprintf(stderr, " service: %d\n", ptr->svc); + fprintf(stderr, " cred: %p\n", ptr->cred); +} +#endif /*DEBUG*/ + +struct rpc_gss_data { + bool_t established; /* context established */ + gss_buffer_desc gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier + * to process at end of context negotiation*/ + CLIENT *clnt; /* client handle */ + gss_name_t name; /* service name */ + struct rpc_gss_sec sec; /* security tuple */ + gss_ctx_id_t ctx; /* context id */ + struct rpc_gss_cred gc; /* client credentials */ + u_int win; /* sequence window */ +}; + +#define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private) + +static struct timeval AUTH_TIMEOUT = { 25, 0 }; + +AUTH * +authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec) +{ + AUTH *auth, *save_auth; + struct rpc_gss_data *gd; + OM_uint32 min_stat = 0; + + log_debug("in authgss_create()"); + + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); + + if ((auth = calloc(sizeof(*auth), 1)) == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + return (NULL); + } + if ((gd = calloc(sizeof(*gd), 1)) == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } +#ifdef DEBUG + fprintf(stderr, "authgss_create: name is %p\n", name); +#endif + if (name != GSS_C_NO_NAME) { + if (gss_duplicate_name(&min_stat, name, &gd->name) + != GSS_S_COMPLETE) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } + } + else + gd->name = name; + +#ifdef DEBUG + fprintf(stderr, "authgss_create: gd->name is %p\n", gd->name); +#endif + gd->clnt = clnt; + gd->ctx = GSS_C_NO_CONTEXT; + gd->sec = *sec; + + gd->gc.gc_v = RPCSEC_GSS_VERSION; + gd->gc.gc_proc = RPCSEC_GSS_INIT; + gd->gc.gc_svc = gd->sec.svc; + + auth->ah_ops = &authgss_ops; + auth->ah_private = (caddr_t)gd; + + save_auth = clnt->cl_auth; + clnt->cl_auth = auth; + + if (!authgss_refresh(auth)) + auth = NULL; + + clnt->cl_auth = save_auth; + + return (auth); +} + +AUTH * +authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec) +{ + AUTH *auth; + OM_uint32 maj_stat = 0, min_stat = 0; + gss_buffer_desc sname; + gss_name_t name = GSS_C_NO_NAME; + + log_debug("in authgss_create_default()"); + + + sname.value = service; + sname.length = strlen(service); + + maj_stat = gss_import_name(&min_stat, &sname, + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, + &name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_import_name", maj_stat, min_stat); + rpc_createerr.cf_stat = RPC_AUTHERROR; + return (NULL); + } + + auth = authgss_create(clnt, name, sec); + + if (name != GSS_C_NO_NAME) { +#ifdef DEBUG + fprintf(stderr, "authgss_create_default: freeing name %p\n", name); +#endif + gss_release_name(&min_stat, &name); + } + + return (auth); +} + +bool_t +authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_get_private_data()"); + + if (!auth || !pd) + return (FALSE); + + gd = AUTH_PRIVATE(auth); + + if (!gd || !gd->established) + return (FALSE); + + pd->pd_ctx = gd->ctx; + pd->pd_ctx_hndl = gd->gc.gc_ctx; + pd->pd_seq_win = gd->win; + + return (TRUE); +} + +static void +authgss_nextverf(AUTH *auth) +{ + log_debug("in authgss_nextverf()"); + /* no action necessary */ +} + +static bool_t +authgss_marshal(AUTH *auth, XDR *xdrs) +{ + XDR tmpxdrs; + char tmp[MAX_AUTH_BYTES]; + struct rpc_gss_data *gd; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat; + bool_t xdr_stat; + + log_debug("in authgss_marshal()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established) + gd->gc.gc_seq++; + + xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); + + if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) { + XDR_DESTROY(&tmpxdrs); + return (FALSE); + } + auth->ah_cred.oa_flavor = RPCSEC_GSS; + auth->ah_cred.oa_base = tmp; + auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs); + + XDR_DESTROY(&tmpxdrs); + + if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) + return (FALSE); + + if (gd->gc.gc_proc == RPCSEC_GSS_INIT || + gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + return (xdr_opaque_auth(xdrs, &_null_auth)); + } + /* Checksum serialized RPC header, up to and including credential. */ + rpcbuf.length = XDR_GETPOS(xdrs); + XDR_SETPOS(xdrs, 0); + rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); + + maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, + &rpcbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + auth->ah_verf.oa_flavor = RPCSEC_GSS; + auth->ah_verf.oa_base = checksum.value; + auth->ah_verf.oa_length = checksum.length; + + xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf); + gss_release_buffer(&min_stat, &checksum); + + return (xdr_stat); +} + +static bool_t +authgss_validate(AUTH *auth, struct opaque_auth *verf) +{ + struct rpc_gss_data *gd; + u_int num, qop_state; + gss_buffer_desc signbuf, checksum; + OM_uint32 maj_stat, min_stat; + + log_debug("in authgss_validate()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established == FALSE) { + /* would like to do this only on NULL rpc -- + * gc->established is good enough. + * save the on the wire verifier to validate last + * INIT phase packet after decode if the major + * status is GSS_S_COMPLETE + */ + if ((gd->gc_wire_verf.value = + mem_alloc(verf->oa_length)) == NULL) { + fprintf(stderr, "gss_validate: out of memory\n"); + return (FALSE); + } + memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length); + gd->gc_wire_verf.length = verf->oa_length; + return (TRUE); + } + + if (gd->gc.gc_proc == RPCSEC_GSS_INIT || + gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + num = htonl(gd->win); + } + else num = htonl(gd->gc.gc_seq); + + signbuf.value = # + signbuf.length = sizeof(num); + + checksum.value = verf->oa_base; + checksum.length = verf->oa_length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf, + &checksum, &qop_state); + if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) { + log_status("gss_verify_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + return (TRUE); +} + +static bool_t +authgss_refresh(AUTH *auth) +{ + struct rpc_gss_data *gd; + struct rpc_gss_init_res gr; + gss_buffer_desc *recv_tokenp, send_token; + OM_uint32 maj_stat, min_stat, call_stat, ret_flags; + + log_debug("in authgss_refresh()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established) + return (TRUE); + + /* GSS context establishment loop. */ + memset(&gr, 0, sizeof(gr)); + recv_tokenp = GSS_C_NO_BUFFER; + +#ifdef DEBUG + print_rpc_gss_sec(&gd->sec); +#endif /*DEBUG*/ + + for (;;) { +#ifdef DEBUG + /* print the token we just received */ + if (recv_tokenp != GSS_C_NO_BUFFER) { + log_debug("The token we just received (length %d):", + recv_tokenp->length); + log_hexdump(recv_tokenp->value, recv_tokenp->length, 0); + } +#endif + maj_stat = gss_init_sec_context(&min_stat, + gd->sec.cred, + &gd->ctx, + gd->name, + gd->sec.mech, + gd->sec.req_flags, + 0, /* time req */ + NULL, /* channel */ + recv_tokenp, + NULL, /* used mech */ + &send_token, + &ret_flags, + NULL); /* time rec */ + + if (recv_tokenp != GSS_C_NO_BUFFER) { + gss_release_buffer(&min_stat, &gr.gr_token); + recv_tokenp = GSS_C_NO_BUFFER; + } + if (maj_stat != GSS_S_COMPLETE && + maj_stat != GSS_S_CONTINUE_NEEDED) { + log_status("gss_init_sec_context", maj_stat, min_stat); + break; + } + if (send_token.length != 0) { + memset(&gr, 0, sizeof(gr)); + +#ifdef DEBUG + /* print the token we are about to send */ + log_debug("The token being sent (length %d):", + send_token.length); + log_hexdump(send_token.value, send_token.length, 0); +#endif + + call_stat = clnt_call(gd->clnt, NULLPROC, + (xdrproc_t)xdr_rpc_gss_init_args, + &send_token, + (xdrproc_t)xdr_rpc_gss_init_res, + (caddr_t)&gr, AUTH_TIMEOUT); + + gss_release_buffer(&min_stat, &send_token); + + if (call_stat != RPC_SUCCESS || + (gr.gr_major != GSS_S_COMPLETE && + gr.gr_major != GSS_S_CONTINUE_NEEDED)) + return FALSE; + + if (gr.gr_ctx.length != 0) { + if (gd->gc.gc_ctx.value) + gss_release_buffer(&min_stat, + &gd->gc.gc_ctx); + gd->gc.gc_ctx = gr.gr_ctx; + } + if (gr.gr_token.length != 0) { + if (maj_stat != GSS_S_CONTINUE_NEEDED) + break; + recv_tokenp = &gr.gr_token; + } + gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT; + } + + /* GSS_S_COMPLETE => check gss header verifier, + * usually checked in gss_validate + */ + if (maj_stat == GSS_S_COMPLETE) { + gss_buffer_desc bufin; + gss_buffer_desc bufout; + u_int seq, qop_state = 0; + + seq = htonl(gr.gr_win); + bufin.value = (unsigned char *)&seq; + bufin.length = sizeof(seq); + bufout.value = (unsigned char *)gd->gc_wire_verf.value; + bufout.length = gd->gc_wire_verf.length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, + &bufin, &bufout, &qop_state); + + if (maj_stat != GSS_S_COMPLETE + || qop_state != gd->sec.qop) { + log_status("gss_verify_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + gd->established = TRUE; + gd->gc.gc_proc = RPCSEC_GSS_DATA; + gd->gc.gc_seq = 0; + gd->win = gr.gr_win; + break; + } + } + /* End context negotiation loop. */ + if (gd->gc.gc_proc != RPCSEC_GSS_DATA) { + if (gr.gr_token.length != 0) + gss_release_buffer(&min_stat, &gr.gr_token); + + authgss_destroy(auth); + auth = NULL; + rpc_createerr.cf_stat = RPC_AUTHERROR; + + return (FALSE); + } + return (TRUE); +} + +bool_t +authgss_service(AUTH *auth, int svc) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_service()"); + + if (!auth) + return(FALSE); + gd = AUTH_PRIVATE(auth); + if (!gd || !gd->established) + return (FALSE); + gd->sec.svc = svc; + gd->gc.gc_svc = svc; + return (TRUE); +} + +static void +authgss_destroy_context(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in authgss_destroy_context()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gc.gc_ctx.length != 0) { + if (gd->established) { + gd->gc.gc_proc = RPCSEC_GSS_DESTROY; + clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); + } + gss_release_buffer(&min_stat, &gd->gc.gc_ctx); + /* XXX ANDROS check size of context - should be 8 */ + memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx)); + } + if (gd->ctx != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&min_stat, &gd->ctx, NULL); + gd->ctx = GSS_C_NO_CONTEXT; + } + + /* free saved wire verifier (if any) */ + mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length); + gd->gc_wire_verf.value = NULL; + gd->gc_wire_verf.length = 0; + + gd->established = FALSE; +} + +static void +authgss_destroy(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in authgss_destroy()"); + + gd = AUTH_PRIVATE(auth); + + authgss_destroy_context(auth); + +#ifdef DEBUG + fprintf(stderr, "authgss_destroy: freeing name %p\n", gd->name); +#endif + if (gd->name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &gd->name); + + free(gd); + free(auth); +} + +bool_t +authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_wrap()"); + + gd = AUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->gc.gc_seq)); +} + +bool_t +authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_unwrap()"); + + gd = AUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->gc.gc_seq)); +} diff --git a/libtirpc/src/auth_none.c b/libtirpc/src/auth_none.c new file mode 100644 index 0000000..dcaf464 --- /dev/null +++ b/libtirpc/src/auth_none.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* +#if defined(LIBC_SCCS) && !defined(lint) +static char *sccsid = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +static char *sccsid = "@(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC"; +#endif +//#include +__FBSDID("$FreeBSD: src/lib/libc/rpc/auth_none.c,v 1.12 2002/03/22 23:18:35 obrien Exp $"); +*/ + + +/* + * auth_none.c + * Creates a client authentication handle for passing "null" + * credentials and verifiers to remote systems. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#include +//#include +#include +#include +#include +#include +#include +#include + +#define MAX_MARSHAL_SIZE 20 + +/* + * Authenticator operations routines + */ + +static bool_t authnone_marshal (AUTH *, XDR *); +static void authnone_verf (AUTH *); +static bool_t authnone_validate (AUTH *, struct opaque_auth *); +static bool_t authnone_refresh (AUTH *, void *); +static void authnone_destroy (AUTH *); + +extern bool_t xdr_opaque_auth(); + +static struct auth_ops *authnone_ops(); + +static struct authnone_private { + AUTH no_client; + char marshalled_client[MAX_MARSHAL_SIZE]; + u_int mcnt; +} *authnone_private; + +AUTH * +authnone_create() +{ + struct authnone_private *ap = authnone_private; + XDR xdr_stream; + XDR *xdrs; + extern mutex_t authnone_lock; + + mutex_lock(&authnone_lock); + if (ap == 0) { + ap = (struct authnone_private *)calloc(1, sizeof (*ap)); + if (ap == 0) { + mutex_unlock(&authnone_lock); + return (0); + } + authnone_private = ap; + } + if (!ap->mcnt) { + ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; + ap->no_client.ah_ops = authnone_ops(); + xdrs = &xdr_stream; + xdrmem_create(xdrs, ap->marshalled_client, + (u_int)MAX_MARSHAL_SIZE, XDR_ENCODE); + (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); + (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); + ap->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + } + mutex_unlock(&authnone_lock); + return (&ap->no_client); +} + +/*ARGSUSED*/ +static bool_t +authnone_marshal(AUTH *client, XDR *xdrs) +{ + struct authnone_private *ap; + bool_t dummy; + extern mutex_t authnone_lock; + + assert(xdrs != NULL); + + ap = authnone_private; + if (ap == NULL) { + mutex_unlock(&authnone_lock); + return (FALSE); + } + dummy = (*xdrs->x_ops->x_putbytes)(xdrs, + ap->marshalled_client, ap->mcnt); + mutex_unlock(&authnone_lock); + return (dummy); +} + +/* All these unused parameters are required to keep ANSI-C from grumbling */ +/*ARGSUSED*/ +static void +authnone_verf(AUTH *client) +{ +} + +/*ARGSUSED*/ +static bool_t +authnone_validate(AUTH *client, struct opaque_auth *opaque) +{ + + return (TRUE); +} + +/*ARGSUSED*/ +static bool_t +authnone_refresh(AUTH *client, void *dummy) +{ + + return (FALSE); +} + +/*ARGSUSED*/ +static void +authnone_destroy(AUTH *client) +{ +} + +static struct auth_ops * +authnone_ops() +{ + static struct auth_ops ops; + extern mutex_t ops_lock; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authnone_verf; + ops.ah_marshal = authnone_marshal; + ops.ah_validate = authnone_validate; + ops.ah_refresh = authnone_refresh; + ops.ah_destroy = authnone_destroy; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/libtirpc/src/auth_sspi.c b/libtirpc/src/auth_sspi.c new file mode 100644 index 0000000..437ba85 --- /dev/null +++ b/libtirpc/src/auth_sspi.c @@ -0,0 +1,634 @@ +/* + * auth_sspi.c + * + * RPCSEC_GSS client routines (using the Windows SSPI rather than GSS-API). + * + * Copyright (c) 2000 Dug Song . + * All rights reserved, all wrongs reversed. + * + * COPYRIGHT (c) 2010 + * The Regents of the University of Michigan + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + */ + +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include + +static void authgss_nextverf(); +static bool_t authgss_marshal(); +static bool_t authgss_refresh(); +static bool_t authgss_validate(); +static void authgss_destroy(); +static void authgss_destroy_context(); +static bool_t authgss_wrap(); +static bool_t authgss_unwrap(); + + +/* + * from mit-krb5-1.2.1 mechglue/mglueP.h: + * Array of context IDs typed by mechanism OID + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +static struct auth_ops authgss_ops = { + authgss_nextverf, + authgss_marshal, + authgss_validate, + authgss_refresh, + authgss_destroy, + authgss_wrap, + authgss_unwrap +}; + +#ifdef DEBUG + +/* useful as i add more mechanisms */ +void +print_rpc_gss_sec(struct rpc_gss_sec *ptr) +{ +int i; +char *p; + + log_debug("rpc_gss_sec:"); + if(ptr->mech == NULL) + log_debug("NULL gss_OID mech"); + else { + fprintf(stderr, " mechanism_OID: {"); + p = (char *)ptr->mech->elements; + for (i=0; i < ptr->mech->length; i++) + /* First byte of OIDs encoded to save a byte */ + if (i == 0) { + int first, second; + if (*p < 40) { + first = 0; + second = *p; + } + else if (40 <= *p && *p < 80) { + first = 1; + second = *p - 40; + } + else if (80 <= *p && *p < 127) { + first = 2; + second = *p - 80; + } + else { + /* Invalid value! */ + first = -1; + second = -1; + } + fprintf(stderr, " %u %u", first, second); + p++; + } + else { + fprintf(stderr, " %u", (unsigned char)*p++); + } + fprintf(stderr, " }\n"); + } + fprintf(stderr, " qop: %d\n", ptr->qop); + fprintf(stderr, " service: %d\n", ptr->svc); + fprintf(stderr, " cred: %p\n", ptr->cred); +} +#endif /*DEBUG*/ + +struct rpc_gss_data { + bool_t established; /* context established */ + gss_buffer_desc gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier + * to process at end of context negotiation*/ + CLIENT *clnt; /* client handle */ + gss_name_t name; /* service name */ + struct rpc_gss_sec sec; /* security tuple */ + gss_ctx_id_t ctx; /* context id */ + struct rpc_gss_cred gc; /* client credentials */ + u_int win; /* sequence window */ +}; + +#define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private) + +static struct timeval AUTH_TIMEOUT = { 25, 0 }; + +AUTH * +authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec) +{ + AUTH *auth, *save_auth; + struct rpc_gss_data *gd; + OM_uint32 min_stat = 0; + + log_debug("in authgss_create()"); + + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); + + if ((auth = calloc(sizeof(*auth), 1)) == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + return (NULL); + } + if ((gd = calloc(sizeof(*gd), 1)) == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } +#ifdef DEBUG + fprintf(stderr, "authgss_create: name is %p\n", name); +#endif + if (name != GSS_C_NO_NAME) { + if (gss_duplicate_name(&min_stat, name, &gd->name) + != GSS_S_COMPLETE) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } + } + else + gd->name = name; + +#ifdef DEBUG + fprintf(stderr, "authgss_create: gd->name is %p\n", gd->name); +#endif + gd->clnt = clnt; + gd->ctx = GSS_C_NO_CONTEXT; + gd->sec = *sec; + + gd->gc.gc_v = RPCSEC_GSS_VERSION; + gd->gc.gc_proc = RPCSEC_GSS_INIT; + gd->gc.gc_svc = gd->sec.svc; + + auth->ah_ops = &authgss_ops; + auth->ah_private = (caddr_t)gd; + + save_auth = clnt->cl_auth; + clnt->cl_auth = auth; + + if (!authgss_refresh(auth)) + auth = NULL; + + clnt->cl_auth = save_auth; + + return (auth); +} + +AUTH * +authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec) +{ + AUTH *auth; + OM_uint32 maj_stat = 0, min_stat = 0; + gss_buffer_desc sname; + gss_name_t name = GSS_C_NO_NAME; + + log_debug("in authgss_create_default()"); + + + sname.value = service; + sname.length = strlen(service); + + maj_stat = gss_import_name(&min_stat, &sname, + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, + &name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_import_name", maj_stat, min_stat); + rpc_createerr.cf_stat = RPC_AUTHERROR; + return (NULL); + } + + auth = authgss_create(clnt, name, sec); + + if (name != GSS_C_NO_NAME) { +#ifdef DEBUG + fprintf(stderr, "authgss_create_default: freeing name %p\n", name); +#endif + gss_release_name(&min_stat, &name); + } + + return (auth); +} + +bool_t +authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_get_private_data()"); + + if (!auth || !pd) + return (FALSE); + + gd = AUTH_PRIVATE(auth); + + if (!gd || !gd->established) + return (FALSE); + + pd->pd_ctx = gd->ctx; + pd->pd_ctx_hndl = gd->gc.gc_ctx; + pd->pd_seq_win = gd->win; + + return (TRUE); +} + +static void +authgss_nextverf(AUTH *auth) +{ + log_debug("in authgss_nextverf()"); + /* no action necessary */ +} + +static bool_t +authgss_marshal(AUTH *auth, XDR *xdrs) +{ + XDR tmpxdrs; + char tmp[MAX_AUTH_BYTES]; + struct rpc_gss_data *gd; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat; + bool_t xdr_stat; + + log_debug("in authgss_marshal()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established) + gd->gc.gc_seq++; + + xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); + + if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) { + XDR_DESTROY(&tmpxdrs); + return (FALSE); + } + auth->ah_cred.oa_flavor = RPCSEC_GSS; + auth->ah_cred.oa_base = tmp; + auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs); + + XDR_DESTROY(&tmpxdrs); + + if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) + return (FALSE); + + if (gd->gc.gc_proc == RPCSEC_GSS_INIT || + gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + return (xdr_opaque_auth(xdrs, &_null_auth)); + } + /* Checksum serialized RPC header, up to and including credential. */ + rpcbuf.length = XDR_GETPOS(xdrs); + XDR_SETPOS(xdrs, 0); + rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); + + maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, + &rpcbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + auth->ah_verf.oa_flavor = RPCSEC_GSS; + auth->ah_verf.oa_base = checksum.value; + auth->ah_verf.oa_length = checksum.length; + + xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf); + gss_release_buffer(&min_stat, &checksum); + + return (xdr_stat); +} + +static bool_t +authgss_validate(AUTH *auth, struct opaque_auth *verf) +{ + struct rpc_gss_data *gd; + u_int num, qop_state; + gss_buffer_desc signbuf, checksum; + OM_uint32 maj_stat, min_stat; + + log_debug("in authgss_validate()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established == FALSE) { + /* would like to do this only on NULL rpc -- + * gc->established is good enough. + * save the on the wire verifier to validate last + * INIT phase packet after decode if the major + * status is GSS_S_COMPLETE + */ + if ((gd->gc_wire_verf.value = + mem_alloc(verf->oa_length)) == NULL) { + fprintf(stderr, "gss_validate: out of memory\n"); + return (FALSE); + } + memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length); + gd->gc_wire_verf.length = verf->oa_length; + return (TRUE); + } + + if (gd->gc.gc_proc == RPCSEC_GSS_INIT || + gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + num = htonl(gd->win); + } + else num = htonl(gd->gc.gc_seq); + + signbuf.value = # + signbuf.length = sizeof(num); + + checksum.value = verf->oa_base; + checksum.length = verf->oa_length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf, + &checksum, &qop_state); + if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) { + log_status("gss_verify_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + return (TRUE); +} + +static bool_t +authgss_refresh(AUTH *auth) +{ + struct rpc_gss_data *gd; + struct rpc_gss_init_res gr; + gss_buffer_desc *recv_tokenp, send_token; + OM_uint32 maj_stat, min_stat, call_stat, ret_flags; + + log_debug("in authgss_refresh()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established) + return (TRUE); + + /* GSS context establishment loop. */ + memset(&gr, 0, sizeof(gr)); + recv_tokenp = GSS_C_NO_BUFFER; + +#ifdef DEBUG + print_rpc_gss_sec(&gd->sec); +#endif /*DEBUG*/ + + for (;;) { +#ifdef DEBUG + /* print the token we just received */ + if (recv_tokenp != GSS_C_NO_BUFFER) { + log_debug("The token we just received (length %d):", + recv_tokenp->length); + log_hexdump(recv_tokenp->value, recv_tokenp->length, 0); + } +#endif + maj_stat = gss_init_sec_context(&min_stat, + gd->sec.cred, + &gd->ctx, + gd->name, + gd->sec.mech, + gd->sec.req_flags, + 0, /* time req */ + NULL, /* channel */ + recv_tokenp, + NULL, /* used mech */ + &send_token, + &ret_flags, + NULL); /* time rec */ + + if (recv_tokenp != GSS_C_NO_BUFFER) { + gss_release_buffer(&min_stat, &gr.gr_token); + recv_tokenp = GSS_C_NO_BUFFER; + } + if (maj_stat != GSS_S_COMPLETE && + maj_stat != GSS_S_CONTINUE_NEEDED) { + log_status("gss_init_sec_context", maj_stat, min_stat); + break; + } + if (send_token.length != 0) { + memset(&gr, 0, sizeof(gr)); + +#ifdef DEBUG + /* print the token we are about to send */ + log_debug("The token being sent (length %d):", + send_token.length); + log_hexdump(send_token.value, send_token.length, 0); +#endif + + call_stat = clnt_call(gd->clnt, NULLPROC, + (xdrproc_t)xdr_rpc_gss_init_args, + &send_token, + (xdrproc_t)xdr_rpc_gss_init_res, + (caddr_t)&gr, AUTH_TIMEOUT); + + gss_release_buffer(&min_stat, &send_token); + + if (call_stat != RPC_SUCCESS || + (gr.gr_major != GSS_S_COMPLETE && + gr.gr_major != GSS_S_CONTINUE_NEEDED)) + return FALSE; + + if (gr.gr_ctx.length != 0) { + if (gd->gc.gc_ctx.value) + gss_release_buffer(&min_stat, + &gd->gc.gc_ctx); + gd->gc.gc_ctx = gr.gr_ctx; + } + if (gr.gr_token.length != 0) { + if (maj_stat != GSS_S_CONTINUE_NEEDED) + break; + recv_tokenp = &gr.gr_token; + } + gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT; + } + + /* GSS_S_COMPLETE => check gss header verifier, + * usually checked in gss_validate + */ + if (maj_stat == GSS_S_COMPLETE) { + gss_buffer_desc bufin; + gss_buffer_desc bufout; + u_int seq, qop_state = 0; + + seq = htonl(gr.gr_win); + bufin.value = (unsigned char *)&seq; + bufin.length = sizeof(seq); + bufout.value = (unsigned char *)gd->gc_wire_verf.value; + bufout.length = gd->gc_wire_verf.length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, + &bufin, &bufout, &qop_state); + + if (maj_stat != GSS_S_COMPLETE + || qop_state != gd->sec.qop) { + log_status("gss_verify_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + gd->established = TRUE; + gd->gc.gc_proc = RPCSEC_GSS_DATA; + gd->gc.gc_seq = 0; + gd->win = gr.gr_win; + break; + } + } + /* End context negotiation loop. */ + if (gd->gc.gc_proc != RPCSEC_GSS_DATA) { + if (gr.gr_token.length != 0) + gss_release_buffer(&min_stat, &gr.gr_token); + + authgss_destroy(auth); + auth = NULL; + rpc_createerr.cf_stat = RPC_AUTHERROR; + + return (FALSE); + } + return (TRUE); +} + +bool_t +authgss_service(AUTH *auth, int svc) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_service()"); + + if (!auth) + return(FALSE); + gd = AUTH_PRIVATE(auth); + if (!gd || !gd->established) + return (FALSE); + gd->sec.svc = svc; + gd->gc.gc_svc = svc; + return (TRUE); +} + +static void +authgss_destroy_context(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in authgss_destroy_context()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gc.gc_ctx.length != 0) { + if (gd->established) { + gd->gc.gc_proc = RPCSEC_GSS_DESTROY; + clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT); + } + gss_release_buffer(&min_stat, &gd->gc.gc_ctx); + /* XXX ANDROS check size of context - should be 8 */ + memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx)); + } + if (gd->ctx != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&min_stat, &gd->ctx, NULL); + gd->ctx = GSS_C_NO_CONTEXT; + } + + /* free saved wire verifier (if any) */ + mem_free(gd->gc_wire_verf.value, gd->gc_wire_verf.length); + gd->gc_wire_verf.value = NULL; + gd->gc_wire_verf.length = 0; + + gd->established = FALSE; +} + +static void +authgss_destroy(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in authgss_destroy()"); + + gd = AUTH_PRIVATE(auth); + + authgss_destroy_context(auth); + +#ifdef DEBUG + fprintf(stderr, "authgss_destroy: freeing name %p\n", gd->name); +#endif + if (gd->name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &gd->name); + + free(gd); + free(auth); +} + +bool_t +authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_wrap()"); + + gd = AUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->gc.gc_seq)); +} + +bool_t +authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_unwrap()"); + + gd = AUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->gc.gc_seq)); +} diff --git a/libtirpc/src/auth_time.c b/libtirpc/src/auth_time.c new file mode 100644 index 0000000..ad8e521 --- /dev/null +++ b/libtirpc/src/auth_time.c @@ -0,0 +1,504 @@ +/* + * auth_time.c + * + * This module contains the private function __rpc_get_time_offset() + * which will return the difference in seconds between the local system's + * notion of time and a remote server's notion of time. This must be + * possible without calling any functions that may invoke the name + * service. (netdir_getbyxxx, getXbyY, etc). The function is used in the + * synchronize call of the authdes code to synchronize clocks between + * NIS+ clients and their servers. + * + * Note to minimize the amount of duplicate code, portions of the + * synchronize() function were folded into this code, and the synchronize + * call becomes simply a wrapper around this function. Further, if this + * function is called with a timehost it *DOES* recurse to the name + * server so don't use it in that mode if you are doing name service code. + * + * Copyright (c) 1992 Sun Microsystems Inc. + * All rights reserved. + * + * Side effects : + * When called a client handle to a RPCBIND process is created + * and destroyed. Two strings "netid" and "uaddr" are malloc'd + * and returned. The SIGALRM processing is modified only if + * needed to deal with TCP connections. + */ + +//#include +#include +//#include +#include +#include +//#include +//#include +//#include +#include +//#include +//#include +//#include + +#include +#include +#include +//#include +//#include +#undef NIS +#include + + +#ifdef TESTING +#define msg(x) printf("ERROR: %s\n", x) +/* #define msg(x) syslog(LOG_ERR, "%s", x) */ +#else +#define msg(x) +#endif + +static int saw_alarm = 0; + +static void +alarm_hndler(s) + int s; +{ + saw_alarm = 1; + return; +} + +/* + * The internet time server defines the epoch to be Jan 1, 1900 + * whereas UNIX defines it to be Jan 1, 1970. To adjust the result + * from internet time-service time, into UNIX time we subtract the + * following offset : + */ +#define NYEARS (1970 - 1900) +#define TOFFSET ((u_long)60*60*24*(365*NYEARS + (NYEARS/4))) + + +/* + * Stolen from rpc.nisd: + * Turn a 'universal address' into a struct sockaddr_in. + * Bletch. + */ +static int uaddr_to_sockaddr(uaddr, sin) +#ifdef foo + endpoint *endpt; +#endif + char *uaddr; + struct sockaddr_in *sin; +{ + unsigned char p_bytes[2]; + int i; + unsigned long a[6]; + + i = sscanf(uaddr, "%lu.%lu.%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2], + &a[3], &a[4], &a[5]); + + if (i < 6) + return(1); + + for (i = 0; i < 4; i++) + sin->sin_addr.s_addr |= (a[i] & 0x000000FF) << (8 * i); + + p_bytes[0] = (unsigned char)a[4] & 0x000000FF; + p_bytes[1] = (unsigned char)a[5] & 0x000000FF; + + sin->sin_family = AF_INET; /* always */ + bcopy((char *)&p_bytes, (char *)&sin->sin_port, 2); + + return (0); +} + +/* + * free_eps() + * + * Free the strings that were strduped into the eps structure. + */ +static void +free_eps(eps, num) + endpoint eps[]; + int num; +{ + int i; + + for (i = 0; i < num; i++) { + free(eps[i].uaddr); + free(eps[i].proto); + free(eps[i].family); + } + return; +} + +/* + * get_server() + * + * This function constructs a nis_server structure description for the + * indicated hostname. + * + * NOTE: There is a chance we may end up recursing here due to the + * fact that gethostbyname() could do an NIS search. Ideally, the + * NIS+ server will call __rpc_get_time_offset() with the nis_server + * structure already populated. + */ +static nis_server * +get_server(sin, host, srv, eps, maxep) + struct sockaddr_in *sin; + char *host; /* name of the time host */ + nis_server *srv; /* nis_server struct to use. */ + endpoint eps[]; /* array of endpoints */ + int maxep; /* max array size */ +{ + char hname[256]; + int num_ep = 0, i; + struct hostent *he; + struct hostent dummy; + char *ptr[2]; + + if (host == NULL && sin == NULL) + return (NULL); + + if (sin == NULL) { + he = gethostbyname(host); + if (he == NULL) + return(NULL); + } else { + he = &dummy; + ptr[0] = (char *)&sin->sin_addr.s_addr; + ptr[1] = NULL; + dummy.h_addr_list = ptr; + } + + /* + * This is lame. We go around once for TCP, then again + * for UDP. + */ + for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep); + i++, num_ep++) { + struct in_addr *a; + + a = (struct in_addr *)he->h_addr_list[i]; + snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); + eps[num_ep].uaddr = strdup(hname); + eps[num_ep].family = strdup("inet"); + eps[num_ep].proto = strdup("tcp"); + } + + for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep); + i++, num_ep++) { + struct in_addr *a; + + a = (struct in_addr *)he->h_addr_list[i]; + snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a)); + eps[num_ep].uaddr = strdup(hname); + eps[num_ep].family = strdup("inet"); + eps[num_ep].proto = strdup("udp"); + } + + srv->name = (nis_name) host; + srv->ep.ep_len = num_ep; + srv->ep.ep_val = eps; + srv->key_type = NIS_PK_NONE; + srv->pkey.n_bytes = NULL; + srv->pkey.n_len = 0; + return (srv); +} + +/* + * __rpc_get_time_offset() + * + * This function uses a nis_server structure to contact the a remote + * machine (as named in that structure) and returns the offset in time + * between that machine and this one. This offset is returned in seconds + * and may be positive or negative. + * + * The first time through, a lot of fiddling is done with the netconfig + * stuff to find a suitable transport. The function is very aggressive + * about choosing UDP or at worst TCP if it can. This is because + * those transports support both the RCPBIND call and the internet + * time service. + * + * Once through, *uaddr is set to the universal address of + * the machine and *netid is set to the local netid for the transport + * that uaddr goes with. On the second call, the netconfig stuff + * is skipped and the uaddr/netid pair are used to fetch the netconfig + * structure and to then contact the machine for the time. + * + * td = "server" - "client" + */ +int +__rpc_get_time_offset(td, srv, thost, uaddr, netid) + struct timeval *td; /* Time difference */ + nis_server *srv; /* NIS Server description */ + char *thost; /* if no server, this is the timehost */ + char **uaddr; /* known universal address */ + struct sockaddr_in *netid; /* known network identifier */ +{ + CLIENT *clnt; /* Client handle */ + endpoint *ep, /* useful endpoints */ + *useep = NULL; /* endpoint of xp */ + char *useua = NULL; /* uaddr of selected xp */ + int epl, i; /* counters */ + enum clnt_stat status; /* result of clnt_call */ + long thetime; + long delta; + int needfree = 0; + struct timeval tv; + int time_valid; + int udp_ep = -1, tcp_ep = -1; + int a1, a2, a3, a4; + char ut[64], ipuaddr[64]; + endpoint teps[32]; + nis_server tsrv; + void (*oldsig)() = NULL; /* old alarm handler */ + struct sockaddr_in sin; + SOCKET s = RPC_ANYSOCK; + socklen_t len; + int type = 0; + + td->tv_sec = 0; + td->tv_usec = 0; + + /* + * First check to see if we need to find and address for this + * server. + */ + if (*uaddr == NULL) { + if ((srv != NULL) && (thost != NULL)) { + msg("both timehost and srv pointer used!"); + return (0); + } + if (! srv) { + srv = get_server(netid, thost, &tsrv, teps, 32); + if (srv == NULL) { + msg("unable to contruct server data."); + return (0); + } + needfree = 1; /* need to free data in endpoints */ + } + + ep = srv->ep.ep_val; + epl = srv->ep.ep_len; + + /* Identify the TCP and UDP endpoints */ + for (i = 0; + (i < epl) && ((udp_ep == -1) || (tcp_ep == -1)); i++) { + if (strcasecmp(ep[i].proto, "udp") == 0) + udp_ep = i; + if (strcasecmp(ep[i].proto, "tcp") == 0) + tcp_ep = i; + } + + /* Check to see if it is UDP or TCP */ + if (tcp_ep > -1) { + useep = &ep[tcp_ep]; + useua = ep[tcp_ep].uaddr; + type = SOCK_STREAM; + } else if (udp_ep > -1) { + useep = &ep[udp_ep]; + useua = ep[udp_ep].uaddr; + type = SOCK_DGRAM; + } + + if (useep == NULL) { + msg("no acceptable transport endpoints."); + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + return (0); + } + } + + /* + * Create a sockaddr from the uaddr. + */ + if (*uaddr != NULL) + useua = *uaddr; + + /* Fixup test for NIS+ */ + sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); + sprintf(ipuaddr, "%d.%d.%d.%d.0.111", a1, a2, a3, a4); + useua = &ipuaddr[0]; + + bzero((char *)&sin, sizeof(sin)); + if (uaddr_to_sockaddr(useua, &sin)) { + msg("unable to translate uaddr to sockaddr."); + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + return (0); + } + + /* + * Create the client handle to rpcbind. Note we always try + * version 3 since that is the earliest version that supports + * the RPCB_GETTIME call. Also it is the version that comes + * standard with SVR4. Since most everyone supports TCP/IP + * we could consider trying the rtime call first. + */ + clnt = clnttcp_create(&sin, RPCBPROG, RPCBVERS, &s, 0, 0); + if (clnt == NULL) { + msg("unable to create client handle to rpcbind."); + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + return (0); + } + + tv.tv_sec = 5; + tv.tv_usec = 0; + time_valid = 0; + status = clnt_call(clnt, RPCBPROC_GETTIME, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_u_long, &thetime, tv); + /* + * The only error we check for is anything but success. In + * fact we could have seen PROGMISMATCH if talking to a 4.1 + * machine (pmap v2) or TIMEDOUT if the net was busy. + */ + if (status == RPC_SUCCESS) + time_valid = 1; + else { + int save; + + /* Blow away possible stale CLNT handle. */ + if (clnt != NULL) { + clnt_destroy(clnt); + clnt = NULL; + } + + /* + * Convert PMAP address into timeservice address + * We take advantage of the fact that we "know" what + * the universal address looks like for inet transports. + * + * We also know that the internet timeservice is always + * listening on port 37. + */ + sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4); + sprintf(ut, "%d.%d.%d.%d.0.37", a1, a2, a3, a4); + + if (uaddr_to_sockaddr(ut, &sin)) { + msg("cannot convert timeservice uaddr to sockaddr."); + goto error; + } + + s = socket(AF_INET, type, 0); + if (s == INVALID_SOCKET) { + msg("unable to open fd to network."); + goto error; + } + + /* + * Now depending on whether or not we're talking to + * UDP we set a timeout or not. + */ + if (type == SOCK_DGRAM) { + struct timeval timeout = { 20, 0 }; + struct sockaddr_in from; + fd_set readfds; + int res; + + if (sendto(s, (const char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)&sin, sizeof(sin)) == -1) { + msg("udp : sendto failed."); + goto error; + } + do { + FD_ZERO(&readfds); + FD_SET(s, &readfds); + res = select(_rpc_dtablesize(), &readfds, + (fd_set *)NULL, (fd_set *)NULL, &timeout); + } while (res == SOCKET_ERROR && WSAGetLastError() == WSAEINTR); + if (res == SOCKET_ERROR) + goto error; + len = sizeof(from); + res = recvfrom(s, (char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)&from, &len); + if (res == SOCKET_ERROR) { + msg("recvfrom failed on udp transport."); + goto error; + } + time_valid = 1; + } else { + int res; +#ifndef _WIN32 + oldsig = (void (*)())signal(SIGALRM, alarm_hndler); + saw_alarm = 0; /* global tracking the alarm */ + alarm(20); /* only wait 20 seconds */ +#else + saw_alarm = 0; + /* XXX Need Windows signal/alarm stuff here XXX */ +#endif + res = connect(s, (struct sockaddr *)&sin, sizeof(sin)); + if (res == SOCKET_ERROR) { + msg("failed to connect to tcp endpoint."); + goto error; + } + if (saw_alarm) { + msg("alarm caught it, must be unreachable."); + goto error; + } +// res = read(s, (char *)&thetime, sizeof(thetime)); + res = recv(s, (char *)&thetime, sizeof(thetime), 0); + if (res != sizeof(thetime)) { + if (saw_alarm) + msg("timed out TCP call."); + else + msg("wrong size of results returned"); + + goto error; + } + time_valid = 1; + } + save = WSAGetLastError(); + (void)closesocket(s); + errno = save; + s = RPC_ANYSOCK; + + if (time_valid) { + thetime = ntohl(thetime); + thetime = thetime - TOFFSET; /* adjust to UNIX time */ + } else + thetime = 0; + } + + gettimeofday(&tv, 0); + +error: + /* + * clean up our allocated data structures. + */ + + if (s != RPC_ANYSOCK) + (void)closesocket(s); + + if (clnt != NULL) + clnt_destroy(clnt); + +#ifdef _WIN32 + /* XXX Need Windows signal/alarm stuff here XXX */ +#else + alarm(0); /* reset that alarm if its outstanding */ + if (oldsig) { + signal(SIGALRM, oldsig); + } +#endif + + /* + * note, don't free uaddr strings until after we've made a + * copy of them. + */ + if (time_valid) { + if (*uaddr == NULL) + *uaddr = strdup(useua); + + /* Round to the nearest second */ + tv.tv_sec += (tv.tv_sec > 500000) ? 1 : 0; + delta = (thetime > tv.tv_sec) ? thetime - tv.tv_sec : + tv.tv_sec - thetime; + td->tv_sec = (thetime < tv.tv_sec) ? - delta : delta; + td->tv_usec = 0; + } else { + msg("unable to get the server's time."); + } + + if (needfree) + free_eps(teps, tsrv.ep.ep_len); + + return (time_valid); +} diff --git a/libtirpc/src/auth_unix.c b/libtirpc/src/auth_unix.c new file mode 100644 index 0000000..2aa550a --- /dev/null +++ b/libtirpc/src/auth_unix.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * auth_unix.c, Implements UNIX style authentication parameters. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The system is very weak. The client uses no encryption for it's + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + * + */ +#include +//#include +#include +//#include + +#include +//#include +#include +#include +//#include +#include + +#include +#include +#include +#include + +/* auth_unix.c */ +static void authunix_nextverf (AUTH *); +static bool_t authunix_marshal (AUTH *, XDR *); +static bool_t authunix_validate (AUTH *, struct opaque_auth *); +static bool_t authunix_refresh (AUTH *, void *); +static void authunix_destroy (AUTH *); +static void marshal_new_auth (AUTH *); +static struct auth_ops *authunix_ops (void); + +/* + * This struct is pointed to by the ah_private field of an auth_handle. + */ +struct audata { + struct opaque_auth au_origcred; /* original credentials */ + struct opaque_auth au_shcred; /* short hand cred */ + u_long au_shfaults; /* short hand cache faults */ + char au_marshed[MAX_AUTH_BYTES]; + u_int au_mpos; /* xdr pos at end of marshed */ +}; +#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) + +/* + * Create a unix style authenticator. + * Returns an auth handle with the given stuff in it. + */ +AUTH * +authunix_create(machname, uid, gid, len, aup_gids) + char *machname; + uid_t uid; + gid_t gid; + int len; + gid_t *aup_gids; +{ + struct authunix_parms aup; + char mymem[MAX_AUTH_BYTES]; + struct timeval now; + XDR xdrs; + AUTH *auth; + struct audata *au; + + /* + * Allocate and set up auth handle + */ + au = NULL; + auth = mem_alloc(sizeof(*auth)); +#ifndef _KERNEL + if (auth == NULL) { + // XXX warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; + } +#endif + au = mem_alloc(sizeof(*au)); +#ifndef _KERNEL + if (au == NULL) { + // XXX warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; + } +#endif + auth->ah_ops = authunix_ops(); + auth->ah_private = (caddr_t)au; + auth->ah_verf = au->au_shcred = _null_auth; + au->au_shfaults = 0; + au->au_origcred.oa_base = NULL; + + /* + * fill in param struct from the given params + */ + (void)gettimeofday(&now, NULL); + aup.aup_time = now.tv_sec; + aup.aup_machname = machname; + aup.aup_uid = uid; + aup.aup_gid = gid; + aup.aup_len = (u_int)len; + aup.aup_gids = aup_gids; + + /* + * Serialize the parameters into origcred + */ + xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); + if (! xdr_authunix_parms(&xdrs, &aup)) + abort(); + au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); + au->au_origcred.oa_flavor = AUTH_UNIX; +#ifdef _KERNEL + au->au_origcred.oa_base = mem_alloc((u_int) len); +#else + if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) { + // XXX warnx("authunix_create: out of memory"); + goto cleanup_authunix_create; + } +#endif + memmove(au->au_origcred.oa_base, mymem, (size_t)len); + + /* + * set auth handle to reflect new cred. + */ + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); + return (auth); +#ifndef _KERNEL + cleanup_authunix_create: + if (auth) + mem_free(auth, sizeof(*auth)); + if (au) { + if (au->au_origcred.oa_base) + mem_free(au->au_origcred.oa_base, (u_int)len); + mem_free(au, sizeof(*au)); + } + return (NULL); +#endif +} + +/* + * Returns an auth handle with parameters determined by doing lots of + * syscalls. + */ +AUTH * +authunix_create_default() +{ + int len; + char machname[MAXHOSTNAMELEN + 1]; + uid_t uid; + gid_t gid; + gid_t gids[NGRPS]; + + if (gethostname(machname, sizeof machname) == -1) + abort(); + machname[sizeof(machname) - 1] = 0; +#if 0 + uid = geteuid(); + gid = getegid(); + if ((len = getgroups(NGRPS, gids)) < 0) + abort(); +#else + // XXX Need to figure out what to do here! + uid = 666; + gid = 777; + gids[0] = 0; + len = 0; +#endif + /* XXX: interface problem; those should all have been unsigned */ + return (authunix_create(machname, uid, gid, len, gids)); +} + +/* + * authunix operations + */ + +/* ARGSUSED */ +static void +authunix_nextverf(auth) + AUTH *auth; +{ + /* no action necessary */ +} + +static bool_t +authunix_marshal(auth, xdrs) + AUTH *auth; + XDR *xdrs; +{ + struct audata *au; + + assert(auth != NULL); + assert(xdrs != NULL); + + au = AUTH_PRIVATE(auth); + return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)); +} + +static bool_t +authunix_validate(auth, verf) + AUTH *auth; + struct opaque_auth *verf; +{ + struct audata *au; + XDR xdrs; + + assert(auth != NULL); + assert(verf != NULL); + + if (verf->oa_flavor == AUTH_SHORT) { + au = AUTH_PRIVATE(auth); + xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, + XDR_DECODE); + + if (au->au_shcred.oa_base != NULL) { + mem_free(au->au_shcred.oa_base, + au->au_shcred.oa_length); + au->au_shcred.oa_base = NULL; + } + if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { + auth->ah_cred = au->au_shcred; + } else { + xdrs.x_op = XDR_FREE; + (void)xdr_opaque_auth(&xdrs, &au->au_shcred); + au->au_shcred.oa_base = NULL; + auth->ah_cred = au->au_origcred; + } + marshal_new_auth(auth); + } + return (TRUE); +} + +static bool_t +authunix_refresh(AUTH *auth, void *dummy) +{ + struct audata *au = AUTH_PRIVATE(auth); + struct authunix_parms aup; + struct timeval now; + XDR xdrs; + int stat; + + assert(auth != NULL); + + if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { + /* there is no hope. Punt */ + return (FALSE); + } + au->au_shfaults ++; + + /* first deserialize the creds back into a struct authunix_parms */ + aup.aup_machname = NULL; + aup.aup_gids = NULL; + xdrmem_create(&xdrs, au->au_origcred.oa_base, + au->au_origcred.oa_length, XDR_DECODE); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + + /* update the time and serialize in place */ + (void)gettimeofday(&now, NULL); + aup.aup_time = now.tv_sec; + xdrs.x_op = XDR_ENCODE; + XDR_SETPOS(&xdrs, 0); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); +done: + /* free the struct authunix_parms created by deserializing */ + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, &aup); + XDR_DESTROY(&xdrs); + return (stat); +} + +static void +authunix_destroy(auth) + AUTH *auth; +{ + struct audata *au; + + assert(auth != NULL); + + au = AUTH_PRIVATE(auth); + mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); + + if (au->au_shcred.oa_base != NULL) + mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); + + mem_free(auth->ah_private, sizeof(struct audata)); + + if (auth->ah_verf.oa_base != NULL) + mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); + + mem_free(auth, sizeof(*auth)); +} + +/* + * Marshals (pre-serializes) an auth struct. + * sets private data, au_marshed and au_mpos + */ +static void +marshal_new_auth(auth) + AUTH *auth; +{ + XDR xdr_stream; + XDR *xdrs = &xdr_stream; + struct audata *au; + + assert(auth != NULL); + + au = AUTH_PRIVATE(auth); + xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); + if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || + (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) + assert(0); // XXX + // XXX warnx("auth_none.c - Fatal marshalling problem"); + else + au->au_mpos = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); +} + +static struct auth_ops * +authunix_ops() +{ + static struct auth_ops ops; + extern mutex_t ops_lock; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authunix_nextverf; + ops.ah_marshal = authunix_marshal; + ops.ah_validate = authunix_validate; + ops.ah_refresh = authunix_refresh; + ops.ah_destroy = authunix_destroy; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/libtirpc/src/authdes_prot.c b/libtirpc/src/authdes_prot.c new file mode 100644 index 0000000..4917e17 --- /dev/null +++ b/libtirpc/src/authdes_prot.c @@ -0,0 +1,86 @@ +//#include +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * authdes_prot.c, XDR routines for DES authentication + */ + +#include + +#include +#include +#include + +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +bool_t +xdr_authdes_cred(xdrs, cred) + XDR *xdrs; + struct authdes_cred *cred; +{ + /* + * Unrolled xdr + */ + ATTEMPT(xdr_enum(xdrs, (enum_t *)&cred->adc_namekind)); + switch (cred->adc_namekind) { + case ADN_FULLNAME: + ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name, + MAXNETNAMELEN)); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key, + sizeof(des_block))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window, + sizeof(cred->adc_fullname.window))); + return (TRUE); + case ADN_NICKNAME: + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname, + sizeof(cred->adc_nickname))); + return (TRUE); + default: + return (FALSE); + } +} + + +bool_t +xdr_authdes_verf(xdrs, verf) + XDR *xdrs; + struct authdes_verf *verf; +{ + /* + * Unrolled xdr + */ + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_xtimestamp, + sizeof(des_block))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_int_u, + sizeof(verf->adv_int_u))); + return (TRUE); +} diff --git a/libtirpc/src/authgss_prot.c b/libtirpc/src/authgss_prot.c new file mode 100644 index 0000000..ab72d91 --- /dev/null +++ b/libtirpc/src/authgss_prot.c @@ -0,0 +1,356 @@ +/* + authgss_prot.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool_t +xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) +{ + bool_t xdr_stat; + + xdr_stat = (xdr_u_int(xdrs, &p->gc_v) && + xdr_enum(xdrs, (enum_t *)&p->gc_proc) && + xdr_u_int(xdrs, &p->gc_seq) && + xdr_enum(xdrs, (enum_t *)&p->gc_svc) && + xdr_bytes(xdrs, (char **)&p->gc_ctx.value, + (u_int *)&p->gc_ctx.length, MAX_AUTH_BYTES)); + + log_debug("xdr_rpc_gss_cred: %s %s " + "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc, + p->gc_ctx.value, p->gc_ctx.length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p) +{ + bool_t xdr_stat; + + xdr_stat = xdr_bytes(xdrs, (char **)&p->value, + (u_int *)&p->length, MAX_NETOBJ_SZ); + + log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->value, p->length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) +{ + bool_t xdr_stat; + + xdr_stat = (xdr_bytes(xdrs, (char **)&p->gr_ctx.value, + (u_int *)&p->gr_ctx.length, MAX_NETOBJ_SZ) && + xdr_u_int(xdrs, &p->gr_major) && + xdr_u_int(xdrs, &p->gr_minor) && + xdr_u_int(xdrs, &p->gr_win) && + xdr_bytes(xdrs, (char **)&p->gr_token.value, + (u_int *)&p->gr_token.length, MAX_NETOBJ_SZ)); + + log_debug("xdr_rpc_gss_init_res %s %s " + "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->gr_ctx.value, p->gr_ctx.length, + p->gr_major, p->gr_minor, p->gr_win, + p->gr_token.value, p->gr_token.length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + gss_ctx_id_t ctx, gss_qop_t qop, + rpc_gss_svc_t svc, u_int seq) +{ + gss_buffer_desc databuf, wrapbuf; + OM_uint32 maj_stat, min_stat; + int start, end, conf_state; + bool_t xdr_stat; + + /* Skip databody length. */ + start = XDR_GETPOS(xdrs); + XDR_SETPOS(xdrs, start + 4); + + /* Marshal rpc_gss_data_t (sequence number + arguments). */ + if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr)) + return (FALSE); + end = XDR_GETPOS(xdrs); + + /* Set databuf to marshalled rpc_gss_data_t. */ + databuf.length = end - start - 4; + XDR_SETPOS(xdrs, start + 4); + databuf.value = XDR_INLINE(xdrs, databuf.length); + + xdr_stat = FALSE; + + if (svc == RPCSEC_GSS_SVC_INTEGRITY) { + /* Marshal databody_integ length. */ + XDR_SETPOS(xdrs, start); + if (!xdr_u_int(xdrs, (u_int *)&databuf.length)) + return (FALSE); + + /* Checksum rpc_gss_data_t. */ + maj_stat = gss_get_mic(&min_stat, ctx, qop, + &databuf, &wrapbuf); + if (maj_stat != GSS_S_COMPLETE) { + log_debug("gss_get_mic failed"); + return (FALSE); + } + /* Marshal checksum. */ + XDR_SETPOS(xdrs, end); + xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, + (u_int *)&wrapbuf.length, MAX_NETOBJ_SZ); + gss_release_buffer(&min_stat, &wrapbuf); + } + else if (svc == RPCSEC_GSS_SVC_PRIVACY) { + /* Encrypt rpc_gss_data_t. */ + maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, + &conf_state, &wrapbuf); + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_wrap", maj_stat, min_stat); + return (FALSE); + } + /* Marshal databody_priv. */ + XDR_SETPOS(xdrs, start); + xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, + (u_int *)&wrapbuf.length, MAX_NETOBJ_SZ); + gss_release_buffer(&min_stat, &wrapbuf); + } + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + gss_ctx_id_t ctx, gss_qop_t qop, + rpc_gss_svc_t svc, u_int seq) +{ + XDR tmpxdrs; + gss_buffer_desc databuf, wrapbuf; + OM_uint32 maj_stat, min_stat; + u_int seq_num, qop_state; + int conf_state; + bool_t xdr_stat; + + if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL) + return (TRUE); + + memset(&databuf, 0, sizeof(databuf)); + memset(&wrapbuf, 0, sizeof(wrapbuf)); + + if (svc == RPCSEC_GSS_SVC_INTEGRITY) { + /* Decode databody_integ. */ + if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length, + MAX_NETOBJ_SZ)) { + log_debug("xdr decode databody_integ failed"); + return (FALSE); + } + /* Decode checksum. */ + if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length, + MAX_NETOBJ_SZ)) { + gss_release_buffer(&min_stat, &databuf); + log_debug("xdr decode checksum failed"); + return (FALSE); + } + /* Verify checksum and QOP. */ + maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, + &wrapbuf, &qop_state); + gss_release_buffer(&min_stat, &wrapbuf); + + if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { + gss_release_buffer(&min_stat, &databuf); + log_status("gss_verify_mic", maj_stat, min_stat); + return (FALSE); + } + } + else if (svc == RPCSEC_GSS_SVC_PRIVACY) { + /* Decode databody_priv. */ + if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length, + MAX_NETOBJ_SZ)) { + log_debug("xdr decode databody_priv failed"); + return (FALSE); + } + /* Decrypt databody. */ + maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, + &conf_state, &qop_state); + + gss_release_buffer(&min_stat, &wrapbuf); + + /* Verify encryption and QOP. */ + if (maj_stat != GSS_S_COMPLETE || qop_state != qop || + conf_state != TRUE) { + gss_release_buffer(&min_stat, &databuf); + log_status("gss_unwrap", maj_stat, min_stat); + return (FALSE); + } + } + /* Decode rpc_gss_data_t (sequence number + arguments). */ + xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); + xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) && + (*xdr_func)(&tmpxdrs, xdr_ptr)); + XDR_DESTROY(&tmpxdrs); + gss_release_buffer(&min_stat, &databuf); + + /* Verify sequence number. */ + if (xdr_stat == TRUE && seq_num != seq) { + log_debug("wrong sequence number in databody"); + return (FALSE); + } + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + gss_ctx_id_t ctx, gss_qop_t qop, + rpc_gss_svc_t svc, u_int seq) +{ + switch (xdrs->x_op) { + + case XDR_ENCODE: + return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr, + ctx, qop, svc, seq)); + case XDR_DECODE: + return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr, + ctx, qop,svc, seq)); + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +#ifdef DEBUG +#include + +void +log_debug(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "rpcsec_gss: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void +log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) +{ + OM_uint32 min; + gss_buffer_desc msg; + int msg_ctx = 0; + + fprintf(stderr, "rpcsec_gss: %s: ", m); + + gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, + &msg_ctx, &msg); + fprintf(stderr, "%s - ", (char *)msg.value); + gss_release_buffer(&min, &msg); + + gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID, + &msg_ctx, &msg); + fprintf(stderr, "%s\n", (char *)msg.value); + gss_release_buffer(&min, &msg); +} + +void +log_hexdump(const u_char *buf, int len, int offset) +{ + u_int i, j, jm; + int c; + + fprintf(stderr, "\n"); + for (i = 0; i < len; i += 0x10) { + fprintf(stderr, " %04x: ", (u_int)(i + offset)); + jm = len - i; + jm = jm > 16 ? 16 : jm; + + for (j = 0; j < jm; j++) { + if ((j % 2) == 1) + fprintf(stderr, "%02x ", (u_int) buf[i+j]); + else + fprintf(stderr, "%02x", (u_int) buf[i+j]); + } + for (; j < 16; j++) { + if ((j % 2) == 1) printf(" "); + else fprintf(stderr, " "); + } + fprintf(stderr, " "); + + for (j = 0; j < jm; j++) { + c = buf[i+j]; + c = isprint(c) ? c : '.'; + fprintf(stderr, "%c", c); + } + fprintf(stderr, "\n"); + } +} + +#else + +void +log_debug(const char *fmt, ...) +{ +} + +void +log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) +{ +} + +void +log_hexdump(const u_char *buf, int len, int offset) +{ +} + +#endif + + diff --git a/libtirpc/src/authunix_prot.c b/libtirpc/src/authunix_prot.c new file mode 100644 index 0000000..79decde --- /dev/null +++ b/libtirpc/src/authunix_prot.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * authunix_prot.c + * XDR for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include + +#include +#include +#include +#include + +/* + * XDR for unix authentication parameters. + */ +bool_t +xdr_authunix_parms(xdrs, p) + XDR *xdrs; + struct authunix_parms *p; +{ + + assert(xdrs != NULL); + assert(p != NULL); + + if (xdr_u_long(xdrs, &(p->aup_time)) + && xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME) + && xdr_u_int(xdrs, &(p->aup_uid)) + && xdr_u_int(xdrs, &(p->aup_gid)) + && xdr_array(xdrs, (caddr_t *)&(p->aup_gids), + &(p->aup_len), NGRPS, sizeof(int), (xdrproc_t)xdr_int) ) { + return (TRUE); + } + return (FALSE); +} diff --git a/libtirpc/src/bindresvport.c b/libtirpc/src/bindresvport.c new file mode 100644 index 0000000..c1f0d9b --- /dev/null +++ b/libtirpc/src/bindresvport.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * Copyright (c) 1987 by Sun Microsystems, Inc. + * + * Portions Copyright(C) 1996, Jason Downs. All rights reserved. + */ + +#include +#include +//#include + +//#include + +#include +#include +//#include + +#include + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport(sd, sin) + SOCKET sd; + struct sockaddr_in *sin; +{ + return bindresvport_sa(sd, (struct sockaddr *)sin); +} + +#ifdef __linux__ + +#define STARTPORT 600 +#define LOWPORT 512 +#define ENDPORT (IPPORT_RESERVED - 1) +#define NPORTS (ENDPORT - STARTPORT + 1) + +int +bindresvport_sa(sd, sa) + int sd; + struct sockaddr *sa; +{ + int res, af; + struct sockaddr_storage myaddr; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + u_int16_t *portp; + static u_int16_t port; + static short startport = STARTPORT; + socklen_t salen; + int nports = ENDPORT - startport + 1; + int endport = ENDPORT; + int i; + + if (sa == NULL) { + salen = sizeof(myaddr); + sa = (struct sockaddr *)&myaddr; + + if (getsockname(sd, (struct sockaddr *)&myaddr, &salen) == -1) + return -1; /* errno is correctly set */ + + af = myaddr.ss_family; + } else + af = sa->sa_family; + + switch (af) { + case AF_INET: + sin = (struct sockaddr_in *)sa; + salen = sizeof(struct sockaddr_in); + port = ntohs(sin->sin_port); + portp = &sin->sin_port; + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)sa; + salen = sizeof(struct sockaddr_in6); + port = ntohs(sin6->sin6_port); + portp = &sin6->sin6_port; + break; +#endif + default: + errno = EPFNOSUPPORT; + return (-1); + } + sa->sa_family = af; + + if (port == 0) { + port = (getpid() % NPORTS) + STARTPORT; + } + res = -1; + errno = EADDRINUSE; + again: + for (i = 0; i < nports; ++i) { + *portp = htons(port++); + if (port > endport) + port = startport; + res = bind(sd, sa, salen); + if (res >= 0 || errno != EADDRINUSE) + break; + } + if (i == nports && startport != LOWPORT) { + startport = LOWPORT; + endport = STARTPORT - 1; + nports = STARTPORT - LOWPORT; + port = LOWPORT + port % (STARTPORT - LOWPORT); + goto again; + } + return (res); +} + +#else +/*---------------------- +#if defined(_WIN32) + +int +bindresvport_sa(SOCKET sd, struct sockaddr *sa) +{ + fprintf(stderr, "Do-nothing bindresvport_sa!\n"); + return 0; +} +#else +-------------------------*/ +#define IP_PORTRANGE 19 +#define IP_PORTRANGE_LOW 2 + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport_sa(sd, sa) + SOCKET sd; + struct sockaddr *sa; +{ +#ifdef IPV6_PORTRANGE + int old; +#endif + int error, af; + struct sockaddr_storage myaddr; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + int proto, portrange, portlow; + u_int16_t *portp; + socklen_t salen; +#ifdef _WIN32 + WSAPROTOCOL_INFO proto_info; + int proto_info_size = sizeof(proto_info); +#endif + + if (sa == NULL) { + salen = sizeof(myaddr); + sa = (struct sockaddr *)&myaddr; + +#ifdef _WIN32 + memset(sa, 0, salen); + if (error = getsockopt(sd, SOL_SOCKET, SO_PROTOCOL_INFO, (char *)&proto_info, &proto_info_size) == SOCKET_ERROR) { + int sockerr = WSAGetLastError(); + return -1; + } + af = proto_info.iAddressFamily; +#else + if (getsockname(sd, sa, &salen) == -1) + return -1; /* errno is correctly set */ + + af = sa->sa_family; + memset(sa, 0, salen); +#endif + } else + af = sa->sa_family; + + switch (af) { + case AF_INET: + proto = IPPROTO_IP; + portrange = IP_PORTRANGE; + portlow = IP_PORTRANGE_LOW; + sin = (struct sockaddr_in *)sa; + salen = sizeof(struct sockaddr_in); + portp = &sin->sin_port; + break; +#ifdef INET6 + case AF_INET6: + proto = IPPROTO_IPV6; +#ifdef IPV6_PORTRANGE + portrange = IPV6_PORTRANGE; + portlow = IPV6_PORTRANGE_LOW; +#endif + sin6 = (struct sockaddr_in6 *)sa; + salen = sizeof(struct sockaddr_in6); + portp = &sin6->sin6_port; + break; +#endif /* INET6 */ + default: + errno = WSAEPFNOSUPPORT; + return (-1); + } + sa->sa_family = (ADDRESS_FAMILY) af; + +#ifdef IPV6_PORTRANGE + if (*portp == 0) { + socklen_t oldlen = sizeof(old); + + error = getsockopt(sd, proto, portrange, &old, &oldlen); + if (error < 0) + return (error); + + error = setsockopt(sd, proto, portrange, &portlow, + sizeof(portlow)); + if (error < 0) + return (error); + } +#endif + + error = bind(sd, sa, salen); + if (error) { + int err = WSAGetLastError(); + } + +#ifdef IPV6_PORTRANGE + if (*portp == 0) { + int saved_errno = errno; + + if (error < 0) { + if (setsockopt(sd, proto, portrange, &old, + sizeof(old)) < 0) + errno = saved_errno; + return (error); + } + + if (sa != (struct sockaddr *)&myaddr) { + /* Hmm, what did the kernel assign? */ + if (getsockname(sd, sa, &salen) < 0) + errno = saved_errno; + return (error); + } + } +#endif + return (error); +} +/* +#endif +*/ +#endif \ No newline at end of file diff --git a/libtirpc/src/clnt_bcast.c b/libtirpc/src/clnt_bcast.c new file mode 100644 index 0000000..8d32c5d --- /dev/null +++ b/libtirpc/src/clnt_bcast.c @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ +//#include + +/* + * clnt_bcast.c + * Client interface to broadcast service. + * + * Copyright (C) 1988, Sun Microsystems, Inc. + * + * The following is kludged-up support for simple rpc broadcasts. + * Someday a large, complicated system will replace these routines. + */ + +#include +//#include +#include +//#include + +/* new queue functions */ +//#include + +//#include +//#include +//#include +//#include +#include +#ifdef PORTMAP +#include +#include +#include +#endif /* PORTMAP */ +#include +//#include +#ifdef RPC_DEBUG +#include +#endif +#include +#include +//#include +//#include +//#include +#include + +#include "rpc_com.h" + +#define MAXBCAST 20 /* Max no of broadcasting transports */ +#define INITTIME 4000 /* Time to wait initially */ +#define WAITTIME 8000 /* Maximum time to wait */ + +#ifndef POLLRDNORM +# define POLLRDNORM 0x040 /* Normal data may be read. */ +#endif +#ifndef POLLRDBAND +# define POLLRDBAND 0x080 /* Priority data may be read. */ +#endif + +/* + * For now, ASSUME that we do not need this for the Windows port!!!! + */ +#include +#ifdef _WIN32 +int __rpc_lowvers = 0; + +enum clnt_stat +rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, + eachresult, nettype) + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ + const char *nettype; /* transport type */ +{ + return 0; +} +#else + + +/* + * If nettype is NULL, it broadcasts on all the available + * datagram_n transports. May potentially lead to broadacst storms + * and hence should be used with caution, care and courage. + * + * The current parameter xdr packet size is limited by the max tsdu + * size of the transport. If the max tsdu size of any transport is + * smaller than the parameter xdr packet, then broadcast is not + * sent on that transport. + * + * Also, the packet size should be less the packet size of + * the data link layer (for ethernet it is 1400 bytes). There is + * no easy way to find out the max size of the data link layer and + * we are assuming that the args would be smaller than that. + * + * The result size has to be smaller than the transport tsdu size. + * + * If PORTMAP has been defined, we send two packets for UDP, one for + * rpcbind and one for portmap. For those machines which support + * both rpcbind and portmap, it will cause them to reply twice, and + * also here it will get two responses ... inefficient and clumsy. + */ + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + + +struct broadif { + int index; + struct sockaddr_storage broadaddr; + TAILQ_ENTRY(broadif) link; +}; + +typedef TAILQ_HEAD(, broadif) broadlist_t; + +int __rpc_getbroadifs(int, int, int, broadlist_t *); +void __rpc_freebroadifs(broadlist_t *); +int __rpc_broadenable(int, int, struct broadif *); + +int __rpc_lowvers = 0; + +int +__rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list) +{ + int count = 0; + struct broadif *bip; + struct ifaddrs *ifap, *ifp; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + struct sockaddr_in *sin; + struct addrinfo hints, *res; + +#if 0 /* WINDOWS */ + if (getifaddrs(&ifp) < 0) + return 0; +#else + /* Use GetAdaptersAddresses() ? */ +#endif + + memset(&hints, 0, sizeof hints); + + hints.ai_family = af; + hints.ai_protocol = proto; + hints.ai_socktype = socktype; + + if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) + return 0; + + for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { + if (ifap->ifa_addr->sa_family != af || + !(ifap->ifa_flags & IFF_UP)) + continue; + bip = (struct broadif *)malloc(sizeof *bip); + if (bip == NULL) + break; + bip->index = if_nametoindex(ifap->ifa_name); + if ( +#ifdef INET6 + af != AF_INET6 && +#endif + (ifap->ifa_flags & IFF_BROADCAST) && + ifap->ifa_broadaddr) { + /* memcpy(&bip->broadaddr, ifap->ifa_broadaddr, + (size_t)ifap->ifa_broadaddr->sa_len);*/ + memcpy(&bip->broadaddr, ifap->ifa_broadaddr, + sizeof(bip->broadaddr)); + sin = (struct sockaddr_in *)(void *)&bip->broadaddr; + sin->sin_port = + ((struct sockaddr_in *) + (void *)res->ai_addr)->sin_port; + } else +#ifdef INET6 + if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) { + sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr; + inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr); + sin6->sin6_family = af; + sin6->sin6_port = + ((struct sockaddr_in6 *) + (void *)res->ai_addr)->sin6_port; + sin6->sin6_scope_id = bip->index; + } else +#endif + { + free(bip); + continue; + } + TAILQ_INSERT_TAIL(list, bip, link); + count++; + } + freeifaddrs(ifp); + freeaddrinfo(res); + + return count; +} + +void +__rpc_freebroadifs(broadlist_t *list) +{ + struct broadif *bip, *next; + + bip = TAILQ_FIRST(list); + + while (bip != NULL) { + next = TAILQ_NEXT(bip, link); + free(bip); + bip = next; + } +} + +int +/*ARGSUSED*/ +__rpc_broadenable(int af, int s, struct broadif *bip) +{ + int o = 1; + +#if 0 + if (af == AF_INET6) { + fprintf(stderr, "set v6 multicast if to %d\n", bip->index); + if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index, + sizeof bip->index) < 0) + return -1; + } else +#endif + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) == SOCKET_ERROR) + return -1; + + return 0; +} + + +enum clnt_stat +rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp, + eachresult, inittime, waittime, nettype) + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ + int inittime; /* how long to wait initially */ + int waittime; /* maximum time to wait */ + const char *nettype; /* transport type */ +{ + enum clnt_stat stat = RPC_SUCCESS; /* Return status */ + XDR xdr_stream; /* XDR stream */ + XDR *xdrs = &xdr_stream; + struct rpc_msg msg; /* RPC message */ + struct timeval t; + char *outbuf = NULL; /* Broadcast msg buffer */ + char *inbuf = NULL; /* Reply buf */ + int inlen; + u_int maxbufsize = 0; + AUTH *sys_auth = authunix_create_default(); + int i; + void *handle; + char uaddress[1024]; /* A self imposed limit */ + char *uaddrp = uaddress; + int pmap_reply_flag; /* reply recvd from PORTMAP */ + /* An array of all the suitable broadcast transports */ + struct { + int fd; /* File descriptor */ + int af; + int proto; + struct netconfig *nconf; /* Netconfig structure */ + u_int asize; /* Size of the addr buf */ + u_int dsize; /* Size of the data buf */ + struct sockaddr_storage raddr; /* Remote address */ + broadlist_t nal; + } fdlist[MAXBCAST]; + struct pollfd pfd[MAXBCAST]; + size_t fdlistno = 0; + struct r_rpcb_rmtcallargs barg; /* Remote arguments */ + struct r_rpcb_rmtcallres bres; /* Remote results */ + size_t outlen; + struct netconfig *nconf; + int msec; + int pollretval; + int fds_found; + +#ifdef PORTMAP + size_t outlen_pmap = 0; + u_long port; /* Remote port number */ + int pmap_flag = 0; /* UDP exists ? */ + char *outbuf_pmap = NULL; + struct rmtcallargs barg_pmap; /* Remote arguments */ + struct rmtcallres bres_pmap; /* Remote results */ + u_int udpbufsz = 0; +#endif /* PORTMAP */ + + if (sys_auth == NULL) { + return (RPC_SYSTEMERROR); + } + /* + * initialization: create a fd, a broadcast address, and send the + * request on the broadcast transport. + * Listen on all of them and on replies, call the user supplied + * function. + */ + + if (nettype == NULL) + nettype = "datagram_n"; + if ((handle = __rpc_setconf(nettype)) == NULL) { + return (RPC_UNKNOWNPROTO); + } + while ((nconf = __rpc_getconf(handle)) != NULL) { + int fd; + struct __rpc_sockinfo si; + + if (nconf->nc_semantics != NC_TPI_CLTS) + continue; + if (fdlistno >= MAXBCAST) + break; /* No more slots available */ + if (!__rpc_nconf2sockinfo(nconf, &si)) + continue; + + TAILQ_INIT(&fdlist[fdlistno].nal); + if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, + &fdlist[fdlistno].nal) == 0) + continue; + + fd = socket(si.si_af, si.si_socktype, si.si_proto); + if (fd == INVALID_SOCKET) { + stat = RPC_CANTSEND; + continue; + } + fdlist[fdlistno].af = si.si_af; + fdlist[fdlistno].proto = si.si_proto; + fdlist[fdlistno].fd = fd; + fdlist[fdlistno].nconf = nconf; + fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af); + pfd[fdlistno].events = POLLIN | POLLPRI | + POLLRDNORM | POLLRDBAND; + pfd[fdlistno].fd = fdlist[fdlistno].fd = fd; + fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto, + 0); + + if (maxbufsize <= fdlist[fdlistno].dsize) + maxbufsize = fdlist[fdlistno].dsize; + +#ifdef PORTMAP + if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) { + udpbufsz = fdlist[fdlistno].dsize; + if ((outbuf_pmap = malloc(udpbufsz)) == NULL) { + closesocket(fd); + stat = RPC_SYSTEMERROR; + goto done_broad; + } + pmap_flag = 1; + } +#endif /* PORTMAP */ + fdlistno++; + } + + if (fdlistno == 0) { + if (stat == RPC_SUCCESS) + stat = RPC_UNKNOWNPROTO; + goto done_broad; + } + if (maxbufsize == 0) { + if (stat == RPC_SUCCESS) + stat = RPC_CANTSEND; + goto done_broad; + } + inbuf = malloc(maxbufsize); + outbuf = malloc(maxbufsize); + if ((inbuf == NULL) || (outbuf == NULL)) { + stat = RPC_SYSTEMERROR; + goto done_broad; + } + + /* Serialize all the arguments which have to be sent */ + (void) gettimeofday(&t, NULL); + msg.rm_xid = __RPC_GETXID(&t); + msg.rm_direction = CALL; + msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + msg.rm_call.cb_prog = RPCBPROG; + msg.rm_call.cb_vers = RPCBVERS; + msg.rm_call.cb_proc = RPCBPROC_CALLIT; + barg.prog = prog; + barg.vers = vers; + barg.proc = proc; + barg.args.args_val = argsp; + barg.xdr_args = xargs; + bres.addr = uaddrp; + bres.results.results_val = resultsp; + bres.xdr_res = xresults; + msg.rm_call.cb_cred = sys_auth->ah_cred; + msg.rm_call.cb_verf = sys_auth->ah_verf; + xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE); + if ((!xdr_callmsg(xdrs, &msg)) || + (!xdr_rpcb_rmtcallargs(xdrs, + (struct rpcb_rmtcallargs *)(void *)&barg))) { + stat = RPC_CANTENCODEARGS; + goto done_broad; + } + outlen = xdr_getpos(xdrs); + xdr_destroy(xdrs); + +#ifdef PORTMAP + /* Prepare the packet for version 2 PORTMAP */ + if (pmap_flag) { + msg.rm_xid++; /* One way to distinguish */ + msg.rm_call.cb_prog = PMAPPROG; + msg.rm_call.cb_vers = PMAPVERS; + msg.rm_call.cb_proc = PMAPPROC_CALLIT; + barg_pmap.prog = prog; + barg_pmap.vers = vers; + barg_pmap.proc = proc; + barg_pmap.args_ptr = argsp; + barg_pmap.xdr_args = xargs; + bres_pmap.port_ptr = &port; + bres_pmap.xdr_results = xresults; + bres_pmap.results_ptr = resultsp; + xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE); + if ((! xdr_callmsg(xdrs, &msg)) || + (! xdr_rmtcall_args(xdrs, &barg_pmap))) { + stat = RPC_CANTENCODEARGS; + goto done_broad; + } + outlen_pmap = xdr_getpos(xdrs); + xdr_destroy(xdrs); + } +#endif /* PORTMAP */ + + /* + * Basic loop: broadcast the packets to transports which + * support data packets of size such that one can encode + * all the arguments. + * Wait a while for response(s). + * The response timeout grows larger per iteration. + */ + for (msec = inittime; msec <= waittime; msec += msec) { + struct broadif *bip; + + /* Broadcast all the packets now */ + for (i = 0; i < fdlistno; i++) { + if (fdlist[i].dsize < outlen) { + stat = RPC_CANTSEND; + continue; + } + for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; + bip = TAILQ_NEXT(bip, link)) { + void *addr; + + addr = &bip->broadaddr; + + __rpc_broadenable(fdlist[i].af, fdlist[i].fd, + bip); + + /* + * Only use version 3 if lowvers is not set + */ + + if (!__rpc_lowvers) + if (sendto(fdlist[i].fd, outbuf, + outlen, 0, (struct sockaddr*)addr, + (size_t)fdlist[i].asize) != + outlen) { +#ifdef RPC_DEBUG + perror("sendto"); +#endif + warnx("clnt_bcast: cannot send" + "broadcast packet"); + stat = RPC_CANTSEND; + continue; + }; +#ifdef RPC_DEBUG + if (!__rpc_lowvers) + fprintf(stderr, "Broadcast packet sent " + "for %s\n", + fdlist[i].nconf->nc_netid); +#endif +#ifdef PORTMAP + /* + * Send the version 2 packet also + * for UDP/IP + */ + if (pmap_flag && + fdlist[i].proto == IPPROTO_UDP) { + if (sendto(fdlist[i].fd, outbuf_pmap, + outlen_pmap, 0, addr, + (size_t)fdlist[i].asize) != + outlen_pmap) { + warnx("clnt_bcast: " + "Cannot send broadcast packet"); + stat = RPC_CANTSEND; + continue; + } + } +#ifdef RPC_DEBUG + fprintf(stderr, "PMAP Broadcast packet " + "sent for %s\n", + fdlist[i].nconf->nc_netid); +#endif +#endif /* PORTMAP */ + } + /* End for sending all packets on this transport */ + } /* End for sending on all transports */ + + if (eachresult == NULL) { + stat = RPC_SUCCESS; + goto done_broad; + } + + /* + * Get all the replies from these broadcast requests + */ + recv_again: + + switch (pollretval = poll(pfd, fdlistno, msec)) { + case 0: /* timed out */ + stat = RPC_TIMEDOUT; + continue; + case -1: /* some kind of error - we ignore it */ + goto recv_again; + } /* end of poll results switch */ + + for (i = fds_found = 0; + i < fdlistno && fds_found < pollretval; i++) { + bool_t done = FALSE; + + if (pfd[i].revents == 0) + continue; + else if (pfd[i].revents & POLLNVAL) { + /* + * Something bad has happened to this descri- + * ptor. We can cause _poll() to ignore + * it simply by using a negative fd. We do that + * rather than compacting the pfd[] and fdlist[] + * arrays. + */ + pfd[i].fd = -1; + fds_found++; + continue; + } else + fds_found++; +#ifdef RPC_DEBUG + fprintf(stderr, "response for %s\n", + fdlist[i].nconf->nc_netid); +#endif + try_again: + inlen = recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, + 0, (struct sockaddr *)(void *)&fdlist[i].raddr, + &fdlist[i].asize); + if (inlen < 0) { + if (errno == EINTR) + goto try_again; + warnx("clnt_bcast: Cannot receive reply to " + "broadcast"); + stat = RPC_CANTRECV; + continue; + } + if (inlen < sizeof (u_int32_t)) + continue; /* Drop that and go ahead */ + /* + * see if reply transaction id matches sent id. + * If so, decode the results. If return id is xid + 1 + * it was a PORTMAP reply + */ + if (*((u_int32_t *)(void *)(inbuf)) == + *((u_int32_t *)(void *)(outbuf))) { + pmap_reply_flag = 0; + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = + (caddr_t)(void *)&bres; + msg.acpted_rply.ar_results.proc = + (xdrproc_t)xdr_rpcb_rmtcallres; +#ifdef PORTMAP + } else if (pmap_flag && + *((u_int32_t *)(void *)(inbuf)) == + *((u_int32_t *)(void *)(outbuf_pmap))) { + pmap_reply_flag = 1; + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = + (caddr_t)(void *)&bres_pmap; + msg.acpted_rply.ar_results.proc = + (xdrproc_t)xdr_rmtcallres; +#endif /* PORTMAP */ + } else + continue; + xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); + if (xdr_replymsg(xdrs, &msg)) { + if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (msg.acpted_rply.ar_stat == SUCCESS)) { + struct netbuf *np; +#ifdef PORTMAP + struct netbuf taddr; + struct sockaddr_in sin; + + if (pmap_flag && pmap_reply_flag) { + memcpy(&sin, &fdlist[i].raddr, sizeof(sin)); + sin.sin_port = htons((u_short)port); + memcpy(&fdlist[i].raddr, &sin, sizeof(sin)); + taddr.len = taddr.maxlen = + sizeof(fdlist[i].raddr); + taddr.buf = &fdlist[i].raddr; + done = (*eachresult)(resultsp, + &taddr, fdlist[i].nconf); + } else { +#endif /* PORTMAP */ +#ifdef RPC_DEBUG + fprintf(stderr, "uaddr %s\n", + uaddrp); +#endif + np = uaddr2taddr( + fdlist[i].nconf, uaddrp); + done = (*eachresult)(resultsp, + np, fdlist[i].nconf); + free(np); +#ifdef PORTMAP + } +#endif /* PORTMAP */ + } + /* otherwise, we just ignore the errors ... */ + } + /* else some kind of deserialization problem ... */ + + xdrs->x_op = XDR_FREE; + msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; + (void) xdr_replymsg(xdrs, &msg); + (void) (*xresults)(xdrs, resultsp); + XDR_DESTROY(xdrs); + if (done) { + stat = RPC_SUCCESS; + goto done_broad; + } else { + goto recv_again; + } + } /* The recv for loop */ + } /* The giant for loop */ + +done_broad: + if (inbuf) + (void) free(inbuf); + if (outbuf) + (void) free(outbuf); +#ifdef PORTMAP + if (outbuf_pmap) + (void) free(outbuf_pmap); +#endif /* PORTMAP */ + for (i = 0; i < fdlistno; i++) { + (void)closesocket(fdlist[i].fd); + __rpc_freebroadifs(&fdlist[i].nal); + } + AUTH_DESTROY(sys_auth); + (void) __rpc_endconf(handle); + + return (stat); +} + + +enum clnt_stat +rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, + eachresult, nettype) + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ + const char *nettype; /* transport type */ +{ + enum clnt_stat dummy; + + dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp, + xresults, resultsp, eachresult, + INITTIME, WAITTIME, nettype); + return (dummy); +} + +#endif diff --git a/libtirpc/src/clnt_dg.c b/libtirpc/src/clnt_dg.c new file mode 100644 index 0000000..145b5e1 --- /dev/null +++ b/libtirpc/src/clnt_dg.c @@ -0,0 +1,845 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * Implements a connectionless client side RPC. + */ +#include +//#include +#include +#include +//#include +//#include +//#include + +//#include + +//#include +#include +//#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +#include "rpc_com.h" + +#ifdef IP_RECVERR +#include +#include +#include +#endif + + +#define MAX_DEFAULT_FDS 20000 + +static struct clnt_ops *clnt_dg_ops(void); +static bool_t time_not_ok(struct timeval *); +static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, + xdrproc_t, void *, struct timeval); +static void clnt_dg_geterr(CLIENT *, struct rpc_err *); +static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); +static void clnt_dg_abort(CLIENT *); +static bool_t clnt_dg_control(CLIENT *, u_int, void *); +static void clnt_dg_destroy(CLIENT *); + + +/* + * This machinery implements per-fd locks for MT-safety. It is not + * sufficient to do per-CLIENT handle locks for MT-safety because a + * user may create more than one CLIENT handle with the same fd behind + * it. Therfore, we allocate an array of flags (dg_fd_locks), protected + * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables + * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some + * CLIENT handle created for that fd. + * The current implementation holds locks across the entire RPC and reply, + * including retransmissions. Yes, this is silly, and as soon as this + * code is proven to work, this should be the first thing fixed. One step + * at a time. + */ +static int *dg_fd_locks; +extern mutex_t clnt_fd_lock; +static cond_t *dg_cv; +#ifndef _WIN32 +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + dg_fd_locks[fd] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ + cond_signal(&dg_cv[fd]); \ +} +#else +/* XXX Needs Windows signal/event stuff XXX */ +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + dg_fd_locks[WINSOCK_HANDLE_HASH(fd)] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + \ + cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(fd)]); \ +} +#endif + +static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; + +/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ + +/* + * Private data kept per client handle + */ +struct cu_data { + SOCKET cu_fd; /* connections fd */ + bool_t cu_closeit; /* opened by library */ + struct sockaddr_storage cu_raddr; /* remote address */ + int cu_rlen; + struct timeval cu_wait; /* retransmit interval */ + struct timeval cu_total; /* total time for the call */ + struct rpc_err cu_error; + XDR cu_outxdrs; + u_int cu_xdrpos; + u_int cu_sendsz; /* send size */ + char *cu_outbuf; + u_int cu_recvsz; /* recv size */ + int cu_async; + int cu_connect; /* Use connect(). */ + int cu_connected; /* Have done connect(). */ + char cu_inbuf[1]; +}; + +/* + * Connection less client creation returns with client handle parameters. + * Default options are set, which the user can change using clnt_control(). + * fd should be open and bound. + * NB: The rpch->cl_auth is initialized to null authentication. + * Caller may wish to set this something more useful. + * + * sendsz and recvsz are the maximum allowable packet sizes that can be + * sent and received. Normally they are the same, but they can be + * changed to improve the program efficiency and buffer allocation. + * If they are 0, use the transport default. + * + * If svcaddr is NULL, returns NULL. + */ +CLIENT * +clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) + SOCKET fd; /* open file descriptor */ + const struct netbuf *svcaddr; /* servers address */ + rpcprog_t program; /* program number */ + rpcvers_t version; /* version number */ + u_int sendsz; /* buffer recv size */ + u_int recvsz; /* buffer send size */ +{ + CLIENT *cl = NULL; /* client handle */ + struct cu_data *cu = NULL; /* private data */ + struct timeval now; + struct rpc_msg call_msg; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + struct __rpc_sockinfo si; + u_long one = 1; + +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + mutex_lock(&clnt_fd_lock); + if (dg_fd_locks == (int *) NULL) { + int cv_allocsz; + size_t fd_allocsz; + int dtbsize = __rpc_dtbsize(); + + fd_allocsz = dtbsize * sizeof (int); + dg_fd_locks = (int *) mem_alloc(fd_allocsz); + if (dg_fd_locks == (int *) NULL) { + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err1; + } else + memset(dg_fd_locks, 0, fd_allocsz); + + cv_allocsz = dtbsize * sizeof (cond_t); + dg_cv = (cond_t *) mem_alloc(cv_allocsz); + if (dg_cv == (cond_t *) NULL) { + mem_free(dg_fd_locks, fd_allocsz); + dg_fd_locks = (int *) NULL; + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err1; + } else { + int i; + + for (i = 0; i < dtbsize; i++) + cond_init(&dg_cv[i], 0, (void *) 0); + } + } + + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + + if (svcaddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + + if (!__rpc_fd2sockinfo(fd, &si)) { + rpc_createerr.cf_stat = RPC_TLIERROR; + rpc_createerr.cf_error.re_errno = 0; + return (NULL); + } + /* + * Find the receive and the send size + */ + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); + if ((sendsz == 0) || (recvsz == 0)) { + rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ + rpc_createerr.cf_error.re_errno = 0; + return (NULL); + } + + if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) + goto err1; + /* + * Should be multiple of 4 for XDR. + */ + sendsz = ((sendsz + 3) / 4) * 4; + recvsz = ((recvsz + 3) / 4) * 4; + cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); + if (cu == NULL) + goto err1; + (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); + cu->cu_rlen = svcaddr->len; + cu->cu_outbuf = &cu->cu_inbuf[recvsz]; + /* Other values can also be set through clnt_control() */ + cu->cu_wait.tv_sec = 15; /* heuristically chosen */ + cu->cu_wait.tv_usec = 0; + cu->cu_total.tv_sec = -1; + cu->cu_total.tv_usec = -1; + cu->cu_sendsz = sendsz; + cu->cu_recvsz = recvsz; + cu->cu_async = FALSE; + cu->cu_connect = FALSE; + cu->cu_connected = FALSE; + (void) gettimeofday(&now, NULL); +// call_msg.rm_xid = __RPC_GETXID(&now); + + call_msg.rm_xid = ((u_int32_t)_getpid() ^ (u_int32_t)(&now)->tv_sec ^ (u_int32_t)(&now)->tv_usec); + call_msg.rm_call.cb_prog = program; + call_msg.rm_call.cb_vers = version; + xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); + if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { + rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ + rpc_createerr.cf_error.re_errno = 0; + goto err2; + } + cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); + + /* XXX fvdl - do we still want this? */ +#if 0 + (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); +#endif +#ifdef IP_RECVERR + { + int on = 1; + setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on)); + } +#endif + ioctlsocket(fd, FIONBIO, &one); + /* + * By default, closeit is always FALSE. It is users responsibility + * to do a close on it, else the user may use clnt_control + * to let clnt_destroy do it for him/her. + */ + cu->cu_closeit = FALSE; + cu->cu_fd = fd; + cl->cl_ops = clnt_dg_ops(); + cl->cl_private = (caddr_t)(void *)cu; + cl->cl_auth = authnone_create(); + cl->cl_tp = NULL; + cl->cl_netid = NULL; + + return (cl); +err1: + //warnx(mem_err_clnt_dg); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; +err2: + if (cl) { + mem_free(cl, sizeof (CLIENT)); + if (cu) + mem_free(cu, sizeof (*cu) + sendsz + recvsz); + } + return (NULL); +} + +static enum clnt_stat +clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) + CLIENT *cl; /* client handle */ + rpcproc_t proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + void *argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + void *resultsp; /* pointer to results */ + struct timeval utimeout; /* seconds to wait before giving up */ +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + XDR *xdrs; + size_t outlen = 0; + struct rpc_msg reply_msg; + XDR reply_xdrs; + bool_t ok; + int nrefreshes = 2; /* number of times to refresh cred */ + struct timeval timeout; + struct pollfd fd; + int total_time, nextsend_time, tv=0; + struct sockaddr *sa; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + socklen_t inlen, salen; + ssize_t recvlen = 0; + int rpc_lock_value; + u_int32_t xid, inval, outval; + + outlen = 0; +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)]) + cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)], &clnt_fd_lock); + rpc_lock_value = 1; + dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + if (cu->cu_total.tv_usec == -1) { + timeout = utimeout; /* use supplied timeout */ + } else { + timeout = cu->cu_total; /* use default timeout */ + } + total_time = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; + nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000; + + if (cu->cu_connect && !cu->cu_connected) { + if (connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, + cu->cu_rlen) < 0) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTSEND; + goto out; + } + cu->cu_connected = 1; + } + if (cu->cu_connected) { + sa = NULL; + salen = 0; + } else { + sa = (struct sockaddr *)&cu->cu_raddr; + salen = cu->cu_rlen; + } + + /* Clean up in case the last call ended in a longjmp(3) call. */ +call_again: + xdrs = &(cu->cu_outxdrs); + if (cu->cu_async == TRUE && xargs == NULL) + goto get_reply; + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, cu->cu_xdrpos); + /* + * the transaction is the first thing in the out buffer + * XXX Yes, and it's in network byte order, so we should to + * be careful when we increment it, shouldn't we. + */ + xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); + xid++; + *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); + + if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + cu->cu_error.re_status = RPC_CANTENCODEARGS; + goto out; + } + outlen = (size_t)XDR_GETPOS(xdrs); + + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + cu->cu_error.re_status = RPC_TIMEDOUT; + goto out; + } + +send_again: + if (total_time <= 0) { + cu->cu_error.re_status = RPC_TIMEDOUT; + goto out; + } + nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000; + if (sendto(cu->cu_fd, cu->cu_outbuf, (int)outlen, 0, sa, salen) != outlen) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTSEND; + goto out; + } + +get_reply: + + /* + * sub-optimal code appears here because we have + * some clock time to spare while the packets are in flight. + * (We assume that this is actually only executed once.) + */ + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + + fd.fd = cu->cu_fd; + fd.events = POLLIN; + fd.revents = 0; + while (total_time > 0) { + tv = total_time < nextsend_time ? total_time : nextsend_time; + switch (poll(&fd, 1, tv)) { + case 0: + total_time -= tv; + goto send_again; + // XXX CHECK THIS FOR WINDOWS! + case -1: + if (errno == EINTR) + continue; + cu->cu_error.re_status = RPC_CANTRECV; + cu->cu_error.re_errno = errno; + goto out; + } + break; + } +#ifdef IP_RECVERR + if (fd.revents & POLLERR) + { + struct msghdr msg; + struct cmsghdr *cmsg; + struct sock_extended_err *e; + struct sockaddr_in err_addr; + struct sockaddr_in *sin = (struct sockaddr_in *)&cu->cu_raddr; + struct iovec iov; + char *cbuf = (char *) alloca (outlen + 256); + int ret; + + iov.iov_base = cbuf + 256; + iov.iov_len = outlen; + msg.msg_name = (void *) &err_addr; + msg.msg_namelen = sizeof (err_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + msg.msg_control = cbuf; + msg.msg_controllen = 256; + ret = recvmsg (cu->cu_fd, &msg, MSG_ERRQUEUE); + if (ret >= 0 + && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0 + && (msg.msg_flags & MSG_ERRQUEUE) + && ((msg.msg_namelen == 0 + && ret >= 12) + || (msg.msg_namelen == sizeof (err_addr) + && err_addr.sin_family == AF_INET + && memcmp (&err_addr.sin_addr, &sin->sin_addr, + sizeof (err_addr.sin_addr)) == 0 + && err_addr.sin_port == sin->sin_port))) + for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; + cmsg = CMSG_NXTHDR (&msg, cmsg)) + if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) + { + e = (struct sock_extended_err *) CMSG_DATA(cmsg); + cu->cu_error.re_errno = e->ee_errno; + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status = RPC_CANTRECV); + } + } +#endif + + /* We have some data now */ + do { + recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf, + cu->cu_recvsz, 0, NULL, NULL); + errno = WSAGetLastError(); + } while (recvlen == SOCKET_ERROR && errno == WSAEINTR); + if (recvlen == SOCKET_ERROR && errno != WSAEWOULDBLOCK) { + cu->cu_error.re_errno = errno; + cu->cu_error.re_status = RPC_CANTRECV; + goto out; + } + + if (recvlen < sizeof(u_int32_t)) { + total_time -= tv; + goto send_again; + } + + if (cu->cu_async == TRUE) + inlen = (socklen_t)recvlen; + else { + memcpy(&inval, cu->cu_inbuf, sizeof(u_int32_t)); + memcpy(&outval, cu->cu_outbuf, sizeof(u_int32_t)); + if (inval != outval) { + total_time -= tv; + goto send_again; + } + inlen = (socklen_t)recvlen; + } + + /* + * now decode and validate the response + */ + + xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE); + ok = xdr_replymsg(&reply_xdrs, &reply_msg); + /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ + if (ok) { + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (reply_msg.acpted_rply.ar_stat == SUCCESS)) + cu->cu_error.re_status = RPC_SUCCESS; + else + _seterr_reply(&reply_msg, &(cu->cu_error)); + + if (cu->cu_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &reply_msg.acpted_rply.ar_verf)) { + cu->cu_error.re_status = RPC_AUTHERROR; + cu->cu_error.re_why = AUTH_INVALIDRESP; + } + if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void) xdr_opaque_auth(xdrs, + &(reply_msg.acpted_rply.ar_verf)); + } + } /* end successful completion */ + /* + * If unsuccesful AND error is an authentication error + * then refresh credentials and try again, else break + */ + else if (cu->cu_error.re_status == RPC_AUTHERROR) + /* maybe our credentials need to be refreshed ... */ + if (nrefreshes > 0 && + AUTH_REFRESH(cl->cl_auth, &reply_msg)) { + nrefreshes--; + goto call_again; + } + /* end of unsuccessful completion */ + } /* end of valid reply message */ + else { + cu->cu_error.re_status = RPC_CANTDECODERES; + + } +out: + release_fd_lock(cu->cu_fd, mask); + return (cu->cu_error.re_status); +} + +static void +clnt_dg_geterr(cl, errp) + CLIENT *cl; + struct rpc_err *errp; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + + *errp = cu->cu_error; +} + +static bool_t +clnt_dg_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + void *res_ptr; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + XDR *xdrs = &(cu->cu_outxdrs); + bool_t dummy; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)]) + cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)], &clnt_fd_lock); + xdrs->x_op = XDR_FREE; + dummy = (*xdr_res)(xdrs, res_ptr); + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &mask, NULL); + cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)]); + return (dummy); +} + +/*ARGSUSED*/ +static void +clnt_dg_abort(h) + CLIENT *h; +{ +} + +static bool_t +clnt_dg_control(cl, request, info) + CLIENT *cl; + u_int request; + void *info; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + struct netbuf *addr; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + int rpc_lock_value; + +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)]) + cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu->cu_fd)], &clnt_fd_lock); + rpc_lock_value = 1; + dg_fd_locks[WINSOCK_HANDLE_HASH(cu->cu_fd)] = rpc_lock_value; + mutex_unlock(&clnt_fd_lock); + switch (request) { + case CLSET_FD_CLOSE: + cu->cu_closeit = TRUE; + release_fd_lock(cu->cu_fd, mask); + return (TRUE); + case CLSET_FD_NCLOSE: + cu->cu_closeit = FALSE; + release_fd_lock(cu->cu_fd, mask); + return (TRUE); + } + + /* for other requests which use info */ + if (info == NULL) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + switch (request) { + case CLSET_TIMEOUT: + if (time_not_ok((struct timeval *)info)) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + cu->cu_total = *(struct timeval *)info; + break; + case CLGET_TIMEOUT: + *(struct timeval *)info = cu->cu_total; + break; + case CLGET_SERVER_ADDR: /* Give him the fd address */ + /* Now obsolete. Only for backward compatibility */ + (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); + break; + case CLSET_RETRY_TIMEOUT: + if (time_not_ok((struct timeval *)info)) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + cu->cu_wait = *(struct timeval *)info; + break; + case CLGET_RETRY_TIMEOUT: + *(struct timeval *)info = cu->cu_wait; + break; + case CLGET_FD: + *(SOCKET *)info = cu->cu_fd; + break; + case CLGET_SVC_ADDR: + addr = (struct netbuf *)info; + addr->buf = &cu->cu_raddr; + addr->len = cu->cu_rlen; + addr->maxlen = sizeof cu->cu_raddr; + break; + case CLSET_SVC_ADDR: /* set to new address */ + addr = (struct netbuf *)info; + if (addr->len < sizeof cu->cu_raddr) { + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); + cu->cu_rlen = addr->len; + break; + case CLGET_XID: + /* + * use the knowledge that xid is the + * first element in the call structure *. + * This will get the xid of the PREVIOUS call + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); + break; + + case CLSET_XID: + /* This will set the xid of the NEXT call */ + *(u_int32_t *)(void *)cu->cu_outbuf = + htonl(*(u_int32_t *)info - 1); + /* decrement by 1 as clnt_dg_call() increments once */ + break; + + case CLGET_VERS: + /* + * This RELIES on the information that, in the call body, + * the version number field is the fifth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + + 4 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_VERS: + *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) + = htonl(*(u_int32_t *)info); + break; + + case CLGET_PROG: + /* + * This RELIES on the information that, in the call body, + * the program number field is the fourth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + + 3 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_PROG: + *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) + = htonl(*(u_int32_t *)info); + break; + case CLSET_ASYNC: + cu->cu_async = *(int *)info; + break; + case CLSET_CONNECT: + cu->cu_connect = *(int *)info; + break; + default: + release_fd_lock(cu->cu_fd, mask); + return (FALSE); + } + release_fd_lock(cu->cu_fd, mask); + return (TRUE); +} + +static void +clnt_dg_destroy(cl) + CLIENT *cl; +{ + struct cu_data *cu = (struct cu_data *)cl->cl_private; + SOCKET cu_fd = cu->cu_fd; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + mutex_lock(&clnt_fd_lock); + while (dg_fd_locks[WINSOCK_HANDLE_HASH(cu_fd)]) + cond_wait(&dg_cv[WINSOCK_HANDLE_HASH(cu_fd)], &clnt_fd_lock); + if (cu->cu_closeit) + (void)closesocket(cu_fd); + XDR_DESTROY(&(cu->cu_outxdrs)); + mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); + if (cl->cl_netid && cl->cl_netid[0]) + mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); + if (cl->cl_tp && cl->cl_tp[0]) + mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); + mem_free(cl, sizeof (CLIENT)); + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &mask, NULL); + cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(cu_fd)]); +} + +static struct clnt_ops * +clnt_dg_ops() +{ + static struct clnt_ops ops; + extern mutex_t ops_lock; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff here XXX */ +#endif + mutex_lock(&ops_lock); + if (ops.cl_call == NULL) { + ops.cl_call = clnt_dg_call; + ops.cl_abort = clnt_dg_abort; + ops.cl_geterr = clnt_dg_geterr; + ops.cl_freeres = clnt_dg_freeres; + ops.cl_destroy = clnt_dg_destroy; + ops.cl_control = clnt_dg_control; + } + mutex_unlock(&ops_lock); +// thr_sigsetmask(SIG_SETMASK, &mask, NULL); + return (&ops); +} + +/* + * Make sure that the time is not garbage. -1 value is allowed. + */ +static bool_t +time_not_ok(t) + struct timeval *t; +{ + return (t->tv_sec < -1 || t->tv_sec > 100000000 || + t->tv_usec < -1 || t->tv_usec > 1000000); +} + diff --git a/libtirpc/src/clnt_generic.c b/libtirpc/src/clnt_generic.c new file mode 100644 index 0000000..bbe153a --- /dev/null +++ b/libtirpc/src/clnt_generic.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. + * All rights reserved. + */ +#include +//#include +#include +#include +//#include +#include +//#include +//#include +//#include +#include +#include +#include +#include +//#include +//#include +#include +#include +//#include +#include "rpc_com.h" + +extern bool_t __rpc_is_local_host(const char *); +#if 0 /* WINDOWS */ +int __rpc_raise_fd(int); +#endif + +#ifndef NETIDLEN +#define NETIDLEN 32 +#endif + +/* + * Generic client creation with version checking the value of + * vers_out is set to the highest server supported value + * vers_low <= vers_out <= vers_high AND an error results + * if this can not be done. + * + * It calls clnt_create_vers_timed() with a NULL value for the timeout + * pointer, which indicates that the default timeout should be used. + */ +CLIENT * +clnt_create_vers(const char *hostname, const rpcprog_t prog, rpcvers_t *vers_out, + const rpcvers_t vers_low, const rpcvers_t vers_high, const char *nettype) +{ + + return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, + vers_high, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create_vers(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + */ +CLIENT * +clnt_create_vers_timed(const char *hostname, const rpcprog_t prog, + rpcvers_t *vers_out, const rpcvers_t vers_low_in, const rpcvers_t vers_high_in, + const char *nettype, const struct timeval *tp) +{ + CLIENT *clnt; + struct timeval to; + enum clnt_stat rpc_stat; + struct rpc_err rpcerr; + rpcvers_t vers_high = vers_high_in; + rpcvers_t vers_low = vers_low_in; + + clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); + if (clnt == NULL) { + return (NULL); + } + to.tv_sec = 10; + to.tv_usec = 0; + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); + if (rpc_stat == RPC_SUCCESS) { + *vers_out = vers_high; + return (clnt); + } + while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { + unsigned int minvers, maxvers; + + clnt_geterr(clnt, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + if (maxvers < vers_high) + vers_high = maxvers; + else + vers_high--; + if (minvers > vers_low) + vers_low = minvers; + if (vers_low > vers_high) { + goto error; + } + CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, + (char *)NULL, to); + if (rpc_stat == RPC_SUCCESS) { + *vers_out = vers_high; + return (clnt); + } + } + clnt_geterr(clnt, &rpcerr); + +error: + rpc_createerr.cf_stat = rpc_stat; + rpc_createerr.cf_error = rpcerr; + clnt_destroy(clnt); + return (NULL); +} + +/* + * Top level client creation routine. + * Generic client creation: takes (servers name, program-number, nettype) and + * returns client handle. Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s. + * + * It tries for all the netids in that particular class of netid until + * it succeeds. + * XXX The error message in the case of failure will be the one + * pertaining to the last create error. + * + * It calls clnt_create_timed() with the default timeout. + */ +CLIENT * +clnt_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, + const char *nettype) +{ + + return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + * + * This function calls clnt_tp_create_timed(). + */ +CLIENT * +clnt_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, + const char *netclass, const struct timeval *tp) +{ + struct netconfig *nconf; + CLIENT *clnt = NULL; + void *handle; + enum clnt_stat save_cf_stat = RPC_SUCCESS; + struct rpc_err save_cf_error; + char nettype_array[NETIDLEN]; + char *nettype = &nettype_array[0]; + + if (netclass == NULL) + nettype = NULL; + else { + size_t len = strlen(netclass); + if (len >= sizeof (nettype_array)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + strcpy(nettype, netclass); + } + + if ((handle = __rpc_setconf((char *)nettype)) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + rpc_createerr.cf_stat = RPC_SUCCESS; + while (clnt == NULL) { + if ((nconf = __rpc_getconf(handle)) == NULL) { + if (rpc_createerr.cf_stat == RPC_SUCCESS) + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + break; + } +#ifdef CLNT_DEBUG + printf("trying netid %s\n", nconf->nc_netid); +#endif + clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); + if (clnt) + break; + else { + /* + * Since we didn't get a name-to-address + * translation failure here, we remember + * this particular error. The object of + * this is to enable us to return to the + * caller a more-specific error than the + * unhelpful ``Name to address translation + * failed'' which might well occur if we + * merely returned the last error (because + * the local loopbacks are typically the + * last ones in /etc/netconfig and the most + * likely to be unable to translate a host + * name). We also check for a more + * meaningful error than ``unknown host + * name'' for the same reasons. + */ + if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && + rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { + save_cf_stat = rpc_createerr.cf_stat; + save_cf_error = rpc_createerr.cf_error; + } + } + } + + /* + * Attempt to return an error more specific than ``Name to address + * translation failed'' or ``unknown host name'' + */ + if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || + rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && + (save_cf_stat != RPC_SUCCESS)) { + rpc_createerr.cf_stat = save_cf_stat; + rpc_createerr.cf_error = save_cf_error; + } + __rpc_endconf(handle); + return (clnt); +} + +/* + * Generic client creation: takes (servers name, program-number, netconf) and + * returns client handle. Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s : clnt_control() + * It finds out the server address from rpcbind and calls clnt_tli_create(). + * + * It calls clnt_tp_create_timed() with the default timeout. + */ +CLIENT * +clnt_tp_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, + const struct netconfig *nconf) +{ + return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); +} + +/* + * This has the same definition as clnt_tp_create(), except it + * takes an additional parameter - a pointer to a timeval structure. + * A NULL value for the timeout pointer indicates that the default + * value for the timeout should be used. + */ +CLIENT * +clnt_tp_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, + const struct netconfig *nconf, const struct timeval *tp) +{ + struct netbuf *svcaddr; /* servers address */ + CLIENT *cl = NULL; /* client handle */ + + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + /* + * Get the address of the server + */ + if ((svcaddr = __rpcb_findaddr_timed(prog, vers, + (struct netconfig *)nconf, (char *)hostname, + &cl, (struct timeval *)tp)) == NULL) { + /* appropriate error number is set by rpcbind libraries */ + return (NULL); + } + if (cl == NULL) { + cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, + prog, vers, 0, 0, NULL, NULL, NULL); + } else { + /* Reuse the CLIENT handle and change the appropriate fields */ + if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) { + if (cl->cl_netid == NULL) + cl->cl_netid = strdup(nconf->nc_netid); + if (cl->cl_tp == NULL) + cl->cl_tp = strdup(nconf->nc_device); + (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog); + (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers); + } else { + CLNT_DESTROY(cl); + cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, + prog, vers, 0, 0, NULL, NULL, NULL); + } + } + free(svcaddr->buf); + free(svcaddr); + return (cl); +} + +/* + * Generic client creation: returns client handle. + * Default options are set, which the user can + * change using the rpc equivalent of _ioctl()'s : clnt_control(). + * If fd is RPC_ANYFD, it will be opened using nconf. + * It will be bound if not so. + * If sizes are 0; appropriate defaults will be chosen. + */ +CLIENT * +clnt_tli_create(const SOCKET fd_in, const struct netconfig *nconf, + struct netbuf *svcaddr, const rpcprog_t prog, const rpcvers_t vers, + const uint sendsz, const uint recvsz, + int (*callback_xdr)(void *, void *), + int (*callback_function)(void *, void *, void **), + void *callback_args) +{ + CLIENT *cl; /* client handle */ + bool_t madefd = FALSE; /* whether fd opened here */ + long servtype; + BOOL one = TRUE; + struct __rpc_sockinfo si; + extern int __rpc_minfd; + SOCKET fd = fd_in; + + if (fd == RPC_ANYFD) { + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + fd = __rpc_nconf2fd(nconf); + + if (fd == INVALID_SOCKET) + goto err; +#if 0 + if (fd < __rpc_minfd) + fd = __rpc_raise_fd(fd); +#endif + madefd = TRUE; + servtype = nconf->nc_semantics; + bindresvport(fd, NULL); + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; + } else { + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; + servtype = __rpc_socktype2seman(si.si_socktype); + if (servtype == -1) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + } + + if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */ + goto err1; + } + + switch (servtype) { + case NC_TPI_COTS: + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz, + callback_xdr, callback_function, callback_args); + break; + case NC_TPI_COTS_ORD: + if (nconf && + ((strcmp(nconf->nc_protofmly, "inet") == 0) || + (strcmp(nconf->nc_protofmly, "inet6") == 0))) { + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, + sizeof (one)); + } + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz, + callback_xdr, callback_function, callback_args); + break; + case NC_TPI_CLTS: + cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); + break; + default: + goto err; + } + + if (cl == NULL) + goto err1; /* borrow errors from clnt_dg/vc creates */ + if (nconf) { + cl->cl_netid = strdup(nconf->nc_netid); + cl->cl_tp = strdup(nconf->nc_device); + } else { + cl->cl_netid = ""; + cl->cl_tp = ""; + } + if (madefd) { + (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); +/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ + }; + + return (cl); + +err: + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; +err1: if (madefd) + (void)closesocket(fd); + return (NULL); +} + +#if 0 /* WINDOWS */ +/* + * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), + * we try to not use them. The __rpc_raise_fd() routine will dup + * a descriptor to a higher value. If we fail to do it, we continue + * to use the old one (and hope for the best). + */ +int __rpc_minfd = 3; + +int +__rpc_raise_fd(int fd) +{ + int nfd; + + if (fd >= __rpc_minfd) + return (fd); + + if ((nfd = fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) + return (fd); + + if (fsync(nfd) == -1) { + closesocket(nfd); + return (fd); + } + + if (closesocket(fd) == -1) { + /* this is okay, we will syslog an error, then use the new fd */ + (void) syslog(LOG_ERR, + "could not close() fd %d; mem & fd leak", fd); + } + + return (nfd); +} +#endif \ No newline at end of file diff --git a/libtirpc/src/clnt_perror.c b/libtirpc/src/clnt_perror.c new file mode 100644 index 0000000..e98d7a4 --- /dev/null +++ b/libtirpc/src/clnt_perror.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* +#include +*/ +/* + * clnt_perror.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +static char *buf; + +static char *_buf(void); +static char *auth_errmsg(enum auth_stat); +#define CLNT_PERROR_BUFLEN 256 + +static char * +_buf() +{ + + if (buf == 0) + buf = (char *)malloc(CLNT_PERROR_BUFLEN); + return (buf); +} + +/* + * Print reply error info + */ +char * +clnt_sperror(rpch, s) + CLIENT *rpch; + const char *s; +{ + struct rpc_err e; + char *err; + char *str; + char *strstart; + size_t len, i; + + if (rpch == NULL || s == NULL) + return(0); + + str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ + if (str == 0) + return (0); + len = CLNT_PERROR_BUFLEN; + strstart = str; + CLNT_GETERR(rpch, &e); + + if (snprintf(str, len, "%s: ", s) > 0) { + i = strlen(str); + str += i; + len -= i; + } + + (void)strncpy(str, clnt_sperrno(e.re_status), len - 1); + i = strlen(str); + str += i; + len -= i; + + switch (e.re_status) { + case RPC_SUCCESS: + case RPC_CANTENCODEARGS: + case RPC_CANTDECODERES: + case RPC_TIMEDOUT: + case RPC_PROGUNAVAIL: + case RPC_PROCUNAVAIL: + case RPC_CANTDECODEARGS: + case RPC_SYSTEMERROR: + case RPC_UNKNOWNHOST: + case RPC_UNKNOWNPROTO: + case RPC_PMAPFAILURE: + case RPC_PROGNOTREGISTERED: + case RPC_FAILED: + break; + + case RPC_CANTSEND: + case RPC_CANTRECV: + snprintf(str, len, "; errno = %s", strerror(e.re_errno)); + i = strlen(str); + if (i > 0) { + str += i; + len -= i; + } + break; + + case RPC_VERSMISMATCH: + snprintf(str, len, "; low version = %u, high version = %u", + e.re_vers.low, e.re_vers.high); + i = strlen(str); + if (i > 0) { + str += i; + len -= i; + } + break; + + case RPC_AUTHERROR: + err = auth_errmsg(e.re_why); + snprintf(str, len, "; why = "); + i = strlen(str); + if (i > 0) { + str += i; + len -= i; + } + if (err != NULL) { + snprintf(str, len, "%s",err); + } else { + snprintf(str, len, + "(unknown authentication error - %d)", + (int) e.re_why); + } + i = strlen(str); + if (i > 0) { + str += i; + len -= i; + } + break; + + case RPC_PROGVERSMISMATCH: + snprintf(str, len, "; low version = %u, high version = %u", + e.re_vers.low, e.re_vers.high); + i = strlen(str); + if (i > 0) { + str += i; + len -= i; + } + break; + + default: /* unknown */ + snprintf(str, len, "; s1 = %u, s2 = %u", + e.re_lb.s1, e.re_lb.s2); + i = strlen(str); + if (i > 0) { + str += i; + len -= i; + } + break; + } + strstart[CLNT_PERROR_BUFLEN-1] = '\0'; + return(strstart) ; +} + +void +clnt_perror(rpch, s) + CLIENT *rpch; + const char *s; +{ + + if (rpch == NULL || s == NULL) + return; + + (void) fprintf(stderr, "%s\n", clnt_sperror(rpch,s)); +} + +static const char *const rpc_errlist[] = { + "RPC: Success", /* 0 - RPC_SUCCESS */ + "RPC: Can't encode arguments", /* 1 - RPC_CANTENCODEARGS */ + "RPC: Can't decode result", /* 2 - RPC_CANTDECODERES */ + "RPC: Unable to send", /* 3 - RPC_CANTSEND */ + "RPC: Unable to receive", /* 4 - RPC_CANTRECV */ + "RPC: Timed out", /* 5 - RPC_TIMEDOUT */ + "RPC: Incompatible versions of RPC", /* 6 - RPC_VERSMISMATCH */ + "RPC: Authentication error", /* 7 - RPC_AUTHERROR */ + "RPC: Program unavailable", /* 8 - RPC_PROGUNAVAIL */ + "RPC: Program/version mismatch", /* 9 - RPC_PROGVERSMISMATCH */ + "RPC: Procedure unavailable", /* 10 - RPC_PROCUNAVAIL */ + "RPC: Server can't decode arguments", /* 11 - RPC_CANTDECODEARGS */ + "RPC: Remote system error", /* 12 - RPC_SYSTEMERROR */ + "RPC: Unknown host", /* 13 - RPC_UNKNOWNHOST */ + "RPC: Port mapper failure", /* 14 - RPC_PMAPFAILURE */ + "RPC: Program not registered", /* 15 - RPC_PROGNOTREGISTERED */ + "RPC: Failed (unspecified error)", /* 16 - RPC_FAILED */ + "RPC: Unknown protocol" /* 17 - RPC_UNKNOWNPROTO */ +}; + + +/* + * This interface for use by clntrpc + */ +char * +clnt_sperrno(stat) + enum clnt_stat stat; +{ + unsigned int errnum = stat; + + if (errnum < (sizeof(rpc_errlist)/sizeof(rpc_errlist[0]))) + /* LINTED interface problem */ + return (char *)rpc_errlist[errnum]; + + return ("RPC: (unknown error code)"); +} + +void +clnt_perrno(num) + enum clnt_stat num; +{ + (void) fprintf(stderr, "%s\n", clnt_sperrno(num)); +} + + +char * +clnt_spcreateerror(s) + const char *s; +{ + char *str, *err; + size_t len, i; + + if (s == NULL) + return(0); + + str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */ + if (str == 0) + return(0); + len = CLNT_PERROR_BUFLEN; + snprintf(str, len, "%s: ", s); + i = strlen(str); + if (i > 0) + len -= i; + (void)strncat(str, clnt_sperrno(rpc_createerr.cf_stat), len - 1); + switch (rpc_createerr.cf_stat) { + case RPC_PMAPFAILURE: + (void) strncat(str, " - ", len - 1); + err = clnt_sperrno(rpc_createerr.cf_error.re_status); + if (err) + (void) strncat(str, err+5, len-5); + switch(rpc_createerr.cf_error.re_status) { + case RPC_CANTSEND: + case RPC_CANTRECV: + i = strlen(str); + len -= i; + snprintf(str+i, len, ": errno %d (%s)", + rpc_createerr.cf_error.re_errno, + strerror(rpc_createerr.cf_error.re_errno)); + break; + default: + break; + } + break; + + case RPC_SYSTEMERROR: + (void)strncat(str, " - ", len - 1); + (void)strncat(str, strerror(rpc_createerr.cf_error.re_errno), + len - 4); + break; + + case RPC_CANTSEND: + case RPC_CANTDECODERES: + case RPC_CANTENCODEARGS: + case RPC_SUCCESS: + case RPC_UNKNOWNPROTO: + case RPC_PROGNOTREGISTERED: + case RPC_FAILED: + case RPC_UNKNOWNHOST: + case RPC_CANTDECODEARGS: + case RPC_PROCUNAVAIL: + case RPC_PROGVERSMISMATCH: + case RPC_PROGUNAVAIL: + case RPC_AUTHERROR: + case RPC_VERSMISMATCH: + case RPC_TIMEDOUT: + case RPC_CANTRECV: + default: + break; + } + str[CLNT_PERROR_BUFLEN-1] = '\0'; + return (str); +} + +void +clnt_pcreateerror(s) + const char *s; +{ + + if (s == NULL) + return; + + (void) fprintf(stderr, "%s\n", clnt_spcreateerror(s)); +} + +static const char *const auth_errlist[] = { + "Authentication OK", /* 0 - AUTH_OK */ + "Invalid client credential", /* 1 - AUTH_BADCRED */ + "Server rejected credential", /* 2 - AUTH_REJECTEDCRED */ + "Invalid client verifier", /* 3 - AUTH_BADVERF */ + "Server rejected verifier", /* 4 - AUTH_REJECTEDVERF */ + "Client credential too weak", /* 5 - AUTH_TOOWEAK */ + "Invalid server verifier", /* 6 - AUTH_INVALIDRESP */ + "Failed (unspecified error)" /* 7 - AUTH_FAILED */ +}; + +static char * +auth_errmsg(stat) + enum auth_stat stat; +{ + unsigned int errnum = stat; + + if (errnum < (sizeof(auth_errlist)/sizeof(auth_errlist[0]))) + /* LINTED interface problem */ + return (char *)auth_errlist[errnum]; + + return(NULL); +} diff --git a/libtirpc/src/clnt_raw.c b/libtirpc/src/clnt_raw.c new file mode 100644 index 0000000..6c433bc --- /dev/null +++ b/libtirpc/src/clnt_raw.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * clnt_raw.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Memory based rpc for simple testing and timing. + * Interface to create an rpc client and server in the same process. + * This lets us similate rpc and get round trip overhead, without + * any interference from the kernel. + */ +#include +//#include +#include +#include +//#include +#include +#include + +#include +#include + +extern mutex_t clntraw_lock; + +#define MCALL_MSG_SIZE 24 + +/* + * This is the "network" we will be moving stuff over. + */ +static struct clntraw_private { + CLIENT client_object; + XDR xdr_stream; + char *_raw_buf; + union { + struct rpc_msg mashl_rpcmsg; + char mashl_callmsg[MCALL_MSG_SIZE]; + } u; + u_int mcnt; +} *clntraw_private; + +static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *, + xdrproc_t, void *, struct timeval); +static void clnt_raw_geterr(CLIENT *, struct rpc_err *); +static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *); +static void clnt_raw_abort(CLIENT *); +static bool_t clnt_raw_control(CLIENT *, u_int, void *); +static void clnt_raw_destroy(CLIENT *); +static struct clnt_ops *clnt_raw_ops(void); + +/* + * Create a client handle for memory based rpc. + */ +CLIENT * +clnt_raw_create(prog, vers) + rpcprog_t prog; + rpcvers_t vers; +{ + struct clntraw_private *clp; + struct rpc_msg call_msg; + XDR *xdrs; + CLIENT *client; + + mutex_lock(&clntraw_lock); + clp = clntraw_private; + if (clp == NULL) { + clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); + if (clp == NULL) { + mutex_unlock(&clntraw_lock); + return NULL; + } + if (__rpc_rawcombuf == NULL) + __rpc_rawcombuf = + (char *)calloc(UDPMSGSIZE, sizeof (char)); + clp->_raw_buf = __rpc_rawcombuf; + clntraw_private = clp; + } + xdrs = &clp->xdr_stream; + client = &clp->client_object; + /* + * pre-serialize the static part of the call msg and stash it away + */ + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + /* XXX: prog and vers have been long historically :-( */ + call_msg.rm_call.cb_prog = (u_int32_t)prog; + call_msg.rm_call.cb_vers = (u_int32_t)vers; + xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); + if (! xdr_callhdr(xdrs, &call_msg)) + //warnx("clntraw_create - Fatal header serialization error."); + clp->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + + /* + * Set xdrmem for client/server shared buffer + */ + xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); + + /* + * create client handle + */ + client->cl_ops = clnt_raw_ops(); + client->cl_auth = authnone_create(); + mutex_unlock(&clntraw_lock); + return (client); +} + +/* ARGSUSED */ +static enum clnt_stat +clnt_raw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) + CLIENT *h; + rpcproc_t proc; + xdrproc_t xargs; + void *argsp; + xdrproc_t xresults; + void *resultsp; + struct timeval timeout; +{ + struct clntraw_private *clp = clntraw_private; + XDR *xdrs = &clp->xdr_stream; + struct rpc_msg msg; + enum clnt_stat status; + struct rpc_err error; + + assert(h != NULL); + + mutex_lock(&clntraw_lock); + if (clp == NULL) { + mutex_unlock(&clntraw_lock); + return (RPC_FAILED); + } + mutex_unlock(&clntraw_lock); + +call_again: + /* + * send request + */ + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + clp->u.mashl_rpcmsg.rm_xid ++ ; + if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || + (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + return (RPC_CANTENCODEARGS); + } + (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ + + /* + * We have to call server input routine here because this is + * all going on in one process. Yuk. + */ + svc_getreq_common(FD_SETSIZE); + + /* + * get results + */ + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = resultsp; + msg.acpted_rply.ar_results.proc = xresults; + if (! xdr_replymsg(xdrs, &msg)) { + /* + * It's possible for xdr_replymsg() to fail partway + * through its attempt to decode the result from the + * server. If this happens, it will leave the reply + * structure partially populated with dynamically + * allocated memory. (This can happen if someone uses + * clntudp_bufcreate() to create a CLIENT handle and + * specifies a receive buffer size that is too small.) + * This memory must be free()ed to avoid a leak. + */ + int op = xdrs->x_op; + xdrs->x_op = XDR_FREE; + xdr_replymsg(xdrs, &msg); + xdrs->x_op = op; + return (RPC_CANTDECODERES); + } + _seterr_reply(&msg, &error); + status = error.re_status; + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + } /* end successful completion */ + else { + if (AUTH_REFRESH(h->cl_auth, &msg)) + goto call_again; + } /* end of unsuccessful completion */ + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + if (msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); + } + } + + return (status); +} + +/*ARGSUSED*/ +static void +clnt_raw_geterr(cl, err) + CLIENT *cl; + struct rpc_err *err; +{ +} + + +/* ARGSUSED */ +static bool_t +clnt_raw_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + void *res_ptr; +{ + struct clntraw_private *clp = clntraw_private; + XDR *xdrs = &clp->xdr_stream; + bool_t rval; + + mutex_lock(&clntraw_lock); + if (clp == NULL) { + rval = (bool_t) RPC_FAILED; + mutex_unlock(&clntraw_lock); + return (rval); + } + mutex_unlock(&clntraw_lock); + xdrs->x_op = XDR_FREE; + return ((*xdr_res)(xdrs, res_ptr)); +} + +/*ARGSUSED*/ +static void +clnt_raw_abort(cl) + CLIENT *cl; +{ +} + +/*ARGSUSED*/ +static bool_t +clnt_raw_control(cl, ui, str) + CLIENT *cl; + u_int ui; + void *str; +{ + return (FALSE); +} + +/*ARGSUSED*/ +static void +clnt_raw_destroy(cl) + CLIENT *cl; +{ +} + +static struct clnt_ops * +clnt_raw_ops() +{ + static struct clnt_ops ops; + extern mutex_t ops_lock; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.cl_call == NULL) { + ops.cl_call = clnt_raw_call; + ops.cl_abort = clnt_raw_abort; + ops.cl_geterr = clnt_raw_geterr; + ops.cl_freeres = clnt_raw_freeres; + ops.cl_destroy = clnt_raw_destroy; + ops.cl_control = clnt_raw_control; + } + mutex_unlock(&ops_lock); + return (&ops); +} diff --git a/libtirpc/src/clnt_simple.c b/libtirpc/src/clnt_simple.c new file mode 100644 index 0000000..c2b8ff8 --- /dev/null +++ b/libtirpc/src/clnt_simple.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +//#include + +/* + * clnt_simple.c + * Simplified front end to client rpc. + */ +#include +//#include +#include +//#include +#include +#include +#include +#include +#include +#include +//#include + +#include + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#ifndef NETIDLEN +#define NETIDLEN 32 +#endif + +struct rpc_call_private { + int valid; /* Is this entry valid ? */ + CLIENT *client; /* Client handle */ + pid_t pid; /* process-id at moment of creation */ + rpcprog_t prognum; /* Program */ + rpcvers_t versnum; /* Version */ + char host[MAXHOSTNAMELEN]; /* Servers host */ + char nettype[NETIDLEN]; /* Network type */ +}; + +static void rpc_call_destroy(void *); + +static void +rpc_call_destroy(void *vp) +{ + struct rpc_call_private *rcp = (struct rpc_call_private *)vp; + + if (rcp) { + if (rcp->client) + CLNT_DESTROY(rcp->client); + free(rcp); + } +} + +/* + * This is the simplified interface to the client rpc layer. + * The client handle is not destroyed here and is reused for + * the future calls to same prog, vers, host and nettype combination. + * + * The total time available is 25 seconds. + */ +enum clnt_stat +rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype) + const char *host; /* host name */ + rpcprog_t prognum; /* program number */ + rpcvers_t versnum; /* version number */ + rpcproc_t procnum; /* procedure number */ + xdrproc_t inproc, outproc; /* in/out XDR procedures */ + const char *in; + char *out; /* recv/send data */ + const char *nettype; /* nettype */ +{ + struct rpc_call_private *rcp = (struct rpc_call_private *) 0; + enum clnt_stat clnt_stat; + struct timeval timeout, tottimeout; + extern thread_key_t rpc_call_key; + extern mutex_t tsd_lock; + + if (rpc_call_key == -1) { + mutex_lock(&tsd_lock); + if (rpc_call_key == -1) + thr_keycreate(&rpc_call_key, rpc_call_destroy); + mutex_unlock(&tsd_lock); + } + rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key); + if (rcp == NULL) { + rcp = malloc(sizeof (*rcp)); + if (rcp == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return (rpc_createerr.cf_stat); + } + thr_setspecific(rpc_call_key, (void *) rcp); + rcp->valid = 0; + rcp->client = NULL; + } + if ((nettype == NULL) || (nettype[0] == 0)) + nettype = "netpath"; + if (!(rcp->valid && rcp->pid == getpid() && + (rcp->prognum == prognum) && + (rcp->versnum == versnum) && + (!strcmp(rcp->host, host)) && + (!strcmp(rcp->nettype, nettype)))) { + int fd; + + rcp->valid = 0; + if (rcp->client) + CLNT_DESTROY(rcp->client); + /* + * Using the first successful transport for that type + */ + rcp->client = clnt_create(host, prognum, versnum, nettype); + rcp->pid = getpid(); + if (rcp->client == NULL) { + return (rpc_createerr.cf_stat); + } + /* + * Set time outs for connectionless case. Do it + * unconditionally. Faster than doing a t_getinfo() + * and then doing the right thing. + */ + timeout.tv_usec = 0; + timeout.tv_sec = 5; + (void) CLNT_CONTROL(rcp->client, + CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout); + if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd)) + ; // XXX fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ + rcp->prognum = prognum; + rcp->versnum = versnum; + if ((strlen(host) < (size_t)MAXHOSTNAMELEN) && + (strlen(nettype) < (size_t)NETIDLEN)) { + (void) strcpy(rcp->host, host); + (void) strcpy(rcp->nettype, nettype); + rcp->valid = 1; + } else { + rcp->valid = 0; + } + } /* else reuse old client */ + tottimeout.tv_sec = 25; + tottimeout.tv_usec = 0; + + /* LINTED const castaway */ + clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in, + outproc, out, tottimeout); + /* + * if call failed, empty cache + */ + if (clnt_stat != RPC_SUCCESS) + rcp->valid = 0; + return (clnt_stat); +} diff --git a/libtirpc/src/clnt_vc.c b/libtirpc/src/clnt_vc.c new file mode 100644 index 0000000..44d6727 --- /dev/null +++ b/libtirpc/src/clnt_vc.c @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * clnt_tcp.c, Implements a TCP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * TCP based RPC supports 'batched calls'. + * A sequence of calls may be batched-up in a send buffer. The rpc call + * return immediately to the client even though the call was not necessarily + * sent. The batching occurs if the results' xdr routine is NULL (0) AND + * the rpc timeout value is zero (see clnt.h, rpc). + * + * Clients should NOT casually batch calls that in fact return results; that is, + * the server side should be aware that a call is batched and not produce any + * return message. Batched calls that produce many result messages can + * deadlock (netlock) the client and the server.... + * + * Now go hang yourself. + */ +#include +//#include + +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +//#include +#include +//#include +#include +#include +#include +//#include +//#include + +#include +#include "rpc_com.h" + +#define MCALL_MSG_SIZE 24 + +#define CMGROUP_MAX 16 +#define SCM_CREDS 0x03 /* process creds (struct cmsgcred) */ + +/* + * Credentials structure, used to verify the identity of a peer + * process that has sent us a message. This is allocated by the + * peer process but filled in by the kernel. This prevents the + * peer from lying about its identity. (Note that cmcred_groups[0] + * is the effective GID.) + */ +struct cmsgcred { + pid_t cmcred_pid; /* PID of sending process */ + uid_t cmcred_uid; /* real UID of sending process */ + uid_t cmcred_euid; /* effective UID of sending process */ + gid_t cmcred_gid; /* real GID of sending process */ + short cmcred_ngroups; /* number or groups */ + gid_t cmcred_groups[CMGROUP_MAX]; /* groups */ +}; + +struct cmessage { + struct cmsghdr cmsg; + struct cmsgcred cmcred; +}; + +static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *, + xdrproc_t, void *, struct timeval); +static void clnt_vc_geterr(CLIENT *, struct rpc_err *); +static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); +static void clnt_vc_abort(CLIENT *); +static bool_t clnt_vc_control(CLIENT *, u_int, void *); +static void clnt_vc_destroy(CLIENT *); +static struct clnt_ops *clnt_vc_ops(void); +static bool_t time_not_ok(struct timeval *); +static int read_vc(void *, void *, int); +static int write_vc(void *, void *, int); + +struct ct_data { + int ct_fd; /* connection's fd */ + bool_t ct_closeit; /* close it on destroy */ + struct timeval ct_wait; /* wait interval in milliseconds */ + bool_t ct_waitset; /* wait set by clnt_control? */ + struct netbuf ct_addr; /* remote addr */ + struct rpc_err ct_error; + union { + char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ + u_int32_t ct_mcalli; + } ct_u; + u_int ct_mpos; /* pos after marshal */ + XDR ct_xdrs; /* XDR stream */ + struct rpc_msg reply_msg; + bool_t use_stored_reply_msg; +}; + +/* + * This machinery implements per-fd locks for MT-safety. It is not + * sufficient to do per-CLIENT handle locks for MT-safety because a + * user may create more than one CLIENT handle with the same fd behind + * it. Therfore, we allocate an array of flags (vc_fd_locks), protected + * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables + * similarly protected. Vc_fd_lock[fd] == 1 => a call is active on some + * CLIENT handle created for that fd. + * The current implementation holds locks across the entire RPC and reply. + * Yes, this is silly, and as soon as this code is proven to work, this + * should be the first thing fixed. One step at a time. + */ +static int *vc_fd_locks; +extern mutex_t clnt_fd_lock; +static cond_t *vc_cv; +#ifndef _WIN32 +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + vc_fd_locks[fd] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \ + cond_signal(&vc_cv[fd]); \ +} +#else +/* XXX Need Windows signal/event stuff XXX */ +#define release_fd_lock(fd, mask) { \ + mutex_lock(&clnt_fd_lock); \ + vc_fd_locks[WINSOCK_HANDLE_HASH(fd)] = 0; \ + mutex_unlock(&clnt_fd_lock); \ + \ + cond_broadcast(&vc_cv[WINSOCK_HANDLE_HASH(fd)]); \ +} +#endif + +#define acquire_fd_lock(fd) { \ + mutex_lock(&clnt_fd_lock); \ + while (vc_fd_locks[WINSOCK_HANDLE_HASH(fd)]) \ + cond_wait(&vc_cv[WINSOCK_HANDLE_HASH(fd)], &clnt_fd_lock); \ + vc_fd_locks[WINSOCK_HANDLE_HASH(fd)] = 1; \ + mutex_unlock(&clnt_fd_lock); \ +} + +static const char clnt_vc_errstr[] = "%s : %s"; +static const char clnt_vc_str[] = "clnt_vc_create"; +static const char clnt_read_vc_str[] = "read_vc"; +static const char __no_mem_str[] = "out of memory"; + +/* callback thread */ +#define CALLBACK_TIMEOUT 5000 +#define RQCRED_SIZE 400 /* this size is excessive */ +static unsigned int WINAPI clnt_cb_thread(void *args) +{ + int status = NO_ERROR; + CLIENT *cl = (CLIENT *)args; + struct ct_data *ct = (struct ct_data *) cl->cl_private; + XDR *xdrs = &(ct->ct_xdrs); + long saved_timeout_sec = ct->ct_wait.tv_sec; + long saved_timeout_usec = ct->ct_wait.tv_usec; + struct rpc_msg reply_msg; + void *res = NULL; + char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE]; + + fprintf(stderr/*stdout*/, "%04x: Creating callback thread\n", GetCurrentThreadId()); + while(1) { + cb_req header; + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)] || + !ct->use_stored_reply_msg || + (ct->use_stored_reply_msg && ct->reply_msg.rm_direction != CALL)) { + if (cl->shutdown) + break; + if (!cond_wait_timed(&vc_cv[WINSOCK_HANDLE_HASH(ct->ct_fd)], &clnt_fd_lock, + CALLBACK_TIMEOUT)) + if (!vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)]) + break; + } + vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)] = 1; + mutex_unlock(&clnt_fd_lock); + + if (cl->shutdown) { + fprintf(stdout, "%04x: callback received shutdown signal\n", GetCurrentThreadId()); + release_fd_lock(ct->ct_fd, mask); + goto out; + } + + saved_timeout_sec = ct->ct_wait.tv_sec; + saved_timeout_usec = ct->ct_wait.tv_usec; + if (ct->use_stored_reply_msg && ct->reply_msg.rm_direction == CALL) { + goto process_rpc_call; + } else if (!ct->use_stored_reply_msg) { + xdrs->x_op = XDR_DECODE; + ct->ct_wait.tv_sec = ct->ct_wait.tv_usec = 0; + xdrrec_skiprecord(xdrs); + if (!xdr_getxiddir(xdrs, &ct->reply_msg)) { + goto skip_process; + } + if (ct->reply_msg.rm_direction == CALL) { + goto process_rpc_call; + } else { + if (ct->reply_msg.rm_direction == REPLY) + ct->use_stored_reply_msg = TRUE; + goto skip_setlastfrag; + } + } else { + goto skip_setlastfrag; + } +process_rpc_call: + //call to get call headers + ct->reply_msg.rm_call.cb_cred.oa_base = cred_area; + ct->reply_msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); + if (!xdr_getcallbody(xdrs, &ct->reply_msg)) { + fprintf(stderr, "%04x: xdr_getcallbody failed\n", GetCurrentThreadId()); + goto skip_process; + } else + fprintf(stdout, "%04x: callbody: rpcvers %d cb_prog %d cb_vers %d cb_proc %d\n", + GetCurrentThreadId(), + ct->reply_msg.rm_call.cb_rpcvers, ct->reply_msg.rm_call.cb_prog, + ct->reply_msg.rm_call.cb_vers, ct->reply_msg.rm_call.cb_proc); + header.rq_prog = ct->reply_msg.rm_call.cb_prog; + header.rq_vers = ct->reply_msg.rm_call.cb_vers; + header.rq_proc = ct->reply_msg.rm_call.cb_proc; + header.xdr = xdrs; + status = (*cl->cb_fn)(cl->cb_args, &header, &res); + if (status) { + fprintf(stderr, "%04x: callback function failed with %d\n", status); + } + ct->use_stored_reply_msg = FALSE; + xdrs->x_op = XDR_ENCODE; + reply_msg.rm_xid = ct->reply_msg.rm_xid; + ct->reply_msg.rm_xid = 0; + reply_msg.rm_direction = REPLY; + reply_msg.rm_reply.rp_stat = MSG_ACCEPTED; + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_stat = status; + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; + xdr_replymsg(xdrs, &reply_msg); + if (!status) + (*cl->cb_xdr)(xdrs, res); + if (! xdrrec_endofrecord(xdrs, 1)) { + fprintf(stderr, "%04x: failed to send REPLY\n", GetCurrentThreadId()); + } +skip_process: + ct->reply_msg.rm_direction = -1; + xdrrec_setlastfrag(xdrs); +skip_setlastfrag: + ct->ct_wait.tv_sec = saved_timeout_sec; + ct->ct_wait.tv_usec = saved_timeout_usec; + release_fd_lock(ct->ct_fd, mask); + } +out: + return status; +} +/* + * Create a client handle for a connection. + * Default options are set, which the user can change using clnt_control()'s. + * The rpc/vc package does buffering similar to stdio, so the client + * must pick send and receive buffer sizes, 0 => use the default. + * NB: fd is copied into a private area. + * NB: The rpch->cl_auth is set null authentication. Caller may wish to + * set this something more useful. + * + * fd should be an open socket + */ +CLIENT * +clnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz, cb_xdr, cb_fn, cb_args) + int fd; /* open file descriptor */ + const struct netbuf *raddr; /* servers address */ + const rpcprog_t prog; /* program number */ + const rpcvers_t vers; /* version number */ + u_int sendsz; /* buffer recv size */ + u_int recvsz; /* buffer send size */ + int (*cb_xdr)(void *, void *); /* if not NULL, point to function to xdr CB args */ + int (*cb_fn)(void *, void *, void **); /* if not NULL, pointer to function to handle RPC_CALLs */ + void *cb_args; /* if not NULL, pointer to pass into cb_fn */ +{ + CLIENT *cl; /* client handle */ + struct ct_data *ct = NULL; /* client handle */ + struct timeval now; + struct rpc_msg call_msg; + static u_int32_t disrupt; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + struct sockaddr_storage ss; + socklen_t slen; + struct __rpc_sockinfo si; + struct cb_fn_args *cfa; + + if (disrupt == 0) + disrupt = PtrToUlong(raddr); + + cl = (CLIENT *)mem_alloc(sizeof (*cl)); + ct = (struct ct_data *)mem_alloc(sizeof (*ct)); + if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) { +// (void) syslog(LOG_ERR, clnt_vc_errstr, +// clnt_vc_str, __no_mem_str); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto err; + } + ct->ct_addr.buf = NULL; +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + mutex_lock(&clnt_fd_lock); + if (vc_fd_locks == (int *) NULL) { + int cv_allocsz, fd_allocsz; + int dtbsize = __rpc_dtbsize(); + + fd_allocsz = dtbsize * sizeof (int); + vc_fd_locks = (int *) mem_alloc(fd_allocsz); + if (vc_fd_locks == (int *) NULL) { + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } else + memset(vc_fd_locks, 0, fd_allocsz); + + assert(vc_cv == (cond_t *) NULL); + cv_allocsz = dtbsize * sizeof (cond_t); + vc_cv = (cond_t *) mem_alloc(cv_allocsz); + if (vc_cv == (cond_t *) NULL) { + mem_free(vc_fd_locks, fd_allocsz); + vc_fd_locks = (int *) NULL; + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } else { + int i; + + for (i = 0; i < dtbsize; i++) + cond_init(&vc_cv[i], 0, (void *) 0); + } + } else + assert(vc_cv != (cond_t *) NULL); + + /* + * XXX - fvdl connecting while holding a mutex? + */ + slen = sizeof ss; + if (getpeername(fd, (struct sockaddr *)&ss, &slen) == SOCKET_ERROR) { + errno = WSAGetLastError(); + if (errno != WSAENOTCONN) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } + if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) == SOCKET_ERROR){ + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = WSAGetLastError(); + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + goto err; + } + } + mutex_unlock(&clnt_fd_lock); + if (!__rpc_fd2sockinfo(fd, &si)) + goto err; +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + + ct->ct_closeit = FALSE; + + /* + * Set up private data struct + */ + ct->ct_fd = fd; + ct->ct_wait.tv_usec = 0; + ct->ct_waitset = FALSE; + ct->ct_addr.buf = malloc(raddr->maxlen); + if (ct->ct_addr.buf == NULL) + goto err; + memcpy(ct->ct_addr.buf, raddr->buf, raddr->len); + ct->ct_addr.len = raddr->len; + ct->ct_addr.maxlen = raddr->maxlen; + ct->use_stored_reply_msg = FALSE; + + /* + * Initialize call message + */ + (void)gettimeofday(&now, NULL); + call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now); + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = (u_int32_t)prog; + call_msg.rm_call.cb_vers = (u_int32_t)vers; + + /* + * pre-serialize the static part of the call msg and stash it away + */ + xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE, + XDR_ENCODE); + if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { + if (ct->ct_closeit) { + (void)closesocket(fd); + } + goto err; + } + ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); + XDR_DESTROY(&(ct->ct_xdrs)); + + /* + * Create a client handle which uses xdrrec for serialization + * and authnone for authentication. + */ + cl->cl_ops = clnt_vc_ops(); + cl->cl_private = ct; + cl->cl_auth = authnone_create(); + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); + xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, + cl->cl_private, read_vc, write_vc); + + if (cb_xdr && cb_fn && cb_args) { + cl->cb_xdr = cb_xdr; + cl->cb_fn = cb_fn; + cl->cb_args = cb_args; + cl->cb_thread = (HANDLE)_beginthreadex(NULL, + 0, clnt_cb_thread, cl, 0, NULL); + if (cl->cb_thread == INVALID_HANDLE_VALUE) { + fprintf(stderr, "_beginthreadex failed %d\n", GetLastError()); + goto err; + } else + fprintf(stdout, "%04x: started the callback thread %04x\n", + GetCurrentThreadId(), cl->cb_thread); + } else + cl->cb_thread = INVALID_HANDLE_VALUE; + return (cl); + +err: + if (cl) { + if (ct) { + if (ct->ct_addr.len) + mem_free(ct->ct_addr.buf, ct->ct_addr.len); + mem_free(ct, sizeof (struct ct_data)); + } + if (cl) + mem_free(cl, sizeof (CLIENT)); + } + return ((CLIENT *)NULL); +} + +static enum clnt_stat +clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) + CLIENT *cl; + rpcproc_t proc; + xdrproc_t xdr_args; + void *args_ptr; + xdrproc_t xdr_results; + void *results_ptr; + struct timeval timeout; +{ + struct ct_data *ct = (struct ct_data *) cl->cl_private; + XDR *xdrs = &(ct->ct_xdrs); + u_int32_t x_id; + u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ + bool_t shipnow; + int refreshes = 2; +#ifndef _WIN32 + sigset_t mask, newmask; +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + + assert(cl != NULL); + +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + acquire_fd_lock(ct->ct_fd); + if (!ct->ct_waitset) { + /* If time is not within limits, we ignore it. */ + if (time_not_ok(&timeout) == FALSE) + ct->ct_wait = timeout; + } + + shipnow = + (xdr_results == NULL && timeout.tv_sec == 0 + && timeout.tv_usec == 0) ? FALSE : TRUE; + +call_again: + xdrs->x_op = XDR_ENCODE; + ct->ct_error.re_status = RPC_SUCCESS; + x_id = ntohl(--(*msg_x_id)); + + if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || + (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! (*xdr_args)(xdrs, args_ptr))) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + if (! xdrrec_endofrecord(xdrs, shipnow)) { + release_fd_lock(ct->ct_fd, mask); + ct->ct_error.re_status = RPC_CANTSEND; + return (ct->ct_error.re_status); + } + if (! shipnow) { + release_fd_lock(ct->ct_fd, mask); + return (RPC_SUCCESS); + } + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + release_fd_lock(ct->ct_fd, mask); + ct->ct_error.re_status = RPC_TIMEDOUT; + return(ct->ct_error.re_status); + } + + release_fd_lock(ct->ct_fd, mask); + /* + * Keep receiving until we get a valid transaction id + */ + + while (TRUE) { + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)] || + (ct->reply_msg.rm_xid && ct->reply_msg.rm_xid != x_id)) + cond_wait(&vc_cv[WINSOCK_HANDLE_HASH(ct->ct_fd)], &clnt_fd_lock); + vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)] = 1; + mutex_unlock(&clnt_fd_lock); + + xdrs->x_op = XDR_DECODE; + ct->reply_msg.acpted_rply.ar_verf = _null_auth; + ct->reply_msg.acpted_rply.ar_results.where = NULL; + ct->reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; + if (!ct->use_stored_reply_msg) { + if (! xdrrec_skiprecord(xdrs)) { + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + if (!xdr_getxiddir(xdrs, &ct->reply_msg)) { + release_fd_lock(ct->ct_fd, mask); + if (ct->ct_error.re_status == RPC_SUCCESS) + continue; + return (ct->ct_error.re_status); + } + + if (ct->reply_msg.rm_direction != REPLY) { + if (cl->cb_thread == INVALID_HANDLE_VALUE) { + ct->reply_msg.rm_xid = 0; + } else { + ct->use_stored_reply_msg = TRUE; + } + release_fd_lock(ct->ct_fd, mask); + continue; + } + } + if (ct->reply_msg.rm_xid == x_id) { + ct->use_stored_reply_msg = FALSE; + ct->reply_msg.rm_xid = 0; + if (!xdr_getreplyunion(xdrs, &ct->reply_msg)) { + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); + } + break; + } + else { + ct->use_stored_reply_msg = TRUE; + release_fd_lock(ct->ct_fd, mask); + SwitchToThread(); + } + } + + /* + * process header + */ + _seterr_reply(&ct->reply_msg, &(ct->ct_error)); + if (ct->ct_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &ct->reply_msg.acpted_rply.ar_verf)) { + ct->ct_error.re_status = RPC_AUTHERROR; + ct->ct_error.re_why = AUTH_INVALIDRESP; + } else if (! (*xdr_results)(xdrs, results_ptr)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTDECODERES; + } + /* free verifier ... */ + if (ct->reply_msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, + &(ct->reply_msg.acpted_rply.ar_verf)); + } + } /* end successful completion */ + else { + /* maybe our credentials need to be refreshed ... */ + if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &ct->reply_msg)) + goto call_again; + } /* end of unsuccessful completion */ + ct->reply_msg.rm_direction = -1; + release_fd_lock(ct->ct_fd, mask); + return (ct->ct_error.re_status); +} + +static void +clnt_vc_geterr(cl, errp) + CLIENT *cl; + struct rpc_err *errp; +{ + struct ct_data *ct; + + assert(cl != NULL); + assert(errp != NULL); + + ct = (struct ct_data *) cl->cl_private; + *errp = ct->ct_error; +} + +static bool_t +clnt_vc_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + void *res_ptr; +{ + struct ct_data *ct; + XDR *xdrs; + bool_t dummy; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + + assert(cl != NULL); + + ct = (struct ct_data *)cl->cl_private; + xdrs = &(ct->ct_xdrs); + +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[WINSOCK_HANDLE_HASH(ct->ct_fd)]) + cond_wait(&vc_cv[WINSOCK_HANDLE_HASH(ct->ct_fd)], &clnt_fd_lock); + xdrs->x_op = XDR_FREE; + dummy = (*xdr_res)(xdrs, res_ptr); + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + cond_signal(&vc_cv[WINSOCK_HANDLE_HASH(ct->ct_fd)]); + + return dummy; +} + +/*ARGSUSED*/ +static void +clnt_vc_abort(cl) + CLIENT *cl; +{ +} + +static bool_t +clnt_vc_control(cl, request, info) + CLIENT *cl; + u_int request; + void *info; +{ + struct ct_data *ct; + void *infop = info; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + + assert(cl != NULL); + + ct = (struct ct_data *)cl->cl_private; + +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + acquire_fd_lock(ct->ct_fd); + + switch (request) { + case CLSET_FD_CLOSE: + ct->ct_closeit = TRUE; + release_fd_lock(ct->ct_fd, mask); + return (TRUE); + case CLSET_FD_NCLOSE: + ct->ct_closeit = FALSE; + release_fd_lock(ct->ct_fd, mask); + return (TRUE); + default: + break; + } + + /* for other requests which use info */ + if (info == NULL) { + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + switch (request) { + case CLSET_TIMEOUT: + if (time_not_ok((struct timeval *)info)) { + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + ct->ct_wait = *(struct timeval *)infop; + ct->ct_waitset = TRUE; + break; + case CLGET_TIMEOUT: + *(struct timeval *)infop = ct->ct_wait; + break; + case CLGET_SERVER_ADDR: + (void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len); + break; + case CLGET_FD: + *(int *)info = ct->ct_fd; + break; + case CLGET_SVC_ADDR: + /* The caller should not free this memory area */ + *(struct netbuf *)info = ct->ct_addr; + break; + case CLSET_SVC_ADDR: /* set to new address */ + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + case CLGET_XID: + /* + * use the knowledge that xid is the + * first element in the call structure + * This will get the xid of the PREVIOUS call + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli); + break; + case CLSET_XID: + /* This will set the xid of the NEXT call */ + *(u_int32_t *)(void *)&ct->ct_u.ct_mcalli = + htonl(*((u_int32_t *)info) + 1); + /* increment by 1 as clnt_vc_call() decrements once */ + break; + case CLGET_VERS: + /* + * This RELIES on the information that, in the call body, + * the version number field is the fifth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 4 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_VERS: + *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 4 * BYTES_PER_XDR_UNIT) = + htonl(*(u_int32_t *)info); + break; + + case CLGET_PROG: + /* + * This RELIES on the information that, in the call body, + * the program number field is the fourth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + *(u_int32_t *)info = + ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 3 * BYTES_PER_XDR_UNIT)); + break; + + case CLSET_PROG: + *(u_int32_t *)(void *)(ct->ct_u.ct_mcallc + + 3 * BYTES_PER_XDR_UNIT) = + htonl(*(u_int32_t *)info); + break; + + default: + release_fd_lock(ct->ct_fd, mask); + return (FALSE); + } + release_fd_lock(ct->ct_fd, mask); + return (TRUE); +} + + +static void +clnt_vc_destroy(cl) + CLIENT *cl; +{ + struct ct_data *ct = (struct ct_data *) cl->cl_private; + int ct_fd = ct->ct_fd; +#ifndef _WIN32 + sigset_t mask; + sigset_t newmask; +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + + assert(cl != NULL); + + ct = (struct ct_data *) cl->cl_private; + +#ifndef _WIN32 + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[WINSOCK_HANDLE_HASH(ct_fd)]) + cond_wait(&vc_cv[WINSOCK_HANDLE_HASH(ct_fd)], &clnt_fd_lock); + if (ct->ct_closeit && ct->ct_fd != -1) { + (void)closesocket(ct->ct_fd); + } + XDR_DESTROY(&(ct->ct_xdrs)); + if (ct->ct_addr.buf) + free(ct->ct_addr.buf); + mem_free(ct, sizeof(struct ct_data)); + if (cl->cl_netid && cl->cl_netid[0]) + mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); + if (cl->cl_tp && cl->cl_tp[0]) + mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); + + if (cl->cb_thread != INVALID_HANDLE_VALUE) { + int status; + fprintf(stdout, "%04x: sending shutdown to callback thread %04x\n", + GetCurrentThreadId(), cl->cb_thread); + cl->shutdown = 1; + mutex_unlock(&clnt_fd_lock); + cond_signal(&vc_cv[WINSOCK_HANDLE_HASH(ct_fd)]); + status = WaitForSingleObject(cl->cb_thread, INFINITE); + fprintf(stdout, "%04x: terminated callback thread\n", GetCurrentThreadId()); + mutex_lock(&clnt_fd_lock); + while (vc_fd_locks[WINSOCK_HANDLE_HASH(ct_fd)]) + cond_wait(&vc_cv[WINSOCK_HANDLE_HASH(ct_fd)], &clnt_fd_lock); + } + mem_free(cl, sizeof(CLIENT)); + mutex_unlock(&clnt_fd_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + cond_signal(&vc_cv[WINSOCK_HANDLE_HASH(ct_fd)]); +} + +/* + * Interface between xdr serializer and tcp connection. + * Behaves like the system calls, read & write, but keeps some error state + * around for the rpc level. + */ +static int +read_vc(ctp, buf, len) + void *ctp; + void *buf; + int len; +{ + /* + struct sockaddr sa; + socklen_t sal; + */ + struct ct_data *ct = (struct ct_data *)ctp; + struct pollfd fd; + int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) + + (ct->ct_wait.tv_usec / 1000)); + + if (len == 0) + return (0); + fd.fd = ct->ct_fd; + fd.events = POLLIN; + for (;;) { + switch (poll(&fd, 1, milliseconds)) { + case 0: + ct->ct_error.re_status = RPC_TIMEDOUT; + return (-1); + + case SOCKET_ERROR: + errno = WSAGetLastError(); + if (errno == WSAEINTR) + continue; + ct->ct_error.re_status = RPC_CANTRECV; + ct->ct_error.re_errno = errno; + return (-1); + } + break; + } + + len = recv(ct->ct_fd, buf, (size_t)len, 0); + errno = WSAGetLastError(); + + switch (len) { + case 0: + /* premature eof */ + ct->ct_error.re_errno = WSAECONNRESET; + ct->ct_error.re_status = RPC_CANTRECV; + len = -1; /* it's really an error */ + break; + + case SOCKET_ERROR: + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTRECV; + break; + } + return (len); +} + +static int +write_vc(ctp, buf, len) + void *ctp; + char *buf; + int len; +{ + struct ct_data *ct = (struct ct_data *)ctp; + int i = 0, cnt; + + for (cnt = len; cnt > 0; cnt -= i, buf += i) { + if ((i = send(ct->ct_fd, buf, (size_t)cnt, 0)) == SOCKET_ERROR) { + ct->ct_error.re_errno = WSAGetLastError(); + ct->ct_error.re_status = RPC_CANTSEND; + return (-1); + } + } + return (len); +} + +static struct clnt_ops * +clnt_vc_ops() +{ + static struct clnt_ops ops; + extern mutex_t ops_lock; +#ifndef _WIN32 + sigset_t mask, newmask; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + sigfillset(&newmask); + thr_sigsetmask(SIG_SETMASK, &newmask, &mask); +#else + /* XXX Need Windows signal/event stuff XXX */ +#endif + mutex_lock(&ops_lock); + if (ops.cl_call == NULL) { + ops.cl_call = clnt_vc_call; + ops.cl_abort = clnt_vc_abort; + ops.cl_geterr = clnt_vc_geterr; + ops.cl_freeres = clnt_vc_freeres; + ops.cl_destroy = clnt_vc_destroy; + ops.cl_control = clnt_vc_control; + } + mutex_unlock(&ops_lock); +// thr_sigsetmask(SIG_SETMASK, &(mask), NULL); + return (&ops); +} + +/* + * Make sure that the time is not garbage. -1 value is disallowed. + * Note this is different from time_not_ok in clnt_dg.c + */ +static bool_t +time_not_ok(t) + struct timeval *t; +{ + return (t->tv_sec <= -1 || t->tv_sec > 100000000 || + t->tv_usec <= -1 || t->tv_usec > 1000000); +} diff --git a/libtirpc/src/crypt_client.c b/libtirpc/src/crypt_client.c new file mode 100644 index 0000000..32023fb --- /dev/null +++ b/libtirpc/src/crypt_client.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1996 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#include + +#include +//#include +#include +#include +#include +#include +#include + +#include + +int +_des_crypt_call(buf, len, dparms) + char *buf; + int len; + struct desparams *dparms; +{ + CLIENT *clnt; + desresp *result_1; + desargs des_crypt_1_arg; + struct netconfig *nconf; + void *localhandle; + int stat; + + nconf = NULL; + localhandle = setnetconfig(); + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) { + //warnx("getnetconfig: %s", nc_sperror()); + return(DESERR_HWERROR); + } + clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf); + if (clnt == (CLIENT *) NULL) { + endnetconfig(localhandle); + return(DESERR_HWERROR); + } + endnetconfig(localhandle); + + des_crypt_1_arg.desbuf.desbuf_len = len; + des_crypt_1_arg.desbuf.desbuf_val = buf; + des_crypt_1_arg.des_dir = dparms->des_dir; + des_crypt_1_arg.des_mode = dparms->des_mode; + bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8); + bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8); + + result_1 = des_crypt_1(&des_crypt_1_arg, clnt); + if (result_1 == (desresp *) NULL) { + clnt_destroy(clnt); + return(DESERR_HWERROR); + } + + stat = result_1->stat; + + if (result_1->stat == DESERR_NONE || + result_1->stat == DESERR_NOHWDEVICE) { + bcopy(result_1->desbuf.desbuf_val, buf, len); + bcopy(result_1->des_ivec, dparms->des_ivec, 8); + } + + clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1); + clnt_destroy(clnt); + + return(stat); +} diff --git a/libtirpc/src/des_crypt.c b/libtirpc/src/des_crypt.c new file mode 100644 index 0000000..89f7266 --- /dev/null +++ b/libtirpc/src/des_crypt.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * des_crypt.c, DES encryption library routines + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#include +#include +#include +#include +#include +#if 0 +#ifndef lint +static char sccsid[] = "@(#)des_crypt.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI"; +#endif +#endif +//#include + +static int common_crypt( char *, char *, unsigned, unsigned, struct desparams * ); +int (*__des_crypt_LOCAL)() = 0; +extern int _des_crypt_call(char *, int, struct desparams *); +/* + * Copy 8 bytes + */ +#define COPY8(src, dst) { \ + char *a = (char *) dst; \ + char *b = (char *) src; \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ +} + +/* + * Copy multiple of 8 bytes + */ +#define DESCOPY(src, dst, len) { \ + char *a = (char *) dst; \ + char *b = (char *) src; \ + int i; \ + for (i = (int) len; i > 0; i -= 8) { \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ + *a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \ + } \ +} + +/* + * CBC mode encryption + */ +int +cbc_crypt(key, buf, len, mode, ivec) + char *key; + char *buf; + unsigned len; + unsigned mode; + char *ivec; +{ + int err; + struct desparams dp; + +#ifdef BROKEN_DES + dp.UDES.UDES_buf = buf; + dp.des_mode = ECB; +#else + dp.des_mode = CBC; +#endif + COPY8(ivec, dp.des_ivec); + err = common_crypt(key, buf, len, mode, &dp); + COPY8(dp.des_ivec, ivec); + return(err); +} + + +/* + * ECB mode encryption + */ +int +ecb_crypt(key, buf, len, mode) + char *key; + char *buf; + unsigned len; + unsigned mode; +{ + struct desparams dp; + +#ifdef BROKEN_DES + dp.UDES.UDES_buf = buf; + dp.des_mode = CBC; +#else + dp.des_mode = ECB; +#endif + return(common_crypt(key, buf, len, mode, &dp)); +} + + + +/* + * Common code to cbc_crypt() & ecb_crypt() + */ +static int +common_crypt(key, buf, len, mode, desp) + char *key; + char *buf; + unsigned len; + unsigned mode; + struct desparams *desp; +{ + int desdev; + + if ((len % 8) != 0 || len > DES_MAXDATA) { + return(DESERR_BADPARAM); + } + desp->des_dir = + ((mode & DES_DIRMASK) == DES_ENCRYPT) ? ENCRYPT : DECRYPT; + + desdev = mode & DES_DEVMASK; + COPY8(key, desp->des_key); + /* + * software + */ + if (__des_crypt_LOCAL != NULL) { + if (!__des_crypt_LOCAL(buf, len, desp)) { + return (DESERR_HWERROR); + } + } else { + if (!_des_crypt_call(buf, len, desp)) { + return (DESERR_HWERROR); + } + } + return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE); +} diff --git a/libtirpc/src/des_soft.c b/libtirpc/src/des_soft.c new file mode 100644 index 0000000..e6fdf20 --- /dev/null +++ b/libtirpc/src/des_soft.c @@ -0,0 +1,65 @@ +//#include + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Table giving odd parity in the low bit for ASCII characters + */ +static char partab[128] = { + 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, + 0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e, + 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, + 0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f, + 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, + 0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f, + 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, + 0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e, + 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, + 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f, + 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, + 0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e, + 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, + 0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e, + 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, + 0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f, +}; + +/* + * Add odd parity to low bit of 8 byte key + */ +void +des_setparity(p) + char *p; +{ + int i; + + for (i = 0; i < 8; i++) { + *p = partab[*p & 0x7f]; + p++; + } +} diff --git a/libtirpc/src/epoll_sub.c b/libtirpc/src/epoll_sub.c new file mode 100644 index 0000000..7345098 --- /dev/null +++ b/libtirpc/src/epoll_sub.c @@ -0,0 +1,62 @@ +/* + * Copyright 2003 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#ifndef _WIN32 +#include + +#include +#include +#include +#include +#include + + +/*Paramètres du syscall - Attention spécifique hardware */ +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 + +int +epoll_create(int size) +{ + return (syscall(__NR_epoll_create, size)); +} + +int +epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + + return (syscall(__NR_epoll_ctl, epfd, op, fd, event)); +} + +int +epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) +{ + return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout)); +} + +#endif \ No newline at end of file diff --git a/libtirpc/src/getnetconfig.c b/libtirpc/src/getnetconfig.c new file mode 100644 index 0000000..0330d86 --- /dev/null +++ b/libtirpc/src/getnetconfig.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1989 by Sun Microsystems, Inc. + */ + +#include +//#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "rpc_com.h" + +// XXX FIXME - this is in wintirpc.c, but that is not currently built +static void wintirpc_debug(char *fmt, ...) +{ + return; +} + +/* + * The five library routines in this file provide application access to the + * system network configuration database, /etc/netconfig. In addition to the + * netconfig database and the routines for accessing it, the environment + * variable NETPATH and its corresponding routines in getnetpath.c may also be + * used to specify the network transport to be used. + */ + +/* + * netconfig errors + */ + +#define NC_NONETCONFIG ENOENT +#define NC_NOMEM ENOMEM +#define NC_NOTINIT EINVAL /* setnetconfig was not called first */ +#define NC_BADFILE EBADF /* format for netconfig file is bad */ +#define NC_NOTFOUND WSAENOPROTOOPT /* specified netid was not found */ + +/* + * semantics as strings (should be in netconfig.h) + */ +#define NC_TPI_CLTS_S "tpi_clts" +#define NC_TPI_COTS_S "tpi_cots" +#define NC_TPI_COTS_ORD_S "tpi_cots_ord" +#define NC_TPI_RAW_S "tpi_raw" + +/* + * flags as characters (also should be in netconfig.h) + */ +#define NC_NOFLAG_C '-' +#define NC_VISIBLE_C 'v' +#define NC_BROADCAST_C 'b' + +/* + * Character used to indicate there is no name-to-address lookup library + */ +#define NC_NOLOOKUP "-" + +static const char * const _nc_errors[] = { + "Netconfig database not found", + "Not enough memory", + "Not initialized", + "Netconfig database has invalid format", + "Netid not found in netconfig database" +}; + +struct netconfig_info { + int eof; /* all entries has been read */ + int ref; /* # of times setnetconfig() has been called */ + struct netconfig_list *head; /* head of the list */ + struct netconfig_list *tail; /* last of the list */ +}; + +struct netconfig_list { + char *linep; /* hold line read from netconfig */ + struct netconfig *ncp; + struct netconfig_list *next; +}; + +struct netconfig_vars { + int valid; /* token that indicates a valid netconfig_vars */ + int flag; /* first time flag */ + struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */ +}; + +#define NC_VALID 0xfeed +#define NC_STORAGE 0xf00d +#define NC_INVALID 0 + + +static int *__nc_error(void); +static int parse_ncp(char *, struct netconfig *); +static struct netconfig *dup_ncp(struct netconfig *); + + +static FILE *nc_file; /* for netconfig db */ +static struct netconfig_info ni = { 0, 0, NULL, NULL}; + +#define MAXNETCONFIGLINE 1000 + +static int * +__nc_error() +{ + extern mutex_t nc_lock; + extern thread_key_t nc_key; + static int nc_error = 0; + int error, *nc_addr; + + /* + * Use the static `nc_error' if we are the main thread + * (including non-threaded programs), or if an allocation + * fails. + */ + if (nc_key == -1) { + error = 0; + mutex_lock(&nc_lock); + if (nc_key == -1) + error = nc_key = TlsAlloc(); //thr_keycreate(&nc_key, free); + mutex_unlock(&nc_lock); + if (error == TLS_OUT_OF_INDEXES) + return (&nc_error); + } + if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) { + nc_addr = (int *)malloc(sizeof (int *)); + if (thr_setspecific(nc_key, (void *) nc_addr) == 0) { + if (nc_addr) + free(nc_addr); + return (&nc_error); + } + *nc_addr = 0; + } + return (nc_addr); +} + +#define nc_error (*(__nc_error())) +/* + * A call to setnetconfig() establishes a /etc/netconfig "session". A session + * "handle" is returned on a successful call. At the start of a session (after + * a call to setnetconfig()) searches through the /etc/netconfig database will + * proceed from the start of the file. The session handle must be passed to + * getnetconfig() to parse the file. Each call to getnetconfig() using the + * current handle will process one subsequent entry in /etc/netconfig. + * setnetconfig() must be called before the first call to getnetconfig(). + * (Handles are used to allow for nested calls to setnetpath()). + * + * A new session is established with each call to setnetconfig(), with a new + * handle being returned on each call. Previously established sessions remain + * active until endnetconfig() is called with that session's handle as an + * argument. + * + * setnetconfig() need *not* be called before a call to getnetconfigent(). + * setnetconfig() returns a NULL pointer on failure (for example, if + * the netconfig database is not present). + */ +void * +setnetconfig() +{ + struct netconfig_vars *nc_vars; + + if ((nc_vars = (struct netconfig_vars *)malloc(sizeof + (struct netconfig_vars))) == NULL) { + return(NULL); + } + + /* + * For multiple calls, i.e. nc_file is not NULL, we just return the + * handle without reopening the netconfig db. + */ + ni.ref++; + if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) { + nc_vars->valid = NC_VALID; + nc_vars->flag = 0; + nc_vars->nc_configs = ni.head; + return ((void *)nc_vars); + } + ni.ref--; + nc_error = NC_NONETCONFIG; + free(nc_vars); + return (NULL); +} + + +/* + * When first called, getnetconfig() returns a pointer to the first entry in + * the netconfig database, formatted as a struct netconfig. On each subsequent + * call, getnetconfig() returns a pointer to the next entry in the database. + * getnetconfig() can thus be used to search the entire netconfig file. + * getnetconfig() returns NULL at end of file. + */ + +struct netconfig * +getnetconfig(handlep) +void *handlep; +{ + struct netconfig_vars *ncp = (struct netconfig_vars *)handlep; + char *stringp; /* tmp string pointer */ + struct netconfig_list *list; + struct netconfig *np; + + /* + * Verify that handle is valid + */ + if (ncp == NULL || nc_file == NULL) { + nc_error = NC_NOTINIT; + return (NULL); + } + + switch (ncp->valid) { + case NC_VALID: + /* + * If entry has already been read into the list, + * we return the entry in the linked list. + * If this is the first time call, check if there are any entries in + * linked list. If no entries, we need to read the netconfig db. + * If we have been here and the next entry is there, we just return + * it. + */ + if (ncp->flag == 0) { /* first time */ + ncp->flag = 1; + ncp->nc_configs = ni.head; + if (ncp->nc_configs != NULL) /* entry already exist */ + return(ncp->nc_configs->ncp); + } + else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) { + ncp->nc_configs = ncp->nc_configs->next; + return(ncp->nc_configs->ncp); + } + + /* + * If we cannot find the entry in the list and is end of file, + * we give up. + */ + if (ni.eof == 1) + return(NULL); + break; + default: + nc_error = NC_NOTINIT; + return (NULL); + } + + stringp = (char *) malloc(MAXNETCONFIGLINE); + if (stringp == NULL) + return (NULL); + +#ifdef MEM_CHK + if (malloc_verify() == 0) { + fprintf(stderr, "memory heap corrupted in getnetconfig\n"); + exit(1); + } +#endif + + /* + * Read a line from netconfig file. + */ + do { + if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) { + free(stringp); + ni.eof = 1; + return (NULL); + } + } while (*stringp == '#'); + + list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list)); + if (list == NULL) { + free(stringp); + return(NULL); + } + np = (struct netconfig *) malloc(sizeof (struct netconfig)); + if (np == NULL) { + free(stringp); + free(list); + return(NULL); + } + list->ncp = np; + list->next = NULL; + list->ncp->nc_lookups = NULL; + list->linep = stringp; + wintirpc_debug("%s: before parse: &list->linep %p, list->linep %p, stringp %p\n", __FUNCTION__, &list->linep, list->linep, stringp); + if (parse_ncp(stringp, list->ncp) == -1) { + free(stringp); + free(np); + free(list); + return (NULL); + } else { + wintirpc_debug("%s: after parse: list->linep %p, stringp %p\n", __FUNCTION__, list->linep, stringp); + /* + * If this is the first entry that's been read, it is the head of + * the list. If not, put the entry at the end of the list. + * Reposition the current pointer of the handle to the last entry + * in the list. + */ + if (ni.head == NULL) { /* first entry */ + ni.head = ni.tail = list; + } + else { + ni.tail->next = list; + ni.tail = ni.tail->next; + } + ncp->nc_configs = ni.tail; + return(ni.tail->ncp); + } +} + +/* + * endnetconfig() may be called to "unbind" or "close" the netconfig database + * when processing is complete, releasing resources for reuse. endnetconfig() + * may not be called before setnetconfig(). endnetconfig() returns 0 on + * success and -1 on failure (for example, if setnetconfig() was not called + * previously). + */ +int +endnetconfig(handlep) +void *handlep; +{ + struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep; + + struct netconfig_list *q, *p; + + /* + * Verify that handle is valid + */ + if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID && + nc_handlep->valid != NC_STORAGE)) { + nc_error = NC_NOTINIT; + return (-1); + } + + /* + * Return 0 if anyone still needs it. + */ + nc_handlep->valid = NC_INVALID; + nc_handlep->flag = 0; + nc_handlep->nc_configs = NULL; + if (--ni.ref > 0) { + free(nc_handlep); + return(0); + } + + /* + * Noone needs these entries anymore, then frees them. + * Make sure all info in netconfig_info structure has been reinitialized. + */ + q = p = ni.head; + ni.eof = ni.ref = 0; + ni.head = NULL; + ni.tail = NULL; + while (q) { + p = q->next; + if (q->ncp->nc_lookups != NULL) free(q->ncp->nc_lookups); + free(q->ncp); + free(q->linep); + free(q); + q = p; + } + free(nc_handlep); + + fclose(nc_file); + nc_file = NULL; + return (0); +} + +/* + * getnetconfigent(netid) returns a pointer to the struct netconfig structure + * corresponding to netid. It returns NULL if netid is invalid (that is, does + * not name an entry in the netconfig database). It returns NULL and sets + * errno in case of failure (for example, if the netconfig database cannot be + * opened). + */ + +struct netconfig * +getnetconfigent(netid) + const char *netid; +{ + FILE *file; /* NETCONFIG db's file pointer */ + char *linep; /* holds current netconfig line */ + char *stringp; /* temporary string pointer */ + struct netconfig *ncp = NULL; /* returned value */ + struct netconfig_list *list; /* pointer to cache list */ + + nc_error = NC_NOTFOUND; /* default error. */ + if (netid == NULL || strlen(netid) == 0) { + return (NULL); + } + + if (strcmp(netid, "unix") == 0) { + fprintf(stderr, "The local transport is called \"unix\" "); + fprintf(stderr, "in /etc/netconfig.\n"); + fprintf(stderr, "Please change this to \"local\" manually "); + fprintf(stderr, "or run mergemaster(8).\n"); + fprintf(stderr, "See UPDATING entry 20021216 for details.\n"); + fprintf(stderr, "Continuing in 10 seconds\n\n"); + fprintf(stderr, "This warning will be removed 20030301\n"); + Sleep(10000); // sleep(10); + } + + /* + * Look up table if the entries have already been read and parsed in + * getnetconfig(), then copy this entry into a buffer and return it. + * If we cannot find the entry in the current list and there are more + * entries in the netconfig db that has not been read, we then read the + * db and try find the match netid. + * If all the netconfig db has been read and placed into the list and + * there is no match for the netid, return NULL. + */ + if (ni.head != NULL) { + for (list = ni.head; list; list = list->next) { + if (strcmp(list->ncp->nc_netid, netid) == 0) { + return(dup_ncp(list->ncp)); + } + } + if (ni.eof == 1) /* that's all the entries */ + return(NULL); + } + + + if ((file = fopen(NETCONFIG, "r")) == NULL) { + nc_error = NC_NONETCONFIG; + return (NULL); + } + + if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) { + fclose(file); + nc_error = NC_NOMEM; + return (NULL); + } + do { + ptrdiff_t len; + char *tmpp; /* tmp string pointer */ + + do { + if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) { + break; + } + } while (*stringp == '#'); + if (stringp == NULL) { /* eof */ + break; + } + if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */ + nc_error = NC_BADFILE; + break; + } + if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */ + strncmp(stringp, netid, (size_t)len) == 0) { + if ((ncp = (struct netconfig *) + malloc(sizeof (struct netconfig))) == NULL) { + break; + } + ncp->nc_lookups = NULL; + if (parse_ncp(linep, ncp) == -1) { + free(ncp); + ncp = NULL; + } + break; + } + } while (stringp != NULL); + if (ncp == NULL) { + free(linep); + } + fclose(file); + return(ncp); +} + +/* + * freenetconfigent(netconfigp) frees the netconfig structure pointed to by + * netconfigp (previously returned by getnetconfigent()). + */ + +void +freenetconfigent(netconfigp) + struct netconfig *netconfigp; +{ + if (netconfigp != NULL) { + free(netconfigp->nc_netid); /* holds all netconfigp's strings */ + if (netconfigp->nc_lookups != NULL) + free(netconfigp->nc_lookups); + free(netconfigp); + } + return; +} + +/* + * Parse line and stuff it in a struct netconfig + * Typical line might look like: + * udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so + * + * We return -1 if any of the tokens don't parse, or malloc fails. + * + * Note that we modify stringp (putting NULLs after tokens) and + * we set the ncp's string field pointers to point to these tokens within + * stringp. + */ + +static int +parse_ncp(stringp, ncp) +char *stringp; /* string to parse */ +struct netconfig *ncp; /* where to put results */ +{ + char *tokenp; /* for processing tokens */ + char *lasts; + + nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */ + wintirpc_debug("%s: The last character being chopped is '%02x'\n", __FUNCTION__, stringp[strlen(stringp)-1]); + wintirpc_debug("%s: The string before chopping is '%s'\n", __FUNCTION__, stringp); + stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */ + wintirpc_debug("%s: The last character after chopping is '%02x'\n", __FUNCTION__, stringp[strlen(stringp)-1]); + wintirpc_debug("%s: The string after chopping is '%s'\n", __FUNCTION__, stringp); + /* netid */ + if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) { + return (-1); + } + + /* semantics */ + if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0) + ncp->nc_semantics = NC_TPI_COTS_ORD; + else if (strcmp(tokenp, NC_TPI_COTS_S) == 0) + ncp->nc_semantics = NC_TPI_COTS; + else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0) + ncp->nc_semantics = NC_TPI_CLTS; + else if (strcmp(tokenp, NC_TPI_RAW_S) == 0) + ncp->nc_semantics = NC_TPI_RAW; + else + return (-1); + + /* flags */ + if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0'; + tokenp++) { + switch (*tokenp) { + case NC_NOFLAG_C: + break; + case NC_VISIBLE_C: + ncp->nc_flag |= NC_VISIBLE; + break; + case NC_BROADCAST_C: + ncp->nc_flag |= NC_BROADCAST; + break; + default: + return (-1); + } + } + /* protocol family */ + if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + /* protocol name */ + if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + /* network device */ + if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) { + return (-1); + } + if (strcmp(tokenp, NC_NOLOOKUP) == 0) { + ncp->nc_nlookups = 0; + ncp->nc_lookups = NULL; + } else { + char *cp; /* tmp string */ + + if (ncp->nc_lookups != NULL) /* from last visit */ + free(ncp->nc_lookups); + /* preallocate one string pointer */ + ncp->nc_lookups = (char **)malloc(sizeof (char *)); + ncp->nc_nlookups = 0; + while ((cp = tokenp) != NULL) { + tokenp = _get_next_token(cp, ','); + ncp->nc_lookups[(size_t)ncp->nc_nlookups++] = cp; + ncp->nc_lookups = (char **)realloc(ncp->nc_lookups, + (size_t)(ncp->nc_nlookups+1) *sizeof(char *)); /* for next loop */ + } + } + return (0); +} + + +/* + * Returns a string describing the reason for failure. + */ +char * +nc_sperror() +{ + const char *message; + + switch(nc_error) { + case NC_NONETCONFIG: + message = _nc_errors[0]; + break; + case NC_NOMEM: + message = _nc_errors[1]; + break; + case NC_NOTINIT: + message = _nc_errors[2]; + break; + case NC_BADFILE: + message = _nc_errors[3]; + break; + case NC_NOTFOUND: + message = _nc_errors[4]; + break; + default: + message = "Unknown network selection error"; + } + /* LINTED const castaway */ + return ((char *)message); +} + +/* + * Prints a message onto standard error describing the reason for failure. + */ +void +nc_perror(s) + const char *s; +{ + fprintf(stderr, "%s: %s\n", s, nc_sperror()); +} + +/* + * Duplicates the matched netconfig buffer. + */ +static struct netconfig * +dup_ncp(ncp) +struct netconfig *ncp; +{ + struct netconfig *p; + char *tmp; + u_int i; + + if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL) + return(NULL); + if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) { + free(tmp); + return(NULL); + } + /* + * First we dup all the data from matched netconfig buffer. Then we + * adjust some of the member pointer to a pre-allocated buffer where + * contains part of the data. + * To follow the convention used in parse_ncp(), we store all the + * necessary information in the pre-allocated buffer and let each + * of the netconfig char pointer member point to the right address + * in the buffer. + */ + *p = *ncp; + p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid); + tmp = strchr(tmp, 0) + 1; + p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly); + tmp = strchr(tmp, 0) + 1; + p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto); + tmp = strchr(tmp, 0) + 1; + p->nc_device = (char *)strcpy(tmp,ncp->nc_device); + p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *)); + if (p->nc_lookups == NULL) { + free(p->nc_netid); + return(NULL); + } + for (i=0; i < p->nc_nlookups; i++) { + tmp = strchr(tmp, 0) + 1; + p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]); + } + return(p); +} diff --git a/libtirpc/src/getnetpath.c b/libtirpc/src/getnetpath.c new file mode 100644 index 0000000..1fb6a12 --- /dev/null +++ b/libtirpc/src/getnetpath.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +//#include + +/* + * Copyright (c) 1989 by Sun Microsystems, Inc. + */ + +//#include +#include +#include +#include +#include +#include +#include +//#include + +/* + * internal structure to keep track of a netpath "session" + */ +struct netpath_chain { + struct netconfig *ncp; /* an nconf entry */ + struct netpath_chain *nchain_next; /* next nconf entry allocated */ +}; + + +struct netpath_vars { + int valid; /* token that indicates a valid netpath_vars */ + void *nc_handlep; /* handle for current netconfig "session" */ + char *netpath; /* pointer to current view-point in NETPATH */ + char *netpath_start; /* pointer to start of our copy of NETPATH */ + struct netpath_chain *ncp_list; /* list of nconfs allocated this session*/ +}; + +#define NP_VALID 0xf00d +#define NP_INVALID 0 + +char *_get_next_token(char *, int); + + +/* + * A call to setnetpath() establishes a NETPATH "session". setnetpath() + * must be called before the first call to getnetpath(). A "handle" is + * returned to distinguish the session; this handle should be passed + * subsequently to getnetpath(). (Handles are used to allow for nested calls + * to setnetpath()). + * If setnetpath() is unable to establish a session (due to lack of memory + * resources, or the absence of the /etc/netconfig file), a NULL pointer is + * returned. + */ + +void * +setnetpath() +{ + + struct netpath_vars *np_sessionp; /* this session's variables */ + char *npp; /* NETPATH env variable */ + +#ifdef MEM_CHK + malloc_debug(1); +#endif + + if ((np_sessionp = + (struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) { + return (NULL); + } + if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) { + //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + return (NULL); + } + np_sessionp->valid = NP_VALID; + np_sessionp->ncp_list = NULL; + if ((npp = getenv(NETPATH)) == NULL) { + np_sessionp->netpath = NULL; + } else { + (void) endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/ + np_sessionp->nc_handlep = NULL; + if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL) { + free(np_sessionp); + return (NULL); + } else { + (void) strcpy(np_sessionp->netpath, npp); + } + } + np_sessionp->netpath_start = np_sessionp->netpath; + return ((void *)np_sessionp); +} + +/* + * When first called, getnetpath() returns a pointer to the netconfig + * database entry corresponding to the first valid NETPATH component. The + * netconfig entry is formatted as a struct netconfig. + * On each subsequent call, getnetpath returns a pointer to the netconfig + * entry that corresponds to the next valid NETPATH component. getnetpath + * can thus be used to search the netconfig database for all networks + * included in the NETPATH variable. + * When NETPATH has been exhausted, getnetpath() returns NULL. It returns + * NULL and sets errno in case of an error (e.g., setnetpath was not called + * previously). + * getnetpath() silently ignores invalid NETPATH components. A NETPATH + * compnent is invalid if there is no corresponding entry in the netconfig + * database. + * If the NETPATH variable is unset, getnetpath() behaves as if NETPATH + * were set to the sequence of default or visible networks in the netconfig + * database, in the order in which they are listed. + */ + +struct netconfig * +getnetpath(handlep) + void *handlep; +{ + struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep; + struct netconfig *ncp = NULL; /* temp. holds a netconfig session */ + struct netpath_chain *chainp; /* holds chain of ncp's we alloc */ + char *npp; /* holds current NETPATH */ + + if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) { + errno = EINVAL; + return (NULL); + } + if (np_sessionp->netpath_start == NULL) { /* NETPATH was not set */ + do { /* select next visible network */ + if (np_sessionp->nc_handlep == NULL) { + np_sessionp->nc_handlep = setnetconfig(); + if (np_sessionp->nc_handlep == NULL) { + //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + } + } + if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) { + return(NULL); + } + } while ((ncp->nc_flag & NC_VISIBLE) == 0); + return (ncp); + } + /* + * Find first valid network ID in netpath. + */ + while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) { + np_sessionp->netpath = _get_next_token(npp, ':'); + /* + * npp is a network identifier. + */ + if ((ncp = getnetconfigent(npp)) != NULL) { + chainp = (struct netpath_chain *) /* cobble alloc chain entry */ + malloc(sizeof (struct netpath_chain)); + chainp->ncp = ncp; + chainp->nchain_next = NULL; + if (np_sessionp->ncp_list == NULL) { + np_sessionp->ncp_list = chainp; + } else { + np_sessionp->ncp_list->nchain_next = chainp; + } + return (ncp); + } + /* couldn't find this token in the database; go to next one. */ + } + return (NULL); +} + +/* + * endnetpath() may be called to unbind NETPATH when processing is complete, + * releasing resources for reuse. It returns 0 on success and -1 on failure + * (e.g. if setnetpath() was not called previously. + */ +int +endnetpath(handlep) + void *handlep; +{ + struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep; + struct netpath_chain *chainp, *lastp; + + if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) { + errno = EINVAL; + return (-1); + } + if (np_sessionp->nc_handlep != NULL) + endnetconfig(np_sessionp->nc_handlep); + if (np_sessionp->netpath_start != NULL) + free(np_sessionp->netpath_start); + for (chainp = np_sessionp->ncp_list; chainp != NULL; + lastp=chainp, chainp=chainp->nchain_next, free(lastp)) { + freenetconfigent(chainp->ncp); + } + free(np_sessionp); +#ifdef MEM_CHK + if (malloc_verify() == 0) { + fprintf(stderr, "memory heap corrupted in endnetpath\n"); + exit(1); + } +#endif + return (0); +} + + + +/* + * Returns pointer to the rest-of-the-string after the current token. + * The token itself starts at arg, and we null terminate it. We return NULL + * if either the arg is empty, or if this is the last token. + */ + +char * +_get_next_token(npp, token) +char *npp; /* string */ +int token; /* char to parse string for */ +{ + char *cp; /* char pointer */ + char *np; /* netpath pointer */ + char *ep; /* escape pointer */ + + if ((cp = strchr(npp, token)) == NULL) { + return (NULL); + } + /* + * did find a token, but it might be escaped. + */ + if ((cp > npp) && (cp[-1] == '\\')) { + /* if slash was also escaped, carry on, otherwise find next token */ + if ((cp > npp + 1) && (cp[-2] != '\\')) { + /* shift r-o-s onto the escaped token */ + strcpy(&cp[-1], cp); /* XXX: overlapping string copy */ + /* + * Do a recursive call. + * We don't know how many escaped tokens there might be. + */ + return (_get_next_token(cp, token)); + } + } + + *cp++ = '\0'; /* null-terminate token */ + /* get rid of any backslash escapes */ + ep = npp; + while ((np = strchr(ep, '\\')) != 0) { + if (np[1] == '\\') + np++; + strcpy(np, (ep = &np[1])); /* XXX: overlapping string copy */ + } + return (cp); /* return ptr to r-o-s */ +} diff --git a/libtirpc/src/getpeereid.c b/libtirpc/src/getpeereid.c new file mode 100644 index 0000000..df8365f --- /dev/null +++ b/libtirpc/src/getpeereid.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2001 Dima Dorfman. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +//#include +#include +#include +//#include +//#include +//#include + +#include +//#include + +#ifdef _WIN32 +int +getpeereid(SOCKET s, uid_t *euid, gid_t *egid) +{ + // XXX Need to figure out what to do here for Windows! + return -1; +} +#else +int +getpeereid(int s, uid_t *euid, gid_t *egid) +{ + struct ucred uc; + socklen_t uclen; + int error; + + uclen = sizeof(uc); + error = getsockopt(s, SOL_SOCKET, SO_PEERCRED, &uc, &uclen); /* SCM_CREDENTIALS */ + if (error != 0) + return (error); + // if (uc.cr_version != XUCRED_VERSION) + // return (EINVAL); + *euid = uc.uid; + *egid = uc.gid; + return (0); + } +#endif diff --git a/libtirpc/src/getpublickey.c b/libtirpc/src/getpublickey.c new file mode 100644 index 0000000..0dee063 --- /dev/null +++ b/libtirpc/src/getpublickey.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* +#include +*/ + +/* + * publickey.c + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +/* + * Public key lookup routines + */ +#include +#ifndef _WIN32 +#include +//#include +#include +#include +#include +#include +#include +#include + +#define PKFILE "/etc/publickey" + +/* + * Hack to let ypserv/rpc.nisd use AUTH_DES. + */ +int (*__getpublickey_LOCAL)() = 0; + +/* + * Get somebody's public key + */ +int +__getpublickey_real(netname, publickey) + char *netname; + char *publickey; +{ + char lookup[3 * HEXKEYBYTES]; + char *p; + + if (publickey == NULL) + return (0); + if (!getpublicandprivatekey(netname, lookup)) + return (0); + p = strchr(lookup, ':'); + if (p == NULL) { + return (0); + } + *p = '\0'; + (void) strncpy(publickey, lookup, HEXKEYBYTES); + publickey[HEXKEYBYTES] = '\0'; + return (1); +} + +/* + * reads the file /etc/publickey looking for a + to optionally go to the + * yellow pages + */ + +int +getpublicandprivatekey(key, ret) + char *key; + char *ret; +{ + char buf[1024]; /* big enough */ + char *res; + FILE *fd; + char *mkey; + char *mval; + + fd = fopen(PKFILE, "r"); + if (fd == NULL) + return (0); + for (;;) { + res = fgets(buf, sizeof(buf), fd); + if (res == NULL) { + fclose(fd); + return (0); + } + if (res[0] == '#') + continue; + else if (res[0] == '+') { +#ifdef YP + char *PKMAP = "publickey.byname"; + char *lookup; + char *domain; + int err; + int len; + + err = yp_get_default_domain(&domain); + if (err) { + continue; + } + lookup = NULL; + err = yp_match(domain, PKMAP, key, strlen(key), &lookup, &len); + if (err) { +#ifdef DEBUG + fprintf(stderr, "match failed error %d\n", err); +#endif + continue; + } + lookup[len] = 0; + strcpy(ret, lookup); + fclose(fd); + free(lookup); + return (2); +#else /* YP */ +#ifdef DEBUG + fprintf(stderr, +"Bad record in %s '+' -- NIS not supported in this library copy\n", PKFILE); +#endif /* DEBUG */ + continue; +#endif /* YP */ + } else { + mkey = strsep(&res, "\t "); + if (mkey == NULL) { + fprintf(stderr, + "Bad record in %s -- %s", PKFILE, buf); + continue; + } + do { + mval = strsep(&res, " \t#\n"); + } while (mval != NULL && !*mval); + if (mval == NULL) { + fprintf(stderr, + "Bad record in %s val problem - %s", PKFILE, buf); + continue; + } + if (strcmp(mkey, key) == 0) { + strcpy(ret, mval); + fclose(fd); + return (1); + } + } + } +} + +int getpublickey(netname, publickey) + const char *netname; + char *publickey; +{ + if (__getpublickey_LOCAL != NULL) + return(__getpublickey_LOCAL(netname, publickey)); + else + return(__getpublickey_real(netname, publickey)); +} +#endif /* ! _WIN32 */ \ No newline at end of file diff --git a/libtirpc/src/getrpcent.c b/libtirpc/src/getrpcent.c new file mode 100644 index 0000000..2e2c896 --- /dev/null +++ b/libtirpc/src/getrpcent.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1984 by Sun Microsystems, Inc. + */ + +#include +#include + +//#include +//#include + +#include +//#include +#include +#include +#include + +#include +#ifdef YP +#include +#include +#endif +#include + +/* + * Internet version. + */ +static struct rpcdata { + FILE *rpcf; + int stayopen; +#define MAXALIASES 35 + char *rpc_aliases[MAXALIASES]; + struct rpcent rpc; + char line[BUFSIZ+1]; +#ifdef YP + char *domain; + char *current; + int currentlen; +#endif +} *rpcdata; + +static struct rpcent *interpret(char *val, size_t len); + +#ifdef YP +static int __yp_nomap = 0; +#endif /* YP */ + +#define RPCDB "/etc/rpc" + +static struct rpcdata *_rpcdata(void); + +static struct rpcdata * +_rpcdata() +{ + struct rpcdata *d = rpcdata; + + if (d == 0) { + d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata)); + rpcdata = d; + } + return (d); +} + +#ifdef GQ +struct rpcent * +getrpcbynumber(number) + int number; +{ +#ifdef YP + int reason; + char adrstr[16]; +#endif + struct rpcent *p; + struct rpcdata *d = _rpcdata(); + + if (d == 0) + return (0); +#ifdef YP + if (!__yp_nomap && _yp_check(&d->domain)) { + sprintf(adrstr, "%d", number); + reason = yp_match(d->domain, "rpc.bynumber", adrstr, strlen(adrstr), + &d->current, &d->currentlen); + switch(reason) { + case 0: + break; + case YPERR_MAP: + __yp_nomap = 1; + goto no_yp; + break; + default: + return(0); + break; + } + d->current[d->currentlen] = '\0'; + p = interpret(d->current, d->currentlen); + (void) free(d->current); + return p; + } +no_yp: +#endif /* YP */ + + setrpcent(0); + while ((p = getrpcent()) != NULL) { + if (p->r_number == number) + break; + } + endrpcent(); + return (p); +} + +struct rpcent * +getrpcbyname(name) + char *name; +{ + struct rpcent *rpc = NULL; + char **rp; + + assert(name != NULL); + + setrpcent(0); + while ((rpc = getrpcent()) != NULL) { + if (strcmp(rpc->r_name, name) == 0) + goto done; + for (rp = rpc->r_aliases; *rp != NULL; rp++) { + if (strcmp(*rp, name) == 0) + goto done; + } + } +done: + endrpcent(); + return (rpc); +} +#endif /* GQ */ + +void +setrpcent(f) + int f; +{ + struct rpcdata *d = _rpcdata(); + + if (d == 0) + return; +#ifdef YP + if (!__yp_nomap && _yp_check(NULL)) { + if (d->current) + free(d->current); + d->current = NULL; + d->currentlen = 0; + return; + } + __yp_nomap = 0; +#endif /* YP */ + if (d->rpcf == NULL) + d->rpcf = fopen(RPCDB, "r"); + else + rewind(d->rpcf); + d->stayopen |= f; +} + +void +endrpcent() +{ + struct rpcdata *d = _rpcdata(); + + if (d == 0) + return; +#ifdef YP + if (!__yp_nomap && _yp_check(NULL)) { + if (d->current && !d->stayopen) + free(d->current); + d->current = NULL; + d->currentlen = 0; + return; + } + __yp_nomap = 0; +#endif /* YP */ + if (d->rpcf && !d->stayopen) { + fclose(d->rpcf); + d->rpcf = NULL; + } +} + +struct rpcent * +getrpcent() +{ + struct rpcdata *d = _rpcdata(); +#ifdef YP + struct rpcent *hp; + int reason; + char *val = NULL; + int vallen; +#endif + + if (d == 0) + return(NULL); +#ifdef YP + if (!__yp_nomap && _yp_check(&d->domain)) { + if (d->current == NULL && d->currentlen == 0) { + reason = yp_first(d->domain, "rpc.bynumber", + &d->current, &d->currentlen, + &val, &vallen); + } else { + reason = yp_next(d->domain, "rpc.bynumber", + d->current, d->currentlen, + &d->current, &d->currentlen, + &val, &vallen); + } + switch(reason) { + case 0: + break; + case YPERR_MAP: + __yp_nomap = 1; + goto no_yp; + break; + default: + return(0); + break; + } + val[vallen] = '\0'; + hp = interpret(val, vallen); + (void) free(val); + return hp; + } +no_yp: +#endif /* YP */ + if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL) + return (NULL); + /* -1 so there is room to append a \n below */ + if (fgets(d->line, BUFSIZ - 1, d->rpcf) == NULL) + return (NULL); + return (interpret(d->line, strlen(d->line))); +} + +static struct rpcent * +interpret(val, len) + char *val; + size_t len; +{ + struct rpcdata *d = _rpcdata(); + char *p; + char *cp, **q; + + assert(val != NULL); + + if (d == 0) + return (0); + (void) strncpy(d->line, val, BUFSIZ); + d->line[BUFSIZ] = '\0'; + p = d->line; + p[len] = '\n'; + if (*p == '#') + return (getrpcent()); + cp = strpbrk(p, "#\n"); + if (cp == NULL) + return (getrpcent()); + *cp = '\0'; + cp = strpbrk(p, " \t"); + if (cp == NULL) + return (getrpcent()); + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ + d->rpc.r_name = d->line; + while (*cp == ' ' || *cp == '\t') + cp++; + d->rpc.r_number = atoi(cp); + q = d->rpc.r_aliases = d->rpc_aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &(d->rpc_aliases[MAXALIASES - 1])) + *q++ = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + *q = NULL; + return (&d->rpc); +} + diff --git a/libtirpc/src/getrpcport.c b/libtirpc/src/getrpcport.c new file mode 100644 index 0000000..8d96a98 --- /dev/null +++ b/libtirpc/src/getrpcport.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +#include +#include +//#include + +#include +//#include +#include +#include + +#include +#include + +int +getrpcport(host, prognum, versnum, proto) + char *host; + int prognum, versnum, proto; +{ + struct sockaddr_in addr; + struct hostent *hp; + + assert(host != NULL); + + if ((hp = gethostbyname(host)) == NULL) + return (0); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + if (hp->h_length > sizeof(addr)) + hp->h_length = sizeof(addr); + memcpy(&addr.sin_addr.s_addr, hp->h_addr, (size_t)hp->h_length); + /* Inconsistent interfaces need casts! :-( */ + return (pmap_getport(&addr, (u_long)prognum, (u_long)versnum, + (u_int)proto)); +} diff --git a/libtirpc/src/gettimeofday.c b/libtirpc/src/gettimeofday.c new file mode 100644 index 0000000..5ccdfd4 --- /dev/null +++ b/libtirpc/src/gettimeofday.c @@ -0,0 +1,44 @@ +/* XXX NEED Copyright info */ +#include +#include < time.h > + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + + if (NULL != tv) + { + GetSystemTimeAsFileTime(&ft); + + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch*/ + tmpres /= 10; /*convert into microseconds*/ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long)(tmpres / 1000000UL); + tv->tv_usec = (long)(tmpres % 1000000UL); + } + + if (NULL != tz) + { + if (!tzflag) + { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} diff --git a/libtirpc/src/key_call.c b/libtirpc/src/key_call.c new file mode 100644 index 0000000..84be343 --- /dev/null +++ b/libtirpc/src/key_call.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + + +//#include + +/* + * key_call.c, Interface to keyserver + * + * setsecretkey(key) - set your secret key + * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent + * decryptsessionkey(agent, deskey) - decrypt ditto + * gendeskey(deskey) - generate a secure des key + */ + +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define KEY_TIMEOUT 5 /* per-try timeout in seconds */ +#define KEY_NRETRY 12 /* number of retries */ + +#ifdef DEBUG +#define debug(msg) (void) fprintf(stderr, "%s\n", msg); +#else +#define debug(msg) +#endif /* DEBUG */ + +/* + * Hack to allow the keyserver to use AUTH_DES (for authenticated + * NIS+ calls, for example). The only functions that get called + * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes. + * + * The approach is to have the keyserver fill in pointers to local + * implementations of these functions, and to call those in key_call(). + */ + +cryptkeyres *(*__key_encryptsession_pk_LOCAL)() = 0; +cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0; +des_block *(*__key_gendes_LOCAL)() = 0; + +static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *); + +int +key_setsecret(secretkey) + const char *secretkey; +{ + keystatus status; + + if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf, + (void *)secretkey, + (xdrproc_t)xdr_keystatus, &status)) { + return (-1); + } + if (status != KEY_SUCCESS) { + debug("set status is nonzero"); + return (-1); + } + return (0); +} + + +/* key_secretkey_is_set() returns 1 if the keyserver has a secret key + * stored for the caller's effective uid; it returns 0 otherwise + * + * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't + * be using it, because it allows them to get the user's secret key. + */ + +int +key_secretkey_is_set(void) +{ + struct key_netstres kres; + + memset((void*)&kres, 0, sizeof (kres)); + if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_key_netstres, &kres) && + (kres.status == KEY_SUCCESS) && + (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { + /* avoid leaving secret key in memory */ + memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); + return (1); + } + return (0); +} + +int +key_encryptsession_pk(remotename, remotekey, deskey) + char *remotename; + netobj *remotekey; + des_block *deskey; +{ + cryptkeyarg2 arg; + cryptkeyres res; + + arg.remotename = remotename; + arg.remotekey = *remotekey; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("encrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_decryptsession_pk(remotename, remotekey, deskey) + char *remotename; + netobj *remotekey; + des_block *deskey; +{ + cryptkeyarg2 arg; + cryptkeyres res; + + arg.remotename = remotename; + arg.remotekey = *remotekey; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("decrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_encryptsession(remotename, deskey) + const char *remotename; + des_block *deskey; +{ + cryptkeyarg arg; + cryptkeyres res; + + arg.remotename = (char *) remotename; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("encrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_decryptsession(remotename, deskey) + const char *remotename; + des_block *deskey; +{ + cryptkeyarg arg; + cryptkeyres res; + + arg.remotename = (char *) remotename; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("decrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +int +key_gendes(key) + des_block *key; +{ + if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_des_block, key)) { + return (-1); + } + return (0); +} + +int +key_setnet(arg) +struct key_netstarg *arg; +{ + keystatus status; + + + if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg, + (xdrproc_t)xdr_keystatus, &status)){ + return (-1); + } + + if (status != KEY_SUCCESS) { + debug("key_setnet status is nonzero"); + return (-1); + } + return (1); +} + + +int +key_get_conv(pkey, deskey) + char *pkey; + des_block *deskey; +{ + cryptkeyres res; + + if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("get_conv status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); +} + +struct key_call_private { + CLIENT *client; /* Client handle */ + pid_t pid; /* process-id at moment of creation */ + uid_t uid; /* user-id at last authorization */ +}; +static struct key_call_private *key_call_private_main = NULL; + +static void +key_call_destroy(void *vp) +{ + struct key_call_private *kcp = (struct key_call_private *)vp; + + if (kcp) { + if (kcp->client) + clnt_destroy(kcp->client); + free(kcp); + } +} + +/* + * Keep the handle cached. This call may be made quite often. + */ +static CLIENT * +getkeyserv_handle(vers) +int vers; +{ + void *localhandle; + struct netconfig *nconf; + struct netconfig *tpconf; + struct key_call_private *kcp = key_call_private_main; + struct timeval wait_time; + struct utsname u; + int fd; + extern thread_key_t key_call_key; + extern mutex_t tsd_lock; + +#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */ +#define TOTAL_TRIES 5 /* Number of tries */ + + if (key_call_key == -1) { + mutex_lock(&tsd_lock); + if (key_call_key == -1) + thr_keycreate(&key_call_key, key_call_destroy); + mutex_unlock(&tsd_lock); + } + kcp = (struct key_call_private *)thr_getspecific(key_call_key); + if (kcp == (struct key_call_private *)NULL) { + kcp = (struct key_call_private *)malloc(sizeof (*kcp)); + if (kcp == (struct key_call_private *)NULL) { + return ((CLIENT *) NULL); + } + thr_setspecific(key_call_key, (void *) kcp); + kcp->client = NULL; + } + + /* if pid has changed, destroy client and rebuild */ + if (kcp->client != NULL && kcp->pid != getpid()) { + clnt_destroy(kcp->client); + kcp->client = NULL; + } + + if (kcp->client != NULL) { + /* if uid has changed, build client handle again */ + if (kcp->uid != geteuid()) { + kcp->uid = geteuid(); + auth_destroy(kcp->client->cl_auth); + kcp->client->cl_auth = + authsys_create("", kcp->uid, 0, 0, NULL); + if (kcp->client->cl_auth == NULL) { + clnt_destroy(kcp->client); + kcp->client = NULL; + return ((CLIENT *) NULL); + } + } + /* Change the version number to the new one */ + clnt_control(kcp->client, CLSET_VERS, (void *)&vers); + return (kcp->client); + } + if (!(localhandle = setnetconfig())) { + return ((CLIENT *) NULL); + } + tpconf = NULL; +#if defined(__FreeBSD__) + if (uname(&u) == -1) +#else +#if defined(i386) + if (uname(&u) == -1) +#elif defined(sparc) + if (uname(&u) == -1) +#else +#error Unknown architecture! +#endif +#endif + { + endnetconfig(localhandle); + return ((CLIENT *) NULL); + } + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + /* + * We use COTS_ORD here so that the caller can + * find out immediately if the server is dead. + */ + if (nconf->nc_semantics == NC_TPI_COTS_ORD) { + kcp->client = clnt_tp_create(u.nodename, + KEY_PROG, vers, nconf); + if (kcp->client) + break; + } else { + tpconf = nconf; + } + } + } + if ((kcp->client == (CLIENT *) NULL) && (tpconf)) + /* Now, try the CLTS or COTS loopback transport */ + kcp->client = clnt_tp_create(u.nodename, + KEY_PROG, vers, tpconf); + endnetconfig(localhandle); + + if (kcp->client == (CLIENT *) NULL) { + return ((CLIENT *) NULL); + } + kcp->uid = geteuid(); + kcp->pid = getpid(); + kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); + if (kcp->client->cl_auth == NULL) { + clnt_destroy(kcp->client); + kcp->client = NULL; + return ((CLIENT *) NULL); + } + + wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; + wait_time.tv_usec = 0; + (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT, + (char *)&wait_time); + if (clnt_control(kcp->client, CLGET_FD, (char *)&fd)) + fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ + + return (kcp->client); +} + +/* returns 0 on failure, 1 on success */ + +static int +key_call(proc, xdr_arg, arg, xdr_rslt, rslt) + u_long proc; + xdrproc_t xdr_arg; + void *arg; + xdrproc_t xdr_rslt; + void *rslt; +{ + CLIENT *clnt; + struct timeval wait_time; + + if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { + cryptkeyres *res; + res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg); + *(cryptkeyres*)rslt = *res; + return (1); + } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { + cryptkeyres *res; + res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg); + *(cryptkeyres*)rslt = *res; + return (1); + } else if (proc == KEY_GEN && __key_gendes_LOCAL) { + des_block *res; + res = (*__key_gendes_LOCAL)(geteuid(), 0); + *(des_block*)rslt = *res; + return (1); + } + + if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || + (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || + (proc == KEY_GET_CONV)) + clnt = getkeyserv_handle(2); /* talk to version 2 */ + else + clnt = getkeyserv_handle(1); /* talk to version 1 */ + + if (clnt == NULL) { + return (0); + } + + wait_time.tv_sec = TOTAL_TIMEOUT; + wait_time.tv_usec = 0; + + if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, + wait_time) == RPC_SUCCESS) { + return (1); + } else { + return (0); + } +} +#endif \ No newline at end of file diff --git a/libtirpc/src/key_prot_xdr.c b/libtirpc/src/key_prot_xdr.c new file mode 100644 index 0000000..985f55b --- /dev/null +++ b/libtirpc/src/key_prot_xdr.c @@ -0,0 +1,173 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _WIN32 +#include +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */ + +//#include + +/* + * Compiled from key_prot.x using rpcgen. + * DO NOT EDIT THIS FILE! + * This is NOT source code! + */ + +bool_t +xdr_keystatus(register XDR *xdrs, keystatus *objp) +{ + + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_keybuf(register XDR *xdrs, keybuf objp) +{ + + if (!xdr_opaque(xdrs, objp, HEXKEYBYTES)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_netnamestr(register XDR *xdrs, netnamestr *objp) +{ + + if (!xdr_string(xdrs, objp, MAXNETNAMELEN)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_cryptkeyarg(register XDR *xdrs, cryptkeyarg *objp) +{ + + if (!xdr_netnamestr(xdrs, &objp->remotename)) + return (FALSE); + if (!xdr_des_block(xdrs, &objp->deskey)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_cryptkeyarg2(register XDR *xdrs, cryptkeyarg2 *objp) +{ + + if (!xdr_netnamestr(xdrs, &objp->remotename)) + return (FALSE); + if (!xdr_netobj(xdrs, &objp->remotekey)) + return (FALSE); + if (!xdr_des_block(xdrs, &objp->deskey)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_cryptkeyres(register XDR *xdrs, cryptkeyres *objp) +{ + + if (!xdr_keystatus(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case KEY_SUCCESS: + if (!xdr_des_block(xdrs, &objp->cryptkeyres_u.deskey)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} + +bool_t +xdr_unixcred(register XDR *xdrs, unixcred *objp) +{ + + if (!xdr_u_int(xdrs, &objp->uid)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->gid)) + return (FALSE); + if (!xdr_array(xdrs, (char **)&objp->gids.gids_val, (u_int *) &objp->gids.gids_len, MAXGIDS, + sizeof (u_int), (xdrproc_t) xdr_u_int)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_getcredres(register XDR *xdrs, getcredres *objp) +{ + + if (!xdr_keystatus(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case KEY_SUCCESS: + if (!xdr_unixcred(xdrs, &objp->getcredres_u.cred)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} + +bool_t +xdr_key_netstarg(register XDR *xdrs, key_netstarg *objp) +{ + + if (!xdr_keybuf(xdrs, objp->st_priv_key)) + return (FALSE); + if (!xdr_keybuf(xdrs, objp->st_pub_key)) + return (FALSE); + if (!xdr_netnamestr(xdrs, &objp->st_netname)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_key_netstres(register XDR *xdrs, key_netstres *objp) +{ + + if (!xdr_keystatus(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case KEY_SUCCESS: + if (!xdr_key_netstarg(xdrs, &objp->key_netstres_u.knet)) + return (FALSE); + break; + default: + break; + } + return (TRUE); +} +#endif \ No newline at end of file diff --git a/libtirpc/src/libtirpc.def b/libtirpc/src/libtirpc.def new file mode 100644 index 0000000..3c58240 --- /dev/null +++ b/libtirpc/src/libtirpc.def @@ -0,0 +1,4 @@ +SECTIONS .TIRPCP READ WRITE SHARED + +EXPORTS + diff --git a/libtirpc/src/makefile b/libtirpc/src/makefile new file mode 100644 index 0000000..66f1c8e --- /dev/null +++ b/libtirpc/src/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def + diff --git a/libtirpc/src/mt_misc.c b/libtirpc/src/mt_misc.c new file mode 100644 index 0000000..58d8522 --- /dev/null +++ b/libtirpc/src/mt_misc.c @@ -0,0 +1,180 @@ +#include + +//#include +//#include +#include +#include +//#include +#include +#include + +/* + * XXX + * For Windows, these must initialized in the DLLMain() function. + * Cannot do static initialization!! + * XXX + */ + +/* protects the services list (svc.c) */ +rwlock_t svc_lock; + +/* protects svc_fdset and the xports[] array */ +rwlock_t svc_fd_lock; + +/* protects the RPCBIND address cache */ +rwlock_t rpcbaddr_cache_lock; + +/* protects authdes cache (svcauth_des.c) */ +mutex_t authdes_lock; + +/* serializes authdes ops initializations */ +mutex_t authdes_ops_lock; + +/* protects des stats list */ +mutex_t svcauthdesstats_lock; + +#ifdef KERBEROS +/* auth_kerb.c serialization */ +mutex_t authkerb_lock = PTHREAD_MUTEX_INITIALIZER; +/* protects kerb stats list */ +mutex_t svcauthkerbstats_lock = PTHREAD_MUTEX_INITIALIZER; +#endif /* KERBEROS */ + +/* auth_none.c serialization */ +mutex_t authnone_lock; + +/* protects the Auths list (svc_auth.c) */ +mutex_t authsvc_lock; + +/* protects client-side fd lock array */ +mutex_t clnt_fd_lock; + +/* clnt_raw.c serialization */ +mutex_t clntraw_lock; + +/* domainname and domain_fd (getdname.c) and default_domain (rpcdname.c) */ +mutex_t dname_lock; + +/* dupreq variables (svc_dg.c) */ +mutex_t dupreq_lock; + +/* protects first_time and hostname (key_call.c) */ +mutex_t keyserv_lock; + +/* serializes rpc_trace() (rpc_trace.c) */ +mutex_t libnsl_trace_lock; + +/* loopnconf (rpcb_clnt.c) */ +mutex_t loopnconf_lock; + +/* serializes ops initializations */ +mutex_t ops_lock; + +/* protects ``port'' static in bindresvport() */ +mutex_t portnum_lock; + +/* protects proglst list (svc_simple.c) */ +mutex_t proglst_lock; + +/* serializes clnt_com_create() (rpc_soc.c) */ +mutex_t rpcsoc_lock; + +/* svc_raw.c serialization */ +mutex_t svcraw_lock; + +/* protects TSD key creation */ +mutex_t tsd_lock; + +/* Library global tsd keys */ +thread_key_t clnt_broadcast_key; +thread_key_t rpc_call_key = -1; +thread_key_t tcp_key = -1; +thread_key_t udp_key = -1; +thread_key_t nc_key = -1; +thread_key_t rce_key = -1; + +/* xprtlist (svc_generic.c) */ +mutex_t xprtlist_lock; + +/* serializes calls to public key routines */ +mutex_t serialize_pkey; + +/* netconfig serialization */ +mutex_t nc_lock; + +#ifdef _WIN32 +/* + * Initialize all the mutexes (CriticalSections) + */ +void multithread_init(void) +{ + InitializeCriticalSection(&authdes_lock); + InitializeCriticalSection(&authdes_ops_lock); + InitializeCriticalSection(&svcauthdesstats_lock); + InitializeCriticalSection(&authnone_lock); + InitializeCriticalSection(&authsvc_lock); + InitializeCriticalSection(&clnt_fd_lock); + InitializeCriticalSection(&clntraw_lock); + InitializeCriticalSection(&dname_lock); + InitializeCriticalSection(&dupreq_lock); + InitializeCriticalSection(&keyserv_lock); + InitializeCriticalSection(&libnsl_trace_lock); + InitializeCriticalSection(&loopnconf_lock); + InitializeCriticalSection(&ops_lock); + InitializeCriticalSection(&portnum_lock); + InitializeCriticalSection(&proglst_lock); + InitializeCriticalSection(&rpcsoc_lock); + InitializeCriticalSection(&svcraw_lock); + InitializeCriticalSection(&tsd_lock); + InitializeCriticalSection(&xprtlist_lock); + InitializeCriticalSection(&serialize_pkey); + InitializeCriticalSection(&nc_lock); +} +#endif + +#undef rpc_createerr + +struct rpc_createerr rpc_createerr; + +struct rpc_createerr * +__rpc_createerr() +{ + struct rpc_createerr *rce_addr; + + mutex_lock(&tsd_lock); + if (rce_key == -1) + rce_key = TlsAlloc(); //thr_keycreate(&rce_key, free); + mutex_unlock(&tsd_lock); + + rce_addr = (struct rpc_createerr *)thr_getspecific(rce_key); + if (!rce_addr) { + rce_addr = (struct rpc_createerr *) + malloc(sizeof (struct rpc_createerr)); + if (!rce_addr || + thr_setspecific(rce_key, (void *) rce_addr) == 0) { + if (rce_addr) + free(rce_addr); + return (&rpc_createerr); + } + memset(rce_addr, 0, sizeof (struct rpc_createerr)); + } + return (rce_addr); +} + +void tsd_key_delete(void) +{ + if (clnt_broadcast_key != -1) + thr_keydelete(clnt_broadcast_key); + if (rpc_call_key != -1) + thr_keydelete(rpc_call_key); + if (tcp_key != -1) + thr_keydelete(tcp_key); + if (udp_key != -1) + thr_keydelete(udp_key); + if (nc_key != -1) + thr_keydelete(nc_key); + if (rce_key != -1) + thr_keydelete(rce_key); + return; +} + diff --git a/libtirpc/src/netname.c b/libtirpc/src/netname.c new file mode 100644 index 0000000..d0588ab --- /dev/null +++ b/libtirpc/src/netname.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * netname utility routines + * convert from unix names to network names and vice-versa + * This module is operating system dependent! + * What we define here will work with any unix system that has adopted + * the sun NIS domain architecture. + */ + +#include +//#include +#include +#include "rpc_com.h" +#ifdef YP +#include +#include +#endif +#include +#include +#include +#include +#include +//#include + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif +#ifndef NGROUPS +#define NGROUPS 16 +#endif + +#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) + +#define TYPE_SIGNED(type) (((type) -1) < 0) + +/* +** 302 / 1000 is log10(2.0) rounded up. +** Subtract one for the sign bit if the type is signed; +** add one for integer division truncation; +** add one more for a minus sign if the type is signed. +*/ +#define INT_STRLEN_MAXIMUM(type) \ + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type)) + +static char *OPSYS = "unix"; + +/* + * Figure out my fully qualified network name + */ +int +getnetname(name) + char name[MAXNETNAMELEN+1]; +{ +#ifdef _WIN32 + /* I don't understand what these underlying routines are accomplishing??? */ + return 1; +#else + uid_t uid; + + uid = geteuid(); + if (uid == 0) { + return (host2netname(name, (char *) NULL, (char *) NULL)); + } else { + return (user2netname(name, uid, (char *) NULL)); + } +#endif +} + +#ifndef _WIN32 +/* + * Convert unix cred to network-name + */ +int +user2netname(netname, uid, domain) + char netname[MAXNETNAMELEN + 1]; + const uid_t uid; + const char *domain; +{ + char *dfltdom; + + if (domain == NULL) { + if (__rpc_get_default_domain(&dfltdom) != 0) { + return (0); + } + domain = dfltdom; + } + if (strlen(domain) + 1 + INT_STRLEN_MAXIMUM(u_long) + 1 + strlen(OPSYS) > MAXNETNAMELEN) { + return (0); + } + (void) sprintf(netname, "%s.%ld@%s", OPSYS, (u_long)uid, domain); + return (1); +} + + +/* + * Convert host to network-name + */ +int +host2netname(netname, host, domain) + char netname[MAXNETNAMELEN + 1]; + const char *host; + const char *domain; +{ + char *dfltdom; + char hostname[MAXHOSTNAMELEN+1]; + + if (domain == NULL) { + if (__rpc_get_default_domain(&dfltdom) != 0) { + return (0); + } + domain = dfltdom; + } + if (host == NULL) { + (void) gethostname(hostname, sizeof(hostname)); + host = hostname; + } + if (strlen(domain) + 1 + strlen(host) + 1 + strlen(OPSYS) > MAXNETNAMELEN) { + return (0); + } + (void) sprintf(netname, "%s.%s@%s", OPSYS, host, domain); + return (1); +} +#endif \ No newline at end of file diff --git a/libtirpc/src/netnamer.c b/libtirpc/src/netnamer.c new file mode 100644 index 0000000..b43f634 --- /dev/null +++ b/libtirpc/src/netnamer.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * netname utility routines convert from unix names to network names and + * vice-versa This module is operating system dependent! What we define here + * will work with any unix system that has adopted the sun NIS domain + * architecture. + */ +#include +#ifndef _WIN32 +#include +#include +#include "rpc_com.h" +#ifdef YP +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +static char *OPSYS = "unix"; +static char *NETID = "netid.byname"; +static char *NETIDFILE = "/etc/netid"; + +static int getnetid( char *, char * ); +static int _getgroups( char *, gid_t * ); + +#ifndef NGROUPS +#define NGROUPS 16 +#endif + +/* + * Convert network-name into unix credential + */ +int +netname2user(netname, uidp, gidp, gidlenp, gidlist) + char netname[MAXNETNAMELEN + 1]; + uid_t *uidp; + gid_t *gidp; + int *gidlenp; + gid_t *gidlist; +{ + char *p; + int gidlen; + uid_t uid; + long luid; + struct passwd *pwd; + char val[1024]; + char *val1, *val2; + char *domain; + int vallen; + int err; + + if (getnetid(netname, val)) { + char *res = val; + + p = strsep(&res, ":"); + if (p == NULL) + return (0); + *uidp = (uid_t) atol(p); + p = strsep(&res, "\n,"); + if (p == NULL) { + return (0); + } + *gidp = (gid_t) atol(p); + gidlen = 0; + for (gidlen = 0; gidlen < NGROUPS; gidlen++) { + p = strsep(&res, "\n,"); + if (p == NULL) + break; + gidlist[gidlen] = (gid_t) atol(p); + } + *gidlenp = gidlen; + + return (1); + } + val1 = strchr(netname, '.'); + if (val1 == NULL) + return (0); + if (strncmp(netname, OPSYS, (val1-netname))) + return (0); + val1++; + val2 = strchr(val1, '@'); + if (val2 == NULL) + return (0); + vallen = val2 - val1; + if (vallen > (1024 - 1)) + vallen = 1024 - 1; + (void) strncpy(val, val1, 1024); + val[vallen] = 0; + + err = __rpc_get_default_domain(&domain); /* change to rpc */ + if (err) + return (0); + + if (strcmp(val2 + 1, domain)) + return (0); /* wrong domain */ + + if (sscanf(val, "%ld", &luid) != 1) + return (0); + uid = luid; + + /* use initgroups method */ + pwd = getpwuid(uid); + if (pwd == NULL) + return (0); + *uidp = pwd->pw_uid; + *gidp = pwd->pw_gid; + *gidlenp = _getgroups(pwd->pw_name, gidlist); + return (1); +} + +/* + * initgroups + */ + +static int +_getgroups(uname, groups) + char *uname; + gid_t groups[NGROUPS]; +{ + gid_t ngroups = 0; + struct group *grp; + int i; + int j; + int filter; + + setgrent(); + while ((grp = getgrent())) { + for (i = 0; grp->gr_mem[i]; i++) + if (!strcmp(grp->gr_mem[i], uname)) { + if (ngroups == NGROUPS) { +#ifdef DEBUG + fprintf(stderr, + "initgroups: %s is in too many groups\n", uname); +#endif + goto toomany; + } + /* filter out duplicate group entries */ + filter = 0; + for (j = 0; j < ngroups; j++) + if (groups[j] == grp->gr_gid) { + filter++; + break; + } + if (!filter) + groups[ngroups++] = grp->gr_gid; + } + } +toomany: + endgrent(); + return (ngroups); +} + +/* + * Convert network-name to hostname + */ +int +netname2host(netname, hostname, hostlen) + char netname[MAXNETNAMELEN + 1]; + char *hostname; + int hostlen; +{ + int err; + char valbuf[1024]; + char *val; + char *val2; + int vallen; + char *domain; + + if (getnetid(netname, valbuf)) { + val = valbuf; + if ((*val == '0') && (val[1] == ':')) { + (void) strncpy(hostname, val + 2, hostlen); + return (1); + } + } + val = strchr(netname, '.'); + if (val == NULL) + return (0); + if (strncmp(netname, OPSYS, (val - netname))) + return (0); + val++; + val2 = strchr(val, '@'); + if (val2 == NULL) + return (0); + vallen = val2 - val; + if (vallen > (hostlen - 1)) + vallen = hostlen - 1; + (void) strncpy(hostname, val, vallen); + hostname[vallen] = 0; + + err = __rpc_get_default_domain(&domain); /* change to rpc */ + if (err) + return (0); + + if (strcmp(val2 + 1, domain)) + return (0); /* wrong domain */ + else + return (1); +} + +/* + * reads the file /etc/netid looking for a + to optionally go to the + * network information service. + */ +int +getnetid(key, ret) + char *key, *ret; +{ + char buf[1024]; /* big enough */ + char *res; + char *mkey; + char *mval; + FILE *fd; +#ifdef YP + char *domain; + int err; + char *lookup; + int len; +#endif + + fd = fopen(NETIDFILE, "r"); + if (fd == NULL) { +#ifdef YP + res = "+"; + goto getnetidyp; +#else + return (0); +#endif + } + for (;;) { + if (fd == NULL) + return (0); /* getnetidyp brings us here */ + res = fgets(buf, sizeof(buf), fd); + if (res == NULL) { + fclose(fd); + return (0); + } + if (res[0] == '#') + continue; + else if (res[0] == '+') { +#ifdef YP + getnetidyp: + err = yp_get_default_domain(&domain); + if (err) { + continue; + } + lookup = NULL; + err = yp_match(domain, NETID, key, + strlen(key), &lookup, &len); + if (err) { +#ifdef DEBUG + fprintf(stderr, "match failed error %d\n", err); +#endif + continue; + } + lookup[len] = 0; + strcpy(ret, lookup); + free(lookup); + if (fd != NULL) + fclose(fd); + return (2); +#else /* YP */ +#ifdef DEBUG + fprintf(stderr, +"Bad record in %s '+' -- NIS not supported in this library copy\n", + NETIDFILE); +#endif + continue; +#endif /* YP */ + } else { + mkey = strsep(&res, "\t "); + if (mkey == NULL) { + fprintf(stderr, + "Bad record in %s -- %s", NETIDFILE, buf); + continue; + } + do { + mval = strsep(&res, " \t#\n"); + } while (mval != NULL && !*mval); + if (mval == NULL) { + fprintf(stderr, + "Bad record in %s val problem - %s", NETIDFILE, buf); + continue; + } + if (strcmp(mkey, key) == 0) { + strcpy(ret, mval); + fclose(fd); + return (1); + + } + } + } +} +#endif /* !_WIN32 */ \ No newline at end of file diff --git a/libtirpc/src/pmap_clnt.c b/libtirpc/src/pmap_clnt.c new file mode 100644 index 0000000..e5ed30b --- /dev/null +++ b/libtirpc/src/pmap_clnt.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * pmap_clnt.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include +#include +//#include + +#include +#include +#include +#include +//#include + +#include +#include + +#include "rpc_com.h" + +bool_t +pmap_set(u_long program, u_long version, int protocol, int port) +{ + bool_t rslt; + struct netbuf *na; + struct netconfig *nconf; + char buf[32]; + + if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) { + return (FALSE); + } + nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp"); + if (nconf == NULL) { + return (FALSE); + } + snprintf(buf, sizeof buf, "0.0.0.0.%d.%d", + (((u_int32_t)port) >> 8) & 0xff, port & 0xff); + na = uaddr2taddr(nconf, buf); + if (na == NULL) { + freenetconfigent(nconf); + return (FALSE); + } + rslt = rpcb_set((rpcprog_t)program, (rpcvers_t)version, nconf, na); + free(na); + freenetconfigent(nconf); + return (rslt); +} + +/* + * Remove the mapping between program, version and port. + * Calls the pmap service remotely to do the un-mapping. + */ +bool_t +pmap_unset(u_long program, u_long version) +{ + struct netconfig *nconf; + bool_t udp_rslt = FALSE; + bool_t tcp_rslt = FALSE; + + nconf = __rpc_getconfip("udp"); + if (nconf != NULL) { + udp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version, + nconf); + freenetconfigent(nconf); + } + nconf = __rpc_getconfip("tcp"); + if (nconf != NULL) { + tcp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version, + nconf); + freenetconfigent(nconf); + } + /* + * XXX: The call may still succeed even if only one of the + * calls succeeded. This was the best that could be + * done for backward compatibility. + */ + return (tcp_rslt || udp_rslt); +} diff --git a/libtirpc/src/pmap_getmaps.c b/libtirpc/src/pmap_getmaps.c new file mode 100644 index 0000000..c6ad2bb --- /dev/null +++ b/libtirpc/src/pmap_getmaps.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * pmap_getmap.c + * Client interface to pmap rpc service. + * contains pmap_getmaps, which is only tcp service involved + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include +//#include +//#include + +//#include +//#include + +#include +#include +//#include +#include +//#include + +#include +#include +#include +//#include +#define NAMELEN 255 +#define MAX_BROADCAST_SIZE 1400 + +/* + * Get a copy of the current port maps. + * Calls the pmap service remotely to do get the maps. + */ +struct pmaplist * +pmap_getmaps(address) + struct sockaddr_in *address; +{ + struct pmaplist *head = NULL; + SOCKET sock = INVALID_SOCKET; + struct timeval minutetimeout; + CLIENT *client; + + assert(address != NULL); + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + address->sin_port = htons(PMAPPORT); + client = clnttcp_create(address, PMAPPROG, + PMAPVERS, &sock, 50, 500); + if (client != NULL) { + if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_DUMP, + (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_pmaplist, &head, minutetimeout) != + RPC_SUCCESS) { + clnt_perror(client, "pmap_getmaps rpc problem"); + } + CLNT_DESTROY(client); + } + address->sin_port = 0; + return (head); +} \ No newline at end of file diff --git a/libtirpc/src/pmap_getport.c b/libtirpc/src/pmap_getport.c new file mode 100644 index 0000000..45c8b1c --- /dev/null +++ b/libtirpc/src/pmap_getport.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +//#include + +//#include +//#include + +#include +//#include + +#include +#include +#include + +static const struct timeval timeout = { 5, 0 }; +static const struct timeval tottimeout = { 60, 0 }; + +#ifdef _WIN32 +/* + * pmap_getport.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +u_short +pmap_getport(address, program, version, protocol) + struct sockaddr_in *address; + u_long program; + u_long version; + u_int protocol; +{ + return (u_short)2049; +} +#else +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +u_short +pmap_getport(address, program, version, protocol) + struct sockaddr_in *address; + u_long program; + u_long version; + u_int protocol; +{ + u_short port = 0; + int sock = -1; + CLIENT *client; + struct pmap parms; + + assert(address != NULL); + + address->sin_port = htons(PMAPPORT); + client = clntudp_bufcreate(address, PMAPPROG, + PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client != NULL) { + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_prot = protocol; + parms.pm_port = 0; /* not needed or used */ + if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, + (xdrproc_t)xdr_pmap, + &parms, (xdrproc_t)xdr_u_short, &port, tottimeout) != + RPC_SUCCESS){ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + } else if (port == 0) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + } + CLNT_DESTROY(client); + } + address->sin_port = 0; + return (port); +} +#endif /* ! _WIN32 */ \ No newline at end of file diff --git a/libtirpc/src/pmap_prot.c b/libtirpc/src/pmap_prot.c new file mode 100644 index 0000000..2f5644d --- /dev/null +++ b/libtirpc/src/pmap_prot.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * pmap_prot.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include + +#include +#include +#include + + +bool_t +xdr_pmap(xdrs, regs) + XDR *xdrs; + struct pmap *regs; +{ + + assert(xdrs != NULL); + assert(regs != NULL); + + if (xdr_u_long(xdrs, ®s->pm_prog) && + xdr_u_long(xdrs, ®s->pm_vers) && + xdr_u_long(xdrs, ®s->pm_prot)) + return (xdr_u_long(xdrs, ®s->pm_port)); + return (FALSE); +} \ No newline at end of file diff --git a/libtirpc/src/pmap_prot2.c b/libtirpc/src/pmap_prot2.c new file mode 100644 index 0000000..beed4a2 --- /dev/null +++ b/libtirpc/src/pmap_prot2.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * pmap_prot2.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include + +#include +#include +#include + + +/* + * What is going on with linked lists? (!) + * First recall the link list declaration from pmap_prot.h: + * + * struct pmaplist { + * struct pmap pml_map; + * struct pmaplist *pml_map; + * }; + * + * Compare that declaration with a corresponding xdr declaration that + * is (a) pointer-less, and (b) recursive: + * + * typedef union switch (bool_t) { + * + * case TRUE: struct { + * struct pmap; + * pmaplist_t foo; + * }; + * + * case FALSE: struct {}; + * } pmaplist_t; + * + * Notice that the xdr declaration has no nxt pointer while + * the C declaration has no bool_t variable. The bool_t can be + * interpreted as ``more data follows me''; if FALSE then nothing + * follows this bool_t; if TRUE then the bool_t is followed by + * an actual struct pmap, and then (recursively) by the + * xdr union, pamplist_t. + * + * This could be implemented via the xdr_union primitive, though this + * would cause a one recursive call per element in the list. Rather than do + * that we can ``unwind'' the recursion + * into a while loop and do the union arms in-place. + * + * The head of the list is what the C programmer wishes to past around + * the net, yet is the data that the pointer points to which is interesting; + * this sounds like a job for xdr_reference! + */ +bool_t +xdr_pmaplist(xdrs, rp) + XDR *xdrs; + struct pmaplist **rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing; + struct pmaplist **next = NULL; /* pacify gcc */ + + assert(xdrs != NULL); + assert(rp != NULL); + + freeing = (xdrs->x_op == XDR_FREE); + + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) + return (FALSE); + if (! more_elements) + return (TRUE); /* we are done */ + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = &((*rp)->pml_next); + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof(struct pmaplist), (xdrproc_t)xdr_pmap)) + return (FALSE); + rp = (freeing) ? next : &((*rp)->pml_next); + } +} + + +/* + * xdr_pmaplist_ptr() is specified to take a PMAPLIST *, but is identical in + * functionality to xdr_pmaplist(). + */ +bool_t +xdr_pmaplist_ptr(xdrs, rp) + XDR *xdrs; + struct pmaplist *rp; +{ + return xdr_pmaplist(xdrs, (struct pmaplist **)(void *)rp); +} diff --git a/libtirpc/src/pmap_rmt.c b/libtirpc/src/pmap_rmt.c new file mode 100644 index 0000000..89b5466 --- /dev/null +++ b/libtirpc/src/pmap_rmt.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * pmap_rmt.c + * Client interface to pmap rpc service. + * remote call and broadcast service + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include +//#include +//#include +//#include + +//#include +//#include +//#include + +#include +//#include +#include +#include +#include +//#include + +#include +#include +#include +#include + +// For the clnttcp_create function +//#include + + +static const struct timeval timeout = { 3, 0 }; + +/* + * pmapper remote-call-service interface. + * This routine is used to call the pmapper remote call service + * which will look up a service program in the port maps, and then + * remotely call that routine with the given parameters. This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, + port_ptr) + struct sockaddr_in *addr; + u_long prog, vers, proc; + xdrproc_t xdrargs, xdrres; + caddr_t argsp, resp; + struct timeval tout; + u_long *port_ptr; +{ + int sock = -1; + CLIENT *client; + struct rmtcallargs a; + struct rmtcallres r; + enum clnt_stat stat; + + assert(addr != NULL); + assert(port_ptr != NULL); + + addr->sin_port = htons(PMAPPORT); + client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock); + if (client != NULL) { + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.args_ptr = argsp; + a.xdr_args = xdrargs; + r.port_ptr = port_ptr; + r.results_ptr = resp; + r.xdr_results = xdrres; + stat = CLNT_CALL(client, (rpcproc_t)PMAPPROC_CALLIT, + (xdrproc_t)xdr_rmtcall_args, &a, (xdrproc_t)xdr_rmtcallres, + &r, tout); + CLNT_DESTROY(client); + } else { + stat = RPC_FAILED; + } + addr->sin_port = 0; + return (stat); +} + + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rmtcall_args(xdrs, cap) + XDR *xdrs; + struct rmtcallargs *cap; +{ + u_int lenposition, argposition, position; + + assert(xdrs != NULL); + assert(cap != NULL); + + if (xdr_u_long(xdrs, &(cap->prog)) && + xdr_u_long(xdrs, &(cap->vers)) && + xdr_u_long(xdrs, &(cap->proc))) { + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_long(xdrs, &(cap->arglen))) + return (FALSE); + argposition = XDR_GETPOS(xdrs); + if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) + return (FALSE); + position = XDR_GETPOS(xdrs); + cap->arglen = (u_long)position - (u_long)argposition; + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_long(xdrs, &(cap->arglen))) + return (FALSE); + XDR_SETPOS(xdrs, position); + return (TRUE); + } + return (FALSE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rmtcallres(xdrs, crp) + XDR *xdrs; + struct rmtcallres *crp; +{ + caddr_t port_ptr; + + assert(xdrs != NULL); + assert(crp != NULL); + + port_ptr = (caddr_t)(void *)crp->port_ptr; + if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), + (xdrproc_t)xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { + crp->port_ptr = (u_long *)(void *)port_ptr; + return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); + } + return (FALSE); +} diff --git a/libtirpc/src/rpc_callmsg.c b/libtirpc/src/rpc_callmsg.c new file mode 100644 index 0000000..48d34cd --- /dev/null +++ b/libtirpc/src/rpc_callmsg.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_callmsg.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ + +#include +#include +#include +#include + +#include +#include + +//#include + +/* + * XDR a call message + */ +bool_t +xdr_callmsg(xdrs, cmsg) + XDR *xdrs; + struct rpc_msg *cmsg; +{ + int32_t *buf; + struct opaque_auth *oa; + + assert(xdrs != NULL); + assert(cmsg != NULL); + + if (xdrs->x_op == XDR_ENCODE) { + if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_cred.oa_length) + + 2 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_verf.oa_length)); + if (buf != NULL) { + IXDR_PUT_INT32(buf, cmsg->rm_xid); + IXDR_PUT_ENUM(buf, cmsg->rm_direction); + if (cmsg->rm_direction != CALL) { + return (FALSE); + } + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers); + if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { + return (FALSE); + } + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog); + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers); + IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc); + oa = &cmsg->rm_call.cb_cred; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_INT32(buf, oa->oa_length); + if (oa->oa_length) { + memmove(buf, oa->oa_base, oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof (int32_t); + } + oa = &cmsg->rm_call.cb_verf; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_INT32(buf, oa->oa_length); + if (oa->oa_length) { + memmove(buf, oa->oa_base, oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / sizeof (int32_t); + */ + } + return (TRUE); + } + } + if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT); + if (buf != NULL) { + cmsg->rm_xid = IXDR_GET_U_INT32(buf); + cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type); + if (cmsg->rm_direction != CALL) { + return (FALSE); + } + cmsg->rm_call.cb_rpcvers = IXDR_GET_U_INT32(buf); + if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { + return (FALSE); + } + cmsg->rm_call.cb_prog = IXDR_GET_U_INT32(buf); + cmsg->rm_call.cb_vers = IXDR_GET_U_INT32(buf); + cmsg->rm_call.cb_proc = IXDR_GET_U_INT32(buf); + oa = &cmsg->rm_call.cb_cred; + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); + if (oa->oa_length) { + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); + } + buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, buf, + oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / + sizeof (int32_t); + */ + } + } + oa = &cmsg->rm_call.cb_verf; + buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE || + xdr_u_int(xdrs, &oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = (u_int)IXDR_GET_U_INT32(buf); + } + if (oa->oa_length) { + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + if (oa->oa_base == NULL) + return (FALSE); + } + buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, buf, + oa->oa_length); + /* no real need... + buf += RNDUP(oa->oa_length) / + sizeof (int32_t); + */ + } + } + return (TRUE); + } + } + if ( + xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && + (cmsg->rm_direction == CALL) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_proc)) && + xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) ) + return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); + return (FALSE); +} diff --git a/libtirpc/src/rpc_com.h b/libtirpc/src/rpc_com.h new file mode 100644 index 0000000..9a7fff0 --- /dev/null +++ b/libtirpc/src/rpc_com.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpc_com.h, Common definitions for both the server and client side. + * All for the topmost layer of rpc + * + * In Sun's tirpc distribution, this was installed as , + * but as it contains only non-exported interfaces, it was moved here. + */ + +#ifndef _TIRPC_RPCCOM_H +#define _TIRPC_RPCCOM_H + +//#include + +/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ + +/* + * The max size of the transport, if the size cannot be determined + * by other means. + */ +#define RPC_MAXDATASIZE 9000 +#define RPC_MAXADDRSIZE 1024 + +//#ifdef _WIN32 +// #define __RPC_GETXID(now) ((u_int32_t)_getpid() ^ (u_int32_t)(now)->tv_sec ^ \ +// (u_int32_t)(now)->tv_usec) +//#else + #define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \ + (u_int32_t)(now)->tv_usec) +//#endif + +__BEGIN_DECLS +extern u_int __rpc_get_a_size(int); +extern int __rpc_dtbsize(void); +extern struct netconfig * __rpcgettp(SOCKET); +extern int __rpc_get_default_domain(char **); +struct netbuf *__rpc_set_netbuf(struct netbuf *, const void *, size_t); + +char *__rpc_taddr2uaddr_af(int, const struct netbuf *); +struct netbuf *__rpc_uaddr2taddr_af(int, const char *); +int __rpc_fixup_addr(struct netbuf *, const struct netbuf *); +int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **); +int __rpc_seman2socktype(int); +int __rpc_socktype2seman(int); +void *rpc_nullproc(CLIENT *); +int __rpc_sockisbound(SOCKET); + +struct netbuf *__rpcb_findaddr(rpcprog_t, rpcvers_t, const struct netconfig *, + const char *, CLIENT **); +struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t, + const struct netconfig *, const char *host, CLIENT **clpp, + struct timeval *tp); + +bool_t __rpc_control(int,void *); + +char *_get_next_token(char *, int); + +bool_t __svc_clean_idle(fd_set *, int, bool_t); +bool_t __xdrrec_setnonblock(XDR *, int); +bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t); +void __xprt_unregister_unlocked(SVCXPRT *); +void __xprt_set_raddr(SVCXPRT *, const struct sockaddr_storage *); + + +SVCXPRT **__svc_xports; +int __svc_maxrec; + +__END_DECLS + +#endif /* _TIRPC_RPCCOM_H */ diff --git a/libtirpc/src/rpc_commondata.c b/libtirpc/src/rpc_commondata.c new file mode 100644 index 0000000..ec8d3fb --- /dev/null +++ b/libtirpc/src/rpc_commondata.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + + +/* + * This file should only contain common data (global data) that is exported + * by public interfaces + */ +struct opaque_auth _null_auth; +fd_set svc_fdset; +int svc_maxfd = -1; diff --git a/libtirpc/src/rpc_dtablesize.c b/libtirpc/src/rpc_dtablesize.c new file mode 100644 index 0000000..0541f58 --- /dev/null +++ b/libtirpc/src/rpc_dtablesize.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +//#include + +//#include + +int _rpc_dtablesize(void); /* XXX */ + +/* + * Cache the result of getdtablesize(), so we don't have to do an + * expensive system call every time. + */ +/* + * XXX In FreeBSD 2.x, you can have the maximum number of open file + * descriptors be greater than FD_SETSIZE (which is 256 by default). + * + * Since old programs tend to use this call to determine the first arg + * for _select(), having this return > FD_SETSIZE is a Bad Idea(TM)! + */ +int +_rpc_dtablesize(void) +{ +#ifdef _WIN32 + return FD_SETSIZE; +#else + static int size; + + if (size == 0) { + size = getdtablesize(); + if (size > FD_SETSIZE) + size = FD_SETSIZE; + } + return (size); +#endif +} diff --git a/libtirpc/src/rpc_generic.c b/libtirpc/src/rpc_generic.c new file mode 100644 index 0000000..bcf4d42 --- /dev/null +++ b/libtirpc/src/rpc_generic.c @@ -0,0 +1,920 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +//#include + +/* + * rpc_generic.c, Miscl routines for RPC. + * + */ +#include +//#include +#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +//#include +//#include +#include +//#include +#include +#include +#include +//#include +#include +#include "rpc_com.h" + +struct handle { + NCONF_HANDLE *nhandle; + int nflag; /* Whether NETPATH or NETCONFIG */ + int nettype; +}; + +static const struct _rpcnettype { + const char *name; + const int type; +} _rpctypelist[] = { + { "netpath", _RPC_NETPATH }, + { "visible", _RPC_VISIBLE }, + { "circuit_v", _RPC_CIRCUIT_V }, + { "datagram_v", _RPC_DATAGRAM_V }, + { "circuit_n", _RPC_CIRCUIT_N }, + { "datagram_n", _RPC_DATAGRAM_N }, + { "tcp", _RPC_TCP }, + { "udp", _RPC_UDP }, + { 0, _RPC_NONE } +}; + +struct netid_af { + const char *netid; + ADDRESS_FAMILY af; + int protocol; +}; + +static const struct netid_af na_cvt[] = { + { "udp", AF_INET, IPPROTO_UDP }, + { "tcp", AF_INET, IPPROTO_TCP }, +#ifdef INET6 + { "udp6", AF_INET6, IPPROTO_UDP }, + { "tcp6", AF_INET6, IPPROTO_TCP }, +#endif +#ifdef AF_LOCAL + { "local", AF_LOCAL, 0 } +#endif +}; + +#if 0 +static char *strlocase(char *); +#endif +static int getnettype(const char *); + +/* + * Cache the result of getrlimit(), so we don't have to do an + * expensive call every time. + */ +int +__rpc_dtbsize() +{ +#ifdef _WIN32 + return (WINSOCK_HANDLE_HASH_SIZE); +#else + + static int tbsize; + struct rlimit rl; + + if (tbsize) { + return (tbsize); + } + if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { + return (tbsize = (int)rl.rlim_max); + } + /* + * Something wrong. I'll try to save face by returning a + * pessimistic number. + */ + return (32); +#endif +} + + +/* + * Find the appropriate buffer size + */ +u_int +/*ARGSUSED*/ +__rpc_get_t_size(af, proto, size) + int af, proto; + int size; /* Size requested */ +{ + int maxsize, defsize; + + maxsize = 256 * 1024; /* XXX */ + switch (proto) { + case IPPROTO_TCP: + defsize = 1024 * 1024; /* XXX */ + break; + case IPPROTO_UDP: + defsize = UDPMSGSIZE; + break; + default: + defsize = RPC_MAXDATASIZE; + break; + } + if (size == 0) + return defsize; +#if 1 + /* cbodley- give us the size we ask for, or we'll get fragmented! */ + return (u_int)size; +#else + /* Check whether the value is within the upper max limit */ + return (size > maxsize ? (u_int)maxsize : (u_int)size); +#endif +} + +/* + * Find the appropriate address buffer size + */ +u_int +__rpc_get_a_size(af) + int af; +{ + switch (af) { + case AF_INET: + return sizeof (struct sockaddr_in); +#ifdef INET6 + case AF_INET6: + return sizeof (struct sockaddr_in6); +#endif +#ifdef AF_LOCAL + case AF_LOCAL: + return sizeof (struct sockaddr_un); +#endif + default: + break; + } + return ((u_int)RPC_MAXADDRSIZE); +} + +#if 0 +static char * +strlocase(p) + char *p; +{ + char *t = p; + + for (; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + return (t); +} +#endif + +/* + * Returns the type of the network as defined in + * If nettype is NULL, it defaults to NETPATH. + */ +static int +getnettype(nettype) + const char *nettype; +{ + int i; + + if ((nettype == NULL) || (nettype[0] == 0)) { + return (_RPC_NETPATH); /* Default */ + } + +#if 0 + nettype = strlocase(nettype); +#endif + for (i = 0; _rpctypelist[i].name; i++) + if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { + return (_rpctypelist[i].type); + } + return (_rpctypelist[i].type); +} + +/* + * For the given nettype (tcp or udp only), return the first structure found. + * This should be freed by calling freenetconfigent() + */ +struct netconfig * +__rpc_getconfip(nettype) + const char *nettype; +{ + char *netid; + char *netid_tcp = (char *) NULL; + char *netid_udp = (char *) NULL; + struct netconfig *dummy; + extern thread_key_t tcp_key, udp_key; + extern mutex_t tsd_lock; + + if (tcp_key == -1) { + mutex_lock(&tsd_lock); + if (tcp_key == -1) + tcp_key = TlsAlloc(); //thr_keycreate(&tcp_key, free); + mutex_unlock(&tsd_lock); + } + netid_tcp = (char *)thr_getspecific(tcp_key); + if (udp_key == -1) { + mutex_lock(&tsd_lock); + if (udp_key == -1) + udp_key = TlsAlloc(); //thr_keycreate(&udp_key, free); + mutex_unlock(&tsd_lock); + } + netid_udp = (char *)thr_getspecific(udp_key); + if (!netid_udp && !netid_tcp) { + struct netconfig *nconf; + void *confighandle; + + if (!(confighandle = setnetconfig())) { + //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + return (NULL); + } + while ((nconf = getnetconfig(confighandle)) != NULL) { + if (strcmp(nconf->nc_protofmly, NC_INET) == 0 || + strcmp(nconf->nc_protofmly, NC_INET6) == 0) { + if (strcmp(nconf->nc_proto, NC_TCP) == 0 && + netid_tcp == NULL) { + netid_tcp = strdup(nconf->nc_netid); + thr_setspecific(tcp_key, + (void *) netid_tcp); + } else + if (strcmp(nconf->nc_proto, NC_UDP) == 0 && + netid_udp == NULL) { + netid_udp = strdup(nconf->nc_netid); + thr_setspecific(udp_key, + (void *) netid_udp); + } + } + } + endnetconfig(confighandle); + } + if (strcmp(nettype, "udp") == 0) + netid = netid_udp; + else if (strcmp(nettype, "tcp") == 0) + netid = netid_tcp; + else { + return (NULL); + } + if ((netid == NULL) || (netid[0] == 0)) { + return (NULL); + } + dummy = getnetconfigent(netid); + return (dummy); +} + +/* + * Returns the type of the nettype, which should then be used with + * __rpc_getconf(). + */ +void * +__rpc_setconf(nettype) + const char *nettype; +{ + struct handle *handle; + + handle = (struct handle *) malloc(sizeof (struct handle)); + if (handle == NULL) { + return (NULL); + } + switch (handle->nettype = getnettype(nettype)) { + case _RPC_NETPATH: + case _RPC_CIRCUIT_N: + case _RPC_DATAGRAM_N: + if (!(handle->nhandle = setnetpath())) { + free(handle); + return (NULL); + } + handle->nflag = TRUE; + break; + case _RPC_VISIBLE: + case _RPC_CIRCUIT_V: + case _RPC_DATAGRAM_V: + case _RPC_TCP: + case _RPC_UDP: + if (!(handle->nhandle = setnetconfig())) { + //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + free(handle); + return (NULL); + } + handle->nflag = FALSE; + break; + default: + return (NULL); + } + + return (handle); +} + +/* + * Returns the next netconfig struct for the given "net" type. + * __rpc_setconf() should have been called previously. + */ +struct netconfig * +__rpc_getconf(vhandle) + void *vhandle; +{ + struct handle *handle; + struct netconfig *nconf; + + handle = (struct handle *)vhandle; + if (handle == NULL) { + return (NULL); + } + for (;;) { + if (handle->nflag) + nconf = getnetpath(handle->nhandle); + else + nconf = getnetconfig(handle->nhandle); + if (nconf == NULL) + break; + if ((nconf->nc_semantics != NC_TPI_CLTS) && + (nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + switch (handle->nettype) { + case _RPC_VISIBLE: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_NETPATH: /* Be happy */ + break; + case _RPC_CIRCUIT_V: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_CIRCUIT_N: + if ((nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) + continue; + break; + case _RPC_DATAGRAM_V: + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + /* FALLTHROUGH */ + case _RPC_DATAGRAM_N: + if (nconf->nc_semantics != NC_TPI_CLTS) + continue; + break; + case _RPC_TCP: + if (((nconf->nc_semantics != NC_TPI_COTS) && + (nconf->nc_semantics != NC_TPI_COTS_ORD)) || + (strcmp(nconf->nc_protofmly, NC_INET) +#ifdef INET6 + && strcmp(nconf->nc_protofmly, NC_INET6)) +#else + ) +#endif + || + strcmp(nconf->nc_proto, NC_TCP)) + continue; + break; + case _RPC_UDP: + if ((nconf->nc_semantics != NC_TPI_CLTS) || + (strcmp(nconf->nc_protofmly, NC_INET) +#ifdef INET6 + && strcmp(nconf->nc_protofmly, NC_INET6)) +#else + ) +#endif + || + strcmp(nconf->nc_proto, NC_UDP)) + continue; + break; + } + break; + } + return (nconf); +} + +void +__rpc_endconf(vhandle) + void * vhandle; +{ + struct handle *handle; + + handle = (struct handle *) vhandle; + if (handle == NULL) { + return; + } + if (handle->nflag) { + endnetpath(handle->nhandle); + } else { + endnetconfig(handle->nhandle); + } + free(handle); +} + +/* + * Used to ping the NULL procedure for clnt handle. + * Returns NULL if fails, else a non-NULL pointer. + */ +void * +rpc_nullproc(clnt) + CLIENT *clnt; +{ + struct timeval TIMEOUT = {25, 0}; + + if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *) clnt); +} + +/* + * Try all possible transports until + * one succeeds in finding the netconf for the given fd. + */ +struct netconfig * +__rpcgettp(fd) + SOCKET fd; +{ + const char *netid; + struct __rpc_sockinfo si; + + if (!__rpc_fd2sockinfo(fd, &si)) + return NULL; + + if (!__rpc_sockinfo2netid(&si, &netid)) + return NULL; + + /*LINTED const castaway*/ + return getnetconfigent((char *)netid); +} + +int +__rpc_fd2sockinfo(SOCKET fd, struct __rpc_sockinfo *sip) +{ + socklen_t len; + int type, proto; + struct sockaddr_storage ss; + +#ifdef _WIN32 + WSAPROTOCOL_INFO proto_info; + int proto_info_size = sizeof(proto_info); + if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL_INFO, (char *)&proto_info, &proto_info_size) == SOCKET_ERROR) { + int err = WSAGetLastError(); + return 0; + } + len = proto_info.iMaxSockAddr; + ss.ss_family = (ADDRESS_FAMILY)proto_info.iAddressFamily; +#else + len = sizeof ss; + if (getsockname(fd, (struct sockaddr *)&ss, &len) == SOCKET_ERROR) { + return 0; + } +#endif + sip->si_alen = len; + + len = sizeof type; + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&type, &len) == SOCKET_ERROR) { + int err = WSAGetLastError(); + return 0; + } + + /* XXX */ +#ifdef AF_LOCAL + if (ss.ss_family != AF_LOCAL) { +#endif + if (type == SOCK_STREAM) + proto = IPPROTO_TCP; + else if (type == SOCK_DGRAM) + proto = IPPROTO_UDP; + else + return 0; +#ifdef AF_LOCAL + } else + proto = 0; +#endif + + sip->si_af = ss.ss_family; + sip->si_proto = proto; + sip->si_socktype = type; + + return 1; +} + +/* + * Linear search, but the number of entries is small. + */ +int +__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) +{ + int i; + + for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) + if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( + strcmp(nconf->nc_netid, "unix") == 0 && + strcmp(na_cvt[i].netid, "local") == 0)) { + sip->si_af = na_cvt[i].af; + sip->si_proto = na_cvt[i].protocol; + sip->si_socktype = + __rpc_seman2socktype((int)nconf->nc_semantics); + if (sip->si_socktype == -1) + return 0; + sip->si_alen = __rpc_get_a_size(sip->si_af); + return 1; + } + + return 0; +} + +SOCKET +__rpc_nconf2fd(const struct netconfig *nconf) +{ + struct __rpc_sockinfo si; + SOCKET fd; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return 0; + + if ((fd = socket(si.si_af, si.si_socktype, si.si_proto)) != INVALID_SOCKET && + si.si_af == AF_INET6) { + int val = 1; + + setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (const char *)&val, sizeof(val)); + } + return fd; +} + +int +__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) +{ + int i; + struct netconfig *nconf; + + nconf = getnetconfigent("local"); + + for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) { + if (na_cvt[i].af == sip->si_af && + na_cvt[i].protocol == sip->si_proto) { + if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) { + if (netid) + *netid = "unix"; + } else { + if (netid) + *netid = na_cvt[i].netid; + } + if (nconf != NULL) + freenetconfigent(nconf); + return 1; + } + } + if (nconf != NULL) + freenetconfigent(nconf); + + return 0; +} + +char * +taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) +{ + struct __rpc_sockinfo si; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return NULL; + return __rpc_taddr2uaddr_af(si.si_af, nbuf); +} + +struct netbuf * +uaddr2taddr(const struct netconfig *nconf, const char *uaddr) +{ + struct __rpc_sockinfo si; + + if (!__rpc_nconf2sockinfo(nconf, &si)) + return NULL; + return __rpc_uaddr2taddr_af(si.si_af, uaddr); +} + +void freeuaddr(char *uaddr) +{ + free(uaddr); +} + +void freenetbuf(struct netbuf *nbuf) +{ + if (nbuf) { + free(nbuf->buf); + free(nbuf); + } +} + +char * +__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) +{ + char *ret; + struct sockaddr_in *sin; +#ifdef AF_LOCAL + struct sockaddr_un *sun; +#endif + char namebuf[INET_ADDRSTRLEN]; +#ifdef INET6 + struct sockaddr_in6 *sin6; + char namebuf6[INET6_ADDRSTRLEN]; +#endif + u_int16_t port; + + if (nbuf->len <= 0) + return NULL; + + switch (af) { + case AF_INET: + sin = nbuf->buf; + if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) + == NULL) + return NULL; + port = ntohs(sin->sin_port); + if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, + port & 0xff) < 0) + return NULL; + break; +#ifdef INET6 + case AF_INET6: + sin6 = nbuf->buf; + if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) + == NULL) + return NULL; + port = ntohs(sin6->sin6_port); + if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, + port & 0xff) < 0) + return NULL; + break; +#endif +#ifdef AF_LOCAL + case AF_LOCAL: + sun = nbuf->buf; + /* if (asprintf(&ret, "%.*s", (int)(sun->sun_len - + offsetof(struct sockaddr_un, sun_path)), + sun->sun_path) < 0)*/ + if (asprintf(&ret, "%.*s", (int)(sizeof(*sun) - + offsetof(struct sockaddr_un, sun_path)), + sun->sun_path) < 0) + + return (NULL); + break; +#endif + default: + return NULL; + } + + return ret; +} + +struct netbuf * +__rpc_uaddr2taddr_af(int af, const char *uaddr) +{ + struct netbuf *ret = NULL; + char *addrstr, *p; + unsigned short port, portlo, porthi; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif +#ifdef AF_LOCAL + struct sockaddr_un *sun; +#endif + + port = 0; + sin = NULL; + addrstr = strdup(uaddr); + if (addrstr == NULL) + return NULL; + + /* + * AF_LOCAL addresses are expected to be absolute + * pathnames, anything else will be AF_INET or AF_INET6. + */ + if (*addrstr != '/') { + p = strrchr(addrstr, '.'); + if (p == NULL) + goto out; + portlo = (unsigned)atoi(p + 1); + *p = '\0'; + + p = strrchr(addrstr, '.'); + if (p == NULL) + goto out; + porthi = (unsigned)atoi(p + 1); + *p = '\0'; + port = (porthi << 8) | portlo; + } + + ret = (struct netbuf *)malloc(sizeof *ret); + if (ret == NULL) + goto out; + + switch (af) { + case AF_INET: + sin = (struct sockaddr_in *)malloc(sizeof *sin); + if (sin == NULL) + goto out; + memset(sin, 0, sizeof *sin); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { + free(sin); + free(ret); + ret = NULL; + goto out; + } + ret->maxlen = ret->len = sizeof *sin; + ret->buf = sin; + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); + if (sin6 == NULL) + goto out; + memset(sin6, 0, sizeof *sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { + free(sin6); + free(ret); + ret = NULL; + goto out; + } + ret->maxlen = ret->len = sizeof *sin6; + ret->buf = sin6; + break; +#endif +#ifdef AF_LOCAL + case AF_LOCAL: + sun = (struct sockaddr_un *)malloc(sizeof *sun); + if (sun == NULL) + goto out; + memset(sun, 0, sizeof *sun); + sun->sun_family = AF_LOCAL; + strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); + ret->len = SUN_LEN(sun); + ret->maxlen = sizeof(struct sockaddr_un); + ret->buf = sun; + break; +#endif + default: + break; + } +out: + free(addrstr); + return ret; +} + +int +__rpc_seman2socktype(int semantics) +{ + switch (semantics) { + case NC_TPI_CLTS: + return SOCK_DGRAM; + case NC_TPI_COTS_ORD: + return SOCK_STREAM; + case NC_TPI_RAW: + return SOCK_RAW; + default: + break; + } + + return -1; +} + +int +__rpc_socktype2seman(int socktype) +{ + switch (socktype) { + case SOCK_DGRAM: + return NC_TPI_CLTS; + case SOCK_STREAM: + return NC_TPI_COTS_ORD; + case SOCK_RAW: + return NC_TPI_RAW; + default: + break; + } + + return -1; +} + +/* + * XXXX - IPv6 scope IDs can't be handled in universal addresses. + * Here, we compare the original server address to that of the RPC + * service we just received back from a call to rpcbind on the remote + * machine. If they are both "link local" or "site local", copy + * the scope id of the server address over to the service address. + */ +int +__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) +{ +#ifdef INET6 + struct sockaddr *sa_new, *sa_svc; + struct sockaddr_in6 *sin6_new, *sin6_svc; + + sa_svc = (struct sockaddr *)svc->buf; + sa_new = (struct sockaddr *)new->buf; + + if (sa_new->sa_family == sa_svc->sa_family && + sa_new->sa_family == AF_INET6) { + sin6_new = (struct sockaddr_in6 *)new->buf; + sin6_svc = (struct sockaddr_in6 *)svc->buf; + + if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && + IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || + (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && + IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { + sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; + } + } +#endif + return 1; +} + +int +__rpc_sockisbound(SOCKET fd) +{ + struct sockaddr_storage ss; + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +#ifdef AF_LOCAL + struct sockaddr_un usin; +#endif + } u_addr; + socklen_t slen; + + slen = sizeof (struct sockaddr_storage); + if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR) + return 0; + + switch (ss.ss_family) { + case AF_INET: + memcpy(&u_addr.sin, &ss, sizeof(u_addr.sin)); + return (u_addr.sin.sin_port != 0); +#ifdef INET6 + case AF_INET6: + memcpy(&u_addr.sin6, &ss, sizeof(u_addr.sin6)); + return (u_addr.sin6.sin6_port != 0); +#endif +#ifdef AF_LOCAL + case AF_LOCAL: + /* XXX check this */ + memcpy(&u_addr.usin, &ss, sizeof(u_addr.usin)); + return (u_addr.usin.sun_path[0] != 0); +#endif + default: + break; + } + + return 0; +} + +/* + * Helper function to set up a netbuf + */ +struct netbuf * +__rpc_set_netbuf(struct netbuf *nb, const void *ptr, size_t len) +{ + if (nb->len != len) { + if (nb->len) + mem_free(nb->buf, nb->len); + nb->buf = mem_alloc(len); + if (nb->buf == NULL) + return NULL; + + nb->maxlen = nb->len = len; + } + memcpy(nb->buf, ptr, len); + return nb; +} diff --git a/libtirpc/src/rpc_prot.c b/libtirpc/src/rpc_prot.c new file mode 100644 index 0000000..88b5b31 --- /dev/null +++ b/libtirpc/src/rpc_prot.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_prot.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements the rpc message definition, + * its serializer and some common rpc utility routines. + * The routines are meant for various implementations of rpc - + * they are NOT for the rpc client or rpc service implementations! + * Because authentication stuff is easy and is part of rpc, the opaque + * routines are also in this program. + */ + +#include +//#include + +#include + +#include + +static void accepted(enum accept_stat, struct rpc_err *); +static void rejected(enum reject_stat, struct rpc_err *); + +/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ + +extern struct opaque_auth _null_auth; + +/* + * XDR an opaque authentication struct + * (see auth.h) + */ +bool_t +xdr_opaque_auth(xdrs, ap) + XDR *xdrs; + struct opaque_auth *ap; +{ + + assert(xdrs != NULL); + assert(ap != NULL); + + if (xdr_enum(xdrs, &(ap->oa_flavor))) + return (xdr_bytes(xdrs, &ap->oa_base, + &ap->oa_length, MAX_AUTH_BYTES)); + return (FALSE); +} + +/* + * XDR a DES block + */ +bool_t +xdr_des_block(xdrs, blkp) + XDR *xdrs; + des_block *blkp; +{ + + assert(xdrs != NULL); + assert(blkp != NULL); + + return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block))); +} + +/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ + +/* + * XDR the MSG_ACCEPTED part of a reply message union + */ +bool_t +xdr_accepted_reply(xdrs, ar) + XDR *xdrs; + struct accepted_reply *ar; +{ + + assert(xdrs != NULL); + assert(ar != NULL); + + /* personalized union, rather than calling xdr_union */ + if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) + return (FALSE); + if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) + return (FALSE); + switch (ar->ar_stat) { + + case SUCCESS: + return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); + + case PROG_MISMATCH: + if (! xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) + return (FALSE); + return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); + + case GARBAGE_ARGS: + case SYSTEM_ERR: + case PROC_UNAVAIL: + case PROG_UNAVAIL: + break; + } + return (TRUE); /* TRUE => open ended set of problems */ +} + +/* + * XDR the MSG_DENIED part of a reply message union + */ +bool_t +xdr_rejected_reply(xdrs, rr) + XDR *xdrs; + struct rejected_reply *rr; +{ + + assert(xdrs != NULL); + assert(rr != NULL); + + /* personalized union, rather than calling xdr_union */ + if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) + return (FALSE); + switch (rr->rj_stat) { + + case RPC_MISMATCH: + if (! xdr_u_int32_t(xdrs, &(rr->rj_vers.low))) + return (FALSE); + return (xdr_u_int32_t(xdrs, &(rr->rj_vers.high))); + + case AUTH_ERROR: + return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); + } + /* NOTREACHED */ + assert(0); + return (FALSE); +} + +static const struct xdr_discrim reply_dscrm[3] = { + { (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply }, + { (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply }, + { __dontcare__, NULL_xdrproc_t } }; + +/* + * XDR a reply message + */ +bool_t +xdr_replymsg(xdrs, rmsg) + XDR *xdrs; + struct rpc_msg *rmsg; +{ + assert(xdrs != NULL); + assert(rmsg != NULL); + + if ( + xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && + (rmsg->rm_direction == REPLY) ) + return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), + (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm, + NULL_xdrproc_t)); + return (FALSE); +} + +/* + * XDR a reply message in pieces, first xid and direction, then union + */ +bool_t +xdr_getxiddir(xdrs, rmsg) + XDR *xdrs; + struct rpc_msg *rmsg; +{ + assert(xdrs != NULL); + assert(rmsg != NULL); + + return (xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction))); +} + +bool_t +xdr_getreplyunion(xdrs, rmsg) + XDR *xdrs; + struct rpc_msg *rmsg; +{ + assert(xdrs != NULL); + assert(rmsg != NULL); + + return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), + (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm, + NULL_xdrproc_t)); +} + +bool_t +xdr_getcallbody(xdrs, rmsg) + XDR *xdrs; + struct rpc_msg *rmsg; +{ + assert(xdrs != NULL); + assert(rmsg != NULL); + + if ( + xdr_u_int32_t(xdrs, &(rmsg->rm_call.cb_rpcvers)) && + xdr_u_int32_t(xdrs, &(rmsg->rm_call.cb_prog)) && + xdr_u_int32_t(xdrs, &(rmsg->rm_call.cb_vers)) && + xdr_u_int32_t(xdrs, &(rmsg->rm_call.cb_proc)) && + xdr_opaque_auth(xdrs, &(rmsg->rm_call.cb_cred)) ) + return (xdr_opaque_auth(xdrs, &(rmsg->rm_call.cb_verf))); + return FALSE; +} + +/* + * Serializes the "static part" of a call message header. + * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. + * The rm_xid is not really static, but the user can easily munge on the fly. + */ +bool_t +xdr_callhdr(xdrs, cmsg) + XDR *xdrs; + struct rpc_msg *cmsg; +{ + + assert(xdrs != NULL); + assert(cmsg != NULL); + + cmsg->rm_direction = CALL; + cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; + if ( + (xdrs->x_op == XDR_ENCODE) && + xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_prog)) ) + return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers))); + return (FALSE); +} + +/* ************************** Client utility routine ************* */ + +static void +accepted(acpt_stat, error) + enum accept_stat acpt_stat; + struct rpc_err *error; +{ + + assert(error != NULL); + + switch (acpt_stat) { + + case PROG_UNAVAIL: + error->re_status = RPC_PROGUNAVAIL; + return; + + case PROG_MISMATCH: + error->re_status = RPC_PROGVERSMISMATCH; + return; + + case PROC_UNAVAIL: + error->re_status = RPC_PROCUNAVAIL; + return; + + case GARBAGE_ARGS: + error->re_status = RPC_CANTDECODEARGS; + return; + + case SYSTEM_ERR: + error->re_status = RPC_SYSTEMERROR; + return; + + case SUCCESS: + error->re_status = RPC_SUCCESS; + return; + } + /* NOTREACHED */ + /* something's wrong, but we don't know what ... */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (int32_t)MSG_ACCEPTED; + error->re_lb.s2 = (int32_t)acpt_stat; +} + +static void +rejected(rjct_stat, error) + enum reject_stat rjct_stat; + struct rpc_err *error; +{ + + assert(error != NULL); + + switch (rjct_stat) { + case RPC_MISMATCH: + error->re_status = RPC_VERSMISMATCH; + return; + + case AUTH_ERROR: + error->re_status = RPC_AUTHERROR; + return; + } + /* something's wrong, but we don't know what ... */ + /* NOTREACHED */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (int32_t)MSG_DENIED; + error->re_lb.s2 = (int32_t)rjct_stat; +} + +/* + * given a reply message, fills in the error + */ +void +_seterr_reply(msg, error) + struct rpc_msg *msg; + struct rpc_err *error; +{ + + assert(msg != NULL); + assert(error != NULL); + + /* optimized for normal, SUCCESSful case */ + switch (msg->rm_reply.rp_stat) { + + case MSG_ACCEPTED: + if (msg->acpted_rply.ar_stat == SUCCESS) { + error->re_status = RPC_SUCCESS; + return; + } + accepted(msg->acpted_rply.ar_stat, error); + break; + + case MSG_DENIED: + rejected(msg->rjcted_rply.rj_stat, error); + break; + + default: + error->re_status = RPC_FAILED; + error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat); + break; + } + switch (error->re_status) { + + case RPC_VERSMISMATCH: + error->re_vers.low = msg->rjcted_rply.rj_vers.low; + error->re_vers.high = msg->rjcted_rply.rj_vers.high; + break; + + case RPC_AUTHERROR: + error->re_why = msg->rjcted_rply.rj_why; + break; + + case RPC_PROGVERSMISMATCH: + error->re_vers.low = msg->acpted_rply.ar_vers.low; + error->re_vers.high = msg->acpted_rply.ar_vers.high; + break; + + case RPC_FAILED: + case RPC_SUCCESS: + case RPC_PROGNOTREGISTERED: + case RPC_PMAPFAILURE: + case RPC_UNKNOWNPROTO: + case RPC_UNKNOWNHOST: + case RPC_SYSTEMERROR: + case RPC_CANTDECODEARGS: + case RPC_PROCUNAVAIL: + case RPC_PROGUNAVAIL: + case RPC_TIMEDOUT: + case RPC_CANTRECV: + case RPC_CANTSEND: + case RPC_CANTDECODERES: + case RPC_CANTENCODEARGS: + default: + break; + } +} diff --git a/libtirpc/src/rpc_soc.c b/libtirpc/src/rpc_soc.c new file mode 100644 index 0000000..4b69810 --- /dev/null +++ b/libtirpc/src/rpc_soc.c @@ -0,0 +1,642 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + * In addition, portions of such source code were derived from Berkeley + * 4.3 BSD under license from the Regents of the University of + * California. + */ + +#if defined(PORTMAP) || defined (_WIN32) +/* + * rpc_soc.c + * + * The backward compatibility routines for the earlier implementation + * of RPC, where the only transports supported were tcp/ip and udp/ip. + * Based on berkeley socket abstraction, now implemented on the top + * of TLI/Streams + */ +#include +//#include +#include +#include +//#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +#include +//#include +#include +#include +//#include + +#include "rpc_com.h" + +extern mutex_t rpcsoc_lock; + +static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t, + int *, u_int, u_int, char *); +static SVCXPRT *svc_com_create(SOCKET, u_int, u_int, char *); +static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *); + +/* XXX */ +#define IN4_LOCALHOST_STRING "127.0.0.1" +#define IN6_LOCALHOST_STRING "::1" + +/* + * A common clnt create routine + */ +static CLIENT * +clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp) + struct sockaddr_in *raddr; + rpcprog_t prog; + rpcvers_t vers; + SOCKET *sockp; + u_int sendsz; + u_int recvsz; + char *tp; +{ + CLIENT *cl; + int madefd = FALSE; + SOCKET fd = *sockp; + struct netconfig *nconf; + struct netbuf bindaddr; + + mutex_lock(&rpcsoc_lock); + if ((nconf = __rpc_getconfip(tp)) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + mutex_unlock(&rpcsoc_lock); + return (NULL); + } + if (fd == RPC_ANYSOCK) { + fd = __rpc_nconf2fd(nconf); + if (fd == -1) + goto syserror; + madefd = TRUE; + } + + if (raddr->sin_port == 0) { + u_int proto; + u_short sport; + + mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */ + proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP; + sport = pmap_getport(raddr, (u_long)prog, (u_long)vers, + proto); + if (sport == 0) { + goto err; + } + raddr->sin_port = htons(sport); + mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */ + } + + /* Transform sockaddr_in to netbuf */ + bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in); + bindaddr.buf = raddr; + + bindresvport(fd, NULL); + cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers, + sendsz, recvsz, NULL, NULL, NULL); + if (cl) { + if (madefd == TRUE) { + /* + * The fd should be closed while destroying the handle. + */ + (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); + *sockp = fd; + } + (void) freenetconfigent(nconf); + mutex_unlock(&rpcsoc_lock); + return (cl); + } + goto err; + +syserror: + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + +err: if (madefd == TRUE) + (void)closesocket(fd); + (void) freenetconfigent(nconf); + mutex_unlock(&rpcsoc_lock); + return (NULL); +} + +CLIENT * +clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + u_long prog; + u_long vers; + struct timeval wait; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + CLIENT *cl; + + cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "udp"); + if (cl == NULL) { + return (NULL); + } + (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait); + return (cl); +} + +CLIENT * +clntudp_create(raddr, program, version, wait, sockp) + struct sockaddr_in *raddr; + u_long program; + u_long version; + struct timeval wait; + int *sockp; +{ + return clntudp_bufcreate(raddr, program, version, wait, sockp, UDPMSGSIZE, UDPMSGSIZE); +} + +CLIENT * +clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + u_long prog; + u_long vers; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "tcp"); +} + +/* IPv6 version of clnt*_*create */ + +#ifdef INET6_NOT_USED + +CLIENT * +clntudp6_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz) + struct sockaddr_in6 *raddr; + u_long prog; + u_long vers; + struct timeval wait; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + CLIENT *cl; + + cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "udp6"); + if (cl == NULL) { + return (NULL); + } + (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait); + return (cl); +} + +CLIENT * +clntudp6_create(raddr, program, version, wait, sockp) + struct sockaddr_in6 *raddr; + u_long program; + u_long version; + struct timeval wait; + int *sockp; +{ + return clntudp6_bufcreate(raddr, program, version, wait, sockp, UDPMSGSIZE, UDPMSGSIZE); +} + +CLIENT * +clnttcp6_create(raddr, prog, vers, sockp, sendsz, recvsz) + struct sockaddr_in6 *raddr; + u_long prog; + u_long vers; + int *sockp; + u_int sendsz; + u_int recvsz; +{ + return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp, + sendsz, recvsz, "tcp6"); +} + +#endif + +CLIENT * +clntraw_create(prog, vers) + u_long prog; + u_long vers; +{ + return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers); +} + +/* + * A common server create routine + */ +static SVCXPRT * +svc_com_create(fd, sendsize, recvsize, netid) + SOCKET fd; + u_int sendsize; + u_int recvsize; + char *netid; +{ + struct netconfig *nconf; + SVCXPRT *svc; + int madefd = FALSE; + int port; + struct sockaddr_in sin; + + if ((nconf = __rpc_getconfip(netid)) == NULL) { + //(void) syslog(LOG_ERR, "Could not get %s transport", netid); + return (NULL); + } + if (fd == RPC_ANYSOCK) { + fd = __rpc_nconf2fd(nconf); + if (fd == -1) { + (void) freenetconfigent(nconf); + //(void) syslog(LOG_ERR, + //"svc%s_create: could not open connection", netid); + return (NULL); + } + madefd = TRUE; + } + + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + bindresvport(fd, &sin); + listen(fd, SOMAXCONN); + svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize); + (void) freenetconfigent(nconf); + if (svc == NULL) { + if (madefd) + (void)closesocket(fd); + return (NULL); + } + port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port); + svc->xp_port = ntohs((u_short)port); + return (svc); +} + +SVCXPRT * +svctcp_create(fd, sendsize, recvsize) + SOCKET fd; + u_int sendsize; + u_int recvsize; +{ + + return svc_com_create(fd, sendsize, recvsize, "tcp"); +} + + + +SVCXPRT * +svcudp_bufcreate(fd, sendsz, recvsz) + SOCKET fd; + u_int sendsz, recvsz; +{ + + return svc_com_create(fd, sendsz, recvsz, "udp"); +} + + + +SVCXPRT * +svcfd_create(fd, sendsize, recvsize) + SOCKET fd; + u_int sendsize; + u_int recvsize; +{ + + return svc_fd_create(fd, sendsize, recvsize); +} + + +SVCXPRT * +svcudp_create(fd) + SOCKET fd; +{ + + return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp"); +} + + +SVCXPRT * +svcraw_create() +{ + + return svc_raw_create(); +} + + +/* IPV6 version */ +#ifdef INET6_NOT_USED +SVCXPRT * +svcudp6_bufcreate(fd, sendsz, recvsz) + int fd; + u_int sendsz, recvsz; +{ + return svc_com_create(fd, sendsz, recvsz, "udp6"); +} + + +SVCXPRT * +svctcp6_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + return svc_com_create(fd, sendsize, recvsize, "tcp6"); +} + + +SVCXPRT * +svcudp6_create(fd) + int fd; +{ + return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp6"); +} +#endif + +int +get_myaddress(addr) + struct sockaddr_in *addr; +{ + + memset((void *) addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(PMAPPORT); + addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return (0); +} + +/* + * For connectionless "udp" transport. Obsoleted by rpc_call(). + */ +int +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) + const char *host; + int prognum, versnum, procnum; + xdrproc_t inproc, outproc; + void *in, *out; +{ + + return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum, + (rpcproc_t)procnum, inproc, in, outproc, out, "udp"); +} + +/* + * For connectionless kind of transport. Obsoleted by rpc_reg() + */ +int +registerrpc(prognum, versnum, procnum, progname, inproc, outproc) + int prognum, versnum, procnum; + char *(*progname)(char [UDPMSGSIZE]); + xdrproc_t inproc, outproc; +{ + + return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum, + (rpcproc_t)procnum, progname, inproc, outproc, "udp"); +} + +/* + * All the following clnt_broadcast stuff is convulated; it supports + * the earlier calling style of the callback function + */ +extern thread_key_t clnt_broadcast_key; + +/* + * Need to translate the netbuf address into sockaddr_in address. + * Dont care about netid here. + */ +/* ARGSUSED */ +static bool_t +rpc_wrap_bcast(resultp, addr, nconf) + char *resultp; /* results of the call */ + struct netbuf *addr; /* address of the guy who responded */ + struct netconfig *nconf; /* Netconf of the transport */ +{ + resultproc_t clnt_broadcast_result; + + if (strcmp(nconf->nc_netid, "udp")) + return (FALSE); + clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key); + return (*clnt_broadcast_result)(resultp, + (struct sockaddr_in *)addr->buf); +} + +/* + * Broadcasts on UDP transport. Obsoleted by rpc_broadcast(). + */ +enum clnt_stat +clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) + u_long prog; /* program number */ + u_long vers; /* version number */ + u_long proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + void *argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + void *resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ +{ + extern mutex_t tsd_lock; + + if (clnt_broadcast_key == -1) { + mutex_lock(&tsd_lock); + if (clnt_broadcast_key == -1) + thr_keycreate(&clnt_broadcast_key, free); + mutex_unlock(&tsd_lock); + } + thr_setspecific(clnt_broadcast_key, (void *) eachresult); + return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers, + (rpcproc_t)proc, xargs, argsp, xresults, resultsp, + (resultproc_t) rpc_wrap_bcast, "udp"); +} + +#ifndef _WIN32 +/* + * Create the client des authentication object. Obsoleted by + * authdes_seccreate(). + */ +AUTH * +authdes_create(servername, window, syncaddr, ckey) + char *servername; /* network name of server */ + u_int window; /* time to live */ + struct sockaddr *syncaddr; /* optional hostaddr to sync with */ + des_block *ckey; /* optional conversation key to use */ +{ + AUTH *dummy; + AUTH *nauth; + char hostname[NI_MAXHOST]; + + if (syncaddr) { + /* + * Change addr to hostname, because that is the way + * new interface takes it. + */ + if (getnameinfo(syncaddr, sizeof(syncaddr), hostname, + sizeof hostname, NULL, 0, 0) != 0) + goto fallback; + + nauth = authdes_seccreate(servername, window, hostname, ckey); + return (nauth); + } +fallback: + dummy = authdes_seccreate(servername, window, NULL, ckey); + return (dummy); +} +#endif + +/* + * Create a client handle for a unix connection. Obsoleted by clnt_vc_create() + */ +CLIENT * +clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz) + struct sockaddr_un *raddr; + u_long prog; + u_long vers; + SOCKET *sockp; + u_int sendsz; + u_int recvsz; +{ + struct netbuf *svcaddr; + struct netconfig *nconf; + CLIENT *cl; + int len; + + cl = NULL; + nconf = NULL; + svcaddr = NULL; + if (((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) || + ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) { + if (svcaddr != NULL) + free(svcaddr); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return(cl); + } + if (*sockp == SOCKET_ERROR) { + *sockp = socket(AF_UNIX, SOCK_STREAM, 0); + len = SUN_LEN(raddr); + if ((*sockp == INVALID_SOCKET) || (connect(*sockp, + (struct sockaddr *)raddr, len) == SOCKET_ERROR)) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + if (*sockp != INVALID_SOCKET) + (void)closesocket(*sockp); + goto done; + } + } + svcaddr->buf = raddr; + svcaddr->len = sizeof(raddr); + svcaddr->maxlen = sizeof (struct sockaddr_un); + cl = clnt_vc_create(*sockp, svcaddr, prog, + vers, sendsz, recvsz, NULL, NULL, NULL); +done: + free(svcaddr->buf); + free(svcaddr); + return(cl); +} + +/* + * Creates, registers, and returns a (rpc) unix based transporter. + * Obsoleted by svc_vc_create(). + */ +SVCXPRT * +svcunix_create(sock, sendsize, recvsize, path) + SOCKET sock; + u_int sendsize; + u_int recvsize; + char *path; +{ + struct netconfig *nconf; + void *localhandle; + struct sockaddr_un sun; + struct sockaddr *sa; + struct t_bind taddr; + SVCXPRT *xprt; + int addrlen; + + xprt = (SVCXPRT *)NULL; + localhandle = setnetconfig(); + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) + return(xprt); + + if ((sock = __rpc_nconf2fd(nconf)) == SOCKET_ERROR) + goto done; + + memset(&sun, 0, sizeof sun); + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, path, sizeof(sun.sun_path)); + addrlen = sizeof(struct sockaddr_un); + sa = (struct sockaddr *)&sun; + + if (bind(sock, sa, addrlen) == SOCKET_ERROR) + goto done; + + taddr.addr.len = taddr.addr.maxlen = addrlen; + taddr.addr.buf = malloc(addrlen); + if (taddr.addr.buf == NULL) + goto done; + memcpy(taddr.addr.buf, sa, addrlen); + + if (nconf->nc_semantics != NC_TPI_CLTS) { + if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { + free(taddr.addr.buf); + goto done; + } + } + + xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize); + +done: + endnetconfig(localhandle); + return(xprt); +} + +/* + * Like svunix_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. Obsoleted by svc_fd_create(); + */ +SVCXPRT * +svcunixfd_create(fd, sendsize, recvsize) + SOCKET fd; + u_int sendsize; + u_int recvsize; +{ + return (svc_fd_create(fd, sendsize, recvsize)); +} + +#endif /* PORTMAP */ diff --git a/libtirpc/src/rpcb_clnt.c b/libtirpc/src/rpcb_clnt.c new file mode 100644 index 0000000..b8c30c1 --- /dev/null +++ b/libtirpc/src/rpcb_clnt.c @@ -0,0 +1,1240 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * rpcb_clnt.c + * interface to rpcbind rpc service. + * + * Copyright (C) 1988, Sun Microsystems, Inc. + */ +#include +//#include +#include +#include +//#include +//#include +//#include +#include +#include +#include +#include +#ifdef PORTMAP +//#include /* FOR IPPROTO_TCP/UDP definitions */ +#include +#endif /* PORTMAP */ +#include +#include +#include +#include +//#include +//#include +//#include + +#include "rpc_com.h" + +static struct timeval tottimeout = { 60, 0 }; +static const struct timeval rmttimeout = { 3, 0 }; +static struct timeval rpcbrmttime = { 15, 0 }; + +extern bool_t xdr_wrapstring(XDR *, char **); + +static const char nullstring[] = "\000"; + +#define RPCB_OWNER_STRING "libtirpc" + +#define CACHESIZE 6 + +struct address_cache { + char *ac_host; + char *ac_netid; + char *ac_uaddr; + struct netbuf *ac_taddr; + struct address_cache *ac_next; +}; + +static struct address_cache *front; +static int cachesize; + +#define CLCR_GET_RPCB_TIMEOUT 1 +#define CLCR_SET_RPCB_TIMEOUT 2 + + +extern int __rpc_lowvers; + +static struct address_cache *check_cache(const char *, const char *); +static void delete_cache(struct netbuf *); +static void add_cache(const char *, const char *, struct netbuf *, char *); +static CLIENT *getclnthandle(const char *, const struct netconfig *, char **); +static CLIENT *local_rpcb(void); +#ifdef NOTUSED +static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *); +#endif + +/* + * This routine adjusts the timeout used for calls to the remote rpcbind. + * Also, this routine can be used to set the use of portmapper version 2 + * only when doing rpc_broadcasts + * These are private routines that may not be provided in future releases. + */ +bool_t +__rpc_control(request, info) + int request; + void *info; +{ + switch (request) { + case CLCR_GET_RPCB_TIMEOUT: + *(struct timeval *)info = tottimeout; + break; + case CLCR_SET_RPCB_TIMEOUT: + tottimeout = *(struct timeval *)info; + break; + case CLCR_SET_LOWVERS: + __rpc_lowvers = *(int *)info; + break; + case CLCR_GET_LOWVERS: + *(int *)info = __rpc_lowvers; + break; + default: + return (FALSE); + } + return (TRUE); +} + +/* + * It might seem that a reader/writer lock would be more reasonable here. + * However because getclnthandle(), the only user of the cache functions, + * may do a delete_cache() operation if a check_cache() fails to return an + * address useful to clnt_tli_create(), we may as well use a mutex. + */ +/* + * As it turns out, if the cache lock is *not* a reader/writer lock, we will + * block all clnt_create's if we are trying to connect to a host that's down, + * since the lock will be held all during that time. + */ +extern rwlock_t rpcbaddr_cache_lock; + +/* + * The routines check_cache(), add_cache(), delete_cache() manage the + * cache of rpcbind addresses for (host, netid). + */ + +static struct address_cache * +check_cache(host, netid) + const char *host, *netid; +{ + struct address_cache *cptr; + + /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!strcmp(cptr->ac_host, host) && + !strcmp(cptr->ac_netid, netid)) { +#ifdef ND_DEBUG + fprintf(stderr, "Found cache entry for %s: %s\n", + host, netid); +#endif + return (cptr); + } + } + return ((struct address_cache *) NULL); +} + +static void +delete_cache(addr) + struct netbuf *addr; +{ + struct address_cache *cptr, *prevptr = NULL; + + /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */ + for (cptr = front; cptr != NULL; cptr = cptr->ac_next) { + if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) { + free(cptr->ac_host); + free(cptr->ac_netid); + free(cptr->ac_taddr->buf); + free(cptr->ac_taddr); + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + if (prevptr) + prevptr->ac_next = cptr->ac_next; + else + front = cptr->ac_next; + free(cptr); + cachesize--; + break; + } + prevptr = cptr; + } +} + +static void +add_cache(host, netid, taddr, uaddr) + const char *host, *netid; + char *uaddr; + struct netbuf *taddr; +{ + struct address_cache *ad_cache, *cptr, *prevptr; + + ad_cache = (struct address_cache *) + malloc(sizeof (struct address_cache)); + if (!ad_cache) { + return; + } + ad_cache->ac_host = strdup(host); + ad_cache->ac_netid = strdup(netid); + ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL; + ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf)); + if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr || + (uaddr && !ad_cache->ac_uaddr)) { + return; + } + ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len; + ad_cache->ac_taddr->buf = (char *) malloc(taddr->len); + if (ad_cache->ac_taddr->buf == NULL) { + return; + } + memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len); +#ifdef ND_DEBUG + fprintf(stderr, "Added to cache: %s : %s\n", host, netid); +#endif + +/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */ + + rwlock_wrlock(&rpcbaddr_cache_lock); + if (cachesize < CACHESIZE) { + ad_cache->ac_next = front; + front = ad_cache; + cachesize++; + } else { + /* Free the last entry */ + cptr = front; + prevptr = NULL; + while (cptr->ac_next) { + prevptr = cptr; + cptr = cptr->ac_next; + } + +#ifdef ND_DEBUG + fprintf(stderr, "Deleted from cache: %s : %s\n", + cptr->ac_host, cptr->ac_netid); +#endif + free(cptr->ac_host); + free(cptr->ac_netid); + free(cptr->ac_taddr->buf); + free(cptr->ac_taddr); + if (cptr->ac_uaddr) + free(cptr->ac_uaddr); + + if (prevptr) { + prevptr->ac_next = NULL; + ad_cache->ac_next = front; + front = ad_cache; + } else { + front = ad_cache; + ad_cache->ac_next = NULL; + } + free(cptr); + } + rwlock_unlock(&rpcbaddr_cache_lock); +} + +/* + * This routine will return a client handle that is connected to the + * rpcbind. If targaddr is non-NULL, the "universal address" of the + * host will be stored in *targaddr; the caller is responsible for + * freeing this string. + * On error, returns NULL and free's everything. + */ +static CLIENT * +getclnthandle(host, nconf, targaddr) + const char *host; + const struct netconfig *nconf; + char **targaddr; +{ + CLIENT *client; + struct netbuf *addr, taddr; + struct netbuf addr_to_delete; + struct __rpc_sockinfo si; + struct addrinfo hints, *res, *tres; + struct address_cache *ad_cache; + char *tmpaddr; + +/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */ + + /* Get the address of the rpcbind. Check cache first */ + client = NULL; + addr_to_delete.len = 0; + rwlock_rdlock(&rpcbaddr_cache_lock); + ad_cache = NULL; + if (host != NULL) + ad_cache = check_cache(host, nconf->nc_netid); + if (ad_cache != NULL) { + addr = ad_cache->ac_taddr; + client = clnt_tli_create(RPC_ANYFD, nconf, addr, + (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0, NULL, NULL, NULL); + if (client != NULL) { + if (targaddr) + *targaddr = strdup(ad_cache->ac_uaddr); + rwlock_unlock(&rpcbaddr_cache_lock); + return (client); + } + addr_to_delete.len = addr->len; + addr_to_delete.buf = (char *)malloc(addr->len); + if (addr_to_delete.buf == NULL) { + addr_to_delete.len = 0; + } else { + memcpy(addr_to_delete.buf, addr->buf, addr->len); + } + } + rwlock_unlock(&rpcbaddr_cache_lock); + if (addr_to_delete.len != 0) { + /* + * Assume this may be due to cache data being + * outdated + */ + rwlock_wrlock(&rpcbaddr_cache_lock); + delete_cache(&addr_to_delete); + rwlock_unlock(&rpcbaddr_cache_lock); + free(addr_to_delete.buf); + } + if (!__rpc_nconf2sockinfo(nconf, &si)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = si.si_af; + hints.ai_socktype = si.si_socktype; + hints.ai_protocol = si.si_proto; + +#ifdef CLNT_DEBUG + printf("trying netid %s family %d proto %d socktype %d\n", + nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype); +#endif + + if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + client = local_rpcb(); + if (! client) { +#ifdef ND_DEBUG + clnt_pcreateerror("rpcbind clnt interface"); +#endif + return (NULL); + } else { + struct sockaddr_un sun; + + *targaddr = malloc(sizeof(sun.sun_path)); + strncpy(*targaddr, _PATH_RPCBINDSOCK, + sizeof(sun.sun_path)); + return (client); + } + } else { + if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; + return NULL; + } + } + + for (tres = res; tres != NULL; tres = tres->ai_next) { + taddr.buf = tres->ai_addr; + taddr.len = taddr.maxlen = tres->ai_addrlen; + +#ifdef ND_DEBUG + { + char *ua; + + ua = taddr2uaddr(nconf, &taddr); + fprintf(stderr, "Got it [%s]\n", ua); + free(ua); + } +#endif + +#ifdef ND_DEBUG + { + int i; + + fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n", + taddr.len, taddr.maxlen); + fprintf(stderr, "\tAddress is "); + for (i = 0; i < taddr.len; i++) + fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]); + fprintf(stderr, "\n"); + } +#endif + client = clnt_tli_create(RPC_ANYFD, nconf, &taddr, + (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0, NULL, NULL, NULL); +#ifdef ND_DEBUG + if (! client) { + clnt_pcreateerror("rpcbind clnt interface"); + } +#endif + + if (client) { + tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL; + add_cache(host, nconf->nc_netid, &taddr, tmpaddr); + if (targaddr) + *targaddr = tmpaddr; + break; + } + } + if (res) + freeaddrinfo(res); + return (client); +} + +/* XXX */ +#define IN4_LOCALHOST_STRING "127.0.0.1" +#define IN6_LOCALHOST_STRING "::1" + +/* + * This routine will return a client handle that is connected to the local + * rpcbind. Returns NULL on error and free's everything. + */ +static CLIENT * +local_rpcb() +{ + CLIENT *client; + static struct netconfig *loopnconf; + static char *hostname; + extern mutex_t loopnconf_lock; + SOCKET sock; + size_t tsize; + struct netbuf nbuf; + struct sockaddr_un sun; + + /* + * Try connecting to the local rpcbind through a local socket + * first. If this doesn't work, try all transports defined in + * the netconfig file. + */ + memset(&sun, 0, sizeof sun); + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + goto try_nconf; + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, _PATH_RPCBINDSOCK); + nbuf.len = SUN_LEN(&sun); + nbuf.maxlen = sizeof (struct sockaddr_un); + nbuf.buf = &sun; + + tsize = __rpc_get_t_size(AF_UNIX, 0, 0); + client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG, + (rpcvers_t)RPCBVERS, (u_int)tsize, (u_int)tsize, + NULL, NULL, NULL); + + if (client != NULL) { + /* Mark the socket to be closed in destructor */ + (void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); + return client; + } + + /* Nobody needs this socket anymore; free the descriptor. */ + closesocket(sock); + +try_nconf: + +/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */ + mutex_lock(&loopnconf_lock); + if (loopnconf == NULL) { + struct netconfig *nconf, *tmpnconf = NULL; + void *nc_handle; + SOCKET fd; + + nc_handle = setnetconfig(); + if (nc_handle == NULL) { + /* fails to open netconfig file */ + //syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + mutex_unlock(&loopnconf_lock); + return (NULL); + } + while ((nconf = getnetconfig(nc_handle)) != NULL) { +#ifdef INET6 + if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 || +#else + if (( +#endif + strcmp(nconf->nc_protofmly, NC_INET) == 0) && + (nconf->nc_semantics == NC_TPI_COTS || + nconf->nc_semantics == NC_TPI_COTS_ORD)) { + fd = __rpc_nconf2fd(nconf); + /* + * Can't create a socket, assume that + * this family isn't configured in the kernel. + */ + if (fd == SOCKET_ERROR) + continue; + closesocket(fd); + tmpnconf = nconf; + if (!strcmp(nconf->nc_protofmly, NC_INET)) + hostname = IN4_LOCALHOST_STRING; + else + hostname = IN6_LOCALHOST_STRING; + } + } + if (tmpnconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + mutex_unlock(&loopnconf_lock); + return (NULL); + } + loopnconf = getnetconfigent(tmpnconf->nc_netid); + /* loopnconf is never freed */ + endnetconfig(nc_handle); + } + mutex_unlock(&loopnconf_lock); + client = getclnthandle(hostname, loopnconf, NULL); + return (client); +} + +/* + * Set a mapping between program, version and address. + * Calls the rpcbind service to do the mapping. + */ +bool_t +rpcb_set(program, version, nconf, address) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; /* Network structure of transport */ + const struct netbuf *address; /* Services netconfig address */ +{ + CLIENT *client; + bool_t rslt = FALSE; + RPCB parms; + char uidbuf[32]; + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (FALSE); + } + if (address == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (FALSE); + } + client = local_rpcb(); + if (! client) { + return (FALSE); + } + + /* convert to universal */ + /*LINTED const castaway*/ + parms.r_addr = taddr2uaddr((struct netconfig *) nconf, + (struct netbuf *)address); + if (!parms.r_addr) { + CLNT_DESTROY(client); + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + return (FALSE); /* no universal address */ + } + parms.r_prog = program; + parms.r_vers = version; + parms.r_netid = nconf->nc_netid; + /* + * Though uid is not being used directly, we still send it for + * completeness. For non-unix platforms, perhaps some other + * string or an empty string can be sent. + */ + (void) snprintf(uidbuf, sizeof uidbuf, "%d", 20010 /*geteuid()*/); + parms.r_owner = uidbuf; + + CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb, + (char *)&parms, (xdrproc_t) xdr_bool, + (char *)&rslt, tottimeout); + + CLNT_DESTROY(client); + free(parms.r_addr); + return (rslt); +} + +/* + * Remove the mapping between program, version and netbuf address. + * Calls the rpcbind service to do the un-mapping. + * If netbuf is NULL, unset for all the transports, otherwise unset + * only for the given transport. + */ +bool_t +rpcb_unset(program, version, nconf) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; +{ + CLIENT *client; + bool_t rslt = FALSE; + RPCB parms; + char uidbuf[32]; + + client = local_rpcb(); + if (! client) { + return (FALSE); + } + + parms.r_prog = program; + parms.r_vers = version; + if (nconf) + parms.r_netid = nconf->nc_netid; + else { + /*LINTED const castaway*/ + parms.r_netid = (char *) &nullstring[0]; /* unsets all */ + } + /*LINTED const castaway*/ + parms.r_addr = (char *) &nullstring[0]; + (void) snprintf(uidbuf, sizeof uidbuf, "%d", 20010 /*geteuid()*/); + parms.r_owner = uidbuf; + + CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb, + (char *)(void *)&parms, (xdrproc_t) xdr_bool, + (char *)(void *)&rslt, tottimeout); + + CLNT_DESTROY(client); + return (rslt); +} +#ifdef NOTUSED +/* + * From the merged list, find the appropriate entry + */ +static struct netbuf * +got_entry(relp, nconf) + rpcb_entry_list_ptr relp; + const struct netconfig *nconf; +{ + struct netbuf *na = NULL; + rpcb_entry_list_ptr sp; + rpcb_entry *rmap; + + for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) { + rmap = &sp->rpcb_entry_map; + if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) && + (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) && + (nconf->nc_semantics == rmap->r_nc_semantics) && + (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) { + na = uaddr2taddr(nconf, rmap->r_maddr); +#ifdef ND_DEBUG + fprintf(stderr, "\tRemote address is [%s].\n", + rmap->r_maddr); + if (!na) + fprintf(stderr, + "\tCouldn't resolve remote address!\n"); +#endif + break; + } + } + return (na); +} +#endif + +/* + * Quick check to see if rpcbind is up. Tries to connect over + * local transport. + */ +bool_t +__rpcbind_is_up() +{ + struct netconfig *nconf; + struct sockaddr_un sun; + void *localhandle; + SOCKET sock; + + nconf = NULL; + localhandle = setnetconfig(); + while ((nconf = getnetconfig(localhandle)) != NULL) { + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) + return (FALSE); + + endnetconfig(localhandle); + + memset(&sun, 0, sizeof sun); + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + return (FALSE); + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); + + if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == SOCKET_ERROR) { + closesocket(sock); + return (FALSE); + } + + closesocket(sock); + return (TRUE); +} + +/* + * An internal function which optimizes rpcb_getaddr function. It also + * returns the client handle that it uses to contact the remote rpcbind. + * + * The algorithm used: If the transports is TCP or UDP, it first tries + * version 2 (portmap), 4 and then 3 (svr4). This order should be + * changed in the next OS release to 4, 2 and 3. We are assuming that by + * that time, version 4 would be available on many machines on the network. + * With this algorithm, we get performance as well as a plan for + * obsoleting version 2. + * + * For all other transports, the algorithm remains as 4 and then 3. + * + * XXX: Due to some problems with t_connect(), we do not reuse the same client + * handle for COTS cases and hence in these cases we do not return the + * client handle. This code will change if t_connect() ever + * starts working properly. Also look under clnt_vc.c. + */ +struct netbuf * +__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; + const char *host; + CLIENT **clpp; + struct timeval *tp; +{ +#ifdef NOTUSED + static bool_t check_rpcbind = TRUE; +#endif + CLIENT *client = NULL; + RPCB parms; + enum clnt_stat clnt_st; + char *ua = NULL; + rpcvers_t vers; + struct netbuf *address = NULL; + rpcvers_t start_vers = RPCBVERS4; + struct netbuf servaddr; + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + + parms.r_addr = NULL; + + /* + * Use default total timeout if no timeout is specified. + */ + if (tp == NULL) + tp = &tottimeout; + +#ifdef PORTMAP + /* Try version 2 for TCP or UDP */ + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { + u_short port = 0; + struct netbuf remote; + rpcvers_t pmapvers = 2; + struct pmap pmapparms; + + /* + * Try UDP only - there are some portmappers out + * there that use UDP only. + */ + if (strcmp(nconf->nc_proto, NC_TCP) == 0) { + struct netconfig *newnconf; + + if ((newnconf = getnetconfigent("udp")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + client = getclnthandle(host, newnconf, &parms.r_addr); + freenetconfigent(newnconf); + } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) + client = getclnthandle(host, nconf, &parms.r_addr); + else + goto try_rpcbind; + if (client == NULL) + return (NULL); + + /* + * Set version and retry timeout. + */ + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); + + pmapparms.pm_prog = program; + pmapparms.pm_vers = version; + pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? + IPPROTO_UDP : IPPROTO_TCP; + pmapparms.pm_port = 0; /* not needed */ + clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, + (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, + (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, + *tp); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) + goto try_rpcbind; + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } else if (port == 0) { + address = NULL; + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + goto error; + } + port = htons(port); + CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); + if (((address = (struct netbuf *) + malloc(sizeof (struct netbuf))) == NULL) || + ((address->buf = (char *) + malloc(remote.len)) == NULL)) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + clnt_geterr(client, &rpc_createerr.cf_error); + if (address) { + free(address); + address = NULL; + } + goto error; + } + memcpy(address->buf, remote.buf, remote.len); + memcpy(&((char *)address->buf)[sizeof (short)], + (char *)(void *)&port, sizeof (short)); + address->len = address->maxlen = remote.len; + goto done; + } + +try_rpcbind: +#endif /* PORTMAP */ + + parms.r_prog = program; + parms.r_vers = version; + parms.r_netid = nconf->nc_netid; + + /* + * rpcbind ignores the r_owner field in GETADDR requests, but we + * need to give xdr_rpcb something to gnaw on. Might as well make + * it something human readable for when we see these in captures. + */ + parms.r_owner = RPCB_OWNER_STRING; + + /* Now the same transport is to be used to get the address */ + if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || + (nconf->nc_semantics == NC_TPI_COTS))) { + /* A CLTS type of client - destroy it */ + CLNT_DESTROY(client); + client = NULL; + free(parms.r_addr); + parms.r_addr = NULL; + } + + if (client == NULL) { + client = getclnthandle(host, nconf, &parms.r_addr); + if (client == NULL) { + goto error; + } + } + if (parms.r_addr == NULL) { + /*LINTED const castaway*/ + parms.r_addr = (char *) &nullstring[0]; + } + + /* First try from start_vers(4) and then version 3 (RPCBVERS) */ + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); + for (vers = start_vers; vers >= RPCBVERS; vers--) { + /* Set the version */ + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, + (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, + (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); + if (clnt_st == RPC_SUCCESS) { + if ((ua == NULL) || (ua[0] == 0)) { + /* address unknown */ + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + goto error; + } + address = uaddr2taddr(nconf, ua); +#ifdef ND_DEBUG + fprintf(stderr, "\tRemote address is [%s]\n", ua); + if (!address) + fprintf(stderr, + "\tCouldn't resolve remote address!\n"); +#endif + xdr_free((xdrproc_t)xdr_wrapstring, + (char *)(void *)&ua); + + if (! address) { + /* We don't know about your universal address */ + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + goto error; + } + CLNT_CONTROL(client, CLGET_SVC_ADDR, + (char *)(void *)&servaddr); + __rpc_fixup_addr(address, &servaddr); + goto done; + } else if (clnt_st == RPC_PROGVERSMISMATCH) { + struct rpc_err rpcerr; + clnt_geterr(client, &rpcerr); + if (rpcerr.re_vers.low > RPCBVERS4) + goto error; /* a new version, can't handle */ + } else if (clnt_st != RPC_PROGUNAVAIL) { + /* Cant handle this error */ + rpc_createerr.cf_stat = clnt_st; + clnt_geterr(client, &rpc_createerr.cf_error); + goto error; + } + } + + if ((address == NULL) || (address->len == 0)) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + clnt_geterr(client, &rpc_createerr.cf_error); + } + +error: + if (client) { + CLNT_DESTROY(client); + client = NULL; + } +done: + if (nconf->nc_semantics != NC_TPI_CLTS) { + /* This client is the connectionless one */ + if (client) { + CLNT_DESTROY(client); + client = NULL; + } + } + if (clpp) { + *clpp = client; + } else if (client) { + CLNT_DESTROY(client); + } + if (parms.r_addr != NULL && parms.r_addr != nullstring) + free(parms.r_addr); + return (address); +} + + +/* + * Find the mapped address for program, version. + * Calls the rpcbind service remotely to do the lookup. + * Uses the transport specified in nconf. + * Returns FALSE (0) if no map exists, else returns 1. + * + * Assuming that the address is all properly allocated + */ +int +rpcb_getaddr(program, version, nconf, address, host) + rpcprog_t program; + rpcvers_t version; + const struct netconfig *nconf; + struct netbuf *address; + const char *host; +{ + struct netbuf *na; + + if ((na = __rpcb_findaddr_timed(program, version, + (struct netconfig *) nconf, (char *) host, + (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) + return (FALSE); + + if (na->len > address->maxlen) { + /* Too long address */ + free(na->buf); + free(na); + rpc_createerr.cf_stat = RPC_FAILED; + return (FALSE); + } + memcpy(address->buf, na->buf, (size_t)na->len); + address->len = na->len; + free(na->buf); + free(na); + return (TRUE); +} + +/* + * Get a copy of the current maps. + * Calls the rpcbind service remotely to get the maps. + * + * It returns only a list of the services + * It returns NULL on failure. + */ +rpcblist * +rpcb_getmaps(nconf, host) + const struct netconfig *nconf; + const char *host; +{ + rpcblist_ptr head = NULL; + CLIENT *client; + enum clnt_stat clnt_st; + rpcvers_t vers = 0; + + client = getclnthandle(host, nconf, NULL); + if (client == NULL) { + return (head); + } + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, + (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, + (char *)(void *)&head, tottimeout); + if (clnt_st == RPC_SUCCESS) + goto done; + + if ((clnt_st != RPC_PROGVERSMISMATCH) && + (clnt_st != RPC_PROGUNAVAIL)) { + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + goto done; + } + + /* fall back to earlier version */ + CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); + if (vers == RPCBVERS4) { + vers = RPCBVERS; + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP, + (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr, + (char *)(void *)&head, tottimeout) == RPC_SUCCESS) + goto done; + } + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + +done: + CLNT_DESTROY(client); + return (head); +} + +/* + * rpcbinder remote-call-service interface. + * This routine is used to call the rpcbind remote call service + * which will look up a service program in the address maps, and then + * remotely call that routine with the given parameters. This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp, + xdrres, resp, tout, addr_ptr) + const struct netconfig *nconf; /* Netconfig structure */ + const char *host; /* Remote host name */ + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; /* Remote proc identifiers */ + xdrproc_t xdrargs, xdrres; /* XDR routines */ + caddr_t argsp, resp; /* Argument and Result */ + struct timeval tout; /* Timeout value for this call */ + const struct netbuf *addr_ptr; /* Preallocated netbuf address */ +{ + CLIENT *client; + enum clnt_stat stat; + struct r_rpcb_rmtcallargs a; + struct r_rpcb_rmtcallres r; + rpcvers_t rpcb_vers; + + stat = 0; + client = getclnthandle(host, nconf, NULL); + if (client == NULL) { + return (RPC_FAILED); + } + /*LINTED const castaway*/ + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout); + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.args.args_val = argsp; + a.xdr_args = xdrargs; + r.addr = NULL; + r.results.results_val = resp; + r.xdr_res = xdrres; + + for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) { + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers); + stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT, + (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a, + (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout); + if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) { + struct netbuf *na; + /*LINTED const castaway*/ + na = uaddr2taddr((struct netconfig *) nconf, r.addr); + if (!na) { + stat = RPC_N2AXLATEFAILURE; + /*LINTED const castaway*/ + ((struct netbuf *) addr_ptr)->len = 0; + goto error; + } + if (na->len > addr_ptr->maxlen) { + /* Too long address */ + stat = RPC_FAILED; /* XXX A better error no */ + free(na->buf); + free(na); + /*LINTED const castaway*/ + ((struct netbuf *) addr_ptr)->len = 0; + goto error; + } + memcpy(addr_ptr->buf, na->buf, (size_t)na->len); + /*LINTED const castaway*/ + ((struct netbuf *)addr_ptr)->len = na->len; + free(na->buf); + free(na); + break; + } else if ((stat != RPC_PROGVERSMISMATCH) && + (stat != RPC_PROGUNAVAIL)) { + goto error; + } + } +error: + CLNT_DESTROY(client); + if (r.addr) + xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr); + return (stat); +} + +#ifndef _WIN32 +/* + * Gets the time on the remote host. + * Returns 1 if succeeds else 0. + */ +bool_t +rpcb_gettime(host, timep) + const char *host; + time_t *timep; +{ + CLIENT *client = NULL; + void *handle; + struct netconfig *nconf; + rpcvers_t vers; + enum clnt_stat st; + + if ((host == NULL) || (host[0] == 0)) { + time(timep); + return (TRUE); + } + + if ((handle = __rpc_setconf("netpath")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (FALSE); + } + rpc_createerr.cf_stat = RPC_SUCCESS; + while (client == NULL) { + if ((nconf = __rpc_getconf(handle)) == NULL) { + if (rpc_createerr.cf_stat == RPC_SUCCESS) + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + break; + } + client = getclnthandle(host, nconf, NULL); + if (client) + break; + } + __rpc_endconf(handle); + if (client == (CLIENT *) NULL) { + return (FALSE); + } + + st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout); + + if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) { + CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers); + if (vers == RPCBVERS4) { + /* fall back to earlier version */ + vers = RPCBVERS; + CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); + st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_int, (char *)(void *)timep, + tottimeout); + } + } + CLNT_DESTROY(client); + return (st == RPC_SUCCESS? TRUE: FALSE); +} +#endif + +/* + * Converts taddr to universal address. This routine should never + * really be called because local n2a libraries are always provided. + */ +char * +rpcb_taddr2uaddr(nconf, taddr) + struct netconfig *nconf; + struct netbuf *taddr; +{ + CLIENT *client; + char *uaddr = NULL; + + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + if (taddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + client = local_rpcb(); + if (! client) { + return (NULL); + } + + CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR, + (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, + (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout); + CLNT_DESTROY(client); + return (uaddr); +} + +/* + * Converts universal address to netbuf. This routine should never + * really be called because local n2a libraries are always provided. + */ +struct netbuf * +rpcb_uaddr2taddr(nconf, uaddr) + struct netconfig *nconf; + char *uaddr; +{ + CLIENT *client; + struct netbuf *taddr; + + + /* parameter checking */ + if (nconf == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + if (uaddr == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return (NULL); + } + client = local_rpcb(); + if (! client) { + return (NULL); + } + + taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); + if (taddr == NULL) { + CLNT_DESTROY(client); + return (NULL); + } + if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR, + (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, + (xdrproc_t) xdr_netbuf, (char *)(void *)taddr, + tottimeout) != RPC_SUCCESS) { + free(taddr); + taddr = NULL; + } + CLNT_DESTROY(client); + return (taddr); +} diff --git a/libtirpc/src/rpcb_prot.c b/libtirpc/src/rpcb_prot.c new file mode 100644 index 0000000..0b762d1 --- /dev/null +++ b/libtirpc/src/rpcb_prot.c @@ -0,0 +1,319 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * rpcb_prot.c + * XDR routines for the rpcbinder version 3. + * + * Copyright (C) 1984, 1988, Sun Microsystems, Inc. + */ + +#include +#include +#include +#include +#include + +bool_t +xdr_rpcb(xdrs, objp) + XDR *xdrs; + RPCB *objp; +{ + if (!xdr_u_int32_t(xdrs, &objp->r_prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->r_vers)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_addr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_owner, (u_int)~0)) { + return (FALSE); + } + return (TRUE); +} + +/* + * rpcblist_ptr implements a linked list. The RPCL definition from + * rpcb_prot.x is: + * + * struct rpcblist { + * rpcb rpcb_map; + * struct rpcblist *rpcb_next; + * }; + * typedef rpcblist *rpcblist_ptr; + * + * Recall that "pointers" in XDR are encoded as a boolean, indicating whether + * there's any data behind the pointer, followed by the data (if any exists). + * The boolean can be interpreted as ``more data follows me''; if FALSE then + * nothing follows the boolean; if TRUE then the boolean is followed by an + * actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct + * rpcblist *"). + * + * This could be implemented via the xdr_pointer type, though this would + * result in one recursive call per element in the list. Rather than do that + * we can ``unwind'' the recursion into a while loop and use xdr_reference to + * serialize the rpcb elements. + */ + +bool_t +xdr_rpcblist_ptr(xdrs, rp) + XDR *xdrs; + rpcblist_ptr *rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing = (xdrs->x_op == XDR_FREE); + rpcblist_ptr next; + rpcblist_ptr next_copy; + + next = NULL; + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) { + return (FALSE); + } + if (! more_elements) { + return (TRUE); /* we are done */ + } + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = (*rp)->rpcb_next; + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof (rpcblist), (xdrproc_t)xdr_rpcb)) { + return (FALSE); + } + if (freeing) { + next_copy = next; + rp = &next_copy; + /* + * Note that in the subsequent iteration, next_copy + * gets nulled out by the xdr_reference + * but next itself survives. + */ + } else { + rp = &((*rp)->rpcb_next); + } + } + /*NOTREACHED*/ +} + +/* + * xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in + * functionality to xdr_rpcblist_ptr(). + */ +bool_t +xdr_rpcblist(xdrs, rp) + XDR *xdrs; + RPCBLIST **rp; +{ + bool_t dummy; + + dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp); + return (dummy); +} + + +bool_t +xdr_rpcb_entry(xdrs, objp) + XDR *xdrs; + rpcb_entry *objp; +{ + if (!xdr_string(xdrs, &objp->r_maddr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_protofmly, (u_int)~0)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->r_nc_proto, (u_int)~0)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcb_entry_list_ptr(xdrs, rp) + XDR *xdrs; + rpcb_entry_list_ptr *rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + int freeing = (xdrs->x_op == XDR_FREE); + rpcb_entry_list_ptr next; + rpcb_entry_list_ptr next_copy; + + next = NULL; + for (;;) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) { + return (FALSE); + } + if (! more_elements) { + return (TRUE); /* we are done */ + } + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = (*rp)->rpcb_entry_next; + if (! xdr_reference(xdrs, (caddr_t *)rp, + (u_int)sizeof (rpcb_entry_list), + (xdrproc_t)xdr_rpcb_entry)) { + return (FALSE); + } + if (freeing) { + next_copy = next; + rp = &next_copy; + /* + * Note that in the subsequent iteration, next_copy + * gets nulled out by the xdr_reference + * but next itself survives. + */ + } else { + rp = &((*rp)->rpcb_entry_next); + } + } + /*NOTREACHED*/ +} + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rpcb_rmtcallargs(xdrs, p) + XDR *xdrs; + struct rpcb_rmtcallargs *p; +{ + struct r_rpcb_rmtcallargs *objp = + (struct r_rpcb_rmtcallargs *)(void *)p; + u_int lenposition, argposition, position; + int32_t *buf; + + buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + } else { + IXDR_PUT_U_INT32(buf, objp->prog); + IXDR_PUT_U_INT32(buf, objp->vers); + IXDR_PUT_U_INT32(buf, objp->proc); + } + + /* + * All the jugglery for just getting the size of the arguments + */ + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_int(xdrs, &(objp->args.args_len))) { + return (FALSE); + } + argposition = XDR_GETPOS(xdrs); + if (! (*objp->xdr_args)(xdrs, objp->args.args_val)) { + return (FALSE); + } + position = XDR_GETPOS(xdrs); + objp->args.args_len = (u_int)((u_long)position - (u_long)argposition); + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_int(xdrs, &(objp->args.args_len))) { + return (FALSE); + } + XDR_SETPOS(xdrs, position); + return (TRUE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rpcb_rmtcallres(xdrs, p) + XDR *xdrs; + struct rpcb_rmtcallres *p; +{ + bool_t dummy; + struct r_rpcb_rmtcallres *objp = (struct r_rpcb_rmtcallres *)(void *)p; + + if (!xdr_string(xdrs, &objp->addr, (u_int)~0)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->results.results_len)) { + return (FALSE); + } + dummy = (*(objp->xdr_res))(xdrs, objp->results.results_val); + return (dummy); +} + +bool_t +xdr_netbuf(xdrs, objp) + XDR *xdrs; + struct netbuf *objp; +{ + bool_t dummy; + + if (!xdr_u_int32_t(xdrs, (u_int32_t *) &objp->maxlen)) { + return (FALSE); + } + dummy = xdr_bytes(xdrs, (char **)&(objp->buf), + (u_int *)&(objp->len), objp->maxlen); + return (dummy); +} diff --git a/libtirpc/src/rpcb_st_xdr.c b/libtirpc/src/rpcb_st_xdr.c new file mode 100644 index 0000000..6feb70b --- /dev/null +++ b/libtirpc/src/rpcb_st_xdr.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright 1991 Sun Microsystems, Inc. + * rpcb_stat_xdr.c + */ + +/* + * This file was generated from rpcb_prot.x, but includes only those + * routines used with the rpcbind stats facility. + */ + +//#include + +#include +#include + +/* Link list of all the stats about getport and getaddr */ + +bool_t +xdr_rpcbs_addrlist(xdrs, objp) + XDR *xdrs; + rpcbs_addrlist *objp; +{ + + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_addrlist), + (xdrproc_t)xdr_rpcbs_addrlist)) { + return (FALSE); + } + + return (TRUE); +} + +/* Link list of all the stats about rmtcall */ + +bool_t +xdr_rpcbs_rmtcalllist(xdrs, objp) + XDR *xdrs; + rpcbs_rmtcalllist *objp; +{ + int32_t *buf; + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + } else { + IXDR_PUT_U_INT32(buf, objp->prog); + IXDR_PUT_U_INT32(buf, objp->vers); + IXDR_PUT_U_INT32(buf, objp->proc); + IXDR_PUT_INT32(buf, objp->success); + IXDR_PUT_INT32(buf, objp->failure); + IXDR_PUT_INT32(buf, objp->indirect); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + } else { + objp->prog = (rpcprog_t)IXDR_GET_U_INT32(buf); + objp->vers = (rpcvers_t)IXDR_GET_U_INT32(buf); + objp->proc = (rpcproc_t)IXDR_GET_U_INT32(buf); + objp->success = (int)IXDR_GET_INT32(buf); + objp->failure = (int)IXDR_GET_INT32(buf); + objp->indirect = (int)IXDR_GET_INT32(buf); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); + } + if (!xdr_u_int32_t(xdrs, &objp->prog)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->vers)) { + return (FALSE); + } + if (!xdr_u_int32_t(xdrs, &objp->proc)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->success)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->failure)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->indirect)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_proc(xdrs, objp) + XDR *xdrs; + rpcbs_proc objp; +{ + if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBSTAT_HIGHPROC, + sizeof (int), (xdrproc_t)xdr_int)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_addrlist_ptr(xdrs, objp) + XDR *xdrs; + rpcbs_addrlist_ptr *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_addrlist), + (xdrproc_t)xdr_rpcbs_addrlist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcbs_rmtcalllist_ptr(xdrs, objp) + XDR *xdrs; + rpcbs_rmtcalllist_ptr *objp; +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_rmtcalllist), + (xdrproc_t)xdr_rpcbs_rmtcalllist)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rpcb_stat(xdrs, objp) + XDR *xdrs; + rpcb_stat *objp; +{ + + if (!xdr_rpcbs_proc(xdrs, objp->info)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->setinfo)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->unsetinfo)) { + return (FALSE); + } + if (!xdr_rpcbs_addrlist_ptr(xdrs, &objp->addrinfo)) { + return (FALSE); + } + if (!xdr_rpcbs_rmtcalllist_ptr(xdrs, &objp->rmtinfo)) { + return (FALSE); + } + return (TRUE); +} + +/* + * One rpcb_stat structure is returned for each version of rpcbind + * being monitored. + */ +bool_t +xdr_rpcb_stat_byvers(xdrs, objp) + XDR *xdrs; + rpcb_stat_byvers objp; +{ + if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBVERS_STAT, + sizeof (rpcb_stat), (xdrproc_t)xdr_rpcb_stat)) { + return (FALSE); + } + return (TRUE); +} diff --git a/libtirpc/src/rpcdname.c b/libtirpc/src/rpcdname.c new file mode 100644 index 0000000..a843e0e --- /dev/null +++ b/libtirpc/src/rpcdname.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +//#include + +/* + * rpcdname.c + * Gets the default domain name + */ + +#include +#include +//#include +#include + +static char *default_domain = NULL; + +static char * +get_default_domain() +{ +#ifndef _WIN32 + char temp[256]; +#endif + + if (default_domain) + return (default_domain); +#ifndef _WIN32 // Need a WIN32 version? + if (getdomainname(temp, sizeof(temp)) < 0) + return (0); + if ((int) strlen(temp) > 0) { + default_domain = (char *)malloc((strlen(temp)+(unsigned)1)); + if (default_domain == 0) + return (NULL); + (void) strcpy(default_domain, temp); + return (default_domain); + } +#endif + return (NULL); +} + +/* + * This is a wrapper for the system call getdomainname which returns a + * ypclnt.h error code in the failure case. It also checks to see that + * the domain name is non-null, knowing that the null string is going to + * get rejected elsewhere in the NIS client package. + */ +int +__rpc_get_default_domain(domain) + char **domain; +{ + if ((*domain = get_default_domain()) != 0) + return (0); + return (-1); +} diff --git a/libtirpc/src/rtime.c b/libtirpc/src/rtime.c new file mode 100644 index 0000000..f933ff6 --- /dev/null +++ b/libtirpc/src/rtime.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + + */ + +/* + * rtime - get time from remote machine + * + * gets time, obtaining value from host + * on the udp/time socket. Since timeserver returns + * with time of day in seconds since Jan 1, 1900, must + * subtract seconds before Jan 1, 1970 to get + * what unix uses. + */ +#include +//#include +#include +#include +//#include +#include +#include +//#include +//#include +//#include +#include +//#include +//#include + +extern int _rpc_dtablesize( void ); + +#define NYEARS (unsigned long)(1970 - 1900) +#define TOFFSET (unsigned long)(60*60*24*(365*NYEARS + (NYEARS/4))) + +static void do_close( SOCKET ); + +int +rtime(addrp, timep, timeout) + struct sockaddr_in *addrp; + struct timeval *timep; + struct timeval *timeout; +{ + SOCKET s; + fd_set readfds; + int res; + unsigned long thetime; + struct sockaddr_in from; + int fromlen; + int type; + struct servent *serv; + + if (timeout == NULL) { + type = SOCK_STREAM; + } else { + type = SOCK_DGRAM; + } + s = socket(AF_INET, type, 0); + if (s == INVALID_SOCKET) { + return(-1); + } + addrp->sin_family = AF_INET; + + /* TCP and UDP port are the same in this case */ + if ((serv = getservbyname("time", "tcp")) == NULL) { + return(-1); + } + + addrp->sin_port = serv->s_port; + + if (type == SOCK_DGRAM) { + res = sendto(s, (char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)addrp, sizeof(*addrp)); + if (res == SOCKET_ERROR) { + do_close(s); + return(-1); + } + do { + FD_ZERO(&readfds); + FD_SET(s, &readfds); + res = select(_rpc_dtablesize(), &readfds, + (fd_set *)NULL, (fd_set *)NULL, timeout); + } while (res == SOCKET_ERROR && WSAGetLastError() == WSAEINTR); + if (res == 0 || res == SOCKET_ERROR) { + if (res == 0) { + errno = WSAETIMEDOUT; + } + do_close(s); + return(-1); + } + fromlen = sizeof(from); + res = recvfrom(s, (char *)&thetime, sizeof(thetime), 0, + (struct sockaddr *)&from, &fromlen); + do_close(s); + if (res == SOCKET_ERROR) { + return(-1); + } + } else { + if (connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) == SOCKET_ERROR) { + do_close(s); + return(-1); + } + res = recv(s, (char *)&thetime, sizeof(thetime), 0); + do_close(s); + if (res == SOCKET_ERROR) { + return(-1); + } + } + if (res != sizeof(thetime)) { + errno = EIO; + return(-1); + } + thetime = ntohl(thetime); + timep->tv_sec = thetime - TOFFSET; + timep->tv_usec = 0; + return(0); +} + +static void +do_close(s) + int s; +{ + int save; + + save = errno; + (void)closesocket(s); + errno = save; +} diff --git a/libtirpc/src/sources b/libtirpc/src/sources new file mode 100644 index 0000000..0167b9b --- /dev/null +++ b/libtirpc/src/sources @@ -0,0 +1,106 @@ +TARGETTYPE=DYNLINK +TARGETNAME=libtirpc +SOURCES=\ + asprintf.c \ + auth_none.c \ + auth_time.c \ + auth_unix.c \ + authunix_prot.c \ + bindresvport.c \ + clnt_bcast.c \ + clnt_dg.c \ + clnt_generic.c \ + clnt_perror.c \ + clnt_raw.c \ + clnt_simple.c \ + clnt_vc.c \ + des_soft.c \ + epoll_sub.c \ + getnetconfig.c \ + getnetpath.c \ + getpeereid.c \ + getpublickey.c \ + getrpcent.c \ + getrpcport.c \ + gettimeofday.c \ + key_call.c \ + key_prot_xdr.c \ + mt_misc.c \ + netname.c \ + netnamer.c \ + pmap_clnt.c \ + pmap_getmaps.c \ + pmap_getport.c \ + pmap_prot.c \ + pmap_prot2.c \ + pmap_rmt.c \ + rpc_callmsg.c \ + rpc_commondata.c \ + rpc_dtablesize.c \ + rpc_generic.c \ + rpc_prot.c \ + rpc_soc.c \ + rpcb_clnt.c \ + rpcb_prot.c \ + rpcb_st_xdr.c \ + rpcdname.c \ + rtime.c \ + svc.c \ + svc_auth.c \ + svc_auth_none.c \ + svc_auth_unix.c \ + svc_dg.c \ + svc_generic.c \ + svc_raw.c \ + svc_run.c \ + svc_simple.c \ + svc_vc.c \ + winstubs.c \ + wintirpc.c \ + xdr.c \ + xdr_array.c \ + xdr_float.c \ + xdr_mem.c \ + xdr_rec.c \ + xdr_reference.c \ + xdr_sizeof.c \ + xdr_stdio.c + +# crypt_client.c \ +# des_crypt.c \ +# svc_auth_sspi.c \ +# auth_sspi.c \ +# auth_des.c \ +# authdes_prot.c \ +# authgss_prot.c \ + +UMTYPE=console +UNICODE=1 +DLLBASE=0x1010000 +#USE_NTDLL=1 +#USE_MSVCRT=1 +USE_LIBCMT=1 +NET_C_DEFINES=-DUNICODE -DINET6 -D_WIN32 -DPORTMAP + +INCLUDES=..\sys; \ + ..\tirpc; \ + $(SDK_INC_PATH); + +TARGETLIBS=$(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ + $(SDK_LIB_PATH)\Advapi32.lib + + +DLLDEF=..\libtirpc\libtirpc.def +#DLLENTRY=tirpc_main + +!IF 0 +/W3 is default level +bump to /Wall, but suppress warnings generated by system includes, +as well as the following warnings: +4100 - unused function call arguments (we have lots of stubs) +4127 - constant conditional (I like to use if(0) or if(1)) +MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4711 +!ENDIF +MSC_WARNING_LEVEL=/W3 diff --git a/libtirpc/src/svc.c b/libtirpc/src/svc.c new file mode 100644 index 0000000..1666364 --- /dev/null +++ b/libtirpc/src/svc.c @@ -0,0 +1,803 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * svc.c, Server-side remote procedure call interface. + * + * There are two sets of procedures here. The xprt routines are + * for handling transport handles. The svc routines handle the + * list of service routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#include +//#include + +#include +#include +//#include +#include +#include +#include +#include + +#include +#ifdef PORTMAP +#include +#endif /* PORTMAP */ + +#include "rpc_com.h" + +#define RQCRED_SIZE 400 /* this size is excessive */ + +#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ +#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) + +#ifndef max +#define max(a, b) (a > b ? a : b) +#endif + +/* + * The services list + * Each entry represents a set of procedures (an rpc program). + * The dispatch routine takes request structs and runs the + * apropriate procedure. + */ +static struct svc_callout +{ + struct svc_callout *sc_next; + rpcprog_t sc_prog; + rpcvers_t sc_vers; + char *sc_netid; + void (*sc_dispatch) (struct svc_req *, SVCXPRT *); +} *svc_head; + +extern rwlock_t svc_lock; +extern rwlock_t svc_fd_lock; +#ifdef HAVE_LIBGSSAPI +extern struct svc_auth_ops svc_auth_gss_ops; +#endif + +static struct svc_callout *svc_find (rpcprog_t, rpcvers_t, + struct svc_callout **, char *); +static void __xprt_do_unregister (SVCXPRT * xprt, bool_t dolock); + +/* *************** SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register (xprt) + SVCXPRT *xprt; +{ + SOCKET sock; + + assert (xprt != NULL); + + sock = xprt->xp_fd; + + rwlock_wrlock (&svc_fd_lock); + if (__svc_xports == NULL) { + __svc_xports = (SVCXPRT **) mem_alloc (FD_SETSIZE * sizeof (SVCXPRT *)); + if (__svc_xports == NULL) { + // XXX Give an error indication? + return; + } + memset (__svc_xports, 0, FD_SETSIZE * sizeof (SVCXPRT *)); + } +#ifndef _WIN32 + if (sock < FD_SETSIZE) { + __svc_xports[sock] = xprt; + FD_SET (sock, &svc_fdset); + svc_maxfd = max (svc_maxfd, sock); + } +#else + fprintf(stderr, "%s: Yikes! Figure out __svc_xports[] issue!!\n", __FUNCTION__); +#endif + rwlock_unlock (&svc_fd_lock); +} + +void +xprt_unregister (SVCXPRT * xprt) +{ + __xprt_do_unregister (xprt, TRUE); +} + +void +__xprt_unregister_unlocked (SVCXPRT * xprt) +{ + __xprt_do_unregister (xprt, FALSE); +} + +/* + * De-activate a transport handle. + */ +static void +__xprt_do_unregister (xprt, dolock) +SVCXPRT *xprt; +bool_t dolock; +{ + SOCKET sock; + + assert (xprt != NULL); + + sock = xprt->xp_fd; + +#ifndef _WIN32 + if (dolock) + rwlock_wrlock (&svc_fd_lock); + if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { + __svc_xports[sock] = NULL; + FD_CLR (sock, &svc_fdset); + if (sock >= svc_maxfd) { + for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--) + if (__svc_xports[svc_maxfd]) + break; + } + } + if (dolock) + rwlock_unlock (&svc_fd_lock); +#else + fprintf(stderr, "%s: Yikes! Figure out __svc_xports[] issue!!\n", __FUNCTION__); +#endif +} + +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_reg (xprt, prog, vers, dispatch, nconf) + SVCXPRT *xprt; + const rpcprog_t prog; + const rpcvers_t vers; + void (*dispatch) (struct svc_req *, SVCXPRT *); + const struct netconfig *nconf; +{ + bool_t dummy; + struct svc_callout *prev; + struct svc_callout *s; + struct netconfig *tnconf; + char *netid = NULL; + int flag = 0; + +/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ + if (xprt->xp_netid) + { + netid = strdup (xprt->xp_netid); + flag = 1; + } + else if (nconf && nconf->nc_netid) + { + netid = strdup (nconf->nc_netid); + flag = 1; + } + else if ((tnconf = __rpcgettp (xprt->xp_fd)) != NULL) + { + netid = strdup (tnconf->nc_netid); + flag = 1; + freenetconfigent (tnconf); + } /* must have been created with svc_raw_create */ + if ((netid == NULL) && (flag == 1)) + { + return (FALSE); + } + + rwlock_wrlock (&svc_lock); + if ((s = svc_find (prog, vers, &prev, netid)) != NULL) + { + if (netid) + free (netid); + if (s->sc_dispatch == dispatch) + goto rpcb_it; /* he is registering another xptr */ + rwlock_unlock (&svc_lock); + return (FALSE); + } + s = mem_alloc (sizeof (struct svc_callout)); + if (s == NULL) + { + if (netid) + free (netid); + rwlock_unlock (&svc_lock); + return (FALSE); + } + + s->sc_prog = prog; + s->sc_vers = vers; + s->sc_dispatch = dispatch; + s->sc_netid = netid; + s->sc_next = svc_head; + svc_head = s; + + if ((xprt->xp_netid == NULL) && (flag == 1) && netid) + ((SVCXPRT *) xprt)->xp_netid = strdup (netid); + +rpcb_it: + rwlock_unlock (&svc_lock); + /* now register the information with the local binder service */ + if (nconf) + { + /*LINTED const castaway */ + dummy = rpcb_set (prog, vers, (struct netconfig *) nconf, + &((SVCXPRT *) xprt)->xp_ltaddr); + return (dummy); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unreg (prog, vers) + const rpcprog_t prog; + const rpcvers_t vers; +{ + struct svc_callout *prev; + struct svc_callout *s; + + /* unregister the information anyway */ + (void) rpcb_unset (prog, vers, NULL); + rwlock_wrlock (&svc_lock); + while ((s = svc_find (prog, vers, &prev, NULL)) != NULL) + { + if (prev == NULL) + { + svc_head = s->sc_next; + } + else + { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL; + if (s->sc_netid) + mem_free (s->sc_netid, sizeof (s->sc_netid) + 1); + mem_free (s, sizeof (struct svc_callout)); + } + rwlock_unlock (&svc_lock); +} + +/* ********************** CALLOUT list related stuff ************* */ + +#ifdef PORTMAP +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_register (xprt, prog, vers, dispatch, protocol) + SVCXPRT *xprt; + u_long prog; + u_long vers; + void (*dispatch) (struct svc_req *, SVCXPRT *); + int protocol; +{ + struct svc_callout *prev; + struct svc_callout *s; + + assert (xprt != NULL); + assert (dispatch != NULL); + + if ((s = svc_find ((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL)) != + NULL) + { + if (s->sc_dispatch == dispatch) + goto pmap_it; /* he is registering another xptr */ + return (FALSE); + } + s = mem_alloc (sizeof (struct svc_callout)); + if (s == NULL) + { + return (FALSE); + } + s->sc_prog = (rpcprog_t) prog; + s->sc_vers = (rpcvers_t) vers; + s->sc_dispatch = dispatch; + s->sc_next = svc_head; + svc_head = s; +pmap_it: + /* now register the information with the local binder service */ + if (protocol) + { + return (pmap_set (prog, vers, protocol, xprt->xp_port)); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unregister (prog, vers) + u_long prog; + u_long vers; +{ + struct svc_callout *prev; + struct svc_callout *s; + + if ((s = svc_find ((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL)) == + NULL) + return; + if (prev == NULL) + { + svc_head = s->sc_next; + } + else + { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL; + mem_free (s, sizeof (struct svc_callout)); + /* now unregister the information with the local binder service */ + (void) pmap_unset (prog, vers); +} +#endif /* PORTMAP */ + +/* + * Search the callout list for a program number, return the callout + * struct. + */ +static struct svc_callout * +svc_find (prog, vers, prev, netid) + rpcprog_t prog; + rpcvers_t vers; + struct svc_callout **prev; + char *netid; +{ + struct svc_callout *s, *p; + + assert (prev != NULL); + + p = NULL; + for (s = svc_head; s != NULL; s = s->sc_next) + { + if (((s->sc_prog == prog) && (s->sc_vers == vers)) && + ((netid == NULL) || (s->sc_netid == NULL) || + (strcmp (netid, s->sc_netid) == 0))) + break; + p = s; + } + *prev = p; + return (s); +} + +/* ******************* REPLY GENERATION ROUTINES ************ */ + +/* + * Send a reply to an rpc request + */ +bool_t +svc_sendreply (xprt, xdr_results, xdr_location) + SVCXPRT *xprt; + xdrproc_t xdr_results; + void *xdr_location; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SUCCESS; + rply.acpted_rply.ar_results.where = xdr_location; + rply.acpted_rply.ar_results.proc = xdr_results; + return (SVC_REPLY (xprt, &rply)); +} + +/* + * No procedure error reply + */ +void +svcerr_noproc (xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROC_UNAVAIL; + SVC_REPLY (xprt, &rply); +} + +/* + * Can't decode args error reply + */ +void +svcerr_decode (xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = GARBAGE_ARGS; + SVC_REPLY (xprt, &rply); +} + +/* + * Some system error + */ +void +svcerr_systemerr (xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SYSTEM_ERR; + SVC_REPLY (xprt, &rply); +} + +#if 0 +/* + * Tell RPC package to not complain about version errors to the client. This + * is useful when revving broadcast protocols that sit on a fixed address. + * There is really one (or should be only one) example of this kind of + * protocol: the portmapper (or rpc binder). + */ +void +__svc_versquiet_on (xprt) + SVCXPRT *xprt; +{ + u_long tmp; + + tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; + xprt->xp_p3 = tmp; +} + +void +__svc_versquiet_off (xprt) + SVCXPRT *xprt; +{ + u_long tmp; + + tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; + xprt->xp_p3 = tmp; +} + +void +svc_versquiet (xprt) + SVCXPRT *xprt; +{ + __svc_versquiet_on (xprt); +} + +int +__svc_versquiet_get (xprt) + SVCXPRT *xprt; +{ + return ((int) xprt->xp_p3) & SVC_VERSQUIET; +} +#endif + +/* + * Authentication error reply + */ +void +svcerr_auth (xprt, why) + SVCXPRT *xprt; + enum auth_stat why; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_DENIED; + rply.rjcted_rply.rj_stat = AUTH_ERROR; + rply.rjcted_rply.rj_why = why; + SVC_REPLY (xprt, &rply); +} + +/* + * Auth too weak error reply + */ +void +svcerr_weakauth (xprt) + SVCXPRT *xprt; +{ + + assert (xprt != NULL); + + svcerr_auth (xprt, AUTH_TOOWEAK); +} + +/* + * Program unavailable error reply + */ +void +svcerr_noprog (xprt) + SVCXPRT *xprt; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_UNAVAIL; + SVC_REPLY (xprt, &rply); +} + +/* + * Program version mismatch error reply + */ +void +svcerr_progvers (xprt, low_vers, high_vers) + SVCXPRT *xprt; + rpcvers_t low_vers; + rpcvers_t high_vers; +{ + struct rpc_msg rply; + + assert (xprt != NULL); + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_MISMATCH; + rply.acpted_rply.ar_vers.low = (u_int32_t) low_vers; + rply.acpted_rply.ar_vers.high = (u_int32_t) high_vers; + SVC_REPLY (xprt, &rply); +} + +/* ******************* SERVER INPUT STUFF ******************* */ + +/* + * Get server side input from some transport. + * + * Statement of authentication parameters management: + * This function owns and manages all authentication parameters, specifically + * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and + * the "cooked" credentials (rqst->rq_clntcred). + * However, this function does not know the structure of the cooked + * credentials, so it make the following assumptions: + * a) the structure is contiguous (no pointers), and + * b) the cred structure size does not exceed RQCRED_SIZE bytes. + * In all events, all three parameters are freed upon exit from this routine. + * The storage is trivially management on the call stack in user land, but + * is mallocated in kernel land. + */ + +void +svc_getreq (rdfds) + int rdfds; +{ + fd_set readfds; + + FD_ZERO (&readfds); + //XXX Windows!! readfds.fds_bits[0] = rdfds; + svc_getreqset (&readfds); +} + +void +svc_getreqset (readfds) + fd_set *readfds; +{ +#ifndef _WIN32 + int bit, fd; + fd_mask mask, *maskp; + int sock; + + assert (readfds != NULL); + + maskp = readfds->fds_bits; + for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) + { + for (mask = *maskp++; (bit = ffs (mask)) != 0; mask ^= (1 << (bit - 1))) + { + /* sock has input waiting */ + fd = sock + bit - 1; + svc_getreq_common (fd); + } + } +#else + fprintf(stderr, "%s: Yikes!\n", __FUNCTION__); +#endif +} + +void +svc_getreq_common (SOCKET fd) +{ + SVCXPRT *xprt; + struct svc_req r; + struct rpc_msg msg; + int prog_found; + rpcvers_t low_vers; + rpcvers_t high_vers; + enum xprt_stat stat; + char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE]; + + msg.rm_call.cb_cred.oa_base = cred_area; + msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); + r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]); + + rwlock_rdlock (&svc_fd_lock); + xprt = __svc_xports[fd]; + rwlock_unlock (&svc_fd_lock); + if (xprt == NULL) + /* But do we control sock? */ + return; + /* now receive msgs from xprtprt (support batch calls) */ + do + { + if (SVC_RECV (xprt, &msg)) + { + + /* now find the exported program and call it */ + struct svc_callout *s; + enum auth_stat why; + + r.rq_xprt = xprt; + r.rq_prog = msg.rm_call.cb_prog; + r.rq_vers = msg.rm_call.cb_vers; + r.rq_proc = msg.rm_call.cb_proc; + r.rq_cred = msg.rm_call.cb_cred; + /* first authenticate the message */ + if ((why = _authenticate (&r, &msg)) != AUTH_OK) + { + svcerr_auth (xprt, why); + goto call_done; + } + /* now match message with a registered service */ + prog_found = FALSE; + low_vers = (rpcvers_t) - 1L; + high_vers = (rpcvers_t) 0L; + for (s = svc_head; s != NULL; s = s->sc_next) + { + if (s->sc_prog == r.rq_prog) + { + if (s->sc_vers == r.rq_vers) + { + (*s->sc_dispatch) (&r, xprt); + goto call_done; + } /* found correct version */ + prog_found = TRUE; + if (s->sc_vers < low_vers) + low_vers = s->sc_vers; + if (s->sc_vers > high_vers) + high_vers = s->sc_vers; + } /* found correct program */ + } + /* + * if we got here, the program or version + * is not served ... + */ + if (prog_found) + svcerr_progvers (xprt, low_vers, high_vers); + else + svcerr_noprog (xprt); + /* Fall through to ... */ + } + /* + * Check if the xprt has been disconnected in a + * recursive call in the service dispatch routine. + * If so, then break. + */ + rwlock_rdlock (&svc_fd_lock); + + if (xprt != __svc_xports[fd]) + { + rwlock_unlock (&svc_fd_lock); + break; + } + rwlock_unlock (&svc_fd_lock); + call_done: + if ((stat = SVC_STAT (xprt)) == XPRT_DIED) + { + SVC_DESTROY (xprt); + break; + } + else if ((xprt->xp_auth != NULL) +#ifdef HAVE_LIBGSSAPI + && (xprt->xp_auth->svc_ah_ops != &svc_auth_gss_ops) +#endif + ) { + xprt->xp_auth = NULL; + } + } + while (stat == XPRT_MOREREQS); +} + + +void +svc_getreq_poll (pfdp, pollretval) + struct pollfd *pfdp; + int pollretval; +{ + int i; + int fds_found; + + for (i = fds_found = 0; fds_found < pollretval; i++) + { + struct pollfd *p = &pfdp[i]; + + if (p->revents) + { + /* fd has input waiting */ + fds_found++; + /* + * We assume that this function is only called + * via someone _select()ing from svc_fdset or + * _poll()ing from svc_pollset[]. Thus it's safe + * to handle the POLLNVAL event by simply turning + * the corresponding bit off in svc_fdset. The + * svc_pollset[] array is derived from svc_fdset + * and so will also be updated eventually. + * + * XXX Should we do an xprt_unregister() instead? + */ + if (p->revents & POLLNVAL) + { + rwlock_wrlock (&svc_fd_lock); + FD_CLR (p->fd, &svc_fdset); + rwlock_unlock (&svc_fd_lock); + } + else + svc_getreq_common (p->fd); + } + } +} + +bool_t +rpc_control (int what, void *arg) +{ + int val; + + switch (what) + { + case RPC_SVC_CONNMAXREC_SET: + val = *(int *) arg; + if (val <= 0) + return FALSE; + __svc_maxrec = val; + return TRUE; + case RPC_SVC_CONNMAXREC_GET: + *(int *) arg = __svc_maxrec; + return TRUE; + default: + break; + } + return FALSE; +} diff --git a/libtirpc/src/svc_auth.c b/libtirpc/src/svc_auth.c new file mode 100644 index 0000000..ac6b7ed --- /dev/null +++ b/libtirpc/src/svc_auth.c @@ -0,0 +1,201 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * svc_auth.c, Server-side rpc authenticator interface. + * + */ +#include +//#include +#include +#include +#include +#include + +/* + * svcauthsw is the bdevsw of server side authentication. + * + * Server side authenticators are called from authenticate by + * using the client auth struct flavor field to index into svcauthsw. + * The server auth flavors must implement a routine that looks + * like: + * + * enum auth_stat + * flavorx_auth(rqst, msg) + * struct svc_req *rqst; + * struct rpc_msg *msg; + * + */ + +/* declarations to allow servers to specify new authentication flavors */ +struct authsvc { + int flavor; + enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *); + struct authsvc *next; +}; +static struct authsvc *Auths = NULL; + +/* + * The call rpc message, msg has been obtained from the wire. The msg contains + * the raw form of credentials and verifiers. authenticate returns AUTH_OK + * if the msg is successfully authenticated. If AUTH_OK then the routine also + * does the following things: + * set rqst->rq_xprt->verf to the appropriate response verifier; + * sets rqst->rq_client_cred to the "cooked" form of the credentials. + * + * NB: rqst->rq_cxprt->verf must be pre-alloctaed; + * its length is set appropriately. + * + * The caller still owns and is responsible for msg->u.cmb.cred and + * msg->u.cmb.verf. The authentication system retains ownership of + * rqst->rq_client_cred, the cooked credentials. + * + * There is an assumption that any flavour less than AUTH_NULL is + * invalid. + */ +enum auth_stat +_authenticate(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + int cred_flavor; + struct authsvc *asp; + enum auth_stat dummy; + extern mutex_t authsvc_lock; + +/* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */ + + rqst->rq_cred = msg->rm_call.cb_cred; + rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; + rqst->rq_xprt->xp_verf.oa_length = 0; + cred_flavor = rqst->rq_cred.oa_flavor; + switch (cred_flavor) { + case AUTH_NULL: + dummy = _svcauth_null(rqst, msg); + return (dummy); + case AUTH_SYS: + dummy = _svcauth_unix(rqst, msg); + return (dummy); + case AUTH_SHORT: + dummy = _svcauth_short(rqst, msg); + return (dummy); +#ifdef DES_BUILTIN + case AUTH_DES: + dummy = _svcauth_des(rqst, msg); + return (dummy); +#endif + default: + break; + } + + /* flavor doesn't match any of the builtin types, so try new ones */ + mutex_lock(&authsvc_lock); + for (asp = Auths; asp; asp = asp->next) { + if (asp->flavor == cred_flavor) { + enum auth_stat as; + + as = (*asp->handler)(rqst, msg); + mutex_unlock(&authsvc_lock); + return (as); + } + } + mutex_unlock(&authsvc_lock); + + return (AUTH_REJECTEDCRED); +} + +/*ARGSUSED*/ +enum auth_stat +_svcauth_null(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + return (AUTH_OK); +} + +/* + * Allow the rpc service to register new authentication types that it is + * prepared to handle. When an authentication flavor is registered, + * the flavor is checked against already registered values. If not + * registered, then a new Auths entry is added on the list. + * + * There is no provision to delete a registration once registered. + * + * This routine returns: + * 0 if registration successful + * 1 if flavor already registered + * -1 if can't register (errno set) + */ + +int +svc_auth_reg(cred_flavor, handler) + int cred_flavor; + enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *); +{ + struct authsvc *asp; + extern mutex_t authsvc_lock; + + switch (cred_flavor) { + case AUTH_NULL: + case AUTH_SYS: + case AUTH_SHORT: +#ifdef DES_BUILTIN + case AUTH_DES: +#endif + /* already registered */ + return (1); + + default: + mutex_lock(&authsvc_lock); + for (asp = Auths; asp; asp = asp->next) { + if (asp->flavor == cred_flavor) { + /* already registered */ + mutex_unlock(&authsvc_lock); + return (1); + } + } + + /* this is a new one, so go ahead and register it */ + asp = mem_alloc(sizeof (*asp)); + if (asp == NULL) { + mutex_unlock(&authsvc_lock); + return (-1); + } + asp->flavor = cred_flavor; + asp->handler = handler; + asp->next = Auths; + Auths = asp; + mutex_unlock(&authsvc_lock); + break; + } + return (0); +} diff --git a/libtirpc/src/svc_auth_des.c b/libtirpc/src/svc_auth_des.c new file mode 100644 index 0000000..75736a6 --- /dev/null +++ b/libtirpc/src/svc_auth_des.c @@ -0,0 +1,531 @@ + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * svcauth_des.c, server-side des authentication + * + * We insure for the service the following: + * (1) The timestamp microseconds do not exceed 1 million. + * (2) The timestamp plus the window is less than the current time. + * (3) The timestamp is not less than the one previously + * seen in the current session. + * + * It is up to the server to determine if the window size is + * too small . + * + */ +#include +//#include +#include +#include +#include +#include +//#include +#include +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int key_decryptsession_pk(const char *, netobj *, des_block *); + +#define debug(msg) printf("svcauth_des: %s\n", msg) + +#define USEC_PER_SEC ((u_long) 1000000L) +#define BEFORE(t1, t2) timercmp(t1, t2, <) + +/* + * LRU cache of conversation keys and some other useful items. + */ +#define AUTHDES_CACHESZ 64 +struct cache_entry { + des_block key; /* conversation key */ + char *rname; /* client's name */ + u_int window; /* credential lifetime window */ + struct timeval laststamp; /* detect replays of creds */ + char *localcred; /* generic local credential */ +}; +static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */; +static short *authdes_lru/* [AUTHDES_CACHESZ] */; + +static void cache_init(); /* initialize the cache */ +static short cache_spot(); /* find an entry in the cache */ +static void cache_ref(/*short sid*/); /* note that sid was ref'd */ + +static void invalidate(); /* invalidate entry in cache */ + +/* + * cache statistics + */ +static struct { + u_long ncachehits; /* times cache hit, and is not replay */ + u_long ncachereplays; /* times cache hit, and is replay */ + u_long ncachemisses; /* times cache missed */ +} svcauthdes_stats; + +/* + * Service side authenticator for AUTH_DES + */ +enum auth_stat +_svcauth_des(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + + long *ixdr; + des_block cryptbuf[2]; + struct authdes_cred *cred; + struct authdes_verf verf; + int status; + struct cache_entry *entry; + short sid = 0; + des_block *sessionkey; + des_block ivec; + u_int window; + struct timeval timestamp; + u_long namelen; + struct area { + struct authdes_cred area_cred; + char area_netname[MAXNETNAMELEN+1]; + } *area; + + if (authdes_cache == NULL) { + cache_init(); + } + + area = (struct area *)rqst->rq_clntcred; + cred = (struct authdes_cred *)&area->area_cred; + + /* + * Get the credential + */ + ixdr = (long *)msg->rm_call.cb_cred.oa_base; + cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind); + switch (cred->adc_namekind) { + case ADN_FULLNAME: + namelen = IXDR_GET_U_LONG(ixdr); + if (namelen > MAXNETNAMELEN) { + return (AUTH_BADCRED); + } + cred->adc_fullname.name = area->area_netname; + bcopy((char *)ixdr, cred->adc_fullname.name, + (u_int)namelen); + cred->adc_fullname.name[namelen] = 0; + ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT); + cred->adc_fullname.key.key.high = (u_long)*ixdr++; + cred->adc_fullname.key.key.low = (u_long)*ixdr++; + cred->adc_fullname.window = (u_long)*ixdr++; + break; + case ADN_NICKNAME: + cred->adc_nickname = (u_long)*ixdr++; + break; + default: + return (AUTH_BADCRED); + } + + /* + * Get the verifier + */ + ixdr = (long *)msg->rm_call.cb_verf.oa_base; + verf.adv_xtimestamp.key.high = (u_long)*ixdr++; + verf.adv_xtimestamp.key.low = (u_long)*ixdr++; + verf.adv_int_u = (u_long)*ixdr++; + + + /* + * Get the conversation key + */ + if (cred->adc_namekind == ADN_FULLNAME) { + netobj pkey; + char pkey_data[1024]; + + sessionkey = &cred->adc_fullname.key; + if (! getpublickey(cred->adc_fullname.name, pkey_data)) { + debug("getpublickey"); + return(AUTH_BADCRED); + } + pkey.n_bytes = pkey_data; + pkey.n_len = strlen(pkey_data) + 1; + if (key_decryptsession_pk(cred->adc_fullname.name, &pkey, + sessionkey) < 0) { + debug("decryptsessionkey"); + return (AUTH_BADCRED); /* key not found */ + } + } else { /* ADN_NICKNAME */ + sid = (short)cred->adc_nickname; + if (sid < 0 || sid >= AUTHDES_CACHESZ) { + debug("bad nickname"); + return (AUTH_BADCRED); /* garbled credential */ + } + sessionkey = &authdes_cache[sid].key; + } + + + /* + * Decrypt the timestamp + */ + cryptbuf[0] = verf.adv_xtimestamp; + if (cred->adc_namekind == ADN_FULLNAME) { + cryptbuf[1].key.high = cred->adc_fullname.window; + cryptbuf[1].key.low = verf.adv_winverf; + ivec.key.high = ivec.key.low = 0; + status = cbc_crypt((char *)sessionkey, (char *)cryptbuf, + 2*sizeof(des_block), DES_DECRYPT | DES_HW, + (char *)&ivec); + } else { + status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, + sizeof(des_block), DES_DECRYPT | DES_HW); + } + if (DES_FAILED(status)) { + debug("decryption failure"); + return (AUTH_FAILED); /* system error */ + } + + /* + * XDR the decrypted timestamp + */ + ixdr = (long *)cryptbuf; + timestamp.tv_sec = IXDR_GET_LONG(ixdr); + timestamp.tv_usec = IXDR_GET_LONG(ixdr); + + /* + * Check for valid credentials and verifiers. + * They could be invalid because the key was flushed + * out of the cache, and so a new session should begin. + * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case. + */ + { + struct timeval current; + int nick; + int winverf; + + if (cred->adc_namekind == ADN_FULLNAME) { + window = IXDR_GET_U_LONG(ixdr); + winverf = IXDR_GET_U_LONG(ixdr); + if (winverf != window - 1) { + debug("window verifier mismatch"); + return (AUTH_BADCRED); /* garbled credential */ + } + sid = cache_spot(sessionkey, cred->adc_fullname.name, + ×tamp); + if (sid < 0) { + debug("replayed credential"); + return (AUTH_REJECTEDCRED); /* replay */ + } + nick = 0; + } else { /* ADN_NICKNAME */ + window = authdes_cache[sid].window; + nick = 1; + } + + if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) { + debug("invalid usecs"); + /* cached out (bad key), or garbled verifier */ + return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF); + } + if (nick && BEFORE(×tamp, + &authdes_cache[sid].laststamp)) { + debug("timestamp before last seen"); + return (AUTH_REJECTEDVERF); /* replay */ + } + (void) gettimeofday(¤t, (struct timezone *)NULL); + current.tv_sec -= window; /* allow for expiration */ + if (!BEFORE(¤t, ×tamp)) { + debug("timestamp expired"); + /* replay, or garbled credential */ + return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED); + } + } + + /* + * Set up the reply verifier + */ + verf.adv_nickname = (u_long)sid; + + /* + * xdr the timestamp before encrypting + */ + ixdr = (long *)cryptbuf; + IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1); + IXDR_PUT_LONG(ixdr, timestamp.tv_usec); + + /* + * encrypt the timestamp + */ + status = ecb_crypt((char *)sessionkey, (char *)cryptbuf, + sizeof(des_block), DES_ENCRYPT | DES_HW); + if (DES_FAILED(status)) { + debug("encryption failure"); + return (AUTH_FAILED); /* system error */ + } + verf.adv_xtimestamp = cryptbuf[0]; + + /* + * Serialize the reply verifier, and update rqst + */ + ixdr = (long *)msg->rm_call.cb_verf.oa_base; + *ixdr++ = (long)verf.adv_xtimestamp.key.high; + *ixdr++ = (long)verf.adv_xtimestamp.key.low; + *ixdr++ = (long)verf.adv_int_u; + + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES; + rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; + rqst->rq_xprt->xp_verf.oa_length = + (char *)ixdr - msg->rm_call.cb_verf.oa_base; + + /* + * We succeeded, commit the data to the cache now and + * finish cooking the credential. + */ + entry = &authdes_cache[sid]; + entry->laststamp = timestamp; + cache_ref(sid); + if (cred->adc_namekind == ADN_FULLNAME) { + cred->adc_fullname.window = window; + cred->adc_nickname = (u_long)sid; /* save nickname */ + if (entry->rname != NULL) { + mem_free(entry->rname, strlen(entry->rname) + 1); + } + entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name) + + 1); + if (entry->rname != NULL) { + (void) strcpy(entry->rname, cred->adc_fullname.name); + } else { + debug("out of memory"); + } + entry->key = *sessionkey; + entry->window = window; + invalidate(entry->localcred); /* mark any cached cred invalid */ + } else { /* ADN_NICKNAME */ + /* + * nicknames are cooked into fullnames + */ + cred->adc_namekind = ADN_FULLNAME; + cred->adc_fullname.name = entry->rname; + cred->adc_fullname.key = entry->key; + cred->adc_fullname.window = entry->window; + } + return (AUTH_OK); /* we made it!*/ +} + + +/* + * Initialize the cache + */ +static void +cache_init() +{ + int i; + + authdes_cache = (struct cache_entry *) + mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ); + bzero((char *)authdes_cache, + sizeof(struct cache_entry) * AUTHDES_CACHESZ); + + authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ); + /* + * Initialize the lru list + */ + for (i = 0; i < AUTHDES_CACHESZ; i++) { + authdes_lru[i] = i; + } +} + + +/* + * Find the lru victim + */ +static short +cache_victim() +{ + return (authdes_lru[AUTHDES_CACHESZ-1]); +} + +/* + * Note that sid was referenced + */ +static void +cache_ref(sid) + short sid; +{ + int i; + short curr; + short prev; + + prev = authdes_lru[0]; + authdes_lru[0] = sid; + for (i = 1; prev != sid; i++) { + curr = authdes_lru[i]; + authdes_lru[i] = prev; + prev = curr; + } +} + + +/* + * Find a spot in the cache for a credential containing + * the items given. Return -1 if a replay is detected, otherwise + * return the spot in the cache. + */ +static short +cache_spot(key, name, timestamp) + des_block *key; + char *name; + struct timeval *timestamp; +{ + struct cache_entry *cp; + int i; + u_long hi; + + hi = key->key.high; + for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) { + if (cp->key.key.high == hi && + cp->key.key.low == key->key.low && + cp->rname != NULL && + bcmp(cp->rname, name, strlen(name) + 1) == 0) { + if (BEFORE(timestamp, &cp->laststamp)) { + svcauthdes_stats.ncachereplays++; + return (-1); /* replay */ + } + svcauthdes_stats.ncachehits++; + return (i); /* refresh */ + } + } + svcauthdes_stats.ncachemisses++; + return (cache_victim()); /* new credential */ +} + + +#if (defined(sun) || defined(vax) || defined(__FreeBSD__)) +/* + * Local credential handling stuff. + * NOTE: bsd unix dependent. + * Other operating systems should put something else here. + */ +#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */ +#define INVALID -1 /* grouplen, if cache entry is invalid */ + +struct bsdcred { + short uid; /* cached uid */ + short gid; /* cached gid */ + short grouplen; /* length of cached groups */ + short groups[NGROUPS]; /* cached groups */ +}; + +/* + * Map a des credential into a unix cred. + * We cache the credential here so the application does + * not have to make an rpc call every time to interpret + * the credential. + */ +int +authdes_getucred(adc, uid, gid, grouplen, groups) + struct authdes_cred *adc; + uid_t *uid; + gid_t *gid; + int *grouplen; + gid_t *groups; +{ + unsigned sid; + int i; + uid_t i_uid; + gid_t i_gid; + int i_grouplen; + struct bsdcred *cred; + + sid = adc->adc_nickname; + if (sid >= AUTHDES_CACHESZ) { + debug("invalid nickname"); + return (0); + } + cred = (struct bsdcred *)authdes_cache[sid].localcred; + if (cred == NULL) { + cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred)); + authdes_cache[sid].localcred = (char *)cred; + cred->grouplen = INVALID; + } + if (cred->grouplen == INVALID) { + /* + * not in cache: lookup + */ + if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, + &i_grouplen, groups)) + { + debug("unknown netname"); + cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */ + return (0); + } + debug("missed ucred cache"); + *uid = cred->uid = i_uid; + *gid = cred->gid = i_gid; + *grouplen = cred->grouplen = i_grouplen; + for (i = i_grouplen - 1; i >= 0; i--) { + cred->groups[i] = groups[i]; /* int to short */ + } + return (1); + } else if (cred->grouplen == UNKNOWN) { + /* + * Already lookup up, but no match found + */ + return (0); + } + + /* + * cached credentials + */ + *uid = cred->uid; + *gid = cred->gid; + *grouplen = cred->grouplen; + for (i = cred->grouplen - 1; i >= 0; i--) { + groups[i] = cred->groups[i]; /* short to int */ + } + return (1); +} + +static void +invalidate(cred) + char *cred; +{ + if (cred == NULL) { + return; + } + ((struct bsdcred *)cred)->grouplen = INVALID; +} +#endif + diff --git a/libtirpc/src/svc_auth_gss.c b/libtirpc/src/svc_auth_gss.c new file mode 100644 index 0000000..bcd240a --- /dev/null +++ b/libtirpc/src/svc_auth_gss.c @@ -0,0 +1,590 @@ +/* + svc_auth_gss.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ +#include +#include +#include +#include +#include +#include + +extern SVCAUTH svc_auth_none; + +/* + * from mit-krb5-1.2.1 mechglue/mglueP.h: + * Array of context IDs typed by mechanism OID + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + + + +static bool_t svcauth_gss_destroy(); +static bool_t svcauth_gss_wrap(); +static bool_t svcauth_gss_unwrap(); + +struct svc_auth_ops svc_auth_gss_ops = { + svcauth_gss_wrap, + svcauth_gss_unwrap, + svcauth_gss_destroy +}; + +struct svc_rpc_gss_data { + bool_t established; /* context established */ + gss_ctx_id_t ctx; /* context id */ + struct rpc_gss_sec sec; /* security triple */ + gss_buffer_desc cname; /* GSS client name */ + u_int seq; /* sequence number */ + u_int win; /* sequence window */ + u_int seqlast; /* last sequence number */ + u_int32_t seqmask; /* bitmask of seqnums */ + gss_name_t client_name; /* unparsed name string */ +}; + +#define SVCAUTH_PRIVATE(auth) \ + ((struct svc_rpc_gss_data *)(auth)->svc_ah_private) + +/* Global server credentials. */ +gss_cred_id_t _svcauth_gss_creds; +static gss_name_t _svcauth_gss_name = NULL; + +bool_t +svcauth_gss_set_svc_name(gss_name_t name) +{ + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_set_svc_name()"); + + if (_svcauth_gss_name != NULL) { + maj_stat = gss_release_name(&min_stat, &_svcauth_gss_name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_release_name", maj_stat, min_stat); + return (FALSE); + } + _svcauth_gss_name = NULL; + } + maj_stat = gss_duplicate_name(&min_stat, name, &_svcauth_gss_name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_duplicate_name", maj_stat, min_stat); + return (FALSE); + } + + return (TRUE); +} + +static bool_t +svcauth_gss_import_name(char *service) +{ + gss_name_t name; + gss_buffer_desc namebuf; + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_import_name()"); + + namebuf.value = service; + namebuf.length = strlen(service); + + maj_stat = gss_import_name(&min_stat, &namebuf, + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_import_name", maj_stat, min_stat); + return (FALSE); + } + if (svcauth_gss_set_svc_name(name) != TRUE) { + gss_release_name(&min_stat, &name); + return (FALSE); + } + return (TRUE); +} + +static bool_t +svcauth_gss_acquire_cred(void) +{ + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_acquire_cred()"); + + maj_stat = gss_acquire_cred(&min_stat, _svcauth_gss_name, 0, + GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + &_svcauth_gss_creds, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_acquire_cred", maj_stat, min_stat); + return (FALSE); + } + return (TRUE); +} + +static bool_t +svcauth_gss_release_cred(void) +{ + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_release_cred()"); + + maj_stat = gss_release_cred(&min_stat, &_svcauth_gss_creds); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_release_cred", maj_stat, min_stat); + return (FALSE); + } + + _svcauth_gss_creds = NULL; + + return (TRUE); +} + +static bool_t +svcauth_gss_accept_sec_context(struct svc_req *rqst, + struct rpc_gss_init_res *gr) +{ + struct svc_rpc_gss_data *gd; + struct rpc_gss_cred *gc; + gss_buffer_desc recv_tok, seqbuf, checksum; + gss_OID mech; + OM_uint32 maj_stat = 0, min_stat = 0, ret_flags, seq; + + log_debug("in svcauth_gss_accept_context()"); + + gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); + gc = (struct rpc_gss_cred *)rqst->rq_clntcred; + memset(gr, 0, sizeof(*gr)); + + /* Deserialize arguments. */ + memset(&recv_tok, 0, sizeof(recv_tok)); + + if (!svc_getargs(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_args, + (caddr_t)&recv_tok)) + return (FALSE); + + gr->gr_major = gss_accept_sec_context(&gr->gr_minor, + &gd->ctx, + _svcauth_gss_creds, + &recv_tok, + GSS_C_NO_CHANNEL_BINDINGS, + &gd->client_name, + &mech, + &gr->gr_token, + &ret_flags, + NULL, + NULL); + + if (gr->gr_major != GSS_S_COMPLETE && + gr->gr_major != GSS_S_CONTINUE_NEEDED) { + log_status("accept_sec_context", gr->gr_major, gr->gr_minor); + gd->ctx = GSS_C_NO_CONTEXT; + gss_release_buffer(&min_stat, &gr->gr_token); + return (FALSE); + } + /* ANDROS: krb5 mechglue returns ctx of size 8 - two pointers, + * one to the mechanism oid, one to the internal_ctx_id */ + if ((gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc))) == NULL) { + fprintf(stderr, "svcauth_gss_accept_context: out of memory\n"); + return (FALSE); + } + memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc)); + gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc); + + /* ANDROS: change for debugging linux kernel version... + gr->gr_win = sizeof(gd->seqmask) * 8; + */ + gr->gr_win = 0x00000005; + + /* Save client info. */ + gd->sec.mech = mech; + gd->sec.qop = GSS_C_QOP_DEFAULT; + gd->sec.svc = gc->gc_svc; + gd->seq = gc->gc_seq; + gd->win = gr->gr_win; + + if (gr->gr_major == GSS_S_COMPLETE) { + maj_stat = gss_display_name(&min_stat, gd->client_name, + &gd->cname, &gd->sec.mech); + if (maj_stat != GSS_S_COMPLETE) { + log_status("display_name", maj_stat, min_stat); + return (FALSE); + } +#ifdef DEBUG +#ifdef HAVE_KRB5 + { + gss_buffer_desc mechname; + + gss_oid_to_str(&min_stat, mech, &mechname); + + log_debug("accepted context for %.*s with " + "", + gd->cname.length, (char *)gd->cname.value, + mechname.length, (char *)mechname.value, + gd->sec.qop, gd->sec.svc); + + gss_release_buffer(&min_stat, &mechname); + } +#elif HAVE_HEIMDAL + log_debug("accepted context for %.*s with " + "", + gd->cname.length, (char *)gd->cname.value, + gd->sec.qop, gd->sec.svc); +#endif +#endif /* DEBUG */ + seq = htonl(gr->gr_win); + seqbuf.value = &seq; + seqbuf.length = sizeof(seq); + + maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT, + &seqbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) + return (FALSE); + + rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; + rqst->rq_xprt->xp_verf.oa_base = checksum.value; + rqst->rq_xprt->xp_verf.oa_length = checksum.length; + } + return (TRUE); +} + +static bool_t +svcauth_gss_validate(struct svc_rpc_gss_data *gd, struct rpc_msg *msg) +{ + struct opaque_auth *oa; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat, qop_state; + u_char rpchdr[128]; + int32_t *buf; + + log_debug("in svcauth_gss_validate()"); + + memset(rpchdr, 0, sizeof(rpchdr)); + + /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */ + oa = &msg->rm_call.cb_cred; + if (oa->oa_length > MAX_AUTH_BYTES) + return (FALSE); + + /* 8 XDR units from the IXDR macro calls. */ + if (sizeof(rpchdr) < (8 * BYTES_PER_XDR_UNIT + + RNDUP(oa->oa_length))) + return (FALSE); + + buf = (int32_t *)rpchdr; + IXDR_PUT_LONG(buf, msg->rm_xid); + IXDR_PUT_ENUM(buf, msg->rm_direction); + IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); + IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); + IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); + IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof(int32_t); + } + rpcbuf.value = rpchdr; + rpcbuf.length = (u_char *)buf - rpchdr; + + checksum.value = msg->rm_call.cb_verf.oa_base; + checksum.length = msg->rm_call.cb_verf.oa_length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, + &qop_state); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_verify_mic", maj_stat, min_stat); + return (FALSE); + } + return (TRUE); +} + +bool_t +svcauth_gss_nextverf(struct svc_req *rqst, u_int num) +{ + struct svc_rpc_gss_data *gd; + gss_buffer_desc signbuf, checksum; + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_nextverf()"); + + if (rqst->rq_xprt->xp_auth == NULL) + return (FALSE); + + gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); + + signbuf.value = # + signbuf.length = sizeof(num); + + maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, + &signbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", maj_stat, min_stat); + return (FALSE); + } + rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; + rqst->rq_xprt->xp_verf.oa_base = (caddr_t)checksum.value; + rqst->rq_xprt->xp_verf.oa_length = (u_int)checksum.length; + + return (TRUE); +} + +enum auth_stat +_svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) +{ + XDR xdrs; + SVCAUTH *auth; + struct svc_rpc_gss_data *gd; + struct rpc_gss_cred *gc; + struct rpc_gss_init_res gr; + int call_stat, offset; + + log_debug("in svcauth_gss()"); + + /* Initialize reply. */ + rqst->rq_xprt->xp_verf = _null_auth; + + /* Allocate and set up server auth handle. */ + if (rqst->rq_xprt->xp_auth == NULL || + rqst->rq_xprt->xp_auth == &svc_auth_none) { + if ((auth = calloc(sizeof(*auth), 1)) == NULL) { + fprintf(stderr, "svcauth_gss: out_of_memory\n"); + return (AUTH_FAILED); + } + if ((gd = calloc(sizeof(*gd), 1)) == NULL) { + fprintf(stderr, "svcauth_gss: out_of_memory\n"); + return (AUTH_FAILED); + } + auth->svc_ah_ops = &svc_auth_gss_ops; + auth->svc_ah_private = (caddr_t) gd; + rqst->rq_xprt->xp_auth = auth; + } + else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); + + /* Deserialize client credentials. */ + if (rqst->rq_cred.oa_length <= 0) + return (AUTH_BADCRED); + + gc = (struct rpc_gss_cred *)rqst->rq_clntcred; + memset(gc, 0, sizeof(*gc)); + + xdrmem_create(&xdrs, rqst->rq_cred.oa_base, + rqst->rq_cred.oa_length, XDR_DECODE); + + if (!xdr_rpc_gss_cred(&xdrs, gc)) { + XDR_DESTROY(&xdrs); + return (AUTH_BADCRED); + } + XDR_DESTROY(&xdrs); + + /* Check version. */ + if (gc->gc_v != RPCSEC_GSS_VERSION) + return (AUTH_BADCRED); + + /* Check RPCSEC_GSS service. */ + if (gc->gc_svc != RPCSEC_GSS_SVC_NONE && + gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY && + gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY) + return (AUTH_BADCRED); + + /* Check sequence number. */ + if (gd->established) { + if (gc->gc_seq > MAXSEQ) + return (RPCSEC_GSS_CTXPROBLEM); + + if ((offset = gd->seqlast - gc->gc_seq) < 0) { + gd->seqlast = gc->gc_seq; + offset = 0 - offset; + gd->seqmask <<= offset; + offset = 0; + } + else if (offset >= gd->win || (gd->seqmask & (1 << offset))) { + *no_dispatch = 1; + return (RPCSEC_GSS_CTXPROBLEM); + } + gd->seq = gc->gc_seq; + gd->seqmask |= (1 << offset); + } + + if (gd->established) { + rqst->rq_clntname = (char *)gd->client_name; + rqst->rq_svcname = (char *)gd->ctx; + } + + /* Handle RPCSEC_GSS control procedure. */ + switch (gc->gc_proc) { + + case RPCSEC_GSS_INIT: + case RPCSEC_GSS_CONTINUE_INIT: + if (rqst->rq_proc != NULLPROC) + return (AUTH_FAILED); /* XXX ? */ + + if (_svcauth_gss_name == NULL) { + if (!svcauth_gss_import_name("nfs")) + return (AUTH_FAILED); + } + + if (!svcauth_gss_acquire_cred()) + return (AUTH_FAILED); + + if (!svcauth_gss_accept_sec_context(rqst, &gr)) + return (AUTH_REJECTEDCRED); + + if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) + return (AUTH_FAILED); + + *no_dispatch = TRUE; + + call_stat = svc_sendreply(rqst->rq_xprt, + (xdrproc_t)xdr_rpc_gss_init_res, (caddr_t)&gr); + + if (!call_stat) + return (AUTH_FAILED); + + if (gr.gr_major == GSS_S_COMPLETE) + gd->established = TRUE; + + break; + + case RPCSEC_GSS_DATA: + if (!svcauth_gss_validate(gd, msg)) + return (RPCSEC_GSS_CREDPROBLEM); + + if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) + return (AUTH_FAILED); + break; + + case RPCSEC_GSS_DESTROY: + if (rqst->rq_proc != NULLPROC) + return (AUTH_FAILED); /* XXX ? */ + + if (!svcauth_gss_validate(gd, msg)) + return (RPCSEC_GSS_CREDPROBLEM); + + if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) + return (AUTH_FAILED); + + if (!svcauth_gss_release_cred()) + return (AUTH_FAILED); + + SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth); + rqst->rq_xprt->xp_auth = &svc_auth_none; + + break; + + default: + return (AUTH_REJECTEDCRED); + break; + } + return (AUTH_OK); +} + +bool_t +svcauth_gss_destroy(SVCAUTH *auth) +{ + struct svc_rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in svcauth_gss_destroy()"); + + gd = SVCAUTH_PRIVATE(auth); + + gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER); + gss_release_buffer(&min_stat, &gd->cname); + + if (gd->client_name) + gss_release_name(&min_stat, &gd->client_name); + + mem_free(gd, sizeof(*gd)); + mem_free(auth, sizeof(*auth)); + + return (TRUE); +} + +bool_t +svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct svc_rpc_gss_data *gd; + + log_debug("in svcauth_gss_wrap()"); + + gd = SVCAUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->seq)); +} + +bool_t +svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct svc_rpc_gss_data *gd; + + log_debug("in svcauth_gss_unwrap()"); + + gd = SVCAUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->seq)); +} + +char * +svcauth_gss_get_principal(SVCAUTH *auth) +{ + struct svc_rpc_gss_data *gd; + char *pname; + + gd = SVCAUTH_PRIVATE(auth); + + if (gd->cname.length == 0) + return (NULL); + + if ((pname = malloc(gd->cname.length + 1)) == NULL) + return (NULL); + + memcpy(pname, gd->cname.value, gd->cname.length); + pname[gd->cname.length] = '\0'; + + return (pname); +} diff --git a/libtirpc/src/svc_auth_none.c b/libtirpc/src/svc_auth_none.c new file mode 100644 index 0000000..18f4e16 --- /dev/null +++ b/libtirpc/src/svc_auth_none.c @@ -0,0 +1,74 @@ +/* + svc_auth_none.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + $Id: svc_auth_none.c,v 1.1 2004/10/22 17:24:30 bfields Exp $ + */ + +#include +#include + +//static bool_t svcauth_none_destroy(); +//static bool_t svcauth_none_wrap(); + +static bool_t +svcauth_none_destroy(SVCAUTH *auth) +{ + return (TRUE); +} + +static bool_t +svcauth_none_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, + caddr_t xdr_ptr) +{ + return ((*xdr_func)(xdrs, xdr_ptr)); +} + +struct svc_auth_ops svc_auth_none_ops = { + svcauth_none_wrap, + svcauth_none_wrap, + svcauth_none_destroy +}; + +SVCAUTH svc_auth_none = { + &svc_auth_none_ops, + NULL, +}; + +enum auth_stat +_svcauth_none(struct svc_req *rqst, struct rpc_msg *msg) +{ + rqst->rq_xprt->xp_auth = &svc_auth_none; + + return (AUTH_OK); +} diff --git a/libtirpc/src/svc_auth_unix.c b/libtirpc/src/svc_auth_unix.c new file mode 100644 index 0000000..551a252 --- /dev/null +++ b/libtirpc/src/svc_auth_unix.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * svc_auth_unix.c + * Handles UNIX flavor authentication parameters on the service side of rpc. + * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT. + * _svcauth_unix does full blown unix style uid,gid+gids auth, + * _svcauth_short uses a shorthand auth to index into a cache of longhand auths. + * Note: the shorthand has been gutted for efficiency. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#include +//#include +#include +#include +#include + +#include + +/* + * Unix longhand authenticator + */ +enum auth_stat +_svcauth_unix(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + enum auth_stat stat; + XDR xdrs; + struct authunix_parms *aup; + int32_t *buf; + struct area { + struct authunix_parms area_aup; + char area_machname[MAX_MACHINE_NAME+1]; + gid_t area_gids[NGRPS]; + } *area; + u_int auth_len; + size_t str_len, gid_len; + u_int i; + + assert(rqst != NULL); + assert(msg != NULL); + + area = (struct area *) rqst->rq_clntcred; + aup = &area->area_aup; + aup->aup_machname = area->area_machname; + aup->aup_gids = area->area_gids; + auth_len = (u_int)msg->rm_call.cb_cred.oa_length; + xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE); + buf = XDR_INLINE(&xdrs, auth_len); + if (buf != NULL) { + aup->aup_time = IXDR_GET_INT32(buf); + str_len = (size_t)IXDR_GET_U_INT32(buf); + if (str_len > MAX_MACHINE_NAME) { + stat = AUTH_BADCRED; + goto done; + } + memmove(aup->aup_machname, buf, str_len); + aup->aup_machname[str_len] = 0; + str_len = RNDUP(str_len); + buf += str_len / sizeof (int32_t); + aup->aup_uid = (int)IXDR_GET_INT32(buf); + aup->aup_gid = (int)IXDR_GET_INT32(buf); + gid_len = (size_t)IXDR_GET_U_INT32(buf); + if (gid_len > NGRPS) { + stat = AUTH_BADCRED; + goto done; + } + aup->aup_len = gid_len; + for (i = 0; i < gid_len; i++) { + aup->aup_gids[i] = (int)IXDR_GET_INT32(buf); + } + /* + * five is the smallest unix credentials structure - + * timestamp, hostname len (0), uid, gid, and gids len (0). + */ + if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) { + (void) printf("bad auth_len gid %ld str %ld auth %u\n", + (long)gid_len, (long)str_len, auth_len); + stat = AUTH_BADCRED; + goto done; + } + } else if (! xdr_authunix_parms(&xdrs, aup)) { + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, aup); + stat = AUTH_BADCRED; + goto done; + } + + /* get the verifier */ + if ((u_int)msg->rm_call.cb_verf.oa_length) { + rqst->rq_xprt->xp_verf.oa_flavor = + msg->rm_call.cb_verf.oa_flavor; + rqst->rq_xprt->xp_verf.oa_base = + msg->rm_call.cb_verf.oa_base; + rqst->rq_xprt->xp_verf.oa_length = + msg->rm_call.cb_verf.oa_length; + } else { + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; + rqst->rq_xprt->xp_verf.oa_length = 0; + } + stat = AUTH_OK; +done: + XDR_DESTROY(&xdrs); + return (stat); +} + + +/* + * Shorthand unix authenticator + * Looks up longhand in a cache. + */ +/*ARGSUSED*/ +enum auth_stat +_svcauth_short(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + return (AUTH_REJECTEDCRED); +} diff --git a/libtirpc/src/svc_dg.c b/libtirpc/src/svc_dg.c new file mode 100644 index 0000000..d8dcada --- /dev/null +++ b/libtirpc/src/svc_dg.c @@ -0,0 +1,585 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +//#include + +/* + * svc_dg.c, Server side for connectionless RPC. + * + * Does some caching in the hopes of achieving execute-at-most-once semantics. + */ +#include +//#include +#include +#include +//#include +#include +#include +#include +//#include +#include +#include +#include +#ifdef RPC_CACHE_DEBUG +#include +#include +#endif +//#include + +#include "rpc_com.h" + +#define su_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2)) +#define rpc_buffer(xprt) ((xprt)->xp_p1) + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +static void svc_dg_ops(SVCXPRT *); +static enum xprt_stat svc_dg_stat(SVCXPRT *); +static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *); +static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *); +static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *); +static void svc_dg_destroy(SVCXPRT *); +static bool_t svc_dg_control(SVCXPRT *, const u_int, void *); +static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *); +static void cache_set(SVCXPRT *, size_t); +int svc_dg_enablecache(SVCXPRT *, u_int); + +/* + * Usage: + * xprt = svc_dg_create(sock, sendsize, recvsize); + * Does other connectionless specific initializations. + * Once *xprt is initialized, it is registered. + * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable + * system defaults are chosen. + * The routines returns NULL if a problem occurred. + */ +static const char svc_dg_str[] = "svc_dg_create: %s"; +static const char svc_dg_err1[] = "could not get transport information"; +static const char svc_dg_err2[] = " transport does not support data transfer"; +static const char __no_mem_str[] = "out of memory"; + +SVCXPRT * +svc_dg_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct svc_dg_data *su = NULL; + struct __rpc_sockinfo si; + struct sockaddr_storage ss; + socklen_t slen; + + if (!__rpc_fd2sockinfo(fd, &si)) { + // XXX warnx(svc_dg_str, svc_dg_err1); + return (NULL); + } + /* + * Find the receive and the send size + */ + sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); + recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); + if ((sendsize == 0) || (recvsize == 0)) { + // XXX warnx(svc_dg_str, svc_dg_err2); + return (NULL); + } + + xprt = mem_alloc(sizeof (SVCXPRT)); + if (xprt == NULL) + goto freedata; + memset(xprt, 0, sizeof (SVCXPRT)); + + su = mem_alloc(sizeof (*su)); + if (su == NULL) + goto freedata; + su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4; + if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) + goto freedata; + xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, + XDR_DECODE); + su->su_cache = NULL; + xprt->xp_fd = fd; + xprt->xp_p2 = su; + xprt->xp_verf.oa_base = su->su_verfbody; + svc_dg_ops(xprt); + xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); + + slen = sizeof ss; + if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR) + goto freedata; + __rpc_set_netbuf(&xprt->xp_ltaddr, &ss, slen); + + xprt_register(xprt); + return (xprt); +freedata: + // XXX (void) warnx(svc_dg_str, __no_mem_str); + if (xprt) { + if (su) + (void) mem_free(su, sizeof (*su)); + (void) mem_free(xprt, sizeof (SVCXPRT)); + } + return (NULL); +} + +/*ARGSUSED*/ +static enum xprt_stat +svc_dg_stat(xprt) + SVCXPRT *xprt; +{ + return (XPRT_IDLE); +} + +static bool_t +svc_dg_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_dg_data *su = su_data(xprt); + XDR *xdrs = &(su->su_xdrs); + char *reply; + struct sockaddr_storage ss; + socklen_t alen; + size_t replylen; + ssize_t rlen; + +again: + alen = sizeof (struct sockaddr_storage); + rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0, + (struct sockaddr *)(void *)&ss, &alen); + if (rlen == -1 && errno == EINTR) + goto again; + if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) + return (FALSE); + __rpc_set_netbuf(&xprt->xp_rtaddr, &ss, alen); + + __xprt_set_raddr(xprt, &ss); + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) { + return (FALSE); + } + su->su_xid = msg->rm_xid; + if (su->su_cache != NULL) { + if (cache_get(xprt, msg, &reply, &replylen)) { + (void)sendto(xprt->xp_fd, reply, replylen, 0, + (struct sockaddr *)(void *)&ss, alen); + return (FALSE); + } + } + return (TRUE); +} + +static bool_t +svc_dg_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_dg_data *su = su_data(xprt); + XDR *xdrs = &(su->su_xdrs); + bool_t stat = FALSE; + size_t slen; + + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + if (xdr_replymsg(xdrs, msg)) { + slen = XDR_GETPOS(xdrs); + if (sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0, + (struct sockaddr *)xprt->xp_rtaddr.buf, + (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) { + stat = TRUE; + if (su->su_cache) + cache_set(xprt, slen); + } + } + return (stat); +} + +static bool_t +svc_dg_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr); +} + +static bool_t +svc_dg_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + XDR *xdrs = &(su_data(xprt)->su_xdrs); + + xdrs->x_op = XDR_FREE; + return (*xdr_args)(xdrs, args_ptr); +} + +static void +svc_dg_destroy(xprt) + SVCXPRT *xprt; +{ + struct svc_dg_data *su = su_data(xprt); + + xprt_unregister(xprt); + if (xprt->xp_fd != -1) + (void)closesocket(xprt->xp_fd); + XDR_DESTROY(&(su->su_xdrs)); + (void) mem_free(rpc_buffer(xprt), su->su_iosz); + (void) mem_free(su, sizeof (*su)); + if (xprt->xp_rtaddr.buf) + (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); + if (xprt->xp_ltaddr.buf) + (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); + if (xprt->xp_tp) + (void) free(xprt->xp_tp); + (void) mem_free(xprt, sizeof (SVCXPRT)); +} + +static bool_t +/*ARGSUSED*/ +svc_dg_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static void +svc_dg_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + extern mutex_t ops_lock; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_dg_recv; + ops.xp_stat = svc_dg_stat; + ops.xp_getargs = svc_dg_getargs; + ops.xp_reply = svc_dg_reply; + ops.xp_freeargs = svc_dg_freeargs; + ops.xp_destroy = svc_dg_destroy; + ops2.xp_control = svc_dg_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +/* The CACHING COMPONENT */ + +/* + * Could have been a separate file, but some part of it depends upon the + * private structure of the client handle. + * + * Fifo cache for cl server + * Copies pointers to reply buffers into fifo cache + * Buffers are sent again if retransmissions are detected. + */ + +#define SPARSENESS 4 /* 75% sparse */ + +#define ALLOC(type, size) \ + (type *) mem_alloc((sizeof (type) * (size))) + +#define MEMZERO(addr, type, size) \ + (void) memset((void *) (addr), 0, sizeof (type) * (int) (size)) + +#define FREE(addr, type, size) \ + mem_free((addr), (sizeof (type) * (size))) + +/* + * An entry in the cache + */ +typedef struct cache_node *cache_ptr; +struct cache_node { + /* + * Index into cache is xid, proc, vers, prog and address + */ + u_int32_t cache_xid; + rpcproc_t cache_proc; + rpcvers_t cache_vers; + rpcprog_t cache_prog; + struct netbuf cache_addr; + /* + * The cached reply and length + */ + char *cache_reply; + size_t cache_replylen; + /* + * Next node on the list, if there is a collision + */ + cache_ptr cache_next; +}; + +/* + * The entire cache + */ +struct cl_cache { + u_int uc_size; /* size of cache */ + cache_ptr *uc_entries; /* hash table of entries in cache */ + cache_ptr *uc_fifo; /* fifo list of entries in cache */ + u_int uc_nextvictim; /* points to next victim in fifo list */ + rpcprog_t uc_prog; /* saved program number */ + rpcvers_t uc_vers; /* saved version number */ + rpcproc_t uc_proc; /* saved procedure number */ +}; + + +/* + * the hashing function + */ +#define CACHE_LOC(transp, xid) \ + (xid % (SPARSENESS * ((struct cl_cache *) \ + su_data(transp)->su_cache)->uc_size)) + +extern mutex_t dupreq_lock; + +/* + * Enable use of the cache. Returns 1 on success, 0 on failure. + * Note: there is no disable. + */ +static const char cache_enable_str[] = "svc_enablecache: %s %s"; +static const char alloc_err[] = "could not allocate cache "; +static const char enable_err[] = "cache already enabled"; + +int +svc_dg_enablecache(transp, size) + SVCXPRT *transp; + u_int size; +{ + struct svc_dg_data *su = su_data(transp); + struct cl_cache *uc; + + mutex_lock(&dupreq_lock); + if (su->su_cache != NULL) { + // XXX (void) warnx(cache_enable_str, enable_err, " "); + mutex_unlock(&dupreq_lock); + return (0); + } + uc = ALLOC(struct cl_cache, 1); + if (uc == NULL) { + // XXX warnx(cache_enable_str, alloc_err, " "); + mutex_unlock(&dupreq_lock); + return (0); + } + uc->uc_size = size; + uc->uc_nextvictim = 0; + uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); + if (uc->uc_entries == NULL) { + // XXX warnx(cache_enable_str, alloc_err, "data"); + FREE(uc, struct cl_cache, 1); + mutex_unlock(&dupreq_lock); + return (0); + } + MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); + uc->uc_fifo = ALLOC(cache_ptr, size); + if (uc->uc_fifo == NULL) { + // XXX warnx(cache_enable_str, alloc_err, "fifo"); + FREE(uc->uc_entries, cache_ptr, size * SPARSENESS); + FREE(uc, struct cl_cache, 1); + mutex_unlock(&dupreq_lock); + return (0); + } + MEMZERO(uc->uc_fifo, cache_ptr, size); + su->su_cache = (char *)(void *)uc; + mutex_unlock(&dupreq_lock); + return (1); +} + +/* + * Set an entry in the cache. It assumes that the uc entry is set from + * the earlier call to cache_get() for the same procedure. This will always + * happen because cache_get() is calle by svc_dg_recv and cache_set() is called + * by svc_dg_reply(). All this hoopla because the right RPC parameters are + * not available at svc_dg_reply time. + */ + +static const char cache_set_str[] = "cache_set: %s"; +static const char cache_set_err1[] = "victim not found"; +static const char cache_set_err2[] = "victim alloc failed"; +static const char cache_set_err3[] = "could not allocate new rpc buffer"; + +static void +cache_set(xprt, replylen) + SVCXPRT *xprt; + size_t replylen; +{ + cache_ptr victim; + cache_ptr *vicp; + struct svc_dg_data *su = su_data(xprt); + struct cl_cache *uc = (struct cl_cache *) su->su_cache; + u_int loc; + char *newbuf; +#ifdef RPC_CACHE_DEBUG + struct netconfig *nconf; + char *uaddr; +#endif + + mutex_lock(&dupreq_lock); + /* + * Find space for the new entry, either by + * reusing an old entry, or by mallocing a new one + */ + victim = uc->uc_fifo[uc->uc_nextvictim]; + if (victim != NULL) { + loc = CACHE_LOC(xprt, victim->cache_xid); + for (vicp = &uc->uc_entries[loc]; + *vicp != NULL && *vicp != victim; + vicp = &(*vicp)->cache_next) + ; + if (*vicp == NULL) { + // XXX warnx(cache_set_str, cache_set_err1); + mutex_unlock(&dupreq_lock); + return; + } + *vicp = victim->cache_next; /* remove from cache */ + newbuf = victim->cache_reply; + } else { + victim = ALLOC(struct cache_node, 1); + if (victim == NULL) { + // XXX warnx(cache_set_str, cache_set_err2); + mutex_unlock(&dupreq_lock); + return; + } + newbuf = mem_alloc(su->su_iosz); + if (newbuf == NULL) { + // XXX warnx(cache_set_str, cache_set_err3); + FREE(victim, struct cache_node, 1); + mutex_unlock(&dupreq_lock); + return; + } + } + + /* + * Store it away + */ +#ifdef RPC_CACHE_DEBUG + if (nconf = getnetconfigent(xprt->xp_netid)) { + uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); + freenetconfigent(nconf); + printf( + "cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n", + su->su_xid, uc->uc_prog, uc->uc_vers, + uc->uc_proc, uaddr); + free(uaddr); + } +#endif + victim->cache_replylen = replylen; + victim->cache_reply = rpc_buffer(xprt); + rpc_buffer(xprt) = newbuf; + xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), + su->su_iosz, XDR_ENCODE); + victim->cache_xid = su->su_xid; + victim->cache_proc = uc->uc_proc; + victim->cache_vers = uc->uc_vers; + victim->cache_prog = uc->uc_prog; + victim->cache_addr = xprt->xp_rtaddr; + victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len); + (void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf, + (size_t)xprt->xp_rtaddr.len); + loc = CACHE_LOC(xprt, victim->cache_xid); + victim->cache_next = uc->uc_entries[loc]; + uc->uc_entries[loc] = victim; + uc->uc_fifo[uc->uc_nextvictim++] = victim; + uc->uc_nextvictim %= uc->uc_size; + mutex_unlock(&dupreq_lock); +} + +/* + * Try to get an entry from the cache + * return 1 if found, 0 if not found and set the stage for cache_set() + */ +static int +cache_get(xprt, msg, replyp, replylenp) + SVCXPRT *xprt; + struct rpc_msg *msg; + char **replyp; + size_t *replylenp; +{ + u_int loc; + cache_ptr ent; + struct svc_dg_data *su = su_data(xprt); + struct cl_cache *uc = (struct cl_cache *) su->su_cache; +#ifdef RPC_CACHE_DEBUG + struct netconfig *nconf; + char *uaddr; +#endif + + mutex_lock(&dupreq_lock); + loc = CACHE_LOC(xprt, su->su_xid); + for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { + if (ent->cache_xid == su->su_xid && + ent->cache_proc == msg->rm_call.cb_proc && + ent->cache_vers == msg->rm_call.cb_vers && + ent->cache_prog == msg->rm_call.cb_prog && + ent->cache_addr.len == xprt->xp_rtaddr.len && + (memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf, + xprt->xp_rtaddr.len) == 0)) { +#ifdef RPC_CACHE_DEBUG + if (nconf = getnetconfigent(xprt->xp_netid)) { + uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr); + freenetconfigent(nconf); + printf( + "cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n", + su->su_xid, msg->rm_call.cb_prog, + msg->rm_call.cb_vers, + msg->rm_call.cb_proc, uaddr); + free(uaddr); + } +#endif + *replyp = ent->cache_reply; + *replylenp = ent->cache_replylen; + mutex_unlock(&dupreq_lock); + return (1); + } + } + /* + * Failed to find entry + * Remember a few things so we can do a set later + */ + uc->uc_proc = msg->rm_call.cb_proc; + uc->uc_vers = msg->rm_call.cb_vers; + uc->uc_prog = msg->rm_call.cb_prog; + mutex_unlock(&dupreq_lock); + return (0); +} diff --git a/libtirpc/src/svc_generic.c b/libtirpc/src/svc_generic.c new file mode 100644 index 0000000..d84f237 --- /dev/null +++ b/libtirpc/src/svc_generic.c @@ -0,0 +1,302 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * svc_generic.c, Server side for RPC. + * + */ +#include +//#include +#include +#include +//#include +//#include +#include +#include +#include +#include +#include +#include +//#include +//#include + +#include "rpc_com.h" +#include + +extern int __svc_vc_setflag(SVCXPRT *, int); + +/* + * The highest level interface for server creation. + * It tries for all the nettokens in that particular class of token + * and returns the number of handles it can create and/or find. + * + * It creates a link list of all the handles it could create. + * If svc_create() is called multiple times, it uses the handle + * created earlier instead of creating a new handle every time. + */ +int +svc_create(dispatch, prognum, versnum, nettype) + void (*dispatch)(struct svc_req *, SVCXPRT *); + rpcprog_t prognum; /* Program number */ + rpcvers_t versnum; /* Version number */ + const char *nettype; /* Networktype token */ +{ + struct xlist { + SVCXPRT *xprt; /* Server handle */ + struct xlist *next; /* Next item */ + } *l; + static struct xlist *xprtlist; /* A link list of all the handles */ + int num = 0; + SVCXPRT *xprt; + struct netconfig *nconf; + void *handle; + extern mutex_t xprtlist_lock; + +/* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */ + + if ((handle = __rpc_setconf(nettype)) == NULL) { + // XXX warnx("svc_create: unknown protocol"); + return (0); + } + while ((nconf = __rpc_getconf(handle)) != NULL) { + mutex_lock(&xprtlist_lock); + for (l = xprtlist; l; l = l->next) { + if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) { + /* Found an old one, use it */ + (void) rpcb_unset(prognum, versnum, nconf); + if (svc_reg(l->xprt, prognum, versnum, + dispatch, nconf) == FALSE) { + // XXX warnx( +// "svc_create: could not register prog %u vers %u on %s", +// (unsigned)prognum, (unsigned)versnum, +// nconf->nc_netid); + } else { + num++; + } + break; + } + } + if (l == NULL) { + /* It was not found. Now create a new one */ + xprt = svc_tp_create(dispatch, prognum, versnum, nconf); + if (xprt) { + l = (struct xlist *)malloc(sizeof (*l)); + if (l == NULL) { + // XXX warnx("svc_create: no memory"); + mutex_unlock(&xprtlist_lock); + return (0); + } + l->xprt = xprt; + l->next = xprtlist; + xprtlist = l; + num++; + } + } + mutex_unlock(&xprtlist_lock); + } + __rpc_endconf(handle); + /* + * In case of num == 0; the error messages are generated by the + * underlying layers; and hence not needed here. + */ + return (num); +} + +/* + * The high level interface to svc_tli_create(). + * It tries to create a server for "nconf" and registers the service + * with the rpcbind. It calls svc_tli_create(); + */ +SVCXPRT * +svc_tp_create(dispatch, prognum, versnum, nconf) + void (*dispatch)(struct svc_req *, SVCXPRT *); + rpcprog_t prognum; /* Program number */ + rpcvers_t versnum; /* Version number */ + const struct netconfig *nconf; /* Netconfig structure for the network */ +{ + SVCXPRT *xprt; + + if (nconf == NULL) { + // XXX warnx( +// "svc_tp_create: invalid netconfig structure for prog %u vers %u", +// (unsigned)prognum, (unsigned)versnum); + return (NULL); + } + xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); + if (xprt == NULL) { + return (NULL); + } + /*LINTED const castaway*/ + (void) rpcb_unset(prognum, versnum, (struct netconfig *) nconf); + if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { + // XXX warnx( +// "svc_tp_create: Could not register prog %u vers %u on %s", +// (unsigned)prognum, (unsigned)versnum, +// nconf->nc_netid); + SVC_DESTROY(xprt); + return (NULL); + } + return (xprt); +} + + /* + * If fd is RPC_ANYFD, then it opens a fd for the given transport + * provider (nconf cannot be NULL then). If the t_state is T_UNBND and + * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For + * NULL bindadr and Connection oriented transports, the value of qlen + * is set to 8. + * + * If sendsz or recvsz are zero, their default values are chosen. + */ +SVCXPRT * +svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz) + SOCKET fd; /* Connection end point */ + const struct netconfig *nconf; /* Netconfig struct for nettoken */ + const struct t_bind *bindaddr; /* Local bind address */ + u_int sendsz; /* Max sendsize */ + u_int recvsz; /* Max recvsize */ +{ + SVCXPRT *xprt = NULL; /* service handle */ + bool_t madefd = FALSE; /* whether fd opened here */ + struct __rpc_sockinfo si; + struct sockaddr_storage ss; + socklen_t slen; + + if (fd == RPC_ANYFD) { + if (nconf == NULL) { + // XXX warnx("svc_tli_create: invalid netconfig"); + return (NULL); + } + fd = __rpc_nconf2fd(nconf); + if (fd == -1) { + // XXX warnx( +// "svc_tli_create: could not open connection for %s", +// nconf->nc_netid); + return (NULL); + } + __rpc_nconf2sockinfo(nconf, &si); + madefd = TRUE; + } else { + /* + * It is an open descriptor. Get the transport info. + */ + if (!__rpc_fd2sockinfo(fd, &si)) { + // XXX warnx( +// "svc_tli_create: could not get transport information"); + return (NULL); + } + } + + /* + * If the fd is unbound, try to bind it. + */ + if (madefd || !__rpc_sockisbound(fd)) { + if (bindaddr == NULL) { + if (bindresvport(fd, NULL) < 0) { + memset(&ss, 0, sizeof ss); + ss.ss_family = si.si_af; + if (bind(fd, (struct sockaddr *)(void *)&ss, + (socklen_t)si.si_alen) == SOCKET_ERROR) { + // XXX warnx( +// "svc_tli_create: could not bind to anonymous port"); + goto freedata; + } + } + listen(fd, SOMAXCONN); + } else { + if (bind(fd, + (struct sockaddr *)bindaddr->addr.buf, + (socklen_t)si.si_alen) == SOCKET_ERROR) { + // XXX warnx( +// "svc_tli_create: could not bind to requested address"); + goto freedata; + } + listen(fd, (int)bindaddr->qlen); + } + + } + /* + * call transport specific function. + */ + switch (si.si_socktype) { + case SOCK_STREAM: + slen = sizeof ss; + if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) + == 0) { + /* accepted socket */ + xprt = svc_fd_create(fd, sendsz, recvsz); + } else + xprt = svc_vc_create(fd, sendsz, recvsz); + if (!nconf || !xprt) + break; +#if 0 + /* XXX fvdl */ + if (strcmp(nconf->nc_protofmly, "inet") == 0 || + strcmp(nconf->nc_protofmly, "inet6") == 0) + (void) __svc_vc_setflag(xprt, TRUE); +#endif + break; + case SOCK_DGRAM: + xprt = svc_dg_create(fd, sendsz, recvsz); + break; + default: + // XXX warnx("svc_tli_create: bad service type"); + goto freedata; + } + + if (xprt == NULL) + /* + * The error messages here are spitted out by the lower layers: + * svc_vc_create(), svc_fd_create() and svc_dg_create(). + */ + goto freedata; + + /* Fill in type of service */ + xprt->xp_type = __rpc_socktype2seman(si.si_socktype); + + if (nconf) { + xprt->xp_netid = strdup(nconf->nc_netid); + xprt->xp_tp = strdup(nconf->nc_device); + } + return (xprt); + +freedata: + if (madefd) + (void)closesocket(fd); + if (xprt) { + if (!madefd) /* so that svc_destroy doesnt close fd */ + xprt->xp_fd = RPC_ANYFD; + SVC_DESTROY(xprt); + } + return (NULL); +} diff --git a/libtirpc/src/svc_raw.c b/libtirpc/src/svc_raw.c new file mode 100644 index 0000000..4324c44 --- /dev/null +++ b/libtirpc/src/svc_raw.c @@ -0,0 +1,248 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +/* + * svc_raw.c, This a toy for simple testing and timing. + * Interface to create an rpc client and server in the same UNIX process. + * This lets us similate rpc and get rpc (round trip) overhead, without + * any interference from the kernel. + * + */ +#include +//#include +#include +#include +#include +#include +#include + +#ifndef UDPMSGSIZE +#define UDPMSGSIZE 8800 +#endif + +/* + * This is the "network" that we will be moving data over + */ +static struct svc_raw_private { + char *raw_buf; /* should be shared with the cl handle */ + SVCXPRT server; + XDR xdr_stream; + char verf_body[MAX_AUTH_BYTES]; +} *svc_raw_private; + +extern mutex_t svcraw_lock; + +static enum xprt_stat svc_raw_stat(SVCXPRT *); +static bool_t svc_raw_recv(SVCXPRT *, struct rpc_msg *); +static bool_t svc_raw_reply(SVCXPRT *, struct rpc_msg *); +static bool_t svc_raw_getargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_raw_freeargs(SVCXPRT *, xdrproc_t, void *); +static void svc_raw_destroy(SVCXPRT *); +static void svc_raw_ops(SVCXPRT *); +static bool_t svc_raw_control(SVCXPRT *, const u_int, void *); + +char *__rpc_rawcombuf = NULL; + +SVCXPRT * +svc_raw_create() +{ + struct svc_raw_private *srp; +/* VARIABLES PROTECTED BY svcraw_lock: svc_raw_private, srp */ + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + srp = (struct svc_raw_private *)calloc(1, sizeof (*srp)); + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (NULL); + } + if (__rpc_rawcombuf == NULL) + __rpc_rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); + srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */ + svc_raw_private = srp; + } + srp->server.xp_fd = FD_SETSIZE; + srp->server.xp_port = 0; + srp->server.xp_p3 = NULL; + svc_raw_ops(&srp->server); + srp->server.xp_verf.oa_base = srp->verf_body; + xdrmem_create(&srp->xdr_stream, srp->raw_buf, UDPMSGSIZE, XDR_DECODE); + xprt_register(&srp->server); + mutex_unlock(&svcraw_lock); + return (&srp->server); +} + +/*ARGSUSED*/ +static enum xprt_stat +svc_raw_stat(xprt) +SVCXPRT *xprt; /* args needed to satisfy ANSI-C typechecking */ +{ + return (XPRT_IDLE); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_raw_private *srp; + XDR *xdrs; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_DECODE; + (void) XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) { + return (FALSE); + } + return (TRUE); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct svc_raw_private *srp; + XDR *xdrs; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_ENCODE; + (void) XDR_SETPOS(xdrs, 0); + if (! xdr_replymsg(xdrs, msg)) { + return (FALSE); + } + (void) XDR_GETPOS(xdrs); /* called just for overhead */ + return (TRUE); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + struct svc_raw_private *srp; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + return (*xdr_args)(&srp->xdr_stream, args_ptr); +} + +/*ARGSUSED*/ +static bool_t +svc_raw_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + struct svc_raw_private *srp; + XDR *xdrs; + + mutex_lock(&svcraw_lock); + srp = svc_raw_private; + if (srp == NULL) { + mutex_unlock(&svcraw_lock); + return (FALSE); + } + mutex_unlock(&svcraw_lock); + + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_FREE; + return (*xdr_args)(xdrs, args_ptr); +} + +/*ARGSUSED*/ +static void +svc_raw_destroy(xprt) +SVCXPRT *xprt; +{ +} + +/*ARGSUSED*/ +static bool_t +svc_raw_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static void +svc_raw_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + extern mutex_t ops_lock; + +/* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_raw_recv; + ops.xp_stat = svc_raw_stat; + ops.xp_getargs = svc_raw_getargs; + ops.xp_reply = svc_raw_reply; + ops.xp_freeargs = svc_raw_freeargs; + ops.xp_destroy = svc_raw_destroy; + ops2.xp_control = svc_raw_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} diff --git a/libtirpc/src/svc_run.c b/libtirpc/src/svc_run.c new file mode 100644 index 0000000..842b5bf --- /dev/null +++ b/libtirpc/src/svc_run.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include +//#include +#include +//#include +#include +#include +#include +#include +//#include + +#include +#include "rpc_com.h" +//#include + +void +svc_run() +{ + fd_set readfds, cleanfds; + struct timeval timeout; + extern rwlock_t svc_fd_lock; + + + for (;;) { + rwlock_rdlock(&svc_fd_lock); + readfds = svc_fdset; + cleanfds = svc_fdset; + rwlock_unlock(&svc_fd_lock); + timeout.tv_sec = 30; + timeout.tv_usec = 0; + switch (select(svc_maxfd+1, &readfds, NULL, NULL, &timeout)) { + case SOCKET_ERROR: + FD_ZERO(&readfds); + if (WSAGetLastError() == WSAEINTR) { + continue; + } + // XXX warn("svc_run: - select failed"); + return; + case 0: + __svc_clean_idle(&cleanfds, 30, FALSE); + continue; + default: + svc_getreqset(&readfds); + } + } +} + +/* + * This function causes svc_run() to exit by telling it that it has no + * more work to do. + */ +void +svc_exit() +{ + extern rwlock_t svc_fd_lock; + + rwlock_wrlock(&svc_fd_lock); + FD_ZERO(&svc_fdset); + rwlock_unlock(&svc_fd_lock); +} diff --git a/libtirpc/src/svc_simple.c b/libtirpc/src/svc_simple.c new file mode 100644 index 0000000..17ec027 --- /dev/null +++ b/libtirpc/src/svc_simple.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986-1991 by Sun Microsystems Inc. + */ + +//#include + +/* + * svc_simple.c + * Simplified front end to rpc. + */ + +/* + * This interface creates a virtual listener for all the services + * started thru rpc_reg(). It listens on the same endpoint for + * all the services and then executes the corresponding service + * for the given prognum and procnum. + */ +#include +//#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#include "rpc_com.h" + +static void universal(struct svc_req *, SVCXPRT *); + +static struct proglst { + char *(*p_progname)(char *); + rpcprog_t p_prognum; + rpcvers_t p_versnum; + rpcproc_t p_procnum; + SVCXPRT *p_transp; + char *p_netid; + char *p_xdrbuf; + int p_recvsz; + xdrproc_t p_inproc, p_outproc; + struct proglst *p_nxt; +} *proglst; + +static const char rpc_reg_err[] = "%s: %s"; +static const char rpc_reg_msg[] = "rpc_reg: "; +static const char __reg_err1[] = "can't find appropriate transport"; +static const char __reg_err2[] = "can't get protocol info"; +static const char __reg_err3[] = "unsupported transport size"; +static const char __no_mem_str[] = "out of memory"; + +/* + * For simplified, easy to use kind of rpc interfaces. + * nettype indicates the type of transport on which the service will be + * listening. Used for conservation of the system resource. Only one + * handle is created for all the services (actually one of each netid) + * and same xdrbuf is used for same netid. The size of the arguments + * is also limited by the recvsize for that transport, even if it is + * a COTS transport. This may be wrong, but for cases like these, they + * should not use the simplified interfaces like this. + */ + +int +rpc_reg(prognum, versnum, procnum, progname, inproc, outproc, nettype) + rpcprog_t prognum; /* program number */ + rpcvers_t versnum; /* version number */ + rpcproc_t procnum; /* procedure number */ + char *(*progname)(char *); /* Server routine */ + xdrproc_t inproc, outproc; /* in/out XDR procedures */ + char *nettype; /* nettype */ +{ + struct netconfig *nconf; + int done = FALSE; + void *handle; + extern mutex_t proglst_lock; + + if (procnum == NULLPROC) { + // XXXwarnx("%s can't reassign procedure number %u", rpc_reg_msg, +// NULLPROC); + return (-1); + } + + if (nettype == NULL) + nettype = "netpath"; /* The default behavior */ + if ((handle = __rpc_setconf(nettype)) == NULL) { + // XXX warnx(rpc_reg_err, rpc_reg_msg, __reg_err1); + return (-1); + } +/* VARIABLES PROTECTED BY proglst_lock: proglst */ + mutex_lock(&proglst_lock); + while ((nconf = __rpc_getconf(handle)) != NULL) { + struct proglst *pl; + SVCXPRT *svcxprt; + int madenow; + u_int recvsz; + char *xdrbuf; + char *netid; + + madenow = FALSE; + svcxprt = NULL; + recvsz = 0; + xdrbuf = netid = NULL; + for (pl = proglst; pl; pl = pl->p_nxt) { + if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { + svcxprt = pl->p_transp; + xdrbuf = pl->p_xdrbuf; + recvsz = pl->p_recvsz; + netid = pl->p_netid; + break; + } + } + + if (svcxprt == NULL) { + struct __rpc_sockinfo si; + + svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); + if (svcxprt == NULL) + continue; + if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) { + // XXX warnx(rpc_reg_err, rpc_reg_msg, __reg_err2); + SVC_DESTROY(svcxprt); + continue; + } + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0); + if (recvsz == 0) { + // XXX warnx(rpc_reg_err, rpc_reg_msg, __reg_err3); + SVC_DESTROY(svcxprt); + continue; + } + if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || + ((netid = strdup(nconf->nc_netid)) == NULL)) { + // XXX warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); + SVC_DESTROY(svcxprt); + break; + } + madenow = TRUE; + } + /* + * Check if this (program, version, netid) had already been + * registered. The check may save a few RPC calls to rpcbind + */ + for (pl = proglst; pl; pl = pl->p_nxt) + if ((pl->p_prognum == prognum) && + (pl->p_versnum == versnum) && + (strcmp(pl->p_netid, netid) == 0)) + break; + if (pl == NULL) { /* Not yet */ + (void) rpcb_unset(prognum, versnum, nconf); + } else { + /* so that svc_reg does not call rpcb_set() */ + nconf = NULL; + } + + if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { + // XXX warnx("%s couldn't register prog %u vers %u for %s", +// rpc_reg_msg, (unsigned)prognum, +// (unsigned)versnum, netid); + if (madenow) { + SVC_DESTROY(svcxprt); + free(xdrbuf); + free(netid); + } + continue; + } + + pl = malloc(sizeof (struct proglst)); + if (pl == NULL) { + // XXX warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); + if (madenow) { + SVC_DESTROY(svcxprt); + free(xdrbuf); + free(netid); + } + break; + } + pl->p_progname = progname; + pl->p_prognum = prognum; + pl->p_versnum = versnum; + pl->p_procnum = procnum; + pl->p_inproc = inproc; + pl->p_outproc = outproc; + pl->p_transp = svcxprt; + pl->p_xdrbuf = xdrbuf; + pl->p_recvsz = recvsz; + pl->p_netid = netid; + pl->p_nxt = proglst; + proglst = pl; + done = TRUE; + } + __rpc_endconf(handle); + mutex_unlock(&proglst_lock); + + if (done == FALSE) { + // XXX warnx("%s cant find suitable transport for %s", +// rpc_reg_msg, nettype); + return (-1); + } + return (0); +} + +/* + * The universal handler for the services registered using registerrpc. + * It handles both the connectionless and the connection oriented cases. + */ + +static void +universal(rqstp, transp) + struct svc_req *rqstp; + SVCXPRT *transp; +{ + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + char *outdata; + char *xdrbuf; + struct proglst *pl; + extern mutex_t proglst_lock; + + /* + * enforce "procnum 0 is echo" convention + */ + if (rqstp->rq_proc == NULLPROC) { + if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) == + FALSE) { + // XXX warnx("svc_sendreply failed"); + } + return; + } + prog = rqstp->rq_prog; + vers = rqstp->rq_vers; + proc = rqstp->rq_proc; + mutex_lock(&proglst_lock); + for (pl = proglst; pl; pl = pl->p_nxt) + if (pl->p_prognum == prog && pl->p_procnum == proc && + pl->p_versnum == vers && + (strcmp(pl->p_netid, transp->xp_netid) == 0)) { + /* decode arguments into a CLEAN buffer */ + xdrbuf = pl->p_xdrbuf; + /* Zero the arguments: reqd ! */ + (void) memset(xdrbuf, 0, sizeof (pl->p_recvsz)); + /* + * Assuming that sizeof (xdrbuf) would be enough + * for the arguments; if not then the program + * may bomb. BEWARE! + */ + if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { + svcerr_decode(transp); + mutex_unlock(&proglst_lock); + return; + } + outdata = (*(pl->p_progname))(xdrbuf); + if (outdata == NULL && + pl->p_outproc != (xdrproc_t) xdr_void){ + /* there was an error */ + mutex_unlock(&proglst_lock); + return; + } + if (!svc_sendreply(transp, pl->p_outproc, outdata)) { + // XXX warnx( +// "rpc: rpc_reg trouble replying to prog %u vers %u", +// (unsigned)prog, (unsigned)vers); + mutex_unlock(&proglst_lock); + return; + } + /* free the decoded arguments */ + (void)svc_freeargs(transp, pl->p_inproc, xdrbuf); + mutex_unlock(&proglst_lock); + return; + } + mutex_unlock(&proglst_lock); + /* This should never happen */ + // XXX warnx("rpc: rpc_reg: never registered prog %u vers %u", +// (unsigned)prog, (unsigned)vers); + return; +} diff --git a/libtirpc/src/svc_vc.c b/libtirpc/src/svc_vc.c new file mode 100644 index 0000000..6ea4140 --- /dev/null +++ b/libtirpc/src/svc_vc.c @@ -0,0 +1,827 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * svc_vc.c, Server side for Connection Oriented based RPC. + * + * Actually implements two flavors of transporter - + * a tcp rendezvouser (a listner and connection establisher) + * and a record/tcp stream. + */ +#include +//#include +#include +//#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +#include +//#include +#include +#include +#include +#include +#include +//#include + +#include + +#include "rpc_com.h" + +#include + + +extern rwlock_t svc_fd_lock; + +static SVCXPRT *makefd_xprt(SOCKET, u_int, u_int); +static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); +static enum xprt_stat rendezvous_stat(SVCXPRT *); +static void svc_vc_destroy(SVCXPRT *); +static void __svc_vc_dodestroy (SVCXPRT *); +static int read_vc(void *, void *, int); +static int write_vc(void *, void *, int); +static enum xprt_stat svc_vc_stat(SVCXPRT *); +static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); +static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); +static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); +static void svc_vc_rendezvous_ops(SVCXPRT *); +static void svc_vc_ops(SVCXPRT *); +static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); +static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, + void *in); + +struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ + u_int sendsize; + u_int recvsize; + int maxrec; +}; + +struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ + enum xprt_stat strm_stat; + u_int32_t x_id; + XDR xdrs; + char verf_body[MAX_AUTH_BYTES]; + u_int sendsize; + u_int recvsize; + int maxrec; + bool_t nonblock; + struct timeval last_recv_time; +}; + +/* + * This is used to set xprt->xp_raddr in a way legacy + * apps can deal with + */ +void +__xprt_set_raddr(SVCXPRT *xprt, const struct sockaddr_storage *ss) +{ + switch (ss->ss_family) { + case AF_INET6: + memcpy(&xprt->xp_raddr, ss, sizeof(struct sockaddr_in6)); + xprt->xp_addrlen = sizeof (struct sockaddr_in6); + break; + case AF_INET: + memcpy(&xprt->xp_raddr, ss, sizeof(struct sockaddr_in)); + xprt->xp_addrlen = sizeof (struct sockaddr_in); + break; + default: + xprt->xp_raddr.sin6_family = AF_UNSPEC; + xprt->xp_addrlen = sizeof (struct sockaddr); + break; + } +} + +/* + * Usage: + * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); + * + * Creates, registers, and returns a (rpc) tcp based transporter. + * Once *xprt is initialized, it is registered as a transporter + * see (svc.h, xprt_register). This routine returns + * a NULL if a problem occurred. + * + * The filedescriptor passed in is expected to refer to a bound, but + * not yet connected socket. + * + * Since streams do buffered io similar to stdio, the caller can specify + * how big the send and receive buffers are via the second and third parms; + * 0 => use the system default. + */ +SVCXPRT * +svc_vc_create(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct cf_rendezvous *r = NULL; + struct __rpc_sockinfo si; + struct sockaddr_storage sslocal; + socklen_t slen; + + r = mem_alloc(sizeof(*r)); + if (r == NULL) { + // XXX warnx("svc_vc_create: out of memory"); + goto cleanup_svc_vc_create; + } + if (!__rpc_fd2sockinfo(fd, &si)) + return NULL; + r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); + r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); + r->maxrec = __svc_maxrec; + xprt = mem_alloc(sizeof(SVCXPRT)); + if (xprt == NULL) { + // XXX warnx("svc_vc_create: out of memory"); + goto cleanup_svc_vc_create; + } + xprt->xp_tp = NULL; + xprt->xp_p1 = r; + xprt->xp_p2 = NULL; + xprt->xp_p3 = NULL; + xprt->xp_verf = _null_auth; + svc_vc_rendezvous_ops(xprt); + xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ + xprt->xp_fd = fd; + + slen = sizeof (struct sockaddr_storage); + if (getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) == SOCKET_ERROR) { + // XXX warnx("svc_vc_create: could not retrieve local addr"); + goto cleanup_svc_vc_create; + } + + if (!__rpc_set_netbuf(&xprt->xp_ltaddr, &sslocal, sizeof(sslocal))) { + // XXX warnx("svc_vc_create: no mem for local addr"); + goto cleanup_svc_vc_create; + } + xprt_register(xprt); + return (xprt); +cleanup_svc_vc_create: + if (r != NULL) + mem_free(r, sizeof(*r)); + return (NULL); +} + +/* + * Like svtcp_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. + */ +SVCXPRT * +svc_fd_create(fd, sendsize, recvsize) + SOCKET fd; + u_int sendsize; + u_int recvsize; +{ + struct sockaddr_storage ss; + socklen_t slen; + SVCXPRT *ret; + + assert(fd != -1); + + ret = makefd_xprt(fd, sendsize, recvsize); + if (ret == NULL) + return NULL; + + slen = sizeof (struct sockaddr_storage); + if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR) { + // XXX warnx("svc_fd_create: could not retrieve local addr"); + goto freedata; + } + if (!__rpc_set_netbuf(&ret->xp_ltaddr, &ss, sizeof(ss))) { + // XXX warnx("svc_fd_create: no mem for local addr"); + goto freedata; + } + + slen = sizeof (struct sockaddr_storage); + if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) == SOCKET_ERROR) { + // XXX warnx("svc_fd_create: could not retrieve remote addr"); + goto freedata; + } + if (!__rpc_set_netbuf(&ret->xp_rtaddr, &ss, sizeof(ss))) { + // XXX warnx("svc_fd_create: no mem for local addr"); + goto freedata; + } + + /* Set xp_raddr for compatibility */ + __xprt_set_raddr(ret, &ss); + + return ret; + +freedata: + if (ret->xp_ltaddr.buf != NULL) + mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); + + return NULL; +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) + SOCKET fd; + u_int sendsize; + u_int recvsize; +{ + SVCXPRT *xprt; + struct cf_conn *cd; + const char *netid; + struct __rpc_sockinfo si; + + assert(fd != SOCKET_ERROR); + + if (fd >= FD_SETSIZE) { + // XXX warnx("svc_vc: makefd_xprt: fd too high\n"); + xprt = NULL; + goto done; + } + + xprt = mem_alloc(sizeof(SVCXPRT)); + if (xprt == NULL) { + // XXX warnx("svc_vc: makefd_xprt: out of memory"); + goto done; + } + memset(xprt, 0, sizeof *xprt); + cd = mem_alloc(sizeof(struct cf_conn)); + if (cd == NULL) { + // XXX warnx("svc_tcp: makefd_xprt: out of memory"); + mem_free(xprt, sizeof(SVCXPRT)); + xprt = NULL; + goto done; + } + cd->strm_stat = XPRT_IDLE; + xdrrec_create(&(cd->xdrs), sendsize, recvsize, + xprt, read_vc, write_vc); + xprt->xp_p1 = cd; + xprt->xp_verf.oa_base = cd->verf_body; + svc_vc_ops(xprt); /* truely deals with calls */ + xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ + xprt->xp_fd = fd; + if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) + xprt->xp_netid = strdup(netid); + + xprt_register(xprt); +done: + return (xprt); +} + +/*ARGSUSED*/ +static bool_t +rendezvous_request(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + SOCKET sock; +#ifndef _WIN32 + int flags; +#endif + struct cf_rendezvous *r; + struct cf_conn *cd; + struct sockaddr_storage addr; + socklen_t len; + struct __rpc_sockinfo si; + SVCXPRT *newxprt; + fd_set cleanfds; + + assert(xprt != NULL); + assert(msg != NULL); + + r = (struct cf_rendezvous *)xprt->xp_p1; +again: + len = sizeof addr; + if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, + &len)) == SOCKET_ERROR) { + if (errno == EINTR) + goto again; + /* + * Clean out the most idle file descriptor when we're + * running out. + */ + if (errno == EMFILE || errno == ENFILE) { + cleanfds = svc_fdset; + __svc_clean_idle(&cleanfds, 0, FALSE); + goto again; + } + return (FALSE); + } + /* + * make a new transporter (re-uses xprt) + */ + + newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); + + if (!__rpc_set_netbuf(&newxprt->xp_rtaddr, &addr, len)) + return (FALSE); + + __xprt_set_raddr(newxprt, &addr); + + if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { + len = 1; + /* XXX fvdl - is this useful? */ + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&len, sizeof (len)); + } + + cd = (struct cf_conn *)newxprt->xp_p1; + + cd->recvsize = r->recvsize; + cd->sendsize = r->sendsize; + cd->maxrec = r->maxrec; + +#ifndef _WIN32 + if (cd->maxrec != 0) { + flags = fcntl(sock, F_GETFL, 0); + if (flags == -1) + return (FALSE); + if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) + return (FALSE); + if (cd->recvsize > cd->maxrec) + cd->recvsize = cd->maxrec; + cd->nonblock = TRUE; + __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); + } else + cd->nonblock = FALSE; +#endif /* _WIN32 */ + + gettimeofday(&cd->last_recv_time, NULL); + + return (FALSE); /* there is never an rpc msg to be processed */ +} + +/*ARGSUSED*/ +static enum xprt_stat +rendezvous_stat(xprt) + SVCXPRT *xprt; +{ + + return (XPRT_IDLE); +} + +static void +svc_vc_destroy(xprt) + SVCXPRT *xprt; +{ + assert(xprt != NULL); + + xprt_unregister(xprt); + __svc_vc_dodestroy(xprt); +} + +static void +__svc_vc_dodestroy(xprt) + SVCXPRT *xprt; +{ + struct cf_conn *cd; + struct cf_rendezvous *r; + + cd = (struct cf_conn *)xprt->xp_p1; + + if (xprt->xp_fd != RPC_ANYFD) + (void)closesocket(xprt->xp_fd); + if (xprt->xp_port != 0) { + /* a rendezvouser socket */ + r = (struct cf_rendezvous *)xprt->xp_p1; + mem_free(r, sizeof (struct cf_rendezvous)); + xprt->xp_port = 0; + } else { + /* an actual connection socket */ + XDR_DESTROY(&(cd->xdrs)); + mem_free(cd, sizeof(struct cf_conn)); + } + if (xprt->xp_rtaddr.buf) + mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); + if (xprt->xp_ltaddr.buf) + mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); + if (xprt->xp_tp) + free(xprt->xp_tp); + if (xprt->xp_netid) + free(xprt->xp_netid); + mem_free(xprt, sizeof(SVCXPRT)); +} + +/*ARGSUSED*/ +static bool_t +svc_vc_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + return (FALSE); +} + +static bool_t +svc_vc_rendezvous_control(xprt, rq, in) + SVCXPRT *xprt; + const u_int rq; + void *in; +{ + struct cf_rendezvous *cfp; + + cfp = (struct cf_rendezvous *)xprt->xp_p1; + if (cfp == NULL) + return (FALSE); + switch (rq) { + case SVCGET_CONNMAXREC: + *(int *)in = cfp->maxrec; + break; + case SVCSET_CONNMAXREC: + cfp->maxrec = *(int *)in; + break; + default: + return (FALSE); + } + return (TRUE); +} + +/* + * reads data from the tcp or uip connection. + * any error is fatal and the connection is closed. + * (And a read of zero bytes is a half closed stream => error.) + * All read operations timeout after 35 seconds. A timeout is + * fatal for the connection. + */ +static int +read_vc(xprtp, buf, len) + void *xprtp; + void *buf; + int len; +{ + SVCXPRT *xprt; + SOCKET sock; + int milliseconds = 35 * 1000; + struct pollfd pollfd; + struct cf_conn *cfp; + + xprt = (SVCXPRT *)xprtp; + assert(xprt != NULL); + + sock = xprt->xp_fd; + + cfp = (struct cf_conn *)xprt->xp_p1; + + if (cfp->nonblock) { +#ifdef _WIN32 + len = recv(sock, buf, (size_t)len, 0); +#else + len = read(sock, buf, (size_t)len); +#endif + if (len == SOCKET_ERROR) { + if (WSAGetLastError() == EAGAIN) + len = 0; + else + goto fatal_err; + } + if (len != 0) + gettimeofday(&cfp->last_recv_time, NULL); + return len; + } + + do { + pollfd.fd = sock; + pollfd.events = POLLIN; + pollfd.revents = 0; + switch (poll(&pollfd, 1, milliseconds)) { + case -1: + if (errno == EINTR) + continue; + /*FALLTHROUGH*/ + case 0: + goto fatal_err; + + default: + break; + } + } while ((pollfd.revents & POLLIN) == 0); + +#ifdef _WIN32 + if ((len = recv(sock, buf, (size_t)len, 0)) > 0) { +#else + if ((len = read(sock, buf, (size_t)len)) > 0) { +#endif + gettimeofday(&cfp->last_recv_time, NULL); + return (len); + } + +fatal_err: + ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; + return (-1); +} + +/* + * writes data to the tcp connection. + * Any error is fatal and the connection is closed. + */ +static int +write_vc(xprtp, buf, len) + void *xprtp; + char *buf; + int len; +{ + SVCXPRT *xprt; + int i, cnt; + struct cf_conn *cd; + struct timeval tv0, tv1; + + xprt = (SVCXPRT *)xprtp; + assert(xprt != NULL); + + cd = (struct cf_conn *)xprt->xp_p1; + + if (cd->nonblock) + gettimeofday(&tv0, NULL); + + for (cnt = len; cnt > 0; cnt -= i, buf += i) { +#ifdef _WIN32 + i = send(xprt->xp_fd, buf, (size_t)cnt, 0); +#else + i = write(xprt->xp_fd, buf, (size_t)cnt); +#endif + if (i == SOCKET_ERROR) { + if (WSAGetLastError() != EAGAIN || !cd->nonblock) { + cd->strm_stat = XPRT_DIED; + return (-1); + } + if (cd->nonblock && i != cnt) { + /* + * For non-blocking connections, do not + * take more than 2 seconds writing the + * data out. + * + * XXX 2 is an arbitrary amount. + */ + gettimeofday(&tv1, NULL); + if (tv1.tv_sec - tv0.tv_sec >= 2) { + cd->strm_stat = XPRT_DIED; + return (-1); + } + } + } + } + + return (len); +} + +static enum xprt_stat +svc_vc_stat(xprt) + SVCXPRT *xprt; +{ + struct cf_conn *cd; + + assert(xprt != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + + if (cd->strm_stat == XPRT_DIED) + return (XPRT_DIED); + if (! xdrrec_eof(&(cd->xdrs))) + return (XPRT_MOREREQS); + return (XPRT_IDLE); +} + +static bool_t +svc_vc_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct cf_conn *cd; + XDR *xdrs; + + assert(xprt != NULL); + assert(msg != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + xdrs = &(cd->xdrs); + + if (cd->nonblock) { + if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) + return FALSE; + } + + xdrs->x_op = XDR_DECODE; + (void)xdrrec_skiprecord(xdrs); + if (xdr_callmsg(xdrs, msg)) { + cd->x_id = msg->rm_xid; + return (TRUE); + } + cd->strm_stat = XPRT_DIED; + return (FALSE); +} + +static bool_t +svc_vc_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + + assert(xprt != NULL); + /* args_ptr may be NULL */ + return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), + args_ptr)); +} + +static bool_t +svc_vc_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + void *args_ptr; +{ + XDR *xdrs; + + assert(xprt != NULL); + /* args_ptr may be NULL */ + + xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); + + xdrs->x_op = XDR_FREE; + return ((*xdr_args)(xdrs, args_ptr)); +} + +static bool_t +svc_vc_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + struct cf_conn *cd; + XDR *xdrs; + bool_t rstat; + + assert(xprt != NULL); + assert(msg != NULL); + + cd = (struct cf_conn *)(xprt->xp_p1); + xdrs = &(cd->xdrs); + + xdrs->x_op = XDR_ENCODE; + msg->rm_xid = cd->x_id; + rstat = xdr_replymsg(xdrs, msg); + (void)xdrrec_endofrecord(xdrs, TRUE); + return (rstat); +} + +static void +svc_vc_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + extern mutex_t ops_lock; + +/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = svc_vc_recv; + ops.xp_stat = svc_vc_stat; + ops.xp_getargs = svc_vc_getargs; + ops.xp_reply = svc_vc_reply; + ops.xp_freeargs = svc_vc_freeargs; + ops.xp_destroy = svc_vc_destroy; + ops2.xp_control = svc_vc_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +static void +svc_vc_rendezvous_ops(xprt) + SVCXPRT *xprt; +{ + static struct xp_ops ops; + static struct xp_ops2 ops2; + extern mutex_t ops_lock; + + mutex_lock(&ops_lock); + if (ops.xp_recv == NULL) { + ops.xp_recv = rendezvous_request; + ops.xp_stat = rendezvous_stat; + ops.xp_getargs = + (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; + ops.xp_reply = + (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; + ops.xp_freeargs = + (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, + ops.xp_destroy = svc_vc_destroy; + ops2.xp_control = svc_vc_rendezvous_control; + } + xprt->xp_ops = &ops; + xprt->xp_ops2 = &ops2; + mutex_unlock(&ops_lock); +} + +/* + * Get the effective UID of the sending process. Used by rpcbind, keyserv + * and rpc.yppasswdd on AF_LOCAL. + */ +int +__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { + SOCKET sock; + int ret; + gid_t egid; + uid_t euid; + struct sockaddr *sa; + + sock = transp->xp_fd; + sa = (struct sockaddr *)transp->xp_rtaddr.buf; + if (sa->sa_family == AF_UNIX) { + ret = getpeereid(sock, &euid, &egid); + if (ret == 0) + *uid = euid; + return (ret); + } else + return (-1); +} + +#ifdef _WIN32 +void timersub( const struct timeval *tvp, const struct timeval *uvp, struct timeval *vvp ) +{ + vvp->tv_sec = tvp->tv_sec - uvp->tv_sec; + vvp->tv_usec = tvp->tv_usec - uvp->tv_usec; + if( vvp->tv_usec < 0 ) + { + --vvp->tv_sec; + vvp->tv_usec += 1000000; + } +} +#endif + +/* + * Destroy xprts that have not have had any activity in 'timeout' seconds. + * If 'cleanblock' is true, blocking connections (the default) are also + * cleaned. If timeout is 0, the least active connection is picked. + */ +bool_t +__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) +{ + int i, ncleaned; + SVCXPRT *xprt, *least_active; + struct timeval tv, tdiff, tmax; + struct cf_conn *cd; + + gettimeofday(&tv, NULL); + tmax.tv_sec = tmax.tv_usec = 0; + least_active = NULL; + rwlock_wrlock(&svc_fd_lock); + for (i = ncleaned = 0; i <= svc_maxfd; i++) { + if (FD_ISSET(i, fds)) { + xprt = __svc_xports[i]; + if (xprt == NULL || xprt->xp_ops == NULL || + xprt->xp_ops->xp_recv != svc_vc_recv) + continue; + cd = (struct cf_conn *)xprt->xp_p1; + if (!cleanblock && !cd->nonblock) + continue; + if (timeout == 0) { + timersub(&tv, &cd->last_recv_time, &tdiff); + if (timercmp(&tdiff, &tmax, >)) { + tmax = tdiff; + least_active = xprt; + } + continue; + } + if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { + __xprt_unregister_unlocked(xprt); + __svc_vc_dodestroy(xprt); + ncleaned++; + } + } + } + if (timeout == 0 && least_active != NULL) { + __xprt_unregister_unlocked(least_active); + __svc_vc_dodestroy(least_active); + ncleaned++; + } + rwlock_unlock(&svc_fd_lock); + return ncleaned > 0 ? TRUE : FALSE; +} diff --git a/libtirpc/src/winstubs.c b/libtirpc/src/winstubs.c new file mode 100644 index 0000000..13bf356 --- /dev/null +++ b/libtirpc/src/winstubs.c @@ -0,0 +1,12 @@ +/* XXX Need copyright info */ + +#include +#include + +/* +DWORD getpid(void) +{ + fprintf(stderr, "STUB: getpid() returning zero!\n"); + return 0; +} +*/ \ No newline at end of file diff --git a/libtirpc/src/wintirpc.c b/libtirpc/src/wintirpc.c new file mode 100644 index 0000000..10b071b --- /dev/null +++ b/libtirpc/src/wintirpc.c @@ -0,0 +1,200 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include + +WSADATA WSAData; + +static int init = 0; +static DWORD dwTlsIndex; + +extern void multithread_init(void); + +VOID +tirpc_report(LPTSTR lpszMsg) +{ + WCHAR chMsg[256]; + HANDLE hEventSource; + LPCWSTR lpszStrings[2]; + + // Use event logging to log the error. + // + hEventSource = RegisterEventSource(NULL, + TEXT("tirpc.dll")); + + swprintf_s(chMsg, sizeof(chMsg), L"tirpc report: %d", GetLastError()); + lpszStrings[0] = (LPCWSTR)chMsg; + lpszStrings[1] = lpszMsg; + + if (hEventSource != NULL) { + ReportEvent(hEventSource, // handle of event source + EVENTLOG_WARNING_TYPE, // event type + 0, // event category + 0, // event ID + NULL, // current user's SID + 2, // strings in lpszStrings + 0, // no bytes of raw data + lpszStrings, // array of error strings + NULL); // no raw data + + (VOID) DeregisterEventSource(hEventSource); + } +} + +void tirpc_criticalsection_init(void) { + multithread_init(); +} + +BOOL winsock_init(void) +{ + int err; + err = WSAStartup(MAKEWORD( 3, 3 ), &WSAData); // XXX THIS SHOULD BE FAILING!!!!!!!!!!!!!!!!! + if (err != 0) { + init = 0; + tirpc_report(L"WSAStartup failed!\n"); + WSACleanup(); + return FALSE; + } + return TRUE; +} + +BOOL winsock_fini(void) +{ + WSACleanup(); + return TRUE; +} + +BOOL WINAPI DllMain/*tirpc_main*/(HINSTANCE hinstDLL, // DLL module handle + DWORD fdwReason, // reason called + LPVOID lpvReserved) // reserved +{ + LPVOID lpvData; + BOOL fIgnore; + +// if (init++) +// return TRUE; + + // Deal with Thread Local Storage initialization!! + switch (fdwReason) + { + // The DLL is loading due to process + // initialization or a call to LoadLibrary. + case DLL_PROCESS_ATTACH: + + // Initialize socket library + if (winsock_init() == FALSE) + return FALSE; + + // Initialize CriticalSections + tirpc_criticalsection_init(); + + // Allocate a TLS index. + if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return FALSE; + + // No break: Initialize the index for first thread. + + // The attached process creates a new thread. + case DLL_THREAD_ATTACH: + + // Initialize the TLS index for this thread + lpvData = (LPVOID) LocalAlloc(LPTR, 256); + if (lpvData != NULL) + fIgnore = TlsSetValue(dwTlsIndex, lpvData); + + break; + + // The thread of the attached process terminates. + case DLL_THREAD_DETACH: + + // Release the allocated memory for this thread. + lpvData = TlsGetValue(dwTlsIndex); + if (lpvData != NULL) + LocalFree((HLOCAL) lpvData); + + break; + + // DLL unload due to process termination or FreeLibrary. + case DLL_PROCESS_DETACH: + + // Release the allocated memory for this thread. + lpvData = TlsGetValue(dwTlsIndex); + if (lpvData != NULL) + LocalFree((HLOCAL) lpvData); + + // Release the TLS index. + TlsFree(dwTlsIndex); + + // Clean up winsock stuff + winsock_fini(); + + break; + + default: + break; + } + + + return TRUE; +} + +int tirpc_exit(void) +{ + if (init == 0 || --init > 0) + return 0; + + return WSACleanup(); +} + + +void wintirpc_debug(char *fmt, ...) +{ +#ifdef _DEBUG + char buffer[2048]; +#else + static int triedToOpen = 0; + static FILE *dbgFile = NULL; +#endif + + va_list vargs; + va_start(vargs, fmt); + +#ifdef _DEBUG + vsprintf(buffer, fmt, vargs); + OutputDebugStringA(buffer); +#else + if (dbgFile == NULL && triedToOpen == 0) { + triedToOpen = 1; + dbgFile = fopen("c:\\etc\\rpcsec_gss_debug.txt", "w"); + } + if (dbgFile != NULL) { + vfprintf(dbgFile, fmt, vargs); + fflush(dbgFile); + } +#endif + + va_end(vargs); +} diff --git a/libtirpc/src/xdr.c b/libtirpc/src/xdr.c new file mode 100644 index 0000000..85396b3 --- /dev/null +++ b/libtirpc/src/xdr.c @@ -0,0 +1,872 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * xdr.c, Generic XDR routines implementation. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + * + * These are the "generic" xdr routines used to serialize and de-serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include +//#include +#include +#include +#include + +#include +#include + +typedef quad_t longlong_t; /* ANSI long long type */ +typedef u_quad_t u_longlong_t; /* ANSI unsigned long long type */ + +/* + * constants specific to the xdr "protocol" + */ +#define XDR_FALSE ((long) 0) +#define XDR_TRUE ((long) 1) +#define LASTUNSIGNED ((u_int) 0-1) + +/* + * for unit alignment + */ +static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; + +/* + * Free a data structure using XDR + * Not a filter, but a convenient utility nonetheless + */ +void +xdr_free(proc, objp) + xdrproc_t proc; + void *objp; +{ + XDR x; + + x.x_op = XDR_FREE; + (*proc)(&x, objp); +} + +/* + * XDR nothing + */ +bool_t +xdr_void(void) +{ + + return (TRUE); +} + + +/* + * XDR integers + */ +bool_t +xdr_int(xdrs, ip) + XDR *xdrs; + int *ip; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *ip; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *ip = (int) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * XDR unsigned integers + */ +bool_t +xdr_u_int(xdrs, up) + XDR *xdrs; + u_int *up; +{ + u_long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (u_long) *up; + return (XDR_PUTLONG(xdrs, (long *)&l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, (long *)&l)) { + return (FALSE); + } + *up = (u_int) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR long integers + * same as xdr_u_long - open coded to save a proc call! + */ +bool_t +xdr_long(xdrs, lp) + XDR *xdrs; + long *lp; +{ + switch (xdrs->x_op) { + case XDR_ENCODE: + return (XDR_PUTLONG(xdrs, lp)); + case XDR_DECODE: + return (XDR_GETLONG(xdrs, lp)); + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * XDR unsigned long integers + * same as xdr_long - open coded to save a proc call! + */ +bool_t +xdr_u_long(xdrs, ulp) + XDR *xdrs; + u_long *ulp; +{ + switch (xdrs->x_op) { + case XDR_ENCODE: + return (XDR_PUTLONG(xdrs, (long *)ulp)); + case XDR_DECODE: + return (XDR_GETLONG(xdrs, (long *)ulp)); + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR 32-bit integers + * same as xdr_u_int32_t - open coded to save a proc call! + */ +bool_t +xdr_int32_t(xdrs, int32_p) + XDR *xdrs; + int32_t *int32_p; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *int32_p; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *int32_p = (int32_t) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * XDR unsigned 32-bit integers + * same as xdr_int32_t - open coded to save a proc call! + */ +bool_t +xdr_u_int32_t(xdrs, u_int32_p) + XDR *xdrs; + u_int32_t *u_int32_p; +{ + u_long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (u_long) *u_int32_p; + return (XDR_PUTLONG(xdrs, (long *)&l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, (long *)&l)) { + return (FALSE); + } + *u_int32_p = (u_int32_t) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR short integers + */ +bool_t +xdr_short(xdrs, sp) + XDR *xdrs; + short *sp; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *sp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *sp = (short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * XDR unsigned short integers + */ +bool_t +xdr_u_short(xdrs, usp) + XDR *xdrs; + u_short *usp; +{ + u_long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (u_long) *usp; + return (XDR_PUTLONG(xdrs, (long *)&l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, (long *)&l)) { + return (FALSE); + } + *usp = (u_short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR 16-bit integers + */ +bool_t +xdr_int16_t(xdrs, int16_p) + XDR *xdrs; + int16_t *int16_p; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *int16_p; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *int16_p = (int16_t) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * XDR unsigned 16-bit integers + */ +bool_t +xdr_u_int16_t(xdrs, u_int16_p) + XDR *xdrs; + u_int16_t *u_int16_p; +{ + u_long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (u_long) *u_int16_p; + return (XDR_PUTLONG(xdrs, (long *)&l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, (long *)&l)) { + return (FALSE); + } + *u_int16_p = (u_int16_t) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR a char + */ +bool_t +xdr_char(xdrs, cp) + XDR *xdrs; + char *cp; +{ + int i; + + i = (*cp); + if (!xdr_int(xdrs, &i)) { + return (FALSE); + } + *cp = (char)i; + return (TRUE); +} + +/* + * XDR an unsigned char + */ +bool_t +xdr_u_char(xdrs, cp) + XDR *xdrs; + u_char *cp; +{ + u_int u; + + u = (*cp); + if (!xdr_u_int(xdrs, &u)) { + return (FALSE); + } + *cp = (u_char)u; + return (TRUE); +} + +/* + * XDR booleans + */ +bool_t +xdr_bool(xdrs, bp) + XDR *xdrs; + bool_t *bp; +{ + long lb; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + lb = *bp ? XDR_TRUE : XDR_FALSE; + return (XDR_PUTLONG(xdrs, &lb)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &lb)) { + return (FALSE); + } + *bp = (lb == XDR_FALSE) ? FALSE : TRUE; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * XDR enumerations + */ +bool_t +xdr_enum(xdrs, ep) + XDR *xdrs; + enum_t *ep; +{ + enum sizecheck { SIZEVAL }; /* used to find the size of an enum */ + + /* + * enums are treated as ints + */ + /* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) { + return (xdr_long(xdrs, (long *)(void *)ep)); + } else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) { + return (xdr_int(xdrs, (int *)(void *)ep)); + } else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) { + return (xdr_short(xdrs, (short *)(void *)ep)); + } else { + return (FALSE); + } +} + +/* + * XDR opaque data + * Allows the specification of a fixed size sequence of opaque bytes. + * cp points to the opaque object and cnt gives the byte length. + */ +bool_t +xdr_opaque(xdrs, cp, cnt) + XDR *xdrs; + caddr_t cp; + u_int cnt; +{ + u_int rndup; + static int crud[BYTES_PER_XDR_UNIT]; + + /* + * if no data we are done + */ + if (cnt == 0) + return (TRUE); + + /* + * round byte count to full xdr units + */ + rndup = cnt % BYTES_PER_XDR_UNIT; + if (rndup > 0) + rndup = BYTES_PER_XDR_UNIT - rndup; + + if (xdrs->x_op == XDR_DECODE) { + if (!XDR_GETBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup)); + } + + if (xdrs->x_op == XDR_ENCODE) { + if (!XDR_PUTBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); + } + + if (xdrs->x_op == XDR_FREE) { + return (TRUE); + } + + return (FALSE); +} + +/* + * XDR counted bytes + * *cpp is a pointer to the bytes, *sizep is the count. + * If *cpp is NULL maxsize bytes are allocated + */ +bool_t +xdr_bytes(xdrs, cpp, sizep, maxsize) + XDR *xdrs; + char **cpp; + u_int *sizep; + u_int maxsize; +{ + char *sp = *cpp; /* sp is the actual string pointer */ + u_int nodesize; + + /* + * first deal with the length since xdr bytes are counted + */ + if (! xdr_u_int(xdrs, sizep)) { + return (FALSE); + } + nodesize = *sizep; + if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { + return (FALSE); + } + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) { + + case XDR_DECODE: + if (nodesize == 0) { + return (TRUE); + } + if (sp == NULL) { + *cpp = sp = mem_alloc(nodesize); + } + if (sp == NULL) { + //warnx("xdr_bytes: out of memory"); + return (FALSE); + } + /* FALLTHROUGH */ + + case XDR_ENCODE: + return (xdr_opaque(xdrs, sp, nodesize)); + + case XDR_FREE: + if (sp != NULL) { + mem_free(sp, nodesize); + *cpp = NULL; + } + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * Implemented here due to commonality of the object. + */ +bool_t +xdr_netobj(xdrs, np) + XDR *xdrs; + struct netobj *np; +{ + + return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); +} + +/* + * XDR a descriminated union + * Support routine for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * an entry with a null procedure pointer. The routine gets + * the discriminant value and then searches the array of xdrdiscrims + * looking for that value. It calls the procedure given in the xdrdiscrim + * to handle the discriminant. If there is no specific routine a default + * routine may be called. + * If there is no specific or default routine an error is returned. + */ +bool_t +xdr_union(xdrs, dscmp, unp, choices, dfault) + XDR *xdrs; + enum_t *dscmp; /* enum to decide which arm to work on */ + char *unp; /* the union itself */ + const struct xdr_discrim *choices; /* [value, xdr proc] for each arm */ + xdrproc_t dfault; /* default xdr routine */ +{ + enum_t dscm; + + /* + * we deal with the discriminator; it's an enum + */ + if (! xdr_enum(xdrs, dscmp)) { + return (FALSE); + } + dscm = *dscmp; + + /* + * search choices for a value that matches the discriminator. + * if we find one, execute the xdr routine for that value. + */ + for (; choices->proc != NULL_xdrproc_t; choices++) { + if (choices->value == dscm) + return ((*(choices->proc))(xdrs, unp)); + } + + /* + * no match - execute the default xdr routine if there is one + */ + return ((dfault == NULL_xdrproc_t) ? FALSE : + (*dfault)(xdrs, unp)); +} + + +/* + * Non-portable xdr primitives. + * Care should be taken when moving these routines to new architectures. + */ + + +/* + * XDR null terminated ASCII strings + * xdr_string deals with "C strings" - arrays of bytes that are + * terminated by a NULL character. The parameter cpp references a + * pointer to storage; If the pointer is null, then the necessary + * storage is allocated. The last parameter is the max allowed length + * of the string as specified by a protocol. + */ +bool_t +xdr_string(xdrs, cpp, maxsize) + XDR *xdrs; + char **cpp; + u_int maxsize; +{ + char *sp = *cpp; /* sp is the actual string pointer */ + u_int size; + u_int nodesize; + + /* + * first deal with the length since xdr strings are counted-strings + */ + switch (xdrs->x_op) { + case XDR_FREE: + if (sp == NULL) { + return(TRUE); /* already free */ + } + /* FALLTHROUGH */ + case XDR_ENCODE: + if (sp == NULL) + return FALSE; + size = strlen(sp); + break; + case XDR_DECODE: + break; + } + if (! xdr_u_int(xdrs, &size)) { + return (FALSE); + } + if (size > maxsize) { + return (FALSE); + } + nodesize = size + 1; + if (nodesize == 0) { + /* This means an overflow. It a bug in the caller which + * provided a too large maxsize but nevertheless catch it + * here. + */ + return FALSE; + } + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) { + + case XDR_DECODE: + if (sp == NULL) + *cpp = sp = mem_alloc(nodesize); + if (sp == NULL) { + //warnx("xdr_string: out of memory"); + return (FALSE); + } + sp[size] = 0; + /* FALLTHROUGH */ + + case XDR_ENCODE: + return (xdr_opaque(xdrs, sp, size)); + + case XDR_FREE: + mem_free(sp, nodesize); + *cpp = NULL; + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +/* + * Wrapper for xdr_string that can be called directly from + * routines like clnt_call + */ +bool_t +xdr_wrapstring(xdrs, cpp) + XDR *xdrs; + char **cpp; +{ + return xdr_string(xdrs, cpp, LASTUNSIGNED); +} + +/* + * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t() + * are in the "non-portable" section because they require that a `long long' + * be a 64-bit type. + * + * --thorpej@netbsd.org, November 30, 1999 + */ + +/* + * XDR 64-bit integers + */ +bool_t +xdr_int64_t(xdrs, llp) + XDR *xdrs; + int64_t *llp; +{ + u_long ul[2]; + + switch (xdrs->x_op) { + case XDR_ENCODE: + ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff; + ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff; + if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + return (XDR_PUTLONG(xdrs, (long *)&ul[1])); + case XDR_DECODE: + if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) + return (FALSE); + *llp = (int64_t) + (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); + return (TRUE); + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR unsigned 64-bit integers + */ +bool_t +xdr_u_int64_t(xdrs, ullp) + XDR *xdrs; + u_int64_t *ullp; +{ + u_long ul[2]; + + switch (xdrs->x_op) { + case XDR_ENCODE: + ul[0] = (u_long)(*ullp >> 32) & 0xffffffff; + ul[1] = (u_long)(*ullp) & 0xffffffff; + if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + return (XDR_PUTLONG(xdrs, (long *)&ul[1])); + case XDR_DECODE: + if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE) + return (FALSE); + if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE) + return (FALSE); + *ullp = (u_int64_t) + (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1])); + return (TRUE); + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + + +/* + * XDR hypers + */ +bool_t +xdr_hyper(xdrs, llp) + XDR *xdrs; + longlong_t *llp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_int64_t(). + */ + return (xdr_int64_t(xdrs, (int64_t *)llp)); +} + + +/* + * XDR unsigned hypers + */ +bool_t +xdr_u_hyper(xdrs, ullp) + XDR *xdrs; + u_longlong_t *ullp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_u_int64_t(). + */ + return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp)); +} + + +/* + * XDR longlong_t's + */ +bool_t +xdr_longlong_t(xdrs, llp) + XDR *xdrs; + longlong_t *llp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_int64_t(). + */ + return (xdr_int64_t(xdrs, (int64_t *)llp)); +} + + +/* + * XDR u_longlong_t's + */ +bool_t +xdr_u_longlong_t(xdrs, ullp) + XDR *xdrs; + u_longlong_t *ullp; +{ + + /* + * Don't bother open-coding this; it's a fair amount of code. Just + * call xdr_u_int64_t(). + */ + return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp)); +} diff --git a/libtirpc/src/xdr_array.c b/libtirpc/src/xdr_array.c new file mode 100644 index 0000000..3ab9ce5 --- /dev/null +++ b/libtirpc/src/xdr_array.c @@ -0,0 +1,157 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * xdr_array.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * arrays. See xdr.h for more info on the interface to xdr. + */ + +#include +#include "namespace.h" +//#include +//#include +#include +#include +#include + +#include +#include +#include "un-namespace.h" + +/* + * XDR an array of arbitrary elements + * *addrp is a pointer to the array, *sizep is the number of elements. + * If addrp is NULL (*sizep * elsize) bytes are allocated. + * elsize is the size (in bytes) of each element, and elproc is the + * xdr procedure to call to handle each element of the array. + */ +bool_t +xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) + XDR *xdrs; + caddr_t *addrp; /* array pointer */ + u_int *sizep; /* number of elements */ + u_int maxsize; /* max numberof elements */ + u_int elsize; /* size in bytes of each element */ + xdrproc_t elproc; /* xdr routine to handle each element */ +{ + u_int i; + caddr_t target = *addrp; + u_int c; /* the actual element count */ + bool_t stat = TRUE; + u_int nodesize; + + /* like strings, arrays are really counted arrays */ + if (!xdr_u_int(xdrs, sizep)) { + return (FALSE); + } + c = *sizep; + if ((c > maxsize || UINT_MAX/elsize < c) && + (xdrs->x_op != XDR_FREE)) { + return (FALSE); + } + nodesize = c * elsize; + + /* + * if we are deserializing, we may need to allocate an array. + * We also save time by checking for a null array if we are freeing. + */ + if (target == NULL) + switch (xdrs->x_op) { + case XDR_DECODE: + if (c == 0) + return (TRUE); + *addrp = target = mem_alloc(nodesize); + if (target == NULL) { + //warnx("xdr_array: out of memory"); + return (FALSE); + } + memset(target, 0, nodesize); + break; + + case XDR_FREE: + return (TRUE); + + case XDR_ENCODE: + break; + } + + /* + * now we xdr each element of array + */ + for (i = 0; (i < c) && stat; i++) { + stat = (*elproc)(xdrs, target); + target += elsize; + } + + /* + * the array may need freeing + */ + if (xdrs->x_op == XDR_FREE) { + mem_free(*addrp, nodesize); + *addrp = NULL; + } + return (stat); +} + +/* + * xdr_vector(): + * + * XDR a fixed length array. Unlike variable-length arrays, + * the storage of fixed length arrays is static and unfreeable. + * > basep: base of the array + * > size: size of the array + * > elemsize: size of each element + * > xdr_elem: routine to XDR each element + */ +bool_t +xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) + XDR *xdrs; + char *basep; + u_int nelem; + u_int elemsize; + xdrproc_t xdr_elem; +{ + u_int i; + char *elptr; + + elptr = basep; + for (i = 0; i < nelem; i++) { + if (!(*xdr_elem)(xdrs, elptr)) { + return(FALSE); + } + elptr += elemsize; + } + return(TRUE); +} diff --git a/libtirpc/src/xdr_float.c b/libtirpc/src/xdr_float.c new file mode 100644 index 0000000..8f2426f --- /dev/null +++ b/libtirpc/src/xdr_float.c @@ -0,0 +1,300 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * xdr_float.c, Generic XDR routines implementation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "floating point" xdr routines used to (de)serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include +#include "namespace.h" +#include +//#include + +#include + +#include +#include +#include "un-namespace.h" + +/* + * NB: Not portable. + * This routine works on machines with IEEE754 FP and Vaxen. + */ + +#if defined(__vax__) + +/* What IEEE single precision floating point looks like on a Vax */ +struct ieee_single { + unsigned int mantissa: 23; + unsigned int exp : 8; + unsigned int sign : 1; +}; + +/* Vax single precision floating point */ +struct vax_single { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; +}; + +#define VAX_SNG_BIAS 0x81 +#define IEEE_SNG_BIAS 0x7f + +static struct sgl_limits { + struct vax_single s; + struct ieee_single ieee; +} sgl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */ + { 0x0, 0xff, 0x0 }}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */ + { 0x0, 0x0, 0x0 }} /* Min IEEE */ +}; +#else + +//#include +#define IEEEFP + +#endif /* vax */ + +bool_t +xdr_float(xdrs, fp) + XDR *xdrs; + float *fp; +{ +#ifndef IEEEFP + struct ieee_single is; + struct vax_single vs, *vsp; + struct sgl_limits *lim; + int i; +#endif + switch (xdrs->x_op) { + + case XDR_ENCODE: +#ifdef IEEEFP + return (XDR_PUTINT32(xdrs, (int32_t *)fp)); +#else + vs = *((struct vax_single *)fp); + for (i = 0, lim = sgl_limits; + i < sizeof(sgl_limits)/sizeof(struct sgl_limits); + i++, lim++) { + if ((vs.mantissa2 == lim->s.mantissa2) && + (vs.exp == lim->s.exp) && + (vs.mantissa1 == lim->s.mantissa1)) { + is = lim->ieee; + goto shipit; + } + } + is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS; + is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2; + shipit: + is.sign = vs.sign; + return (XDR_PUTINT32(xdrs, (int32_t *)&is)); +#endif + + case XDR_DECODE: +#ifdef IEEEFP + return (XDR_GETINT32(xdrs, (int32_t *)fp)); +#else + vsp = (struct vax_single *)fp; + if (!XDR_GETINT32(xdrs, (int32_t *)&is)) + return (FALSE); + for (i = 0, lim = sgl_limits; + i < sizeof(sgl_limits)/sizeof(struct sgl_limits); + i++, lim++) { + if ((is.exp == lim->ieee.exp) && + (is.mantissa == lim->ieee.mantissa)) { + *vsp = lim->s; + goto doneit; + } + } + vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; + vsp->mantissa2 = is.mantissa; + vsp->mantissa1 = (is.mantissa >> 16); + doneit: + vsp->sign = is.sign; + return (TRUE); +#endif + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} + +#if defined(__vax__) +/* What IEEE double precision floating point looks like on a Vax */ +struct ieee_double { + unsigned int mantissa1 : 20; + unsigned int exp : 11; + unsigned int sign : 1; + unsigned int mantissa2 : 32; +}; + +/* Vax double precision floating point */ +struct vax_double { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; + unsigned int mantissa3 : 16; + unsigned int mantissa4 : 16; +}; + +#define VAX_DBL_BIAS 0x81 +#define IEEE_DBL_BIAS 0x3ff +#define MASK(nbits) ((1 << nbits) - 1) + +static struct dbl_limits { + struct vax_double d; + struct ieee_double ieee; +} dbl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */ + { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */ + { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */ +}; + +#endif /* vax */ + + +bool_t +xdr_double(xdrs, dp) + XDR *xdrs; + double *dp; +{ +#ifdef IEEEFP + int32_t *i32p; + bool_t rv; +#else + int32_t *lp; + struct ieee_double id; + struct vax_double vd; + struct dbl_limits *lim; + int i; +#endif + + switch (xdrs->x_op) { + + case XDR_ENCODE: +#ifdef IEEEFP + i32p = (int32_t *)(void *)dp; +#if BYTE_ORDER == BIG_ENDIAN + rv = XDR_PUTINT32(xdrs, i32p); + if (!rv) + return (rv); + rv = XDR_PUTINT32(xdrs, i32p+1); +#else + rv = XDR_PUTINT32(xdrs, i32p+1); + if (!rv) + return (rv); + rv = XDR_PUTINT32(xdrs, i32p); +#endif + return (rv); +#else + vd = *((struct vax_double *)dp); + for (i = 0, lim = dbl_limits; + i < sizeof(dbl_limits)/sizeof(struct dbl_limits); + i++, lim++) { + if ((vd.mantissa4 == lim->d.mantissa4) && + (vd.mantissa3 == lim->d.mantissa3) && + (vd.mantissa2 == lim->d.mantissa2) && + (vd.mantissa1 == lim->d.mantissa1) && + (vd.exp == lim->d.exp)) { + id = lim->ieee; + goto shipit; + } + } + id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS; + id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3); + id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) | + (vd.mantissa3 << 13) | + ((vd.mantissa4 >> 3) & MASK(13)); + shipit: + id.sign = vd.sign; + lp = (int32_t *)&id; + return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp)); +#endif + + case XDR_DECODE: +#ifdef IEEEFP + i32p = (int32_t *)(void *)dp; +#if BYTE_ORDER == BIG_ENDIAN + rv = XDR_GETINT32(xdrs, i32p); + if (!rv) + return (rv); + rv = XDR_GETINT32(xdrs, i32p+1); +#else + rv = XDR_GETINT32(xdrs, i32p+1); + if (!rv) + return (rv); + rv = XDR_GETINT32(xdrs, i32p); +#endif + return (rv); +#else + lp = (int32_t *)&id; + if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp)) + return (FALSE); + for (i = 0, lim = dbl_limits; + i < sizeof(dbl_limits)/sizeof(struct dbl_limits); + i++, lim++) { + if ((id.mantissa2 == lim->ieee.mantissa2) && + (id.mantissa1 == lim->ieee.mantissa1) && + (id.exp == lim->ieee.exp)) { + vd = lim->d; + goto doneit; + } + } + vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS; + vd.mantissa1 = (id.mantissa1 >> 13); + vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) | + (id.mantissa2 >> 29); + vd.mantissa3 = (id.mantissa2 >> 13); + vd.mantissa4 = (id.mantissa2 << 3); + doneit: + vd.sign = id.sign; + *dp = *((double *)&vd); + return (TRUE); +#endif + + case XDR_FREE: + return (TRUE); + } + /* NOTREACHED */ + return (FALSE); +} diff --git a/libtirpc/src/xdr_mem.c b/libtirpc/src/xdr_mem.c new file mode 100644 index 0000000..9a6c063 --- /dev/null +++ b/libtirpc/src/xdr_mem.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * xdr_mem.h, XDR implementation using memory buffers. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * If you have some data to be interpreted as external data representation + * or to be converted to external data representation in a memory buffer, + * then this is the package for you. + * + */ + +#include +#include "namespace.h" +#include + +//#include + +#include + +#include +#include +#include "un-namespace.h" + +static void xdrmem_destroy(XDR *); +static bool_t xdrmem_getlong_aligned(XDR *, long *); +static bool_t xdrmem_putlong_aligned(XDR *, const long *); +static bool_t xdrmem_getlong_unaligned(XDR *, long *); +static bool_t xdrmem_putlong_unaligned(XDR *, const long *); +static bool_t xdrmem_getbytes(XDR *, char *, u_int); +static bool_t xdrmem_putbytes(XDR *, const char *, u_int); +/* XXX: w/64-bit pointers, u_int not enough! */ +static u_int xdrmem_getpos(XDR *); +static bool_t xdrmem_setpos(XDR *, u_int); +static int32_t *xdrmem_inline_aligned(XDR *, u_int); +static int32_t *xdrmem_inline_unaligned(XDR *, u_int); + +static const struct xdr_ops xdrmem_ops_aligned = { + xdrmem_getlong_aligned, + xdrmem_putlong_aligned, + xdrmem_getbytes, + xdrmem_putbytes, + xdrmem_getpos, + xdrmem_setpos, + xdrmem_inline_aligned, + xdrmem_destroy +}; + +static const struct xdr_ops xdrmem_ops_unaligned = { + xdrmem_getlong_unaligned, + xdrmem_putlong_unaligned, + xdrmem_getbytes, + xdrmem_putbytes, + xdrmem_getpos, + xdrmem_setpos, + xdrmem_inline_unaligned, + xdrmem_destroy +}; + +/* + * The procedure xdrmem_create initializes a stream descriptor for a + * memory buffer. + */ +void +xdrmem_create(xdrs, addr, size, op) + XDR *xdrs; + char *addr; + u_int size; + enum xdr_op op; +{ + + xdrs->x_op = op; + xdrs->x_ops = (PtrToUlong(addr) & (sizeof(int32_t) - 1)) + ? &xdrmem_ops_unaligned : &xdrmem_ops_aligned; + xdrs->x_private = xdrs->x_base = addr; + xdrs->x_handy = size; +} + +/*ARGSUSED*/ +static void +xdrmem_destroy(xdrs) + XDR *xdrs; +{ + +} + +static bool_t +xdrmem_getlong_aligned(xdrs, lp) + XDR *xdrs; + long *lp; +{ + + if (xdrs->x_handy < sizeof(int32_t)) + return (FALSE); + xdrs->x_handy -= sizeof(int32_t); + *lp = ntohl(*(u_int32_t *)xdrs->x_private); + xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t); + return (TRUE); +} + +static bool_t +xdrmem_putlong_aligned(xdrs, lp) + XDR *xdrs; + const long *lp; +{ + + if (xdrs->x_handy < sizeof(int32_t)) + return (FALSE); + xdrs->x_handy -= sizeof(int32_t); + *(u_int32_t *)xdrs->x_private = htonl((u_int32_t)*lp); + xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t); + return (TRUE); +} + +static bool_t +xdrmem_getlong_unaligned(xdrs, lp) + XDR *xdrs; + long *lp; +{ + u_int32_t l; + + if (xdrs->x_handy < sizeof(int32_t)) + return (FALSE); + xdrs->x_handy -= sizeof(int32_t); + memmove(&l, xdrs->x_private, sizeof(int32_t)); + *lp = ntohl(l); + xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t); + return (TRUE); +} + +static bool_t +xdrmem_putlong_unaligned(xdrs, lp) + XDR *xdrs; + const long *lp; +{ + u_int32_t l; + + if (xdrs->x_handy < sizeof(int32_t)) + return (FALSE); + xdrs->x_handy -= sizeof(int32_t); + l = htonl((u_int32_t)*lp); + memmove(xdrs->x_private, &l, sizeof(int32_t)); + xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t); + return (TRUE); +} + +static bool_t +xdrmem_getbytes(xdrs, addr, len) + XDR *xdrs; + char *addr; + u_int len; +{ + + if (xdrs->x_handy < len) + return (FALSE); + xdrs->x_handy -= len; + memmove(addr, xdrs->x_private, len); + xdrs->x_private = (char *)xdrs->x_private + len; + return (TRUE); +} + +static bool_t +xdrmem_putbytes(xdrs, addr, len) + XDR *xdrs; + const char *addr; + u_int len; +{ + + if (xdrs->x_handy < len) + return (FALSE); + xdrs->x_handy -= len; + memmove(xdrs->x_private, addr, len); + xdrs->x_private = (char *)xdrs->x_private + len; + return (TRUE); +} + +static u_int +xdrmem_getpos(xdrs) + XDR *xdrs; +{ + + /* XXX w/64-bit pointers, u_int not enough! */ + return (u_int)(PtrToUlong(xdrs->x_private) - PtrToUlong(xdrs->x_base)); +} + +static bool_t +xdrmem_setpos(xdrs, pos) + XDR *xdrs; + u_int pos; +{ + char *newaddr = xdrs->x_base + pos; + char *lastaddr = (char *)xdrs->x_private + xdrs->x_handy; + + if (newaddr > lastaddr) + return (FALSE); + xdrs->x_private = newaddr; + xdrs->x_handy = (u_int)(lastaddr - newaddr); /* XXX sizeof(u_int) x_handy >= len) { + xdrs->x_handy -= len; + buf = (int32_t *)xdrs->x_private; + xdrs->x_private = (char *)xdrs->x_private + len; + } + return (buf); +} + +/* ARGSUSED */ +static int32_t * +xdrmem_inline_unaligned(xdrs, len) + XDR *xdrs; + u_int len; +{ + + return (0); +} diff --git a/libtirpc/src/xdr_rec.c b/libtirpc/src/xdr_rec.c new file mode 100644 index 0000000..8e97ac6 --- /dev/null +++ b/libtirpc/src/xdr_rec.c @@ -0,0 +1,791 @@ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include +//#include + +/* + * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" + * layer above tcp (for rpc's use). + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These routines interface XDRSTREAMS to a tcp/ip connection. + * There is a record marking layer between the xdr stream + * and the tcp transport level. A record is composed on one or more + * record fragments. A record fragment is a thirty-two bit header followed + * by n bytes of data, where n is contained in the header. The header + * is represented as a htonl(u_long). Thegh order bit encodes + * whether or not the fragment is the last fragment of the record + * (1 => fragment is last, 0 => more fragments to follow. + * The other 31 bits encode the byte length of the fragment. + */ + +#include +#include +#include + +//#include + +//#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "rpc_com.h" +//#include +static bool_t xdrrec_getlong(XDR *, long *); +static bool_t xdrrec_putlong(XDR *, const long *); +static bool_t xdrrec_getbytes(XDR *, char *, u_int); + +static bool_t xdrrec_putbytes(XDR *, const char *, u_int); +static u_int xdrrec_getpos(XDR *); +static bool_t xdrrec_setpos(XDR *, u_int); +static int32_t *xdrrec_inline(XDR *, u_int); +static void xdrrec_destroy(XDR *); + +static const struct xdr_ops xdrrec_ops = { + xdrrec_getlong, + xdrrec_putlong, + xdrrec_getbytes, + xdrrec_putbytes, + xdrrec_getpos, + xdrrec_setpos, + xdrrec_inline, + xdrrec_destroy +}; + +/* + * A record is composed of one or more record fragments. + * A record fragment is a four-byte header followed by zero to + * 2**32-1 bytes. The header is treated as a long unsigned and is + * encode/decoded to the network via htonl/ntohl. The low order 31 bits + * are a byte count of the fragment. The highest order bit is a boolean: + * 1 => this fragment is the last fragment of the record, + * 0 => this fragment is followed by more fragment(s). + * + * The fragment/record machinery is not general; it is constructed to + * meet the needs of xdr and rpc based on tcp. + */ + +#define LAST_FRAG ((u_int32_t)(1 << 31)) + +typedef struct rec_strm { + char *tcp_handle; + /* + * out-goung bits + */ + int (*writeit)(void *, void *, int); + char *out_base; /* output buffer (points to frag header) */ + char *out_finger; /* next output position */ + char *out_boundry; /* data cannot up to this address */ + u_int32_t *frag_header; /* beginning of curren fragment */ + bool_t frag_sent; /* true if buffer sent in middle of record */ + /* + * in-coming bits + */ + int (*readit)(void *, void *, int); + u_long in_size; /* fixed size of the input buffer */ + char *in_base; + char *in_finger; /* location of next byte to be had */ + char *in_boundry; /* can read up to this location */ + u_int fbtbc; /* fragment bytes to be consumed */ + bool_t last_frag; + u_int sendsize; + u_int recvsize; + + bool_t nonblock; + bool_t in_haveheader; + u_int32_t in_header; + char *in_hdrp; + u_int in_hdrlen; + u_int in_reclen; + u_int in_received; + u_int in_maxrec; +} RECSTREAM; + +static u_int fix_buf_size(u_int); +static bool_t flush_out(RECSTREAM *, bool_t); +static bool_t fill_input_buf(RECSTREAM *); +static bool_t get_input_bytes(RECSTREAM *, char *, u_int); +static bool_t set_input_fragment(RECSTREAM *); +static bool_t skip_input_bytes(RECSTREAM *, u_int); +static bool_t realloc_stream(RECSTREAM *, u_int); + + +/* + * Create an xdr handle for xdrrec + * xdrrec_create fills in xdrs. Sendsize and recvsize are + * send and recv buffer sizes (0 => use default). + * tcp_handle is an opaque handle that is passed as the first parameter to + * the procedures readit and writeit. Readit and writeit are read and + * write respectively. They are like the system + * calls expect that they take an opaque handle rather than an fd. + */ +void +xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) + XDR *xdrs; + u_int sendsize; + u_int recvsize; + void *tcp_handle; + /* like read, but pass it a tcp_handle, not sock */ + int (*readit)(void *, void *, int); + /* like write, but pass it a tcp_handle, not sock */ + int (*writeit)(void *, void *, int); +{ + RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM)); + + if (rstrm == NULL) { + //warnx("xdrrec_create: out of memory"); + /* + * This is bad. Should rework xdrrec_create to + * return a handle, and in this case return NULL + */ + return; + } + rstrm->sendsize = sendsize = fix_buf_size(sendsize); + rstrm->out_base = mem_alloc(rstrm->sendsize); + if (rstrm->out_base == NULL) { + //warnx("xdrrec_create: out of memory"); + mem_free(rstrm, sizeof(RECSTREAM)); + return; + } + rstrm->recvsize = recvsize = fix_buf_size(recvsize); + rstrm->in_base = mem_alloc(recvsize); + if (rstrm->in_base == NULL) { + //warnx("xdrrec_create: out of memory"); + mem_free(rstrm->out_base, sendsize); + mem_free(rstrm, sizeof(RECSTREAM)); + return; + } + /* + * now the rest ... + */ + xdrs->x_ops = &xdrrec_ops; + xdrs->x_private = rstrm; + rstrm->tcp_handle = tcp_handle; + rstrm->readit = readit; + rstrm->writeit = writeit; + rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; + rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base; + rstrm->out_finger += sizeof(u_int32_t); + rstrm->out_boundry += sendsize; + rstrm->frag_sent = FALSE; + rstrm->in_size = recvsize; + rstrm->in_boundry = rstrm->in_base; + rstrm->in_finger = (rstrm->in_boundry += recvsize); + rstrm->fbtbc = 0; + rstrm->last_frag = TRUE; + rstrm->in_haveheader = FALSE; + rstrm->in_hdrlen = 0; + rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; + rstrm->nonblock = FALSE; + rstrm->in_reclen = 0; + rstrm->in_received = 0; +} + + +/* + * The reoutines defined below are the xdr ops which will go into the + * xdr handle filled in by xdrrec_create. + */ + +static bool_t +xdrrec_getlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger); + int32_t mylong; + + /* first try the inline, fast case */ + if ((rstrm->fbtbc >= sizeof(int32_t)) && + ((PtrToLong(rstrm->in_boundry) - PtrToLong(buflp)) >= sizeof(int32_t))) { + *lp = (long)ntohl((u_int32_t)(*buflp)); + rstrm->fbtbc -= sizeof(int32_t); + rstrm->in_finger += sizeof(int32_t); + } else { + if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, + sizeof(int32_t))) + return (FALSE); + *lp = (long)ntohl((u_int32_t)mylong); + } + return (TRUE); +} + +static bool_t +xdrrec_putlong(xdrs, lp) + XDR *xdrs; + const long *lp; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); + + if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) { + /* + * this case should almost never happen so the code is + * inefficient + */ + rstrm->out_finger -= sizeof(int32_t); + rstrm->frag_sent = TRUE; + if (! flush_out(rstrm, FALSE)) + return (FALSE); + dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); + rstrm->out_finger += sizeof(int32_t); + } + *dest_lp = (int32_t)htonl((u_int32_t)(*lp)); + return (TRUE); +} + +static bool_t /* must manage buffers, fragments, and records */ +xdrrec_getbytes(xdrs, addr, len) + XDR *xdrs; + char *addr; + u_int len; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + u_int current; + + while (len > 0) { + current = (int)rstrm->fbtbc; + if (current == 0) { + if (rstrm->last_frag) + return (FALSE); + if (! set_input_fragment(rstrm)) + return (FALSE); + continue; + } + current = (len < current) ? len : current; + if (! get_input_bytes(rstrm, addr, current)) + return (FALSE); + addr += current; + rstrm->fbtbc -= current; + len -= current; + } + return (TRUE); +} + +static bool_t +xdrrec_putbytes(xdrs, addr, len) + XDR *xdrs; + const char *addr; + u_int len; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + size_t current; + + while (len > 0) { + current = (size_t)(PtrToUlong(rstrm->out_boundry) - + PtrToUlong(rstrm->out_finger)); + current = (len < current) ? len : current; + memmove(rstrm->out_finger, addr, current); + rstrm->out_finger += current; + addr += current; + len -= current; + if (rstrm->out_finger == rstrm->out_boundry) { + rstrm->frag_sent = TRUE; + if (! flush_out(rstrm, FALSE)) + return (FALSE); + } + } + return (TRUE); +} + +static u_int +xdrrec_getpos(xdrs) + XDR *xdrs; +{ + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + off_t pos; + + //pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); + pos = _lseek((int)PtrToUlong(rstrm->tcp_handle), (off_t)0, 1); + if (pos != -1) + switch (xdrs->x_op) { + + case XDR_ENCODE: + pos += PtrToLong(rstrm->out_finger) - PtrToLong(rstrm->out_base); + break; + + case XDR_DECODE: + pos -= PtrToLong(rstrm->in_boundry) - PtrToLong(rstrm->in_finger); + break; + + default: + pos = (off_t) -1; + break; + } + return ((u_int) pos); +} + +static bool_t +xdrrec_setpos(xdrs, pos) + XDR *xdrs; + u_int pos; +{ + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + u_int currpos = xdrrec_getpos(xdrs); + int delta = currpos - pos; + char *newpos; + + if ((int)currpos != -1) + switch (xdrs->x_op) { + + case XDR_ENCODE: + newpos = rstrm->out_finger - delta; + if ((newpos > (char *)(void *)(rstrm->frag_header)) && + (newpos < rstrm->out_boundry)) { + rstrm->out_finger = newpos; + return (TRUE); + } + break; + + case XDR_DECODE: + newpos = rstrm->in_finger - delta; + if ((delta < (int)(rstrm->fbtbc)) && + (newpos <= rstrm->in_boundry) && + (newpos >= rstrm->in_base)) { + rstrm->in_finger = newpos; + rstrm->fbtbc -= delta; + return (TRUE); + } + break; + + case XDR_FREE: + break; + } + return (FALSE); +} + +static int32_t * +xdrrec_inline(xdrs, len) + XDR *xdrs; + u_int len; +{ + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + int32_t *buf = NULL; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + if ((rstrm->out_finger + len) <= rstrm->out_boundry) { + buf = (int32_t *)(void *)rstrm->out_finger; + rstrm->out_finger += len; + } + break; + + case XDR_DECODE: + if ((len <= rstrm->fbtbc) && + ((rstrm->in_finger + len) <= rstrm->in_boundry)) { + buf = (int32_t *)(void *)rstrm->in_finger; + rstrm->fbtbc -= len; + rstrm->in_finger += len; + } + break; + + case XDR_FREE: + break; + } + return (buf); +} + +static void +xdrrec_destroy(xdrs) + XDR *xdrs; +{ + RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + + mem_free(rstrm->out_base, rstrm->sendsize); + mem_free(rstrm->in_base, rstrm->recvsize); + mem_free(rstrm, sizeof(RECSTREAM)); +} + + +/* + * Exported routines to manage xdr records + */ + +/* + * Before reading (deserializing from the stream, one should always call + * this procedure to guarantee proper record alignment. + */ +void xdrrec_setlastfrag(xdrs) + XDR *xdrs; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + rstrm->last_frag = 1; +} + +bool_t +xdrrec_skiprecord(xdrs) + XDR *xdrs; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + enum xprt_stat xstat; + + if (rstrm->nonblock) { + if (__xdrrec_getrec(xdrs, &xstat, FALSE)) { + rstrm->fbtbc = 0; + return TRUE; + } + if (rstrm->in_finger == rstrm->in_boundry && + xstat == XPRT_MOREREQS) { + rstrm->fbtbc = 0; + return TRUE; + } + return FALSE; + } + + while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { + if (! skip_input_bytes(rstrm, rstrm->fbtbc)) + return (FALSE); + rstrm->fbtbc = 0; + if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) + return (FALSE); + } + rstrm->last_frag = FALSE; + return (TRUE); +} + +/* + * Look ahead function. + * Returns TRUE iff there is no more input in the buffer + * after consuming the rest of the current record. + */ +bool_t +xdrrec_eof(xdrs) + XDR *xdrs; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + + while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { + if (! skip_input_bytes(rstrm, rstrm->fbtbc)) + return (TRUE); + rstrm->fbtbc = 0; + if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) + return (TRUE); + } + if (rstrm->in_finger == rstrm->in_boundry) + return (TRUE); + return (FALSE); +} + +/* + * The client must tell the package when an end-of-record has occurred. + * The second paraemters tells whether the record should be flushed to the + * (output) tcp stream. (This let's the package support batched or + * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. + */ +bool_t +xdrrec_endofrecord(xdrs, sendnow) + XDR *xdrs; + bool_t sendnow; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + u_long len; /* fragment length */ + + if (sendnow || rstrm->frag_sent || + (PtrToUlong(rstrm->out_finger) + sizeof(u_int32_t) >= + PtrToUlong(rstrm->out_boundry))) { + rstrm->frag_sent = FALSE; + return (flush_out(rstrm, TRUE)); + } + len = PtrToUlong(rstrm->out_finger) - PtrToUlong(rstrm->frag_header) - + sizeof(u_int32_t); + *(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG); + rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger; + rstrm->out_finger += sizeof(u_int32_t); + return (TRUE); +} + +/* + * Fill the stream buffer with a record for a non-blocking connection. + * Return true if a record is available in the buffer, false if not. + */ +bool_t +__xdrrec_getrec(xdrs, statp, expectdata) + XDR *xdrs; + enum xprt_stat *statp; + bool_t expectdata; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + int n; + u_int fraglen; + + if (!rstrm->in_haveheader) { + n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp, + (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen); + if (n == 0) { + *statp = expectdata ? XPRT_DIED : XPRT_IDLE; + return FALSE; + } + if (n < 0) { + *statp = XPRT_DIED; + return FALSE; + } + rstrm->in_hdrp += n; + rstrm->in_hdrlen += n; + if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) { + *statp = XPRT_MOREREQS; + return FALSE; + } + rstrm->in_header = ntohl(rstrm->in_header); + fraglen = (int)(rstrm->in_header & ~LAST_FRAG); + if (fraglen == 0 || fraglen > rstrm->in_maxrec || + (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) { + *statp = XPRT_DIED; + return FALSE; + } + rstrm->in_reclen += fraglen; + if (rstrm->in_reclen > rstrm->recvsize) + realloc_stream(rstrm, rstrm->in_reclen); + if (rstrm->in_header & LAST_FRAG) { + rstrm->in_header &= ~LAST_FRAG; + rstrm->last_frag = TRUE; + } + } + + n = rstrm->readit(rstrm->tcp_handle, + rstrm->in_base + rstrm->in_received, + (rstrm->in_reclen - rstrm->in_received)); + + if (n < 0) { + *statp = XPRT_DIED; + return FALSE; + } + + if (n == 0) { + *statp = expectdata ? XPRT_DIED : XPRT_IDLE; + return FALSE; + } + + rstrm->in_received += n; + + if (rstrm->in_received == rstrm->in_reclen) { + rstrm->in_haveheader = FALSE; + rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; + rstrm->in_hdrlen = 0; + if (rstrm->last_frag) { + rstrm->fbtbc = rstrm->in_reclen; + rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen; + rstrm->in_finger = rstrm->in_base; + rstrm->in_reclen = rstrm->in_received = 0; + *statp = XPRT_MOREREQS; + return TRUE; + } + } + + *statp = XPRT_MOREREQS; + return FALSE; +} + +bool_t +__xdrrec_setnonblock(xdrs, maxrec) + XDR *xdrs; + int maxrec; +{ + RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + + rstrm->nonblock = TRUE; + if (maxrec == 0) + maxrec = rstrm->recvsize; + rstrm->in_maxrec = maxrec; + return TRUE; +} + +/* + * Internal useful routines + */ +static bool_t +flush_out(rstrm, eor) + RECSTREAM *rstrm; + bool_t eor; +{ + u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0; + u_int32_t len = (u_int32_t)(PtrToUlong(rstrm->out_finger) - + PtrToUlong(rstrm->frag_header) - sizeof(u_int32_t)); + + *(rstrm->frag_header) = htonl(len | eormask); + len = (u_int32_t)(PtrToUlong(rstrm->out_finger) - + PtrToUlong(rstrm->out_base)); + if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) + != (int)len) + return (FALSE); + rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base; + rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t); + return (TRUE); +} + +static bool_t /* knows nothing about records! Only about input buffers */ +fill_input_buf(rstrm) + RECSTREAM *rstrm; +{ + char *where; + u_int32_t i; + int len; + + if (rstrm->nonblock) + return FALSE; + + where = rstrm->in_base; + i = (u_int32_t)(PtrToUlong(rstrm->in_boundry) % BYTES_PER_XDR_UNIT); + where += i; + len = (u_int32_t)(rstrm->in_size - i); + if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) + return (FALSE); + rstrm->in_finger = where; + where += len; + rstrm->in_boundry = where; + return (TRUE); +} + +static bool_t /* knows nothing about records! Only about input buffers */ +get_input_bytes(rstrm, addr, len) + RECSTREAM *rstrm; + char *addr; + u_int len; +{ + size_t current; + + if (rstrm->nonblock) { + if (len > (u_int)(rstrm->in_boundry - rstrm->in_finger)) + return FALSE; + memcpy(addr, rstrm->in_finger, (size_t)len); + rstrm->in_finger += len; + return TRUE; + } + + while (len > 0) { + current = (size_t)(PtrToLong(rstrm->in_boundry) - + PtrToLong(rstrm->in_finger)); + if (current == 0) { + if (! fill_input_buf(rstrm)) + return (FALSE); + continue; + } + current = (len < current) ? len : current; + memmove(addr, rstrm->in_finger, current); + rstrm->in_finger += current; + addr += current; + len -= current; + } + return (TRUE); +} + +static bool_t /* next two bytes of the input stream are treated as a header */ +set_input_fragment(rstrm) + RECSTREAM *rstrm; +{ + u_int32_t header; + + if (rstrm->nonblock) + return FALSE; + if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header))) + return (FALSE); + header = ntohl(header); + rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; + /* + * Sanity check. Try not to accept wildly incorrect + * record sizes. Unfortunately, the only record size + * we can positively identify as being 'wildly incorrect' + * is zero. Ridiculously large record sizes may look wrong, + * but we don't have any way to be certain that they aren't + * what the client actually intended to send us. + */ + if (header == 0) + return(FALSE); + rstrm->fbtbc = header & (~LAST_FRAG); + return (TRUE); +} + +static bool_t /* consumes input bytes; knows nothing about records! */ +skip_input_bytes(rstrm, cnt) + RECSTREAM *rstrm; + u_int cnt; +{ + u_int32_t current; + + while (cnt > 0) { + current = (u_int32_t)(PtrToUlong(rstrm->in_boundry) - + PtrToUlong(rstrm->in_finger)); + if (current == 0) { + if (! fill_input_buf(rstrm)) + return (FALSE); + continue; + } + current = (u_int32_t)((cnt < current) ? cnt : current); + rstrm->in_finger += current; + cnt -= current; + } + return (TRUE); +} + +static u_int +fix_buf_size(s) + u_int s; +{ + + if (s < 100) + s = 4000; + return (RNDUP(s)); +} + +/* + * Reallocate the input buffer for a non-block stream. + */ +static bool_t +realloc_stream(rstrm, size) + RECSTREAM *rstrm; + u_int size; +{ + ptrdiff_t diff; + char *buf; + + if (size > rstrm->recvsize) { + buf = realloc(rstrm->in_base, (size_t)size); + if (buf == NULL) + return FALSE; + diff = buf - rstrm->in_base; + rstrm->in_finger += diff; + rstrm->in_base = buf; + rstrm->in_boundry = buf + size; + rstrm->recvsize = size; + rstrm->in_size = size; + } + + return TRUE; +} diff --git a/libtirpc/src/xdr_reference.c b/libtirpc/src/xdr_reference.c new file mode 100644 index 0000000..875cffb --- /dev/null +++ b/libtirpc/src/xdr_reference.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include +//#include + +/* + * xdr_reference.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1987, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * "pointers". See xdr.h for more info on the interface to xdr. + */ + +#include +#include "namespace.h" +//#include +#include +#include +#include + +#include +#include +#include "libc_private.h" + +/* + * XDR an indirect pointer + * xdr_reference is for recursively translating a structure that is + * referenced by a pointer inside the structure that is currently being + * translated. pp references a pointer to storage. If *pp is null + * the necessary storage is allocated. + * size is the sizeof the referneced structure. + * proc is the routine to handle the referenced structure. + */ +bool_t +xdr_reference(xdrs, pp, size, proc) + XDR *xdrs; + caddr_t *pp; /* the pointer to work on */ + u_int size; /* size of the object pointed to */ + xdrproc_t proc; /* xdr routine to handle the object */ +{ + caddr_t loc = *pp; + bool_t stat; + + if (loc == NULL) + switch (xdrs->x_op) { + case XDR_FREE: + return (TRUE); + + case XDR_DECODE: + *pp = loc = (caddr_t) mem_alloc(size); + if (loc == NULL) { + //warnx("xdr_reference: out of memory"); + return (FALSE); + } + memset(loc, 0, size); + break; + + case XDR_ENCODE: + break; + } + + stat = (*proc)(xdrs, loc); + + if (xdrs->x_op == XDR_FREE) { + mem_free(loc, size); + *pp = NULL; + } + return (stat); +} + + +/* + * xdr_pointer(): + * + * XDR a pointer to a possibly recursive data structure. This + * differs with xdr_reference in that it can serialize/deserialiaze + * trees correctly. + * + * What's sent is actually a union: + * + * union object_pointer switch (boolean b) { + * case TRUE: object_data data; + * case FALSE: void nothing; + * } + * + * > objpp: Pointer to the pointer to the object. + * > obj_size: size of the object. + * > xdr_obj: routine to XDR an object. + * + */ +bool_t +xdr_pointer(xdrs,objpp,obj_size,xdr_obj) + XDR *xdrs; + char **objpp; + u_int obj_size; + xdrproc_t xdr_obj; +{ + + bool_t more_data; + + more_data = (*objpp != NULL); + if (! xdr_bool(xdrs,&more_data)) { + return (FALSE); + } + if (! more_data) { + *objpp = NULL; + return (TRUE); + } + return (xdr_reference(xdrs,objpp,obj_size,xdr_obj)); +} diff --git a/libtirpc/src/xdr_sizeof.c b/libtirpc/src/xdr_sizeof.c new file mode 100644 index 0000000..81278db --- /dev/null +++ b/libtirpc/src/xdr_sizeof.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * xdr_sizeof.c + * + * Copyright 1990 Sun Microsystems, Inc. + * + * General purpose routine to see how much space something will use + * when serialized using XDR. + */ + +//#include + +#include +#include "namespace.h" +#include +#include +#include +#include +#include "un-namespace.h" + +/* ARGSUSED */ +static bool_t +x_putlong(XDR *xdrs, const long *longp) +{ + xdrs->x_handy += BYTES_PER_XDR_UNIT; + return (TRUE); +} + +/* ARGSUSED */ +static bool_t +x_putbytes(XDR *xdrs, const char *bp, u_int len) +{ + xdrs->x_handy += len; + return (TRUE); +} + +static u_int +x_getpostn(XDR *xdrs) +{ + return (xdrs->x_handy); +} + +/* ARGSUSED */ +static bool_t +x_setpostn(XDR *xdrs, u_int pos) +{ + /* This is not allowed */ + return (FALSE); +} + +static int32_t * +x_inline(XDR *xdrs, u_int len) +{ + if (len == 0) { + return (NULL); + } + if (xdrs->x_op != XDR_ENCODE) { + return (NULL); + } + if (len < PtrToUlong(xdrs->x_base)) { + /* x_private was already allocated */ + xdrs->x_handy += len; + return ((int32_t *) xdrs->x_private); + } else { + /* Free the earlier space and allocate new area */ + if (xdrs->x_private) + free(xdrs->x_private); + if ((xdrs->x_private = (caddr_t) malloc(len)) == NULL) { + xdrs->x_base = 0; + return (NULL); + } + xdrs->x_base = UIntToPtr(len); + //xdrs->x_base = len; // XXX Is this right??? + xdrs->x_handy += len; + return ((int32_t *) xdrs->x_private); + } +} + +static int +harmless() +{ + /* Always return FALSE/NULL, as the case may be */ + return (0); +} + +static void +x_destroy(XDR *xdrs) +{ + xdrs->x_handy = 0; + xdrs->x_base = 0; + if (xdrs->x_private) { + free(xdrs->x_private); + xdrs->x_private = NULL; + } + return; +} + +unsigned long +xdr_sizeof(func, data) + xdrproc_t func; + void *data; +{ + XDR x; + struct xdr_ops ops; + bool_t stat; + /* to stop ANSI-C compiler from complaining */ + typedef bool_t (* dummyfunc1)(XDR *, long *); + typedef bool_t (* dummyfunc2)(XDR *, caddr_t, u_int); + + ops.x_putlong = x_putlong; + ops.x_putbytes = x_putbytes; + ops.x_inline = x_inline; + ops.x_getpostn = x_getpostn; + ops.x_setpostn = x_setpostn; + ops.x_destroy = x_destroy; + + /* the other harmless ones */ + ops.x_getlong = (dummyfunc1) harmless; + ops.x_getbytes = (dummyfunc2) harmless; + + x.x_op = XDR_ENCODE; + x.x_ops = &ops; + x.x_handy = 0; + x.x_private = (caddr_t) NULL; + x.x_base = (caddr_t) 0; + + stat = func(&x, data); + if (x.x_private) + free(x.x_private); + return (stat == TRUE ? (unsigned) x.x_handy: 0); +} diff --git a/libtirpc/src/xdr_stdio.c b/libtirpc/src/xdr_stdio.c new file mode 100644 index 0000000..c129b2f --- /dev/null +++ b/libtirpc/src/xdr_stdio.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#include + +/* + * xdr_stdio.c, XDR implementation on standard i/o file. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements a XDR on a stdio stream. + * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes + * from the stream. + */ + +#include +#include "namespace.h" +#include + +//#include +#include +#include +#include "un-namespace.h" + +static void xdrstdio_destroy(XDR *); +static bool_t xdrstdio_getlong(XDR *, long *); +static bool_t xdrstdio_putlong(XDR *, const long *); +static bool_t xdrstdio_getbytes(XDR *, char *, u_int); +static bool_t xdrstdio_putbytes(XDR *, const char *, u_int); +static u_int xdrstdio_getpos(XDR *); +static bool_t xdrstdio_setpos(XDR *, u_int); +static int32_t *xdrstdio_inline(XDR *, u_int); + +/* + * Ops vector for stdio type XDR + */ +static const struct xdr_ops xdrstdio_ops = { + xdrstdio_getlong, /* deseraialize a long int */ + xdrstdio_putlong, /* seraialize a long int */ + xdrstdio_getbytes, /* deserialize counted bytes */ + xdrstdio_putbytes, /* serialize counted bytes */ + xdrstdio_getpos, /* get offset in the stream */ + xdrstdio_setpos, /* set offset in the stream */ + xdrstdio_inline, /* prime stream for inline macros */ + xdrstdio_destroy /* destroy stream */ +}; + +/* + * Initialize a stdio xdr stream. + * Sets the xdr stream handle xdrs for use on the stream file. + * Operation flag is set to op. + */ +void +xdrstdio_create(xdrs, file, op) + XDR *xdrs; + FILE *file; + enum xdr_op op; +{ + + xdrs->x_op = op; + xdrs->x_ops = &xdrstdio_ops; + xdrs->x_private = file; + xdrs->x_handy = 0; + xdrs->x_base = 0; +} + +/* + * Destroy a stdio xdr stream. + * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create. + */ +static void +xdrstdio_destroy(xdrs) + XDR *xdrs; +{ + (void)fflush((FILE *)xdrs->x_private); + /* XXX: should we close the file ?? */ +} + +static bool_t +xdrstdio_getlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + + if (fread(lp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1) + return (FALSE); + *lp = (long)ntohl((u_int32_t)*lp); + return (TRUE); +} + +static bool_t +xdrstdio_putlong(xdrs, lp) + XDR *xdrs; + const long *lp; +{ + long mycopy = (long)htonl((u_int32_t)*lp); + + if (fwrite(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1) + return (FALSE); + return (TRUE); +} + +static bool_t +xdrstdio_getbytes(xdrs, addr, len) + XDR *xdrs; + char *addr; + u_int len; +{ + + if ((len != 0) && (fread(addr, (size_t)len, 1, (FILE *)xdrs->x_private) != 1)) + return (FALSE); + return (TRUE); +} + +static bool_t +xdrstdio_putbytes(xdrs, addr, len) + XDR *xdrs; + const char *addr; + u_int len; +{ + + if ((len != 0) && (fwrite(addr, (size_t)len, 1, + (FILE *)xdrs->x_private) != 1)) + return (FALSE); + return (TRUE); +} + +static u_int +xdrstdio_getpos(xdrs) + XDR *xdrs; +{ + + return ((u_int) ftell((FILE *)xdrs->x_private)); +} + +static bool_t +xdrstdio_setpos(xdrs, pos) + XDR *xdrs; + u_int pos; +{ + + return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ? + FALSE : TRUE); +} + +/* ARGSUSED */ +static int32_t * +xdrstdio_inline(xdrs, len) + XDR *xdrs; + u_int len; +{ + + /* + * Must do some work to implement this: must insure + * enough data in the underlying stdio buffer, + * that the buffer is aligned so that we can indirect through a + * long *, and stuff this pointer in xdrs->x_buf. Doing + * a fread or fwrite to a scratch buffer would defeat + * most of the gains to be had here and require storage + * management on this buffer, so we don't do this. + */ + return (NULL); +} diff --git a/libtirpc/tirpc/fpmath.h b/libtirpc/tirpc/fpmath.h new file mode 100644 index 0000000..e63d73f --- /dev/null +++ b/libtirpc/tirpc/fpmath.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2003 Mike Barcroft + * Copyright (c) 2002 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/fpmath.h,v 1.1 2003/02/08 20:37:53 mike Exp $ + */ + +#include +#include "_fpmath.h" + +union IEEEf2bits { + float f; + struct { +#if _BYTE_ORDER == _LITTLE_ENDIAN + unsigned int man :23; + unsigned int exp :8; + unsigned int sign :1; +#else /* _BIG_ENDIAN */ + unsigned int sign :1; + unsigned int exp :8; + unsigned int man :23; +#endif + } bits; +}; + +union IEEEd2bits { + double d; + struct { +#if _BYTE_ORDER == _LITTLE_ENDIAN + unsigned int manl :32; + unsigned int manh :20; + unsigned int exp :11; + unsigned int sign :1; +#else /* _BIG_ENDIAN */ + unsigned int sign :1; + unsigned int exp :11; + unsigned int manh :20; + unsigned int manl :32; +#endif + } bits; +}; diff --git a/libtirpc/tirpc/getpeereid.h b/libtirpc/tirpc/getpeereid.h new file mode 100644 index 0000000..cdecd0e --- /dev/null +++ b/libtirpc/tirpc/getpeereid.h @@ -0,0 +1,2 @@ + +int getpeereid(SOCKET s, uid_t *euid, gid_t *egid); diff --git a/libtirpc/tirpc/libc_private.h b/libtirpc/tirpc/libc_private.h new file mode 100644 index 0000000..63f8610 --- /dev/null +++ b/libtirpc/tirpc/libc_private.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1998 John Birrell . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/libc_private.h,v 1.11 2003/11/05 18:17:30 deischen Exp $ + * + * Private definitions for libc, libc_r and libpthread. + * + */ + +#ifndef _LIBC_PRIVATE_H_ +#define _LIBC_PRIVATE_H_ + +/* + * This global flag is non-zero when a process has created one + * or more threads. It is used to avoid calling locking functions + * when they are not required. + */ +extern int __isthreaded; + +/* + * File lock contention is difficult to diagnose without knowing + * where locks were set. Allow a debug library to be built which + * records the source file and line number of each lock call. + */ +#ifdef _FLOCK_DEBUG +#define _FLOCKFILE(x) _flockfile_debug(x, __FILE__, __LINE__) +#else +#define _FLOCKFILE(x) _flockfile(x) +#endif + +/* + * Macros for locking and unlocking FILEs. These test if the + * process is threaded to avoid locking when not required. + */ +#define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp) +#define FUNLOCKFILE(fp) if (__isthreaded) _funlockfile(fp) + +/* + * Indexes into the pthread jump table. + * + * Warning! If you change this type, you must also change the threads + * libraries that reference it (libc_r, libpthread). + */ +typedef enum { + PJT_COND_BROADCAST, + PJT_COND_DESTROY, + PJT_COND_INIT, + PJT_COND_SIGNAL, + PJT_COND_WAIT, + PJT_GETSPECIFIC, + PJT_KEY_CREATE, + PJT_KEY_DELETE, + PJT_MAIN_NP, + PJT_MUTEX_DESTROY, + PJT_MUTEX_INIT, + PJT_MUTEX_LOCK, + PJT_MUTEX_TRYLOCK, + PJT_MUTEX_UNLOCK, + PJT_MUTEXATTR_DESTROY, + PJT_MUTEXATTR_INIT, + PJT_MUTEXATTR_SETTYPE, + PJT_ONCE, + PJT_RWLOCK_DESTROY, + PJT_RWLOCK_INIT, + PJT_RWLOCK_RDLOCK, + PJT_RWLOCK_TRYRDLOCK, + PJT_RWLOCK_TRYWRLOCK, + PJT_RWLOCK_UNLOCK, + PJT_RWLOCK_WRLOCK, + PJT_SELF, + PJT_SETSPECIFIC, + PJT_SIGMASK, + PJT_MAX +} pjt_index_t; + +typedef int (*pthread_func_t)(void); +typedef pthread_func_t pthread_func_entry_t[2]; + +extern pthread_func_entry_t __thr_jtable[]; + +/* + * yplib internal interfaces + */ +#ifdef YP +int _yp_check(char **); +#endif + + +/* + * This is a pointer in the C run-time startup code. It is used + * by getprogname() and setprogname(). + */ +extern const char *__progname; + +/* + * This is the lock to make malloc() thread-safe. It is externalized + * so that thread libraries can protect malloc across fork(). + */ +extern struct _spinlock *__malloc_lock; + +#endif /* _LIBC_PRIVATE_H_ */ diff --git a/libtirpc/tirpc/misc/event.h b/libtirpc/tirpc/misc/event.h new file mode 100644 index 0000000..ca21c2f --- /dev/null +++ b/libtirpc/tirpc/misc/event.h @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 1999,2000,2001 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/event.h,v 1.22 2003/02/02 19:39:51 nectar Exp $ + */ + +#ifndef _TIRPC_EVENT_H_ +#define _TIRPC_EVENT_H_ + +#define EVFILT_READ (-1) +#define EVFILT_WRITE (-2) +#define EVFILT_AIO (-3) /* attached to aio requests */ +#define EVFILT_VNODE (-4) /* attached to vnodes */ +#define EVFILT_PROC (-5) /* attached to struct proc */ +#define EVFILT_SIGNAL (-6) /* attached to struct proc */ +#define EVFILT_TIMER (-7) /* timers */ +#define EVFILT_NETDEV (-8) /* network devices */ + +#define EVFILT_SYSCOUNT 8 + +#define EV_SET(kevp_, a, b, c, d, e, f) do { \ + struct kevent *kevp = (kevp_); \ + (kevp)->ident = (a); \ + (kevp)->filter = (b); \ + (kevp)->flags = (c); \ + (kevp)->fflags = (d); \ + (kevp)->data = (e); \ + (kevp)->udata = (f); \ +} while(0) + +#include + +struct kevent { + uintptr_t ident; /* identifier for this event */ + short filter; /* filter for event */ + u_short flags; + u_int fflags; + intptr_t data; + void *udata; /* opaque user data identifier */ +}; + +/* actions */ +#define EV_ADD 0x0001 /* add event to kq (implies enable) */ +#define EV_DELETE 0x0002 /* delete event from kq */ +#define EV_ENABLE 0x0004 /* enable event */ +#define EV_DISABLE 0x0008 /* disable event (not reported) */ + +/* flags */ +#define EV_ONESHOT 0x0010 /* only report one occurrence */ +#define EV_CLEAR 0x0020 /* clear event state after reporting */ + +#define EV_SYSFLAGS 0xF000 /* reserved by system */ +#define EV_FLAG1 0x2000 /* filter-specific flag */ + +/* returned values */ +#define EV_EOF 0x8000 /* EOF detected */ +#define EV_ERROR 0x4000 /* error, data contains errno */ + +/* + * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace + */ +#define NOTE_LOWAT 0x0001 /* low water mark */ + +/* + * data/hint flags for EVFILT_VNODE, shared with userspace + */ +#define NOTE_DELETE 0x0001 /* vnode was removed */ +#define NOTE_WRITE 0x0002 /* data contents changed */ +#define NOTE_EXTEND 0x0004 /* size increased */ +#define NOTE_ATTRIB 0x0008 /* attributes changed */ +#define NOTE_LINK 0x0010 /* link count changed */ +#define NOTE_RENAME 0x0020 /* vnode was renamed */ +#define NOTE_REVOKE 0x0040 /* vnode access was revoked */ + +/* + * data/hint flags for EVFILT_PROC, shared with userspace + */ +#define NOTE_EXIT 0x80000000 /* process exited */ +#define NOTE_FORK 0x40000000 /* process forked */ +#define NOTE_EXEC 0x20000000 /* process exec'd */ +#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */ +#define NOTE_PDATAMASK 0x000fffff /* mask for pid */ + +/* additional flags for EVFILT_PROC */ +#define NOTE_TRACK 0x00000001 /* follow across forks */ +#define NOTE_TRACKERR 0x00000002 /* could not track child */ +#define NOTE_CHILD 0x00000004 /* am a child process */ + +/* + * data/hint flags for EVFILT_NETDEV, shared with userspace + */ +#define NOTE_LINKUP 0x0001 /* link is up */ +#define NOTE_LINKDOWN 0x0002 /* link is down */ +#define NOTE_LINKINV 0x0004 /* link state is invalid */ + +/* + * This is currently visible to userland to work around broken + * programs which pull in . + */ +#include + +struct knote; +SLIST_HEAD(klist, knote); + +#ifdef _KERNEL + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_KQUEUE); +#endif + +#define KNOTE(list, hint) if ((list) != NULL) knote(list, hint) + +/* + * Flag indicating hint is a signal. Used by EVFILT_SIGNAL, and also + * shared by EVFILT_PROC (all knotes attached to p->p_klist) + */ +#define NOTE_SIGNAL 0x08000000 + +struct filterops { + int f_isfd; /* true if ident == filedescriptor */ + int (*f_attach)(struct knote *kn); + void (*f_detach)(struct knote *kn); + int (*f_event)(struct knote *kn, long hint); +}; + +struct knote { + SLIST_ENTRY(knote) kn_link; /* for fd */ + SLIST_ENTRY(knote) kn_selnext; /* for struct selinfo */ + TAILQ_ENTRY(knote) kn_tqe; + struct kqueue *kn_kq; /* which queue we are on */ + struct kevent kn_kevent; + int kn_status; + int kn_sfflags; /* saved filter flags */ + intptr_t kn_sdata; /* saved data field */ + union { + struct file *p_fp; /* file data pointer */ + struct proc *p_proc; /* proc pointer */ + } kn_ptr; + struct filterops *kn_fop; + void *kn_hook; +#define KN_ACTIVE 0x01 /* event has been triggered */ +#define KN_QUEUED 0x02 /* event is on queue */ +#define KN_DISABLED 0x04 /* event is disabled */ +#define KN_DETACHED 0x08 /* knote is detached */ + +#define kn_id kn_kevent.ident +#define kn_filter kn_kevent.filter +#define kn_flags kn_kevent.flags +#define kn_fflags kn_kevent.fflags +#define kn_data kn_kevent.data +#define kn_fp kn_ptr.p_fp +}; + +struct thread; +struct proc; + +extern void knote(struct klist *list, long hint); +extern void knote_remove(struct thread *p, struct klist *list); +extern void knote_fdclose(struct thread *p, int fd); +extern int kqueue_register(struct kqueue *kq, + struct kevent *kev, struct thread *p); +extern int kqueue_add_filteropts(int filt, struct filterops *filtops); +extern int kqueue_del_filteropts(int filt); + +#else /* !_KERNEL */ + +//#include +struct timespec; + +__BEGIN_DECLS +int kqueue(void); +int kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, + const struct timespec *timeout); +__END_DECLS + +#endif /* !_KERNEL */ + +#endif /* !_TIRPC_EVENT_H_ */ diff --git a/libtirpc/tirpc/misc/queue.h b/libtirpc/tirpc/misc/queue.h new file mode 100644 index 0000000..0346905 --- /dev/null +++ b/libtirpc/tirpc/misc/queue.h @@ -0,0 +1,6 @@ +#include + + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_FIRST(head) ((head)->stqh_first) diff --git a/libtirpc/tirpc/misc/socket.h b/libtirpc/tirpc/misc/socket.h new file mode 100644 index 0000000..ad6ec76 --- /dev/null +++ b/libtirpc/tirpc/misc/socket.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1982, 1985, 1986, 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)socket.h 8.4 (Berkeley) 2/21/94 + * $FreeBSD: src/sys/sys/socket.h,v 1.73 2003/11/14 18:48:15 bms Exp $ + */ + + +#ifndef _MISC_SYS_SOCKET_H_ +#define _MISC_SYS_SOCKET_H_ + +#include + +#define CMGROUP_MAX 16 +#define SCM_CREDS 0x03 /* process creds (struct cmsgcred) */ + +/* + * Credentials structure, used to verify the identity of a peer + * process that has sent us a message. This is allocated by the + * peer process but filled in by the kernel. This prevents the + * peer from lying about its identity. (Note that cmcred_groups[0] + * is the effective GID.) + */ +struct cmsgcred { + pid_t cmcred_pid; /* PID of sending process */ + uid_t cmcred_uid; /* real UID of sending process */ + uid_t cmcred_euid; /* effective UID of sending process */ + gid_t cmcred_gid; /* real GID of sending process */ + short cmcred_ngroups; /* number or groups */ + gid_t cmcred_groups[CMGROUP_MAX]; /* groups */ +}; + +#endif /* _MISC_SYS_SOCKET_H_ */ diff --git a/libtirpc/tirpc/namespace.h b/libtirpc/tirpc/namespace.h new file mode 100644 index 0000000..79e671e --- /dev/null +++ b/libtirpc/tirpc/namespace.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2001 Daniel Eischen . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/namespace.h,v 1.16 2003/05/01 19:03:13 nectar Exp $ + */ + +#ifndef _NAMESPACE_H_ +#define _NAMESPACE_H_ + + +#endif /* _NAMESPACE_H_ */ diff --git a/libtirpc/tirpc/netconfig.h b/libtirpc/tirpc/netconfig.h new file mode 100644 index 0000000..9182b5d --- /dev/null +++ b/libtirpc/tirpc/netconfig.h @@ -0,0 +1,95 @@ +#ifndef _NETCONFIG_H_ +#define _NETCONFIG_H_ + +//#include + +// XXX Should be in, or come from, the registry!!! +#define NETCONFIG "c:\\etc\\netconfig" +#define NETPATH "NETPATH" + +struct netconfig { + char *nc_netid; /* Network ID */ + unsigned long nc_semantics; /* Semantics (see below) */ + unsigned long nc_flag; /* Flags (see below) */ + char *nc_protofmly; /* Protocol family */ + char *nc_proto; /* Protocol name */ + char *nc_device; /* Network device pathname */ + unsigned long nc_nlookups; /* Number of directory lookup libs */ + char **nc_lookups; /* Names of the libraries */ + unsigned long nc_unused[9]; /* reserved */ +}; + +typedef struct { + struct netconfig **nc_head; + struct netconfig **nc_curr; +} NCONF_HANDLE; + +/* + * nc_semantics values + */ +#define NC_TPI_CLTS 1 +#define NC_TPI_COTS 2 +#define NC_TPI_COTS_ORD 3 +#define NC_TPI_RAW 4 + +/* + * nc_flag values + */ +#define NC_NOFLAG 0x00 +#define NC_VISIBLE 0x01 +#define NC_BROADCAST 0x02 + +/* + * nc_protofmly values + */ +#define NC_NOPROTOFMLY "-" +#define NC_LOOPBACK "loopback" +#define NC_INET "inet" +#define NC_INET6 "inet6" +#define NC_IMPLINK "implink" +#define NC_PUP "pup" +#define NC_CHAOS "chaos" +#define NC_NS "ns" +#define NC_NBS "nbs" +#define NC_ECMA "ecma" +#define NC_DATAKIT "datakit" +#define NC_CCITT "ccitt" +#define NC_SNA "sna" +#define NC_DECNET "decnet" +#define NC_DLI "dli" +#define NC_LAT "lat" +#define NC_HYLINK "hylink" +#define NC_APPLETALK "appletalk" +#define NC_NIT "nit" +#define NC_IEEE802 "ieee802" +#define NC_OSI "osi" +#define NC_X25 "x25" +#define NC_OSINET "osinet" +#define NC_GOSIP "gosip" + +/* + * nc_proto values + */ +#define NC_NOPROTO "-" +#define NC_TCP "tcp" +#define NC_UDP "udp" +#define NC_ICMP "icmp" + +__BEGIN_DECLS + +extern void *setnetconfig (void); +extern struct netconfig *getnetconfig (void *); +extern struct netconfig *getnetconfigent (const char *); +extern void freenetconfigent (struct netconfig *); +extern int endnetconfig (void *); + +extern void *setnetpath (void); +extern struct netconfig *getnetpath (void *); +extern int endnetpath (void *); + +extern void nc_perror (const char *); +extern char *nc_sperror (void); + +__END_DECLS + +#endif /* _NETCONFIG_H_ */ diff --git a/libtirpc/tirpc/nss_tls.h b/libtirpc/tirpc/nss_tls.h new file mode 100644 index 0000000..7536736 --- /dev/null +++ b/libtirpc/tirpc/nss_tls.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by + * Jacques A. Vidrine, Safeport Network Services, and Network + * Associates Laboratories, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/nss_tls.h,v 1.2 2003/04/21 15:44:25 nectar Exp $ + * + * Macros which generate thread local storage handling code in NSS modules. + */ +#ifndef _NSS_TLS_H_ +#define _NSS_TLS_H_ + +#define NSS_TLS_HANDLING(name) \ +static pthread_key_t name##_state_key; \ +static void name##_keyinit(void); \ +static int name##_getstate(struct name##_state **); \ +\ +static void \ +name##_keyinit(void) \ +{ \ + (void)_pthread_key_create(&name##_state_key, name##_endstate); \ +} \ +\ +static int \ +name##_getstate(struct name##_state **p) \ +{ \ + static struct name##_state st; \ + static pthread_once_t keyinit = PTHREAD_ONCE_INIT; \ + int rv; \ + \ + if (!__isthreaded || _pthread_main_np() != 0) { \ + *p = &st; \ + return (0); \ + } \ + rv = _pthread_once(&keyinit, name##_keyinit); \ + if (rv != 0) \ + return (rv); \ + *p = _pthread_getspecific(name##_state_key); \ + if (*p != NULL) \ + return (0); \ + *p = calloc(1, sizeof(**p)); \ + if (*p == NULL) \ + return (ENOMEM); \ + rv = _pthread_setspecific(name##_state_key, *p); \ + if (rv != 0) { \ + free(*p); \ + *p = NULL; \ + } \ + return (rv); \ +} \ +/* allow the macro invocation to end with a semicolon */ \ +typedef int _##name##_bmVjdGFy + +#endif /* _NSS_TLS_H_ */ diff --git a/libtirpc/tirpc/reentrant.h b/libtirpc/tirpc/reentrant.h new file mode 100644 index 0000000..154489e --- /dev/null +++ b/libtirpc/tirpc/reentrant.h @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 1997,98 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by J.T. Conklin. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/reentrant.h,v 1.2 2002/11/01 09:37:17 dfr Exp $ + */ + +/* + * Requirements: + * + * 1. The thread safe mechanism should be lightweight so the library can + * be used by non-threaded applications without unreasonable overhead. + * + * 2. There should be no dependency on a thread engine for non-threaded + * applications. + * + * 3. There should be no dependency on any particular thread engine. + * + * 4. The library should be able to be compiled without support for thread + * safety. + * + * + * Rationale: + * + * One approach for thread safety is to provide discrete versions of the + * library: one thread safe, the other not. The disadvantage of this is + * that libc is rather large, and two copies of a library which are 99%+ + * identical is not an efficent use of resources. + * + * Another approach is to provide a single thread safe library. However, + * it should not add significant run time or code size overhead to non- + * threaded applications. + * + * Since the NetBSD C library is used in other projects, it should be + * easy to replace the mutual exclusion primitives with ones provided by + * another system. Similarly, it should also be easy to remove all + * support for thread safety completely if the target environment does + * not support threads. + * + * + * Implementation Details: + * + * The mutex primitives used by the library (mutex_t, mutex_lock, etc.) + * are macros which expand to the cooresponding primitives provided by + * the thread engine or to nothing. The latter is used so that code is + * not unreasonably cluttered with #ifdefs when all thread safe support + * is removed. + * + * The mutex macros can be directly mapped to the mutex primitives from + * pthreads, however it should be reasonably easy to wrap another mutex + * implementation so it presents a similar interface. + * + * Stub implementations of the mutex functions are provided with *weak* + * linkage. These functions simply return success. When linked with a + * thread library (i.e. -lpthread), the functions will override the + * stubs. + */ +#ifndef _REENTRANT_H +#define _REENTRANT_H +//#include +#include + +#include + + +#define mutex_t CRITICAL_SECTION +#define cond_t CONDITION_VARIABLE +#define rwlock_t SRWLOCK + + +#define thread_key_t DWORD +#define MUTEX_INITIALIZER -1 /*THIS_NEEDS_HELP*/ +#define RWLOCK_INITIALIZER -1 /*THIS_NEEDS_HELP*/ +#define mutex_init(m, a) InitializeCriticalSection(m) +#define mutex_lock(m) EnterCriticalSection(m) +#define mutex_unlock(m) LeaveCriticalSection(m) +#define mutex_trylock(m) TryEnterCriticalSection(m) + +#define cond_init(c, a, p) InitializeConditionVariable(c) +#define cond_signal(m) WakeConditionVariable(m) +#define cond_broadcast(m) WakeAllConditionVariable(m) +#define cond_wait(c, m) SleepConditionVariableCS(c, m, INFINITE) +#define cond_wait_timed(c, m, t) SleepConditionVariableCS(c, m, t) + +#define rwlock_init(l, a) InitializeSRWLock(l) +#define rwlock_rdlock(l) AcquireSRWLockShared(l) +#define rwlock_wrlock(l) AcquireSRWLockExclusive(l) +/* XXX Code will have to be changed to release the right kind!!! XXX */ +#define rwlock_unlock(l) ReleaseSRWLockExclusive(l) + +#define thr_keycreate(k, d) ((*k) = TlsAlloc()) +#define thr_keydelete(k) TlsFree(k) +#define thr_setspecific(k, p) TlsSetValue(k, p) +#define thr_getspecific(k) TlsGetValue(k) +#define thr_sigsetmask(f, n, o) dunno_sigmask(f, n, o) + +#define thr_self() GetCurrentThreadId() +#define thr_exit(x) ExitThread(x) + +/* +#define mutex_t pthread_mutex_t +#define cond_t pthread_cond_t +#define rwlock_t pthread_rwlock_t + +#define thread_key_t pthread_key_t +#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER +#define mutex_init(m, a) pthread_mutex_init(m, a) +#define mutex_lock(m) pthread_mutex_lock(m) +#define mutex_unlock(m) pthread_mutex_unlock(m) +#define mutex_trylock(m) pthread_mutex_trylock(m) + +#define cond_init(c, a, p) pthread_cond_init(c, a) +#define cond_signal(m) pthread_cond_signal(m) +#define cond_broadcast(m) pthread_cond_broadcast(m) +#define cond_wait(c, m) pthread_cond_wait(c, m) + +#define rwlock_init(l, a) pthread_rwlock_init(l, a) +#define rwlock_rdlock(l) pthread_rwlock_rdlock(l) +#define rwlock_wrlock(l) pthread_rwlock_wrlock(l) +#define rwlock_unlock(l) pthread_rwlock_unlock(l) + +#define thr_keycreate(k, d) pthread_key_create(k, d) +#define thr_keydelete(k) pthread_key_delete(k) +#define thr_setspecific(k, p) pthread_setspecific(k, p) +#define thr_getspecific(k) pthread_getspecific(k) +#define thr_sigsetmask(f, n, o) pthread_sigmask(f, n, o) + +#define thr_self() pthread_self() +#define thr_exit(x) pthread_exit(x) +*/ +#endif /* reentrant.h */ diff --git a/libtirpc/tirpc/rpc/auth.h b/libtirpc/tirpc/rpc/auth.h new file mode 100644 index 0000000..5446af1 --- /dev/null +++ b/libtirpc/tirpc/rpc/auth.h @@ -0,0 +1,391 @@ +/* $NetBSD: auth.h,v 1.15 2000/06/02 22:57:55 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)auth.h 1.17 88/02/08 SMI + * from: @(#)auth.h 2.3 88/08/07 4.0 RPCSRC + * from: @(#)auth.h 1.43 98/02/02 SMI + * $FreeBSD: src/include/rpc/auth.h,v 1.20 2003/01/01 18:48:42 schweikh Exp $ + */ + +/* + * auth.h, Authentication interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The data structures are completely opaque to the client. The client + * is required to pass an AUTH * to routines that create rpc + * "sessions". + */ + +#ifndef _TIRPC_AUTH_H +#define _TIRPC_AUTH_H + +#include +#include +//#include +//#include +#include + + +#define MAX_AUTH_BYTES 400 +#define MAXNETNAMELEN 255 /* maximum length of network user's name */ + +/* + * Client side authentication/security data + */ + +typedef struct sec_data { + u_int secmod; /* security mode number e.g. in nfssec.conf */ + u_int rpcflavor; /* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */ + int flags; /* AUTH_F_xxx flags */ + caddr_t data; /* opaque data per flavor */ +} sec_data_t; + +#ifdef _SYSCALL32_IMPL +struct sec_data32 { + uint32_t secmod; /* security mode number e.g. in nfssec.conf */ + uint32_t rpcflavor; /* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */ + int32_t flags; /* AUTH_F_xxx flags */ + caddr32_t data; /* opaque data per flavor */ +}; +#endif /* _SYSCALL32_IMPL */ + +/* + * AUTH_DES flavor specific data from sec_data opaque data field. + * AUTH_KERB has the same structure. + */ +typedef struct des_clnt_data { + struct netbuf syncaddr; /* time sync addr */ + struct knetconfig *knconf; /* knetconfig info that associated */ + /* with the syncaddr. */ + char *netname; /* server's netname */ + int netnamelen; /* server's netname len */ +} dh_k4_clntdata_t; + +#ifdef _SYSCALL32_IMPL +struct des_clnt_data32 { + struct netbuf32 syncaddr; /* time sync addr */ + caddr32_t knconf; /* knetconfig info that associated */ + /* with the syncaddr. */ + caddr32_t netname; /* server's netname */ + int32_t netnamelen; /* server's netname len */ +}; +#endif /* _SYSCALL32_IMPL */ + +#ifdef KERBEROS +/* + * flavor specific data to hold the data for AUTH_DES/AUTH_KERB(v4) + * in sec_data->data opaque field. + */ +typedef struct krb4_svc_data { + int window; /* window option value */ +} krb4_svcdata_t; + +typedef struct krb4_svc_data des_svcdata_t; +#endif /* KERBEROS */ + +/* + * authentication/security specific flags + */ +#define AUTH_F_RPCTIMESYNC 0x001 /* use RPC to do time sync */ +#define AUTH_F_TRYNONE 0x002 /* allow fall back to AUTH_NONE */ + + +/* + * Status returned from authentication check + */ +enum auth_stat { + AUTH_OK=0, + /* + * failed at remote end + */ + AUTH_BADCRED=1, /* bogus credentials (seal broken) */ + AUTH_REJECTEDCRED=2, /* client should begin new session */ + AUTH_BADVERF=3, /* bogus verifier (seal broken) */ + AUTH_REJECTEDVERF=4, /* verifier expired or was replayed */ + AUTH_TOOWEAK=5, /* rejected due to security reasons */ + /* + * failed locally + */ + AUTH_INVALIDRESP=6, /* bogus response verifier */ + AUTH_FAILED=7, /* some unknown reason */ +#ifdef KERBEROS + /* + * kerberos errors + */ + AUTH_KERB_GENERIC = 8, /* kerberos generic error */ + AUTH_TIMEEXPIRE = 9, /* time of credential expired */ + AUTH_TKT_FILE = 10, /* something wrong with ticket file */ + AUTH_DECODE = 11, /* can't decode authenticator */ + AUTH_NET_ADDR = 12, /* wrong net address in ticket */ +#endif /* KERBEROS */ + + /* + * RPCSEC_GSS errors + */ + RPCSEC_GSS_CREDPROBLEM = 13, + RPCSEC_GSS_CTXPROBLEM = 14 + +}; + +typedef u_int32_t u_int32; /* 32-bit unsigned integers */ + +union des_block { + struct { + u_int32_t high; + u_int32_t low; + } key; + char c[8]; +}; +typedef union des_block des_block; +__BEGIN_DECLS +extern bool_t xdr_des_block(XDR *, des_block *); +__END_DECLS + +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + u_int oa_length; /* not to exceed MAX_AUTH_BYTES */ +}; + + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct __auth { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + union des_block ah_key; + struct auth_ops { + void (*ah_nextverf) (struct __auth *); + /* nextverf & serialize */ + int (*ah_marshal) (struct __auth *, XDR *); + /* validate verifier */ + int (*ah_validate) (struct __auth *, + struct opaque_auth *); + /* refresh credentials */ + int (*ah_refresh) (struct __auth *, void *); + /* destroy this structure */ + void (*ah_destroy) (struct __auth *); + /* encode data for wire */ + int (*ah_wrap) (struct __auth *, XDR *, xdrproc_t, caddr_t); + /* decode data for wire */ + int (*ah_unwrap) (struct __auth *, XDR *, xdrproc_t, caddr_t); + + } *ah_ops; + void *ah_private; +} AUTH; + + +/* + * Authentication ops. + * The ops and the auth handle provide the interface to the authenticators. + * + * AUTH *auth; + * XDR *xdrs; + * struct opaque_auth verf; + */ +#define AUTH_NEXTVERF(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) +#define auth_nextverf(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) + +#define AUTH_MARSHALL(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) +#define auth_marshall(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) + +#define AUTH_VALIDATE(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) +#define auth_validate(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) + +#define AUTH_REFRESH(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) +#define auth_refresh(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) + +#define AUTH_DESTROY(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) +#define auth_destroy(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) + +#define AUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ + xfunc, xwhere)) +#define auth_wrap(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ + xfunc, xwhere)) + +#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ + xfunc, xwhere)) +#define auth_unwrap(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ + xfunc, xwhere)) + + +__BEGIN_DECLS +extern struct opaque_auth _null_auth; +__END_DECLS + +/* + * Any style authentication. These routines can be used by any + * authentication style that does not use the wrap/unwrap functions. + */ +int authany_wrap(void), authany_unwrap(void); + +/* + * These are the various implementations of client side authenticators. + */ + +/* + * System style authentication + * AUTH *authunix_create(machname, uid, gid, len, aup_gids) + * char *machname; + * int uid; + * int gid; + * int len; + * int *aup_gids; + */ +__BEGIN_DECLS +extern AUTH *authunix_create(char *, uid_t, uid_t, int, uid_t *); +extern AUTH *authunix_create_default(void); /* takes no parameters */ +extern AUTH *authnone_create(void); /* takes no parameters */ +__END_DECLS +/* + * DES style authentication + * AUTH *authsecdes_create(servername, window, timehost, ckey) + * char *servername; - network name of server + * u_int window; - time to live + * const char *timehost; - optional hostname to sync with + * des_block *ckey; - optional conversation key to use + */ +__BEGIN_DECLS +extern AUTH *authdes_create (char *, u_int, struct sockaddr *, des_block *); +extern AUTH *authdes_seccreate (const char *, const u_int, const char *, + const des_block *); +__END_DECLS + +__BEGIN_DECLS +extern bool_t xdr_opaque_auth (XDR *, struct opaque_auth *); +__END_DECLS + +#define authsys_create(c,i1,i2,i3,ip) authunix_create((c),(i1),(i2),(i3),(ip)) +#define authsys_create_default() authunix_create_default() + +/* + * Netname manipulation routines. + */ +__BEGIN_DECLS +extern int getnetname(char *); +extern int host2netname(char *, const char *, const char *); +extern int user2netname(char *, const uid_t, const char *); +extern int netname2user(char *, uid_t *, gid_t *, int *, gid_t *); +extern int netname2host(char *, char *, const int); +extern void passwd2des ( char *, char * ); +__END_DECLS + +/* + * + * These routines interface to the keyserv daemon + * + */ +__BEGIN_DECLS +extern int key_decryptsession(const char *, des_block *); +extern int key_encryptsession(const char *, des_block *); +extern int key_gendes(des_block *); +extern int key_setsecret(const char *); +extern int key_secretkey_is_set(void); +__END_DECLS + +/* + * Publickey routines. + */ +__BEGIN_DECLS +extern int getpublickey (const char *, char *); +extern int getpublicandprivatekey (char *, char *); +extern int getsecretkey (char *, char *, char *); +__END_DECLS + +#ifdef KERBEROS +/* + * Kerberos style authentication + * AUTH *authkerb_seccreate(service, srv_inst, realm, window, timehost, status) + * const char *service; - service name + * const char *srv_inst; - server instance + * const char *realm; - server realm + * const u_int window; - time to live + * const char *timehost; - optional hostname to sync with + * int *status; - kerberos status returned + */ +__BEGIN_DECLS +extern AUTH *authkerb_seccreate(const char *, const char *, const char *, + const u_int, const char *, int *); +__END_DECLS + +/* + * Map a kerberos credential into a unix cred. + * + * authkerb_getucred(rqst, uid, gid, grouplen, groups) + * const struct svc_req *rqst; - request pointer + * uid_t *uid; + * gid_t *gid; + * short *grouplen; + * int *groups; + * + */ +__BEGIN_DECLS +extern int authkerb_getucred(/* struct svc_req *, uid_t *, gid_t *, + short *, int * */); +__END_DECLS +#endif /* KERBEROS */ + +__BEGIN_DECLS +struct svc_req; +struct rpc_msg; +enum auth_stat _svcauth_null (struct svc_req *, struct rpc_msg *); +enum auth_stat _svcauth_short (struct svc_req *, struct rpc_msg *); +enum auth_stat _svcauth_unix (struct svc_req *, struct rpc_msg *); +__END_DECLS + +#define AUTH_NONE 0 /* no authentication */ +#define AUTH_NULL 0 /* backward compatibility */ +#define AUTH_SYS 1 /* unix style (uid, gids) */ +#define AUTH_UNIX AUTH_SYS +#define AUTH_SHORT 2 /* short hand unix style */ +#define AUTH_DH 3 /* for Diffie-Hellman mechanism */ +#define AUTH_DES AUTH_DH /* for backward compatibility */ +#define AUTH_KERB 4 /* kerberos style */ +#define RPCSEC_GSS 6 /* RPCSEC_GSS */ + +#endif /* !_TIRPC_AUTH_H */ diff --git a/libtirpc/tirpc/rpc/auth_des.h b/libtirpc/tirpc/rpc/auth_des.h new file mode 100644 index 0000000..f3f9f31 --- /dev/null +++ b/libtirpc/tirpc/rpc/auth_des.h @@ -0,0 +1,130 @@ +/* @(#)auth_des.h 2.2 88/07/29 4.0 RPCSRC; from 1.3 88/02/08 SMI */ +/* $FreeBSD: src/include/rpc/auth_des.h,v 1.3 2002/03/23 17:24:55 imp Exp $ */ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)auth_des.h 2.2 88/07/29 4.0 RPCSRC + * from: @(#)auth_des.h 1.14 94/04/25 SMI + */ + +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * auth_des.h, Protocol for DES style authentication for RPC + */ + +#ifndef _TI_AUTH_DES_ +#define _TI_AUTH_DES_ + +#include + +/* + * There are two kinds of "names": fullnames and nicknames + */ +enum authdes_namekind { + ADN_FULLNAME, + ADN_NICKNAME +}; + +/* + * A fullname contains the network name of the client, + * a conversation key and the window + */ +struct authdes_fullname { + char *name; /* network name of client, up to MAXNETNAMELEN */ + union des_block key; /* conversation key */ + /* u_long window; */ + u_int32_t window; /* associated window */ +}; + + +/* + * A credential + */ +struct authdes_cred { + enum authdes_namekind adc_namekind; + struct authdes_fullname adc_fullname; + /*u_long adc_nickname;*/ + u_int32_t adc_nickname; +}; + + + +/* + * A des authentication verifier + */ +struct authdes_verf { + union { + struct timeval adv_ctime; /* clear time */ + des_block adv_xtime; /* crypt time */ + } adv_time_u; + //u_long adv_int_u; + u_int32_t adv_int_u; +}; + +/* + * des authentication verifier: client variety + * + * adv_timestamp is the current time. + * adv_winverf is the credential window + 1. + * Both are encrypted using the conversation key. + */ +#define adv_timestamp adv_time_u.adv_ctime +#define adv_xtimestamp adv_time_u.adv_xtime +#define adv_winverf adv_int_u + +/* + * des authentication verifier: server variety + * + * adv_timeverf is the client's timestamp + client's window + * adv_nickname is the server's nickname for the client. + * adv_timeverf is encrypted using the conversation key. + */ +#define adv_timeverf adv_time_u.adv_ctime +#define adv_xtimeverf adv_time_u.adv_xtime +#define adv_nickname adv_int_u + +/* + * Map a des credential into a unix cred. + * + */ +__BEGIN_DECLS +extern int authdes_getucred( struct authdes_cred *, uid_t *, gid_t *, int *, gid_t * ); +__END_DECLS + +__BEGIN_DECLS +extern bool_t xdr_authdes_cred(XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf(XDR *, struct authdes_verf *); +extern int rtime(dev_t, struct netbuf *, int, struct timeval *, + struct timeval *); +extern void kgetnetname(char *); +extern enum auth_stat _svcauth_des(struct svc_req *, struct rpc_msg *); +__END_DECLS + +#endif /* ndef _TI_AUTH_DES_ */ diff --git a/libtirpc/tirpc/rpc/auth_gss.h b/libtirpc/tirpc/rpc/auth_gss.h new file mode 100644 index 0000000..e2858ae --- /dev/null +++ b/libtirpc/tirpc/rpc/auth_gss.h @@ -0,0 +1,131 @@ +/* + auth_gss.h + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _TIRPC_AUTH_GSS_H +#define _TIRPC_AUTH_GSS_H + +#include +#define SECURITY_WIN32 +#include + +/* RPCSEC_GSS control procedures. */ +typedef enum { + RPCSEC_GSS_DATA = 0, + RPCSEC_GSS_INIT = 1, + RPCSEC_GSS_CONTINUE_INIT = 2, + RPCSEC_GSS_DESTROY = 3 +} rpc_gss_proc_t; + +/* RPCSEC_GSS services. */ +typedef enum { + RPCSEC_GSS_SVC_NONE = 1, + RPCSEC_GSS_SVC_INTEGRITY = 2, + RPCSEC_GSS_SVC_PRIVACY = 3 +} rpc_gss_svc_t; + +#define RPCSEC_GSS_VERSION 1 + +/* RPCSEC_GSS security triple. */ +struct rpc_gss_sec { + gss_OID mech; /* mechanism */ + gss_qop_t qop; /* quality of protection */ + rpc_gss_svc_t svc; /* service */ + gss_cred_id_t cred; /* cred handle */ + u_int req_flags; /* req flags for init_sec_context */ +}; + +/* Private data required for kernel implementation */ +struct authgss_private_data { + gss_ctx_id_t pd_ctx; /* Session context handle */ + gss_buffer_desc pd_ctx_hndl; /* Credentials context handle */ + u_int pd_seq_win; /* Sequence window */ +}; + +#define g_OID_equal(o1, o2) \ + (((o1)->length == (o2)->length) && \ + ((o1)->elements != 0) && ((o2)->elements != 0) && \ + (memcmp((o1)->elements, (o2)->elements, (int) (o1)->length) == 0)) + +/* from kerberos source, gssapi_krb5.c */ +extern gss_OID_desc krb5oid; +extern gss_OID_desc spkm3oid; + +/* Credentials. */ +struct rpc_gss_cred { + u_int gc_v; /* version */ + rpc_gss_proc_t gc_proc; /* control procedure */ + u_int gc_seq; /* sequence number */ + rpc_gss_svc_t gc_svc; /* service */ + gss_buffer_desc gc_ctx; /* context handle */ +}; + +/* Context creation response. */ +struct rpc_gss_init_res { + gss_buffer_desc gr_ctx; /* context handle */ + u_int gr_major; /* major status */ + u_int gr_minor; /* minor status */ + u_int gr_win; /* sequence window */ + gss_buffer_desc gr_token; /* token */ +}; + +/* Maximum sequence number value. */ +#define MAXSEQ 0x80000000 + +/* Prototypes. */ +__BEGIN_DECLS +bool_t xdr_rpc_gss_cred __P((XDR *xdrs, struct rpc_gss_cred *p)); +bool_t xdr_rpc_gss_init_args __P((XDR *xdrs, gss_buffer_desc *p)); +bool_t xdr_rpc_gss_init_res __P((XDR *xdrs, struct rpc_gss_init_res *p)); +bool_t xdr_rpc_gss_data __P((XDR *xdrs, xdrproc_t xdr_func, + caddr_t xdr_ptr, gss_ctx_id_t ctx, + gss_qop_t qop, rpc_gss_svc_t svc, + u_int seq)); + +AUTH *authgss_create __P((CLIENT *, gss_name_t, + struct rpc_gss_sec *)); +AUTH *authgss_create_default __P((CLIENT *, char *, struct rpc_gss_sec *)); +bool_t authgss_service __P((AUTH *auth, int svc)); +bool_t authgss_get_private_data __P((AUTH *auth, + struct authgss_private_data *)); + +void log_debug __P((const char *fmt, ...)); +void log_status __P((char *m, OM_uint32 major, + OM_uint32 minor)); +void log_hexdump __P((const u_char *buf, int len, int offset)); + +__END_DECLS + +#endif /* !_TIRPC_AUTH_GSS_H */ diff --git a/libtirpc/tirpc/rpc/auth_kerb.h b/libtirpc/tirpc/rpc/auth_kerb.h new file mode 100644 index 0000000..416b21c --- /dev/null +++ b/libtirpc/tirpc/rpc/auth_kerb.h @@ -0,0 +1,140 @@ +/* $FreeBSD: src/include/rpc/auth_kerb.h,v 1.2 2002/09/04 23:58:23 alfred Exp $ */ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * auth_kerb.h, Protocol for Kerberos style authentication for RPC + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#ifndef _RPC_AUTH_KERB_H +#define _RPC_AUTH_KERB_H + +#ifdef KERBEROS + +#include +#include +#include +#include +#include + +/* + * There are two kinds of "names": fullnames and nicknames + */ +enum authkerb_namekind { + AKN_FULLNAME, + AKN_NICKNAME +}; +/* + * A fullname contains the ticket and the window + */ +struct authkerb_fullname { + KTEXT_ST ticket; + u_long window; /* associated window */ +}; + +/* + * cooked credential stored in rq_clntcred + */ +struct authkerb_clnt_cred { + /* start of AUTH_DAT */ + unsigned char k_flags; /* Flags from ticket */ + char pname[ANAME_SZ]; /* Principal's name */ + char pinst[INST_SZ]; /* His Instance */ + char prealm[REALM_SZ]; /* His Realm */ + unsigned long checksum; /* Data checksum (opt) */ + C_Block session; /* Session Key */ + int life; /* Life of ticket */ + unsigned long time_sec; /* Time ticket issued */ + unsigned long address; /* Address in ticket */ + /* KTEXT_ST reply; Auth reply (opt) */ + /* end of AUTH_DAT */ + unsigned long expiry; /* time the ticket is expiring */ + u_long nickname; /* Nickname into cache */ + u_long window; /* associated window */ +}; + +typedef struct authkerb_clnt_cred authkerb_clnt_cred; + +/* + * A credential + */ +struct authkerb_cred { + enum authkerb_namekind akc_namekind; + struct authkerb_fullname akc_fullname; + u_long akc_nickname; +}; + +/* + * A kerb authentication verifier + */ +struct authkerb_verf { + union { + struct timeval akv_ctime; /* clear time */ + des_block akv_xtime; /* crypt time */ + } akv_time_u; + u_long akv_int_u; +}; + +/* + * des authentication verifier: client variety + * + * akv_timestamp is the current time. + * akv_winverf is the credential window + 1. + * Both are encrypted using the conversation key. + */ +#ifndef akv_timestamp +#define akv_timestamp akv_time_u.akv_ctime +#define akv_xtimestamp akv_time_u.akv_xtime +#define akv_winverf akv_int_u +#endif +/* + * des authentication verifier: server variety + * + * akv_timeverf is the client's timestamp + client's window + * akv_nickname is the server's nickname for the client. + * akv_timeverf is encrypted using the conversation key. + */ +#ifndef akv_timeverf +#define akv_timeverf akv_time_u.akv_ctime +#define akv_xtimeverf akv_time_u.akv_xtime +#define akv_nickname akv_int_u +#endif + +/* + * Register the service name, instance and realm. + */ +extern int authkerb_create(char *, char *, char *, u_int, + struct netbuf *, int *, dev_t, int, AUTH **); +extern bool_t xdr_authkerb_cred(XDR *, struct authkerb_cred *); +extern bool_t xdr_authkerb_verf(XDR *, struct authkerb_verf *); +extern int svc_kerb_reg(SVCXPRT *, char *, char *, char *); +extern enum auth_stat _svcauth_kerb(struct svc_req *, struct rpc_msg *); + +#endif KERBEROS +#endif /* !_RPC_AUTH_KERB_H */ diff --git a/libtirpc/tirpc/rpc/auth_unix.h b/libtirpc/tirpc/rpc/auth_unix.h new file mode 100644 index 0000000..2adf21a --- /dev/null +++ b/libtirpc/tirpc/rpc/auth_unix.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)auth_unix.h 1.8 88/02/08 SMI + * from: @(#)auth_unix.h 2.2 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/auth_unix.h,v 1.11 2002/03/23 17:24:55 imp Exp $ + */ + +/* + * auth_unix.h, Protocol for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * The system is very weak. The client uses no encryption for it + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + */ + +#ifndef _TIRPC_AUTH_UNIX_H +#define _TIRPC_AUTH_UNIX_H +//#include + +/* The machine name is part of a credential; it may not exceed 255 bytes */ +#define MAX_MACHINE_NAME 255 + +/* gids compose part of a credential; there may not be more than 16 of them */ +#define NGRPS 16 + +/* + * Unix style credentials. + */ +struct authunix_parms { + u_long aup_time; + char *aup_machname; + uid_t aup_uid; + gid_t aup_gid; + u_int aup_len; + gid_t *aup_gids; +}; + +#define authsys_parms authunix_parms + +__BEGIN_DECLS +extern bool_t xdr_authunix_parms(XDR *, struct authunix_parms *); +__END_DECLS + +/* + * If a response verifier has flavor AUTH_SHORT, + * then the body of the response verifier encapsulates the following structure; + * again it is serialized in the obvious fashion. + */ +struct short_hand_verf { + struct opaque_auth new_cred; +}; + +#endif /* !_TIRPC_AUTH_UNIX_H */ diff --git a/libtirpc/tirpc/rpc/clnt.h b/libtirpc/tirpc/rpc/clnt.h new file mode 100644 index 0000000..61ba2f0 --- /dev/null +++ b/libtirpc/tirpc/rpc/clnt.h @@ -0,0 +1,558 @@ +/* $NetBSD: clnt.h,v 1.14 2000/06/02 22:57:55 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)clnt.h 1.31 94/04/29 SMI + * from: @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/clnt.h,v 1.21 2003/01/24 01:47:55 fjoe Exp $ + */ + +/* + * clnt.h - Client side remote procedure call interface. + * + * Copyright (c) 1986-1991,1994-1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _TIRPC_CLNT_H_ +#define _TIRPC_CLNT_H_ + +//#include +#include "clnt_stat.h" +#include + +//#include +//#include +//#include + +/* + * Well-known IPV6 RPC broadcast address. + */ +#define RPCB_MULTICAST_ADDR "ff02::202" + +/* + * the following errors are in general unrecoverable. The caller + * should give up rather than retry. + */ +#define IS_UNRECOVERABLE_RPC(s) (((s) == RPC_AUTHERROR) || \ + ((s) == RPC_CANTENCODEARGS) || \ + ((s) == RPC_CANTDECODERES) || \ + ((s) == RPC_VERSMISMATCH) || \ + ((s) == RPC_PROCUNAVAIL) || \ + ((s) == RPC_PROGUNAVAIL) || \ + ((s) == RPC_PROGVERSMISMATCH) || \ + ((s) == RPC_CANTDECODEARGS)) + +/* + * Error info. + */ +struct rpc_err { + enum clnt_stat re_status; + union { + int RE_errno; /* related system error */ + enum auth_stat RE_why; /* why the auth error occurred */ + struct { + rpcvers_t low; /* lowest version supported */ + rpcvers_t high; /* highest version supported */ + } RE_vers; + struct { /* maybe meaningful if RPC_FAILED */ + int32_t s1; + int32_t s2; + } RE_lb; /* life boot & debugging only */ + } ru; +#define re_errno ru.RE_errno +#define re_why ru.RE_why +#define re_vers ru.RE_vers +#define re_lb ru.RE_lb +}; + + +/* + * Client rpc handle. + * Created by individual implementations + * Client is responsible for initializing auth, see e.g. auth_none.c. + */ +typedef struct __rpc_client { + AUTH *cl_auth; /* authenticator */ + struct clnt_ops { + /* call remote procedure */ + enum clnt_stat (*cl_call)(struct __rpc_client *, + rpcproc_t, xdrproc_t, void *, xdrproc_t, + void *, struct timeval); + /* abort a call */ + void (*cl_abort)(struct __rpc_client *); + /* get specific error code */ + void (*cl_geterr)(struct __rpc_client *, + struct rpc_err *); + /* frees results */ + bool_t (*cl_freeres)(struct __rpc_client *, + xdrproc_t, void *); + /* destroy this structure */ + void (*cl_destroy)(struct __rpc_client *); + /* the ioctl() of rpc */ + bool_t (*cl_control)(struct __rpc_client *, u_int, + void *); + } *cl_ops; + void *cl_private; /* private stuff */ + char *cl_netid; /* network token */ + char *cl_tp; /* device name */ + HANDLE *cb_thread; + int (*cb_xdr)(void *, void *); + int (*cb_fn)(void *, void *, void **); + void *cb_args; + bool_t shutdown; +} CLIENT; + +typedef struct __cb_req { + u_int32_t rq_prog; + u_int32_t rq_vers; + u_int32_t rq_proc; + void *xdr; +} cb_req; + +/* + * Timers used for the pseudo-transport protocol when using datagrams + */ +struct rpc_timers { + u_short rt_srtt; /* smoothed round-trip time */ + u_short rt_deviate; /* estimated deviation */ + u_long rt_rtxcur; /* current (backed-off) rto */ +}; + +/* + * Feedback values used for possible congestion and rate control + */ +#define FEEDBACK_REXMIT1 1 /* first retransmit */ +#define FEEDBACK_OK 2 /* no retransmits */ + +/* Used to set version of portmapper used in broadcast */ + +#define CLCR_SET_LOWVERS 3 +#define CLCR_GET_LOWVERS 4 + +#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ + +/* + * client side rpc interface ops + * + * Parameter types are: + * + */ + +/* + * enum clnt_stat + * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout) + * CLIENT *rh; + * rpcproc_t proc; + * xdrproc_t xargs; + * void *argsp; + * xdrproc_t xres; + * void *resp; + * struct timeval timeout; + */ +#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \ + argsp, xres, resp, secs)) +#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \ + argsp, xres, resp, secs)) + +/* + * void + * CLNT_ABORT(rh); + * CLIENT *rh; + */ +#define CLNT_ABORT(rh) ((*(rh)->cl_ops->cl_abort)(rh)) +#define clnt_abort(rh) ((*(rh)->cl_ops->cl_abort)(rh)) + +/* + * struct rpc_err + * CLNT_GETERR(rh); + * CLIENT *rh; + */ +#define CLNT_GETERR(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) +#define clnt_geterr(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) + + +/* + * bool_t + * CLNT_FREERES(rh, xres, resp); + * CLIENT *rh; + * xdrproc_t xres; + * void *resp; + */ +#define CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) +#define clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) + +/* + * bool_t + * CLNT_CONTROL(cl, request, info) + * CLIENT *cl; + * u_int request; + * char *info; + */ +#define CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) +#define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) + +/* + * control operations that apply to both udp and tcp transports + */ +#define CLSET_TIMEOUT 1 /* set timeout (timeval) */ +#define CLGET_TIMEOUT 2 /* get timeout (timeval) */ +#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */ +#define CLGET_FD 6 /* get connections file descriptor */ +#define CLGET_SVC_ADDR 7 /* get server's address (netbuf) */ +#define CLSET_FD_CLOSE 8 /* close fd while clnt_destroy */ +#define CLSET_FD_NCLOSE 9 /* Do not close fd while clnt_destroy */ +#define CLGET_XID 10 /* Get xid */ +#define CLSET_XID 11 /* Set xid */ +#define CLGET_VERS 12 /* Get version number */ +#define CLSET_VERS 13 /* Set version number */ +#define CLGET_PROG 14 /* Get program number */ +#define CLSET_PROG 15 /* Set program number */ +#define CLSET_SVC_ADDR 16 /* get server's address (netbuf) */ +#define CLSET_PUSH_TIMOD 17 /* push timod if not already present */ +#define CLSET_POP_TIMOD 18 /* pop timod */ +/* + * Connectionless only control operations + */ +#define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */ +#define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */ +#define CLSET_ASYNC 19 +#define CLSET_CONNECT 20 /* Use connect() for UDP. (int) */ + +/* + * void + * CLNT_DESTROY(rh); + * CLIENT *rh; + */ +#define CLNT_DESTROY(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) +#define clnt_destroy(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) + + +/* + * RPCTEST is a test program which is accessible on every rpc + * transport/port. It is used for testing, performance evaluation, + * and network administration. + */ + +#define RPCTEST_PROGRAM ((rpcprog_t)1) +#define RPCTEST_VERSION ((rpcvers_t)1) +#define RPCTEST_NULL_PROC ((rpcproc_t)2) +#define RPCTEST_NULL_BATCH_PROC ((rpcproc_t)3) + +/* + * By convention, procedure 0 takes null arguments and returns them + */ + +#define NULLPROC ((rpcproc_t)0) + +/* + * Below are the client handle creation routines for the various + * implementations of client side rpc. They can return NULL if a + * creation failure occurs. + */ + +/* + * Generic client creation routine. Supported protocols are those that + * belong to the nettype namespace (/etc/netconfig). + */ +__BEGIN_DECLS +extern CLIENT *clnt_create(const char *, const rpcprog_t, const rpcvers_t, + const char *); +/* + * + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const char *nettype; -- network type + */ + + /* + * Generic client creation routine. Just like clnt_create(), except + * it takes an additional timeout parameter. + */ +extern CLIENT * clnt_create_timed(const char *, const rpcprog_t, + const rpcvers_t, const char *, const struct timeval *); +/* + * + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const char *nettype; -- network type + * const struct timeval *tp; -- timeout + */ + +/* + * Generic client creation routine. Supported protocols are which belong + * to the nettype name space. + */ +extern CLIENT *clnt_create_vers(const char *, const rpcprog_t, rpcvers_t *, + const rpcvers_t, const rpcvers_t, + const char *); +/* + * const char *host; -- hostname + * const rpcprog_t prog; -- program number + * rpcvers_t *vers_out; -- servers highest available version + * const rpcvers_t vers_low; -- low version number + * const rpcvers_t vers_high; -- high version number + * const char *nettype; -- network type + */ + +/* + * Generic client creation routine. Supported protocols are which belong + * to the nettype name space. + */ +extern CLIENT * clnt_create_vers_timed(const char *, const rpcprog_t, + rpcvers_t *, const rpcvers_t, const rpcvers_t, const char *, + const struct timeval *); +/* + * const char *host; -- hostname + * const rpcprog_t prog; -- program number + * rpcvers_t *vers_out; -- servers highest available version + * const rpcvers_t vers_low; -- low version number + * const rpcvers_t vers_high; -- high version number + * const char *nettype; -- network type + * const struct timeval *tp -- timeout + */ + +/* + * Generic client creation routine. It takes a netconfig structure + * instead of nettype + */ +extern CLIENT *clnt_tp_create(const char *, const rpcprog_t, + const rpcvers_t, const struct netconfig *); +/* + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const struct netconfig *netconf; -- network config structure + */ + +/* + * Generic client creation routine. Just like clnt_tp_create(), except + * it takes an additional timeout parameter. + */ +extern CLIENT * clnt_tp_create_timed(const char *, const rpcprog_t, + const rpcvers_t, const struct netconfig *, const struct timeval *); +/* + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const struct netconfig *netconf; -- network config structure + * const struct timeval *tp -- timeout + */ + +/* + * Generic TLI create routine. Only provided for compatibility. + */ + +extern CLIENT *clnt_tli_create(const SOCKET, const struct netconfig *, + struct netbuf *, const rpcprog_t, + const rpcvers_t, const u_int, const u_int, + int (*cb_xdr)(void *, void *), + int (*cb)(void *, void *, void **), void *args); +/* + * const register int fd; -- fd + * const struct netconfig *nconf; -- netconfig structure + * struct netbuf *svcaddr; -- servers address + * const u_long prog; -- program number + * const u_long vers; -- version number + * const u_int sendsz; -- send size + * const u_int recvsz; -- recv size + */ + +/* + * Low level clnt create routine for connectionful transports, e.g. tcp. + */ +extern CLIENT *clnt_vc_create(const SOCKET, const struct netbuf *, + const rpcprog_t, const rpcvers_t, + u_int, u_int, int (*cb_xdr)(void *, void *), + int (*cb)(void *, void *, void **), void *args); +/* + * Added for compatibility to old rpc 4.0. Obsoleted by clnt_vc_create(). + */ +extern CLIENT *clntunix_create(struct sockaddr_un *, + u_long, u_long, int *, u_int, u_int); +/* + * const int fd; -- open file descriptor + * const struct netbuf *svcaddr; -- servers address + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const u_int sendsz; -- buffer recv size + * const u_int recvsz; -- buffer send size + */ + +/* + * Low level clnt create routine for connectionless transports, e.g. udp. + */ +extern CLIENT *clnt_dg_create(const SOCKET, const struct netbuf *, + const rpcprog_t, const rpcvers_t, + const u_int, const u_int); +/* + * const int fd; -- open file descriptor + * const struct netbuf *svcaddr; -- servers address + * const rpcprog_t program; -- program number + * const rpcvers_t version; -- version number + * const u_int sendsz; -- buffer recv size + * const u_int recvsz; -- buffer send size + */ + +/* + * Memory based rpc (for speed check and testing) + * CLIENT * + * clnt_raw_create(prog, vers) + * u_long prog; + * u_long vers; + */ +extern CLIENT *clnt_raw_create(rpcprog_t, rpcvers_t); + +__END_DECLS + + +/* + * Print why creation failed + */ +__BEGIN_DECLS +extern void clnt_pcreateerror(const char *); /* stderr */ +extern char *clnt_spcreateerror(const char *); /* string */ +__END_DECLS + +/* + * Like clnt_perror(), but is more verbose in its output + */ +__BEGIN_DECLS +extern void clnt_perrno(enum clnt_stat); /* stderr */ +extern char *clnt_sperrno(enum clnt_stat); /* string */ +__END_DECLS + +/* + * Print an English error message, given the client error code + */ +__BEGIN_DECLS +extern void clnt_perror(CLIENT *, const char *); /* stderr */ +extern char *clnt_sperror(CLIENT *, const char *); /* string */ +__END_DECLS + + +/* + * If a creation fails, the following allows the user to figure out why. + */ +struct rpc_createerr { + enum clnt_stat cf_stat; + struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */ +}; + +__BEGIN_DECLS +extern struct rpc_createerr *__rpc_createerr(void); +__END_DECLS +#define get_rpc_createerr() (*(__rpc_createerr())) +#define rpc_createerr (*(__rpc_createerr())) + +/* + * The simplified interface: + * enum clnt_stat + * rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype) + * const char *host; + * const rpcprog_t prognum; + * const rpcvers_t versnum; + * const rpcproc_t procnum; + * const xdrproc_t inproc, outproc; + * const char *in; + * char *out; + * const char *nettype; + */ +__BEGIN_DECLS +extern enum clnt_stat rpc_call(const char *, const rpcprog_t, + const rpcvers_t, const rpcproc_t, + const xdrproc_t, const char *, + const xdrproc_t, char *, const char *); +__END_DECLS + +/* + * RPC broadcast interface + * The call is broadcasted to all locally connected nets. + * + * extern enum clnt_stat + * rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, + * eachresult, nettype) + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const rpcproc_t proc; -- procedure number + * const xdrproc_t xargs; -- xdr routine for args + * caddr_t argsp; -- pointer to args + * const xdrproc_t xresults; -- xdr routine for results + * caddr_t resultsp; -- pointer to results + * const resultproc_t eachresult; -- call with each result + * const char *nettype; -- Transport type + * + * For each valid response received, the procedure eachresult is called. + * Its form is: + * done = eachresult(resp, raddr, nconf) + * bool_t done; + * caddr_t resp; + * struct netbuf *raddr; + * struct netconfig *nconf; + * where resp points to the results of the call and raddr is the + * address if the responder to the broadcast. nconf is the transport + * on which the response was received. + * + * extern enum clnt_stat + * rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp, + * eachresult, inittime, waittime, nettype) + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const rpcproc_t proc; -- procedure number + * const xdrproc_t xargs; -- xdr routine for args + * caddr_t argsp; -- pointer to args + * const xdrproc_t xresults; -- xdr routine for results + * caddr_t resultsp; -- pointer to results + * const resultproc_t eachresult; -- call with each result + * const int inittime; -- how long to wait initially + * const int waittime; -- maximum time to wait + * const char *nettype; -- Transport type + */ + +typedef bool_t (*resultproc_t)(caddr_t, ...); + +__BEGIN_DECLS +extern enum clnt_stat rpc_broadcast(const rpcprog_t, const rpcvers_t, + const rpcproc_t, const xdrproc_t, + caddr_t, const xdrproc_t, caddr_t, + const resultproc_t, const char *); +extern enum clnt_stat rpc_broadcast_exp(const rpcprog_t, const rpcvers_t, + const rpcproc_t, const xdrproc_t, + caddr_t, const xdrproc_t, caddr_t, + const resultproc_t, const int, + const int, const char *); +__END_DECLS + +/* For backward compatibility */ +#include + +#endif /* !_TIRPC_CLNT_H_ */ diff --git a/libtirpc/tirpc/rpc/clnt_soc.h b/libtirpc/tirpc/rpc/clnt_soc.h new file mode 100644 index 0000000..582f555 --- /dev/null +++ b/libtirpc/tirpc/rpc/clnt_soc.h @@ -0,0 +1,122 @@ +/* $NetBSD: clnt_soc.h,v 1.1 2000/06/02 22:57:55 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/clnt_soc.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. + */ + +/* + * clnt.h - Client side remote procedure call interface. + */ + +#ifndef _RPC_CLNT_SOC_H +#define _RPC_CLNT_SOC_H + +/* derived from clnt_soc.h 1.3 88/12/17 SMI */ + +/* + * All the following declarations are only for backward compatibility + * with TS-RPC. + */ + +//#include + +#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long prog; + * u_long version; + * register int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clnttcp_create(struct sockaddr_in *, u_long, u_long, SOCKET *, + u_int, u_int); +__END_DECLS + +/* + * Raw (memory) rpc. + */ +__BEGIN_DECLS +extern CLIENT *clntraw_create(u_long, u_long); +__END_DECLS + + +/* +IPv6 socket version +*/ +#ifdef INET6 +__BEGIN_DECLS +extern CLIENT *clnttcp6_create(struct sockaddr_in6 *, u_long, u_long, int *, + u_int, u_int); +__END_DECLS +#endif + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + * struct sockaddr_in *raddr; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * + * Same as above, but you specify max packet sizes. + * CLIENT * + * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clntudp_create(struct sockaddr_in *, u_long, u_long, + struct timeval, int *); +extern CLIENT *clntudp_bufcreate(struct sockaddr_in *, u_long, u_long, + struct timeval, int *, u_int, u_int); +#ifdef INET6 +extern CLIENT *clntudp6_create(struct sockaddr_in6 *, u_long, u_long, + struct timeval, int *); +extern CLIENT *clntudp6_bufcreate(struct sockaddr_in6 *, u_long, u_long, + struct timeval, int *, u_int, u_int); +#endif +__END_DECLS + + +#endif /* _RPC_CLNT_SOC_H */ diff --git a/libtirpc/tirpc/rpc/clnt_stat.h b/libtirpc/tirpc/rpc/clnt_stat.h new file mode 100644 index 0000000..397bdbc --- /dev/null +++ b/libtirpc/tirpc/rpc/clnt_stat.h @@ -0,0 +1,83 @@ +/* $FreeBSD: src/include/rpc/clnt_stat.h,v 1.2 2001/03/20 08:20:50 alfred Exp $ */ +/* + * Copyright (c) 1986 - 1991, 1994, 1996, 1997 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* + * clnt_stat.h - Client side remote procedure call enum + * + */ + +#ifndef _RPC_CLNT_STAT_H +#define _RPC_CLNT_STAT_H + +/* #pragma ident "@(#)clnt_stat.h 1.2 97/04/28 SMI" */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum clnt_stat { + RPC_SUCCESS = 0, /* call succeeded */ + /* + * local errors + */ + RPC_CANTENCODEARGS = 1, /* can't encode arguments */ + RPC_CANTDECODERES = 2, /* can't decode results */ + RPC_CANTSEND = 3, /* failure in sending call */ + RPC_CANTRECV = 4, + /* failure in receiving result */ + RPC_TIMEDOUT = 5, /* call timed out */ + RPC_INTR = 18, /* call interrupted */ + RPC_UDERROR = 23, /* recv got uderr indication */ + /* + * remote errors + */ + RPC_VERSMISMATCH = 6, /* rpc versions not compatible */ + RPC_AUTHERROR = 7, /* authentication error */ + RPC_PROGUNAVAIL = 8, /* program not available */ + RPC_PROGVERSMISMATCH = 9, /* program version mismatched */ + RPC_PROCUNAVAIL = 10, /* procedure unavailable */ + RPC_CANTDECODEARGS = 11, /* decode arguments error */ + RPC_SYSTEMERROR = 12, /* generic "other problem" */ + + /* + * rpc_call & clnt_create errors + */ + RPC_UNKNOWNHOST = 13, /* unknown host name */ + RPC_UNKNOWNPROTO = 17, /* unknown protocol */ + RPC_UNKNOWNADDR = 19, /* Remote address unknown */ + RPC_NOBROADCAST = 21, /* Broadcasting not supported */ + + /* + * rpcbind errors + */ + RPC_RPCBFAILURE = 14, /* the pmapper failed in its call */ +#define RPC_PMAPFAILURE RPC_RPCBFAILURE + RPC_PROGNOTREGISTERED = 15, /* remote program is not registered */ + RPC_N2AXLATEFAILURE = 22, + /* Name to address translation failed */ + /* + * Misc error in the TLI library + */ + RPC_TLIERROR = 20, + /* + * unspecified error + */ + RPC_FAILED = 16, + /* + * asynchronous errors + */ + RPC_INPROGRESS = 24, + RPC_STALERACHANDLE = 25, + RPC_CANTCONNECT = 26, /* couldn't make connection (cots) */ + RPC_XPRTFAILED = 27, /* received discon from remote (cots) */ + RPC_CANTCREATESTREAM = 28 /* can't push rpc module (cots) */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !_RPC_CLNT_STAT_H */ diff --git a/libtirpc/tirpc/rpc/des.h b/libtirpc/tirpc/rpc/des.h new file mode 100644 index 0000000..e3d6897 --- /dev/null +++ b/libtirpc/tirpc/rpc/des.h @@ -0,0 +1,82 @@ +/* @(#)des.h 2.2 88/08/10 4.0 RPCSRC; from 2.7 88/02/08 SMI */ +/* $FreeBSD: src/include/rpc/des.h,v 1.4 2002/03/23 17:24:55 imp Exp $ */ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Generic DES driver interface + * Keep this file hardware independent! + * Copyright (c) 1986 by Sun Microsystems, Inc. + */ + +#define DES_MAXLEN 65536 /* maximum # of bytes to encrypt */ +#define DES_QUICKLEN 16 /* maximum # of bytes to encrypt quickly */ + +enum desdir { ENCRYPT, DECRYPT }; +enum desmode { CBC, ECB }; + +/* + * parameters to ioctl call + */ +struct desparams { + u_char des_key[8]; /* key (with low bit parity) */ + enum desdir des_dir; /* direction */ + enum desmode des_mode; /* mode */ + u_char des_ivec[8]; /* input vector */ + unsigned des_len; /* number of bytes to crypt */ + union { + u_char UDES_data[DES_QUICKLEN]; + u_char *UDES_buf; + } UDES; +# define des_data UDES.UDES_data /* direct data here if quick */ +# define des_buf UDES.UDES_buf /* otherwise, pointer to data */ +}; + +#ifdef notdef + +/* + * These ioctls are only implemented in SunOS. Maybe someday + * if somebody writes a driver for DES hardware that works + * with FreeBSD, we can being that back. + */ + +/* + * Encrypt an arbitrary sized buffer + */ +#define DESIOCBLOCK _IOWR('d', 6, struct desparams) + +/* + * Encrypt of small amount of data, quickly + */ +#define DESIOCQUICK _IOWR('d', 7, struct desparams) + +#endif + +/* + * Software DES. + */ +extern int _des_crypt( char *, int, struct desparams * ); diff --git a/libtirpc/tirpc/rpc/des_crypt.h b/libtirpc/tirpc/rpc/des_crypt.h new file mode 100644 index 0000000..d4bd825 --- /dev/null +++ b/libtirpc/tirpc/rpc/des_crypt.h @@ -0,0 +1,105 @@ +/* + * @(#)des_crypt.h 2.1 88/08/11 4.0 RPCSRC; from 1.4 88/02/08 (C) 1986 SMI + * $FreeBSD: src/include/rpc/des_crypt.h,v 1.4 2002/03/23 17:24:55 imp Exp $ + * + * des_crypt.h, des library routine interface + * Copyright (C) 1986, Sun Microsystems, Inc. + */ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * des_crypt.h, des library routine interface + */ + +#ifndef _DES_DES_CRYPT_H +#define _DES_DES_CRYPT_H + +//#include +#include + +#define DES_MAXDATA 8192 /* max bytes encrypted in one call */ +#define DES_DIRMASK (1 << 0) +#define DES_ENCRYPT (0*DES_DIRMASK) /* Encrypt */ +#define DES_DECRYPT (1*DES_DIRMASK) /* Decrypt */ + + +#define DES_DEVMASK (1 << 1) +#define DES_HW (0*DES_DEVMASK) /* Use hardware device */ +#define DES_SW (1*DES_DEVMASK) /* Use software device */ + + +#define DESERR_NONE 0 /* succeeded */ +#define DESERR_NOHWDEVICE 1 /* succeeded, but hw device not available */ +#define DESERR_HWERROR 2 /* failed, hardware/driver error */ +#define DESERR_BADPARAM 3 /* failed, bad parameter to call */ + +#define DES_FAILED(err) \ + ((err) > DESERR_NOHWDEVICE) + +/* + * cbc_crypt() + * ecb_crypt() + * + * Encrypt (or decrypt) len bytes of a buffer buf. + * The length must be a multiple of eight. + * The key should have odd parity in the low bit of each byte. + * ivec is the input vector, and is updated to the new one (cbc only). + * The mode is created by oring together the appropriate parameters. + * DESERR_NOHWDEVICE is returned if DES_HW was specified but + * there was no hardware to do it on (the data will still be + * encrypted though, in software). + */ + + +/* + * Cipher Block Chaining mode + */ +__BEGIN_DECLS +int cbc_crypt( char *, char *, unsigned int, unsigned int, char *); +__END_DECLS + +/* + * Electronic Code Book mode + */ +__BEGIN_DECLS +int ecb_crypt( char *, char *, unsigned int, unsigned int ); +__END_DECLS + +/* + * Set des parity for a key. + * DES parity is odd and in the low bit of each byte + */ +__BEGIN_DECLS +void des_setparity( char *); +__END_DECLS + +#endif /* _DES_DES_CRYPT_H */ diff --git a/libtirpc/tirpc/rpc/nettype.h b/libtirpc/tirpc/rpc/nettype.h new file mode 100644 index 0000000..92063c6 --- /dev/null +++ b/libtirpc/tirpc/rpc/nettype.h @@ -0,0 +1,63 @@ +/* $NetBSD: nettype.h,v 1.2 2000/07/06 03:17:19 christos Exp $ */ +/* $FreeBSD: src/include/rpc/nettype.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * nettype.h, Nettype definitions. + * All for the topmost layer of rpc + * + */ + +#ifndef _TIRPC_NETTYPE_H +#define _TIRPC_NETTYPE_H + +#include + +#define _RPC_NONE 0 +#define _RPC_NETPATH 1 +#define _RPC_VISIBLE 2 +#define _RPC_CIRCUIT_V 3 +#define _RPC_DATAGRAM_V 4 +#define _RPC_CIRCUIT_N 5 +#define _RPC_DATAGRAM_N 6 +#define _RPC_TCP 7 +#define _RPC_UDP 8 + +__BEGIN_DECLS +extern void *__rpc_setconf(const char *); +extern void __rpc_endconf(void *); +extern struct netconfig *__rpc_getconf(void *); +extern struct netconfig *__rpc_getconfip(const char *); +__END_DECLS + +#endif /* !_TIRPC_NETTYPE_H */ diff --git a/libtirpc/tirpc/rpc/pmap_clnt.h b/libtirpc/tirpc/rpc/pmap_clnt.h new file mode 100644 index 0000000..98ac4fd --- /dev/null +++ b/libtirpc/tirpc/rpc/pmap_clnt.h @@ -0,0 +1,85 @@ +/* $NetBSD: pmap_clnt.h,v 1.9 2000/06/02 22:57:55 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)pmap_clnt.h 1.11 88/02/08 SMI + * from: @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/pmap_clnt.h,v 1.14 2002/04/28 15:18:45 des Exp $ + */ + +/* + * pmap_clnt.h + * Supplies C routines to get to portmap services. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Usage: + * success = pmap_set(program, version, protocol, port); + * success = pmap_unset(program, version); + * port = pmap_getport(address, program, version, protocol); + * head = pmap_getmaps(address); + * clnt_stat = pmap_rmtcall(address, program, version, procedure, + * xdrargs, argsp, xdrres, resp, tout, port_ptr) + * (works for udp only.) + * clnt_stat = clnt_broadcast(program, version, procedure, + * xdrargs, argsp, xdrres, resp, eachresult) + * (like pmap_rmtcall, except the call is broadcasted to all + * locally connected nets. For each valid response received, + * the procedure eachresult is called. Its form is: + * done = eachresult(resp, raddr) + * bool_t done; + * caddr_t resp; + * struct sockaddr_in raddr; + * where resp points to the results of the call and raddr is the + * address if the responder to the broadcast. + */ + +#ifndef _RPC_PMAP_CLNT_H_ +#define _RPC_PMAP_CLNT_H_ +//#include + +__BEGIN_DECLS +extern bool_t pmap_set(u_long, u_long, int, int); +extern bool_t pmap_unset(u_long, u_long); +extern struct pmaplist *pmap_getmaps(struct sockaddr_in *); +extern enum clnt_stat pmap_rmtcall(struct sockaddr_in *, + u_long, u_long, u_long, + xdrproc_t, caddr_t, + xdrproc_t, caddr_t, + struct timeval, u_long *); +extern enum clnt_stat clnt_broadcast(u_long, u_long, u_long, + xdrproc_t, void *, + xdrproc_t, void *, + resultproc_t); +extern u_short pmap_getport(struct sockaddr_in *, + u_long, u_long, u_int); +__END_DECLS + +#endif /* !_RPC_PMAP_CLNT_H_ */ diff --git a/libtirpc/tirpc/rpc/pmap_prot.h b/libtirpc/tirpc/rpc/pmap_prot.h new file mode 100644 index 0000000..27fae0c --- /dev/null +++ b/libtirpc/tirpc/rpc/pmap_prot.h @@ -0,0 +1,106 @@ +/* $NetBSD: pmap_prot.h,v 1.8 2000/06/02 22:57:55 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)pmap_prot.h 1.14 88/02/08 SMI + * from: @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/pmap_prot.h,v 1.12 2002/03/23 17:24:55 imp Exp $ + */ + +/* + * pmap_prot.h + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The following procedures are supported by the protocol: + * + * PMAPPROC_NULL() returns () + * takes nothing, returns nothing + * + * PMAPPROC_SET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Registers the tuple + * [prog, vers, prot, port]. + * + * PMAPPROC_UNSET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Un-registers pair + * [prog, vers]. prot and port are ignored. + * + * PMAPPROC_GETPORT(struct pmap) returns (long unsigned). + * 0 is failure. Otherwise returns the port number where the pair + * [prog, vers] is registered. It may lie! + * + * PMAPPROC_DUMP() RETURNS (struct pmaplist *) + * + * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>) + * RETURNS (port, string<>); + * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs); + * Calls the procedure on the local machine. If it is not registered, + * this procedure is quite; ie it does not return error information!!! + * This procedure only is supported on rpc/udp and calls via + * rpc/udp. This routine only passes null authentication parameters. + * This file has no interface to xdr routines for PMAPPROC_CALLIT. + * + * The service supports remote procedure calls on udp/ip or tcp/ip socket 111. + */ + +#ifndef _RPC_PMAP_PROT_H +#define _RPC_PMAP_PROT_H +//#include + +#define PMAPPORT ((u_short)111) +#define PMAPPROG ((u_long)100000) +#define PMAPVERS ((u_long)2) +#define PMAPVERS_PROTO ((u_long)2) +#define PMAPVERS_ORIG ((u_long)1) +#define PMAPPROC_NULL ((u_long)0) +#define PMAPPROC_SET ((u_long)1) +#define PMAPPROC_UNSET ((u_long)2) +#define PMAPPROC_GETPORT ((u_long)3) +#define PMAPPROC_DUMP ((u_long)4) +#define PMAPPROC_CALLIT ((u_long)5) + +struct pmap { + long unsigned pm_prog; + long unsigned pm_vers; + long unsigned pm_prot; + long unsigned pm_port; +}; + +struct pmaplist { + struct pmap pml_map; + struct pmaplist *pml_next; +}; + +__BEGIN_DECLS +extern bool_t xdr_pmap(XDR *, struct pmap *); +extern bool_t xdr_pmaplist(XDR *, struct pmaplist **); +extern bool_t xdr_pmaplist_ptr(XDR *, struct pmaplist *); +__END_DECLS + +#endif /* !_RPC_PMAP_PROT_H */ diff --git a/libtirpc/tirpc/rpc/pmap_rmt.h b/libtirpc/tirpc/rpc/pmap_rmt.h new file mode 100644 index 0000000..bb9591d --- /dev/null +++ b/libtirpc/tirpc/rpc/pmap_rmt.h @@ -0,0 +1,64 @@ +/* $NetBSD: pmap_rmt.h,v 1.7 1998/02/11 23:01:23 lukem Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)pmap_rmt.h 1.2 88/02/08 SMI + * from: @(#)pmap_rmt.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/pmap_rmt.h,v 1.12 2002/03/23 17:24:55 imp Exp $ + */ + +/* + * Structures and XDR routines for parameters to and replies from + * the portmapper remote-call-service. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#ifndef _RPC_PMAP_RMT_H +#define _RPC_PMAP_RMT_H +//#include + +struct rmtcallargs { + u_long prog, vers, proc, arglen; + caddr_t args_ptr; + xdrproc_t xdr_args; +}; + +struct rmtcallres { + u_long *port_ptr; + u_long resultslen; + caddr_t results_ptr; + xdrproc_t xdr_results; +}; + +__BEGIN_DECLS +extern bool_t xdr_rmtcall_args(XDR *, struct rmtcallargs *); +extern bool_t xdr_rmtcallres(XDR *, struct rmtcallres *); +__END_DECLS + +#endif /* !_RPC_PMAP_RMT_H */ diff --git a/libtirpc/tirpc/rpc/raw.h b/libtirpc/tirpc/rpc/raw.h new file mode 100644 index 0000000..4edd738 --- /dev/null +++ b/libtirpc/tirpc/rpc/raw.h @@ -0,0 +1,57 @@ +/* $NetBSD: raw.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/raw.h,v 1.1 2001/03/19 12:49:47 alfred Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +#ifndef _RPC_RAW_H +#define _RPC_RAW_H + +/* from: @(#)raw.h 1.11 94/04/25 SMI */ +/* from: @(#)raw.h 1.2 88/10/25 SMI */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * raw.h + * + * Raw interface + * The common memory area over which they will communicate + */ +extern char *__rpc_rawcombuf; + +#ifdef __cplusplus +} +#endif + +#endif /* _RPC_RAW_H */ diff --git a/libtirpc/tirpc/rpc/rpc.h b/libtirpc/tirpc/rpc/rpc.h new file mode 100644 index 0000000..685fe42 --- /dev/null +++ b/libtirpc/tirpc/rpc/rpc.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc.h, Just includes the billions of rpc header files necessary to + * do remote procedure calling. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#ifndef _TIRPC_RPC_H +#define _TIRPC_RPC_H + +#include /* some typedefs */ +#include "winsock2.h" +//#include +//#include + +/* external data representation interfaces */ +#include /* generic (de)serializer */ + +/* Client side only authentication */ +#include /* generic authenticator (client side) */ + +/* Client side (mostly) remote procedure call */ +#include /* generic rpc stuff */ + +/* semi-private protocol headers */ +#include /* protocol for rpc messages */ +#include /* protocol for unix style cred */ + +/* + * Uncomment-out the next line if you are building the rpc library with + * DES Authentication (see the README file in the secure_rpc/ directory). + */ +#include /* protocol for des style cred */ + +#ifdef HAVE_RPCSEC_GSS +#include /* RPCSEC_GSS */ +#endif + +/* Server side only remote procedure callee */ +#include /* service side authenticator */ +#include /* service manager and multiplexer */ + +/* Portmapper client, server, and protocol headers */ +#include +#include + +#ifndef _KERNEL +#include /* rpcbind interface functions */ +#endif +#include + +#ifndef UDPMSGSIZE +#define UDPMSGSIZE 8800 +#endif + +__BEGIN_DECLS +extern int get_myaddress(struct sockaddr_in *); +extern int bindresvport(SOCKET, struct sockaddr_in *) __THROW; +extern int registerrpc(int, int, int, char *(*)(char [UDPMSGSIZE]), + xdrproc_t, xdrproc_t); +extern int callrpc(const char *, int, int, int, xdrproc_t, void *, + xdrproc_t , void *); +extern int getrpcport(char *, int, int, int); + +char *taddr2uaddr(const struct netconfig *, const struct netbuf *); +struct netbuf *uaddr2taddr(const struct netconfig *, const char *); + +void freeuaddr(char *); /* free memory allocated by taddr2uaddr */ +void freenetbuf(struct netbuf *); /* free memory allocated by uaddr2taddr */ + +struct sockaddr; +extern int bindresvport_sa(SOCKET, struct sockaddr *); +__END_DECLS + +/* + * The following are not exported interfaces, they are for internal library + * and rpcbind use only. Do not use, they may change without notice. + */ +__BEGIN_DECLS +SOCKET __rpc_nconf2fd(const struct netconfig *); +int __rpc_nconf2sockinfo(const struct netconfig *, struct __rpc_sockinfo *); +int __rpc_fd2sockinfo(SOCKET, struct __rpc_sockinfo *); +u_int __rpc_get_t_size(int, int, int); +__END_DECLS + +#endif /* !_RPC_RPC_H */ diff --git a/libtirpc/tirpc/rpc/rpc_com.h b/libtirpc/tirpc/rpc/rpc_com.h new file mode 100644 index 0000000..adde181 --- /dev/null +++ b/libtirpc/tirpc/rpc/rpc_com.h @@ -0,0 +1,87 @@ +/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */ +/* $FreeBSD: src/include/rpc/rpc_com.h,v 1.6 2003/01/16 07:13:51 mbr Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpc_com.h, Common definitions for both the server and client side. + * All for the topmost layer of rpc + * + */ + +#ifndef _RPC_RPCCOM_H +#define _RPC_RPCCOM_H + +//#include + +/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */ + +/* + * The max size of the transport, if the size cannot be determined + * by other means. + */ +#define RPC_MAXDATASIZE 9000 +#define RPC_MAXADDRSIZE 1024 + +//#ifdef _WIN32 +//#define __RPC_GETXID(now) ((u_int32_t)_getpid() ^ (u_int32_t)(now)->tv_sec ^ \ +// (u_int32_t)(now)->tv_usec) +//#else +#define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \ + (u_int32_t)(now)->tv_usec) +//#endif + +__BEGIN_DECLS +extern u_int __rpc_get_a_size(int); +extern int __rpc_dtbsize(void); +extern int _rpc_dtablesize(void); +extern struct netconfig * __rpcgettp(int); +extern int __rpc_get_default_domain(char **); + +char *__rpc_taddr2uaddr_af(int, const struct netbuf *); +struct netbuf *__rpc_uaddr2taddr_af(int, const char *); +int __rpc_fixup_addr(struct netbuf *, const struct netbuf *); +int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **); +int __rpc_seman2socktype(int); +int __rpc_socktype2seman(int); +void *rpc_nullproc(CLIENT *); +int __rpc_sockisbound(SOCKET); + +struct netbuf *__rpcb_findaddr(rpcprog_t, rpcvers_t, const struct netconfig *, + const char *, CLIENT **); +bool_t rpc_control(int,void *); + +char *_get_next_token(char *, int); + +__END_DECLS + +#endif /* _RPC_RPCCOM_H */ diff --git a/libtirpc/tirpc/rpc/rpc_msg.h b/libtirpc/tirpc/rpc/rpc_msg.h new file mode 100644 index 0000000..3bbf7be --- /dev/null +++ b/libtirpc/tirpc/rpc/rpc_msg.h @@ -0,0 +1,224 @@ +/* $NetBSD: rpc_msg.h,v 1.11 2000/06/02 22:57:56 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)rpc_msg.h 1.7 86/07/16 SMI + * from: @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/rpc_msg.h,v 1.15 2003/01/01 18:48:42 schweikh Exp $ + */ + +/* + * rpc_msg.h + * rpc message definition + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _TIRPC_RPC_MSG_H +#define _TIRPC_RPC_MSG_H + +#define RPC_MSG_VERSION ((u_int32_t) 2) +#define RPC_SERVICE_PORT ((u_short) 2048) + +#include + +/* + * Bottom up definition of an rpc message. + * NOTE: call and reply use the same overall stuct but + * different parts of unions within it. + */ + +enum msg_type { + CALL=0, + REPLY=1 +}; + +enum reply_stat { + MSG_ACCEPTED=0, + MSG_DENIED=1 +}; + +enum accept_stat { + SUCCESS=0, + PROG_UNAVAIL=1, + PROG_MISMATCH=2, + PROC_UNAVAIL=3, + GARBAGE_ARGS=4, + SYSTEM_ERR=5 +}; + +enum reject_stat { + RPC_MISMATCH=0, + AUTH_ERROR=1 +}; + +/* + * Reply part of an rpc exchange + */ + +/* + * Reply to an rpc request that was accepted by the server. + * Note: there could be an error even though the request was + * accepted. + */ +struct accepted_reply { + struct opaque_auth ar_verf; + enum accept_stat ar_stat; + union { + struct { + rpcvers_t low; + rpcvers_t high; + } AR_versions; + struct { + caddr_t where; + xdrproc_t proc; + } AR_results; + /* and many other null cases */ + } ru; +#define ar_results ru.AR_results +#define ar_vers ru.AR_versions +}; + +/* + * Reply to an rpc request that was rejected by the server. + */ +struct rejected_reply { + enum reject_stat rj_stat; + union { + struct { + rpcvers_t low; + rpcvers_t high; + } RJ_versions; + enum auth_stat RJ_why; /* why authentication did not work */ + } ru; +#define rj_vers ru.RJ_versions +#define rj_why ru.RJ_why +}; + +/* + * Body of a reply to an rpc request. + */ +struct reply_body { + enum reply_stat rp_stat; + union { + struct accepted_reply RP_ar; + struct rejected_reply RP_dr; + } ru; +#define rp_acpt ru.RP_ar +#define rp_rjct ru.RP_dr +}; + +/* + * Body of an rpc request call. + */ +struct call_body { + rpcvers_t cb_rpcvers; /* must be equal to two */ + rpcprog_t cb_prog; + rpcvers_t cb_vers; + rpcproc_t cb_proc; + struct opaque_auth cb_cred; + struct opaque_auth cb_verf; /* protocol specific - provided by client */ +}; + +/* + * The rpc message + */ +struct rpc_msg { + u_int32_t rm_xid; + enum msg_type rm_direction; + union { + struct call_body RM_cmb; + struct reply_body RM_rmb; + } ru; +#define rm_call ru.RM_cmb +#define rm_reply ru.RM_rmb +}; +#define acpted_rply ru.RM_rmb.ru.RP_ar +#define rjcted_rply ru.RM_rmb.ru.RP_dr + +__BEGIN_DECLS +/* + * XDR routine to handle a rpc message. + * xdr_callmsg(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callmsg(XDR *, struct rpc_msg *); + +/* + * XDR routine to pre-serialize the static part of a rpc message. + * xdr_callhdr(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callhdr(XDR *, struct rpc_msg *); + +/* + * XDR routine to handle a rpc reply. + * xdr_replymsg(xdrs, rmsg) + * XDR *xdrs; + * struct rpc_msg *rmsg; + */ +extern bool_t xdr_replymsg(XDR *, struct rpc_msg *); + +/* + * XDR routine to read just xid and direction, then union + * xdr_getxiddir(xdrs, rmsg) + * XDR *xdrs; + * struct rpc_msg *rmsg; + */ +extern bool_t xdr_getxiddir(XDR *, struct rpc_msg *); +extern bool_t xdr_getreplyunion(XDR *, struct rpc_msg *); +extern bool_t xdr_getcallbody(XDR *, struct rpc_msg *); + +/* + * XDR routine to handle an accepted rpc reply. + * xdr_accepted_reply(xdrs, rej) + * XDR *xdrs; + * struct accepted_reply *rej; + */ +extern bool_t xdr_accepted_reply(XDR *, struct accepted_reply *); + +/* + * XDR routine to handle a rejected rpc reply. + * xdr_rejected_reply(xdrs, rej) + * XDR *xdrs; + * struct rejected_reply *rej; + */ +extern bool_t xdr_rejected_reply(XDR *, struct rejected_reply *); + +/* + * Fills in the error part of a reply message. + * _seterr_reply(msg, error) + * struct rpc_msg *msg; + * struct rpc_err *error; + */ +extern void _seterr_reply(struct rpc_msg *, struct rpc_err *); +__END_DECLS + +#endif /* !_TIRPC_RPC_MSG_H */ diff --git a/libtirpc/tirpc/rpc/rpcb_clnt.h b/libtirpc/tirpc/rpc/rpcb_clnt.h new file mode 100644 index 0000000..7e64f8f --- /dev/null +++ b/libtirpc/tirpc/rpc/rpcb_clnt.h @@ -0,0 +1,83 @@ +/* $NetBSD: rpcb_clnt.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/rpcb_clnt.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpcb_clnt.h + * Supplies C routines to get to rpcbid services. + * + */ + +/* + * Usage: + * success = rpcb_set(program, version, nconf, address); + * success = rpcb_unset(program, version, nconf); + * success = rpcb_getaddr(program, version, nconf, host); + * head = rpcb_getmaps(nconf, host); + * clnt_stat = rpcb_rmtcall(nconf, host, program, version, procedure, + * xdrargs, argsp, xdrres, resp, tout, addr_ptr) + * success = rpcb_gettime(host, timep) + * uaddr = rpcb_taddr2uaddr(nconf, taddr); + * taddr = rpcb_uaddr2uaddr(nconf, uaddr); + */ + +#ifndef _RPC_RPCB_CLNT_H +#define _RPC_RPCB_CLNT_H + +/* #pragma ident "@(#)rpcb_clnt.h 1.13 94/04/25 SMI" */ +/* rpcb_clnt.h 1.3 88/12/05 SMI */ + +#include +#include +__BEGIN_DECLS +extern bool_t rpcb_set(const rpcprog_t, const rpcvers_t, + const struct netconfig *, const struct netbuf *); +extern bool_t rpcb_unset(const rpcprog_t, const rpcvers_t, + const struct netconfig *); +extern rpcblist *rpcb_getmaps(const struct netconfig *, const char *); +extern enum clnt_stat rpcb_rmtcall(const struct netconfig *, + const char *, const rpcprog_t, + const rpcvers_t, const rpcproc_t, + const xdrproc_t, const caddr_t, + const xdrproc_t, const caddr_t, + const struct timeval, + const struct netbuf *); +extern bool_t rpcb_getaddr(const rpcprog_t, const rpcvers_t, + const struct netconfig *, struct netbuf *, + const char *); +extern bool_t rpcb_gettime(const char *, time_t *); +extern char *rpcb_taddr2uaddr(struct netconfig *, struct netbuf *); +extern struct netbuf *rpcb_uaddr2taddr(struct netconfig *, char *); +__END_DECLS + +#endif /* !_RPC_RPCB_CLNT_H */ diff --git a/libtirpc/tirpc/rpc/rpcb_prot.h b/libtirpc/tirpc/rpc/rpcb_prot.h new file mode 100644 index 0000000..b69b4ce --- /dev/null +++ b/libtirpc/tirpc/rpc/rpcb_prot.h @@ -0,0 +1,803 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _RPCB_PROT_H_RPCGEN +#define _RPCB_PROT_H_RPCGEN + +#include + +#ifndef IXDR_GET_INT32 +#define IXDR_GET_INT32(buf) IXDR_GET_LONG((buf)) +#endif +#ifndef IXDR_PUT_INT32 +#define IXDR_PUT_INT32(buf, v) IXDR_PUT_LONG((buf), (v)) +#endif +#ifndef IXDR_GET_U_INT32 +#define IXDR_GET_U_INT32(buf) IXDR_GET_U_LONG((buf)) +#endif +#ifndef IXDR_PUT_U_INT32 +#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_U_LONG((buf), (v)) +#endif +/* + * $FreeBSD: src/include/rpc/rpcb_prot.x,v 1.3 2002/03/13 10:29:06 obrien Exp $ + * + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ +/* from rpcb_prot.x */ + +/* #pragma ident "@(#)rpcb_prot.x 1.5 94/04/29 SMI" */ + +#ifndef _KERNEL + + +/* + * The following procedures are supported by the protocol in version 3: + * + * RPCBPROC_NULL() returns () + * takes nothing, returns nothing + * + * RPCBPROC_SET(rpcb) returns (bool_t) + * TRUE is success, FALSE is failure. Registers the tuple + * [prog, vers, address, owner, netid]. + * Finds out owner and netid information on its own. + * + * RPCBPROC_UNSET(rpcb) returns (bool_t) + * TRUE is success, FALSE is failure. Un-registers tuple + * [prog, vers, netid]. addresses is ignored. + * If netid is NULL, unregister all. + * + * RPCBPROC_GETADDR(rpcb) returns (string). + * 0 is failure. Otherwise returns the universal address where the + * triple [prog, vers, netid] is registered. Ignore address and owner. + * + * RPCBPROC_DUMP() RETURNS (rpcblist_ptr) + * used to dump the entire rpcbind maps + * + * RPCBPROC_CALLIT(rpcb_rmtcallargs) + * RETURNS (rpcb_rmtcallres); + * Calls the procedure on the remote machine. If it is not registered, + * this procedure is quiet; i.e. it does not return error information!!! + * This routine only passes null authentication parameters. + * It has no interface to xdr routines for RPCBPROC_CALLIT. + * + * RPCBPROC_GETTIME() returns (int). + * Gets the remote machines time + * + * RPCBPROC_UADDR2TADDR(strint) RETURNS (struct netbuf) + * Returns the netbuf address from universal address. + * + * RPCBPROC_TADDR2UADDR(struct netbuf) RETURNS (string) + * Returns the universal address from netbuf address. + * + * END OF RPCBIND VERSION 3 PROCEDURES + */ +/* + * Except for RPCBPROC_CALLIT, the procedures above are carried over to + * rpcbind version 4. Those below are added or modified for version 4. + * NOTE: RPCBPROC_BCAST HAS THE SAME FUNCTIONALITY AND PROCEDURE NUMBER + * AS RPCBPROC_CALLIT. + * + * RPCBPROC_BCAST(rpcb_rmtcallargs) + * RETURNS (rpcb_rmtcallres); + * Calls the procedure on the remote machine. If it is not registered, + * this procedure IS quiet; i.e. it DOES NOT return error information!!! + * This routine should be used for broadcasting and nothing else. + * + * RPCBPROC_GETVERSADDR(rpcb) returns (string). + * 0 is failure. Otherwise returns the universal address where the + * triple [prog, vers, netid] is registered. Ignore address and owner. + * Same as RPCBPROC_GETADDR except that if the given version number + * is not available, the address is not returned. + * + * RPCBPROC_INDIRECT(rpcb_rmtcallargs) + * RETURNS (rpcb_rmtcallres); + * Calls the procedure on the remote machine. If it is not registered, + * this procedure is NOT quiet; i.e. it DOES return error information!!! + * as any normal application would expect. + * + * RPCBPROC_GETADDRLIST(rpcb) returns (rpcb_entry_list_ptr). + * Same as RPCBPROC_GETADDR except that it returns a list of all the + * addresses registered for the combination (prog, vers) (for all + * transports). + * + * RPCBPROC_GETSTAT(void) returns (rpcb_stat_byvers) + * Returns the statistics about the kind of requests received by rpcbind. + */ + +/* + * A mapping of (program, version, network ID) to address + */ + +struct rpcb { + rpcprog_t r_prog; + rpcvers_t r_vers; + char *r_netid; + char *r_addr; + char *r_owner; +}; +typedef struct rpcb rpcb; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb(XDR *, rpcb*); +#elif __STDC__ +extern bool_t xdr_rpcb(XDR *, rpcb*); +#else /* Old Style C */ +//bool_t xdr_rpcb(); +bool_t xdr_rpcb(XDR *, rpcb*); +#endif /* Old Style C */ + + +typedef rpcb RPCB; + + +/* + * A list of mappings + * + * Below are two definitions for the rpcblist structure. This is done because + * xdr_rpcblist() is specified to take a struct rpcblist **, rather than a + * struct rpcblist * that rpcgen would produce. One version of the rpcblist + * structure (actually called rp__list) is used with rpcgen, and the other is + * defined only in the header file for compatibility with the specified + * interface. + */ + +struct rp__list { + rpcb rpcb_map; + struct rp__list *rpcb_next; +}; +typedef struct rp__list rp__list; +#ifdef __cplusplus +extern "C" bool_t xdr_rp__list(XDR *, rp__list*); +#elif __STDC__ +extern bool_t xdr_rp__list(XDR *, rp__list*); +#else /* Old Style C */ +//bool_t xdr_rp__list(); +bool_t xdr_rp__list(XDR *, rp__list*); +#endif /* Old Style C */ + + +typedef rp__list *rpcblist_ptr; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcblist_ptr(XDR *, rpcblist_ptr*); +#elif __STDC__ +extern bool_t xdr_rpcblist_ptr(XDR *, rpcblist_ptr*); +#else /* Old Style C */ +//bool_t xdr_rpcblist_ptr(); +bool_t xdr_rpcblist_ptr(XDR *, rpcblist_ptr*); +#endif /* Old Style C */ + + +typedef struct rp__list rpcblist; +typedef struct rp__list RPCBLIST; + +#ifndef __cplusplus +struct rpcblist { + RPCB rpcb_map; + struct rpcblist *rpcb_next; +}; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +extern bool_t xdr_rpcblist(XDR *, rpcblist**); +#ifdef __cplusplus +} +#endif + + +/* + * Arguments of remote calls + */ + +struct rpcb_rmtcallargs { + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + struct { + u_int args_len; + char *args_val; + } args; +}; +typedef struct rpcb_rmtcallargs rpcb_rmtcallargs; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_rmtcallargs(XDR *, rpcb_rmtcallargs*); +#elif __STDC__ +extern bool_t xdr_rpcb_rmtcallargs(XDR *, rpcb_rmtcallargs*); +#else /* Old Style C */ +//bool_t xdr_rpcb_rmtcallargs(); +bool_t xdr_rpcb_rmtcallargs(XDR *, rpcb_rmtcallargs*); +#endif /* Old Style C */ + + +/* + * Client-side only representation of rpcb_rmtcallargs structure. + * + * The routine that XDRs the rpcb_rmtcallargs structure must deal with the + * opaque arguments in the "args" structure. xdr_rpcb_rmtcallargs() needs to + * be passed the XDR routine that knows the args' structure. This routine + * doesn't need to go over-the-wire (and it wouldn't make sense anyway) since + * the application being called already knows the args structure. So we use a + * different "XDR" structure on the client side, r_rpcb_rmtcallargs, which + * includes the args' XDR routine. + */ +struct r_rpcb_rmtcallargs { + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + struct { + u_int args_len; + char *args_val; + } args; + xdrproc_t xdr_args; /* encodes args */ +}; + + +/* + * Results of the remote call + */ + +struct rpcb_rmtcallres { + char *addr; + struct { + u_int results_len; + char *results_val; + } results; +}; +typedef struct rpcb_rmtcallres rpcb_rmtcallres; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_rmtcallres(XDR *, rpcb_rmtcallres*); +#elif __STDC__ +extern bool_t xdr_rpcb_rmtcallres(XDR *, rpcb_rmtcallres*); +#else /* Old Style C */ +//bool_t xdr_rpcb_rmtcallres(); +bool_t xdr_rpcb_rmtcallres(XDR *, rpcb_rmtcallres*); +#endif /* Old Style C */ + + +/* + * Client-side only representation of rpcb_rmtcallres structure. + */ +struct r_rpcb_rmtcallres { + char *addr; + struct { + u_int32_t results_len; + char *results_val; + } results; + xdrproc_t xdr_res; /* decodes results */ +}; + +/* + * rpcb_entry contains a merged address of a service on a particular + * transport, plus associated netconfig information. A list of rpcb_entrys + * is returned by RPCBPROC_GETADDRLIST. See netconfig.h for values used + * in r_nc_* fields. + */ + +struct rpcb_entry { + char *r_maddr; + char *r_nc_netid; + u_int r_nc_semantics; + char *r_nc_protofmly; + char *r_nc_proto; +}; +typedef struct rpcb_entry rpcb_entry; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_entry(XDR *, rpcb_entry*); +#elif __STDC__ +extern bool_t xdr_rpcb_entry(XDR *, rpcb_entry*); +#else /* Old Style C */ +bool_t xdr_rpcb_entry(); +#endif /* Old Style C */ + + +/* + * A list of addresses supported by a service. + */ + +struct rpcb_entry_list { + rpcb_entry rpcb_entry_map; + struct rpcb_entry_list *rpcb_entry_next; +}; +typedef struct rpcb_entry_list rpcb_entry_list; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_entry_list(XDR *, rpcb_entry_list*); +#elif __STDC__ +extern bool_t xdr_rpcb_entry_list(XDR *, rpcb_entry_list*); +#else /* Old Style C */ +bool_t xdr_rpcb_entry_list(); +#endif /* Old Style C */ + + +typedef rpcb_entry_list *rpcb_entry_list_ptr; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_entry_list_ptr(XDR *, rpcb_entry_list_ptr*); +#elif __STDC__ +extern bool_t xdr_rpcb_entry_list_ptr(XDR *, rpcb_entry_list_ptr*); +#else /* Old Style C */ +bool_t xdr_rpcb_entry_list_ptr(); +#endif /* Old Style C */ + + +/* + * rpcbind statistics + */ + +#define rpcb_highproc_2 RPCBPROC_CALLIT +#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR +#define rpcb_highproc_4 RPCBPROC_GETSTAT +#define RPCBSTAT_HIGHPROC 13 +#define RPCBVERS_STAT 3 +#define RPCBVERS_4_STAT 2 +#define RPCBVERS_3_STAT 1 +#define RPCBVERS_2_STAT 0 + +/* Link list of all the stats about getport and getaddr */ + +struct rpcbs_addrlist { + rpcprog_t prog; + rpcvers_t vers; + int success; + int failure; + char *netid; + struct rpcbs_addrlist *next; +}; +typedef struct rpcbs_addrlist rpcbs_addrlist; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcbs_addrlist(XDR *, rpcbs_addrlist*); +#elif __STDC__ +extern bool_t xdr_rpcbs_addrlist(XDR *, rpcbs_addrlist*); +#else /* Old Style C */ +bool_t xdr_rpcbs_addrlist(); +#endif /* Old Style C */ + + +/* Link list of all the stats about rmtcall */ + +struct rpcbs_rmtcalllist { + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + int success; + int failure; + int indirect; + char *netid; + struct rpcbs_rmtcalllist *next; +}; +typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcbs_rmtcalllist(XDR *, rpcbs_rmtcalllist*); +#elif __STDC__ +extern bool_t xdr_rpcbs_rmtcalllist(XDR *, rpcbs_rmtcalllist*); +#else /* Old Style C */ +bool_t xdr_rpcbs_rmtcalllist(); +#endif /* Old Style C */ + + +typedef int rpcbs_proc[RPCBSTAT_HIGHPROC]; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcbs_proc(XDR *, rpcbs_proc); +#elif __STDC__ +extern bool_t xdr_rpcbs_proc(XDR *, rpcbs_proc); +#else /* Old Style C */ +bool_t xdr_rpcbs_proc(); +#endif /* Old Style C */ + + +typedef rpcbs_addrlist *rpcbs_addrlist_ptr; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcbs_addrlist_ptr(XDR *, rpcbs_addrlist_ptr*); +#elif __STDC__ +extern bool_t xdr_rpcbs_addrlist_ptr(XDR *, rpcbs_addrlist_ptr*); +#else /* Old Style C */ +bool_t xdr_rpcbs_addrlist_ptr(); +#endif /* Old Style C */ + + +typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcbs_rmtcalllist_ptr(XDR *, rpcbs_rmtcalllist_ptr*); +#elif __STDC__ +extern bool_t xdr_rpcbs_rmtcalllist_ptr(XDR *, rpcbs_rmtcalllist_ptr*); +#else /* Old Style C */ +//bool_t xdr_rpcbs_rmtcalllist_ptr(); +bool_t xdr_rpcbs_rmtcalllist_ptr(XDR *, rpcbs_rmtcalllist_ptr*); +#endif /* Old Style C */ + + +struct rpcb_stat { + rpcbs_proc info; + int setinfo; + int unsetinfo; + rpcbs_addrlist_ptr addrinfo; + rpcbs_rmtcalllist_ptr rmtinfo; +}; +typedef struct rpcb_stat rpcb_stat; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_stat(XDR *, rpcb_stat*); +#elif __STDC__ +extern bool_t xdr_rpcb_stat(XDR *, rpcb_stat*); +#else /* Old Style C */ +bool_t xdr_rpcb_stat(); +#endif /* Old Style C */ + + +/* + * One rpcb_stat structure is returned for each version of rpcbind + * being monitored. + */ + +typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT]; +#ifdef __cplusplus +extern "C" bool_t xdr_rpcb_stat_byvers(XDR *, rpcb_stat_byvers); +#elif __STDC__ +extern bool_t xdr_rpcb_stat_byvers(XDR *, rpcb_stat_byvers); +#else /* Old Style C */ +bool_t xdr_rpcb_stat_byvers(); +#endif /* Old Style C */ + + +/* + * We don't define netbuf in RPCL, since it would contain structure member + * names that would conflict with the definition of struct netbuf in + * . Instead we merely declare the XDR routine xdr_netbuf() here, + * and implement it ourselves in rpc/rpcb_prot.c. + */ +#ifdef __cplusplus +extern "C" bool_t xdr_netbuf(XDR *, struct netbuf *); + +#else /* __STDC__ */ +extern bool_t xdr_netbuf(XDR *, struct netbuf *); + +#endif + +#define RPCBVERS_3 RPCBVERS +#define RPCBVERS_4 RPCBVERS4 + +#define _PATH_RPCBINDSOCK "/var/run/rpcbind.sock" + +#else /* ndef _KERNEL */ +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A mapping of (program, version, network ID) to address + */ +struct rpcb { + rpcprog_t r_prog; /* program number */ + rpcvers_t r_vers; /* version number */ + char *r_netid; /* network id */ + char *r_addr; /* universal address */ + char *r_owner; /* owner of the mapping */ +}; +typedef struct rpcb RPCB; + +/* + * A list of mappings + */ +struct rpcblist { + RPCB rpcb_map; + struct rpcblist *rpcb_next; +}; +typedef struct rpcblist RPCBLIST; +typedef struct rpcblist *rpcblist_ptr; + +/* + * Remote calls arguments + */ +struct rpcb_rmtcallargs { + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + u_int32_t arglen; /* arg len */ + caddr_t args_ptr; /* argument */ + xdrproc_t xdr_args; /* XDR routine for argument */ +}; +typedef struct rpcb_rmtcallargs rpcb_rmtcallargs; + +/* + * Remote calls results + */ +struct rpcb_rmtcallres { + char *addr_ptr; /* remote universal address */ + u_int32_t resultslen; /* results length */ + caddr_t results_ptr; /* results */ + xdrproc_t xdr_results; /* XDR routine for result */ +}; +typedef struct rpcb_rmtcallres rpcb_rmtcallres; + +struct rpcb_entry { + char *r_maddr; + char *r_nc_netid; + unsigned int r_nc_semantics; + char *r_nc_protofmly; + char *r_nc_proto; +}; +typedef struct rpcb_entry rpcb_entry; + +/* + * A list of addresses supported by a service. + */ + +struct rpcb_entry_list { + rpcb_entry rpcb_entry_map; + struct rpcb_entry_list *rpcb_entry_next; +}; +typedef struct rpcb_entry_list rpcb_entry_list; + +typedef rpcb_entry_list *rpcb_entry_list_ptr; + +/* + * rpcbind statistics + */ + +#define rpcb_highproc_2 RPCBPROC_CALLIT +#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR +#define rpcb_highproc_4 RPCBPROC_GETSTAT +#define RPCBSTAT_HIGHPROC 13 +#define RPCBVERS_STAT 3 +#define RPCBVERS_4_STAT 2 +#define RPCBVERS_3_STAT 1 +#define RPCBVERS_2_STAT 0 + +/* Link list of all the stats about getport and getaddr */ + +struct rpcbs_addrlist { + rpcprog_t prog; + rpcvers_t vers; + int success; + int failure; + char *netid; + struct rpcbs_addrlist *next; +}; +typedef struct rpcbs_addrlist rpcbs_addrlist; + +/* Link list of all the stats about rmtcall */ + +struct rpcbs_rmtcalllist { + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + int success; + int failure; + int indirect; + char *netid; + struct rpcbs_rmtcalllist *next; +}; +typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist; + +typedef int rpcbs_proc[RPCBSTAT_HIGHPROC]; + +typedef rpcbs_addrlist *rpcbs_addrlist_ptr; + +typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr; + +struct rpcb_stat { + rpcbs_proc info; + int setinfo; + int unsetinfo; + rpcbs_addrlist_ptr addrinfo; + rpcbs_rmtcalllist_ptr rmtinfo; +}; +typedef struct rpcb_stat rpcb_stat; + +/* + * One rpcb_stat structure is returned for each version of rpcbind + * being monitored. + */ + +typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT]; + +#ifdef __cplusplus +} +#endif + +#endif /* ndef _KERNEL */ + +#define RPCBPROG ((u_int32_t)100000) +#define RPCBVERS ((u_int32_t)3) + +#ifdef __cplusplus +#define RPCBPROC_SET ((u_int32_t)1) +extern "C" bool_t * rpcbproc_set_3(rpcb *, CLIENT *); +extern "C" bool_t * rpcbproc_set_3_svc(rpcb *, struct svc_req *); +#define RPCBPROC_UNSET ((u_int32_t)2) +extern "C" bool_t * rpcbproc_unset_3(rpcb *, CLIENT *); +extern "C" bool_t * rpcbproc_unset_3_svc(rpcb *, struct svc_req *); +#define RPCBPROC_GETADDR ((u_int32_t)3) +extern "C" char ** rpcbproc_getaddr_3(rpcb *, CLIENT *); +extern "C" char ** rpcbproc_getaddr_3_svc(rpcb *, struct svc_req *); +#define RPCBPROC_DUMP ((u_int32_t)4) +extern "C" rpcblist_ptr * rpcbproc_dump_3(void *, CLIENT *); +extern "C" rpcblist_ptr * rpcbproc_dump_3_svc(void *, struct svc_req *); +#define RPCBPROC_CALLIT ((u_int32_t)5) +extern "C" rpcb_rmtcallres * rpcbproc_callit_3(rpcb_rmtcallargs *, CLIENT *); +extern "C" rpcb_rmtcallres * rpcbproc_callit_3_svc(rpcb_rmtcallargs *, struct svc_req *); +#define RPCBPROC_GETTIME ((u_int32_t)6) +extern "C" u_int * rpcbproc_gettime_3(void *, CLIENT *); +extern "C" u_int * rpcbproc_gettime_3_svc(void *, struct svc_req *); +#define RPCBPROC_UADDR2TADDR ((u_int32_t)7) +extern "C" struct netbuf * rpcbproc_uaddr2taddr_3(char **, CLIENT *); +extern "C" struct netbuf * rpcbproc_uaddr2taddr_3_svc(char **, struct svc_req *); +#define RPCBPROC_TADDR2UADDR ((u_int32_t)8) +extern "C" char ** rpcbproc_taddr2uaddr_3(struct netbuf *, CLIENT *); +extern "C" char ** rpcbproc_taddr2uaddr_3_svc(struct netbuf *, struct svc_req *); + +#elif __STDC__ +#define RPCBPROC_SET ((u_int32_t)1) +extern bool_t * rpcbproc_set_3(rpcb *, CLIENT *); +extern bool_t * rpcbproc_set_3_svc(rpcb *, struct svc_req *); +#define RPCBPROC_UNSET ((u_int32_t)2) +extern bool_t * rpcbproc_unset_3(rpcb *, CLIENT *); +extern bool_t * rpcbproc_unset_3_svc(rpcb *, struct svc_req *); +#define RPCBPROC_GETADDR ((u_int32_t)3) +extern char ** rpcbproc_getaddr_3(rpcb *, CLIENT *); +extern char ** rpcbproc_getaddr_3_svc(rpcb *, struct svc_req *); +#define RPCBPROC_DUMP ((u_int32_t)4) +extern rpcblist_ptr * rpcbproc_dump_3(void *, CLIENT *); +extern rpcblist_ptr * rpcbproc_dump_3_svc(void *, struct svc_req *); +#define RPCBPROC_CALLIT ((u_int32_t)5) +extern rpcb_rmtcallres * rpcbproc_callit_3(rpcb_rmtcallargs *, CLIENT *); +extern rpcb_rmtcallres * rpcbproc_callit_3_svc(rpcb_rmtcallargs *, struct svc_req *); +#define RPCBPROC_GETTIME ((u_int32_t)6) +extern u_int * rpcbproc_gettime_3(void *, CLIENT *); +extern u_int * rpcbproc_gettime_3_svc(void *, struct svc_req *); +#define RPCBPROC_UADDR2TADDR ((u_int32_t)7) +extern struct netbuf * rpcbproc_uaddr2taddr_3(char **, CLIENT *); +extern struct netbuf * rpcbproc_uaddr2taddr_3_svc(char **, struct svc_req *); +#define RPCBPROC_TADDR2UADDR ((u_int32_t)8) +extern char ** rpcbproc_taddr2uaddr_3(struct netbuf *, CLIENT *); +extern char ** rpcbproc_taddr2uaddr_3_svc(struct netbuf *, struct svc_req *); + +#else /* Old Style C */ +#define RPCBPROC_SET ((u_int32_t)1) +extern bool_t * rpcbproc_set_3(); +extern bool_t * rpcbproc_set_3_svc(); +#define RPCBPROC_UNSET ((u_int32_t)2) +extern bool_t * rpcbproc_unset_3(); +extern bool_t * rpcbproc_unset_3_svc(); +#define RPCBPROC_GETADDR ((u_int32_t)3) +extern char ** rpcbproc_getaddr_3(); +extern char ** rpcbproc_getaddr_3_svc(); +#define RPCBPROC_DUMP ((u_int32_t)4) +extern rpcblist_ptr * rpcbproc_dump_3(); +extern rpcblist_ptr * rpcbproc_dump_3_svc(); +#define RPCBPROC_CALLIT ((u_int32_t)5) +extern rpcb_rmtcallres * rpcbproc_callit_3(); +extern rpcb_rmtcallres * rpcbproc_callit_3_svc(); +#define RPCBPROC_GETTIME ((u_int32_t)6) +extern u_int * rpcbproc_gettime_3(); +extern u_int * rpcbproc_gettime_3_svc(); +#define RPCBPROC_UADDR2TADDR ((u_int32_t)7) +extern struct netbuf * rpcbproc_uaddr2taddr_3(); +extern struct netbuf * rpcbproc_uaddr2taddr_3_svc(); +#define RPCBPROC_TADDR2UADDR ((u_int32_t)8) +extern char ** rpcbproc_taddr2uaddr_3(); +extern char ** rpcbproc_taddr2uaddr_3_svc(); +#endif /* Old Style C */ +#define RPCBVERS4 ((u_int32_t)4) + +#ifdef __cplusplus +extern "C" bool_t * rpcbproc_set_4(rpcb *, CLIENT *); +extern "C" bool_t * rpcbproc_set_4_svc(rpcb *, struct svc_req *); +extern "C" bool_t * rpcbproc_unset_4(rpcb *, CLIENT *); +extern "C" bool_t * rpcbproc_unset_4_svc(rpcb *, struct svc_req *); +extern "C" char ** rpcbproc_getaddr_4(rpcb *, CLIENT *); +extern "C" char ** rpcbproc_getaddr_4_svc(rpcb *, struct svc_req *); +extern "C" rpcblist_ptr * rpcbproc_dump_4(void *, CLIENT *); +extern "C" rpcblist_ptr * rpcbproc_dump_4_svc(void *, struct svc_req *); +#define RPCBPROC_BCAST ((u_int32_t)RPCBPROC_CALLIT) +extern "C" rpcb_rmtcallres * rpcbproc_bcast_4(rpcb_rmtcallargs *, CLIENT *); +extern "C" rpcb_rmtcallres * rpcbproc_bcast_4_svc(rpcb_rmtcallargs *, struct svc_req *); +extern "C" u_int * rpcbproc_gettime_4(void *, CLIENT *); +extern "C" u_int * rpcbproc_gettime_4_svc(void *, struct svc_req *); +extern "C" struct netbuf * rpcbproc_uaddr2taddr_4(char **, CLIENT *); +extern "C" struct netbuf * rpcbproc_uaddr2taddr_4_svc(char **, struct svc_req *); +extern "C" char ** rpcbproc_taddr2uaddr_4(struct netbuf *, CLIENT *); +extern "C" char ** rpcbproc_taddr2uaddr_4_svc(struct netbuf *, struct svc_req *); +#define RPCBPROC_GETVERSADDR ((u_int32_t)9) +extern "C" char ** rpcbproc_getversaddr_4(rpcb *, CLIENT *); +extern "C" char ** rpcbproc_getversaddr_4_svc(rpcb *, struct svc_req *); +#define RPCBPROC_INDIRECT ((u_int32_t)10) +extern "C" rpcb_rmtcallres * rpcbproc_indirect_4(rpcb_rmtcallargs *, CLIENT *); +extern "C" rpcb_rmtcallres * rpcbproc_indirect_4_svc(rpcb_rmtcallargs *, struct svc_req *); +#define RPCBPROC_GETADDRLIST ((u_int32_t)11) +extern "C" rpcb_entry_list_ptr * rpcbproc_getaddrlist_4(rpcb *, CLIENT *); +extern "C" rpcb_entry_list_ptr * rpcbproc_getaddrlist_4_svc(rpcb *, struct svc_req *); +#define RPCBPROC_GETSTAT ((u_int32_t)12) +extern "C" rpcb_stat * rpcbproc_getstat_4(void *, CLIENT *); +extern "C" rpcb_stat * rpcbproc_getstat_4_svc(void *, struct svc_req *); + +#elif __STDC__ +extern bool_t * rpcbproc_set_4(rpcb *, CLIENT *); +extern bool_t * rpcbproc_set_4_svc(rpcb *, struct svc_req *); +extern bool_t * rpcbproc_unset_4(rpcb *, CLIENT *); +extern bool_t * rpcbproc_unset_4_svc(rpcb *, struct svc_req *); +extern char ** rpcbproc_getaddr_4(rpcb *, CLIENT *); +extern char ** rpcbproc_getaddr_4_svc(rpcb *, struct svc_req *); +extern rpcblist_ptr * rpcbproc_dump_4(void *, CLIENT *); +extern rpcblist_ptr * rpcbproc_dump_4_svc(void *, struct svc_req *); +#define RPCBPROC_BCAST ((u_int32_t)RPCBPROC_CALLIT) +extern rpcb_rmtcallres * rpcbproc_bcast_4(rpcb_rmtcallargs *, CLIENT *); +extern rpcb_rmtcallres * rpcbproc_bcast_4_svc(rpcb_rmtcallargs *, struct svc_req *); +extern u_int * rpcbproc_gettime_4(void *, CLIENT *); +extern u_int * rpcbproc_gettime_4_svc(void *, struct svc_req *); +extern struct netbuf * rpcbproc_uaddr2taddr_4(char **, CLIENT *); +extern struct netbuf * rpcbproc_uaddr2taddr_4_svc(char **, struct svc_req *); +extern char ** rpcbproc_taddr2uaddr_4(struct netbuf *, CLIENT *); +extern char ** rpcbproc_taddr2uaddr_4_svc(struct netbuf *, struct svc_req *); +#define RPCBPROC_GETVERSADDR ((u_int32_t)9) +extern char ** rpcbproc_getversaddr_4(rpcb *, CLIENT *); +extern char ** rpcbproc_getversaddr_4_svc(rpcb *, struct svc_req *); +#define RPCBPROC_INDIRECT ((u_int32_t)10) +extern rpcb_rmtcallres * rpcbproc_indirect_4(rpcb_rmtcallargs *, CLIENT *); +extern rpcb_rmtcallres * rpcbproc_indirect_4_svc(rpcb_rmtcallargs *, struct svc_req *); +#define RPCBPROC_GETADDRLIST ((u_int32_t)11) +extern rpcb_entry_list_ptr * rpcbproc_getaddrlist_4(rpcb *, CLIENT *); +extern rpcb_entry_list_ptr * rpcbproc_getaddrlist_4_svc(rpcb *, struct svc_req *); +#define RPCBPROC_GETSTAT ((u_int32_t)12) +extern rpcb_stat * rpcbproc_getstat_4(void *, CLIENT *); +extern rpcb_stat * rpcbproc_getstat_4_svc(void *, struct svc_req *); + +#else /* Old Style C */ +extern bool_t * rpcbproc_set_4(); +extern bool_t * rpcbproc_set_4_svc(); +extern bool_t * rpcbproc_unset_4(); +extern bool_t * rpcbproc_unset_4_svc(); +extern char ** rpcbproc_getaddr_4(); +extern char ** rpcbproc_getaddr_4_svc(); +extern rpcblist_ptr * rpcbproc_dump_4(); +extern rpcblist_ptr * rpcbproc_dump_4_svc(); +#define RPCBPROC_BCAST ((u_int32_t)RPCBPROC_CALLIT) +extern rpcb_rmtcallres * rpcbproc_bcast_4(); +extern rpcb_rmtcallres * rpcbproc_bcast_4_svc(); +extern u_int * rpcbproc_gettime_4(); +extern u_int * rpcbproc_gettime_4_svc(); +extern struct netbuf * rpcbproc_uaddr2taddr_4(); +extern struct netbuf * rpcbproc_uaddr2taddr_4_svc(); +extern char ** rpcbproc_taddr2uaddr_4(); +extern char ** rpcbproc_taddr2uaddr_4_svc(); +#define RPCBPROC_GETVERSADDR ((u_int32_t)9) +extern char ** rpcbproc_getversaddr_4(); +extern char ** rpcbproc_getversaddr_4_svc(); +#define RPCBPROC_INDIRECT ((u_int32_t)10) +extern rpcb_rmtcallres * rpcbproc_indirect_4(); +extern rpcb_rmtcallres * rpcbproc_indirect_4_svc(); +#define RPCBPROC_GETADDRLIST ((u_int32_t)11) +extern rpcb_entry_list_ptr * rpcbproc_getaddrlist_4(); +extern rpcb_entry_list_ptr * rpcbproc_getaddrlist_4_svc(); +#define RPCBPROC_GETSTAT ((u_int32_t)12) +extern rpcb_stat * rpcbproc_getstat_4(); +extern rpcb_stat * rpcbproc_getstat_4_svc(); +#endif /* Old Style C */ + +#endif /* !_RPCB_PROT_H_RPCGEN */ diff --git a/libtirpc/tirpc/rpc/rpcb_prot.x b/libtirpc/tirpc/rpc/rpcb_prot.x new file mode 100644 index 0000000..b21ac3d --- /dev/null +++ b/libtirpc/tirpc/rpc/rpcb_prot.x @@ -0,0 +1,553 @@ +%/* +% * $FreeBSD: src/include/rpc/rpcb_prot.x,v 1.3 2002/03/13 10:29:06 obrien Exp $ +% * +% * Copyright (c) 2009, Sun Microsystems, Inc. +% * All rights reserved. +% * +% * Redistribution and use in source and binary forms, with or without +% * modification, are permitted provided that the following conditions are met: +% * - Redistributions of source code must retain the above copyright notice, +% * this list of conditions and the following disclaimer. +% * - Redistributions in binary form must reproduce the above copyright notice, +% * this list of conditions and the following disclaimer in the documentation +% * and/or other materials provided with the distribution. +% * - Neither the name of Sun Microsystems, Inc. nor the names of its +% * contributors may be used to endorse or promote products derived +% * from this software without specific prior written permission. +% * +% * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% * POSSIBILITY OF SUCH DAMAGE. +% */ +%/* +% * Copyright (c) 1988 by Sun Microsystems, Inc. +% */ + +%/* from rpcb_prot.x */ + +#ifdef RPC_HDR +% +%/* #pragma ident "@(#)rpcb_prot.x 1.5 94/04/29 SMI" */ +% +%#ifndef _KERNEL +% +#endif + +/* + * rpcb_prot.x + * rpcbind protocol, versions 3 and 4, in RPC Language + */ +% +%/* +% * The following procedures are supported by the protocol in version 3: +% * +% * RPCBPROC_NULL() returns () +% * takes nothing, returns nothing +% * +% * RPCBPROC_SET(rpcb) returns (bool_t) +% * TRUE is success, FALSE is failure. Registers the tuple +% * [prog, vers, address, owner, netid]. +% * Finds out owner and netid information on its own. +% * +% * RPCBPROC_UNSET(rpcb) returns (bool_t) +% * TRUE is success, FALSE is failure. Un-registers tuple +% * [prog, vers, netid]. addresses is ignored. +% * If netid is NULL, unregister all. +% * +% * RPCBPROC_GETADDR(rpcb) returns (string). +% * 0 is failure. Otherwise returns the universal address where the +% * triple [prog, vers, netid] is registered. Ignore address and owner. +% * +% * RPCBPROC_DUMP() RETURNS (rpcblist_ptr) +% * used to dump the entire rpcbind maps +% * +% * RPCBPROC_CALLIT(rpcb_rmtcallargs) +% * RETURNS (rpcb_rmtcallres); +% * Calls the procedure on the remote machine. If it is not registered, +% * this procedure is quiet; i.e. it does not return error information!!! +% * This routine only passes null authentication parameters. +% * It has no interface to xdr routines for RPCBPROC_CALLIT. +% * +% * RPCBPROC_GETTIME() returns (int). +% * Gets the remote machines time +% * +% * RPCBPROC_UADDR2TADDR(strint) RETURNS (struct netbuf) +% * Returns the netbuf address from universal address. +% * +% * RPCBPROC_TADDR2UADDR(struct netbuf) RETURNS (string) +% * Returns the universal address from netbuf address. +% * +% * END OF RPCBIND VERSION 3 PROCEDURES +% */ +%/* +% * Except for RPCBPROC_CALLIT, the procedures above are carried over to +% * rpcbind version 4. Those below are added or modified for version 4. +% * NOTE: RPCBPROC_BCAST HAS THE SAME FUNCTIONALITY AND PROCEDURE NUMBER +% * AS RPCBPROC_CALLIT. +% * +% * RPCBPROC_BCAST(rpcb_rmtcallargs) +% * RETURNS (rpcb_rmtcallres); +% * Calls the procedure on the remote machine. If it is not registered, +% * this procedure IS quiet; i.e. it DOES NOT return error information!!! +% * This routine should be used for broadcasting and nothing else. +% * +% * RPCBPROC_GETVERSADDR(rpcb) returns (string). +% * 0 is failure. Otherwise returns the universal address where the +% * triple [prog, vers, netid] is registered. Ignore address and owner. +% * Same as RPCBPROC_GETADDR except that if the given version number +% * is not available, the address is not returned. +% * +% * RPCBPROC_INDIRECT(rpcb_rmtcallargs) +% * RETURNS (rpcb_rmtcallres); +% * Calls the procedure on the remote machine. If it is not registered, +% * this procedure is NOT quiet; i.e. it DOES return error information!!! +% * as any normal application would expect. +% * +% * RPCBPROC_GETADDRLIST(rpcb) returns (rpcb_entry_list_ptr). +% * Same as RPCBPROC_GETADDR except that it returns a list of all the +% * addresses registered for the combination (prog, vers) (for all +% * transports). +% * +% * RPCBPROC_GETSTAT(void) returns (rpcb_stat_byvers) +% * Returns the statistics about the kind of requests received by rpcbind. +% */ +% +%/* +% * A mapping of (program, version, network ID) to address +% */ +struct rpcb { + rpcprog_t r_prog; /* program number */ + rpcvers_t r_vers; /* version number */ + string r_netid<>; /* network id */ + string r_addr<>; /* universal address */ + string r_owner<>; /* owner of this service */ +}; +#ifdef RPC_HDR +% +%typedef rpcb RPCB; +% +#endif +% +%/* +% * A list of mappings +% * +% * Below are two definitions for the rpcblist structure. This is done because +% * xdr_rpcblist() is specified to take a struct rpcblist **, rather than a +% * struct rpcblist * that rpcgen would produce. One version of the rpcblist +% * structure (actually called rp__list) is used with rpcgen, and the other is +% * defined only in the header file for compatibility with the specified +% * interface. +% */ + +struct rp__list { + rpcb rpcb_map; + struct rp__list *rpcb_next; +}; + +typedef rp__list *rpcblist_ptr; /* results of RPCBPROC_DUMP */ + +#ifdef RPC_HDR +% +%typedef struct rp__list rpcblist; +%typedef struct rp__list RPCBLIST; +% +%#ifndef __cplusplus +%struct rpcblist { +% RPCB rpcb_map; +% struct rpcblist *rpcb_next; +%}; +%#endif +% +%#ifdef __cplusplus +%extern "C" { +%#endif +%extern bool_t xdr_rpcblist(XDR *, rpcblist**); +%#ifdef __cplusplus +%} +%#endif +% +#endif + +% +%/* +% * Arguments of remote calls +% */ +struct rpcb_rmtcallargs { + rpcprog_t prog; /* program number */ + rpcvers_t vers; /* version number */ + rpcproc_t proc; /* procedure number */ + opaque args<>; /* argument */ +}; +#ifdef RPC_HDR +% +%/* +% * Client-side only representation of rpcb_rmtcallargs structure. +% * +% * The routine that XDRs the rpcb_rmtcallargs structure must deal with the +% * opaque arguments in the "args" structure. xdr_rpcb_rmtcallargs() needs to +% * be passed the XDR routine that knows the args' structure. This routine +% * doesn't need to go over-the-wire (and it wouldn't make sense anyway) since +% * the application being called already knows the args structure. So we use a +% * different "XDR" structure on the client side, r_rpcb_rmtcallargs, which +% * includes the args' XDR routine. +% */ +%struct r_rpcb_rmtcallargs { +% rpcprog_t prog; +% rpcvers_t vers; +% rpcproc_t proc; +% struct { +% u_int args_len; +% char *args_val; +% } args; +% xdrproc_t xdr_args; /* encodes args */ +%}; +% +#endif /* def RPC_HDR */ +% +%/* +% * Results of the remote call +% */ +struct rpcb_rmtcallres { + string addr<>; /* remote universal address */ + opaque results<>; /* result */ +}; +#ifdef RPC_HDR +% +%/* +% * Client-side only representation of rpcb_rmtcallres structure. +% */ +%struct r_rpcb_rmtcallres { +% char *addr; +% struct { +% u_int32_t results_len; +% char *results_val; +% } results; +% xdrproc_t xdr_res; /* decodes results */ +%}; +#endif /* RPC_HDR */ +% +%/* +% * rpcb_entry contains a merged address of a service on a particular +% * transport, plus associated netconfig information. A list of rpcb_entrys +% * is returned by RPCBPROC_GETADDRLIST. See netconfig.h for values used +% * in r_nc_* fields. +% */ +struct rpcb_entry { + string r_maddr<>; /* merged address of service */ + string r_nc_netid<>; /* netid field */ + unsigned int r_nc_semantics; /* semantics of transport */ + string r_nc_protofmly<>; /* protocol family */ + string r_nc_proto<>; /* protocol name */ +}; +% +%/* +% * A list of addresses supported by a service. +% */ +struct rpcb_entry_list { + rpcb_entry rpcb_entry_map; + struct rpcb_entry_list *rpcb_entry_next; +}; + +typedef rpcb_entry_list *rpcb_entry_list_ptr; + +% +%/* +% * rpcbind statistics +% */ +% +const rpcb_highproc_2 = RPCBPROC_CALLIT; +const rpcb_highproc_3 = RPCBPROC_TADDR2UADDR; +const rpcb_highproc_4 = RPCBPROC_GETSTAT; + +const RPCBSTAT_HIGHPROC = 13; /* # of procs in rpcbind V4 plus one */ +const RPCBVERS_STAT = 3; /* provide only for rpcbind V2, V3 and V4 */ +const RPCBVERS_4_STAT = 2; +const RPCBVERS_3_STAT = 1; +const RPCBVERS_2_STAT = 0; +% +%/* Link list of all the stats about getport and getaddr */ +struct rpcbs_addrlist { + rpcprog_t prog; + rpcvers_t vers; + int success; + int failure; + string netid<>; + struct rpcbs_addrlist *next; +}; +% +%/* Link list of all the stats about rmtcall */ +struct rpcbs_rmtcalllist { + rpcprog_t prog; + rpcvers_t vers; + rpcproc_t proc; + int success; + int failure; + int indirect; /* whether callit or indirect */ + string netid<>; + struct rpcbs_rmtcalllist *next; +}; + +typedef int rpcbs_proc[RPCBSTAT_HIGHPROC]; +typedef rpcbs_addrlist *rpcbs_addrlist_ptr; +typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr; + +struct rpcb_stat { + rpcbs_proc info; + int setinfo; + int unsetinfo; + rpcbs_addrlist_ptr addrinfo; + rpcbs_rmtcalllist_ptr rmtinfo; +}; +% +%/* +% * One rpcb_stat structure is returned for each version of rpcbind +% * being monitored. +% */ + +typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT]; + +#ifdef RPC_HDR +% +%/* +% * We don't define netbuf in RPCL, since it would contain structure member +% * names that would conflict with the definition of struct netbuf in +% * . Instead we merely declare the XDR routine xdr_netbuf() here, +% * and implement it ourselves in rpc/rpcb_prot.c. +% */ +%#ifdef __cplusplus +%extern "C" bool_t xdr_netbuf(XDR *, struct netbuf *); +% +%#else /* __STDC__ */ +%extern bool_t xdr_netbuf(XDR *, struct netbuf *); +% +%#endif +#endif /* def RPC_HDR */ + +/* + * rpcbind procedures + */ +program RPCBPROG { + version RPCBVERS { + bool + RPCBPROC_SET(rpcb) = 1; + + bool + RPCBPROC_UNSET(rpcb) = 2; + + string + RPCBPROC_GETADDR(rpcb) = 3; + + rpcblist_ptr + RPCBPROC_DUMP(void) = 4; + + rpcb_rmtcallres + RPCBPROC_CALLIT(rpcb_rmtcallargs) = 5; + + unsigned int + RPCBPROC_GETTIME(void) = 6; + + struct netbuf + RPCBPROC_UADDR2TADDR(string) = 7; + + string + RPCBPROC_TADDR2UADDR(struct netbuf) = 8; + } = 3; + + version RPCBVERS4 { + bool + RPCBPROC_SET(rpcb) = 1; + + bool + RPCBPROC_UNSET(rpcb) = 2; + + string + RPCBPROC_GETADDR(rpcb) = 3; + + rpcblist_ptr + RPCBPROC_DUMP(void) = 4; + + /* + * NOTE: RPCBPROC_BCAST has the same functionality as CALLIT; + * the new name is intended to indicate that this + * procedure should be used for broadcast RPC, and + * RPCBPROC_INDIRECT should be used for indirect calls. + */ + rpcb_rmtcallres + RPCBPROC_BCAST(rpcb_rmtcallargs) = RPCBPROC_CALLIT; + + unsigned int + RPCBPROC_GETTIME(void) = 6; + + struct netbuf + RPCBPROC_UADDR2TADDR(string) = 7; + + string + RPCBPROC_TADDR2UADDR(struct netbuf) = 8; + + string + RPCBPROC_GETVERSADDR(rpcb) = 9; + + rpcb_rmtcallres + RPCBPROC_INDIRECT(rpcb_rmtcallargs) = 10; + + rpcb_entry_list_ptr + RPCBPROC_GETADDRLIST(rpcb) = 11; + + rpcb_stat_byvers + RPCBPROC_GETSTAT(void) = 12; + } = 4; +} = 100000; +#ifdef RPC_HDR +% +%#define RPCBVERS_3 RPCBVERS +%#define RPCBVERS_4 RPCBVERS4 +% +%#define _PATH_RPCBINDSOCK "/var/run/rpcbind.sock" +% +%#else /* ndef _KERNEL */ +%#ifdef __cplusplus +%extern "C" { +%#endif +% +%/* +% * A mapping of (program, version, network ID) to address +% */ +%struct rpcb { +% rpcprog_t r_prog; /* program number */ +% rpcvers_t r_vers; /* version number */ +% char *r_netid; /* network id */ +% char *r_addr; /* universal address */ +% char *r_owner; /* owner of the mapping */ +%}; +%typedef struct rpcb RPCB; +% +%/* +% * A list of mappings +% */ +%struct rpcblist { +% RPCB rpcb_map; +% struct rpcblist *rpcb_next; +%}; +%typedef struct rpcblist RPCBLIST; +%typedef struct rpcblist *rpcblist_ptr; +% +%/* +% * Remote calls arguments +% */ +%struct rpcb_rmtcallargs { +% rpcprog_t prog; /* program number */ +% rpcvers_t vers; /* version number */ +% rpcproc_t proc; /* procedure number */ +% u_int32_t arglen; /* arg len */ +% caddr_t args_ptr; /* argument */ +% xdrproc_t xdr_args; /* XDR routine for argument */ +%}; +%typedef struct rpcb_rmtcallargs rpcb_rmtcallargs; +% +%/* +% * Remote calls results +% */ +%struct rpcb_rmtcallres { +% char *addr_ptr; /* remote universal address */ +% u_int32_t resultslen; /* results length */ +% caddr_t results_ptr; /* results */ +% xdrproc_t xdr_results; /* XDR routine for result */ +%}; +%typedef struct rpcb_rmtcallres rpcb_rmtcallres; +% +%struct rpcb_entry { +% char *r_maddr; +% char *r_nc_netid; +% unsigned int r_nc_semantics; +% char *r_nc_protofmly; +% char *r_nc_proto; +%}; +%typedef struct rpcb_entry rpcb_entry; +% +%/* +% * A list of addresses supported by a service. +% */ +% +%struct rpcb_entry_list { +% rpcb_entry rpcb_entry_map; +% struct rpcb_entry_list *rpcb_entry_next; +%}; +%typedef struct rpcb_entry_list rpcb_entry_list; +% +%typedef rpcb_entry_list *rpcb_entry_list_ptr; +% +%/* +% * rpcbind statistics +% */ +% +%#define rpcb_highproc_2 RPCBPROC_CALLIT +%#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR +%#define rpcb_highproc_4 RPCBPROC_GETSTAT +%#define RPCBSTAT_HIGHPROC 13 +%#define RPCBVERS_STAT 3 +%#define RPCBVERS_4_STAT 2 +%#define RPCBVERS_3_STAT 1 +%#define RPCBVERS_2_STAT 0 +% +%/* Link list of all the stats about getport and getaddr */ +% +%struct rpcbs_addrlist { +% rpcprog_t prog; +% rpcvers_t vers; +% int success; +% int failure; +% char *netid; +% struct rpcbs_addrlist *next; +%}; +%typedef struct rpcbs_addrlist rpcbs_addrlist; +% +%/* Link list of all the stats about rmtcall */ +% +%struct rpcbs_rmtcalllist { +% rpcprog_t prog; +% rpcvers_t vers; +% rpcproc_t proc; +% int success; +% int failure; +% int indirect; +% char *netid; +% struct rpcbs_rmtcalllist *next; +%}; +%typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist; +% +%typedef int rpcbs_proc[RPCBSTAT_HIGHPROC]; +% +%typedef rpcbs_addrlist *rpcbs_addrlist_ptr; +% +%typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr; +% +%struct rpcb_stat { +% rpcbs_proc info; +% int setinfo; +% int unsetinfo; +% rpcbs_addrlist_ptr addrinfo; +% rpcbs_rmtcalllist_ptr rmtinfo; +%}; +%typedef struct rpcb_stat rpcb_stat; +% +%/* +% * One rpcb_stat structure is returned for each version of rpcbind +% * being monitored. +% */ +% +%typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT]; +% +%#ifdef __cplusplus +%} +%#endif +% +%#endif /* ndef _KERNEL */ +#endif /* RPC_HDR */ diff --git a/libtirpc/tirpc/rpc/rpcent.h b/libtirpc/tirpc/rpc/rpcent.h new file mode 100644 index 0000000..b47eedb --- /dev/null +++ b/libtirpc/tirpc/rpc/rpcent.h @@ -0,0 +1,68 @@ +/* $NetBSD: rpcent.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/rpcent.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * rpcent.h, + * For converting rpc program numbers to names etc. + * + */ + +#ifndef _RPC_RPCENT_H +#define _RPC_RPCENT_H + +/* #pragma ident "@(#)rpcent.h 1.13 94/04/25 SMI" */ +/* @(#)rpcent.h 1.1 88/12/06 SMI */ + + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +__BEGIN_DECLS +//extern struct rpcent *getrpcbyname_r(const char *, struct rpcent *, +// char *, int); +//extern struct rpcent *getrpcbynumber_r(int, struct rpcent *, char *, int); +//extern struct rpcent *getrpcent_r(struct rpcent *, char *, int); + +/* Old interfaces that return a pointer to a static area; MT-unsafe */ +//extern struct rpcent *getrpcbyname(char *); +//extern struct rpcent *getrpcbynumber(int); +//extern struct rpcent *getrpcent(void); +extern void setrpcent(int) __THROW; +extern void endrpcent(void) __THROW; +__END_DECLS + +#endif /* !_RPC_CENT_H */ diff --git a/libtirpc/tirpc/rpc/svc.h b/libtirpc/tirpc/rpc/svc.h new file mode 100644 index 0000000..a919c50 --- /dev/null +++ b/libtirpc/tirpc/rpc/svc.h @@ -0,0 +1,438 @@ +/* $NetBSD: svc.h,v 1.17 2000/06/02 22:57:56 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)svc.h 1.35 88/12/17 SMI + * from: @(#)svc.h 1.27 94/04/25 SMI + * $FreeBSD: src/include/rpc/svc.h,v 1.24 2003/06/15 10:32:01 mbr Exp $ + */ + +/* + * svc.h, Server-side remote procedure call interface. + * + * Copyright (C) 1986-1993 by Sun Microsystems, Inc. + */ + +#ifndef _TIRPC_SVC_H +#define _TIRPC_SVC_H +//#include + +/* + * This interface must manage two items concerning remote procedure calling: + * + * 1) An arbitrary number of transport connections upon which rpc requests + * are received. The two most notable transports are TCP and UDP; they are + * created and registered by routines in svc_tcp.c and svc_udp.c, respectively; + * they in turn call xprt_register and xprt_unregister. + * + * 2) An arbitrary number of locally registered services. Services are + * described by the following four data: program number, version number, + * "service dispatch" function, a transport handle, and a boolean that + * indicates whether or not the exported program should be registered with a + * local binder service; if true the program's number and version and the + * port number from the transport handle are registered with the binder. + * These data are registered with the rpc svc system via svc_register. + * + * A service's dispatch function is called whenever an rpc request comes in + * on a transport. The request's program and version numbers must match + * those of the registered service. The dispatch function is passed two + * parameters, struct svc_req * and SVCXPRT *, defined below. + */ + +/* + * Service control requests + */ +#define SVCGET_VERSQUIET 1 +#define SVCSET_VERSQUIET 2 +#define SVCGET_CONNMAXREC 3 +#define SVCSET_CONNMAXREC 4 + +/* + * Operations for rpc_control(). + */ +#define RPC_SVC_CONNMAXREC_SET 0 /* set max rec size, enable nonblock */ +#define RPC_SVC_CONNMAXREC_GET 1 + +enum xprt_stat { + XPRT_DIED, + XPRT_MOREREQS, + XPRT_IDLE +}; + +/* + * Server side transport handle + */ +typedef struct __rpc_svcxprt { + SOCKET xp_fd; + u_short xp_port; /* associated port number */ + const struct xp_ops { + /* receive incoming requests */ + bool_t (*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *); + /* get transport status */ + enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *); + /* get arguments */ + bool_t (*xp_getargs)(struct __rpc_svcxprt *, xdrproc_t, + void *); + /* send reply */ + bool_t (*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *); + /* free mem allocated for args */ + bool_t (*xp_freeargs)(struct __rpc_svcxprt *, xdrproc_t, + void *); + /* destroy this struct */ + void (*xp_destroy)(struct __rpc_svcxprt *); + } *xp_ops; + int xp_addrlen; /* length of remote address */ + struct sockaddr_in6 xp_raddr; /* remote addr. (backward ABI compat) */ + /* XXX - fvdl stick this here for ABI backward compat reasons */ + const struct xp_ops2 { + /* catch-all function */ + bool_t (*xp_control)(struct __rpc_svcxprt *, const u_int, + void *); + } *xp_ops2; + char *xp_tp; /* transport provider device name */ + char *xp_netid; /* network token */ + struct netbuf xp_ltaddr; /* local transport address */ + struct netbuf xp_rtaddr; /* remote transport address */ + struct opaque_auth xp_verf; /* raw response verifier */ + SVCAUTH *xp_auth; /* auth handle of current req */ + void *xp_p1; /* private: for use by svc ops */ + void *xp_p2; /* private: for use by svc ops */ + void *xp_p3; /* private: for use by svc lib */ + int xp_type; /* transport type */ +} SVCXPRT; + +/* + * Service request + */ +struct svc_req { + /* ORDER: compatibility with legacy RPC */ + u_int32_t rq_prog; /* service program number */ + u_int32_t rq_vers; /* service protocol version */ + u_int32_t rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + void *rq_clntcred; /* read only cooked cred */ + SVCXPRT *rq_xprt; /* associated transport */ + + /* New with TI-RPC */ + caddr_t rq_clntname; /* read only client name */ + caddr_t rq_svcname; /* read only cooked service cred */ +}; + +/* + * Approved way of getting address of caller + */ +#define svc_getrpccaller(x) (&(x)->xp_rtaddr) + +/* + * Operations defined on an SVCXPRT handle + * + * SVCXPRT *xprt; + * struct rpc_msg *msg; + * xdrproc_t xargs; + * void * argsp; + */ +#define SVC_RECV(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) +#define svc_recv(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) + +#define SVC_STAT(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) +#define svc_stat(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) + +#define SVC_GETARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) +#define svc_getargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) + +#define SVC_REPLY(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) +#define svc_reply(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) + +#define SVC_FREEARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) +#define svc_freeargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) + +#define SVC_DESTROY(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) +#define svc_destroy(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) + +#define SVC_CONTROL(xprt, rq, in) \ + (*(xprt)->xp_ops2->xp_control)((xprt), (rq), (in)) + +/* + * Service registration + * + * svc_reg(xprt, prog, vers, dispatch, nconf) + * const SVCXPRT *xprt; + * const rpcprog_t prog; + * const rpcvers_t vers; + * const void (*dispatch)(); + * const struct netconfig *nconf; + */ + +__BEGIN_DECLS +extern bool_t svc_reg(SVCXPRT *, const rpcprog_t, const rpcvers_t, + void (*)(struct svc_req *, SVCXPRT *), + const struct netconfig *); +__END_DECLS + +/* + * Service un-registration + * + * svc_unreg(prog, vers) + * const rpcprog_t prog; + * const rpcvers_t vers; + */ + +__BEGIN_DECLS +extern void svc_unreg(const rpcprog_t, const rpcvers_t); +__END_DECLS + +/* + * Transport registration. + * + * xprt_register(xprt) + * SVCXPRT *xprt; + */ +__BEGIN_DECLS +extern void xprt_register(SVCXPRT *); +__END_DECLS + +/* + * Transport un-register + * + * xprt_unregister(xprt) + * SVCXPRT *xprt; + */ +__BEGIN_DECLS +extern void xprt_unregister(SVCXPRT *); +__END_DECLS + + +/* + * When the service routine is called, it must first check to see if it + * knows about the procedure; if not, it should call svcerr_noproc + * and return. If so, it should deserialize its arguments via + * SVC_GETARGS (defined above). If the deserialization does not work, + * svcerr_decode should be called followed by a return. Successful + * decoding of the arguments should be followed the execution of the + * procedure's code and a call to svc_sendreply. + * + * Also, if the service refuses to execute the procedure due to too- + * weak authentication parameters, svcerr_weakauth should be called. + * Note: do not confuse access-control failure with weak authentication! + * + * NB: In pure implementations of rpc, the caller always waits for a reply + * msg. This message is sent when svc_sendreply is called. + * Therefore pure service implementations should always call + * svc_sendreply even if the function logically returns void; use + * xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows + * for the abuse of pure rpc via batched calling or pipelining. In the + * case of a batched call, svc_sendreply should NOT be called since + * this would send a return message, which is what batching tries to avoid. + * It is the service/protocol writer's responsibility to know which calls are + * batched and which are not. Warning: responding to batch calls may + * deadlock the caller and server processes! + */ + +__BEGIN_DECLS +extern bool_t svc_sendreply(SVCXPRT *, xdrproc_t, void *); +extern void svcerr_decode(SVCXPRT *); +extern void svcerr_weakauth(SVCXPRT *); +extern void svcerr_noproc(SVCXPRT *); +extern void svcerr_progvers(SVCXPRT *, rpcvers_t, rpcvers_t); +extern void svcerr_auth(SVCXPRT *, enum auth_stat); +extern void svcerr_noprog(SVCXPRT *); +extern void svcerr_systemerr(SVCXPRT *); +extern int rpc_reg(rpcprog_t, rpcvers_t, rpcproc_t, + char *(*)(char *), xdrproc_t, xdrproc_t, + char *); +__END_DECLS + +/* + * Lowest level dispatching -OR- who owns this process anyway. + * Somebody has to wait for incoming requests and then call the correct + * service routine. The routine svc_run does infinite waiting; i.e., + * svc_run never returns. + * Since another (co-existant) package may wish to selectively wait for + * incoming calls or other events outside of the rpc architecture, the + * routine svc_getreq is provided. It must be passed readfds, the + * "in-place" results of a select system call (see select, section 2). + */ + +/* + * Global keeper of rpc service descriptors in use + * dynamic; must be inspected before each call to select + */ +extern int svc_maxfd; +#ifdef FD_SETSIZE +extern fd_set svc_fdset; +#define svc_fds svc_fdset.fds_bits[0] /* compatibility */ +#else +extern int svc_fds; +#endif /* def FD_SETSIZE */ + +/* + * a small program implemented by the svc_rpc implementation itself; + * also see clnt.h for protocol numbers. + */ +__BEGIN_DECLS +extern void rpctest_service(void); +__END_DECLS + +__BEGIN_DECLS +extern void svc_getreq(int); +extern void svc_getreqset(fd_set *); +extern void svc_getreq_common(SOCKET); +struct pollfd; +extern void svc_getreq_poll(struct pollfd *, int); + +extern void svc_run(void); +extern void svc_exit(void); +__END_DECLS + +/* + * Socket to use on svcxxx_create call to get default socket + */ +#define RPC_ANYSOCK INVALID_SOCKET /* -1 */ +#define RPC_ANYFD RPC_ANYSOCK + +/* + * These are the existing service side transport implementations + */ + +__BEGIN_DECLS +/* + * Transport independent svc_create routine. + */ +extern int svc_create(void (*)(struct svc_req *, SVCXPRT *), + const rpcprog_t, const rpcvers_t, const char *); +/* + * void (*dispatch)(); -- dispatch routine + * const rpcprog_t prognum; -- program number + * const rpcvers_t versnum; -- version number + * const char *nettype; -- network type + */ + + +/* + * Generic server creation routine. It takes a netconfig structure + * instead of a nettype. + */ + +extern SVCXPRT *svc_tp_create(void (*)(struct svc_req *, SVCXPRT *), + const rpcprog_t, const rpcvers_t, + const struct netconfig *); + /* + * void (*dispatch)(); -- dispatch routine + * const rpcprog_t prognum; -- program number + * const rpcvers_t versnum; -- version number + * const struct netconfig *nconf; -- netconfig structure + */ + + +/* + * Generic TLI create routine + */ +extern SVCXPRT *svc_tli_create(const SOCKET, const struct netconfig *, + const struct t_bind *, const u_int, + const u_int); +/* + * const SOCKET fd; -- connection end point + * const struct netconfig *nconf; -- netconfig structure for network + * const struct t_bind *bindaddr; -- local bind address + * const u_int sendsz; -- max sendsize + * const u_int recvsz; -- max recvsize + */ + +/* + * Connectionless and connectionful create routines + */ + +extern SVCXPRT *svc_vc_create(const SOCKET, const u_int, const u_int); +/* + * const SOCKET fd; -- open connection end point + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + +/* + * Added for compatibility to old rpc 4.0. Obsoleted by svc_vc_create(). + */ +extern SVCXPRT *svcunix_create(int, u_int, u_int, char *); + +extern SVCXPRT *svc_dg_create(const SOCKET, const u_int, const u_int); + /* + * const SOCKET fd; -- open connection + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + + +/* + * the routine takes any *open* connection + * descriptor as its first input and is used for open connections. + */ +extern SVCXPRT *svc_fd_create(const SOCKET, const u_int, const u_int); +/* + * const SOCKET fd; -- open connection end point + * const u_int sendsize; -- max send size + * const u_int recvsize; -- max recv size + */ + +/* + * Added for compatibility to old rpc 4.0. Obsoleted by svc_fd_create(). + */ +extern SVCXPRT *svcunixfd_create(int, u_int, u_int); + +/* + * Memory based rpc (for speed check and testing) + */ +extern SVCXPRT *svc_raw_create(void); + +/* + * svc_dg_enable_cache() enables the cache on dg transports. + */ +int svc_dg_enablecache(SVCXPRT *, const u_int); + +int __rpc_get_local_uid(SVCXPRT *_transp, uid_t *_uid); + +__END_DECLS + + +/* for backward compatibility */ +#include + + + +#endif /* !_TIRPC_SVC_H */ diff --git a/libtirpc/tirpc/rpc/svc_auth.h b/libtirpc/tirpc/rpc/svc_auth.h new file mode 100644 index 0000000..e790a54 --- /dev/null +++ b/libtirpc/tirpc/rpc/svc_auth.h @@ -0,0 +1,69 @@ +/* $NetBSD: svc_auth.h,v 1.8 2000/06/02 22:57:57 fvdl Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)svc_auth.h 1.6 86/07/16 SMI + * @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/svc_auth.h,v 1.14 2002/03/23 17:24:55 imp Exp $ + */ + +/* + * svc_auth.h, Service side of rpc authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_SVC_AUTH_H +#define _RPC_SVC_AUTH_H + +/* + * Interface to server-side authentication flavors. + */ +typedef struct __svcauth { + struct svc_auth_ops { + int (*svc_ah_wrap)(struct __svcauth *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr); + int (*svc_ah_unwrap)(struct __svcauth *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr); + int (*svc_ah_destroy)(struct __svcauth *auth); + } *svc_ah_ops; + caddr_t svc_ah_private; +} SVCAUTH; + +#define SVCAUTH_DESTROY(cred) ((*(cred)->svc_ah_ops->svc_ah_destroy)()) +#define svcauth_destroy(cred) ((*(cred)->svc_ah_ops->svc_ah_destroy)()) + +/* + * Server side authenticator + */ +__BEGIN_DECLS +extern enum auth_stat _authenticate(struct svc_req *, struct rpc_msg *); +extern int svc_auth_reg(int, enum auth_stat (*)(struct svc_req *, + struct rpc_msg *)); + +__END_DECLS + +#endif /* !_RPC_SVC_AUTH_H */ diff --git a/libtirpc/tirpc/rpc/svc_dg.h b/libtirpc/tirpc/rpc/svc_dg.h new file mode 100644 index 0000000..aef8e8b --- /dev/null +++ b/libtirpc/tirpc/rpc/svc_dg.h @@ -0,0 +1,50 @@ +/* $NetBSD: svc_dg.h,v 1.1 2000/06/02 23:11:16 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/svc_dg.h,v 1.1 2001/03/19 12:49:47 alfred Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * XXX - this file exists only so that the rpcbind code can pull it in. + * This should go away. It should only be include by svc_dg.c and + * rpcb_svc_com.c in the rpcbind code. + */ + +/* + * kept in xprt->xp_p2 + */ +struct svc_dg_data { + /* XXX: optbuf should be the first field, used by ti_opts.c code */ + size_t su_iosz; /* size of send.recv buffer */ + u_int32_t su_xid; /* transaction id */ + XDR su_xdrs; /* XDR handle */ + char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ + void *su_cache; /* cached data, NULL if none */ +}; + +#define __rpcb_get_dg_xidp(x) (&((struct svc_dg_data *)(x)->xp_p2)->su_xid) diff --git a/libtirpc/tirpc/rpc/svc_soc.h b/libtirpc/tirpc/rpc/svc_soc.h new file mode 100644 index 0000000..d21f1ab --- /dev/null +++ b/libtirpc/tirpc/rpc/svc_soc.h @@ -0,0 +1,119 @@ +/* $NetBSD: svc_soc.h,v 1.1 2000/06/02 22:57:57 fvdl Exp $ */ +/* $FreeBSD: src/include/rpc/svc_soc.h,v 1.2 2002/03/23 17:24:55 imp Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * svc.h, Server-side remote procedure call interface. + */ + +#ifndef _RPC_SVC_SOC_H +#define _RPC_SVC_SOC_H +//#include + +/* #pragma ident "@(#)svc_soc.h 1.11 94/04/25 SMI" */ +/* svc_soc.h 1.8 89/05/01 SMI */ + +/* + * All the following declarations are only for backward compatibility + * with TS-RPC + */ + +/* + * Approved way of getting address of caller + */ +#define svc_getcaller(x) (&(x)->xp_raddr) +/* Getting address of a caller using netbuf xp_rtaddr */ +#define svc_getcaller_netbuf(x) (&(x)->xp_rtaddr) +/* + * Service registration + * + * svc_register(xprt, prog, vers, dispatch, protocol) + * SVCXPRT *xprt; + * u_long prog; + * u_long vers; + * void (*dispatch)(); + * int protocol; like TCP or UDP, zero means do not register + */ +__BEGIN_DECLS +extern bool_t svc_register(SVCXPRT *, u_long, u_long, + void (*)(struct svc_req *, SVCXPRT *), int); +__END_DECLS + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + * u_long prog; + * u_long vers; + */ +__BEGIN_DECLS +extern void svc_unregister(u_long, u_long); +__END_DECLS + + +/* + * Memory based rpc for testing and timing. + */ +__BEGIN_DECLS +extern SVCXPRT *svcraw_create(void); +__END_DECLS + + +/* + * Udp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcudp_create(int); +extern SVCXPRT *svcudp_bufcreate(int, u_int, u_int); +extern int svcudp_enablecache(SVCXPRT *, u_long); +extern SVCXPRT *svcudp6_create(int); +extern SVCXPRT *svcudp6_bufcreate(int, u_int, u_int); +__END_DECLS + + +/* + * Tcp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svctcp_create(int, u_int, u_int); +extern SVCXPRT *svctcp6_create(int, u_int, u_int); +__END_DECLS + +/* + * Fd based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcfd_create(int, u_int, u_int); +__END_DECLS + +#endif /* !_RPC_SVC_SOC_H */ diff --git a/libtirpc/tirpc/rpc/types.h b/libtirpc/tirpc/rpc/types.h new file mode 100644 index 0000000..65a9a55 --- /dev/null +++ b/libtirpc/tirpc/rpc/types.h @@ -0,0 +1,138 @@ +/* $NetBSD: types.h,v 1.13 2000/06/13 01:02:44 thorpej Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)types.h 1.18 87/07/24 SMI + * from: @(#)types.h 2.3 88/08/15 4.0 RPCSRC + * $FreeBSD: src/include/rpc/types.h,v 1.10.6.1 2003/12/18 00:59:50 peter Exp $ + */ + +/* + * Rpc additions to + */ +#ifndef _TIRPC_TYPES_H +#define _TIRPC_TYPES_H + +#include +//#include + +// Windows mappings of data types +// Fixed size things +typedef INT16 int16_t; +typedef INT32 int32_t; +typedef INT64 int64_t; +typedef UINT16 u_int16_t; +typedef UINT32 u_int32_t; +typedef UINT32 uint32_t; +typedef UINT64 u_int64_t; +typedef UINT64 uint64_t; +typedef PCHAR caddr_t; +// Scalable things +typedef UCHAR u_char; +typedef unsigned short u_short; +typedef UINT32 u_int; +typedef UINT32 uint; + +typedef INT64 quad_t; +typedef UINT64 u_quad_t; + +typedef UINT uid_t; +typedef UINT gid_t; +typedef DWORD pid_t; + +//typedef SIZE_T size_t; //This is causing a "benign redefinition error" +typedef SSIZE_T ssize_t; +// End of Windows... + +typedef int32_t bool_t; +typedef int32_t enum_t; + +typedef u_int32_t rpcprog_t; +typedef u_int32_t rpcvers_t; +typedef u_int32_t rpcproc_t; +typedef u_int32_t rpcprot_t; +typedef u_int32_t rpcport_t; +typedef int32_t rpc_inline_t; + +#ifndef NULL +# define NULL 0 +#endif +#define __dontcare__ -1 + +#ifndef FALSE +# define FALSE (0) +#endif +#ifndef TRUE +# define TRUE (1) +#endif + +#define mem_alloc(bsize) calloc(1, bsize) +#define mem_free(ptr, bsize) free(ptr) + +//#include +//#include +#include +#include + +/* + * The netbuf structure is defined here, because FreeBSD / NetBSD only use + * it inside the RPC code. It's in on SVR4, but it would be confusing + * to have an xti.h, since FreeBSD / NetBSD does not support XTI/TLI. + */ + +/* + * The netbuf structure is used for transport-independent address storage. + */ +struct netbuf { + unsigned int maxlen; + unsigned int len; + void *buf; +}; + +/* + * The format of the addres and options arguments of the XTI t_bind call. + * Only provided for compatibility, it should not be used. + */ + +struct t_bind { + struct netbuf addr; + unsigned int qlen; +}; + +/* + * Internal library and rpcbind use. This is not an exported interface, do + * not use. + */ +struct __rpc_sockinfo { + ADDRESS_FAMILY si_af; + int si_proto; + int si_socktype; + int si_alen; +}; + +#endif /* _TIRPC_TYPES_H */ diff --git a/libtirpc/tirpc/rpc/xdr.h b/libtirpc/tirpc/rpc/xdr.h new file mode 100644 index 0000000..9c3e5e1 --- /dev/null +++ b/libtirpc/tirpc/rpc/xdr.h @@ -0,0 +1,367 @@ +/* $NetBSD: xdr.h,v 1.19 2000/07/17 05:00:45 matt Exp $ */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)xdr.h 1.19 87/04/22 SMI + * from: @(#)xdr.h 2.2 88/07/29 4.0 RPCSRC + * $FreeBSD: src/include/rpc/xdr.h,v 1.23 2003/03/07 13:19:40 nectar Exp $ + */ + +/* + * xdr.h, External Data Representation Serialization Routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _TIRPC_XDR_H +#define _TIRPC_XDR_H +//#include +#include +//#include +// Rajout pour la définition des types +#include + +/* + * XDR provides a conventional way for converting between C data + * types and an external bit-string representation. Library supplied + * routines provide for the conversion on built-in C data types. These + * routines and utility routines defined here are used to help implement + * a type encode/decode routine for each user-defined type. + * + * Each data type provides a single procedure which takes two arguments: + * + * bool_t + * xdrproc(xdrs, argresp) + * XDR *xdrs; + * *argresp; + * + * xdrs is an instance of a XDR handle, to which or from which the data + * type is to be converted. argresp is a pointer to the structure to be + * converted. The XDR handle contains an operation field which indicates + * which of the operations (ENCODE, DECODE * or FREE) is to be performed. + * + * XDR_DECODE may allocate space if the pointer argresp is null. This + * data can be freed with the XDR_FREE operation. + * + * We write only one procedure per data type to make it easy + * to keep the encode and decode procedures for a data type consistent. + * In many cases the same code performs all operations on a user defined type, + * because all the hard work is done in the component type routines. + * decode as a series of calls on the nested data types. + */ + +/* + * Xdr operations. XDR_ENCODE causes the type to be encoded into the + * stream. XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { + XDR_ENCODE=0, + XDR_DECODE=1, + XDR_FREE=2 +}; + +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT (4) +#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \ + * BYTES_PER_XDR_UNIT) + +/* + * The XDR handle. + * Contains operation which is being applied to the stream, + * an operations vector for the particular implementation (e.g. see xdr_mem.c), + * and two private fields for the use of the particular implementation. + */ +typedef struct __rpc_xdr { + enum xdr_op x_op; /* operation; fast additional param */ + const struct xdr_ops { + /* get a long from underlying stream */ + bool_t (*x_getlong)(struct __rpc_xdr *, long *); + /* put a long to " */ + bool_t (*x_putlong)(struct __rpc_xdr *, const long *); + /* get some bytes from " */ + bool_t (*x_getbytes)(struct __rpc_xdr *, char *, u_int); + /* put some bytes to " */ + bool_t (*x_putbytes)(struct __rpc_xdr *, const char *, u_int); + /* returns bytes off from beginning */ + u_int (*x_getpostn)(struct __rpc_xdr *); + /* lets you reposition the stream */ + bool_t (*x_setpostn)(struct __rpc_xdr *, u_int); + /* buf quick ptr to buffered data */ + int32_t *(*x_inline)(struct __rpc_xdr *, u_int); + /* free privates of this xdr_stream */ + void (*x_destroy)(struct __rpc_xdr *); + bool_t (*x_control)(struct __rpc_xdr *, int, void *); + } *x_ops; + char * x_public; /* users' data */ + void * x_private; /* pointer to private data */ + char * x_base; /* private used for position info */ + u_int x_handy; /* extra private word */ +} XDR; + +/* + * A xdrproc_t exists for each data type which is to be encoded or decoded. + * + * The second argument to the xdrproc_t is a pointer to an opaque pointer. + * The opaque pointer generally points to a structure of the data type + * to be decoded. If this pointer is 0, then the type routines should + * allocate dynamic storage of the appropriate size and return it. + */ +#ifdef _KERNEL +typedef bool_t (*xdrproc_t)(XDR *, void *, u_int); +#else +/* + * XXX can't actually prototype it, because some take three args!!! + */ +typedef bool_t (*xdrproc_t)(XDR *, ...); +#endif + +/* + * Operations defined on a XDR handle + * + * XDR *xdrs; + * long *longp; + * char * addr; + * u_int len; + * u_int pos; + */ +#define XDR_GETLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) +#define xdr_getlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) + +#define XDR_PUTLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) +#define xdr_putlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) + +static __inline int +xdr_getint32(XDR *xdrs, int32_t *ip) +{ + long l; + + if (!xdr_getlong(xdrs, &l)) + return (FALSE); + *ip = (int32_t)l; + return (TRUE); +} + +static __inline int +xdr_putint32(XDR *xdrs, int32_t *ip) +{ + long l; + + l = (long)*ip; + return xdr_putlong(xdrs, &l); +} + +#define XDR_GETINT32(xdrs, int32p) xdr_getint32(xdrs, int32p) +#define XDR_PUTINT32(xdrs, int32p) xdr_putint32(xdrs, int32p) + +#define XDR_GETBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) +#define xdr_getbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) + +#define XDR_PUTBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) +#define xdr_putbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) + +#define XDR_GETPOS(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) +#define xdr_getpos(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) + +#define XDR_SETPOS(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) +#define xdr_setpos(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) + +#define XDR_INLINE(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) +#define xdr_inline(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) + +#define XDR_DESTROY(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) +#define xdr_destroy(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) + +#define XDR_CONTROL(xdrs, req, op) \ + if ((xdrs)->x_ops->x_control) \ + (*(xdrs)->x_ops->x_control)(xdrs, req, op) +#define xdr_control(xdrs, req, op) XDR_CONTROL(xdrs, req, op) + +/* + * Solaris strips the '_t' from these types -- not sure why. + * But, let's be compatible. + */ +#define xdr_rpcvers(xdrs, versp) xdr_u_int32(xdrs, versp) +#define xdr_rpcprog(xdrs, progp) xdr_u_int32(xdrs, progp) +#define xdr_rpcproc(xdrs, procp) xdr_u_int32(xdrs, procp) +#define xdr_rpcprot(xdrs, protp) xdr_u_int32(xdrs, protp) +#define xdr_rpcport(xdrs, portp) xdr_u_int32(xdrs, portp) + +/* + * Support struct for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * an entry with a null procedure pointer. The xdr_union routine gets + * the discriminant value and then searches the array of structures + * for a matching value. If a match is found the associated xdr routine + * is called to handle that part of the union. If there is + * no match, then a default routine may be called. + * If there is no match and no default routine it is an error. + */ +#define NULL_xdrproc_t ((xdrproc_t)0) +struct xdr_discrim { + int value; + xdrproc_t proc; +}; + +/* + * In-line routines for fast encode/decode of primitive data types. + * Caveat emptor: these use single memory cycles to get the + * data from the underlying buffer, and will fail to operate + * properly if the data is not aligned. The standard way to use these + * is to say: + * if ((buf = XDR_INLINE(xdrs, count)) == NULL) + * return (FALSE); + * <<< macro calls >>> + * where ``count'' is the number of bytes of data occupied + * by the primitive data types. + * + * N.B. and frozen for all time: each data type here uses 4 bytes + * of external representation. + */ +#define IXDR_GET_INT32(buf) ((int32_t)ntohl((u_int32_t)*(buf)++)) +#define IXDR_PUT_INT32(buf, v) (*(buf)++ =(int32_t)htonl((u_int32_t)v)) +#define IXDR_GET_U_INT32(buf) ((u_int32_t)IXDR_GET_INT32(buf)) +#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_INT32((buf), ((int32_t)(v))) + +#define IXDR_GET_LONG(buf) ((long)ntohl((u_int32_t)*(buf)++)) +#define IXDR_PUT_LONG(buf, v) (*(buf)++ =(int32_t)htonl((u_int32_t)v)) + +#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf)) +#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_LONG(buf) ((u_long)IXDR_GET_LONG(buf)) +#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_SHORT(buf) ((u_short)IXDR_GET_LONG(buf)) + +#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), (v)) +#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), (v)) + +/* + * These are the "generic" xdr routines. + */ +__BEGIN_DECLS +extern bool_t xdr_void(void); +extern bool_t xdr_int(XDR *, int *); +extern bool_t xdr_u_int(XDR *, u_int *); +extern bool_t xdr_long(XDR *, long *); +extern bool_t xdr_u_long(XDR *, u_long *); +extern bool_t xdr_short(XDR *, short *); +extern bool_t xdr_u_short(XDR *, u_short *); +extern bool_t xdr_int16_t(XDR *, int16_t *); +extern bool_t xdr_u_int16_t(XDR *, u_int16_t *); +extern bool_t xdr_int32_t(XDR *, int32_t *); +extern bool_t xdr_u_int32_t(XDR *, u_int32_t *); +extern bool_t xdr_int64_t(XDR *, int64_t *); +extern bool_t xdr_u_int64_t(XDR *, u_int64_t *); +extern bool_t xdr_bool(XDR *, bool_t *); +extern bool_t xdr_enum(XDR *, enum_t *); +extern bool_t xdr_array(XDR *, char **, u_int *, u_int, u_int, xdrproc_t); +extern bool_t xdr_bytes(XDR *, char **, u_int *, u_int); +extern bool_t xdr_opaque(XDR *, char *, u_int); +extern bool_t xdr_string(XDR *, char **, u_int); +extern bool_t xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t); +extern bool_t xdr_char(XDR *, char *); +extern bool_t xdr_u_char(XDR *, u_char *); +extern bool_t xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t); +extern bool_t xdr_float(XDR *, float *); +extern bool_t xdr_double(XDR *, double *); +extern bool_t xdr_quadruple(XDR *, long double *); +extern bool_t xdr_reference(XDR *, char **, u_int, xdrproc_t); +extern bool_t xdr_pointer(XDR *, char **, u_int, xdrproc_t); +extern bool_t xdr_wrapstring(XDR *, char **); +extern void xdr_free(xdrproc_t, void *); +extern bool_t xdr_hyper(XDR *, quad_t *); +extern bool_t xdr_u_hyper(XDR *, u_quad_t *); +extern bool_t xdr_longlong_t(XDR *, quad_t *); +extern bool_t xdr_u_longlong_t(XDR *, u_quad_t *); +__END_DECLS + +/* + * Common opaque bytes objects used by many rpc protocols; + * declared here due to commonality. + */ +#define MAX_NETOBJ_SZ 1024 +struct netobj { + u_int n_len; + char *n_bytes; +}; +typedef struct netobj netobj; +extern bool_t xdr_netobj(XDR *, struct netobj *); + +/* + * These are the public routines for the various implementations of + * xdr streams. + */ +__BEGIN_DECLS +/* XDR using memory buffers */ +extern void xdrmem_create(XDR *, char *, u_int, enum xdr_op); + +/* XDR using stdio library */ +extern void xdrstdio_create(XDR *, FILE *, enum xdr_op); + +/* XDR pseudo records for tcp */ +extern void xdrrec_create(XDR *, u_int, u_int, void *, + int (*)(void *, void *, int), + int (*)(void *, void *, int)); + +/* make end of xdr record */ +extern bool_t xdrrec_endofrecord(XDR *, int); + +/* move to beginning of next record */ +extern bool_t xdrrec_skiprecord(XDR *); +extern void xdrrec_setlastfrag(XDR *); + +/* true if no more input */ +extern bool_t xdrrec_eof(XDR *); +extern u_int xdrrec_readbytes(XDR *, caddr_t, u_int); +__END_DECLS + +#endif /* !_TIRPC_XDR_H */ diff --git a/libtirpc/tirpc/rpcsvc/crypt.h b/libtirpc/tirpc/rpcsvc/crypt.h new file mode 100644 index 0000000..da1f9cc --- /dev/null +++ b/libtirpc/tirpc/rpcsvc/crypt.h @@ -0,0 +1,109 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _CRYPT_H_RPCGEN +#define _CRYPT_H_RPCGEN + +#include + +#ifndef IXDR_GET_INT32 +#define IXDR_GET_INT32(buf) IXDR_GET_LONG((buf)) +#endif +#ifndef IXDR_PUT_INT32 +#define IXDR_PUT_INT32(buf, v) IXDR_PUT_LONG((buf), (v)) +#endif +#ifndef IXDR_GET_U_INT32 +#define IXDR_GET_U_INT32(buf) IXDR_GET_U_LONG((buf)) +#endif +#ifndef IXDR_PUT_U_INT32 +#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_U_LONG((buf), (v)) +#endif + +enum des_dir { + ENCRYPT_DES = 0, + DECRYPT_DES = 1, +}; +typedef enum des_dir des_dir; +#ifdef __cplusplus +extern "C" bool_t xdr_des_dir(XDR *, des_dir*); +#elif __STDC__ +extern bool_t xdr_des_dir(XDR *, des_dir*); +#else /* Old Style C */ +bool_t xdr_des_dir(); +#endif /* Old Style C */ + + +enum des_mode { + CBC_DES = 0, + ECB_DES = 1, +}; +typedef enum des_mode des_mode; +#ifdef __cplusplus +extern "C" bool_t xdr_des_mode(XDR *, des_mode*); +#elif __STDC__ +extern bool_t xdr_des_mode(XDR *, des_mode*); +#else /* Old Style C */ +bool_t xdr_des_mode(); +#endif /* Old Style C */ + + +struct desargs { + u_char des_key[8]; + des_dir des_dir; + des_mode des_mode; + u_char des_ivec[8]; + struct { + u_int desbuf_len; + char *desbuf_val; + } desbuf; +}; +typedef struct desargs desargs; +#ifdef __cplusplus +extern "C" bool_t xdr_desargs(XDR *, desargs*); +#elif __STDC__ +extern bool_t xdr_desargs(XDR *, desargs*); +#else /* Old Style C */ +bool_t xdr_desargs(); +#endif /* Old Style C */ + + +struct desresp { + struct { + u_int desbuf_len; + char *desbuf_val; + } desbuf; + u_char des_ivec[8]; + int stat; +}; +typedef struct desresp desresp; +#ifdef __cplusplus +extern "C" bool_t xdr_desresp(XDR *, desresp*); +#elif __STDC__ +extern bool_t xdr_desresp(XDR *, desresp*); +#else /* Old Style C */ +bool_t xdr_desresp(); +#endif /* Old Style C */ + + +#define CRYPT_PROG ((u_int32_t)600100029) +#define CRYPT_VERS ((u_int32_t)1) + +#ifdef __cplusplus +#define DES_CRYPT ((u_int32_t)1) +extern "C" desresp * des_crypt_1(desargs *, CLIENT *); +extern "C" desresp * des_crypt_1_svc(desargs *, struct svc_req *); + +#elif __STDC__ +#define DES_CRYPT ((u_int32_t)1) +extern desresp * des_crypt_1(desargs *, CLIENT *); +extern desresp * des_crypt_1_svc(desargs *, struct svc_req *); + +#else /* Old Style C */ +#define DES_CRYPT ((u_int32_t)1) +extern desresp * des_crypt_1(); +extern desresp * des_crypt_1_svc(); +#endif /* Old Style C */ + +#endif /* !_CRYPT_H_RPCGEN */ diff --git a/libtirpc/tirpc/rpcsvc/crypt.x b/libtirpc/tirpc/rpcsvc/crypt.x new file mode 100644 index 0000000..b50cf8d --- /dev/null +++ b/libtirpc/tirpc/rpcsvc/crypt.x @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1996 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef RPC_HDR +%#include +%__FBSDID("$FreeBSD: src/include/rpcsvc/crypt.x,v 1.5 2003/05/04 02:51:42 obrien Exp $"); +#endif + +/* + * This protocol definition exists because of the U.S. government and + * its stupid export laws. We can't export DES code from the United + * States to other countries (even though the code already exists + * outside the U.S. -- go figure that one out) but we need to make + * Secure RPC work. The normal way around this is to break the DES + * code out into a shared library; we can then provide a dummy lib + * in the base OS and provide the real lib in the secure dist, which + * the user can install later. But we need Secure RPC for NIS+, and + * there are several system programs that use NIS+ which are statically + * linked. We would have to provide replacements for these programs + * in the secure dist, but there are a lot, and this is a pain. The + * shared lib trick won't work for these programs, and we can't change + * them once they're compiled. + * + * One solution for this problem is to do the DES encryption as a system + * call; no programs need to be changed and we can even supply the DES + * support as an LKM. But this bloats the kernel. Maybe if we have + * Secure NFS one day this will be worth it, but for now we should keep + * this mess in user space. + * + * So we have this second solution: we provide a server that does the + * DES encryption for us. In this case, the server is keyserv (we need + * it to make Secure RPC work anyway) and we use this protocol to ship + * the data back and forth between keyserv and the application. + */ + +enum des_dir { ENCRYPT_DES, DECRYPT_DES }; +enum des_mode { CBC_DES, ECB_DES }; + +struct desargs { + u_char des_key[8]; /* key (with low bit parity) */ + des_dir des_dir; /* direction */ + des_mode des_mode; /* mode */ + u_char des_ivec[8]; /* input vector */ + opaque desbuf<>; +}; + +struct desresp { + opaque desbuf<>; + u_char des_ivec[8]; + int stat; +}; + +program CRYPT_PROG { + version CRYPT_VERS { + desresp + DES_CRYPT(desargs) = 1; + } = 1; +} = 600100029; diff --git a/libtirpc/tirpc/rpcsvc/nis.h b/libtirpc/tirpc/rpcsvc/nis.h new file mode 100644 index 0000000..92a10cb --- /dev/null +++ b/libtirpc/tirpc/rpcsvc/nis.h @@ -0,0 +1,29 @@ +#ifndef _RPCSVC_NIS_H +#define _RPCSVC_NIS_H + +#define NIS_PK_NONE 0 /* no public key (unix/sys auth) */ +#define NIS_PK_DH 1 /* Public key is Diffie-Hellman type */ +#define NIS_PK_RSA 2 /* Public key is RSA type */ +#define NIS_PK_KERB 3 /* Use kerberos style authentication */ + +typedef char * nis_name; +struct endpoint { + char *uaddr; + char *family; + char *proto; +}; +typedef struct endpoint endpoint; + +struct nis_server{ + nis_name name; + struct { + u_int ep_len; + endpoint *ep_val; + } ep; + uint32_t key_type; + netobj pkey; +}; +typedef struct nis_server nis_server; + +#endif /* !_RPCSVC_NIS_H */ + diff --git a/libtirpc/tirpc/spinlock.h b/libtirpc/tirpc/spinlock.h new file mode 100644 index 0000000..8c65ab5 --- /dev/null +++ b/libtirpc/tirpc/spinlock.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1998 John Birrell . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/spinlock.h,v 1.7 2003/11/05 18:17:30 deischen Exp $ + * + * Lock definitions used in both libc and libpthread. + * + */ + +#ifndef _SPINLOCK_H_ +#define _SPINLOCK_H_ +//#include +#include + +/* + * Lock structure with room for debugging information. + */ +struct _spinlock { + volatile long access_lock; + volatile long lock_owner; + volatile char *fname; + volatile int lineno; +}; +typedef struct _spinlock spinlock_t; + +#define _SPINLOCK_INITIALIZER { 0, 0, 0, 0 } + +#define _SPINUNLOCK(_lck) _spinunlock(_lck); +#ifdef _LOCK_DEBUG +#define _SPINLOCK(_lck) _spinlock_debug(_lck, __FILE__, __LINE__) +#else +#define _SPINLOCK(_lck) _spinlock(_lck) +#endif + +/* + * Thread function prototype definitions: + */ +__BEGIN_DECLS +long _atomic_lock(volatile long *); +void _spinlock(spinlock_t *); +void _spinunlock(spinlock_t *); +void _spinlock_debug(spinlock_t *, char *, int); +__END_DECLS + +#endif /* _SPINLOCK_H_ */ diff --git a/libtirpc/tirpc/sys/queue.h b/libtirpc/tirpc/sys/queue.h new file mode 100644 index 0000000..553f745 --- /dev/null +++ b/libtirpc/tirpc/sys/queue.h @@ -0,0 +1,529 @@ +/* $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != SLIST_END(head); \ + (varp) = &SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ + + diff --git a/libtirpc/tirpc/un-namespace.h b/libtirpc/tirpc/un-namespace.h new file mode 100644 index 0000000..067e22d --- /dev/null +++ b/libtirpc/tirpc/un-namespace.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2001 Daniel Eischen . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/include/un-namespace.h,v 1.13 2003/05/01 19:03:13 nectar Exp $ + */ + +#ifndef _UN_NAMESPACE_H_ +#define _UN_NAMESPACE_H_ + +#undef accept +#undef __acl_aclcheck_fd +#undef __acl_delete_fd +#undef __acl_get_fd +#undef __acl_set_fd +#undef bind +#undef __cap_get_fd +#undef __cap_set_fd +#undef close +#undef connect +#undef dup +#undef dup2 +#undef execve +#undef fcntl +#undef flock +#undef flockfile +#undef fpathconf +#undef fstat +#undef fstatfs +#undef fsync +#undef funlockfile +#undef getdirentries +#undef getlogin +#undef getpeername +#undef getprogname +#undef getsockname +#undef getsockopt +#undef ioctl +#undef kevent +#undef listen +#undef nanosleep +#undef open +#undef poll +#undef pthread_cond_broadcast +#undef pthread_cond_destroy +#undef pthread_cond_init +#undef pthread_cond_signal +#undef pthread_cond_timedwait +#undef pthread_cond_wait +#undef pthread_exit +#undef pthread_getspecific +#undef pthread_key_create +#undef pthread_key_delete +#undef pthread_main_np +#undef pthread_mutex_destroy +#undef pthread_mutex_init +#undef pthread_mutex_lock +#undef pthread_mutex_trylock +#undef pthread_mutex_unlock +#undef pthread_mutexattr_init +#undef pthread_mutexattr_destroy +#undef pthread_mutexattr_settype +#undef pthread_once +#undef pthread_rwlock_destroy +#undef pthread_rwlock_init +#undef pthread_rwlock_rdlock +#undef pthread_rwlock_wrlock +#undef pthread_rwlock_tryrdlock +#undef pthread_rwlock_trywrlock +#undef pthread_rwlock_unlock +#undef pthread_self +#undef pthread_setspecific +#undef pthread_sigmask +#undef read +#undef readv +#undef recvfrom +#undef recvmsg +#undef select +#undef sendmsg +#undef sendto +#undef setsockopt +#undef sigaction +#undef sigprocmask +#undef sigsuspend +#undef socket +#undef socketpair +#undef wait4 +#undef waitpid +#undef write +#undef writev + +#if 0 +#undef creat +#undef fchflags +#undef fchmod +#undef ftrylockfile +#undef msync +#undef nfssvc +#undef pause +#undef pthread_rwlockattr_init +#undef pthread_rwlockattr_destroy +#undef sched_yield +#undef sendfile +#undef shutdown +#undef sigaltstack +#undef sigpending +#undef sigreturn +#undef sigsetmask +#undef sleep +#undef system +#undef tcdrain +#undef wait +#endif /* 0 */ + +#ifdef _SIGNAL_H_ +int _sigaction(int, const struct sigaction *, struct sigaction *); +#endif + +#ifdef _SYS_EVENT_H_ +int _kevent(int, const struct kevent *, int, struct kevent *, + int, const struct timespec *); +#endif + +#ifdef _SYS_FCNTL_H_ +int _flock(int, int); +#endif + +#undef err +#undef warn +#undef nsdispatch + +#endif /* _UN_NAMESPACE_H_ */ diff --git a/libtirpc/tirpc/wintirpc.h b/libtirpc/tirpc/wintirpc.h new file mode 100644 index 0000000..86802be --- /dev/null +++ b/libtirpc/tirpc/wintirpc.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef _TIRPC_WINTIRPC_H +#define _TIRPC_WINTIRPC_H + +/* + * Eliminate warnings about possibly unsafe uses of snprintf and friends + * XXX Think about cleaning these up and removing this later XXX + */ +#define _CRT_SECURE_NO_WARNINGS 1 + + +#ifdef _DEBUG +/* use visual studio's debug heap */ +# define _CRTDBG_MAP_ALLOC +# include +# include +#else +# include +#endif + +/* Common Windows includes */ +#include +#include +#include +#include +#include + +#define snprintf _snprintf +//#define vsnprintf _vsnprintf +#define strcasecmp _stricmp +#define strdup _strdup +#define getpid _getpid + +#define bcmp memcmp +#define bcopy(d,s,l) memcpy(d,s,l) +#define bzero(d,s) memset(d,0,s) +#define strtok_r strtok_s + +#define poll WSAPoll +#define ioctl ioctlsocket + +#define __BEGIN_DECLS +#define __END_DECLS +#define __THROW + +/* + * Hash of Windows Socket Handle values + */ +#define WINSOCK_HANDLE_HASH_SIZE 1024 +#define WINSOCK_HANDLE_HASH(x) (((x) >> 2) % WINSOCK_HANDLE_HASH_SIZE) + +/* + * Functions imported from BSD + */ +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +extern int gettimeofday(struct timeval *tv, struct timezone *tz); +extern int asprintf(char **str, const char *fmt, ...); + +#define SOL_IPV6 IPPROTO_IPV6 + +#define MAXHOSTNAMELEN 256 + +struct sockaddr_un { + int sun_family; + char sun_path[MAX_PATH]; +}; +/* Evaluate to actual length of the sockaddr_un structure */ +/* XXX Should this return size_t or unsigned int ?? */ +#define SUN_LEN(ptr) ((unsigned int)(sizeof(int) + strlen ((ptr)->sun_path))) + +/* Debugging function */ +void wintirpc_debug(char *fmt, ...); + +#endif /* !_TIRPC_WINTIRPC_H */ diff --git a/mount/enum.c b/mount/enum.c new file mode 100644 index 0000000..91ae64a --- /dev/null +++ b/mount/enum.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include + +#include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */ + + +void PrintErrorMessage( + IN DWORD dwError); + +static __inline +void PrintMountLine( + LPCTSTR local, + LPCTSTR remote) +{ + _tprintf(TEXT("%-11s %s\n"), local, remote); +} + +/* ENUM_RESOURCE_BUFFER_SIZE + * from msdn re: WNetEnumResource + * "An application cannot set the lpBuffer parameter to NULL and + * retrieve the required buffer size from the lpBufferSize parameter. + * Instead, the application should allocate a buffer of a reasonable + * size—16 kilobytes is typical—and use the value of lpBufferSize for + * error detection." */ +#define ENUM_RESOURCE_BUFFER_SIZE (16*1024) + +DWORD EnumMounts( + IN LPNETRESOURCE pContainer) +{ + DWORD result = NO_ERROR; + LPNETRESOURCE pResources; + DWORD i, dwCount, dwTotal = 0; + DWORD dwBufferSize = ENUM_RESOURCE_BUFFER_SIZE; + HANDLE hEnum; + + pResources = (LPNETRESOURCE)GlobalAlloc(0, ENUM_RESOURCE_BUFFER_SIZE); + if (pResources == NULL) { + result = WN_OUT_OF_MEMORY; + goto out; + } + + result = WNetOpenEnum(RESOURCE_CONNECTED, + RESOURCETYPE_DISK, 0, pContainer, &hEnum); + if (result) + goto out_free; + + _tprintf(TEXT("Listing %s mounts:\n\n"), TEXT(NFS41_PROVIDER_NAME_A)); + PrintMountLine(TEXT("Volume"), TEXT("Remote path")); + do + { + dwCount = (DWORD)-1; + result = WNetEnumResource(hEnum, + &dwCount, pResources, &dwBufferSize); + + if (result == NO_ERROR) + { + for (i = 0; i < dwCount; i++) + { + if (_tcscmp(pResources[i].lpProvider, + TEXT(NFS41_PROVIDER_NAME_A)) == 0) + { + PrintMountLine(pResources[i].lpLocalName, + pResources[i].lpRemoteName); + dwTotal++; + } + } + } + else if (result != WN_NO_MORE_ENTRIES) + break; + } + while (result != WN_NO_MORE_ENTRIES); + + result = WNetCloseEnum(hEnum); + + _tprintf(TEXT("\nFound %d share%s.\n"), dwTotal, + dwTotal == 1 ? TEXT("") : TEXT("s")); + +out_free: + GlobalFree((HGLOBAL)pResources); +out: + return result; +} \ No newline at end of file diff --git a/mount/mount.c b/mount/mount.c new file mode 100644 index 0000000..a130684 --- /dev/null +++ b/mount/mount.c @@ -0,0 +1,369 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include /* for WNet*Connection */ +#include +#include + +#include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */ +#include "options.h" + + +DWORD EnumMounts( + IN LPNETRESOURCE pContainer); + +static DWORD DoMount( + IN LPTSTR pLocalName, + IN LPTSTR pRemoteName, + IN PMOUNT_OPTION_LIST pOptions); +static DWORD DoUnmount( + IN LPTSTR pLocalName, + IN BOOL bForce); + +static void RecursivePrintEaInformation( + IN PFILE_FULL_EA_INFORMATION EA); +static BOOL ParseDriveLetter( + IN LPTSTR pArg, + OUT PTCH pDriveLetter); +void PrintErrorMessage( + IN DWORD dwError); + +static VOID PrintUsage(LPTSTR pProcess) +{ + _tprintf(TEXT("Usage: %s [options] :\n") + TEXT("Options:\n") + TEXT("\t-h\thelp\n") + TEXT("\t-d\tunmount\n") + TEXT("\t-f\tforce unmount if the drive is in use\n") + TEXT("\t-o \n") + TEXT("Mount options:\n") + TEXT("\tro\tmount as read-only\n") + TEXT("\trsize=#\tread buffer size in bytes\n") + TEXT("\twsize=#\twrite buffer size in bytes\n"), + pProcess, pProcess, pProcess); +} + +DWORD __cdecl _tmain(DWORD argc, LPTSTR argv[]) +{ + DWORD i, result = NO_ERROR; + TCHAR szLocalName[] = TEXT("C:\0"); + LPTSTR pLocalName = NULL; + LPTSTR pRemoteName = NULL; + BOOL bUnmount = FALSE; + BOOL bForceUnmount = FALSE; + MOUNT_OPTION_LIST Options; + + if (argc == 1) { + /* list open nfs shares */ + result = EnumMounts(NULL); + if (result) + PrintErrorMessage(GetLastError()); + goto out; + } + + result = InitializeMountOptions(&Options, MAX_OPTION_BUFFER_SIZE); + if (result) { + PrintErrorMessage(GetLastError()); + goto out; + } + + /* parse command line */ + for (i = 1; i < argc; i++) + { + if (argv[i][0] == TEXT('-')) + { + if (_tcscmp(argv[i], TEXT("-h")) == 0) /* help */ + { + PrintUsage(argv[0]); + goto out; + } + else if (_tcscmp(argv[i], TEXT("-d")) == 0) /* unmount */ + { + bUnmount = TRUE; + } + else if (_tcscmp(argv[i], TEXT("-f")) == 0) /* force unmount */ + { + bForceUnmount = TRUE; + } + else if (_tcscmp(argv[i], TEXT("-o")) == 0) /* mount option */ + { + ++i; + if (i >= argc) + { + result = ERROR_BAD_ARGUMENTS; + _ftprintf(stderr, TEXT("Mount options missing ") + TEXT("after '-o'.\n\n")); + PrintUsage(argv[0]); + goto out_free; + } + + if (!ParseMountOptions(argv[i], &Options)) + { + result = ERROR_BAD_ARGUMENTS; + goto out_free; + } + } + else + _ftprintf(stderr, TEXT("Unrecognized option ") + TEXT("'%s', disregarding.\n"), argv[i]); + } + else if (pLocalName == NULL) /* drive letter */ + { + pLocalName = argv[i]; + } + else if (pRemoteName == NULL) /* remote path */ + { + pRemoteName = argv[i]; + } + else + _ftprintf(stderr, TEXT("Unrecognized argument ") + TEXT("'%s', disregarding.\n"), argv[i]); + } + + /* validate local drive letter */ + if (pLocalName == NULL) + { + result = ERROR_BAD_ARGUMENTS; + _ftprintf(stderr, TEXT("Missing argument for drive letter.\n\n")); + PrintUsage(argv[0]); + goto out_free; + } + if (FALSE == ParseDriveLetter(pLocalName, szLocalName)) + { + result = ERROR_BAD_ARGUMENTS; + _ftprintf(stderr, TEXT("Invalid drive letter '%s'. ") + TEXT("Expected 'C' or 'C:'.\n\n"), pLocalName); + PrintUsage(argv[0]); + goto out_free; + } + + if (bUnmount == TRUE) /* unmount */ + { + result = DoUnmount(szLocalName, bForceUnmount); + if (result) + PrintErrorMessage(result); + } + else /* mount */ + { + if (pRemoteName == NULL) + { + result = ERROR_BAD_NET_NAME; + _ftprintf(stderr, TEXT("Missing argument for remote path.\n\n")); + PrintUsage(argv[0]); + goto out_free; + } + + result = DoMount(szLocalName, pRemoteName, &Options); + if (result) + PrintErrorMessage(result); + } + +out_free: + FreeMountOptions(&Options); +out: + return result; +} + +static void ConvertUnixSlashes( + IN OUT LPTSTR pRemoteName) +{ + LPTSTR pos = pRemoteName; + for (pos = pRemoteName; *pos; pos++) + if (*pos == TEXT('/')) + *pos = TEXT('\\'); +} + +static LPTSTR FindEndOfServer( + IN LPTSTR pRemoteName) +{ + LPTSTR pos = pRemoteName; + while (*pos && *pos != TEXT(':')) + pos++; + return pos; +} + +static DWORD ParseRemoteName( + IN LPTSTR pRemoteName, + IN OUT PMOUNT_OPTION_LIST pOptions, + OUT LPTSTR pConnectionName, + IN size_t cchConnectionLen) +{ + DWORD result = NO_ERROR; + LPTSTR pEnd; + + ConvertUnixSlashes(pRemoteName); + pEnd = FindEndOfServer(pRemoteName); + + /* fail if the server name doesn't end with :\ */ + if (*pEnd == 0 || pEnd[0] != TEXT(':') || pEnd[1] != TEXT('\\')) { + _ftprintf(stderr, TEXT("Failed to parse the remote path. ") + TEXT("Expected 'hostname:\\path'.\n")); + result = ERROR_BAD_ARGUMENTS; + goto out; + } + *pEnd = TEXT('\0'); + ++pEnd; + + if (!InsertOption(TEXT("srvname"), pRemoteName, pOptions) || + !InsertOption(TEXT("mntpt"), *pEnd ? pEnd : TEXT("\\"), pOptions)) { + result = ERROR_BAD_ARGUMENTS; + goto out; + } + + result = StringCchCopy(pConnectionName, cchConnectionLen, TEXT("\\\\")); + if (FAILED(result)) + goto out; + result = StringCbCat(pConnectionName, cchConnectionLen, pRemoteName); + if (FAILED(result)) + goto out; + if (*pEnd) + result = StringCchCat(pConnectionName, cchConnectionLen, pEnd); + +out: + return result; +} + +static DWORD DoMount( + IN LPTSTR pLocalName, + IN LPTSTR pRemoteName, + IN PMOUNT_OPTION_LIST pOptions) +{ + DWORD result = NO_ERROR; + TCHAR szExisting[MAX_PATH]; + TCHAR szRemoteName[MAX_PATH]; + DWORD dwLength; + + *szRemoteName = TEXT('\0'); + result = ParseRemoteName(pRemoteName, pOptions, szRemoteName, MAX_PATH); + if (result) + goto out; + + /* fail if the connection already exists */ + result = WNetGetConnection(pLocalName, (LPTSTR)szExisting, &dwLength); + if (result == NO_ERROR) + { + result = ERROR_ALREADY_ASSIGNED; + _ftprintf(stderr, TEXT("Mount failed, drive %s is ") + TEXT("already assigned to '%s'.\n"), + pLocalName, szExisting); + } + else + { + NETRESOURCE NetResource; + TCHAR szConnection[MAX_PATH]; + DWORD ConnectSize = MAX_PATH, ConnectResult; + + ZeroMemory(&NetResource, sizeof(NETRESOURCE)); + NetResource.dwType = RESOURCETYPE_DISK; + /* drive letter is chosen automatically if lpLocalName == NULL */ + NetResource.lpLocalName = *pLocalName == TEXT('*') ? NULL : pLocalName; + NetResource.lpRemoteName = szRemoteName; + /* ignore other network providers */ + NetResource.lpProvider = TEXT(NFS41_PROVIDER_NAME_A); + /* pass mount options via lpComment */ + if (pOptions->Buffer->Length) + { + if (pOptions->Current) + pOptions->Current->NextEntryOffset = 0; + NetResource.lpComment = (LPTSTR)pOptions->Buffer; + } + + result = WNetUseConnection(NULL, + &NetResource, NULL, NULL, 0, + szConnection, &ConnectSize, &ConnectResult); + + if (result == NO_ERROR) + _tprintf(TEXT("Successfully mounted %s to drive %s\n"), + pRemoteName, szConnection); + else + _ftprintf(stderr, TEXT("WNetUseConnection(%s, %s) ") + TEXT("failed with error code %u.\n"), + pLocalName, szRemoteName, result); + } + +out: + return result; +} + +static DWORD DoUnmount( + IN LPTSTR pLocalName, + IN BOOL bForce) +{ + DWORD result; + + /* disconnect the specified local drive */ + result = WNetCancelConnection2(pLocalName, 0, bForce); + /* TODO: verify that this connection uses the nfs41 provider -cbodley */ + switch (result) + { + case NO_ERROR: + _tprintf(TEXT("Drive %s unmounted successfully.\n"), pLocalName); + break; + case ERROR_NOT_CONNECTED: + _ftprintf(stderr, TEXT("Drive %s is not currently ") + TEXT("connected.\n"), pLocalName); + break; + default: + _ftprintf(stderr, TEXT("WNetCancelConnection2(%s) failed ") + TEXT("with error code %u.\n"), pLocalName, result); + break; + } + return result; +} + +static BOOL ParseDriveLetter( + IN LPTSTR pArg, + OUT PTCH pDriveLetter) +{ + /* accept 'C' or 'C:' */ + switch (_tcslen(pArg)) + { + case 2: + if (pArg[1] != TEXT(':')) + return FALSE; + /* break intentionally missing */ + case 1: + if (_istlower(*pArg)) + *pArg = (TCHAR)_totupper(*pArg); + else if (!_istupper(*pArg) && *pArg != TEXT('*')) + return FALSE; + + *pDriveLetter = *pArg; + return TRUE; + } + return FALSE; +} + +void PrintErrorMessage( + IN DWORD dwError) +{ + LPTSTR lpMsgBuf = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, 0, NULL); + _fputts(lpMsgBuf, stderr); + LocalFree(lpMsgBuf); +} diff --git a/mount/options.c b/mount/options.c new file mode 100644 index 0000000..058a901 --- /dev/null +++ b/mount/options.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#include +#include +#include +#include + +#include "options.h" + + +DWORD InitializeMountOptions( + IN OUT PMOUNT_OPTION_LIST Options, + IN ULONG BufferSize) +{ + Options->Current = NULL; + Options->Remaining = BufferSize; + Options->Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize); + if (Options->Buffer == NULL) + return ERROR_OUTOFMEMORY; + + Options->Buffer->Secret = MOUNT_OPTION_BUFFER_SECRET; + return NO_ERROR; +} + +void FreeMountOptions( + IN OUT PMOUNT_OPTION_LIST Options) +{ + Options->Current = NULL; + Options->Remaining = 0; + if (Options->Buffer) + { + LocalFree(Options->Buffer); + Options->Buffer = NULL; + } +} + +static BOOL FindOptionByName( + IN LPCTSTR Name, + IN PMOUNT_OPTION_LIST Options, + OUT PFILE_FULL_EA_INFORMATION* ppOption) +{ + PFILE_FULL_EA_INFORMATION Current = + (PFILE_FULL_EA_INFORMATION)Options->Buffer->Buffer; + ULONG NameLength = (ULONG)_tcslen(Name) * sizeof(TCHAR); + + for (;;) + { + if (Current->EaNameLength == NameLength && + _tcscmp((LPTSTR)Current->EaName, Name) == 0) + { + *ppOption = Current; + return TRUE; + } + if (Current->NextEntryOffset == 0) + break; + Current = (PFILE_FULL_EA_INFORMATION) + ((PBYTE)Current + Current->NextEntryOffset); + } + return FALSE; +} + +static FORCEINLINE ULONG EaBufferSize( + IN UCHAR NameSize, + IN USHORT ValueSize) +{ + ULONG Size = sizeof(ULONG) + 2 * sizeof(UCHAR) + sizeof(USHORT) + + NameSize + ValueSize + sizeof(TCHAR); + /* extended attributes require ULONG alignment; + * see documentation for IoCheckEaBufferValidity() */ + return ( (Size + 3) / sizeof(ULONG) ) * sizeof(ULONG); +} + +static FORCEINLINE ULONG EaBufferNextOffset( + IN PFILE_FULL_EA_INFORMATION EaBuffer) +{ + return EaBufferSize( + EaBuffer->EaNameLength, + EaBuffer->EaValueLength); +} + +BOOL InsertOption( + IN LPCTSTR Name, + IN LPCTSTR Value, + IN OUT PMOUNT_OPTION_LIST Options) +{ + PFILE_FULL_EA_INFORMATION Current; + UCHAR NameLen = (UCHAR)_tcslen(Name) * sizeof(TCHAR); + USHORT ValueLen = (USHORT)_tcslen(Value) * sizeof(TCHAR); + ULONG SpaceRequired = EaBufferSize(NameLen, ValueLen); + + /* don't allow duplicate options */ + if (FindOptionByName(Name, Options, &Current)) { + _ftprintf(stderr, TEXT("Found a duplicate option ") + TEXT("'%s%s%s' while parsing '%s%s%s'.\n"), + (PTCH)Current->EaName, + Current->EaValueLength ? TEXT("=") : TEXT(""), + (PTCH)(Current->EaName + Current->EaNameLength + sizeof(TCHAR)), + Name, ValueLen ? TEXT("=") : Value, Value); + return FALSE; + } + + /* fail if we're out of space */ + if (SpaceRequired > Options->Remaining) { + _ftprintf(stderr, TEXT("Out of space for options!\n")); + return FALSE; + } + + if (Options->Current == NULL) + Current = Options->Current = (PFILE_FULL_EA_INFORMATION) + Options->Buffer->Buffer; + else + Current = Options->Current = (PFILE_FULL_EA_INFORMATION) + ((PBYTE)Options->Current + Options->Current->NextEntryOffset); + + Current->EaNameLength = NameLen; + if (NameLen) /* copy attribute name */ + StringCbCopy((LPTSTR)Current->EaName, + NameLen + sizeof(TCHAR), Name); + + Current->EaValueLength = ValueLen; + if (ValueLen) /* copy attribute value */ + StringCbCopy((LPTSTR)(Current->EaName + NameLen + sizeof(TCHAR)), + ValueLen + sizeof(TCHAR), Value); + + Current->Flags = 0; + Current->NextEntryOffset = EaBufferNextOffset(Options->Current); + + Options->Buffer->Length = (ULONG)( + (Current->EaName + NameLen + ValueLen + 2 * sizeof(TCHAR)) + - Options->Buffer->Buffer ); + Options->Remaining -= SpaceRequired; + return TRUE; +} + +static void RecursivePrintEaInformation( + IN PFILE_FULL_EA_INFORMATION EA) +{ + _tprintf( + TEXT("----------------------\n") + TEXT("Alignment: %5lu\n") + TEXT("NextEntryOffset: %5lu\n") + TEXT("Flags: %5u\n") + TEXT("EaNameLength: %5u\n") + TEXT("EaValueLength: %5u\n") + TEXT("EaName: %16ls\n") + TEXT("EaValue: %16ls\n\n"), + (ULONG_PTR)EA % sizeof(ULONG), + EA->NextEntryOffset, + EA->Flags, + EA->EaNameLength, + EA->EaValueLength, + (LPTSTR)EA->EaName, + (LPTSTR)(EA->EaName + EA->EaNameLength + sizeof(TCHAR))); + + if (EA->NextEntryOffset) + RecursivePrintEaInformation((PFILE_FULL_EA_INFORMATION) + ((PBYTE)EA + EA->NextEntryOffset)); +} + +static const TCHAR COMMA_T = TEXT(','); +static const TCHAR EQUAL_T = TEXT('='); + +BOOL ParseMountOptions( + IN LPTSTR Arg, + IN OUT PMOUNT_OPTION_LIST Options) +{ + PTCH pos, comma, equals; + + pos = Arg; + for (;;) + { + comma = _tcschr(pos, COMMA_T); + if (comma) + { + if (comma == pos) + goto out_empty_option; + *comma = 0; + } + else if (_tcslen(pos) == 0) + goto out_empty_option; + + /* accept 'option=value' or 'option' */ + equals = _tcschr(pos, EQUAL_T); + if (equals) + { + if (equals == pos) + goto out_empty_option; + *equals = 0; + if (!InsertOption(pos, equals + 1, Options)) + return FALSE; + } + else if (!InsertOption(pos, TEXT(""), Options)) + return FALSE; + + if (comma == NULL) + break; + + pos = comma + 1; + } + +/* RecursivePrintEaInformation( + (PFILE_FULL_EA_INFORMATION)Options->Buffer->Buffer); */ + return TRUE; + +out_empty_option: + _ftprintf(stderr, TEXT("Found an empty option while ") + TEXT("reading mount options at '%s'.\n"), pos); + return FALSE; +} diff --git a/mount/options.h b/mount/options.h new file mode 100644 index 0000000..9248d45 --- /dev/null +++ b/mount/options.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef __NFS41_MOUNT_OPTIONS_H__ +#define __NFS41_MOUNT_OPTIONS_H__ + + +#define MOUNT_OPTION_BUFFER_SECRET ('n4') + +/* MOUNT_OPTION_BUFFER + * Buffer passed to the network provider via NETRESOURCE.lpComment. + * To avoid interpreting a normal comment string as mount options, a + * NULL and secret number are expected at the front. */ +typedef struct _MOUNT_OPTION_BUFFER { + USHORT Zero; /* = 0 */ + USHORT Secret; /* = 'n4' */ + ULONG Length; + CHAR Buffer[1]; +} MOUNT_OPTION_BUFFER, *PMOUNT_OPTION_BUFFER; + + +#ifndef FILE_FULL_EA_INFORMATION +/* from wdm.h + * couldn't find a definition outside of the ddk -cbodley */ +typedef struct _FILE_FULL_EA_INFORMATION { + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; +#endif + +/* MOUNT_OPTION_LIST + * Used internally to encapsulate the formation of the + * extended attribute buffer for mount options. */ +typedef struct _MOUNT_OPTION_LIST { + PMOUNT_OPTION_BUFFER Buffer; + ULONG Remaining; + PFILE_FULL_EA_INFORMATION Current; +} MOUNT_OPTION_LIST, *PMOUNT_OPTION_LIST; + +/* allocate space for 8 full attributes, but limit options by + * space rather than count. */ +#define MAX_OPTION_EA_SIZE ( 8 * \ + (sizeof(FILE_FULL_EA_INFORMATION) + MAX_PATH) ) + +#define MAX_OPTION_BUFFER_SIZE ( sizeof(MOUNT_OPTION_BUFFER) + \ + MAX_OPTION_EA_SIZE - 1 ) + + +/* options.c */ +DWORD InitializeMountOptions( + IN OUT PMOUNT_OPTION_LIST Options, + IN ULONG BufferSize); + +void FreeMountOptions( + IN OUT PMOUNT_OPTION_LIST Options); + +BOOL ParseMountOptions( + IN LPTSTR Arg, + IN OUT PMOUNT_OPTION_LIST Options); + +BOOL InsertOption( + IN LPCTSTR Name, + IN LPCTSTR Value, + IN OUT PMOUNT_OPTION_LIST Options); + +#endif /* !__NFS41_MOUNT_OPTIONS_H__ */ diff --git a/mount/sources b/mount/sources new file mode 100644 index 0000000..678d0bd --- /dev/null +++ b/mount/sources @@ -0,0 +1,17 @@ +TARGETTYPE=PROGRAM +TARGETNAME=nfs_mount +SOURCES=mount.c options.c enum.c +UMTYPE=console +USE_MSVCRT=1 +TARGETLIBS=$(DDK_LIB_PATH)\mpr.lib +INCLUDES=..\sys + +UMENTRY=wmain +UNICODE=1 +C_DEFINES=$(C_DEFINES) -DUNICODE -D_UNICODE + +!IF 0 +/W3 is default level +bump to /Wall, but suppress warnings generated by system includes +!ENDIF +MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4711 diff --git a/nfs41rdr.inf b/nfs41rdr.inf new file mode 100644 index 0000000..02ee912 --- /dev/null +++ b/nfs41rdr.inf @@ -0,0 +1,63 @@ +[Version] +Signature="$CHICAGO$" +DriverVer=05/27/2009,1.0 +ClassGUID={00000000-0000-0000-0000-000000000000} +;Its possible that we should be using: +;Class=NetService +;ClassGUID={4d36e974-e325-11ce-bfc1-08002be10318} +CatalogFile=catalogfile.cat +Provider=%ProviderName% + +[SourceDisksNames] +1=%Disk% + +[SourceDisksFiles] +nfs41_driver.sys=1, +nfs41_np.dll=1, + +[DestinationDirs] +DefaultDestDir=10 ;%windir% +nfs41_driver.sysfile=12 ;%windir%\system32\drivers +nfs41_driver.dllfile=11 ;%windir%\system32 + +[DefaultInstall] +CopyFiles=nfs41_driver.sysfile,nfs41_driver.dllfile +AddReg=nfs41_np.AddReg + +[DefaultInstall.Services] +AddService=%Nfs41RdrServiceName%,,nfs41rdr.Service + +[DefaultUninstall] +DelFiles=nfs41_driver.sysfile,nfs41_driver.dllfile +DelReg=nfs41_driver.DelReg + +[DefaultUninstall.Services] +DelService=%Nfs41RdrServiceName% + +[nfs41_driver.sysfile] +nfs41_driver.sys + +[nfs41_driver.dllfile] +nfs41_np.dll + +[nfs41rdr.Service] +DisplayName=%Nfs41RdrServiceName% +Description=%Nfs41RdrServiceName% +ServiceType=0x00000002 ;SERVICE_FILE_SYSTEM_DRIVER +StartType=0x00000001 ;SERVICE_SYSTEM_START +ErrorControl=0x00000001 ;SERVICE_ERROR_NORMAL +ServiceBinary=%12%\nfs41_driver.sys +LoadOrderGroup=Network + +[nfs41_np.AddReg] +HKLM,SYSTEM\CurrentControlSet\Services\nfs41_driver\NetworkProvider,DeviceName,,\Device\nfs41_driver +HKLM,SYSTEM\CurrentControlSet\Services\nfs41_driver\NetworkProvider,Name,,"NFS41 Network" +HKLM,SYSTEM\CurrentControlSet\Services\nfs41_driver\NetworkProvider,ProviderPath,,System32\nfs41_np.dll + +[nfs41_driver.DelReg] +HKLM,SYSTEM\CurrentControlSet\Services\nfs41_driver + +[Strings] +Nfs41RdrServiceName="nfs41_driver" +Disk="Source files" +ProviderName="NFS41 Provider" diff --git a/sys/makefile b/sys/makefile new file mode 100644 index 0000000..66f1c8e --- /dev/null +++ b/sys/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def + diff --git a/sys/nfs41_debug.c b/sys/nfs41_debug.c new file mode 100644 index 0000000..6e7b27a --- /dev/null +++ b/sys/nfs41_debug.c @@ -0,0 +1,685 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#define MINIRDR__NAME "Value is ignored, only fact of definition" +#include + +#include "nfs41_driver.h" +#include "nfs41_debug.h" +#include +#include +#include +#include + +//#define INCLUDE_TIMESTAMPS + +ULONG __cdecl DbgP(IN PCCH fmt, ...) +{ + CHAR msg[512]; + va_list args; + NTSTATUS status; + + va_start(args, fmt); + ASSERT(fmt != NULL); + status = RtlStringCbVPrintfA(msg, sizeof(msg), fmt, args); + if (NT_SUCCESS(status)) { +#ifdef INCLUDE_TIMESTAMPS + LARGE_INTEGER timestamp, local_time; + TIME_FIELDS time_fields; + + KeQuerySystemTime(×tamp); + ExSystemTimeToLocalTime(×tamp,&local_time); + RtlTimeToTimeFields(&local_time, &time_fields); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "[%ld].[%02u:%02u:%02u.%u] %s", IoGetCurrentProcess(), + time_fields.Hour, time_fields.Minute, time_fields.Second, + time_fields.Milliseconds, msg); +#else + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "[%ld] %s", IoGetCurrentProcess(), msg); +#endif + } + va_end(args); + + return 0; +} + +void print_hexbuf(int on, unsigned char *title, unsigned char *buf, int len) +{ + int j, k; + LARGE_INTEGER timestamp, local_time; + TIME_FIELDS time_fields; + + if (!on) return; + + KeQuerySystemTime(×tamp); + ExSystemTimeToLocalTime(×tamp,&local_time); + RtlTimeToTimeFields(&local_time, &time_fields); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "[%ld].[%02u:%02u:%02u.%u] %s\n", IoGetCurrentProcess(), + time_fields.Hour, time_fields.Minute, time_fields.Second, + time_fields.Milliseconds, title); + for(j = 0, k = 0; j < len; j++, k++) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "%02x ", buf[j]); + if (((k+1) % 30 == 0 && k > 0)) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "\n"); + } + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "\n"); +} + +void print_ioctl(int on, int op) +{ + if(!on) return; + switch(op) { + case IRP_MJ_FILE_SYSTEM_CONTROL: + DbgP("IRP_MJ_FILE_SYSTEM_CONTROL\n"); + break; + case IRP_MJ_DEVICE_CONTROL: + DbgP("IRP_MJ_DEVICE_CONTROL\n"); + break; + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + DbgP("IRP_MJ_INTERNAL_DEVICE_CONTROL\n"); + break; + default: + DbgP("UNKNOWN MJ IRP %d\n", op); + }; +} + +void print_fs_ioctl(int on, int op) +{ + if(!on) return; + switch(op) { + case IOCTL_NFS41_INVALCACHE: + DbgP("IOCTL_NFS41_INVALCACHE\n"); + break; + case IOCTL_NFS41_READ: + DbgP("IOCTL_NFS41_UPCALL\n"); + break; + case IOCTL_NFS41_WRITE: + DbgP("IOCTL_NFS41_DOWNCALL\n"); + break; + case IOCTL_NFS41_ADDCONN: + DbgP("IOCTL_NFS41_ADDCONN\n"); + break; + case IOCTL_NFS41_DELCONN: + DbgP("IOCTL_NFS41_DELCONN\n"); + break; + case IOCTL_NFS41_GETSTATE: + DbgP("IOCTL_NFS41_GETSTATE\n"); + break; + case IOCTL_NFS41_START: + DbgP("IOCTL_NFS41_START\n"); + break; + case IOCTL_NFS41_STOP: + DbgP("IOCTL_NFS41_STOP\n"); + break; + default: + DbgP("UNKNOWN FS IOCTL %d\n", op); + }; +} + +void print_driver_state(int state) +{ + switch (state) { + case NFS41_START_DRIVER_STARTABLE: + DbgP("NFS41_START_DRIVER_STARTABLE\n"); + break; + case NFS41_START_DRIVER_STOPPED: + DbgP("NFS41_START_DRIVER_STOPPED\n"); + break; + case NFS41_START_DRIVER_START_IN_PROGRESS: + DbgP("NFS41_START_DRIVER_START_IN_PROGRESS\n"); + break; + case NFS41_START_DRIVER_STARTED: + DbgP("NFS41_START_DRIVER_STARTED\n"); + break; + default: + DbgP("UNKNOWN DRIVER STATE %d\n", state); + }; + +} + +void print_basic_info(int on, PFILE_BASIC_INFORMATION info) +{ + if (!on) return; + DbgP("BASIC_INFO: Create=%x Access=%x Write=%x Change=%x Attr=%x\n", + info->CreationTime.QuadPart, info->LastAccessTime.QuadPart, + info->LastWriteTime.QuadPart, info->ChangeTime.QuadPart, + info->FileAttributes); +} +void print_std_info(int on, PFILE_STANDARD_INFORMATION info) +{ + if (!on) return; + DbgP("STD_INFO: Type=%s #Links=%d Alloc=%x EOF=%x Delete=%d\n", + info->Directory?"DIR":"FILE", info->NumberOfLinks, + info->AllocationSize, info->EndOfFile, info->DeletePending); +} + +void print_ea_info(int on, PFILE_FULL_EA_INFORMATION info) +{ + if (!on) return; + DbgP("FULL_EA_INFO: NextOffset=%d Flags=%x EaNameLength=%d " + "ExValueLength=%x EaName=%s\n", info->NextEntryOffset, info->Flags, + info->EaNameLength, info->EaValueLength, info->EaName); + if (info->EaValueLength) + print_hexbuf(0, (unsigned char *)"eavalue", + (unsigned char *)info->EaName + info->EaNameLength + 1, + info->EaValueLength); +} + +void print_get_ea(int on, PFILE_GET_EA_INFORMATION info) +{ + if (!on) return; + DbgP("GET_EA_INFO: NextOffset=%d EaNameLength=%d EaName=%s\n", + info->NextEntryOffset, info->EaNameLength, info->EaName); +} + +VOID print_srv_call(int on, IN PMRX_SRV_CALL p) +{ + if (!on) return; + DbgP("PMRX_SRV_CALL %p\n", p); +#if 0 + DbgP("\tNodeReferenceCount %ld\n", p->NodeReferenceCount); + //DbgP("Context %p\n", p->Context); + //DbgP("Context2 %p\n", p->Context2); + //DbgP("pSrvCallName %wZ\n", p->pSrvCallName); + //DbgP("pPrincipalName %wZ\n", p->pPrincipalName); + //DbgP("PDomainName %wZ\n", p->pDomainName); + //DbgP("Flags %08lx\n", p->Flags); + //DbgP("MaximumNumberOfCloseDelayedFiles %ld\n", p->MaximumNumberOfCloseDelayedFiles); + //DbgP("Status %ld\n", p->Status); + DbgP("*****************\n"); +#endif +} + +VOID print_net_root(int on, IN PMRX_NET_ROOT p) +{ + if (!on) return; + DbgP("PMRX_NET_ROOT %p\n", p); +#if 0 + DbgP("\tNodeReferenceCount %ld\n", p->NodeReferenceCount); + DbgP("\tpSrvCall %p\n", p->pSrvCall); + //DbgP("Context %p\n", p->Context); + //DbgP("Context2 %p\n", p->Context2); + //DbgP("Flags %08lx\n", p->Flags); + DbgP("\tNumberOfFcbs %ld\n", p->NumberOfFcbs); + DbgP("\tNumberofSrvOpens %ld\n", p->NumberOfSrvOpens); + //DbgP("MRxNetRootState %ld\n", p->MRxNetRootState); + //DbgP("Type %ld\n", p->Type); + //DbgP("DeviceType %ld\n", p->DeviceType); + //DbgP("pNetRootName %wZ\n", p->pNetRootName); + //DbgP("InnerNamePrefix %wZ\n", &p->InnerNamePrefix); + DbgP("*****************\n"); +#endif +} + +VOID print_v_net_root(int on, IN PMRX_V_NET_ROOT p) +{ + if (!on) return; + DbgP("PMRX_V_NET_ROOT %p\n", p); +#if 0 + DbgP("\tNodeReferenceCount %ld\n", p->NodeReferenceCount); + DbgP("\tpNetRoot %p\n", p->pNetRoot); + //DbgP("Context %p\n", p->Context); + //DbgP("Context2 %p\n", p->Context2); + //DbgP("Flags %08lx\n", p->Flags); + DbgP("\tNumberofOpens %ld\n", p->NumberOfOpens); + DbgP("\tNumberofFobxs %ld\n", p->NumberOfFobxs); + //DbgP("LogonId\n"); + //DbgP("pUserDomainName %wZ\n", p->pUserDomainName); + //DbgP("pUserName %wZ\n", p->pUserName); + //DbgP("pPassword %wZ\n", p->pPassword); + //DbgP("SessionId %ld\n", p->SessionId); + //DbgP("ConstructionStatus %08lx\n", p->ConstructionStatus); + //DbgP("IsExplicitConnection %d\n", p->IsExplicitConnection); + DbgP("*****************\n"); +#endif +} + +void print_file_object(int on, PFILE_OBJECT file) +{ + if (!on) return; + DbgP("FsContext %p FsContext2 %p\n", file->FsContext, file->FsContext2); + DbgP("DeletePending %d ReadAccess %d WriteAccess %d DeleteAccess %d\n", + file->DeletePending, file->WriteAccess, file->DeleteAccess); + DbgP("SharedRead %d SharedWrite %d SharedDelete %d Flags %x\n", + file->SharedRead, file->SharedWrite, file->SharedDelete, file->Flags); +} + +VOID print_fcb(int on, IN PMRX_FCB p) +{ + if (!on) return; + DbgP("PMRX_FCB %p OpenCount %d\n", p, p->OpenCount); +#if 0 + DbgP("\tNodeReferenceCount %ld\n", p->NodeReferenceCount); + DbgP("\tpNetRoot %p\n", p->pNetRoot); + //DbgP("Context %p\n", p->Context); + //DbgP("Context2 %p\n", p->Context2); + //DbgP("FcbState %ld\n", p->FcbState); + //DbgP("UncleanCount %ld\n", p->UncleanCount); + //DbgP("UncachedUncleanCount %ld\n", p->UncachedUncleanCount); + DbgP("\tOpenCount %ld\n", p->OpenCount); + //DbgP("OutstandingLockOperationsCount %ld\n", p->OutstandingLockOperationsCount); + //DbgP("ActualAllocationLength %ull\n", p->ActualAllocationLength); + //DbgP("Attributes %ld\n", p->Attributes); + //DbgP("IsFileWritten %d\n", p->IsFileWritten); + //DbgP("fShouldBeOrphaned %d\n", p->fShouldBeOrphaned); + //DbgP("fMiniInited %ld\n", p->fMiniInited); + //DbgP("CachedNetRootType %c\n", p->CachedNetRootType); + //DbgP("SrvOpenList\n"); + //DbgP("SrvOpenListVersion %ld\n", p->SrvOpenListVersion); + DbgP("*****************\n"); +#endif +} + +VOID print_srv_open(int on, IN PMRX_SRV_OPEN p) +{ + if (!on) return; + DbgP("PMRX_SRV_OPEN %p\n", p); +#if 0 + DbgP("\tNodeReferenceCount %ld\n", p->NodeReferenceCount); + DbgP("\tpFcb %p\n", p->pFcb); + DbgP("\tpVNetRoot %p\n", p->pVNetRoot); + //DbgP("Context %p\n", p->Context); + //DbgP("Context2 %p\n", p->Context2); + //DbgP("Flags %08lx\n", p->Flags); + //DbgP("pAlreadyPrefixedName %wZ\n", p->pAlreadyPrefixedName); + //DbgP("UncleanFobxCount %ld\n", p->UncleanFobxCount); + DbgP("\tOpenCount %ld\n", p->OpenCount); + //DbgP("Key %p\n", p->Key); + //DbgP("DesiredAccess\n"); + //DbgP("ShareAccess %ld\n", p->ShareAccess); + //DbgP("CreateOptions %ld\n", p->CreateOptions); + //DbgP("BufferingFlags %ld\n", p->BufferingFlags); + //DbgP("ulFileSizeVersion %ld\n", p->ulFileSizeVersion); + //DbgP("SrvOpenQLinks\n"); + DbgP("*****************\n"); +#endif +} + +VOID print_fobx(int on, IN PMRX_FOBX p) +{ + if (!on) return; + DbgP("PMRX_FOBX %p\n", p); +#if 0 + DbgP("\tNodeReferenceCount %ld\n", p->NodeReferenceCount); + DbgP("\tpSrvOpen %p\n", p->pSrvOpen); + DbgP("\tAssociatedFileObject %p\n", p->AssociatedFileObject); + //DbgP("Context %p\n", p->Context); + //DbgP("Context2 %p\n", p->Context2); + //DbgP("Flags %08lx\n", p->Flags); + DbgP("*****************\n"); +#endif +} + +VOID print_irp_flags(int on, PIRP irp) +{ + if (!on) return; + DbgP("RxContext->CurrentIrp %p\n", irp); + DbgP("IRP FLAGS:\n"); + if (irp->Flags & IRP_NOCACHE) + DbgP("\tIRP_NOCACHE\n"); + if (irp->Flags & IRP_PAGING_IO) + DbgP("\tIRP_PAGING_IO\n"); + if (irp->Flags & IRP_MOUNT_COMPLETION) + DbgP("\tIRP_MOUNT_COMPLETION\n"); + if (irp->Flags & IRP_SYNCHRONOUS_API) + DbgP("\tIRP_SYNCHRONOUS_API\n"); + if (irp->Flags & IRP_ASSOCIATED_IRP) + DbgP("\tIRP_ASSOCIATED_IRP\n"); + if (irp->Flags & IRP_BUFFERED_IO) + DbgP("\tIRP_BUFFERED_IO\n"); + if (irp->Flags & IRP_DEALLOCATE_BUFFER) + DbgP("\tIRP_DEALLOCATE_BUFFER\n"); + if (irp->Flags & IRP_INPUT_OPERATION) + DbgP("\tIRP_INPUT_OPERATION\n"); + if (irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) + DbgP("\tIRP_SYNCHRONOUS_PAGING_IO\n"); + if (irp->Flags & IRP_CREATE_OPERATION) + DbgP("\tIRP_CREATE_OPERATION\n"); + if (irp->Flags & IRP_READ_OPERATION) + DbgP("\tIRP_READ_OPERATION\n"); + if (irp->Flags & IRP_WRITE_OPERATION) + DbgP("\tIRP_WRITE_OPERATION\n"); + if (irp->Flags & IRP_CLOSE_OPERATION) + DbgP("\tIRP_CLOSE_OPERATION\n"); + if (irp->Flags & IRP_DEFER_IO_COMPLETION) + DbgP("\tIRP_DEFER_IO_COMPLETION\n"); +} + +void print_irps_flags(int on, PIO_STACK_LOCATION irps) +{ + if (!on) return; + DbgP("RxContext->CurrentIrpSp %p\n", irps); + if(irps->Flags & SL_CASE_SENSITIVE) + DbgP("\tSL_CASE_SENSITIVE\n"); + if(irps->Flags & SL_OPEN_PAGING_FILE) + DbgP("\tSL_OPEN_PAGING_FILE\n"); + if(irps->Flags & SL_FORCE_ACCESS_CHECK) + DbgP("\tSL_FORCE_ACCESS_CHECK\n"); + if(irps->Flags & SL_OPEN_TARGET_DIRECTORY) + DbgP("\tSL_OPEN_TARGET_DIRECTORY\n"); +} +void print_nt_create_params(int on, NT_CREATE_PARAMETERS params) +{ + if (!on) return; + DbgP("File attributes %ld: %s %s %s %s %s\n", params.FileAttributes, + (params.FileAttributes & FILE_ATTRIBUTE_TEMPORARY)?"TEMPFILE":"", + (params.FileAttributes & FILE_ATTRIBUTE_READONLY)?"READONLY":"", + (params.FileAttributes & FILE_ATTRIBUTE_HIDDEN)?"HIDDEN":"", + (params.FileAttributes & FILE_ATTRIBUTE_SYSTEM)?"SYSTEM":"", + (params.FileAttributes & FILE_ATTRIBUTE_ARCHIVE)?"ARCHIVE":""); + + if (params.Disposition == FILE_SUPERSEDE) + DbgP("Create Dispositions: FILE_SUPERSEDE\n"); + if (params.Disposition == FILE_CREATE) + DbgP("Create Dispositions: FILE_CREATE\n"); + if (params.Disposition == FILE_OPEN) + DbgP("Create Dispositions: FILE_OPEN\n"); + if (params.Disposition == FILE_OPEN_IF) + DbgP("Create Dispositions: FILE_OPEN_IF\n"); + if (params.Disposition == FILE_OVERWRITE) + DbgP("Create Dispositions: FILE_OVERWRITE\n"); + if (params.Disposition == FILE_OVERWRITE_IF) + DbgP("Create Dispositions: FILE_OVERWRITE_IF\n"); + + DbgP("Create Attributes: %s %s %s\n", + (params.CreateOptions & FILE_DIRECTORY_FILE)?"DIRFILE":"", + (params.CreateOptions & FILE_NON_DIRECTORY_FILE)?"FILE":"", + (params.CreateOptions & FILE_DELETE_ON_CLOSE)?"DELETEONCLOSE":""); + if (on > 1) { + DbgP("More Create Attrss:\n"); + if (params.CreateOptions & FILE_WRITE_THROUGH) + DbgP("\tFILE_WRITE_THROUGH\n"); + if (params.CreateOptions & FILE_SEQUENTIAL_ONLY) + DbgP("\tFILE_SEQUENTIAL_ONLY\n"); + if (params.CreateOptions & FILE_RANDOM_ACCESS) + DbgP("\tFILE_RANDOM_ACCESS\n"); + if (params.CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) + DbgP("\tFILE_NO_INTERMEDIATE_BUFFERING\n"); + if (params.CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) + DbgP("\tFILE_SYNCHRONOUS_IO_ALERT\n"); + if (params.CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT) + DbgP("\tFILE_SYNCHRONOUS_IO_NONALERT\n"); + if (params.CreateOptions & FILE_CREATE_TREE_CONNECTION) + DbgP("\tFILE_CREATE_TREE_CONNECTION\n"); + if (params.CreateOptions & FILE_COMPLETE_IF_OPLOCKED) + DbgP("\tFILE_COMPLETE_IF_OPLOCKED\n"); + if (params.CreateOptions & FILE_NO_EA_KNOWLEDGE) + DbgP("\tFILE_NO_EA_KNOWLEDGE\n"); + if (params.CreateOptions & FILE_OPEN_REPARSE_POINT) + DbgP("\tFILE_OPEN_REPARSE_POINT\n"); + if (params.CreateOptions & FILE_OPEN_BY_FILE_ID) + DbgP("\tFILE_OPEN_BY_FILE_ID\n"); + if (params.CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT) + DbgP("\tFILE_OPEN_FOR_BACKUP_INTENT\n"); + if (params.CreateOptions & FILE_RESERVE_OPFILTER) + DbgP("\tFILE_RESERVE_OPFILTER \n"); + } + + DbgP("Share Access: %s %s %s\n", + (params.ShareAccess & FILE_SHARE_READ)?"READ ":"", + (params.ShareAccess & FILE_SHARE_WRITE)?"WRITE ":"", + (params.ShareAccess & FILE_SHARE_DELETE)?"DELETE":""); + + DbgP("Desired Access: %s %s %s %s %s %s %s %s %s %s %s %s\n", + (params.DesiredAccess & FILE_READ_DATA)?"READ":"", + (params.DesiredAccess & STANDARD_RIGHTS_READ)?"READ_ACL":"", + (params.DesiredAccess & FILE_READ_ATTRIBUTES)?"GETATTR":"", + (params.DesiredAccess & FILE_READ_EA)?"READ_EA":"", + (params.DesiredAccess & FILE_WRITE_DATA)?"WRITE":"", + (params.DesiredAccess & STANDARD_RIGHTS_WRITE)?"WRITE_ACL":"", + (params.DesiredAccess & FILE_WRITE_ATTRIBUTES)?"SETATTR":"", + (params.DesiredAccess & FILE_WRITE_EA)?"WRITE_EA":"", + (params.DesiredAccess & FILE_APPEND_DATA)?"APPEND":"", + (params.DesiredAccess & FILE_EXECUTE)?"EXEC":"", + (params.DesiredAccess & FILE_LIST_DIRECTORY)?"LSDIR":"", + (params.DesiredAccess & FILE_TRAVERSE)?"TRAVERSE":""); +} + +unsigned char * print_file_information_class(int InfoClass) +{ + switch(InfoClass) { + case FileBothDirectoryInformation: + return (unsigned char *)"FileBothDirectoryInformation"; + case FileDirectoryInformation: + return (unsigned char *)"FileDirectoryInformation"; + case FileFullDirectoryInformation: + return (unsigned char *)"FileFullDirectoryInformation"; + case FileIdBothDirectoryInformation: + return (unsigned char *)"FileIdBothDirectoryInformation"; + case FileIdFullDirectoryInformation: + return (unsigned char *)"FileIdFullDirectoryInformation"; + case FileNamesInformation: + return (unsigned char *)"FileNamesInformation"; + case FileObjectIdInformation: + return (unsigned char *)"FileObjectIdInformation"; + case FileQuotaInformation: + return (unsigned char *)"FileQuotaInformation"; + case FileReparsePointInformation: + return (unsigned char *)"FileReparsePointInformation"; + case FileAllInformation: + return (unsigned char *)"FileAllInformation"; + case FileAttributeTagInformation: + return (unsigned char *)"FileAttributeTagInformation"; + case FileBasicInformation: + return (unsigned char *)"FileBasicInformation"; + case FileCompressionInformation: + return (unsigned char *)"FileCompressionInformation"; + case FileEaInformation: + return (unsigned char *)"FileEaInformation"; + case FileInternalInformation: + return (unsigned char *)"FileInternalInformation"; + case FileNameInformation: + return (unsigned char *)"FileNameInformation"; + case FileNetworkOpenInformation: + return (unsigned char *)"FileNetworkOpenInformation"; + case FilePositionInformation: + return (unsigned char *)"FilePositionInformation"; + case FileStandardInformation: + return (unsigned char *)"FileStandardInformation"; + case FileStreamInformation: + return (unsigned char *)"FileStreamInformation"; + case FileAllocationInformation: + return (unsigned char *)"FileAllocationInformation"; + case FileDispositionInformation: + return (unsigned char *)"FileDispositionInformation"; + case FileEndOfFileInformation: + return (unsigned char *)"FileEndOfFileInformation"; + case FileLinkInformation: + return (unsigned char *)"FileLinkInformation"; + case FileRenameInformation: + return (unsigned char *)"FileRenameInformation"; + case FileValidDataLengthInformation: + return (unsigned char *)"FileValidDataLengthInformation"; + default: + return (unsigned char *)"UNKNOWN"; + } +} + +unsigned char *print_fs_information_class(int InfoClass) +{ + switch (InfoClass) { + case FileFsAttributeInformation: + return (unsigned char *)"FileFsAttributeInformation"; + case FileFsControlInformation: + return (unsigned char *)"FileFsControlInformation"; + case FileFsDeviceInformation: + return (unsigned char *)"FileFsDeviceInformation"; + case FileFsDriverPathInformation: + return (unsigned char *)"FileFsDriverPathInformation"; + case FileFsFullSizeInformation: + return (unsigned char *)"FileFsFullSizeInformation"; + case FileFsObjectIdInformation: + return (unsigned char *)"FileFsObjectIdInformation"; + case FileFsSizeInformation: + return (unsigned char *)"FileFsSizeInformation"; + case FileFsVolumeInformation: + return (unsigned char *)"FileFsVolumeInformation"; + default: + return (unsigned char *)"UNKNOWN"; + } +} + +void print_caching_level(int on, ULONG flag) +{ + if (!on) return; + switch(flag) { + case 0: + DbgP("DISABLE_CACHING\n"); + break; + case 1: + DbgP("ENABLE_READ_CACHING\n"); + break; + case 2: + DbgP("ENABLE_WRITE_CACHING\n"); + break; + case 3: + DbgP("ENABLE_READWRITE_CACHING\n"); + break; + } +} + +const char *opcode2string(int opcode) +{ + switch(opcode) { + case NFS41_SHUTDOWN: return "NFS41_SHUTDOWN"; + case NFS41_MOUNT: return "NFS41_MOUNT"; + case NFS41_UNMOUNT: return "NFS41_UNMOUNT"; + case NFS41_OPEN: return "NFS41_OPEN"; + case NFS41_CLOSE: return "NFS41_CLOSE"; + case NFS41_READ: return "NFS41_READ"; + case NFS41_WRITE: return "NFS41_WRITE"; + case NFS41_LOCK: return "NFS41_LOCK"; + case NFS41_UNLOCK: return "NFS41_UNLOCK"; + case NFS41_DIR_QUERY: return "NFS41_DIR_QUERY"; + case NFS41_FILE_QUERY: return "NFS41_FILE_QUERY"; + case NFS41_FILE_SET: return "NFS41_FILE_SET"; + case NFS41_EA_SET: return "NFS41_EA_SET"; + case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY"; + default: return "UNKNOWN"; + } +} + +void print_open_error(int on, int status) +{ + switch (status) { + case ERROR_ACCESS_DENIED: + DbgP("[ERROR] nfs41_Create: STATUS_NETWORK_ACCESS_DENIED\n"); + break; + case ERROR_INVALID_NAME: + DbgP("[ERROR] nfs41_Create: STATUS_OBJECT_NAME_INVALID\n"); + break; + case ERROR_FILE_EXISTS: + DbgP("[ERROR] nfs41_Create: ERROR_FILE_EXISTS\n"); + break; + case ERROR_FILE_INVALID: + DbgP("[ERROR] nfs41_Create: STATUS_FILE_INVALID\n"); + break; + case ERROR_FILE_NOT_FOUND: + DbgP("[ERROR] nfs41_Create: ERROR_FILE_NOT_FOUND\n"); + break; + case ERROR_FILENAME_EXCED_RANGE: + DbgP("[ERROR] nfs41_Create: STATUS_NAME_TOO_LONG\n"); + break; + case ERROR_NETWORK_ACCESS_DENIED: + DbgP("[ERROR] nfs41_Create: ERROR_NETWORK_ACCESS_DENIED\n"); + break; + case ERROR_PATH_NOT_FOUND: + DbgP("[ERROR] nfs41_Create: STATUS_OBJECT_PATH_NOT_FOUND\n"); + break; + case ERROR_SHARING_VIOLATION: + DbgP("[ERROR] nfs41_Create: STATUS_SHARING_VIOLATION\n"); + break; + default: + DbgP("[ERROR] nfs41_Create: upcall returned %d returning " + "STATUS_INSUFFICIENT_RESOURCES\n", status); + case ERROR_OUTOFMEMORY: + DbgP("[ERROR] nfs41_Create: STATUS_INSUFFICIENT_RESOURCES\n"); + } +} + +void print_wait_status(int on, const char *prefix, NTSTATUS status, + const char *opcode, PVOID entry, int xid) +{ + switch (status) { + case STATUS_SUCCESS: + if (opcode) + DbgP("%s Got a wakeup call, finishing %s entry=%p xid=%d\n", + prefix, opcode, entry, xid); + else + DbgP("%s Got a wakeup call\n", prefix); + break; + case STATUS_USER_APC: + DbgP("%s KeWaitForSingleObject returned STATUS_USER_APC\n", prefix); + break; + case STATUS_ALERTED: + DbgP("%s KeWaitForSingleObject returned STATUS_ALERTED\n", prefix); + break; + default: + DbgP("%s KeWaitForSingleObject returned %d\n", prefix, status); + } +} +/* This is taken from toaster/func. Rumor says this should be replaced + * with a WMI interface??? + */ +ULONG +dprintk( + IN PCHAR func, + IN ULONG flags, + IN PCHAR format, + ...) +{ + #define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status, rv = STATUS_SUCCESS; + + va_start(list, format); + + if (format) + { + // + // Use the safe string function, RtlStringCbVPrintfA, instead of _vsnprintf. + // RtlStringCbVPrintfA NULL terminates the output buffer even if the message + // is longer than the buffer. This prevents malicious code from compromising + // the security of the system. + // + status = RtlStringCbVPrintfA(debugMessageBuffer, sizeof(debugMessageBuffer), + format, list); + + if (!NT_SUCCESS(status)) + rv = DbgPrintEx(PNFS_FLTR_ID, DPFLTR_MASK | flags, + "RtlStringCbVPrintfA failed %x \n", status); + else + rv = DbgPrintEx(PNFS_FLTR_ID, DPFLTR_MASK | flags, "%s %s: %s\n", + PNFS_TRACE_TAG, func, debugMessageBuffer); + } + va_end(list); + + return rv; +} + diff --git a/sys/nfs41_debug.h b/sys/nfs41_debug.h new file mode 100644 index 0000000..48ab491 --- /dev/null +++ b/sys/nfs41_debug.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef _NFS41_DEBUG_ +#define _NFS41_DEBUG_ + +#define _DRIVER_NAME_ "NFS4.1 Driver" + +ULONG __cdecl DbgP(IN PCCH fmt, ...); +VOID print_srv_call(int on, IN PMRX_SRV_CALL p); +VOID print_net_root(int on, IN PMRX_NET_ROOT p); +VOID print_v_net_root(int on, IN PMRX_V_NET_ROOT p); +VOID print_fcb(int on, IN PMRX_FCB p); +VOID print_srv_open(int on, IN PMRX_SRV_OPEN p); +VOID print_fobx(int on, IN PMRX_FOBX p); +VOID print_irp_flags(int on, PIRP irp); +VOID print_irps_flags(int on, PIO_STACK_LOCATION irps); +void print_nt_create_params(int on, NT_CREATE_PARAMETERS params); +unsigned char *print_file_information_class(int InfoClass); +unsigned char *print_fs_information_class(int InfoClass); +void print_hexbuf(int on, unsigned char *title, unsigned char *buf, int len); +void print_ioctl(int on, int op); +void print_fs_ioctl(int on, int op); +void print_driver_state(int state); +void print_file_object(int on, PFILE_OBJECT file); +void print_basic_info(int on, PFILE_BASIC_INFORMATION info); +void print_std_info(int on, PFILE_STANDARD_INFORMATION info); +void print_ea_info(int on, PFILE_FULL_EA_INFORMATION info); +void print_get_ea(int on, PFILE_GET_EA_INFORMATION info); +void print_caching_level(int on, ULONG flag); +const char *opcode2string(int opcode); +void print_open_error(int on, int status); +void print_wait_status(int on, const char *str, NTSTATUS status, + const char *opcode, PVOID entry, int xid); + +#define DbgEn() DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \ + "--> [%s] [%d] %s\n", _DRIVER_NAME_, IoGetCurrentProcess(), \ + __FUNCTION__); try { + +#define DbgEx() DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \ + "<-- [%s] [%d] %s status = %08lx\n", _DRIVER_NAME_, IoGetCurrentProcess(), \ + __FUNCTION__, status); \ + } except (EXCEPTION_EXECUTE_HANDLER) { \ + status = GetExceptionCode() ; \ + DbgP("Exception encountered with value = Ox%x\n", status); \ + } +#define DbgR() DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, \ + "<-- [%s] [%d] %s\n", _DRIVER_NAME_, IoGetCurrentProcess(), __FUNCTION__); \ + } except (EXCEPTION_EXECUTE_HANDLER) { \ + NTSTATUS status; \ + status = GetExceptionCode() ; \ + DbgP("Exception encountered with value = Ox%x\n", status); \ + } + +/* These are for ToasterDebugPrint */ + +#define DBG_ERROR 0x00000001 +#define DBG_WARN 0x00000002 +#define DBG_TRACE 0x00000004 +#define DBG_INFO 0x00000008 +#define DBG_DISP_IN 0x00000010 /* Marks entry into dispatch functions */ +#define DBG_DISP_OUT 0x00000020 /* Marks exit from dispatch functions */ + +/* I want to do: + * #define dprintk(flags, args...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_MASK | flags, ## args) + * but the ... is gcc specific, can't seem to do it here. + */ +#define PNFS_TRACE_TAG "PNFSMRX: " +#define PNFS_FLTR_ID DPFLTR_IHVDRIVER_ID + +#define DbgEnter() DbgPrintEx(PNFS_FLTR_ID, DPFLTR_MASK | DBG_DISP_IN, "%s*** %s ***\n", \ + PNFS_TRACE_TAG, __FUNCTION__); +#define DbgExit(status) DbgPrintEx(PNFS_FLTR_ID, DPFLTR_MASK | DBG_DISP_OUT, "%s<-- %s <-- 0x%08lx\n", \ + PNFS_TRACE_TAG, __FUNCTION__, status); +ULONG +dprintk( + IN PCHAR func, + IN ULONG flags, + IN PCHAR format, + ...); +#endif \ No newline at end of file diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c new file mode 100644 index 0000000..dcef2d4 --- /dev/null +++ b/sys/nfs41_driver.c @@ -0,0 +1,4499 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#define MINIRDR__NAME "Value is ignored, only fact of definition" +#include +#include +#include + +#include + +#include "nfs41_driver.h" +#include "nfs41_np.h" +#include "nfs41_debug.h" + +//#define DEBUG_CLOSE + +DRIVER_INITIALIZE DriverEntry; +DRIVER_UNLOAD nfs41_driver_unload; +DRIVER_DISPATCH ( nfs41_FsdDispatch ); + +struct _MINIRDR_DISPATCH nfs41_ops; +PRDBSS_DEVICE_OBJECT nfs41_dev; + +#define FCB_BASIC_INFO_CACHED 0x0001 +#define FCB_STANDARD_INFO_CACHED 0x0010 + +#define DISABLE_CACHING 0 +#define ENABLE_READ_CACHING 1 +#define ENABLE_WRITE_CACHING 2 +#define ENABLE_READWRITE_CACHING 3 + +#define NFS41_MM_POOLTAG ('nfs4') + +KEVENT upcallEvent; +FAST_MUTEX upcallLock, downcallLock; +FAST_MUTEX xidLock; +FAST_MUTEX openOwnerLock; + +ULONG xid = 0; +ULONG open_owner_id = 1; + +#define DECLARE_CONST_ANSI_STRING(_var, _string) \ + const CHAR _var ## _buffer[] = _string; \ + const ANSI_STRING _var = { sizeof(_string) - sizeof(CHAR), \ + sizeof(_string), (PCH) _var ## _buffer } + +DECLARE_CONST_ANSI_STRING(NfsV3Attributes, "NfsV3Attributes"); +DECLARE_CONST_ANSI_STRING(NfsSymlinkTargetName, "NfsSymlinkTargetName"); +DECLARE_CONST_ANSI_STRING(NfsActOnLink, "NfsActOnLink"); + +static INLINE BOOL AnsiStrEq( + IN const ANSI_STRING *lhs, + IN const CHAR *rhs, + IN const UCHAR rhs_len) +{ + return lhs->Length == rhs_len && + RtlCompareMemory(lhs->Buffer, rhs, rhs_len) == rhs_len; +} + +typedef struct _nfs3_attrs { + DWORD type, mode, nlink, uid, gid, filler1; + LARGE_INTEGER size, used; + struct { + DWORD specdata1; + DWORD specdata2; + } rdev; + LONGLONG fsid, fileid; + LARGE_INTEGER atime, mtime, ctime; +} nfs3_attrs; + +enum ftype3 { + NF3REG = 1, + NF3DIR, + NF3BLK, + NF3CHR, + NF3LNK, + NF3SOCK, + NF3FIFO +}; + +typedef enum _nfs41_updowncall_state { + NFS41_WAITING_FOR_UPCALL, + NFS41_WAITING_FOR_DOWNCALL, + NFS41_DONE_PROCESSING, + NFS41_NOT_WAITING +} nfs41_updowncall_state; + +typedef struct _updowncall_entry { + DWORD xid; + DWORD opcode; + NTSTATUS status; + nfs41_updowncall_state state; + FAST_MUTEX lock; + LIST_ENTRY next; + KEVENT cond; + DWORD errno; + BOOLEAN async_op; + union { + struct { + PUNICODE_STRING srv_name; + PUNICODE_STRING root; + HANDLE session; + } Mount; + struct { + HANDLE open_state; + HANDLE session; + PMDL MdlAddress; + PVOID buf; + LONGLONG offset; + ULONG len; + PRX_CONTEXT rxcontext; + } ReadWrite; + struct { + HANDLE open_state; + HANDLE session; + HANDLE handle; + LONGLONG offset; + LONGLONG length; + BOOLEAN exclusive; + BOOLEAN blocking; + } Lock; + struct { + HANDLE open_state; + HANDLE session; + ULONG count; + LOWIO_LOCK_LIST locks; + } Unlock; + struct { + FILE_BASIC_INFORMATION binfo; + FILE_STANDARD_INFORMATION sinfo; + HANDLE session; + HANDLE open_state; + PUNICODE_STRING filename; + ULONG access_mask; + ULONG access_mode; + ULONG attrs; + ULONG copts; + ULONG disp; + ULONG cattrs; + ULONG open_owner_id; + DWORD mode; + LONGLONG changeattr; + } Open; + struct { + HANDLE open_state; + HANDLE session; + PUNICODE_STRING filename; + BOOLEAN remove; + BOOLEAN renamed; + } Close; + struct { + HANDLE readdir_cookie; + HANDLE open_state; + HANDLE session; + PUNICODE_STRING filter; + PVOID buf; + ULONG buf_len; + FILE_INFORMATION_CLASS InfoClass; + BOOLEAN restart_scan; + BOOLEAN return_single; + BOOLEAN initial_query; + } QueryFile; + struct { + HANDLE open_state; + HANDLE session; + PUNICODE_STRING filename; + PVOID buf; + ULONG buf_len; + FILE_INFORMATION_CLASS InfoClass; + ULONG open_owner_id; + ULONG access_mask; + ULONG access_mode; + } SetFile; + struct { + HANDLE open_state; + HANDLE session; + DWORD mode; + } SetEa; + struct { + HANDLE session; + ULONGLONG total; + ULONGLONG user; + ULONGLONG avail; + } Volume; + } u; + +} nfs41_updowncall_entry; + +typedef struct _updowncall_list { + LIST_ENTRY head; +} nfs41_updowncall_list; +nfs41_updowncall_list *upcall = NULL, *downcall = NULL; + +#define nfs41_AddEntry(lock,pList,pEntry) \ + ExAcquireFastMutex(&lock); \ + InsertTailList(&pList->head, &(pEntry)->next); \ + ExReleaseFastMutex(&lock); +#define nfs41_RemoveFirst(lock,pList,pEntry) \ + ExAcquireFastMutex(&lock); \ + pEntry = (IsListEmpty(&pList->head) \ + ? NULL \ + : RemoveHeadList(&pList->head)); \ + ExReleaseFastMutex(&lock); +#define nfs41_RemoveLast(lock,pList,pEntry) \ + ExAcquireFastMutex(&lock); \ + pEntry = RemoveTailList(&pList->head); \ + ExReleaseFastMutex(&lock); +#define nfs41_RemoveEntry(lock,pList,pEntry) \ + ExAcquireFastMutex(&lock); \ + RemoveEntryList(&pEntry->next); \ + ExReleaseFastMutex(&lock); +#define nfs41_IsListEmpty(lock,pList,flag) \ + ExAcquireFastMutex(&lock); \ + *flag = IsListEmpty(&pList->head); \ + ExReleaseFastMutex(&lock); +#define nfs41_GetFirstEntry(lock,pList,pEntry) \ + ExAcquireFastMutex(&lock); \ + pEntry = (IsListEmpty(&pList->head) \ + ? NULL \ + : (nfs41_updowncall_entry *) \ + (CONTAINING_RECORD(pList->head.Flink, \ + nfs41_updowncall_entry, \ + next))); \ + ExReleaseFastMutex(&lock); +#define nfs41_GetNextEntry(pList,pEntry) \ + ((pEntry->next.Flink == &pList->head) \ + ? NULL \ + : (nfs41_updowncall_entry *) \ + (CONTAINING_RECORD(pEntry->next.Flink, \ + nfs41_updowncall_entry, \ + next))); + +/* In order to cooperate with other network providers, + * we only claim paths of the format '\\server\nfs4\path' */ +DECLARE_CONST_UNICODE_STRING(NfsPrefix, L"\\nfs4"); + +#define SERVER_NAME_BUFFER_SIZE 1024 + +#define MOUNT_CONFIG_RW_SIZE_MIN 1024 +#define MOUNT_CONFIG_RW_SIZE_DEFAULT 32768 +#define MOUNT_CONFIG_RW_SIZE_MAX 65536 + +typedef struct _NFS41_MOUNT_CONFIG { + DWORD ReadSize; + DWORD WriteSize; + BOOLEAN ReadOnly; + WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE]; + UNICODE_STRING SrvName; + WCHAR mntpt_buffer[MAX_PATH]; + UNICODE_STRING MntPt; + BOOLEAN Initialized; +} NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG; + +typedef struct _NFS41_NETROOT_EXTENSION { + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + NFS41_MOUNT_CONFIG Config; + HANDLE session; +} NFS41_NETROOT_EXTENSION, *PNFS41_NETROOT_EXTENSION; +#define NFS41GetNetRootExtension(pNetRoot) \ + (((pNetRoot) == NULL) ? NULL : (PNFS41_NETROOT_EXTENSION)((pNetRoot)->Context)) + +typedef struct _NFS41_V_NET_ROOT_EXTENSION { + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + NFS41_MOUNT_CONFIG Config; + HANDLE session; +} NFS41_V_NET_ROOT_EXTENSION, *PNFS41_V_NET_ROOT_EXTENSION; +#define NFS41GetVNetRootExtension(pVNetRoot) \ + (((pVNetRoot) == NULL) ? NULL : \ + (PNFS41_V_NET_ROOT_EXTENSION)((pVNetRoot)->Context)) + +typedef struct _NFS41_FCB { + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + ULONG Flags; + FILE_BASIC_INFORMATION BasicInfo; + FILE_STANDARD_INFORMATION StandardInfo; + BOOLEAN Renamed; + DWORD mode; + LONGLONG changeattr; +} NFS41_FCB, *PNFS41_FCB; +#define NFS41GetFcbExtension(pFcb) \ + (((pFcb) == NULL) ? NULL : (PNFS41_FCB)((pFcb)->Context)) + +typedef struct _NFS41_SRV_OPEN { + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; +} NFS41_SRV_OPEN, *PNFS41_SRV_OPEN; +#define NFS41GetSrvOpenExtension(pSrvOpen) \ + (((pSrvOpen) == NULL) ? NULL : (PNFS41_SRV_OPEN)((pSrvOpen)->Context)) + +typedef struct _NFS41_FOBX { + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + + HANDLE nfs41_open_state; + HANDLE nfs41_readdir_cookie; +} NFS41_FOBX, *PNFS41_FOBX; +#define NFS41GetFileObjectExtension(pFobx) \ + (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context)) + +typedef struct _NFS41_SERVER_ENTRY { + PMRX_SRV_CALL pRdbssSrvCall; + WCHAR NameBuffer[SERVER_NAME_BUFFER_SIZE]; + UNICODE_STRING Name; // the server name. +} NFS41_SERVER_ENTRY, *PNFS41_SERVER_ENTRY; + +typedef struct _NFS41_DEVICE_EXTENSION { + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + PRDBSS_DEVICE_OBJECT DeviceObject; + ULONG ActiveNodes; + HANDLE SharedMemorySection; +} NFS41_DEVICE_EXTENSION, *PNFS41_DEVICE_EXTENSION; + +#define NFS41GetDeviceExtension(RxContext,pExt) \ + PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \ + ((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT)) + +typedef enum _NULMRX_STORAGE_TYPE_CODES { + NTC_NFS41_DEVICE_EXTENSION = (NODE_TYPE_CODE)0xFC00, +} NFS41_STORAGE_TYPE_CODES; +#define RxDefineNode( node, type ) \ + node->NodeTypeCode = NTC_##type; \ + node->NodeByteSize = sizeof(type); + +#define RDR_NULL_STATE 0 +#define RDR_UNLOADED 1 +#define RDR_UNLOADING 2 +#define RDR_LOADING 3 +#define RDR_LOADED 4 +#define RDR_STOPPED 5 +#define RDR_STOPPING 6 +#define RDR_STARTING 7 +#define RDR_STARTED 8 + +nfs41_init_driver_state nfs41_init_state = NFS41_INIT_DRIVER_STARTABLE; +nfs41_start_driver_state nfs41_start_state = NFS41_START_DRIVER_STARTABLE; + +static NTSTATUS map_readwrite_errors(DWORD status); + +ULONG get_next_xid() { + ULONG x; + ExAcquireFastMutex(&xidLock); + x = ++xid; + ExReleaseFastMutex(&xidLock); + return x; +} + +ULONG get_next_open_owner() { + ULONG x; + ExAcquireFastMutex(&openOwnerLock); + x = open_owner_id++; + ExReleaseFastMutex(&openOwnerLock); + return x; +} + +void print_debug_header(PRX_CONTEXT RxContext) +{ + + PIO_STACK_LOCATION IrpSp = RxContext->CurrentIrpSp; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot); + PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + + if (IrpSp) { + DbgP("FileOject %p Filename %wZ %wZ\n", IrpSp->FileObject, + &IrpSp->FileObject->FileName, SrvOpen->pAlreadyPrefixedName); + print_file_object(0, IrpSp->FileObject); + } else + DbgP("Couldn't print FileObject IrpSp is NULL\n"); + print_fcb(1, RxContext->pFcb); + print_srv_open(1, RxContext->pRelevantSrvOpen); + print_fobx(1, RxContext->pFobx); + if (RxContext->pFobx) { + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + DbgP("Session=0x%x OpenState=0x%x\n", pVNetRootContext->session, + nfs41_fobx->nfs41_open_state); + } +} + +NTSTATUS marshal_nfs41_header(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + header_len = sizeof(entry->xid) + sizeof(entry->opcode); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + else + *len = header_len; + RtlCopyMemory(tmp, &entry->xid, sizeof(entry->xid)); + tmp += sizeof(xid); + RtlCopyMemory(tmp, &entry->opcode, sizeof(entry->opcode)); + + DbgP("[upcall] entry=%p xid=%d opcode=%d\n", entry, entry->xid, entry->opcode); +out: + return status; +} + +NTSTATUS marshal_nfs41_mount(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + entry->u.Mount.srv_name->Length + + sizeof(entry->u.Mount.srv_name->Length) + entry->u.Mount.root->Length + + sizeof(entry->u.Mount.root->Length); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.Mount.srv_name->Length, + sizeof(entry->u.Mount.srv_name->Length)); + tmp += sizeof(entry->u.Mount.srv_name->Length); + RtlCopyMemory(tmp, entry->u.Mount.srv_name->Buffer, + entry->u.Mount.srv_name->Length); + tmp += entry->u.Mount.srv_name->Length; + RtlCopyMemory(tmp, &entry->u.Mount.root->Length, + sizeof(entry->u.Mount.root->Length)); + tmp += sizeof(entry->u.Mount.root->Length); + RtlCopyMemory(tmp, entry->u.Mount.root->Buffer, entry->u.Mount.root->Length); + + *len = header_len; + + DbgP("server name=%wZ mount point=%wZ\n", + entry->u.Mount.srv_name, entry->u.Mount.root); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_unmount(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + + + header_len = *len + sizeof(HANDLE); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.Mount.session, sizeof(HANDLE)); + + *len = header_len; + + DbgP("session=0x%x\n", entry->u.Mount.session); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_open(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + entry->u.Open.filename->Length + + sizeof(entry->u.Open.filename->Length) + 6 * sizeof(ULONG) + sizeof(HANDLE) + + sizeof(DWORD); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.Open.filename->Length, + sizeof(entry->u.Open.filename->Length)); + tmp += sizeof(entry->u.Open.filename->Length); + RtlCopyMemory(tmp, entry->u.Open.filename->Buffer, entry->u.Open.filename->Length); + tmp += entry->u.Open.filename->Length; + + RtlCopyMemory(tmp, &entry->u.Open.access_mask, sizeof(entry->u.Open.access_mask)); + tmp += sizeof(entry->u.Open.access_mask); + RtlCopyMemory(tmp, &entry->u.Open.access_mode, sizeof(entry->u.Open.access_mode)); + tmp += sizeof(entry->u.Open.access_mode); + RtlCopyMemory(tmp, &entry->u.Open.attrs, sizeof(entry->u.Open.attrs)); + tmp += sizeof(entry->u.Open.attrs); + RtlCopyMemory(tmp, &entry->u.Open.copts, sizeof(entry->u.Open.copts)); + tmp += sizeof(entry->u.Open.copts); + RtlCopyMemory(tmp, &entry->u.Open.disp, sizeof(entry->u.Open.disp)); + tmp += sizeof(entry->u.Open.disp); + RtlCopyMemory(tmp, &entry->u.Open.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Open.open_owner_id, + sizeof(entry->u.Open.open_owner_id)); + tmp += sizeof(entry->u.Open.open_owner_id); + RtlCopyMemory(tmp, &entry->u.Open.mode, sizeof(DWORD)); + + *len = header_len; + + DbgP("mask=0x%x mode=0x%x attrs=0x%x opts=0x%x dispo=0x%x " + "session=0x%x open_owner_id=0x%x mode=%o\n", + entry->u.Open.access_mask, entry->u.Open.access_mode, + entry->u.Open.attrs, entry->u.Open.copts, entry->u.Open.disp, + entry->u.Open.session, entry->u.Open.open_owner_id, + entry->u.Open.mode); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_rw(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + sizeof(entry->u.ReadWrite.len) + + sizeof(entry->u.ReadWrite.offset) + 3 * sizeof(HANDLE); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + RtlCopyMemory(tmp, &entry->u.ReadWrite.len, sizeof(entry->u.ReadWrite.len)); + tmp += sizeof(entry->u.ReadWrite.len); + RtlCopyMemory(tmp, &entry->u.ReadWrite.offset, sizeof(entry->u.ReadWrite.offset)); + tmp += sizeof(entry->u.ReadWrite.offset); + __try { + entry->u.ReadWrite.buf = + MmMapLockedPagesSpecifyCache(entry->u.ReadWrite.MdlAddress, + UserMode, MmCached, NULL, FALSE, NormalPagePriority); + DbgP("MdlAddress=%p Userspace=%p\n", entry->u.ReadWrite.MdlAddress, + entry->u.ReadWrite.buf); + } __except(EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS code; + code = GetExceptionCode(); + DbgP("Call to MmMapLocked failed due to exception 0x%0x\n", code); + status = STATUS_ACCESS_DENIED; + goto out; + } + RtlCopyMemory(tmp, &entry->u.ReadWrite.buf, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.ReadWrite.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.ReadWrite.open_state, sizeof(HANDLE)); + + *len = header_len; + + DbgP("len=%u offset=%lu session=0x%p open_state=0x%p\n", + entry->u.ReadWrite.len, entry->u.ReadWrite.offset, + entry->u.ReadWrite.session, entry->u.ReadWrite.open_state); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_lock(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + PULONG len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + + header_len = *len + 2 * sizeof(HANDLE) + 2 * sizeof(LONGLONG) + + 2 * sizeof(BOOLEAN); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.Lock.open_state, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Lock.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Lock.offset, sizeof(LONGLONG)); + tmp += sizeof(LONGLONG); + RtlCopyMemory(tmp, &entry->u.Lock.length, sizeof(LONGLONG)); + tmp += sizeof(LONGLONG); + RtlCopyMemory(tmp, &entry->u.Lock.exclusive, sizeof(BOOLEAN)); + tmp += sizeof(BOOLEAN); + RtlCopyMemory(tmp, &entry->u.Lock.blocking, sizeof(BOOLEAN)); + tmp += sizeof(BOOLEAN); + + *len = header_len; + + DbgP("session=%p open_state=%p offset=%llx length=%llx " + "exclusive=%u blocking=%u\n", + entry->u.Lock.open_state, entry->u.Lock.session, + entry->u.Lock.offset, entry->u.Lock.length, + entry->u.Lock.exclusive, entry->u.Lock.blocking); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_unlock(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + PULONG len) +{ + NTSTATUS status; + ULONG header_len = 0; + unsigned char *tmp = buf; + PLOWIO_LOCK_LIST lock; + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + + header_len = *len + 2 * sizeof(HANDLE) + sizeof(ULONG) + + entry->u.Unlock.count * 2 * sizeof(LONGLONG); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.Unlock.open_state, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Unlock.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Unlock.count, sizeof(ULONG)); + tmp += sizeof(ULONG); + + lock = &entry->u.Unlock.locks; + while (lock) { + RtlCopyMemory(tmp, &lock->ByteOffset, sizeof(LONGLONG)); + tmp += sizeof(LONGLONG); + RtlCopyMemory(tmp, &lock->Length, sizeof(LONGLONG)); + tmp += sizeof(LONGLONG); + lock = lock->Next; + } + + *len = header_len; + + DbgP("session=%p open_state=%p count=%u\n", + entry->u.Unlock.open_state, entry->u.Unlock.session, + entry->u.Unlock.count); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_close(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + + + header_len = *len + 2 * sizeof(HANDLE) + sizeof(BOOLEAN); + if (entry->u.Close.remove) { + header_len += entry->u.Close.filename->Length + + sizeof(entry->u.Close.filename->Length) + + sizeof(BOOLEAN); + } + + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.Close.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Close.open_state, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.Close.remove, sizeof(BOOLEAN)); + if (entry->u.Close.remove) { + tmp += sizeof(BOOLEAN); + RtlCopyMemory(tmp, &entry->u.Close.filename->Length, + sizeof(entry->u.Close.filename->Length)); + tmp += sizeof(entry->u.Close.filename->Length); + RtlCopyMemory(tmp, entry->u.Close.filename->Buffer, + entry->u.Close.filename->Length); + tmp += entry->u.Close.filename->Length; + RtlCopyMemory(tmp, &entry->u.Close.renamed, sizeof(BOOLEAN)); + } + + *len = header_len; + + DbgP("session=0x%x open_state=0x%x remove=%d renamed=%d filename=%wZ\n", + entry->u.Close.session, entry->u.Close.open_state, + entry->u.Close.remove, entry->u.Close.renamed, + entry->u.Close.filename); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_dirquery(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + + header_len = *len + 2 * sizeof(ULONG) + entry->u.QueryFile.filter->Length + + sizeof(entry->u.QueryFile.filter->Length) + + 3 * sizeof(BOOLEAN) + 3 * sizeof(HANDLE); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + RtlCopyMemory(tmp, &entry->u.QueryFile.InfoClass, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, &entry->u.QueryFile.buf_len, sizeof(ULONG)); + tmp += sizeof(ULONG); + + RtlCopyMemory(tmp, &entry->u.QueryFile.filter->Length, + sizeof(entry->u.QueryFile.filter->Length)); + tmp += sizeof(entry->u.QueryFile.filter->Length); + RtlCopyMemory(tmp, entry->u.QueryFile.filter->Buffer, + entry->u.QueryFile.filter->Length); + tmp += entry->u.QueryFile.filter->Length; + + RtlCopyMemory(tmp, &entry->u.QueryFile.initial_query, sizeof(BOOLEAN)); + tmp += sizeof(BOOLEAN); + RtlCopyMemory(tmp, &entry->u.QueryFile.restart_scan, sizeof(BOOLEAN)); + tmp += sizeof(BOOLEAN); + RtlCopyMemory(tmp, &entry->u.QueryFile.return_single, sizeof(BOOLEAN)); + tmp += sizeof(BOOLEAN); + RtlCopyMemory(tmp, &entry->u.QueryFile.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.QueryFile.open_state, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.QueryFile.readdir_cookie, sizeof(HANDLE)); + + *len = header_len; + + DbgP("filter='%wZ' class=%d\n\t1st\\restart\\single=%d\\%d\\%d " + "session=0x%x open_state=0x%x readdir_cookie=0x%x\n", + entry->u.QueryFile.filter, entry->u.QueryFile.InfoClass, + entry->u.QueryFile.initial_query, entry->u.QueryFile.restart_scan, + entry->u.QueryFile.return_single, entry->u.QueryFile.session, + entry->u.QueryFile.open_state, entry->u.QueryFile.readdir_cookie); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_filequery(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + 2 * sizeof(ULONG) + 2 * sizeof(HANDLE); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlCopyMemory(tmp, &entry->u.QueryFile.InfoClass, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, &entry->u.QueryFile.buf_len, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, &entry->u.QueryFile.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.QueryFile.open_state, sizeof(HANDLE)); + + *len = header_len; + + DbgP("class=%d session=0x%x open_state=0x%x\n", + entry->u.QueryFile.InfoClass, entry->u.QueryFile.session, + entry->u.QueryFile.open_state); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_fileset(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + entry->u.SetFile.filename->Length + + sizeof(entry->u.SetFile.filename->Length) + 5 * sizeof(ULONG) + + entry->u.SetFile.buf_len + 2 * sizeof(HANDLE); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + RtlCopyMemory(tmp, &entry->u.SetFile.filename->Length, + sizeof(entry->u.SetFile.filename->Length)); + tmp += sizeof(entry->u.SetFile.filename->Length); + RtlCopyMemory(tmp, entry->u.SetFile.filename->Buffer, + entry->u.SetFile.filename->Length); + tmp += entry->u.SetFile.filename->Length; + + RtlCopyMemory(tmp, &entry->u.SetFile.InfoClass, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, &entry->u.SetFile.buf_len, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, entry->u.SetFile.buf, entry->u.SetFile.buf_len); + tmp += entry->u.SetFile.buf_len; + RtlCopyMemory(tmp, &entry->u.SetFile.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.SetFile.open_state, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.SetFile.open_owner_id, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, &entry->u.SetFile.access_mask, sizeof(ULONG)); + tmp += sizeof(ULONG); + RtlCopyMemory(tmp, &entry->u.SetFile.access_mode, sizeof(ULONG)); + + *len = header_len; + + DbgP("filename='%wZ' class=%d session=0x%x open_state=0x%x " + "open_owner_id=0x%x access_mask=0x%x access_mode=0x%x\n", + entry->u.SetFile.filename, entry->u.SetFile.InfoClass, + entry->u.SetFile.session, entry->u.SetFile.open_state, + entry->u.SetFile.open_owner_id, entry->u.SetFile.access_mask, + entry->u.SetFile.access_mode); + print_hexbuf(0, (unsigned char *)"setfile buffer", entry->u.SetFile.buf, + entry->u.SetFile.buf_len); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_easet(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + 2 * sizeof(HANDLE) + sizeof(DWORD); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + RtlCopyMemory(tmp, &entry->u.SetEa.session, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.SetEa.open_state, sizeof(HANDLE)); + tmp += sizeof(HANDLE); + RtlCopyMemory(tmp, &entry->u.SetEa.mode, sizeof(DWORD)); + + *len = header_len; + + DbgP("session=0x%x open_state=0x%x mode=0x%x\n", + entry->u.SetEa.session, entry->u.SetEa.open_state, entry->u.SetEa.mode); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_volume(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG header_len = 0; + unsigned char *tmp = buf; + + DbgEn(); + status = marshal_nfs41_header(entry, tmp, buf_len, len); + if (status == STATUS_INSUFFICIENT_RESOURCES) + goto out; + else + tmp += *len; + header_len = *len + sizeof(HANDLE); + if (header_len > buf_len) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + RtlCopyMemory(tmp, &entry->u.Volume.session, sizeof(HANDLE)); + *len = header_len; + + DbgP("session=0x%x\n", entry->u.Volume.session); +out: + DbgEx(); + return status; +} + +NTSTATUS marshal_nfs41_shutdown(nfs41_updowncall_entry *entry, + unsigned char *buf, + ULONG buf_len, + ULONG *len) +{ + NTSTATUS status = STATUS_SUCCESS; + unsigned char *tmp = buf; + + DbgEn(); + + status = marshal_nfs41_header(entry, tmp, buf_len, len); + + DbgEx(); + return status; +} + +NTSTATUS +nfs41_invalidate_cache ( + IN PRX_CONTEXT RxContext + ) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; + +} + +NTSTATUS +handle_upcall( + IN PRX_CONTEXT RxContext, + IN nfs41_updowncall_entry *entry, + OUT ULONG *len + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + ULONG cbOut = LowIoContext->ParamsFor.IoCtl.OutputBufferLength; + unsigned char *pbOut = LowIoContext->ParamsFor.IoCtl.pOutputBuffer; + + switch(entry->opcode) { + case NFS41_SHUTDOWN: + status = marshal_nfs41_shutdown(entry, pbOut, cbOut, len); + DbgP("[upcall] About to signal waiting IO thread\n"); + KeSetEvent(&entry->cond, 0, FALSE); + break; + case NFS41_MOUNT: + status = marshal_nfs41_mount(entry, pbOut, cbOut, len); + break; + case NFS41_UNMOUNT: + status = marshal_nfs41_unmount(entry, pbOut, cbOut, len); + break; + case NFS41_OPEN: + status = marshal_nfs41_open(entry, pbOut, cbOut, len); + break; + case NFS41_READ: + status = marshal_nfs41_rw(entry, pbOut, cbOut, len); + break; + case NFS41_WRITE: + status = marshal_nfs41_rw(entry, pbOut, cbOut, len); + break; + case NFS41_LOCK: + status = marshal_nfs41_lock(entry, pbOut, cbOut, len); + break; + case NFS41_UNLOCK: + status = marshal_nfs41_unlock(entry, pbOut, cbOut, len); + break; + case NFS41_CLOSE: + status = marshal_nfs41_close(entry, pbOut, cbOut, len); + break; + case NFS41_DIR_QUERY: + status = marshal_nfs41_dirquery(entry, pbOut, cbOut, len); + break; + case NFS41_FILE_QUERY: + status = marshal_nfs41_filequery(entry, pbOut, cbOut, len); + break; + case NFS41_FILE_SET: + status = marshal_nfs41_fileset(entry, pbOut, cbOut, len); + break; + case NFS41_EA_SET: + status = marshal_nfs41_easet(entry, pbOut, cbOut, len); + break; + case NFS41_VOLUME_QUERY: + status = marshal_nfs41_volume(entry, pbOut, cbOut, len); + break; + default: + status = STATUS_INVALID_PARAMETER; + DbgP("Unknown nfs41 ops %d\n", entry->opcode); + } + + if (status == STATUS_SUCCESS) + print_hexbuf(0, (unsigned char *)"upcall buffer", pbOut, *len); + + return status; +} +NTSTATUS nfs41_UpcallCreate( + IN DWORD opcode, + OUT nfs41_updowncall_entry **entry_out) +{ + NTSTATUS status = STATUS_SUCCESS; + nfs41_updowncall_entry *entry; + + entry = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_entry), + NFS41_MM_POOLTAG); + if (entry == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + RtlZeroMemory(entry, sizeof(nfs41_updowncall_entry)); + entry->xid = get_next_xid(); + entry->opcode = opcode; + entry->state = NFS41_WAITING_FOR_UPCALL; + /*XXX KeInitializeEvent will bugcheck under verifier if allocated from PagedPool? */ + KeInitializeEvent(&entry->cond, SynchronizationEvent, FALSE); + ExInitializeFastMutex(&entry->lock); + *entry_out = entry; +out: + return status; +} + +NTSTATUS nfs41_UpcallWaitForReply( + IN nfs41_updowncall_entry *entry) +{ + NTSTATUS status = STATUS_SUCCESS; + const char *opstring = opcode2string(entry->opcode); + + nfs41_AddEntry(upcallLock, upcall, entry); + KeSetEvent(&upcallEvent, 0, FALSE); + DbgP("@@@ Creating %s upcall entry=%p xid=%d\n", opstring, entry, entry->xid); + if (!entry->async_op) { + status = KeWaitForSingleObject(&entry->cond, Executive, UserMode, TRUE, NULL); + print_wait_status(1, "[downcall]", status, opcode2string(entry->opcode), + entry, entry->xid); + } else + goto out; + + switch(status) { + case STATUS_SUCCESS: + break; + case STATUS_USER_APC: + case STATUS_ALERTED: + default: + ExAcquireFastMutex(&entry->lock); + if (entry->state == NFS41_DONE_PROCESSING) { + DbgP("[downcall] finish processing %s entry=%p xid=%d\n", + opcode2string(entry->opcode), entry, entry->xid); + ExReleaseFastMutex(&entry->lock); + break; + } + DbgP("[upcall] abandoning %s entry=%p xid=%d\n", + opcode2string(entry->opcode), entry, entry->xid); + entry->state = NFS41_NOT_WAITING; + ExReleaseFastMutex(&entry->lock); + goto out; + } + nfs41_RemoveEntry(downcallLock, downcall, entry); +out: + return status; +} + +NTSTATUS +nfs41_upcall ( + IN PRX_CONTEXT RxContext + ) +{ + NTSTATUS status = STATUS_SUCCESS; /* XXX */ + nfs41_updowncall_entry *entry = NULL; + ULONG len = 0; + PLIST_ENTRY pEntry; + + DbgEn(); + +process_upcall: + nfs41_RemoveFirst(upcallLock, upcall, pEntry); + if (pEntry) { + entry = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry, + nfs41_updowncall_entry, next); + ExAcquireFastMutex(&entry->lock); + if (entry->state == NFS41_WAITING_FOR_UPCALL) { + nfs41_AddEntry(downcallLock, downcall, entry); + status = handle_upcall(RxContext, entry, &len); + if (status == STATUS_SUCCESS) + entry->state = NFS41_WAITING_FOR_DOWNCALL; + } else if (entry->state == NFS41_NOT_WAITING) { + DbgP("[upcall] Canceling %s upcall entry %p xid %d\n", + opcode2string(entry->opcode), entry, entry->xid); + ExReleaseFastMutex(&entry->lock); + RxFreePool(entry); + goto process_upcall; + } + ExReleaseFastMutex(&entry->lock); + if (status == STATUS_INSUFFICIENT_RESOURCES) { + DbgP("upcall buffer is too small\n"); + entry->status = status; + KeSetEvent(&entry->cond, 0, FALSE); + RxContext->InformationToReturn = 0; + } else + RxContext->InformationToReturn = len; + } + else { + DbgP("[upcall] About to go to sleep\n"); + status = KeWaitForSingleObject(&upcallEvent, Executive, UserMode, TRUE, + (PLARGE_INTEGER) NULL); + print_wait_status(1, "[upcall]", status, NULL, NULL, 0); + switch (status) { + case STATUS_SUCCESS: + goto process_upcall; + case STATUS_USER_APC: + case STATUS_ALERTED: + default: + goto out; + } + } +out: + DbgEx(); + return status; +} + +NTSTATUS +nfs41_downcall ( + IN PRX_CONTEXT RxContext + ) +{ + NTSTATUS status = STATUS_SUCCESS; /* XXX */ + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + ULONG in_len = LowIoContext->ParamsFor.IoCtl.InputBufferLength; + unsigned char *buf = LowIoContext->ParamsFor.IoCtl.pInputBuffer; + PLIST_ENTRY pEntry; + nfs41_updowncall_entry *tmp; + nfs41_updowncall_entry *cur= NULL; + DWORD found = 0; + + DbgEn(); + print_hexbuf(0, (unsigned char *)"downcall buffer", buf, in_len); + + tmp = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_entry), + NFS41_MM_POOLTAG); + if (tmp == NULL) { + goto out; + } + RtlZeroMemory(tmp, sizeof(nfs41_updowncall_entry)); + + RtlCopyMemory(&tmp->xid, buf, sizeof(tmp->xid)); + buf += sizeof(tmp->xid); + RtlCopyMemory(&tmp->opcode, buf, sizeof(tmp->opcode)); + buf += sizeof(tmp->opcode); + RtlCopyMemory(&tmp->status, buf, sizeof(tmp->status)); + buf += sizeof(tmp->status); + RtlCopyMemory(&tmp->errno, buf, sizeof(tmp->errno)); + buf += sizeof(tmp->errno); + DbgP("[downcall] xid=%d opcode=%d status=%d errno=%d\n", tmp->xid, tmp->opcode, + tmp->status, tmp->errno); + + ExAcquireFastMutex(&downcallLock); + pEntry = &downcall->head; + while (pEntry != NULL) { + cur = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry, + nfs41_updowncall_entry, next); + if (cur->xid == tmp->xid) { + found = 1; + break; + } + if (pEntry->Flink == &downcall->head) { + DbgP("reached end of the list\n"); + break; + } + pEntry = pEntry->Flink; + } + ExReleaseFastMutex(&downcallLock); + if (!found) { + DbgP("Didn't find xid=%d entry\n", tmp->xid); + goto out_free; + } + + ExAcquireFastMutex(&cur->lock); + if (cur->state == NFS41_NOT_WAITING) { + DbgP("[downcall] Nobody is waiting for this request!!!\n"); + ExReleaseFastMutex(&cur->lock); + nfs41_RemoveEntry(downcallLock, downcall, cur); + RxFreePool(cur); + status = STATUS_UNSUCCESSFUL; + goto out_free; + } + cur->state = NFS41_DONE_PROCESSING; + cur->status = tmp->status; + cur->errno = tmp->errno; + + if (!tmp->status) { + switch (tmp->opcode) { + case NFS41_MOUNT: + RtlCopyMemory(&cur->u.Mount.session, buf, sizeof(HANDLE)); + DbgP("[mount] session pointer 0x%x\n", cur->u.Mount.session); + break; + case NFS41_WRITE: + case NFS41_READ: + RtlCopyMemory(&cur->u.ReadWrite.len, buf, sizeof(cur->u.ReadWrite.len)); + DbgP("[read/write] returned len %ld\n", cur->u.ReadWrite.len); +#if 0 + /* 08/27/2010: it looks like we really don't need to call MmUnmapLockedPages() + * eventhough we called MmMapLockedPagesSpecifyCache() as the MDL passed to us + * is already locked. + */ + __try { + MmUnmapLockedPages(cur->u.ReadWrite.buf, cur->u.ReadWrite.MdlAddress); + } __except(EXCEPTION_EXECUTE_HANDLER) { + NTSTATUS code; + code = GetExceptionCode(); + DbgP("Call to MmUnmapLockedPages failed due to exception 0x%0x\n", code); + status = STATUS_ACCESS_DENIED; + } +#endif + break; + case NFS41_OPEN: + RtlCopyMemory(&cur->u.Open.binfo, buf, sizeof(FILE_BASIC_INFORMATION)); + buf += sizeof(FILE_BASIC_INFORMATION); + RtlCopyMemory(&cur->u.Open.sinfo, buf, sizeof(FILE_STANDARD_INFORMATION)); + buf += sizeof(FILE_STANDARD_INFORMATION); + RtlCopyMemory(&cur->u.Open.open_state, buf, sizeof(HANDLE)); + buf += sizeof(HANDLE); + RtlCopyMemory(&cur->u.Open.mode, buf, sizeof(DWORD)); + buf += sizeof(DWORD); + RtlCopyMemory(&cur->u.Open.changeattr, buf, sizeof(ULONG)); + DbgP("[open] open_state 0x%x mode %o changeattr 0x%x\n", + cur->u.Open.open_state, cur->u.Open.mode, cur->u.Open.changeattr); + break; + case NFS41_DIR_QUERY: + case NFS41_FILE_QUERY: + RtlCopyMemory(&tmp->u.QueryFile.buf_len, buf, sizeof(ULONG)); + buf += sizeof(ULONG); + if (tmp->u.QueryFile.buf_len > cur->u.QueryFile.buf_len) { + cur->status = STATUS_BUFFER_TOO_SMALL; + cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len; + break; + } + cur->u.QueryFile.buf_len = tmp->u.QueryFile.buf_len; + RtlCopyMemory(cur->u.QueryFile.buf, buf, tmp->u.QueryFile.buf_len); + if (tmp->opcode == NFS41_DIR_QUERY) { + buf += tmp->u.QueryFile.buf_len; + RtlCopyMemory(&cur->u.QueryFile.readdir_cookie, buf, sizeof(HANDLE)); + } + break; + case NFS41_VOLUME_QUERY: + RtlCopyMemory(&cur->u.Volume.total, buf, sizeof(ULONGLONG)); + buf += sizeof(ULONGLONG); + RtlCopyMemory(&cur->u.Volume.user, buf, sizeof(ULONGLONG)); + buf += sizeof(ULONGLONG); + RtlCopyMemory(&cur->u.Volume.avail, buf, sizeof(ULONGLONG)); + DbgP("[volume] total %llu user %llu avail %llu\n", + cur->u.Volume.total, cur->u.Volume.user, cur->u.Volume.avail); + break; + } + } + DbgP("[downcall] About to signal waiting IO thread\n"); + ExReleaseFastMutex(&cur->lock); + if (cur->async_op) { + if (cur->status == STATUS_SUCCESS) { + cur->u.ReadWrite.rxcontext->StoredStatus = STATUS_SUCCESS; + cur->u.ReadWrite.rxcontext->InformationToReturn = cur->u.ReadWrite.len; + } else { + cur->u.ReadWrite.rxcontext->StoredStatus = map_readwrite_errors(cur->status); + cur->u.ReadWrite.rxcontext->InformationToReturn = 0; + } + nfs41_RemoveEntry(downcallLock, downcall, cur); + RxLowIoCompletion(cur->u.ReadWrite.rxcontext); + } else + KeSetEvent(&cur->cond, 0, FALSE); + status = STATUS_SUCCESS; + +out_free: + RxFreePool(tmp); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_shutdown_daemon() +{ + NTSTATUS status = STATUS_SUCCESS; + nfs41_updowncall_entry *entry = NULL; + + DbgEn(); + status = nfs41_UpcallCreate(NFS41_SHUTDOWN, &entry); + if (status) + goto out; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +static NTSTATUS SharedMemoryInit( + OUT PHANDLE phSection) +{ + NTSTATUS status; + HANDLE hSection; + UNICODE_STRING SectionName; + SECURITY_DESCRIPTOR SecurityDesc; + OBJECT_ATTRIBUTES SectionAttrs; + LARGE_INTEGER nSectionSize; + + DbgEn(); + + RtlInitUnicodeString(&SectionName, NFS41_SHARED_MEMORY_NAME); + + /* XXX: setting dacl=NULL grants access to everyone */ + status = RtlCreateSecurityDescriptor(&SecurityDesc, + SECURITY_DESCRIPTOR_REVISION); + if (status) { + DbgP("RtlCreateSecurityDescriptor() failed with %08X\n", status); + goto out; + } + status = RtlSetDaclSecurityDescriptor(&SecurityDesc, TRUE, NULL, FALSE); + if (status) { + DbgP("RtlSetDaclSecurityDescriptor() failed with %08X\n", status); + goto out; + } + + InitializeObjectAttributes(&SectionAttrs, &SectionName, + 0, NULL, &SecurityDesc); + + nSectionSize.QuadPart = sizeof(NFS41NP_SHARED_MEMORY); + + status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, + &SectionAttrs, &nSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL); + switch (status) { + case STATUS_SUCCESS: + break; + case STATUS_OBJECT_NAME_COLLISION: + DbgP("section already created; returning success\n"); + status = STATUS_SUCCESS; + goto out; + default: + DbgP("ZwCreateSection failed with %08X\n", status); + goto out; + } +out: + DbgEx(); + return status; +} + +static NTSTATUS SharedMemoryFree( + IN HANDLE hSection) +{ + NTSTATUS status; + DbgEn(); + status = ZwClose(hSection); + DbgEx(); + return status; +} + +NTSTATUS nfs41_Start( + IN OUT struct _RX_CONTEXT *RxContext, + IN OUT PRDBSS_DEVICE_OBJECT dev) +{ + NTSTATUS status; + NFS41GetDeviceExtension(RxContext, DevExt); + + DbgEn(); + + status = SharedMemoryInit(&DevExt->SharedMemorySection); + if (status) { + DbgP("InitSharedMemory failed with %08X\n", status); + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + + InterlockedCompareExchange((PLONG)&nfs41_start_state, + NFS41_START_DRIVER_STARTED, + NFS41_START_DRIVER_START_IN_PROGRESS); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_Stop( + IN OUT struct _RX_CONTEXT * RxContext, + IN OUT PRDBSS_DEVICE_OBJECT dev) +{ + NTSTATUS status; + NFS41GetDeviceExtension(RxContext, DevExt); + DbgEn(); + status = SharedMemoryFree(DevExt->SharedMemorySection); + DbgEx(); + return status; +} + +HANDLE +GetConnectionHandle( + IN PUNICODE_STRING ConnectionName, + IN PVOID EaBuffer, + IN ULONG EaLength + ) +{ + NTSTATUS status; + HANDLE Handle = INVALID_HANDLE_VALUE; + IO_STATUS_BLOCK IoStatusBlock; + OBJECT_ATTRIBUTES ObjectAttributes; + + DbgEn(); + InitializeObjectAttributes(&ObjectAttributes, ConnectionName, + OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL); + + status = ZwCreateFile(&Handle, SYNCHRONIZE, &ObjectAttributes, + &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN_IF, + FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT, + EaBuffer, EaLength); + if (!NT_SUCCESS(status)) + Handle = INVALID_HANDLE_VALUE; + else + DbgP("created handle %p\n", &Handle); + + DbgEx(); + return Handle; +} + +NTSTATUS nfs41_GetConnectionInfoFromBuffer( + IN PVOID Buffer, + IN ULONG BufferLen, + OUT PUNICODE_STRING pConnectionName, + OUT PVOID *ppEaBuffer, + OUT PULONG pEaLength) +{ + NTSTATUS status = STATUS_SUCCESS; + USHORT NameLength; + USHORT EaPadding; + ULONG EaLength; + ULONG BufferLenExpected; + PBYTE ptr; + + DbgEn(); + + /* make sure buffer is at least big enough for header */ + if (BufferLen < sizeof(USHORT) + sizeof(USHORT) + sizeof(ULONG)) + { + status = STATUS_BAD_NETWORK_NAME; + DbgP("Invalid input buffer.\n"); + pConnectionName->Length = pConnectionName->MaximumLength = 0; + *ppEaBuffer = NULL; + *pEaLength = 0; + goto out; + } + + ptr = Buffer; + NameLength = *(PUSHORT)ptr; + ptr += sizeof(USHORT); + EaPadding = *(PUSHORT)ptr; + ptr += sizeof(USHORT); + EaLength = *(PULONG)ptr; + ptr += sizeof(ULONG); + + /* validate buffer length */ + BufferLenExpected = sizeof(USHORT) + sizeof(USHORT) + sizeof(ULONG) + + NameLength + EaPadding + EaLength; + if (BufferLen != BufferLenExpected) + { + status = STATUS_BAD_NETWORK_NAME; + DbgP("Received buffer of length %lu, but expected %lu bytes.\n", + BufferLen, BufferLenExpected); + pConnectionName->Length = pConnectionName->MaximumLength = 0; + *ppEaBuffer = NULL; + *pEaLength = 0; + goto out; + } + + pConnectionName->Buffer = (PWCH)ptr; + pConnectionName->Length = NameLength - sizeof(WCHAR); + pConnectionName->MaximumLength = NameLength; + DbgP("connection name %wZ\n", pConnectionName); + + if (EaLength) + *ppEaBuffer = ptr + NameLength + EaPadding; + else + *ppEaBuffer = NULL; + *pEaLength = EaLength; + +out: + DbgEx(); + return status; +} + +NTSTATUS +nfs41_CreateConnection ( + IN PRX_CONTEXT RxContext, + OUT PBOOLEAN PostToFsp + ) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE Handle; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PVOID Buffer = LowIoContext->ParamsFor.IoCtl.pInputBuffer; + ULONG BufferLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength; + UNICODE_STRING FileName; + PVOID EaBuffer; + ULONG EaLength; + BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); + + DbgEn(); + + if (!Wait) { + //just post right now! + DbgP("returning STATUS_PENDING\n"); + *PostToFsp = TRUE; + status = STATUS_PENDING; + goto out; + } + + status = nfs41_GetConnectionInfoFromBuffer(Buffer, BufferLen, + &FileName, &EaBuffer, &EaLength); + if (status != STATUS_SUCCESS) + goto out; + + Handle = GetConnectionHandle(&FileName, EaBuffer, EaLength); + if (Handle == INVALID_HANDLE_VALUE) + status = STATUS_BAD_NETWORK_NAME; +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_unmount(HANDLE session) +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + nfs41_updowncall_entry *entry; + + DbgEn(); + status = nfs41_UpcallCreate(NFS41_UNMOUNT, &entry); + if (status) + goto out; + entry->u.Mount.session = session; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS +nfs41_DeleteConnection ( + IN PRX_CONTEXT RxContext, + OUT PBOOLEAN PostToFsp + ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PWCHAR ConnectName = LowIoContext->ParamsFor.IoCtl.pInputBuffer; + ULONG ConnectNameLen = LowIoContext->ParamsFor.IoCtl.InputBufferLength; + HANDLE Handle; + UNICODE_STRING FileName; + PFILE_OBJECT pFileObject; + BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); + + DbgEn(); + + if (!Wait) { + //just post right now! + *PostToFsp = TRUE; + DbgP("returning STATUS_PENDING\n"); + status = STATUS_PENDING; + goto out; + } + + FileName.Buffer = ConnectName; + FileName.Length = (USHORT) ConnectNameLen - sizeof(WCHAR); + FileName.MaximumLength = (USHORT) ConnectNameLen; + + Handle = GetConnectionHandle(&FileName, NULL, 0); + if (Handle == INVALID_HANDLE_VALUE) + goto out; + + DbgP("GetConnectionHandle returned success\n"); + status = ObReferenceObjectByHandle(Handle, 0L, NULL, KernelMode, + (PVOID *)&pFileObject, NULL); + if (NT_SUCCESS(status)) { + PV_NET_ROOT VNetRoot; + + DbgP("ObReferenceObjectByHandle worked ok %p\n", pFileObject); + // VNetRoot exists as FOBx in the FsContext2 + VNetRoot = (PV_NET_ROOT) pFileObject->FsContext2; + // make sure the node looks right + if (NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT) + { + DbgP("Calling RxFinalizeConnection for NetRoot %p from VNetRoot %p\n", + VNetRoot->NetRoot, VNetRoot); + status = RxFinalizeConnection(VNetRoot->NetRoot, VNetRoot, TRUE); + } + else + status = STATUS_BAD_NETWORK_NAME; + + ObDereferenceObject(pFileObject); + } + ZwClose(Handle); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_DevFcbXXXControlFile( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + UCHAR op = RxContext->MajorFunction; + PLOWIO_CONTEXT io_ctx = &RxContext->LowIoContext; + ULONG fsop = io_ctx->ParamsFor.FsCtl.FsControlCode; + ULONG state; + + //DbgEn(); + + print_ioctl(0, op); + switch(op) { + case IRP_MJ_FILE_SYSTEM_CONTROL: + status = STATUS_INVALID_DEVICE_REQUEST; + break; + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + print_fs_ioctl(0, fsop); + switch (fsop) { + case IOCTL_NFS41_INVALCACHE: + status = nfs41_invalidate_cache(RxContext); + break; + case IOCTL_NFS41_READ: + status = nfs41_upcall(RxContext); + break; + case IOCTL_NFS41_WRITE: + status = nfs41_downcall(RxContext); + break; + case IOCTL_NFS41_ADDCONN: + status = nfs41_CreateConnection(RxContext, &RxContext->PostRequest); + break; + case IOCTL_NFS41_DELCONN: + if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) { + DbgP("device has open handles %d\n", + RxContext->RxDeviceObject->NumberOfActiveFcbs); + status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES; + break; + } + status = nfs41_DeleteConnection(RxContext, &RxContext->PostRequest); + break; + case IOCTL_NFS41_GETSTATE: + state = RDR_NULL_STATE; + + if (io_ctx->ParamsFor.IoCtl.OutputBufferLength >= + sizeof(ULONG) ) { + // map the states to control app's equivalents + print_driver_state(nfs41_start_state); + switch (nfs41_start_state) { + case NFS41_START_DRIVER_STARTABLE: + case NFS41_START_DRIVER_STOPPED: + state = RDR_STOPPED; + break; + case NFS41_START_DRIVER_START_IN_PROGRESS: + state = RDR_STARTING; + break; + case NFS41_START_DRIVER_STARTED: + state = RDR_STARTED; + break; + } + *(ULONG *)io_ctx->ParamsFor.IoCtl.pOutputBuffer = state; + RxContext->InformationToReturn = sizeof(ULONG); + status = STATUS_SUCCESS; + } else + status = STATUS_INVALID_PARAMETER; + break; + case IOCTL_NFS41_START: + print_driver_state(nfs41_start_state); + switch(nfs41_start_state) { + case NFS41_START_DRIVER_STARTABLE: + (nfs41_start_driver_state)InterlockedCompareExchange( + (PLONG)&nfs41_start_state, + NFS41_START_DRIVER_START_IN_PROGRESS, + NFS41_START_DRIVER_STARTABLE); + //lack of break is intentional + case NFS41_START_DRIVER_START_IN_PROGRESS: + status = RxStartMinirdr(RxContext, &RxContext->PostRequest); + if (status == STATUS_REDIRECTOR_STARTED) { + DbgP("redirector started\n"); + status = STATUS_SUCCESS; + } else if (status == STATUS_PENDING && + RxContext->PostRequest == TRUE) { + DbgP("RxStartMinirdr pending %08lx\n", status); + status = STATUS_MORE_PROCESSING_REQUIRED; + } + break; + case NFS41_START_DRIVER_STARTED: + status = STATUS_SUCCESS; + break; + default: + status = STATUS_INVALID_PARAMETER; + } + break; + case IOCTL_NFS41_STOP: + if (nfs41_start_state == NFS41_START_DRIVER_STARTED) + nfs41_shutdown_daemon(); + if (RxContext->RxDeviceObject->NumberOfActiveFcbs > 0) { + DbgP("device has open handles %d\n", + RxContext->RxDeviceObject->NumberOfActiveFcbs); + status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES; + break; + } + + state = (nfs41_start_driver_state)InterlockedCompareExchange( + (PLONG)&nfs41_start_state, + NFS41_START_DRIVER_STARTABLE, + NFS41_START_DRIVER_STARTED); + + status = RxStopMinirdr(RxContext, &RxContext->PostRequest); + DbgP("RxStopMinirdr status %08lx\n", status); + if (status == STATUS_PENDING && RxContext->PostRequest == TRUE ) + status = STATUS_MORE_PROCESSING_REQUIRED; + break; + default: + status = STATUS_INVALID_DEVICE_REQUEST; + }; + break; + default: + status = STATUS_INVALID_DEVICE_REQUEST; + }; + + //DbgEx(); + return status; +} + +NTSTATUS +_nfs41_CreateSrvCall( + PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext) +{ + NTSTATUS status = STATUS_SUCCESS; + PMRX_SRVCALL_CALLBACK_CONTEXT SCCBC = pCallbackContext; + PMRX_SRV_CALL pSrvCall; + PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure = + (PMRX_SRVCALLDOWN_STRUCTURE)(SCCBC->SrvCalldownStructure); + PNFS41_SERVER_ENTRY pServerEntry = NULL; + + DbgEn(); + + pSrvCall = SrvCalldownStructure->SrvCall; + + ASSERT( pSrvCall ); + ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL ); + print_srv_call(0, pSrvCall); + + // validate the server name with the test name of 'pnfs' + DbgP("SrvCall: Connection Name Length: %d %wZ\n", + pSrvCall->pSrvCallName->Length, pSrvCall->pSrvCallName); + + if (pSrvCall->pSrvCallName->Length > SERVER_NAME_BUFFER_SIZE) { + DbgP("Server name '%wZ' too long for server entry (max %u)\n", + pSrvCall->pSrvCallName, SERVER_NAME_BUFFER_SIZE); + status = STATUS_NAME_TOO_LONG; + goto out; + } + + /* Let's create our own representation of the server */ + pServerEntry = (PNFS41_SERVER_ENTRY)RxAllocatePoolWithTag(PagedPool, + sizeof(NFS41_SERVER_ENTRY), NFS41_MM_POOLTAG); + if (pServerEntry == NULL) { + DbgP("failed to allocate memory for pServerEntry\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + goto out; + } + RtlZeroMemory(pServerEntry, sizeof(NFS41_SERVER_ENTRY)); + + pServerEntry->Name.Buffer = pServerEntry->NameBuffer; + pServerEntry->Name.Length = pSrvCall->pSrvCallName->Length; + pServerEntry->Name.MaximumLength = SERVER_NAME_BUFFER_SIZE; + RtlCopyMemory(pServerEntry->Name.Buffer, pSrvCall->pSrvCallName->Buffer, + pServerEntry->Name.Length); + DbgP("copying server name %wZ into server entry %p\n", + &pServerEntry->Name, pServerEntry); + + pCallbackContext->RecommunicateContext = pServerEntry; + DbgP("saving pServerEntry %p in RecommunicateContext\n", pServerEntry); + InterlockedExchangePointer(&pServerEntry->pRdbssSrvCall, pSrvCall); + DbgP("saving pSrvCall %p in pServerEntry's pRdbssSrvCall\n", pSrvCall); + +out: + SCCBC->Status = status; + SrvCalldownStructure->CallBack(SCCBC); + + DbgEx(); + return status; +} + +NTSTATUS nfs41_CreateSrvCall( + PMRX_SRV_CALL pSrvCall, + PMRX_SRVCALL_CALLBACK_CONTEXT pCallbackContext) +{ + NTSTATUS status; + + DbgEn(); + + ASSERT( pSrvCall ); + ASSERT( NodeType(pSrvCall) == RDBSS_NTC_SRVCALL ); + + DbgP("pCallbackContext %p\n", pCallbackContext); + if (IoGetCurrentProcess() == RxGetRDBSSProcess()) { + DbgP("executing with RDBSS context\n"); + status = _nfs41_CreateSrvCall(pCallbackContext); + } else { + DbgP("dispatching CreateSrvCall to a system thread\n"); + status = RxDispatchToWorkerThread(nfs41_dev, DelayedWorkQueue, + _nfs41_CreateSrvCall, pCallbackContext); + if (status != STATUS_SUCCESS) { + DbgP("RxDispatchToWorkerThread returned status %08lx\n", status); + pCallbackContext->Status = status; + pCallbackContext->SrvCalldownStructure->CallBack(pCallbackContext); + status = STATUS_PENDING; + } + } + /* RDBSS expects MRxCreateSrvCall to return STATUS_PENDING */ + if (status == STATUS_SUCCESS) { + DbgP("mapping SUCCESS returned status to PENDING\n"); + status = STATUS_PENDING; + } + + DbgEx(); + return status; +} + +NTSTATUS nfs41_SrvCallWinnerNotify( + IN OUT PMRX_SRV_CALL pSrvCall, + IN BOOLEAN ThisMinirdrIsTheWinner, + IN OUT PVOID pSrvCallContext) +{ + NTSTATUS status = STATUS_SUCCESS; + PNFS41_SERVER_ENTRY pServerEntry; + + DbgEn(); + pServerEntry = (PNFS41_SERVER_ENTRY)pSrvCallContext; + + if (!ThisMinirdrIsTheWinner) { + ASSERT(1); + goto out; + } + + pSrvCall->Context = pServerEntry; + DbgP("This minirdr is the winner SrvCall context %p points to server entry %p\n", + pSrvCall->Context, pServerEntry); +out: + DbgEx(); + return status; +} + +static NTSTATUS map_mount_errors(DWORD status) +{ + switch (status) { + case NO_ERROR: return STATUS_SUCCESS; + case ERROR_NETWORK_UNREACHABLE: + case ERROR_BAD_NET_RESP: return STATUS_UNEXPECTED_NETWORK_ERROR; + case ERROR_BAD_NETPATH: return STATUS_BAD_NETWORK_PATH; + default: + DbgP("failed to map windows error %d to NTSTATUS; " + "defaulting to STATUS_INSUFFICIENT_RESOURCES\n", status); + return STATUS_INSUFFICIENT_RESOURCES; + } +} + +NTSTATUS nfs41_mount(PUNICODE_STRING srv_name, PUNICODE_STRING root, PHANDLE session) +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + nfs41_updowncall_entry *entry; + + DbgEn(); + status = nfs41_UpcallCreate(NFS41_MOUNT, &entry); + if (status) + goto out; + entry->u.Mount.srv_name = srv_name; + entry->u.Mount.root = root; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + *session = entry->u.Mount.session; + + /* map windows ERRORs to NTSTATUS */ + status = map_mount_errors(entry->status); + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +/* TODO: move mount config stuff to another file -cbodley */ + +void nfs41_MountConfig_InitDefaults( + OUT PNFS41_MOUNT_CONFIG Config) +{ + RtlZeroMemory(Config, sizeof(NFS41_MOUNT_CONFIG)); + + Config->ReadSize = MOUNT_CONFIG_RW_SIZE_DEFAULT; + Config->WriteSize = MOUNT_CONFIG_RW_SIZE_DEFAULT; + Config->ReadOnly = FALSE; + Config->SrvName.Length = SERVER_NAME_BUFFER_SIZE; + Config->SrvName.MaximumLength = SERVER_NAME_BUFFER_SIZE; + Config->SrvName.Buffer = Config->srv_buffer; + Config->MntPt.Length = MAX_PATH; + Config->MntPt.MaximumLength = MAX_PATH; + Config->MntPt.Buffer = Config->mntpt_buffer; + Config->Initialized = FALSE; + +} + +static NTSTATUS nfs41_MountConfig_ParseBoolean( + IN PFILE_FULL_EA_INFORMATION Option, + IN PUNICODE_STRING usValue, + OUT PBOOLEAN Value) +{ + NTSTATUS status = STATUS_SUCCESS; + + /* if no value is specified, assume TRUE + * if a value is specified, it must be a '1' */ + if (Option->EaValueLength == 0 || *usValue->Buffer == L'1') + *Value = TRUE; + else + *Value = FALSE; + + DbgP(" '%ls' -> '%wZ' -> %u\n", + (LPWSTR)Option->EaName, *usValue, *Value); + return status; +} + +static NTSTATUS nfs41_MountConfig_ParseDword( + IN PFILE_FULL_EA_INFORMATION Option, + IN PUNICODE_STRING usValue, + OUT PDWORD Value, + IN DWORD Minimum, + IN DWORD Maximum) +{ + NTSTATUS status; + LPWSTR Name = (LPWSTR)Option->EaName; + + if (Option->EaValueLength) + { + status = RtlUnicodeStringToInteger(usValue, 0, Value); + if (status == STATUS_SUCCESS) + { + if (*Value < Minimum) + *Value = Minimum; + if (*Value > Maximum) + *Value = Maximum; + DbgP(" '%ls' -> '%wZ' -> %lu\n", Name, *usValue, *Value); + } + else + DbgP("Failed to convert %s='%wZ' to unsigned long.\n", + Name, *usValue); + } + else + status = STATUS_INVALID_PARAMETER; + + return status; +} + +NTSTATUS nfs41_MountConfig_ParseOptions( + IN PFILE_FULL_EA_INFORMATION EaBuffer, + IN ULONG EaLength, + IN OUT PNFS41_MOUNT_CONFIG Config) +{ + NTSTATUS status = STATUS_SUCCESS; + PFILE_FULL_EA_INFORMATION Option; + LPWSTR Name; + size_t NameLen; + UNICODE_STRING usValue; + DbgEn(); + + Option = EaBuffer; + while (status == STATUS_SUCCESS) + { + Name = (LPWSTR)Option->EaName; + NameLen = Option->EaNameLength/sizeof(WCHAR); + + usValue.Length = usValue.MaximumLength = Option->EaValueLength; + usValue.Buffer = (PWCH)(Option->EaName + + Option->EaNameLength + sizeof(WCHAR)); + + if (wcsncmp(L"ro", Name, NameLen) == 0) + { + status = nfs41_MountConfig_ParseBoolean(Option, &usValue, + &Config->ReadOnly); + } + else if (wcsncmp(L"rsize", Name, NameLen) == 0) + { + status = nfs41_MountConfig_ParseDword(Option, &usValue, + &Config->ReadSize, MOUNT_CONFIG_RW_SIZE_MIN, + MOUNT_CONFIG_RW_SIZE_MAX); + } + else if (wcsncmp(L"wsize", Name, NameLen) == 0) + { + status = nfs41_MountConfig_ParseDword(Option, &usValue, + &Config->WriteSize, MOUNT_CONFIG_RW_SIZE_MIN, + MOUNT_CONFIG_RW_SIZE_MAX); + } + else if (wcsncmp(L"srvname", Name, NameLen) == 0) + { + if (usValue.Length > Config->SrvName.MaximumLength) + status = STATUS_NAME_TOO_LONG; + else + RtlCopyUnicodeString(&Config->SrvName, &usValue); + } + else if (wcsncmp(L"mntpt", Name, NameLen) == 0) + { + if (usValue.Length > Config->MntPt.MaximumLength) + status = STATUS_NAME_TOO_LONG; + else + RtlCopyUnicodeString(&Config->MntPt, &usValue); + } + else + { + status = STATUS_INVALID_PARAMETER; + DbgP("Unrecognized option '%ls' -> '%wZ'\n", + Name, usValue); + } + + if (Option->NextEntryOffset == 0) + break; + + Option = (PFILE_FULL_EA_INFORMATION) + ((PBYTE)Option + Option->NextEntryOffset); + } + + if (status == STATUS_SUCCESS) + Config->Initialized = TRUE; + + DbgEx(); + return status; +} + +static NTSTATUS has_nfs_prefix( + IN PUNICODE_STRING SrvCallName, + IN PUNICODE_STRING NetRootName) +{ + NTSTATUS status = STATUS_BAD_NETWORK_NAME; + + if (NetRootName->Length >= SrvCallName->Length + NfsPrefix.Length) { + const UNICODE_STRING NetRootPrefix = { + NfsPrefix.Length, + NetRootName->MaximumLength - SrvCallName->Length, + &NetRootName->Buffer[SrvCallName->Length/2] + }; + if (RtlCompareUnicodeString(&NetRootPrefix, &NfsPrefix, FALSE) == 0) + status = STATUS_SUCCESS; + } + return status; +} + +NTSTATUS nfs41_CreateVNetRoot( + IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext) +{ + NTSTATUS status = STATUS_SUCCESS; + PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot; + PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot; + PMRX_SRV_CALL pSrvCall = pNetRoot->pSrvCall; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(pVNetRoot); + PNFS41_NETROOT_EXTENSION pNetRootContext = + NFS41GetNetRootExtension(pNetRoot); + + ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) && + (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL)); + + DbgEn(); + print_srv_call(0, pSrvCall); + print_net_root(0, pNetRoot); + print_v_net_root(1, pVNetRoot); + + DbgP("pVNetRoot=%p pNetRoot=%p\n", pVNetRoot, pNetRoot); + DbgP("pNetRoot=%wZ pSrvCallName=%wZ VirtualNetRootStatus=0x%x " + "NetRootStatus=0x%x\n", pNetRoot->pNetRootName, pSrvCall->pSrvCallName, + pCreateNetRootContext->VirtualNetRootStatus, + pCreateNetRootContext->NetRootStatus); + + if (pNetRoot->Type != NET_ROOT_DISK) { + DbgP("pNetRoot->Type %u != NET_ROOT_DISK\n", pNetRoot->Type); + status = STATUS_NOT_SUPPORTED; + goto out; + } + + /* In order to cooperate with other network providers, we must + * only claim paths of the form '\\server\nfs4\path' */ + status = has_nfs_prefix(pSrvCall->pSrvCallName, pNetRoot->pNetRootName); + if (status) { + DbgP("NetRootName %wZ doesn't match '\\nfs4'!\n", pNetRoot->pNetRootName); + goto out; + } + pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD; + pNetRoot->DeviceType = FILE_DEVICE_DISK; + + nfs41_MountConfig_InitDefaults(&pVNetRootContext->Config); + + /* parse the extended attributes for mount options */ + if (pCreateNetRootContext->RxContext->Create.EaLength && + !pNetRootContext->Config.Initialized) + { + DbgP("EaLength %d\n", pCreateNetRootContext->RxContext->Create.EaLength); + DbgP("parsing storing into vnetroot\n"); + status = nfs41_MountConfig_ParseOptions( + pCreateNetRootContext->RxContext->Create.EaBuffer, + pCreateNetRootContext->RxContext->Create.EaLength, + &pVNetRootContext->Config); + if (status != STATUS_SUCCESS) { + if (pNetRootContext->Config.Initialized) { + DbgP("Using values from the NETROOT %p\n", pNetRootContext); + status = STATUS_SUCCESS; + RtlCopyMemory(&pVNetRootContext->Config, &pNetRootContext->Config, + sizeof(pNetRootContext->Config)); + pVNetRootContext->session = pNetRootContext->session; + } + goto out; + } + + // we need to save mount options in netroot not vnetroot!!!! + nfs41_MountConfig_InitDefaults(&pNetRootContext->Config); + DbgP("parsing storing into netroot\n"); + status = nfs41_MountConfig_ParseOptions( + pCreateNetRootContext->RxContext->Create.EaBuffer, + pCreateNetRootContext->RxContext->Create.EaLength, + &pNetRootContext->Config); + if (status != STATUS_SUCCESS) + goto out; + DbgP("Server Name %wZ Mount Point %wZ\n", &pVNetRootContext->Config.SrvName, + &pVNetRootContext->Config.MntPt); + pVNetRootContext->session = pNetRootContext->session = INVALID_HANDLE_VALUE; + status = nfs41_mount(&pVNetRootContext->Config.SrvName, + &pVNetRootContext->Config.MntPt, &pVNetRootContext->session); + if (status == STATUS_SUCCESS) + pNetRootContext->session = pVNetRootContext->session; + else + goto out; + } else { + if (pNetRootContext->session == NULL) { + DbgP("We dont have a valid existing session and we don't have a mount point!\n"); + status = STATUS_UNEXPECTED_NETWORK_ERROR; + pNetRootContext->session = INVALID_HANDLE_VALUE; + goto out; + } + RtlCopyMemory(&pVNetRootContext->Config, &pNetRootContext->Config, + sizeof(pNetRootContext->Config)); + pVNetRootContext->session = pNetRootContext->session; + } + DbgP("Saving point to nfs41_session 0x%x\n", pVNetRootContext->session); + + +out: + /* AGLO do we need to worry about handling new netroot vs using existing one */ + pCreateNetRootContext->VirtualNetRootStatus = status; + pCreateNetRootContext->NetRootStatus = status; + DbgP("initiating net root callback with status %08lx\n", status); + pCreateNetRootContext->Callback(pCreateNetRootContext); + + /* RDBSS expects that MRxCreateVNetRoot returns STATUS_PENDING + * on success or failure */ + status = STATUS_PENDING; + + DbgEx(); + return status; +} + +VOID nfs41_ExtractNetRootName( + IN PUNICODE_STRING FilePathName, + IN PMRX_SRV_CALL SrvCall, + OUT PUNICODE_STRING NetRootName, + OUT PUNICODE_STRING RestOfName OPTIONAL) +{ + ULONG length = FilePathName->Length; + PWCH w = FilePathName->Buffer; + PWCH wlimit = (PWCH)(((PCHAR)w)+length); + PWCH wlow; + + DbgEn(); + DbgP("Input: pSrvCall %p\n", SrvCall); + DbgP("Input: FilePathName=%wZ SrvCallName=%wZ\n", + FilePathName, SrvCall->pSrvCallName); + + w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR)); + NetRootName->Buffer = wlow = w; + /* parse the entire path into NetRootName */ +#if USE_ENTIRE_PATH + w = wlimit; +#else + for (;;) { + if (w >= wlimit) + break; + if ((*w == OBJ_NAME_PATH_SEPARATOR) && (w != wlow)) + break; + w++; + } +#endif + NetRootName->Length = NetRootName->MaximumLength + = (USHORT)((PCHAR)w - (PCHAR)wlow); + DbgP("Output: NetRootName=%wZ\n", NetRootName); + DbgR(); + return; + +} + +NTSTATUS nfs41_FinalizeSrvCall( + PMRX_SRV_CALL pSrvCall, + BOOLEAN Force) +{ + NTSTATUS status = STATUS_SUCCESS; + PNFS41_SERVER_ENTRY pServerEntry = (PNFS41_SERVER_ENTRY)(pSrvCall->Context); + + DbgEn(); + print_srv_call(0, pSrvCall); + + if (pSrvCall->Context == NULL) + goto out; + + InterlockedCompareExchangePointer(&pServerEntry->pRdbssSrvCall, NULL, pSrvCall); + DbgP("freeing server name %wZ and server entry %p\n", + &pServerEntry->Name, pServerEntry); + RxFreePool(pServerEntry); + + pSrvCall->Context = NULL; +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_FinalizeNetRoot( + IN OUT PMRX_NET_ROOT pNetRoot, + IN PBOOLEAN ForceDisconnect) +{ + NTSTATUS status = STATUS_SUCCESS; + PNFS41_NETROOT_EXTENSION pNetRootContext = + NFS41GetNetRootExtension((PMRX_NET_ROOT)pNetRoot); + nfs41_updowncall_entry *tmp; + + DbgEn(); + print_net_root(1, pNetRoot); + + if (pNetRoot->Type != NET_ROOT_DISK) { + status = STATUS_NOT_SUPPORTED; + goto out; + } + + if (pNetRootContext == NULL || pNetRootContext->session == INVALID_HANDLE_VALUE || + pNetRootContext->session == NULL) { + DbgP("No valid session has been established\n"); + goto out; + } + + if (pNetRoot->NumberOfFcbs > 0 || pNetRoot->NumberOfSrvOpens > 0) { + DbgP("%d open Fcbs %d open SrvOpens\n", pNetRoot->NumberOfFcbs, + pNetRoot->NumberOfSrvOpens); + goto out; + } + + status = nfs41_unmount(pNetRootContext->session); + if (status) { + DbgP("nfs41_mount failed with %d\n", status); + goto out; + } + + // check if there is anything waiting in the upcall or downcall queue + do { + nfs41_GetFirstEntry(upcallLock, upcall, tmp); + if (tmp != NULL) { + DbgP("Removing entry from upcall list\n"); + nfs41_RemoveEntry(upcallLock, upcall, tmp); + tmp->status = STATUS_INSUFFICIENT_RESOURCES; + KeSetEvent(&tmp->cond, 0, FALSE); + } else + break; + } while (1); + + do { + nfs41_GetFirstEntry(downcallLock, downcall, tmp); + if (tmp != NULL) { + DbgP("Removing entry from downcall list\n"); + nfs41_RemoveEntry(downcallLock, downcall, tmp); + tmp->status = STATUS_INSUFFICIENT_RESOURCES; + KeSetEvent(&tmp->cond, 0, FALSE); + } else + break; + } while (1); +out: + DbgEx(); + return status; +} + + +NTSTATUS nfs41_FinalizeVNetRoot( + IN OUT PMRX_V_NET_ROOT pVNetRoot, + IN PBOOLEAN ForceDisconnect) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + print_v_net_root(1, pVNetRoot); + if (pVNetRoot->pNetRoot->Type != NET_ROOT_DISK) + status = STATUS_NOT_SUPPORTED; + DbgEx(); + return status; +} + +BOOLEAN isDataAccess(ACCESS_MASK mask) +{ + if ((mask & FILE_READ_DATA) || + (mask & FILE_WRITE_DATA) || + (mask & FILE_APPEND_DATA)) + return TRUE; + return FALSE; +} + +BOOLEAN has_file_changed( + IN LONGLONG new_changeattr, + IN PFILE_BASIC_INFORMATION new_binfo, + IN PNFS41_FCB nfs41_fcb) +{ + if (new_changeattr != nfs41_fcb->changeattr && nfs41_fcb->changeattr) + return TRUE; + if (new_binfo->ChangeTime.QuadPart != nfs41_fcb->BasicInfo.ChangeTime.QuadPart) + return TRUE; + return FALSE; +} + +void print_open_args(PRX_CONTEXT RxContext) +{ + print_debug_header(RxContext); + print_net_root(0, RxContext->pFcb->pNetRoot); + print_v_net_root(0, RxContext->pRelevantSrvOpen->pVNetRoot); + //DbgP("RxContext->FsdUid %ld\n", RxContext->FsdUid); + //DbgP("RxInferFileType returns %d\n", RxInferFileType(RxContext)); + print_irps_flags(0, RxContext->CurrentIrpSp); + print_irp_flags(0, RxContext->CurrentIrp); + print_nt_create_params(1, RxContext->Create.NtCreateParameters); +} + +static NTSTATUS map_open_errors(DWORD status, int len) +{ + switch (status) { + case NO_ERROR: return STATUS_SUCCESS; + case ERROR_ACCESS_DENIED: + if (len > 0) return STATUS_NETWORK_ACCESS_DENIED; + else return STATUS_SUCCESS; + case ERROR_INVALID_NAME: return STATUS_OBJECT_NAME_INVALID; + case ERROR_FILE_EXISTS: return STATUS_OBJECT_NAME_COLLISION; + case ERROR_FILE_INVALID: return STATUS_FILE_INVALID; + case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND; + case ERROR_FILENAME_EXCED_RANGE: return STATUS_NAME_TOO_LONG; + case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED; + case ERROR_PATH_NOT_FOUND: return STATUS_OBJECT_PATH_NOT_FOUND; + case ERROR_SHARING_VIOLATION: return STATUS_SHARING_VIOLATION; + default: + DbgP("[ERROR] nfs41_Create: upcall returned %d returning " + "STATUS_INSUFFICIENT_RESOURCES\n", status); + case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES; + } +} +static DWORD map_disposition_to_create_retval(DWORD disposition, DWORD errno) +{ + switch(disposition) { + case FILE_SUPERSEDE: + if (errno == ERROR_FILE_NOT_FOUND) return FILE_CREATED; + else return FILE_SUPERSEDED; + case FILE_CREATE: return FILE_CREATED; + case FILE_OPEN: return FILE_OPENED; + case FILE_OPEN_IF: + if (errno == ERROR_FILE_NOT_FOUND) return FILE_CREATED; + else return FILE_OPENED; + case FILE_OVERWRITE: return FILE_OVERWRITTEN; + case FILE_OVERWRITE_IF: + if (errno == ERROR_FILE_NOT_FOUND) return FILE_CREATED; + else return FILE_OVERWRITTEN; + default: + DbgP("unknown disposition %d\n", disposition); + return FILE_OPENED; + } +} + +NTSTATUS nfs41_Create( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + __notnull PMRX_FCB Fcb = RxContext->pFcb; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + FCB_INIT_PACKET InitPacket; + RX_FILE_TYPE StorageType = 0; + NT_CREATE_PARAMETERS params = RxContext->Create.NtCreateParameters; + nfs41_updowncall_entry *entry = NULL; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FOBX nfs41_fobx = NULL; + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)Fcb->Context; + PFILE_FULL_EA_INFORMATION eainfo = NULL; + nfs3_attrs *attrs = NULL; + BOOLEAN file_changed = FALSE; + PNFS41_NETROOT_EXTENSION pNetRootContext = + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot); + + ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN ); + + DbgEn(); + print_open_args(RxContext); + if (RxContext->CurrentIrp->AssociatedIrp.SystemBuffer) + print_ea_info(1, RxContext->CurrentIrp->AssociatedIrp.SystemBuffer); + + if (Fcb->pNetRoot->Type != NET_ROOT_DISK) { + DbgP("unknown netroot type %d\n", Fcb->pNetRoot->Type); + status = STATUS_NOT_IMPLEMENTED; + goto out; + } + + if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE )) { + DbgP("FCB_STATE_PAGING_FILE\n"); + status = STATUS_NOT_IMPLEMENTED; + goto out; + } + + if (pNetRootContext->session == INVALID_HANDLE_VALUE) { + DbgP("No valid session established\n"); + goto out; + } + + status = nfs41_UpcallCreate(NFS41_OPEN, &entry); + if (status) + goto out; + entry->u.Open.filename = SrvOpen->pAlreadyPrefixedName; + entry->u.Open.access_mask = params.DesiredAccess; + entry->u.Open.access_mode = params.ShareAccess; + entry->u.Open.attrs = params.FileAttributes; + entry->u.Open.disp = params.Disposition; + entry->u.Open.copts = params.CreateOptions; + entry->u.Open.session = pVNetRootContext->session; + if (isDataAccess(params.DesiredAccess)) + entry->u.Open.open_owner_id = get_next_open_owner(); + // if we are creating a file check if nfsv3attributes were passed in + if (params.Disposition != FILE_OPEN && params.Disposition != FILE_OVERWRITE) { + if (RxContext->CurrentIrp->AssociatedIrp.SystemBuffer) { + eainfo = (PFILE_FULL_EA_INFORMATION) + RxContext->CurrentIrp->AssociatedIrp.SystemBuffer; + if (AnsiStrEq(&NfsV3Attributes, eainfo->EaName, eainfo->EaNameLength)) { + attrs = (nfs3_attrs *)(eainfo->EaName + eainfo->EaNameLength + 1); + DbgP("creating file with mode %o\n", attrs->mode); + entry->u.Open.mode = attrs->mode; + } + } + if (!entry->u.Open.mode) + entry->u.Open.mode = 0777; + } + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + status = map_open_errors(entry->status, SrvOpen->pAlreadyPrefixedName->Length); + if (status != STATUS_SUCCESS) { + print_open_error(1, entry->status); + goto out_free; + } + + if (!RxIsFcbAcquiredExclusive(Fcb)) { + ASSERT(!RxIsFcbAcquiredShared(Fcb)); + RxAcquireExclusiveFcbResourceInMRx(Fcb); + } + + RxContext->pFobx = RxCreateNetFobx(RxContext, SrvOpen); + if( RxContext->pFobx == NULL ) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out_free; + } + print_fobx(1, RxContext->pFobx); + nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + nfs41_fobx->nfs41_open_state = entry->u.Open.open_state; + nfs41_fobx->nfs41_readdir_cookie = INVALID_HANDLE_VALUE; + + // we get attributes only for data access and file (not directories) + if (Fcb->OpenCount > 0) + file_changed = has_file_changed(entry->u.Open.changeattr, + &entry->u.Open.binfo, nfs41_fcb); + if (Fcb->OpenCount == 0 || file_changed) { + print_basic_info(1, &entry->u.Open.binfo); + print_std_info(1, &entry->u.Open.sinfo); + RtlCopyMemory(&nfs41_fcb->BasicInfo, &entry->u.Open.binfo, + sizeof(entry->u.Open.binfo)); + RtlCopyMemory(&nfs41_fcb->StandardInfo, &entry->u.Open.sinfo, + sizeof(entry->u.Open.sinfo)); + nfs41_fcb->mode = entry->u.Open.mode; + nfs41_fcb->changeattr = entry->u.Open.changeattr; + nfs41_fcb->Flags = FCB_BASIC_INFO_CACHED | FCB_STANDARD_INFO_CACHED; + + RxFormInitPacket(InitPacket, + &entry->u.Open.binfo.FileAttributes, + &entry->u.Open.sinfo.NumberOfLinks, + &entry->u.Open.binfo.CreationTime, + &entry->u.Open.binfo.LastAccessTime, + &entry->u.Open.binfo.LastWriteTime, + &entry->u.Open.binfo.ChangeTime, + &entry->u.Open.sinfo.AllocationSize, + &entry->u.Open.sinfo.EndOfFile, + &entry->u.Open.sinfo.EndOfFile); + + if (entry->u.Open.sinfo.Directory) + StorageType = FileTypeDirectory; + else + StorageType = FileTypeFile; + + RxFinishFcbInitialization(Fcb, RDBSS_STORAGE_NTC(StorageType), + &InitPacket); + } + else { + DbgP("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n"); + if (nfs41_fcb->Flags) { + print_basic_info(1, &nfs41_fcb->BasicInfo); + print_std_info(1, &nfs41_fcb->StandardInfo); + } + } + + if (file_changed && !nfs41_fcb->StandardInfo.Directory) { + ULONG flag = DISABLE_CACHING; + DbgP("file object %wZ changed\n", SrvOpen->pAlreadyPrefixedName); + RxIndicateChangeOfBufferingStateForSrvOpen(SrvOpen->pVNetRoot->pNetRoot->pSrvCall, + SrvOpen, SrvOpen->Key, ULongToPtr(flag)); + } else if (!file_changed && !nfs41_fcb->StandardInfo.Directory) { +#if 0 + SrvOpen->BufferingFlags |= FCB_STATE_DISABLE_LOCAL_BUFFERING; +#else + // turn on read caching + if (params.DesiredAccess & FILE_READ_DATA) + SrvOpen->BufferingFlags |= + (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED); + // turn on write caching only if the file opened for both reading and writing + // we current CANT turn on write-only caching because RDBSS translates a write + // into a read first which leads to a NFS4ERR_IO error from the server because + // the file was opened read-only. + if ((params.DesiredAccess & FILE_READ_DATA) && + (params.DesiredAccess & FILE_WRITE_DATA || + params.DesiredAccess & FILE_APPEND_DATA)) + SrvOpen->BufferingFlags |= + (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED); +#endif + } + + if (params.CreateOptions & FILE_DELETE_ON_CLOSE) { + DbgP("We need to delete this file on close\n"); + nfs41_fcb->StandardInfo.DeletePending = TRUE; + } + + RxContext->Create.ReturnedCreateInformation = + map_disposition_to_create_retval(params.Disposition, entry->errno); + + RxContext->pFobx->OffsetOfNextEaToReturn = 1; + RxContext->CurrentIrp->IoStatus.Information = + RxContext->Create.ReturnedCreateInformation; + status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS; + +out_free: + if (entry) + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_CollapseOpen( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_ShouldTryToCollapseThisOpen( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; + DbgEn(); + if (RxContext->pRelevantSrvOpen == NULL) + status = STATUS_SUCCESS; + else + print_debug_header(RxContext); + + DbgEx(); + return status; +} + +ULONG nfs41_ExtendForCache( + IN OUT PRX_CONTEXT RxContext, + IN PLARGE_INTEGER pNewFileSize, + OUT PLARGE_INTEGER pNewAllocationSize + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + + DbgEn(); + print_debug_header(RxContext); + DbgP("input: byte count 0x%x filesize 0x%x alloc size 0x%x\n", + LowIoContext->ParamsFor.ReadWrite.ByteCount, *pNewFileSize, *pNewAllocationSize); + pNewAllocationSize->QuadPart = pNewFileSize->QuadPart + 8192; + nfs41_fcb->StandardInfo.AllocationSize.QuadPart = pNewAllocationSize->QuadPart; + nfs41_fcb->StandardInfo.EndOfFile.QuadPart = pNewFileSize->QuadPart; + DbgP("new filesize 0x%x new allocation size 0x%x\n", *pNewFileSize, + *pNewAllocationSize); + + DbgEx(); + return status; +} + + +ULONG nfs41_ExtendForNonCache( + IN OUT PRX_CONTEXT RxContext, + IN PLARGE_INTEGER pNewFileSize, + OUT PLARGE_INTEGER pNewAllocationSize + ) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_Truncate ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_ZeroExtend( + IN PRX_CONTEXT RxContext + ) +{ + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_CleanupFobx ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_SUCCESS; +#ifdef DEBUG_CLOSE + RxCaptureFcb; + RxCaptureFobx; + DbgEn(); + print_fcb(1, capFcb); + print_fobx(1, capFobx); + DbgEx(); +#endif + return status; +} + +void print_close_args(PRX_CONTEXT RxContext) +{ + print_debug_header(RxContext); +} + +static NTSTATUS map_close_errors(DWORD status) +{ + switch (status) { + case NO_ERROR: return STATUS_SUCCESS; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + default: + DbgP("failed to map windows error %d to NTSTATUS; defaulting to " + "STATUS_INTERNAL_ERROR\n", status); + case ERROR_INTERNAL_ERROR: return STATUS_INTERNAL_ERROR; + } +} + +NTSTATUS nfs41_CloseSrvOpen ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + + DbgEn(); + print_close_args(RxContext); + + status = nfs41_UpcallCreate(NFS41_CLOSE, &entry); + if (status) + goto out; + entry->u.Close.open_state = nfs41_fobx->nfs41_open_state; + entry->u.Close.session = pVNetRootContext->session; + if (!RxContext->pFcb->OpenCount) { + entry->u.Close.remove = nfs41_fcb->StandardInfo.DeletePending; + entry->u.Close.renamed = nfs41_fcb->Renamed; + entry->u.Close.filename = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + } else if (nfs41_fcb->StandardInfo.DeletePending && nfs41_fcb->StandardInfo.Directory) { + entry->u.Close.remove = nfs41_fcb->StandardInfo.DeletePending; + entry->u.Close.filename = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + } + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + /* map windows ERRORs to NTSTATUS */ + status = map_close_errors(entry->status); + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_Flush( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_ForcedClose ( + IN OUT PMRX_SRV_OPEN SrvOpen) +{ + NTSTATUS status = STATUS_SUCCESS; +#ifdef DEBUG_CLOSE + DbgEn(); + print_srv_open(1, SrvOpen); + print_fcb(1, SrvOpen->pFcb); + print_v_net_root(1, SrvOpen->pVNetRoot); +#ifdef TESTING_CACHE_INVALIDATIO + if (SrvOpen == saved_srv_open) { + DbgP("closing saved SRV_OPEN\n"); + saved_srv_open = NULL; + saved_srv_call = NULL; + } +#endif + DbgEx(); +#endif + return status; +} + +NTSTATUS nfs41_DeallocateForFcb ( + IN OUT PMRX_FCB pFcb) +{ + NTSTATUS status = STATUS_SUCCESS; +#ifdef DEBUG_CLOSE + DbgEn(); + print_fcb(1, pFcb); + print_net_root(1, pFcb->pNetRoot); + DbgEx(); +#endif + return status; +} + +NTSTATUS nfs41_DeallocateForFobx ( + IN OUT PMRX_FOBX pFobx) +{ + NTSTATUS status = STATUS_SUCCESS; +#ifdef DEBUG_CLOSE + DbgEn(); + print_fobx(1, pFobx); + print_srv_open(1, pFobx->pSrvOpen); + DbgEx(); +#endif + return status; +} + +void print_debug_filedirquery_header(PRX_CONTEXT RxContext) +{ + print_debug_header(RxContext); + DbgP("FileName='%wZ', InfoClass = %s\n", + GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), + print_file_information_class(RxContext->Info.FileInformationClass)); +} + +void print_querydir_args(PRX_CONTEXT RxContext) +{ + print_debug_filedirquery_header(RxContext); + DbgP("Filter='%wZ', Index=%d, Restart/Single/Specified/Init=%d/%d/%d/%d\n", + &RxContext->pFobx->UnicodeQueryTemplate, RxContext->QueryDirectory.FileIndex, + RxContext->QueryDirectory.RestartScan, + RxContext->QueryDirectory.ReturnSingleEntry, + RxContext->QueryDirectory.IndexSpecified, + RxContext->QueryDirectory.InitialQuery); +} + +static NTSTATUS map_querydir_errors(DWORD status) +{ + switch (status) { + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_BUFFER_OVERFLOW: return STATUS_BUFFER_OVERFLOW; + case ERROR_FILE_NOT_FOUND: return STATUS_NO_SUCH_FILE; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + case ERROR_NO_MORE_FILES: return STATUS_NO_MORE_FILES; + case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES; + default: + DbgP("failed to map windows error %d to NTSTATUS; defaulting to " + "STATUS_INVALID_NETWORK_RESPONSE\n", status); + case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE; + } +} + +NTSTATUS nfs41_QueryDirectory ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + nfs41_updowncall_entry *entry; + FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass; + PUNICODE_STRING Filter = &RxContext->pFobx->UnicodeQueryTemplate; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + + DbgEn(); + print_querydir_args(RxContext); + + switch (InfoClass) { + /* classes handled in readdir_copy_entry() and readdir_size_for_entry() */ + case FileNamesInformation: + case FileDirectoryInformation: + case FileFullDirectoryInformation: + case FileIdFullDirectoryInformation: + case FileBothDirectoryInformation: + case FileIdBothDirectoryInformation: + break; + default: + DbgP("unhandled dir query class %d\n", InfoClass); + status = STATUS_INVALID_PARAMETER; + goto out; + } + + status = nfs41_UpcallCreate(NFS41_DIR_QUERY, &entry); + if (status) + goto out; + entry->u.QueryFile.open_state = nfs41_fobx->nfs41_open_state; + entry->u.QueryFile.readdir_cookie = nfs41_fobx->nfs41_readdir_cookie; + entry->u.QueryFile.InfoClass = InfoClass; + entry->u.QueryFile.buf_len = RxContext->Info.LengthRemaining; + entry->u.QueryFile.buf = RxContext->Info.Buffer; + entry->u.QueryFile.filter = Filter; + entry->u.QueryFile.initial_query = RxContext->QueryDirectory.InitialQuery; + entry->u.QueryFile.restart_scan = RxContext->QueryDirectory.RestartScan; + entry->u.QueryFile.return_single = RxContext->QueryDirectory.ReturnSingleEntry; + entry->u.QueryFile.session = pVNetRootContext->session; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + nfs41_fobx->nfs41_readdir_cookie = INVALID_HANDLE_VALUE; + if (entry->status == STATUS_BUFFER_TOO_SMALL) { + DbgP("ERROR: buffer too small provided %d need %d\n", + RxContext->Info.LengthRemaining, entry->u.QueryFile.buf_len); + RxContext->InformationToReturn = entry->u.QueryFile.buf_len; + status = STATUS_BUFFER_TOO_SMALL; + } else if (entry->status == STATUS_SUCCESS) { + nfs41_fobx->nfs41_readdir_cookie = entry->u.QueryFile.readdir_cookie; + RtlCopyMemory(RxContext->Info.Buffer, entry->u.QueryFile.buf, + entry->u.QueryFile.buf_len); + RxContext->Info.LengthRemaining -= entry->u.QueryFile.buf_len; + status = STATUS_SUCCESS; + } else { + /* map windows ERRORs to NTSTATUS */ + status = map_querydir_errors(entry->status); + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +void print_queryvolume_args(PRX_CONTEXT RxContext) +{ + print_debug_header(RxContext); + DbgP("FileName='%wZ', InfoClass = %s BufferLen = %d\n", + GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext), + print_fs_information_class(RxContext->Info.FileInformationClass), + RxContext->Info.LengthRemaining); +} + +static NTSTATUS map_volume_errors(DWORD status) +{ + switch (status) { + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_VC_DISCONNECTED: return STATUS_CONNECTION_DISCONNECTED; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES; + default: + DbgP("failed to map windows error %d to NTSTATUS; defaulting to " + "STATUS_INVALID_NETWORK_RESPONSE\n", status); + case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE; + } +} + +static NTSTATUS get_volume_size_info( + IN PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext, + IN ULONG BytesPerUnit, + OUT OPTIONAL PLONGLONG pTotal, + OUT OPTIONAL PLONGLONG pUser, + OUT OPTIONAL PLONGLONG pAvail) +{ + nfs41_updowncall_entry *entry; + NTSTATUS status; + + DbgEn(); + + status = nfs41_UpcallCreate(NFS41_VOLUME_QUERY, &entry); + if (status) + goto out; + entry->u.Volume.session = pVNetRootContext->session; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + if (entry->status == NO_ERROR) { + if (pTotal) *pTotal = entry->u.Volume.total / BytesPerUnit; + if (pUser) *pUser = entry->u.Volume.user / BytesPerUnit; + if (pAvail) *pAvail = entry->u.Volume.avail / BytesPerUnit; + status = STATUS_SUCCESS; + } else { + /* map windows ERRORs to NTSTATUS */ + status = map_volume_errors(entry->status); + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_QueryVolumeInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + ULONG RemainingLength = RxContext->Info.LengthRemaining; + FS_INFORMATION_CLASS InfoClass = RxContext->Info.FsInformationClass; + ULONG SizeUsed; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + + DbgEn(); + print_queryvolume_args(RxContext); + + switch (InfoClass) { + case FileFsVolumeInformation: + { + PFILE_FS_VOLUME_INFORMATION pVolInfo = RxContext->Info.Buffer; + DECLARE_CONST_UNICODE_STRING(Label, L"PnfsLabel"); + + SizeUsed = sizeof(FILE_FS_VOLUME_INFORMATION) + Label.Length; + if (RemainingLength < SizeUsed) { +#if 0 + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = SizeUsed; +#else + /* Have to have status success for Notepad to be happy */ + status = STATUS_SUCCESS; +#endif + break; + } + RtlZeroMemory(pVolInfo, sizeof(FILE_FS_VOLUME_INFORMATION)); + pVolInfo->VolumeCreationTime.QuadPart = 0; + pVolInfo->VolumeSerialNumber = 0xBABAFACE; + pVolInfo->SupportsObjects = FALSE; + RtlCopyMemory(&pVolInfo->VolumeLabel[0], (PVOID)Label.Buffer, Label.Length); + RxContext->Info.LengthRemaining -= SizeUsed; + status = STATUS_SUCCESS; + } + break; + case FileFsDeviceInformation: + { + PFILE_FS_DEVICE_INFORMATION pDevInfo = RxContext->Info.Buffer; + + SizeUsed = sizeof(FILE_FS_DEVICE_INFORMATION); + if (RemainingLength < SizeUsed) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = SizeUsed; + break; + } + RtlZeroMemory(pDevInfo, SizeUsed); + pDevInfo->DeviceType = RxContext->pFcb->pNetRoot->DeviceType; + pDevInfo->Characteristics = FILE_REMOTE_DEVICE; // | FILE_READ_ONLY_DEVICE; + RxContext->Info.LengthRemaining -= SizeUsed; + status = STATUS_SUCCESS; + } + break; + case FileFsAttributeInformation: + { + PFILE_FS_ATTRIBUTE_INFORMATION pAttrInfo = RxContext->Info.Buffer; + //DECLARE_CONST_UNICODE_STRING(FSName, L"PNFS Stub FileSystemName"); + DECLARE_CONST_UNICODE_STRING(FSName, L"NFS"); + + SizeUsed = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + FSName.Length; + if (RemainingLength < SizeUsed) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn -= SizeUsed; + break; + } + RtlZeroMemory(pAttrInfo, SizeUsed); + pAttrInfo->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | + FILE_CASE_SENSITIVE_SEARCH | + FILE_SUPPORTS_REMOTE_STORAGE; + pAttrInfo->MaximumComponentNameLength = 64; + pAttrInfo->FileSystemNameLength = FSName.Length; + RtlCopyMemory(pAttrInfo->FileSystemName, FSName.Buffer, FSName.Length); + RxContext->Info.LengthRemaining -= SizeUsed; + status = STATUS_SUCCESS; + } + break; + case FileFsFullSizeInformation: + { + PFILE_FS_FULL_SIZE_INFORMATION pSizeInfo = + (PFILE_FS_FULL_SIZE_INFORMATION) RxContext->Info.Buffer; + + SizeUsed = sizeof(FILE_FS_FULL_SIZE_INFORMATION); + if (RemainingLength < SizeUsed) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = SizeUsed; + break; + } + RtlZeroMemory(pSizeInfo, SizeUsed); + pSizeInfo->SectorsPerAllocationUnit = 8; + pSizeInfo->BytesPerSector = 512; + + status = get_volume_size_info(pVNetRootContext, + pSizeInfo->SectorsPerAllocationUnit * pSizeInfo->BytesPerSector, + &pSizeInfo->TotalAllocationUnits.QuadPart, + &pSizeInfo->CallerAvailableAllocationUnits.QuadPart, + &pSizeInfo->ActualAvailableAllocationUnits.QuadPart); + RxContext->Info.LengthRemaining -= SizeUsed; + break; + } + break; + case FileFsSizeInformation: + { + PFILE_FS_SIZE_INFORMATION pSizeInfo = + (PFILE_FS_SIZE_INFORMATION) RxContext->Info.Buffer; + + SizeUsed = sizeof(FILE_FS_SIZE_INFORMATION); + if (RemainingLength < SizeUsed) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = SizeUsed; + break; + } + RtlZeroMemory(pSizeInfo, SizeUsed); + pSizeInfo->SectorsPerAllocationUnit = 8; + pSizeInfo->BytesPerSector = 512; + + status = get_volume_size_info(pVNetRootContext, + pSizeInfo->SectorsPerAllocationUnit * pSizeInfo->BytesPerSector, + &pSizeInfo->TotalAllocationUnits.QuadPart, + &pSizeInfo->AvailableAllocationUnits.QuadPart, + NULL); + RxContext->Info.LengthRemaining -= SizeUsed; + break; + } + break; + } + + DbgEx(); + return status; +} + +NTSTATUS nfs41_SetVolumeInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +void print_nfs3_attrs(nfs3_attrs *attrs) +{ + DbgP("type=%d mode=%o nlink=%d size=%d atime=%x mtime=%x ctime=%x\n", + attrs->type, attrs->mode, attrs->nlink, attrs->size, attrs->atime, + attrs->mtime, attrs->ctime); +} +void create_nfs3_attrs(nfs3_attrs *attrs, PNFS41_FCB nfs41_fcb) +{ + RtlZeroMemory(attrs, sizeof(nfs3_attrs)); + if (nfs41_fcb->StandardInfo.Directory) + attrs->type = NF3DIR; + else + attrs->type = NF3REG; + attrs->mode = nfs41_fcb->mode; + attrs->nlink = nfs41_fcb->StandardInfo.NumberOfLinks; + attrs->size.QuadPart = attrs->used.QuadPart = + nfs41_fcb->StandardInfo.EndOfFile.QuadPart; + attrs->atime.QuadPart = nfs41_fcb->BasicInfo.LastAccessTime.QuadPart; + attrs->mtime.QuadPart = nfs41_fcb->BasicInfo.ChangeTime.QuadPart; + attrs->ctime.QuadPart = nfs41_fcb->BasicInfo.CreationTime.QuadPart; +} + +NTSTATUS nfs41_QueryEaInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_EAS_NOT_SUPPORTED; + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + PFILE_GET_EA_INFORMATION query = (PFILE_GET_EA_INFORMATION) + RxContext->CurrentIrpSp->Parameters.QueryEa.EaList; + PFILE_FULL_EA_INFORMATION info; + DbgEn(); + print_debug_header(RxContext); + if (RxContext->CurrentIrpSp->Parameters.QueryEa.EaList) { + DbgP("Looking for a specific EA?\n"); + print_get_ea(1, query); + + if (AnsiStrEq(&NfsV3Attributes, query->EaName, query->EaNameLength)) { + nfs3_attrs attrs; + + const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) + + NfsV3Attributes.Length + sizeof(nfs3_attrs) - sizeof(CHAR); + if (LengthRequired > RxContext->Info.LengthRemaining) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = LengthRequired; + goto out; + } + + create_nfs3_attrs(&attrs, nfs41_fcb); + DbgP("returning fake v3attrs EA\n"); + print_nfs3_attrs(&attrs); + + info = RxContext->Info.Buffer; + info->NextEntryOffset = 0; + info->Flags = 0; + info->EaNameLength = (UCHAR)NfsV3Attributes.Length; + info->EaValueLength = sizeof(nfs3_attrs); + RtlCopyMemory(info->EaName, NfsV3Attributes.Buffer, NfsV3Attributes.Length); + RtlCopyMemory(info->EaName + info->EaNameLength + 1, &attrs, + sizeof(nfs3_attrs)); + RxContext->Info.LengthRemaining = LengthRequired; + status = STATUS_SUCCESS; + } else if (AnsiStrEq(&NfsActOnLink, query->EaName, query->EaNameLength) + || AnsiStrEq(&NfsSymlinkTargetName, query->EaName, query->EaNameLength)) { + + const LONG LengthRequired = sizeof(FILE_FULL_EA_INFORMATION) + + NfsActOnLink.Length - sizeof(CHAR); + if (LengthRequired > RxContext->Info.LengthRemaining) { + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = LengthRequired; + goto out; + } + + DbgP("returning fake link EA\n"); + info = RxContext->Info.Buffer; + info->NextEntryOffset = 0; + info->Flags = 0; + info->EaNameLength = (UCHAR)NfsActOnLink.Length; + info->EaValueLength = 0; + RtlCopyMemory(info->EaName, NfsActOnLink.Buffer, NfsActOnLink.Length); + RxContext->Info.LengthRemaining = LengthRequired; + status = STATUS_SUCCESS; + } else + DbgP("Couldn't match %s\n", query->EaName); + } +out: + DbgEx(); + return status; +} + +static NTSTATUS map_setea_error(DWORD error) +{ + switch (error) { + case NO_ERROR: return STATUS_SUCCESS; + case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case ERROR_FILE_EXISTS: return STATUS_OBJECT_NAME_COLLISION; + case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND; + case ERROR_PATH_NOT_FOUND: return STATUS_OBJECT_PATH_NOT_FOUND; + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_NOT_SUPPORTED: return STATUS_NOT_IMPLEMENTED; + case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_BUFFER_OVERFLOW: return STATUS_INSUFFICIENT_RESOURCES; + default: + DbgP("failed to map windows error %d to NTSTATUS; " + "defaulting to STATUS_INVALID_PARAMETER\n", error); + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + } +} + +NTSTATUS nfs41_SetEaInformation ( + IN OUT struct _RX_CONTEXT *RxContext) +{ + NTSTATUS status = STATUS_EAS_NOT_SUPPORTED; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + PFILE_FULL_EA_INFORMATION eainfo = + (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer; + nfs3_attrs *attrs = NULL; + + DbgEn(); + print_debug_header(RxContext); + print_ea_info(1, eainfo); + if (AnsiStrEq(&NfsV3Attributes, eainfo->EaName, eainfo->EaNameLength)) { + attrs = (nfs3_attrs *)(eainfo->EaName + eainfo->EaNameLength + 1); + print_nfs3_attrs(attrs); + DbgP("old mode is %x new mode is %x\n", nfs41_fcb->mode, attrs->mode); + nfs41_fcb->mode = attrs->mode; + } else + goto out; + + status = nfs41_UpcallCreate(NFS41_EA_SET, &entry); + if (status) + goto out; + entry->u.SetEa.open_state = nfs41_fobx->nfs41_open_state; + entry->u.SetEa.session = pVNetRootContext->session; + entry->u.SetEa.mode = attrs->mode; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + status = map_setea_error(entry->status); + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_QuerySecurityInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_SetSecurityInformation ( + IN OUT struct _RX_CONTEXT *RxContext) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_QueryQuotaInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_SetQuotaInformation ( + IN OUT struct _RX_CONTEXT *RxContext) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_SetVolumeInfo ( + IN OUT struct _RX_CONTEXT *RxContext) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +void print_queryfile_args(PRX_CONTEXT RxContext) +{ + print_debug_filedirquery_header(RxContext); +} + +static NTSTATUS map_queryfile_error(DWORD error) +{ + switch (error) { + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + default: + DbgP("failed to map windows error %d to NTSTATUS; defaulting to " + "STATUS_INVALID_NETWORK_RESPONSE\n", error); + case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE; + } +} + +NTSTATUS nfs41_QueryFileInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + + DbgEn(); + switch (InfoClass) { + case FileInternalInformation: + { + PFILE_INTERNAL_INFORMATION info = + (PFILE_INTERNAL_INFORMATION)RxContext->Info.Buffer; + info->IndexNumber.QuadPart = 0; + RxContext->Info.LengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION); + status = STATUS_SUCCESS; + goto out; + } + case FileEaInformation: + { + PFILE_EA_INFORMATION info = + (PFILE_EA_INFORMATION)RxContext->Info.Buffer; + info->EaSize = 0; + RxContext->Info.LengthRemaining -= sizeof(FILE_EA_INFORMATION); + status = STATUS_SUCCESS; + goto out; + } +#ifdef FCB_ATTR_CACHING + case FileBasicInformation: + if(nfs41_fcb->Flags & FCB_BASIC_INFO_CACHED) { + RtlCopyMemory(RxContext->Info.Buffer, &nfs41_fcb->BasicInfo, + sizeof(nfs41_fcb->BasicInfo)); + RxContext->Info.LengthRemaining -= sizeof(nfs41_fcb->BasicInfo); + status = STATUS_SUCCESS; + goto out; + } + break; + case FileStandardInformation: + if(nfs41_fcb->Flags & FCB_STANDARD_INFO_CACHED) { + RtlCopyMemory(RxContext->Info.Buffer, &nfs41_fcb->StandardInfo, + sizeof(nfs41_fcb->StandardInfo)); + RxContext->Info.LengthRemaining -= sizeof(nfs41_fcb->StandardInfo); + status = STATUS_SUCCESS; + goto out; + } + break; +#else + case FileBasicInformation: + case FileStandardInformation: +#endif + case FileAttributeTagInformation: + break; + default: + DbgP("unhandled file query class %d\n", InfoClass); + status = STATUS_INVALID_PARAMETER; + goto out; + } + print_queryfile_args(RxContext); + + status = nfs41_UpcallCreate(NFS41_FILE_QUERY, &entry); + if (status) + goto out; + entry->u.QueryFile.open_state = nfs41_fobx->nfs41_open_state; + entry->u.QueryFile.InfoClass = InfoClass; + entry->u.QueryFile.buf = RxContext->Info.Buffer; + entry->u.QueryFile.buf_len = RxContext->Info.LengthRemaining; + entry->u.QueryFile.session = pVNetRootContext->session; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + if (entry->status == STATUS_BUFFER_TOO_SMALL) { + RxContext->InformationToReturn = entry->u.QueryFile.buf_len; + status = STATUS_BUFFER_TOO_SMALL; + } else if (entry->status == STATUS_SUCCESS) { + BOOLEAN DeletePending = FALSE; + RtlCopyMemory(RxContext->Info.Buffer, entry->u.QueryFile.buf, + entry->u.QueryFile.buf_len); + RxContext->Info.LengthRemaining -= entry->u.QueryFile.buf_len; + status = STATUS_SUCCESS; + + switch (InfoClass) { + case FileBasicInformation: + RtlCopyMemory(&nfs41_fcb->BasicInfo, RxContext->Info.Buffer, + sizeof(nfs41_fcb->BasicInfo)); + nfs41_fcb->Flags |= FCB_BASIC_INFO_CACHED; + print_basic_info(1, &nfs41_fcb->BasicInfo); + break; + case FileStandardInformation: +#ifndef FCB_ATTR_CACHING + /* this a fix for RDBSS behaviour when it first calls ExtendForCache, + * then it sends a file query irp for standard attributes and + * expects to receive EndOfFile of value set by the ExtendForCache. + * It seems to cache the filesize based on that instead of sending + * a file size query for after doing the write. + */ + { + PFILE_STANDARD_INFORMATION std_info; + std_info = (PFILE_STANDARD_INFORMATION)RxContext->Info.Buffer; + if (nfs41_fcb->StandardInfo.AllocationSize.QuadPart > + std_info->AllocationSize.QuadPart) { + DbgP("Old AllocationSize is bigger: saving %x\n", + nfs41_fcb->StandardInfo.AllocationSize.QuadPart); + std_info->AllocationSize.QuadPart = + nfs41_fcb->StandardInfo.AllocationSize.QuadPart; + } + if (nfs41_fcb->StandardInfo.EndOfFile.QuadPart > + std_info->EndOfFile.QuadPart) { + DbgP("Old EndOfFile is bigger: saving %x\n", + nfs41_fcb->StandardInfo.EndOfFile); + std_info->EndOfFile.QuadPart = + nfs41_fcb->StandardInfo.EndOfFile.QuadPart; + } + } +#endif + if (nfs41_fcb->StandardInfo.DeletePending) + DeletePending = TRUE; + RtlCopyMemory(&nfs41_fcb->StandardInfo, RxContext->Info.Buffer, + sizeof(nfs41_fcb->StandardInfo)); + nfs41_fcb->StandardInfo.DeletePending = DeletePending; + nfs41_fcb->Flags |= FCB_STANDARD_INFO_CACHED; + print_std_info(1, &nfs41_fcb->StandardInfo); + break; + } + } else { + status = map_queryfile_error(entry->status); + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +void print_setfile_args(PRX_CONTEXT RxContext) +{ + print_debug_filedirquery_header(RxContext); +} + +static NTSTATUS map_setfile_error(DWORD error) +{ + switch (error) { + case NO_ERROR: return STATUS_SUCCESS; + case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case ERROR_FILE_EXISTS: return STATUS_OBJECT_NAME_COLLISION; + case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND; + case ERROR_PATH_NOT_FOUND: return STATUS_OBJECT_PATH_NOT_FOUND; + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_NOT_SAME_DEVICE: return STATUS_NOT_SAME_DEVICE; + case ERROR_NOT_SUPPORTED: return STATUS_NOT_IMPLEMENTED; + case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_BUFFER_OVERFLOW: return STATUS_INSUFFICIENT_RESOURCES; + default: + DbgP("failed to map windows error %d to NTSTATUS; " + "defaulting to STATUS_INVALID_PARAMETER\n", error); + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + } +} + +NTSTATUS nfs41_SetFileInformation ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + FILE_INFORMATION_CLASS InfoClass = RxContext->Info.FileInformationClass; + PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + FILE_RENAME_INFORMATION rinfo; + PFILE_OBJECT fo = RxContext->CurrentIrpSp->FileObject; + + DbgEn(); + print_setfile_args(RxContext); + switch (InfoClass) { + case FileRenameInformation: + { + PFILE_RENAME_INFORMATION rinfo = + (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer; + if (rinfo->RootDirectory) { + status = STATUS_NOT_SUPPORTED; + goto out; + } + nfs41_fcb->Flags = 0; + } + break; + case FileLinkInformation: + { + PFILE_LINK_INFORMATION linfo = + (PFILE_LINK_INFORMATION)RxContext->Info.Buffer; + if (linfo->RootDirectory) { + status = STATUS_NOT_SUPPORTED; + goto out; + } + nfs41_fcb->Flags = 0; + } + break; + case FileDispositionInformation: + { + PFILE_DISPOSITION_INFORMATION dinfo = + (PFILE_DISPOSITION_INFORMATION)RxContext->Info.Buffer; + if (dinfo->DeleteFile) { + // we can delete directories right away + if (nfs41_fcb->StandardInfo.Directory) { + status = nfs41_UpcallCreate(NFS41_CLOSE, &entry); + if (status) + goto out; + entry->u.Close.open_state = nfs41_fobx->nfs41_open_state; + entry->u.Close.session = pVNetRootContext->session; + entry->u.Close.remove = 1; + entry->u.Close.renamed = nfs41_fcb->Renamed; + entry->u.Close.filename = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext); + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + /* map windows ERRORs to NTSTATUS */ + status = map_close_errors(entry->status); + RxFreePool(entry); + goto out; + } + nfs41_fcb->Flags = 0; + nfs41_fcb->StandardInfo.DeletePending = TRUE; + if (RxContext->pFcb->OpenCount > 1 && !nfs41_fcb->StandardInfo.Directory) { + rinfo.ReplaceIfExists = 0; + rinfo.RootDirectory = INVALID_HANDLE_VALUE; + rinfo.FileNameLength = 0; + rinfo.FileName[0] = L'\0'; + InfoClass = FileRenameInformation; + nfs41_fcb->Renamed = TRUE; + break; + } + } + status = STATUS_SUCCESS; + goto out; + } + case FileBasicInformation: + case FileAllocationInformation: + nfs41_fcb->Flags = 0; + break; + case FileEndOfFileInformation: + { + PFILE_END_OF_FILE_INFORMATION info = + (PFILE_END_OF_FILE_INFORMATION)RxContext->Info.Buffer; + nfs41_fcb->StandardInfo.AllocationSize = + nfs41_fcb->StandardInfo.EndOfFile = info->EndOfFile; + nfs41_fcb->Flags = 0; + break; + } + default: + DbgP("unknown set_file information class %d\n", InfoClass); + status = STATUS_NOT_SUPPORTED; + goto out; + } + + status = nfs41_UpcallCreate(NFS41_FILE_SET, &entry); + if (status) + goto out; + entry->u.SetFile.open_state = nfs41_fobx->nfs41_open_state; + entry->u.SetFile.filename = FileName; + entry->u.SetFile.InfoClass = InfoClass; + switch(InfoClass) { + case FileAllocationInformation: + case FileEndOfFileInformation: + entry->u.SetFile.open_owner_id = get_next_open_owner(); + if (fo->ReadAccess) + entry->u.SetFile.access_mask = FILE_READ_DATA; + if (fo->WriteAccess) + entry->u.SetFile.access_mask |= FILE_WRITE_DATA; + if (fo->SharedRead) + entry->u.SetFile.access_mode = FILE_SHARE_READ; + if (fo->SharedWrite) + entry->u.SetFile.access_mode |= FILE_SHARE_WRITE; + } + if (RxContext->Info.FileInformationClass == FileDispositionInformation && + InfoClass == FileRenameInformation) { + entry->u.SetFile.buf = &rinfo; + entry->u.SetFile.buf_len = sizeof(rinfo); + } else { + entry->u.SetFile.buf = RxContext->Info.Buffer; + entry->u.SetFile.buf_len = RxContext->Info.Length; + } + entry->u.SetFile.session = pVNetRootContext->session; + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + status = map_setfile_error(entry->status); + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_SetFileInformationAtCleanup( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status; + DbgEn(); + status = nfs41_SetFileInformation(RxContext); + DbgEx(); + return status; +} + +NTSTATUS nfs41_IsValidDirectory ( + IN OUT PRX_CONTEXT RxContext, + IN PUNICODE_STRING DirectoryName) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_PreparseName( + IN OUT PRX_CONTEXT RxContext, + IN PUNICODE_STRING Name + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + //DbgEn(); + //DbgEx(); + return status; +} + +NTSTATUS nfs41_ComputeNewBufferingState( + IN OUT PMRX_SRV_OPEN pSrvOpen, + IN PVOID pMRxContext, + OUT ULONG *pNewBufferingState) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG flag; + DbgEn(); + flag = PtrToUlong(pMRxContext); + DbgP("pSrvOpen %p Flags %08x\n", pSrvOpen, pSrvOpen->BufferingFlags); + switch(flag) { + case DISABLE_CACHING: + if (pSrvOpen->BufferingFlags & + (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED)) + pSrvOpen->BufferingFlags &= + ~(FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED); + if (pSrvOpen->BufferingFlags & + (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED)) + pSrvOpen->BufferingFlags &= + ~(FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED); + pSrvOpen->BufferingFlags |= FCB_STATE_DISABLE_LOCAL_BUFFERING; + break; + case ENABLE_READ_CACHING: + pSrvOpen->BufferingFlags = + (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED); + break; + case ENABLE_WRITE_CACHING: + pSrvOpen->BufferingFlags = + (FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED); + break; + case ENABLE_READWRITE_CACHING: + pSrvOpen->BufferingFlags = + (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED | + FCB_STATE_WRITECACHING_ENABLED | FCB_STATE_WRITEBUFFERING_ENABLED); + } + DbgP("new Flags %08x\n", pSrvOpen->BufferingFlags); + *pNewBufferingState = pSrvOpen->BufferingFlags; + + DbgEx(); + return status; +} + +void print_readwrite_args(PRX_CONTEXT RxContext) +{ + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + PIO_STACK_LOCATION IrpSp = RxContext->CurrentIrpSp; + PIRP Irp = RxContext->CurrentIrp; + + print_debug_header(RxContext); + DbgP("Irp flags: paging io %ld noncachedio %ld syncio %ld\n", + FlagOn(Irp->Flags, IRP_PAGING_IO), + FlagOn(Irp->Flags, IRP_NOCACHE), + FlagOn(IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO)); + DbgP("Bytecount 0x%x Byteoffset 0x%x Buffer %p\n", + LowIoContext->ParamsFor.ReadWrite.ByteCount, + LowIoContext->ParamsFor.ReadWrite.ByteOffset, + LowIoContext->ParamsFor.ReadWrite.Buffer); +} + +void enable_caching(PMRX_SRV_OPEN SrvOpen) +{ + ULONG flag = 0; + if (SrvOpen->DesiredAccess & FILE_READ_DATA) + flag = ENABLE_READ_CACHING; + if (SrvOpen->DesiredAccess & FILE_WRITE_DATA) + flag = ENABLE_WRITE_CACHING; + if ((SrvOpen->DesiredAccess & FILE_READ_DATA) && + (SrvOpen->DesiredAccess & FILE_WRITE_DATA)) + flag = ENABLE_READWRITE_CACHING; + + print_caching_level(1, flag); + + if (!flag) + return; + + RxIndicateChangeOfBufferingStateForSrvOpen(SrvOpen->pVNetRoot->pNetRoot->pSrvCall, + SrvOpen, SrvOpen->Key, ULongToPtr(flag)); +} + +static NTSTATUS map_readwrite_errors(DWORD status) +{ + switch (status) { + case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; + case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE; + case ERROR_FILE_INVALID: return STATUS_FILE_CLOSED; + case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; + case ERROR_LOCK_VIOLATION: return STATUS_FILE_LOCK_CONFLICT; + case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + default: + DbgP("failed to map windows error %d to NTSTATUS; " + "defaulting to STATUS_NET_WRITE_FAULT\n", status); + case ERROR_NET_WRITE_FAULT: return STATUS_NET_WRITE_FAULT; + } +} + +NTSTATUS nfs41_Read ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + BOOLEAN async = FALSE; + + DbgEn(); + print_readwrite_args(RxContext); + + status = nfs41_UpcallCreate(NFS41_READ, &entry); + if (status) + goto out; + entry->u.ReadWrite.open_state = nfs41_fobx->nfs41_open_state; + entry->u.ReadWrite.MdlAddress = LowIoContext->ParamsFor.ReadWrite.Buffer; + entry->u.ReadWrite.len = LowIoContext->ParamsFor.ReadWrite.ByteCount; + entry->u.ReadWrite.offset = LowIoContext->ParamsFor.ReadWrite.ByteOffset; + entry->u.ReadWrite.session = pVNetRootContext->session; + if (FlagOn(RxContext->CurrentIrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) == FALSE) { + entry->u.ReadWrite.rxcontext = RxContext; + async = entry->async_op = TRUE; + } + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + if (async) { + DbgP("This is asynchronous read, returning control back to the user\n"); + status = STATUS_PENDING; + goto out; + } + + if (entry->status == NO_ERROR) { + status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS; + RxContext->IoStatusBlock.Information = entry->u.ReadWrite.len; + nfs41_fcb->Flags = 0; + + if (!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, + LOWIO_READWRITEFLAG_PAGING_IO) && + (SrvOpen->DesiredAccess & FILE_READ_DATA) && + !(SrvOpen->BufferingFlags & + (FCB_STATE_READBUFFERING_ENABLED | FCB_STATE_READCACHING_ENABLED))) + enable_caching(SrvOpen); + } else { + status = map_readwrite_errors(entry->status); + RxContext->CurrentIrp->IoStatus.Status = status; + RxContext->IoStatusBlock.Information = 0; + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_Write ( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + PNFS41_FCB nfs41_fcb = (PNFS41_FCB)(RxContext->pFcb)->Context; + BOOLEAN async = FALSE; + + DbgEn(); + print_readwrite_args(RxContext); + + status = nfs41_UpcallCreate(NFS41_WRITE, &entry); + if (status) + goto out; + entry->u.ReadWrite.open_state = nfs41_fobx->nfs41_open_state; + entry->u.ReadWrite.MdlAddress = LowIoContext->ParamsFor.ReadWrite.Buffer; + entry->u.ReadWrite.len = LowIoContext->ParamsFor.ReadWrite.ByteCount; + entry->u.ReadWrite.offset = LowIoContext->ParamsFor.ReadWrite.ByteOffset; + entry->u.ReadWrite.session = pVNetRootContext->session; + if (FlagOn(RxContext->CurrentIrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO) == FALSE) { + entry->u.ReadWrite.rxcontext = RxContext; + async = entry->async_op = TRUE; + } + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + if (async) { + DbgP("This is asynchronous write, returning control back to the user\n"); + status = STATUS_PENDING; + goto out; + } + + if (entry->status == NO_ERROR) { + //update cached file attributes + nfs41_fcb->StandardInfo.EndOfFile.QuadPart = entry->u.ReadWrite.len + + entry->u.ReadWrite.offset; + status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS; + RxContext->IoStatusBlock.Information = entry->u.ReadWrite.len; + nfs41_fcb->Flags = 0; + + if (!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, + LOWIO_READWRITEFLAG_PAGING_IO) && + (SrvOpen->DesiredAccess & FILE_WRITE_DATA) && + (SrvOpen->DesiredAccess & FILE_READ_DATA) && + !(SrvOpen->BufferingFlags & + (FCB_STATE_WRITEBUFFERING_ENABLED | FCB_STATE_WRITECACHING_ENABLED))) + enable_caching(SrvOpen); + } else { + status = map_readwrite_errors(entry->status); + RxContext->CurrentIrp->IoStatus.Status = status; + RxContext->IoStatusBlock.Information = 0; + } + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_IsLockRealizable ( + IN OUT PMRX_FCB pFcb, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + IN ULONG LowIoLockFlags) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n", + ByteOffset->QuadPart,Length->QuadPart, + BooleanFlagOn(LowIoLockFlags, SL_EXCLUSIVE_LOCK), + !BooleanFlagOn(LowIoLockFlags, SL_FAIL_IMMEDIATELY)); + DbgEx(); + return status; +} + +static NTSTATUS map_lock_errors(DWORD status) +{ + switch (status) { + case NO_ERROR: return STATUS_SUCCESS; + case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; + case ERROR_LOCK_FAILED: return STATUS_LOCK_NOT_GRANTED; + case ERROR_NOT_LOCKED: return STATUS_RANGE_NOT_LOCKED; + case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED: return STATUS_UNSUCCESSFUL; + case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES; + case ERROR_SHARING_VIOLATION: return STATUS_SHARING_VIOLATION; + /* if we return ERROR_INVALID_PARAMETER, Windows translates that to + * success!! */ + case ERROR_INVALID_PARAMETER: return STATUS_LOCK_NOT_GRANTED; + default: + DbgP("failed to map windows error %d to NTSTATUS; " + "defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", status); + case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE; + } +} + +static void print_lock_args(PRX_CONTEXT RxContext) +{ + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + const ULONG flags = LowIoContext->ParamsFor.Locks.Flags; + print_debug_header(RxContext); + DbgP("offset 0x%llx, length 0x%llx, exclusive=%u, blocking=%u\n", + LowIoContext->ParamsFor.Locks.ByteOffset, + LowIoContext->ParamsFor.Locks.Length, + BooleanFlagOn(flags, SL_EXCLUSIVE_LOCK), + !BooleanFlagOn(flags, SL_FAIL_IMMEDIATELY)); +} + + +/* use exponential backoff between polls for blocking locks */ +#define MSEC_TO_RELATIVE_WAIT (-10000) +#define MIN_LOCK_POLL_WAIT (500 * MSEC_TO_RELATIVE_WAIT) /* 500ms */ +#define MAX_LOCK_POLL_WAIT (30000 * MSEC_TO_RELATIVE_WAIT) /* 30s */ + +static void denied_lock_backoff( + IN OUT PLARGE_INTEGER delay) +{ + if (delay->QuadPart == 0) + delay->QuadPart = MIN_LOCK_POLL_WAIT; + else + delay->QuadPart <<= 1; + + if (delay->QuadPart < MAX_LOCK_POLL_WAIT) + delay->QuadPart = MAX_LOCK_POLL_WAIT; +} + +NTSTATUS nfs41_Lock( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_SUCCESS; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + const ULONG flags = LowIoContext->ParamsFor.Locks.Flags; + LARGE_INTEGER poll_delay = {0}; + + DbgEn(); + print_lock_args(RxContext); + +/* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb, + LowIoContext->ResourceThreadId); */ + + status = nfs41_UpcallCreate(NFS41_LOCK, &entry); + if (status) + goto out; + entry->u.Lock.open_state = nfs41_fobx->nfs41_open_state; + entry->u.Lock.session = pVNetRootContext->session; + entry->u.Lock.offset = LowIoContext->ParamsFor.Locks.ByteOffset; + entry->u.Lock.length = LowIoContext->ParamsFor.Locks.Length; + entry->u.Lock.exclusive = BooleanFlagOn(flags, SL_EXCLUSIVE_LOCK); + entry->u.Lock.blocking = !BooleanFlagOn(flags, SL_FAIL_IMMEDIATELY); + +retry_upcall: + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + /* blocking locks keep trying until it succeeds */ + if (entry->status == ERROR_LOCK_FAILED && entry->u.Lock.blocking) { + denied_lock_backoff(&poll_delay); + DbgP("returned ERROR_LOCK_FAILED; retrying in %llums\n", + poll_delay.QuadPart / MSEC_TO_RELATIVE_WAIT); + KeDelayExecutionThread(KernelMode, FALSE, &poll_delay); + entry->state = NFS41_WAITING_FOR_UPCALL; + goto retry_upcall; + } + + status = map_lock_errors(entry->status); + RxContext->CurrentIrp->IoStatus.Status = status; + + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +static void print_unlock_args(PRX_CONTEXT RxContext) +{ + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + print_debug_header(RxContext); + if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) { + PLOWIO_LOCK_LIST lock = LowIoContext->ParamsFor.Locks.LockList; + DbgP("LOWIO_OP_UNLOCK_MULTIPLE:"); + while (lock) { + DbgP(" (offset=%llu, length=%llu)", lock->ByteOffset, lock->Length); + lock = lock->Next; + } + DbgP("\n"); + } else { + DbgP("LOWIO_OP_UNLOCK: offset=%llu, length=%llu\n", + LowIoContext->ParamsFor.Locks.ByteOffset, + LowIoContext->ParamsFor.Locks.Length); + } +} + +static __inline ULONG unlock_list_count(PLOWIO_LOCK_LIST lock) +{ + ULONG count = 0; + while (lock) { + count++; + lock = lock->Next; + } + return count; +} + +NTSTATUS nfs41_Unlock( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_SUCCESS; + nfs41_updowncall_entry *entry; + PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context; + PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext; + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; + PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); + + DbgEn(); + print_lock_args(RxContext); + +/* RxReleaseFcbResourceForThreadInMRx(RxContext, RxContext->pFcb, + LowIoContext->ResourceThreadId); */ + + status = nfs41_UpcallCreate(NFS41_UNLOCK, &entry); + if (status) + goto out; + entry->u.Unlock.open_state = nfs41_fobx->nfs41_open_state; + entry->u.Unlock.session = pVNetRootContext->session; + + if (LowIoContext->Operation == LOWIO_OP_UNLOCK_MULTIPLE) { + entry->u.Unlock.count = unlock_list_count( + LowIoContext->ParamsFor.Locks.LockList); + RtlCopyMemory(&entry->u.Unlock.locks, + LowIoContext->ParamsFor.Locks.LockList, + sizeof(LOWIO_LOCK_LIST)); + } else { + entry->u.Unlock.count = 1; + entry->u.Unlock.locks.ByteOffset = + LowIoContext->ParamsFor.Locks.ByteOffset; + entry->u.Unlock.locks.Length = + LowIoContext->ParamsFor.Locks.Length; + } + + if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { + status = STATUS_INTERNAL_ERROR; + goto out; + } + + status = map_lock_errors(entry->status); + RxContext->CurrentIrp->IoStatus.Status = status; + RxFreePool(entry); +out: + DbgEx(); + return status; +} + +NTSTATUS nfs41_FsCtl( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + DbgEn(); + DbgEx(); + return status; + +} + +NTSTATUS nfs41_IoCtl( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_NotifyChangeDirectory( + IN OUT PRX_CONTEXT RxContext) +{ + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_CompleteBufferingStateChangeRequest ( + IN OUT PRX_CONTEXT RxContext, + IN OUT PMRX_SRV_OPEN SrvOpen, + IN PVOID pContext) +{ + NTSTATUS status = STATUS_SUCCESS; + DbgEn(); + DbgEx(); + return status; +} + +NTSTATUS nfs41_AreFilesAliased( + PFCB Fcb1, + PFCB Fcb2) +{ + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + PMRX_SRV_OPEN srv1 = (PMRX_SRV_OPEN)Fcb1->InternalSrvOpen, + srv2 = (PMRX_SRV_OPEN)Fcb2->InternalSrvOpen; + DbgEn(); + DbgP("fcb1 %p fcb2 %p srv1 %p srv2 %p\n", Fcb1, Fcb2, srv1, srv2); + DbgP("file1 %wZ file2 %wZ\n", srv1->pAlreadyPrefixedName, + srv2->pAlreadyPrefixedName); + DbgEx(); + return status; +} + +NTSTATUS nfs41_GetConnectionId( + IN OUT PRX_CONTEXT RxContext, + IN OUT PRX_CONNECTION_ID UniqueId) +{ + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + //DbgEn(); + //DbgEx(); + return status; +} + +NTSTATUS nfs41_FsdDispatch ( + IN PDEVICE_OBJECT dev, + IN PIRP Irp + ) +{ +#ifdef DEBUG_FSDDISPATCH + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); +#endif + NTSTATUS status; + +#ifdef DEBUG_FSDDISPATCH + DbgEn(); + DbgP("CURRENT IRP = %d.%d\n", IrpSp->MajorFunction, IrpSp->MinorFunction); + if(IrpSp->FileObject) + DbgP("FileOject %p Filename %wZ\n", IrpSp->FileObject, + &IrpSp->FileObject->FileName); + switch(IrpSp->MajorFunction) { + case 0: + DbgP("Create: share access %d\n", IrpSp->Parameters.Create.ShareAccess); + break; + case 5: + DbgP("InfoClass %d\n", IrpSp->Parameters.QueryFile.FileInformationClass); + break; + } +#endif + + if (dev != (PDEVICE_OBJECT)nfs41_dev) { + DbgP("*** not ours ***\n"); + Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT ); + status = STATUS_INVALID_DEVICE_REQUEST; + goto out; + } + + status = RxFsdDispatch((PRDBSS_DEVICE_OBJECT)dev,Irp); + /* AGLO: 08/05/2009 - looks like RxFsdDispatch frees IrpSp */ + +out: +#ifdef DEBUG_FSDDISPATCH + DbgEx(); +#endif + return status; +} + +NTSTATUS nfs41_init_ops() +{ + DbgEn(); + + ZeroAndInitializeNodeType(&nfs41_ops, RDBSS_NTC_MINIRDR_DISPATCH, + sizeof(MINIRDR_DISPATCH)); + + nfs41_ops.MRxFlags = (RDBSS_MANAGE_NET_ROOT_EXTENSION | + RDBSS_MANAGE_V_NET_ROOT_EXTENSION | + RDBSS_MANAGE_FCB_EXTENSION | + RDBSS_MANAGE_SRV_OPEN_EXTENSION | + RDBSS_MANAGE_FOBX_EXTENSION); + + nfs41_ops.MRxSrvCallSize = 0; + nfs41_ops.MRxNetRootSize = sizeof(NFS41_NETROOT_EXTENSION); + nfs41_ops.MRxVNetRootSize = sizeof(NFS41_V_NET_ROOT_EXTENSION); + nfs41_ops.MRxFcbSize = sizeof(NFS41_FCB); + nfs41_ops.MRxSrvOpenSize = sizeof(NFS41_SRV_OPEN); + nfs41_ops.MRxFobxSize = sizeof(NFS41_FOBX); + + // Mini redirector cancel routine .. + + nfs41_ops.MRxCancel = NULL; + + // + // Mini redirector Start/Stop. Each mini-rdr can be started or stopped + // while the others continue to operate. + // + + nfs41_ops.MRxStart = nfs41_Start; + nfs41_ops.MRxStop = nfs41_Stop; + nfs41_ops.MRxDevFcbXXXControlFile = nfs41_DevFcbXXXControlFile; + + // + // Mini redirector name resolution. + // + + nfs41_ops.MRxCreateSrvCall = nfs41_CreateSrvCall; + nfs41_ops.MRxSrvCallWinnerNotify = nfs41_SrvCallWinnerNotify; + nfs41_ops.MRxCreateVNetRoot = nfs41_CreateVNetRoot; + nfs41_ops.MRxExtractNetRootName = nfs41_ExtractNetRootName; + nfs41_ops.MRxFinalizeSrvCall = nfs41_FinalizeSrvCall; + nfs41_ops.MRxFinalizeNetRoot = nfs41_FinalizeNetRoot; + nfs41_ops.MRxFinalizeVNetRoot = nfs41_FinalizeVNetRoot; + + // + // File System Object Creation/Deletion. + // + + nfs41_ops.MRxCreate = nfs41_Create; + nfs41_ops.MRxCollapseOpen = nfs41_CollapseOpen; + nfs41_ops.MRxShouldTryToCollapseThisOpen = nfs41_ShouldTryToCollapseThisOpen; + nfs41_ops.MRxExtendForCache = nfs41_ExtendForCache; + nfs41_ops.MRxExtendForNonCache = nfs41_ExtendForCache; + nfs41_ops.MRxZeroExtend = nfs41_ZeroExtend; + nfs41_ops.MRxTruncate = nfs41_Truncate; + nfs41_ops.MRxCleanupFobx = nfs41_CleanupFobx; + nfs41_ops.MRxCloseSrvOpen = nfs41_CloseSrvOpen; + nfs41_ops.MRxFlush = nfs41_Flush; + nfs41_ops.MRxForceClosed = nfs41_ForcedClose; + nfs41_ops.MRxDeallocateForFcb = nfs41_DeallocateForFcb; + nfs41_ops.MRxDeallocateForFobx = nfs41_DeallocateForFobx; + nfs41_ops.MRxIsLockRealizable = nfs41_IsLockRealizable; + // + // File System Objects query/Set + // + + nfs41_ops.MRxQueryDirectory = nfs41_QueryDirectory; + nfs41_ops.MRxQueryVolumeInfo = nfs41_QueryVolumeInformation; + nfs41_ops.MRxSetVolumeInfo = nfs41_SetVolumeInfo; + nfs41_ops.MRxQueryEaInfo = nfs41_QueryEaInformation; + nfs41_ops.MRxSetEaInfo = nfs41_SetEaInformation; + nfs41_ops.MRxQuerySdInfo = nfs41_QuerySecurityInformation; + nfs41_ops.MRxSetSdInfo = nfs41_SetSecurityInformation; + nfs41_ops.MRxQueryQuotaInfo = nfs41_QueryQuotaInformation; + nfs41_ops.MRxSetQuotaInfo = nfs41_SetQuotaInformation; + nfs41_ops.MRxQueryFileInfo = nfs41_QueryFileInformation; + nfs41_ops.MRxSetFileInfo = nfs41_SetFileInformation; + nfs41_ops.MRxSetFileInfoAtCleanup = nfs41_SetFileInformationAtCleanup ; + // + // Buffering state change + // + + nfs41_ops.MRxComputeNewBufferingState = nfs41_ComputeNewBufferingState; + + // + // File System Object I/O + // + + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_READ] = nfs41_Read; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_WRITE] = nfs41_Write; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_SHAREDLOCK] = nfs41_Lock; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_EXCLUSIVELOCK] = nfs41_Lock; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_UNLOCK] = nfs41_Unlock; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_UNLOCK_MULTIPLE] = nfs41_Unlock; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_FSCTL] = nfs41_FsCtl; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_IOCTL] = nfs41_IoCtl; + nfs41_ops.MRxLowIOSubmit[LOWIO_OP_NOTIFY_CHANGE_DIRECTORY] = + nfs41_NotifyChangeDirectory; + + // + // Miscellanous + // + + nfs41_ops.MRxCompleteBufferingStateChangeRequest = + nfs41_CompleteBufferingStateChangeRequest; + nfs41_ops.MRxIsValidDirectory = nfs41_IsValidDirectory; + nfs41_ops.MRxPreparseName = nfs41_PreparseName; + + nfs41_ops.MRxAreFilesAliased = nfs41_AreFilesAliased; + nfs41_ops.MRxGetConnectionId = nfs41_GetConnectionId; + + DbgR(); + return(STATUS_SUCCESS); +} + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT drv, IN PUNICODE_STRING path) +{ + NTSTATUS status; + ULONG flags = 0, i; + UNICODE_STRING dev_name, user_dev_name; + PNFS41_DEVICE_EXTENSION dev_exts; + + DbgEn(); + + status = RxDriverEntry(drv, path); + if (status != STATUS_SUCCESS) { + DbgP("RxDriverEntry failed: %08lx\n", status); + goto out; + } + + RtlInitUnicodeString(&dev_name, NFS41_DEVICE_NAME); + SetFlag(flags, RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS); + + status = nfs41_init_ops(); + if (status != STATUS_SUCCESS) { + DbgP("nfs41_init_ops failed to initialize dispatch table\n"); + goto out; + } + + DbgP("calling RxRegisterMinirdr\n"); + status = RxRegisterMinirdr(&nfs41_dev, drv, &nfs41_ops, flags, &dev_name, + sizeof(NFS41_DEVICE_EXTENSION), + FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE); + if (status != STATUS_SUCCESS) { + DbgP("RxRegisterMinirdr failed: %08lx\n", status); + goto out; + } + nfs41_dev->Flags |= DO_BUFFERED_IO; + + dev_exts = (PNFS41_DEVICE_EXTENSION) + ((PBYTE)(nfs41_dev) + sizeof(RDBSS_DEVICE_OBJECT)); + + RxDefineNode(dev_exts, NFS41_DEVICE_EXTENSION); + dev_exts->DeviceObject = nfs41_dev; + + RtlInitUnicodeString(&user_dev_name, NFS41_SHADOW_DEVICE_NAME); + DbgP("calling IoCreateSymbolicLink %wZ %wZ\n", &user_dev_name, &dev_name); + status = IoCreateSymbolicLink(&user_dev_name, &dev_name); + if (status != STATUS_SUCCESS) { + DbgP("Device name IoCreateSymbolicLink failed: %08lx\n", status); + goto out_unregister; + } + + KeInitializeEvent(&upcallEvent, SynchronizationEvent, FALSE ); + ExInitializeFastMutex(&upcallLock); + ExInitializeFastMutex(&downcallLock); + ExInitializeFastMutex(&xidLock); + ExInitializeFastMutex(&openOwnerLock); + upcall = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_list), + NFS41_MM_POOLTAG); + if (upcall == NULL) + goto out_unregister; + InitializeListHead(&upcall->head); + downcall = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_list), + NFS41_MM_POOLTAG); + if (downcall == NULL) { + RxFreePool(upcall); + goto out_unregister; + } + InitializeListHead(&downcall->head); + + drv->DriverUnload = nfs41_driver_unload; + + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + drv->MajorFunction[i] = (PDRIVER_DISPATCH)nfs41_FsdDispatch; + +out_unregister: + if (status != STATUS_SUCCESS) + RxUnregisterMinirdr(nfs41_dev); +out: + DbgEx(); + return status; +} + +VOID nfs41_driver_unload(IN PDRIVER_OBJECT drv) +{ + PRX_CONTEXT RxContext; + NTSTATUS status; + UNICODE_STRING dev_name, pipe_name; + + DbgEn(); + + RxContext = RxCreateRxContext(NULL, nfs41_dev, RX_CONTEXT_FLAG_IN_FSP); + if (RxContext == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto unload; + } + status = RxStopMinirdr(RxContext, &RxContext->PostRequest); + RxDereferenceAndDeleteRxContext(RxContext); + +unload: + RtlInitUnicodeString(&dev_name, NFS41_SHADOW_DEVICE_NAME); + status = IoDeleteSymbolicLink(&dev_name); + if (status != STATUS_SUCCESS) { + DbgP("couldn't delete device symbolic link\n"); + } + RtlInitUnicodeString(&pipe_name, NFS41_SHADOW_PIPE_NAME); + status = IoDeleteSymbolicLink(&pipe_name); + if (status != STATUS_SUCCESS) { + DbgP("couldn't delete pipe symbolic link\n"); + } + if (upcall) + RxFreePool(upcall); + if (downcall) + RxFreePool(downcall); + RxUnload(drv); + + DbgP("driver unloaded %p\n", drv); + DbgR(); +} diff --git a/sys/nfs41_driver.h b/sys/nfs41_driver.h new file mode 100644 index 0000000..30b0153 --- /dev/null +++ b/sys/nfs41_driver.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef _NFS41_DRIVER_ +#define _NFS41_DRIVER_ + +#define NFS41_DEVICE_NAME L"\\Device\\nfs41_driver" +#define NFS41_SHADOW_DEVICE_NAME L"\\??\\nfs41_driver" +#define NFS41_USER_DEVICE_NAME L"\\\\.\\nfs41_driver" +#define NFS41_USER_DEVICE_NAME_A "\\\\.\\nfs41_driver" +#define NFS41_PROVIDER_NAME_A "NFS41 Network" +#define NFS41_PROVIDER_NAME_U L"NFS41 Network" + +#define NFS41_PIPE_NAME L"\\Device\\nfs41_pipe" +#define NFS41_SHADOW_PIPE_NAME L"\\??\\nfs41_pipe" +#define NFS41_USER_PIPE_NAME L"\\\\.\\nfs41_pipe" + +#define NFS41_SHARED_MEMORY_NAME L"\\BaseNamedObjects\\nfs41_shared_memory" +#define NFS41_USER_SHARED_MEMORY_NAME "Global\\nfs41_shared_memory" + +// See "Defining I/O Control Codes" in WDK docs +#define _RDR_CTL_CODE(code, method) \ + CTL_CODE(FILE_DEVICE_NETWORK_REDIRECTOR, 0x800 | (code), method, FILE_ANY_ACCESS) + +#define IOCTL_NFS41_START _RDR_CTL_CODE(0, METHOD_NEITHER) +#define IOCTL_NFS41_STOP _RDR_CTL_CODE(1, METHOD_NEITHER) +#define IOCTL_NFS41_GETSTATE _RDR_CTL_CODE(3, METHOD_NEITHER) +#define IOCTL_NFS41_ADDCONN _RDR_CTL_CODE(4, METHOD_BUFFERED) +#define IOCTL_NFS41_DELCONN _RDR_CTL_CODE(5, METHOD_BUFFERED) +#define IOCTL_NFS41_READ _RDR_CTL_CODE(6, METHOD_BUFFERED) +#define IOCTL_NFS41_WRITE _RDR_CTL_CODE(7, METHOD_BUFFERED) +#define IOCTL_NFS41_INVALCACHE _RDR_CTL_CODE(8, METHOD_BUFFERED) + +typedef enum _nfs41_opcodes { + NFS41_MOUNT, + NFS41_UNMOUNT, + NFS41_OPEN, + NFS41_CLOSE, + NFS41_READ, + NFS41_WRITE, + NFS41_LOCK, + NFS41_UNLOCK, + NFS41_DIR_QUERY, + NFS41_FILE_QUERY, + NFS41_FILE_SET, + NFS41_EA_SET, + NFS41_VOLUME_QUERY, + NFS41_SHUTDOWN, + INVALID_OPCODE +} nfs41_opcodes; + +typedef enum _nfs41_init_driver_state { + NFS41_INIT_DRIVER_STARTABLE, + NFS41_INIT_DRIVER_START_IN_PROGRESS, + NFS41_INIT_DRIVER_STARTED +} nfs41_init_driver_state; + +typedef enum _nfs41_start_driver_state { + NFS41_START_DRIVER_STARTABLE, + NFS41_START_DRIVER_START_IN_PROGRESS, + NFS41_START_DRIVER_STARTED, + NFS41_START_DRIVER_STOPPED +} nfs41_start_driver_state; +#endif diff --git a/sys/nfs41_driver.ini b/sys/nfs41_driver.ini new file mode 100644 index 0000000..69d5103 --- /dev/null +++ b/sys/nfs41_driver.ini @@ -0,0 +1,13 @@ +\registry\machine\system\currentcontrolset\services\nfs41_driver + Description = nfs41_driver + DisplayName = nfs41_driver + ErrorControl = REG_DWORD 0x00000001 + Group = Network + ImagePath = System32\DRIVERS\nfs41_driver.sys + LastLoadStatus = REG_DWORD 0 + Start = REG_DWORD 0x00000001 + Type = REG_DWORD 0x00000002 +\registry\machine\system\currentcontrolset\services\nfs41_driver\NetworkProvider + DeviceName = \Device\nfs41_driver + Name = NFS41 Network + ProviderPath = System32\nfs41_np.dll diff --git a/sys/nfs41_driver.rc b/sys/nfs41_driver.rc new file mode 100644 index 0000000..de908ab --- /dev/null +++ b/sys/nfs41_driver.rc @@ -0,0 +1,11 @@ +#include +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "CITI's nfs41 driver" +#define VER_INTERNALNAME_STR "nfs41_driver.sys" +#define VER_ORIGINALFILENAME_STR "nfs41_driver.Sys" + +#include "common.ver" + diff --git a/sys/sources b/sys/sources new file mode 100644 index 0000000..30e993c --- /dev/null +++ b/sys/sources @@ -0,0 +1,26 @@ +TARGETNAME=nfs41_driver +TARGETTYPE=DRIVER +#KMDF_VERSION_MAJOR=1 +TARGETLIBS = $(TARGETLIBS) \ + $(DDK_LIB_PATH)\ksecdd.lib \ + $(DDK_LIB_PATH)\rxce.lib \ + $(DDK_LIB_PATH)\rdbsslib.lib \ + $(DDK_LIB_PATH)\copysup.lib +C_DEFINES= -DEXPLODE_POOLTAGS -DMONOLITHIC_MINIRDR +!IF 0 +Enable Buffer Security Check +!ENDIF +USER_C_FLAGS=/GS + +INCLUDES=..\dll +SOURCES= nfs41_driver.rc nfs41_driver.c wmlkm.c nfs41_debug.c + +!IF 0 +/W3 is default level +bump to /Wall, but suppress warnings generated by system includes, +as well as the following warnings: +4100 - unused function call arguments (we have lots of stubs) +4127 - constant conditional (I like to use if(0) or if(1)) +4204 - nonstandard extension used : non-constant aggregate initializer +!ENDIF +MSC_WARNING_LEVEL=/Wall /wd4668 /wd4619 /wd4820 /wd4255 /wd4100 /wd4127 /wd4201 /wd4204 /wd4115 /wd4711 diff --git a/sys/wmlkm.c b/sys/wmlkm.c new file mode 100644 index 0000000..49a7dad --- /dev/null +++ b/sys/wmlkm.c @@ -0,0 +1,51 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + * + * Comments: RDBSS depends on wmlkm files. See comments in nulmrx/wmlkm + */ +#pragma hdrstop + +#include +#include +#define LPVOID PVOID64 // BUG - need to find include for this +#include "wmlkm.h" + +NTSTATUS +WmlTinySystemControl( + __inout PVOID WmiLibInfo, + __in PVOID DeviceObject, + __in PVOID Irp + ) +{ + return(STATUS_WMI_GUID_NOT_FOUND); +} + +ULONG +WmlTrace( + __in ULONG Type, + __in LPVOID TraceGuid, + __in ULONG64 LoggerHandle, + ... // Pairs: Address, Length + ) +{ + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/sys/wmlkm.h b/sys/wmlkm.h new file mode 100644 index 0000000..d3912c3 --- /dev/null +++ b/sys/wmlkm.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2010 + * The Regents of the University of Michigan + * All Rights Reserved + * + * Permission is granted to use, copy and redistribute this software + * for noncommercial education and research purposes, so long as no + * fee is charged, and so long as the name of the University of Michigan + * is not used in any advertising or publicity pertaining to the use + * or distribution of this software without specific, written prior + * authorization. Permission to modify or otherwise create derivative + * works of this software is not granted. + * + * This software is provided as is, without representation or warranty + * of any kind either express or implied, including without limitation + * the implied warranties of merchantability, fitness for a particular + * purpose, or noninfringement. The Regents of the University of + * Michigan shall not be liable for any damages, including special, + * indirect, incidental, or consequential damages, with respect to any + * claim arising out of or in connection with the use of the software, + * even if it has been or is hereafter advised of the possibility of + * such damages. + */ + +#ifndef NFS41_WMLKM_H +#define NFS41_WMLKM_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +NTSTATUS +WmlTinySystemControl( + __inout PVOID WmiLibInfo, + __in PVOID DeviceObject, + __in PVOID Irp + ); + +ULONG +WmlTrace( + __in ULONG Type, + __in LPVOID TraceGuid, + __in ULONG64 LoggerHandle, + ... // Pairs: Address, Length + ); + +#ifdef __cplusplus +}; +#endif + +#endif // NFS41_WMLKM_H + diff --git a/uninstall.bat b/uninstall.bat new file mode 100644 index 0000000..4c714b3 --- /dev/null +++ b/uninstall.bat @@ -0,0 +1,2 @@ +nfs_install.exe 0 +rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 ./nfs41rdr.inf