summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:45:02 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:45:02 +0000
commit68a560641f7a38c184fd3346dd8008b86e12d77a (patch)
treed927b2a890d51e5d9e037c03042fb6fabd689cc0 /src
parentInitial commit. (diff)
downloadlibtirpc-68a560641f7a38c184fd3346dd8008b86e12d77a.tar.xz
libtirpc-68a560641f7a38c184fd3346dd8008b86e12d77a.zip
Adding upstream version 1.3.4+ds.upstream/1.3.4+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/Makefile.am52
-rw-r--r--src/Makefile.in1515
-rw-r--r--src/auth_des.c500
-rw-r--r--src/auth_gss.c992
-rw-r--r--src/auth_none.c182
-rw-r--r--src/auth_time.c495
-rw-r--r--src/auth_unix.c424
-rw-r--r--src/authdes_prot.c85
-rw-r--r--src/authgss_prot.c371
-rw-r--r--src/authunix_prot.c65
-rw-r--r--src/binddynport.c231
-rw-r--r--src/bindresvport.c338
-rw-r--r--src/clnt_bcast.c698
-rw-r--r--src/clnt_dg.c809
-rw-r--r--src/clnt_fd_locks.h209
-rw-r--r--src/clnt_generic.c434
-rw-r--r--src/clnt_perror.c335
-rw-r--r--src/clnt_raw.c307
-rw-r--r--src/clnt_simple.c178
-rw-r--r--src/clnt_vc.c801
-rw-r--r--src/crypt_client.c99
-rw-r--r--src/debug.c73
-rw-r--r--src/debug.h59
-rw-r--r--src/des_crypt.c146
-rw-r--r--src/des_impl.c594
-rw-r--r--src/des_soft.c65
-rw-r--r--src/epoll_sub.c58
-rw-r--r--src/getnetconfig.c716
-rw-r--r--src/getnetpath.c261
-rw-r--r--src/getpeereid.c51
-rw-r--r--src/getpublickey.c170
-rw-r--r--src/getrpcent.c332
-rw-r--r--src/getrpcport.c66
-rw-r--r--src/key_call.c446
-rw-r--r--src/key_prot_xdr.c170
-rw-r--r--src/libtirpc.map335
-rw-r--r--src/mt_misc.c153
-rw-r--r--src/netname.c143
-rw-r--r--src/netnamer.c322
-rw-r--r--src/nis.h70
-rw-r--r--src/pmap_clnt.c109
-rw-r--r--src/pmap_getmaps.c89
-rw-r--r--src/pmap_getport.c91
-rw-r--r--src/pmap_prot.c57
-rw-r--r--src/pmap_prot2.c131
-rw-r--r--src/pmap_rmt.c168
-rw-r--r--src/rpc_callmsg.c196
-rw-r--r--src/rpc_com.h70
-rw-r--r--src/rpc_commondata.c41
-rw-r--r--src/rpc_dtablesize.c47
-rw-r--r--src/rpc_generic.c879
-rw-r--r--src/rpc_gss_utils.c467
-rw-r--r--src/rpc_prot.c342
-rw-r--r--src/rpc_soc.c745
-rw-r--r--src/rpcb_clnt.c1398
-rw-r--r--src/rpcb_prot.c324
-rw-r--r--src/rpcb_st_xdr.c264
-rw-r--r--src/rpcdname.c72
-rw-r--r--src/rtime.c157
-rw-r--r--src/svc.c821
-rw-r--r--src/svc_auth.c219
-rw-r--r--src/svc_auth_des.c529
-rw-r--r--src/svc_auth_gss.c1180
-rw-r--r--src/svc_auth_none.c71
-rw-r--r--src/svc_auth_unix.c148
-rw-r--r--src/svc_dg.c721
-rw-r--r--src/svc_generic.c299
-rw-r--r--src/svc_raw.c256
-rw-r--r--src/svc_run.c114
-rw-r--r--src/svc_simple.c302
-rw-r--r--src/svc_vc.c882
-rw-r--r--src/xdr.c1025
-rw-r--r--src/xdr_array.c154
-rw-r--r--src/xdr_float.c297
-rw-r--r--src/xdr_mem.c250
-rw-r--r--src/xdr_rec.c792
-rw-r--r--src/xdr_reference.c136
-rw-r--r--src/xdr_sizeof.c165
-rw-r--r--src/xdr_stdio.c194
79 files changed, 27552 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..0cef093
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,52 @@
+## 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.
+
+noinst_HEADERS = rpc_com.h debug.h
+
+AM_CPPFLAGS = -I$(top_srcdir)/tirpc -include config.h -DPORTMAP -DINET6 \
+ -D_GNU_SOURCE -Wall -pipe
+
+lib_LTLIBRARIES = libtirpc.la
+
+libtirpc_la_LDFLAGS = @LDFLAG_NOUNDEFINED@ -no-undefined @PTHREAD_LIBS@
+libtirpc_la_LDFLAGS += -version-info @LT_VERSION_INFO@
+
+libtirpc_la_SOURCES = auth_none.c auth_unix.c authunix_prot.c \
+ binddynport.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_auth_none.c \
+ svc_generic.c svc_raw.c svc_run.c svc_simple.c svc_vc.c getpeereid.c \
+ auth_time.c debug.c
+
+if AUTHDES
+libtirpc_la_SOURCES += auth_des.c authdes_prot.c des_crypt.c des_impl.c des_soft.c svc_auth_des.c
+endif
+
+## XDR
+libtirpc_la_SOURCES += xdr.c xdr_rec.c xdr_array.c xdr_float.c xdr_mem.c xdr_reference.c xdr_stdio.c xdr_sizeof.c
+
+if SYMVERS
+ libtirpc_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libtirpc.map
+endif
+
+## Secure-RPC
+if GSS
+ libtirpc_la_SOURCES += auth_gss.c authgss_prot.c svc_auth_gss.c \
+ rpc_gss_utils.c
+ libtirpc_la_LIBADD = $(GSSAPI_LIBS)
+ libtirpc_la_CFLAGS = -DHAVE_RPCSEC_GSS $(GSSAPI_CFLAGS)
+endif
+
+libtirpc_la_SOURCES += key_call.c key_prot_xdr.c getpublickey.c
+libtirpc_la_SOURCES += netname.c netnamer.c rpcdname.c rtime.c
+
+CLEANFILES = cscope.* *~
+DISTCLEANFILES = Makefile.in
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..cc4c5cb
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1515 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@AUTHDES_TRUE@am__append_1 = auth_des.c authdes_prot.c des_crypt.c des_impl.c des_soft.c svc_auth_des.c
+@SYMVERS_TRUE@am__append_2 = -Wl,--version-script=$(srcdir)/libtirpc.map
+@GSS_TRUE@am__append_3 = auth_gss.c authgss_prot.c svc_auth_gss.c \
+@GSS_TRUE@ rpc_gss_utils.c
+
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@GSS_TRUE@libtirpc_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__libtirpc_la_SOURCES_DIST = auth_none.c auth_unix.c authunix_prot.c \
+ binddynport.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_auth_none.c svc_generic.c \
+ svc_raw.c svc_run.c svc_simple.c svc_vc.c getpeereid.c \
+ auth_time.c debug.c auth_des.c authdes_prot.c des_crypt.c \
+ des_impl.c des_soft.c svc_auth_des.c xdr.c xdr_rec.c \
+ xdr_array.c xdr_float.c xdr_mem.c xdr_reference.c xdr_stdio.c \
+ xdr_sizeof.c auth_gss.c authgss_prot.c svc_auth_gss.c \
+ rpc_gss_utils.c key_call.c key_prot_xdr.c getpublickey.c \
+ netname.c netnamer.c rpcdname.c rtime.c
+@AUTHDES_TRUE@am__objects_1 = libtirpc_la-auth_des.lo \
+@AUTHDES_TRUE@ libtirpc_la-authdes_prot.lo \
+@AUTHDES_TRUE@ libtirpc_la-des_crypt.lo libtirpc_la-des_impl.lo \
+@AUTHDES_TRUE@ libtirpc_la-des_soft.lo \
+@AUTHDES_TRUE@ libtirpc_la-svc_auth_des.lo
+@GSS_TRUE@am__objects_2 = libtirpc_la-auth_gss.lo \
+@GSS_TRUE@ libtirpc_la-authgss_prot.lo \
+@GSS_TRUE@ libtirpc_la-svc_auth_gss.lo \
+@GSS_TRUE@ libtirpc_la-rpc_gss_utils.lo
+am_libtirpc_la_OBJECTS = libtirpc_la-auth_none.lo \
+ libtirpc_la-auth_unix.lo libtirpc_la-authunix_prot.lo \
+ libtirpc_la-binddynport.lo libtirpc_la-bindresvport.lo \
+ libtirpc_la-clnt_bcast.lo libtirpc_la-clnt_dg.lo \
+ libtirpc_la-clnt_generic.lo libtirpc_la-clnt_perror.lo \
+ libtirpc_la-clnt_raw.lo libtirpc_la-clnt_simple.lo \
+ libtirpc_la-clnt_vc.lo libtirpc_la-rpc_dtablesize.lo \
+ libtirpc_la-getnetconfig.lo libtirpc_la-getnetpath.lo \
+ libtirpc_la-getrpcent.lo libtirpc_la-getrpcport.lo \
+ libtirpc_la-mt_misc.lo libtirpc_la-pmap_clnt.lo \
+ libtirpc_la-pmap_getmaps.lo libtirpc_la-pmap_getport.lo \
+ libtirpc_la-pmap_prot.lo libtirpc_la-pmap_prot2.lo \
+ libtirpc_la-pmap_rmt.lo libtirpc_la-rpc_prot.lo \
+ libtirpc_la-rpc_commondata.lo libtirpc_la-rpc_callmsg.lo \
+ libtirpc_la-rpc_generic.lo libtirpc_la-rpc_soc.lo \
+ libtirpc_la-rpcb_clnt.lo libtirpc_la-rpcb_prot.lo \
+ libtirpc_la-rpcb_st_xdr.lo libtirpc_la-svc.lo \
+ libtirpc_la-svc_auth.lo libtirpc_la-svc_dg.lo \
+ libtirpc_la-svc_auth_unix.lo libtirpc_la-svc_auth_none.lo \
+ libtirpc_la-svc_generic.lo libtirpc_la-svc_raw.lo \
+ libtirpc_la-svc_run.lo libtirpc_la-svc_simple.lo \
+ libtirpc_la-svc_vc.lo libtirpc_la-getpeereid.lo \
+ libtirpc_la-auth_time.lo libtirpc_la-debug.lo $(am__objects_1) \
+ libtirpc_la-xdr.lo libtirpc_la-xdr_rec.lo \
+ libtirpc_la-xdr_array.lo libtirpc_la-xdr_float.lo \
+ libtirpc_la-xdr_mem.lo libtirpc_la-xdr_reference.lo \
+ libtirpc_la-xdr_stdio.lo libtirpc_la-xdr_sizeof.lo \
+ $(am__objects_2) libtirpc_la-key_call.lo \
+ libtirpc_la-key_prot_xdr.lo libtirpc_la-getpublickey.lo \
+ libtirpc_la-netname.lo libtirpc_la-netnamer.lo \
+ libtirpc_la-rpcdname.lo libtirpc_la-rtime.lo
+libtirpc_la_OBJECTS = $(am_libtirpc_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libtirpc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libtirpc_la_CFLAGS) \
+ $(CFLAGS) $(libtirpc_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/libtirpc_la-auth_des.Plo \
+ ./$(DEPDIR)/libtirpc_la-auth_gss.Plo \
+ ./$(DEPDIR)/libtirpc_la-auth_none.Plo \
+ ./$(DEPDIR)/libtirpc_la-auth_time.Plo \
+ ./$(DEPDIR)/libtirpc_la-auth_unix.Plo \
+ ./$(DEPDIR)/libtirpc_la-authdes_prot.Plo \
+ ./$(DEPDIR)/libtirpc_la-authgss_prot.Plo \
+ ./$(DEPDIR)/libtirpc_la-authunix_prot.Plo \
+ ./$(DEPDIR)/libtirpc_la-binddynport.Plo \
+ ./$(DEPDIR)/libtirpc_la-bindresvport.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_bcast.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_dg.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_generic.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_perror.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_raw.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_simple.Plo \
+ ./$(DEPDIR)/libtirpc_la-clnt_vc.Plo \
+ ./$(DEPDIR)/libtirpc_la-debug.Plo \
+ ./$(DEPDIR)/libtirpc_la-des_crypt.Plo \
+ ./$(DEPDIR)/libtirpc_la-des_impl.Plo \
+ ./$(DEPDIR)/libtirpc_la-des_soft.Plo \
+ ./$(DEPDIR)/libtirpc_la-getnetconfig.Plo \
+ ./$(DEPDIR)/libtirpc_la-getnetpath.Plo \
+ ./$(DEPDIR)/libtirpc_la-getpeereid.Plo \
+ ./$(DEPDIR)/libtirpc_la-getpublickey.Plo \
+ ./$(DEPDIR)/libtirpc_la-getrpcent.Plo \
+ ./$(DEPDIR)/libtirpc_la-getrpcport.Plo \
+ ./$(DEPDIR)/libtirpc_la-key_call.Plo \
+ ./$(DEPDIR)/libtirpc_la-key_prot_xdr.Plo \
+ ./$(DEPDIR)/libtirpc_la-mt_misc.Plo \
+ ./$(DEPDIR)/libtirpc_la-netname.Plo \
+ ./$(DEPDIR)/libtirpc_la-netnamer.Plo \
+ ./$(DEPDIR)/libtirpc_la-pmap_clnt.Plo \
+ ./$(DEPDIR)/libtirpc_la-pmap_getmaps.Plo \
+ ./$(DEPDIR)/libtirpc_la-pmap_getport.Plo \
+ ./$(DEPDIR)/libtirpc_la-pmap_prot.Plo \
+ ./$(DEPDIR)/libtirpc_la-pmap_prot2.Plo \
+ ./$(DEPDIR)/libtirpc_la-pmap_rmt.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_callmsg.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_commondata.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_dtablesize.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_generic.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_gss_utils.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_prot.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpc_soc.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpcb_clnt.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpcb_prot.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpcb_st_xdr.Plo \
+ ./$(DEPDIR)/libtirpc_la-rpcdname.Plo \
+ ./$(DEPDIR)/libtirpc_la-rtime.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_auth.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_auth_des.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_auth_gss.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_auth_none.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_auth_unix.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_dg.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_generic.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_raw.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_run.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_simple.Plo \
+ ./$(DEPDIR)/libtirpc_la-svc_vc.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_array.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_float.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_mem.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_rec.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_reference.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_sizeof.Plo \
+ ./$(DEPDIR)/libtirpc_la-xdr_stdio.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libtirpc_la_SOURCES)
+DIST_SOURCES = $(am__libtirpc_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KRB5_CONFIG = @KRB5_CONFIG@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAG_NOUNDEFINED = @LDFLAG_NOUNDEFINED@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = rpc_com.h debug.h
+AM_CPPFLAGS = -I$(top_srcdir)/tirpc -include config.h -DPORTMAP -DINET6 \
+ -D_GNU_SOURCE -Wall -pipe
+
+lib_LTLIBRARIES = libtirpc.la
+libtirpc_la_LDFLAGS = @LDFLAG_NOUNDEFINED@ -no-undefined \
+ @PTHREAD_LIBS@ -version-info @LT_VERSION_INFO@ $(am__append_2)
+libtirpc_la_SOURCES = auth_none.c auth_unix.c authunix_prot.c \
+ binddynport.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_auth_none.c svc_generic.c \
+ svc_raw.c svc_run.c svc_simple.c svc_vc.c getpeereid.c \
+ auth_time.c debug.c $(am__append_1) xdr.c xdr_rec.c \
+ xdr_array.c xdr_float.c xdr_mem.c xdr_reference.c xdr_stdio.c \
+ xdr_sizeof.c $(am__append_3) key_call.c key_prot_xdr.c \
+ getpublickey.c netname.c netnamer.c rpcdname.c rtime.c
+@GSS_TRUE@libtirpc_la_LIBADD = $(GSSAPI_LIBS)
+@GSS_TRUE@libtirpc_la_CFLAGS = -DHAVE_RPCSEC_GSS $(GSSAPI_CFLAGS)
+CLEANFILES = cscope.* *~
+DISTCLEANFILES = Makefile.in
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libtirpc.la: $(libtirpc_la_OBJECTS) $(libtirpc_la_DEPENDENCIES) $(EXTRA_libtirpc_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libtirpc_la_LINK) -rpath $(libdir) $(libtirpc_la_OBJECTS) $(libtirpc_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-auth_des.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-auth_gss.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-auth_none.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-auth_time.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-auth_unix.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-authdes_prot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-authgss_prot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-authunix_prot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-binddynport.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-bindresvport.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_bcast.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_dg.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_generic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_perror.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_raw.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_simple.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-clnt_vc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-debug.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-des_crypt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-des_impl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-des_soft.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-getnetconfig.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-getnetpath.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-getpeereid.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-getpublickey.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-getrpcent.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-getrpcport.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-key_call.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-key_prot_xdr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-mt_misc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-netname.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-netnamer.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-pmap_clnt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-pmap_getmaps.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-pmap_getport.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-pmap_prot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-pmap_prot2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-pmap_rmt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_callmsg.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_commondata.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_dtablesize.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_generic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_gss_utils.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_prot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpc_soc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpcb_clnt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpcb_prot.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpcb_st_xdr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rpcdname.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-rtime.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_auth.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_auth_des.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_auth_gss.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_auth_none.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_auth_unix.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_dg.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_generic.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_raw.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_run.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_simple.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-svc_vc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_array.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_float.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_mem.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_rec.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_reference.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_sizeof.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtirpc_la-xdr_stdio.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libtirpc_la-auth_none.lo: auth_none.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-auth_none.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-auth_none.Tpo -c -o libtirpc_la-auth_none.lo `test -f 'auth_none.c' || echo '$(srcdir)/'`auth_none.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-auth_none.Tpo $(DEPDIR)/libtirpc_la-auth_none.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth_none.c' object='libtirpc_la-auth_none.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-auth_none.lo `test -f 'auth_none.c' || echo '$(srcdir)/'`auth_none.c
+
+libtirpc_la-auth_unix.lo: auth_unix.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-auth_unix.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-auth_unix.Tpo -c -o libtirpc_la-auth_unix.lo `test -f 'auth_unix.c' || echo '$(srcdir)/'`auth_unix.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-auth_unix.Tpo $(DEPDIR)/libtirpc_la-auth_unix.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth_unix.c' object='libtirpc_la-auth_unix.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-auth_unix.lo `test -f 'auth_unix.c' || echo '$(srcdir)/'`auth_unix.c
+
+libtirpc_la-authunix_prot.lo: authunix_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-authunix_prot.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-authunix_prot.Tpo -c -o libtirpc_la-authunix_prot.lo `test -f 'authunix_prot.c' || echo '$(srcdir)/'`authunix_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-authunix_prot.Tpo $(DEPDIR)/libtirpc_la-authunix_prot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='authunix_prot.c' object='libtirpc_la-authunix_prot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-authunix_prot.lo `test -f 'authunix_prot.c' || echo '$(srcdir)/'`authunix_prot.c
+
+libtirpc_la-binddynport.lo: binddynport.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-binddynport.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-binddynport.Tpo -c -o libtirpc_la-binddynport.lo `test -f 'binddynport.c' || echo '$(srcdir)/'`binddynport.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-binddynport.Tpo $(DEPDIR)/libtirpc_la-binddynport.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='binddynport.c' object='libtirpc_la-binddynport.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-binddynport.lo `test -f 'binddynport.c' || echo '$(srcdir)/'`binddynport.c
+
+libtirpc_la-bindresvport.lo: bindresvport.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-bindresvport.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-bindresvport.Tpo -c -o libtirpc_la-bindresvport.lo `test -f 'bindresvport.c' || echo '$(srcdir)/'`bindresvport.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-bindresvport.Tpo $(DEPDIR)/libtirpc_la-bindresvport.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bindresvport.c' object='libtirpc_la-bindresvport.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-bindresvport.lo `test -f 'bindresvport.c' || echo '$(srcdir)/'`bindresvport.c
+
+libtirpc_la-clnt_bcast.lo: clnt_bcast.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_bcast.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_bcast.Tpo -c -o libtirpc_la-clnt_bcast.lo `test -f 'clnt_bcast.c' || echo '$(srcdir)/'`clnt_bcast.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_bcast.Tpo $(DEPDIR)/libtirpc_la-clnt_bcast.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_bcast.c' object='libtirpc_la-clnt_bcast.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_bcast.lo `test -f 'clnt_bcast.c' || echo '$(srcdir)/'`clnt_bcast.c
+
+libtirpc_la-clnt_dg.lo: clnt_dg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_dg.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_dg.Tpo -c -o libtirpc_la-clnt_dg.lo `test -f 'clnt_dg.c' || echo '$(srcdir)/'`clnt_dg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_dg.Tpo $(DEPDIR)/libtirpc_la-clnt_dg.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_dg.c' object='libtirpc_la-clnt_dg.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_dg.lo `test -f 'clnt_dg.c' || echo '$(srcdir)/'`clnt_dg.c
+
+libtirpc_la-clnt_generic.lo: clnt_generic.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_generic.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_generic.Tpo -c -o libtirpc_la-clnt_generic.lo `test -f 'clnt_generic.c' || echo '$(srcdir)/'`clnt_generic.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_generic.Tpo $(DEPDIR)/libtirpc_la-clnt_generic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_generic.c' object='libtirpc_la-clnt_generic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_generic.lo `test -f 'clnt_generic.c' || echo '$(srcdir)/'`clnt_generic.c
+
+libtirpc_la-clnt_perror.lo: clnt_perror.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_perror.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_perror.Tpo -c -o libtirpc_la-clnt_perror.lo `test -f 'clnt_perror.c' || echo '$(srcdir)/'`clnt_perror.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_perror.Tpo $(DEPDIR)/libtirpc_la-clnt_perror.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_perror.c' object='libtirpc_la-clnt_perror.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_perror.lo `test -f 'clnt_perror.c' || echo '$(srcdir)/'`clnt_perror.c
+
+libtirpc_la-clnt_raw.lo: clnt_raw.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_raw.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_raw.Tpo -c -o libtirpc_la-clnt_raw.lo `test -f 'clnt_raw.c' || echo '$(srcdir)/'`clnt_raw.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_raw.Tpo $(DEPDIR)/libtirpc_la-clnt_raw.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_raw.c' object='libtirpc_la-clnt_raw.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_raw.lo `test -f 'clnt_raw.c' || echo '$(srcdir)/'`clnt_raw.c
+
+libtirpc_la-clnt_simple.lo: clnt_simple.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_simple.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_simple.Tpo -c -o libtirpc_la-clnt_simple.lo `test -f 'clnt_simple.c' || echo '$(srcdir)/'`clnt_simple.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_simple.Tpo $(DEPDIR)/libtirpc_la-clnt_simple.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_simple.c' object='libtirpc_la-clnt_simple.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_simple.lo `test -f 'clnt_simple.c' || echo '$(srcdir)/'`clnt_simple.c
+
+libtirpc_la-clnt_vc.lo: clnt_vc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-clnt_vc.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-clnt_vc.Tpo -c -o libtirpc_la-clnt_vc.lo `test -f 'clnt_vc.c' || echo '$(srcdir)/'`clnt_vc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-clnt_vc.Tpo $(DEPDIR)/libtirpc_la-clnt_vc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clnt_vc.c' object='libtirpc_la-clnt_vc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-clnt_vc.lo `test -f 'clnt_vc.c' || echo '$(srcdir)/'`clnt_vc.c
+
+libtirpc_la-rpc_dtablesize.lo: rpc_dtablesize.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_dtablesize.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_dtablesize.Tpo -c -o libtirpc_la-rpc_dtablesize.lo `test -f 'rpc_dtablesize.c' || echo '$(srcdir)/'`rpc_dtablesize.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_dtablesize.Tpo $(DEPDIR)/libtirpc_la-rpc_dtablesize.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_dtablesize.c' object='libtirpc_la-rpc_dtablesize.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_dtablesize.lo `test -f 'rpc_dtablesize.c' || echo '$(srcdir)/'`rpc_dtablesize.c
+
+libtirpc_la-getnetconfig.lo: getnetconfig.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-getnetconfig.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-getnetconfig.Tpo -c -o libtirpc_la-getnetconfig.lo `test -f 'getnetconfig.c' || echo '$(srcdir)/'`getnetconfig.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-getnetconfig.Tpo $(DEPDIR)/libtirpc_la-getnetconfig.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getnetconfig.c' object='libtirpc_la-getnetconfig.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-getnetconfig.lo `test -f 'getnetconfig.c' || echo '$(srcdir)/'`getnetconfig.c
+
+libtirpc_la-getnetpath.lo: getnetpath.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-getnetpath.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-getnetpath.Tpo -c -o libtirpc_la-getnetpath.lo `test -f 'getnetpath.c' || echo '$(srcdir)/'`getnetpath.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-getnetpath.Tpo $(DEPDIR)/libtirpc_la-getnetpath.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getnetpath.c' object='libtirpc_la-getnetpath.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-getnetpath.lo `test -f 'getnetpath.c' || echo '$(srcdir)/'`getnetpath.c
+
+libtirpc_la-getrpcent.lo: getrpcent.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-getrpcent.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-getrpcent.Tpo -c -o libtirpc_la-getrpcent.lo `test -f 'getrpcent.c' || echo '$(srcdir)/'`getrpcent.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-getrpcent.Tpo $(DEPDIR)/libtirpc_la-getrpcent.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getrpcent.c' object='libtirpc_la-getrpcent.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-getrpcent.lo `test -f 'getrpcent.c' || echo '$(srcdir)/'`getrpcent.c
+
+libtirpc_la-getrpcport.lo: getrpcport.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-getrpcport.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-getrpcport.Tpo -c -o libtirpc_la-getrpcport.lo `test -f 'getrpcport.c' || echo '$(srcdir)/'`getrpcport.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-getrpcport.Tpo $(DEPDIR)/libtirpc_la-getrpcport.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getrpcport.c' object='libtirpc_la-getrpcport.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-getrpcport.lo `test -f 'getrpcport.c' || echo '$(srcdir)/'`getrpcport.c
+
+libtirpc_la-mt_misc.lo: mt_misc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-mt_misc.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-mt_misc.Tpo -c -o libtirpc_la-mt_misc.lo `test -f 'mt_misc.c' || echo '$(srcdir)/'`mt_misc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-mt_misc.Tpo $(DEPDIR)/libtirpc_la-mt_misc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mt_misc.c' object='libtirpc_la-mt_misc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-mt_misc.lo `test -f 'mt_misc.c' || echo '$(srcdir)/'`mt_misc.c
+
+libtirpc_la-pmap_clnt.lo: pmap_clnt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-pmap_clnt.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-pmap_clnt.Tpo -c -o libtirpc_la-pmap_clnt.lo `test -f 'pmap_clnt.c' || echo '$(srcdir)/'`pmap_clnt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-pmap_clnt.Tpo $(DEPDIR)/libtirpc_la-pmap_clnt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pmap_clnt.c' object='libtirpc_la-pmap_clnt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-pmap_clnt.lo `test -f 'pmap_clnt.c' || echo '$(srcdir)/'`pmap_clnt.c
+
+libtirpc_la-pmap_getmaps.lo: pmap_getmaps.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-pmap_getmaps.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-pmap_getmaps.Tpo -c -o libtirpc_la-pmap_getmaps.lo `test -f 'pmap_getmaps.c' || echo '$(srcdir)/'`pmap_getmaps.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-pmap_getmaps.Tpo $(DEPDIR)/libtirpc_la-pmap_getmaps.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pmap_getmaps.c' object='libtirpc_la-pmap_getmaps.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-pmap_getmaps.lo `test -f 'pmap_getmaps.c' || echo '$(srcdir)/'`pmap_getmaps.c
+
+libtirpc_la-pmap_getport.lo: pmap_getport.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-pmap_getport.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-pmap_getport.Tpo -c -o libtirpc_la-pmap_getport.lo `test -f 'pmap_getport.c' || echo '$(srcdir)/'`pmap_getport.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-pmap_getport.Tpo $(DEPDIR)/libtirpc_la-pmap_getport.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pmap_getport.c' object='libtirpc_la-pmap_getport.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-pmap_getport.lo `test -f 'pmap_getport.c' || echo '$(srcdir)/'`pmap_getport.c
+
+libtirpc_la-pmap_prot.lo: pmap_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-pmap_prot.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-pmap_prot.Tpo -c -o libtirpc_la-pmap_prot.lo `test -f 'pmap_prot.c' || echo '$(srcdir)/'`pmap_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-pmap_prot.Tpo $(DEPDIR)/libtirpc_la-pmap_prot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pmap_prot.c' object='libtirpc_la-pmap_prot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-pmap_prot.lo `test -f 'pmap_prot.c' || echo '$(srcdir)/'`pmap_prot.c
+
+libtirpc_la-pmap_prot2.lo: pmap_prot2.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-pmap_prot2.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-pmap_prot2.Tpo -c -o libtirpc_la-pmap_prot2.lo `test -f 'pmap_prot2.c' || echo '$(srcdir)/'`pmap_prot2.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-pmap_prot2.Tpo $(DEPDIR)/libtirpc_la-pmap_prot2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pmap_prot2.c' object='libtirpc_la-pmap_prot2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-pmap_prot2.lo `test -f 'pmap_prot2.c' || echo '$(srcdir)/'`pmap_prot2.c
+
+libtirpc_la-pmap_rmt.lo: pmap_rmt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-pmap_rmt.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-pmap_rmt.Tpo -c -o libtirpc_la-pmap_rmt.lo `test -f 'pmap_rmt.c' || echo '$(srcdir)/'`pmap_rmt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-pmap_rmt.Tpo $(DEPDIR)/libtirpc_la-pmap_rmt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pmap_rmt.c' object='libtirpc_la-pmap_rmt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-pmap_rmt.lo `test -f 'pmap_rmt.c' || echo '$(srcdir)/'`pmap_rmt.c
+
+libtirpc_la-rpc_prot.lo: rpc_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_prot.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_prot.Tpo -c -o libtirpc_la-rpc_prot.lo `test -f 'rpc_prot.c' || echo '$(srcdir)/'`rpc_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_prot.Tpo $(DEPDIR)/libtirpc_la-rpc_prot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_prot.c' object='libtirpc_la-rpc_prot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_prot.lo `test -f 'rpc_prot.c' || echo '$(srcdir)/'`rpc_prot.c
+
+libtirpc_la-rpc_commondata.lo: rpc_commondata.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_commondata.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_commondata.Tpo -c -o libtirpc_la-rpc_commondata.lo `test -f 'rpc_commondata.c' || echo '$(srcdir)/'`rpc_commondata.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_commondata.Tpo $(DEPDIR)/libtirpc_la-rpc_commondata.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_commondata.c' object='libtirpc_la-rpc_commondata.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_commondata.lo `test -f 'rpc_commondata.c' || echo '$(srcdir)/'`rpc_commondata.c
+
+libtirpc_la-rpc_callmsg.lo: rpc_callmsg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_callmsg.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_callmsg.Tpo -c -o libtirpc_la-rpc_callmsg.lo `test -f 'rpc_callmsg.c' || echo '$(srcdir)/'`rpc_callmsg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_callmsg.Tpo $(DEPDIR)/libtirpc_la-rpc_callmsg.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_callmsg.c' object='libtirpc_la-rpc_callmsg.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_callmsg.lo `test -f 'rpc_callmsg.c' || echo '$(srcdir)/'`rpc_callmsg.c
+
+libtirpc_la-rpc_generic.lo: rpc_generic.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_generic.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_generic.Tpo -c -o libtirpc_la-rpc_generic.lo `test -f 'rpc_generic.c' || echo '$(srcdir)/'`rpc_generic.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_generic.Tpo $(DEPDIR)/libtirpc_la-rpc_generic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_generic.c' object='libtirpc_la-rpc_generic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_generic.lo `test -f 'rpc_generic.c' || echo '$(srcdir)/'`rpc_generic.c
+
+libtirpc_la-rpc_soc.lo: rpc_soc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_soc.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_soc.Tpo -c -o libtirpc_la-rpc_soc.lo `test -f 'rpc_soc.c' || echo '$(srcdir)/'`rpc_soc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_soc.Tpo $(DEPDIR)/libtirpc_la-rpc_soc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_soc.c' object='libtirpc_la-rpc_soc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_soc.lo `test -f 'rpc_soc.c' || echo '$(srcdir)/'`rpc_soc.c
+
+libtirpc_la-rpcb_clnt.lo: rpcb_clnt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpcb_clnt.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpcb_clnt.Tpo -c -o libtirpc_la-rpcb_clnt.lo `test -f 'rpcb_clnt.c' || echo '$(srcdir)/'`rpcb_clnt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpcb_clnt.Tpo $(DEPDIR)/libtirpc_la-rpcb_clnt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpcb_clnt.c' object='libtirpc_la-rpcb_clnt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpcb_clnt.lo `test -f 'rpcb_clnt.c' || echo '$(srcdir)/'`rpcb_clnt.c
+
+libtirpc_la-rpcb_prot.lo: rpcb_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpcb_prot.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpcb_prot.Tpo -c -o libtirpc_la-rpcb_prot.lo `test -f 'rpcb_prot.c' || echo '$(srcdir)/'`rpcb_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpcb_prot.Tpo $(DEPDIR)/libtirpc_la-rpcb_prot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpcb_prot.c' object='libtirpc_la-rpcb_prot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpcb_prot.lo `test -f 'rpcb_prot.c' || echo '$(srcdir)/'`rpcb_prot.c
+
+libtirpc_la-rpcb_st_xdr.lo: rpcb_st_xdr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpcb_st_xdr.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpcb_st_xdr.Tpo -c -o libtirpc_la-rpcb_st_xdr.lo `test -f 'rpcb_st_xdr.c' || echo '$(srcdir)/'`rpcb_st_xdr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpcb_st_xdr.Tpo $(DEPDIR)/libtirpc_la-rpcb_st_xdr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpcb_st_xdr.c' object='libtirpc_la-rpcb_st_xdr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpcb_st_xdr.lo `test -f 'rpcb_st_xdr.c' || echo '$(srcdir)/'`rpcb_st_xdr.c
+
+libtirpc_la-svc.lo: svc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc.Tpo -c -o libtirpc_la-svc.lo `test -f 'svc.c' || echo '$(srcdir)/'`svc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc.Tpo $(DEPDIR)/libtirpc_la-svc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc.c' object='libtirpc_la-svc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc.lo `test -f 'svc.c' || echo '$(srcdir)/'`svc.c
+
+libtirpc_la-svc_auth.lo: svc_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_auth.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_auth.Tpo -c -o libtirpc_la-svc_auth.lo `test -f 'svc_auth.c' || echo '$(srcdir)/'`svc_auth.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_auth.Tpo $(DEPDIR)/libtirpc_la-svc_auth.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_auth.c' object='libtirpc_la-svc_auth.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_auth.lo `test -f 'svc_auth.c' || echo '$(srcdir)/'`svc_auth.c
+
+libtirpc_la-svc_dg.lo: svc_dg.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_dg.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_dg.Tpo -c -o libtirpc_la-svc_dg.lo `test -f 'svc_dg.c' || echo '$(srcdir)/'`svc_dg.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_dg.Tpo $(DEPDIR)/libtirpc_la-svc_dg.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_dg.c' object='libtirpc_la-svc_dg.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_dg.lo `test -f 'svc_dg.c' || echo '$(srcdir)/'`svc_dg.c
+
+libtirpc_la-svc_auth_unix.lo: svc_auth_unix.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_auth_unix.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_auth_unix.Tpo -c -o libtirpc_la-svc_auth_unix.lo `test -f 'svc_auth_unix.c' || echo '$(srcdir)/'`svc_auth_unix.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_auth_unix.Tpo $(DEPDIR)/libtirpc_la-svc_auth_unix.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_auth_unix.c' object='libtirpc_la-svc_auth_unix.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_auth_unix.lo `test -f 'svc_auth_unix.c' || echo '$(srcdir)/'`svc_auth_unix.c
+
+libtirpc_la-svc_auth_none.lo: svc_auth_none.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_auth_none.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_auth_none.Tpo -c -o libtirpc_la-svc_auth_none.lo `test -f 'svc_auth_none.c' || echo '$(srcdir)/'`svc_auth_none.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_auth_none.Tpo $(DEPDIR)/libtirpc_la-svc_auth_none.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_auth_none.c' object='libtirpc_la-svc_auth_none.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_auth_none.lo `test -f 'svc_auth_none.c' || echo '$(srcdir)/'`svc_auth_none.c
+
+libtirpc_la-svc_generic.lo: svc_generic.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_generic.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_generic.Tpo -c -o libtirpc_la-svc_generic.lo `test -f 'svc_generic.c' || echo '$(srcdir)/'`svc_generic.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_generic.Tpo $(DEPDIR)/libtirpc_la-svc_generic.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_generic.c' object='libtirpc_la-svc_generic.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_generic.lo `test -f 'svc_generic.c' || echo '$(srcdir)/'`svc_generic.c
+
+libtirpc_la-svc_raw.lo: svc_raw.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_raw.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_raw.Tpo -c -o libtirpc_la-svc_raw.lo `test -f 'svc_raw.c' || echo '$(srcdir)/'`svc_raw.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_raw.Tpo $(DEPDIR)/libtirpc_la-svc_raw.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_raw.c' object='libtirpc_la-svc_raw.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_raw.lo `test -f 'svc_raw.c' || echo '$(srcdir)/'`svc_raw.c
+
+libtirpc_la-svc_run.lo: svc_run.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_run.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_run.Tpo -c -o libtirpc_la-svc_run.lo `test -f 'svc_run.c' || echo '$(srcdir)/'`svc_run.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_run.Tpo $(DEPDIR)/libtirpc_la-svc_run.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_run.c' object='libtirpc_la-svc_run.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_run.lo `test -f 'svc_run.c' || echo '$(srcdir)/'`svc_run.c
+
+libtirpc_la-svc_simple.lo: svc_simple.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_simple.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_simple.Tpo -c -o libtirpc_la-svc_simple.lo `test -f 'svc_simple.c' || echo '$(srcdir)/'`svc_simple.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_simple.Tpo $(DEPDIR)/libtirpc_la-svc_simple.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_simple.c' object='libtirpc_la-svc_simple.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_simple.lo `test -f 'svc_simple.c' || echo '$(srcdir)/'`svc_simple.c
+
+libtirpc_la-svc_vc.lo: svc_vc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_vc.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_vc.Tpo -c -o libtirpc_la-svc_vc.lo `test -f 'svc_vc.c' || echo '$(srcdir)/'`svc_vc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_vc.Tpo $(DEPDIR)/libtirpc_la-svc_vc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_vc.c' object='libtirpc_la-svc_vc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_vc.lo `test -f 'svc_vc.c' || echo '$(srcdir)/'`svc_vc.c
+
+libtirpc_la-getpeereid.lo: getpeereid.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-getpeereid.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-getpeereid.Tpo -c -o libtirpc_la-getpeereid.lo `test -f 'getpeereid.c' || echo '$(srcdir)/'`getpeereid.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-getpeereid.Tpo $(DEPDIR)/libtirpc_la-getpeereid.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getpeereid.c' object='libtirpc_la-getpeereid.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-getpeereid.lo `test -f 'getpeereid.c' || echo '$(srcdir)/'`getpeereid.c
+
+libtirpc_la-auth_time.lo: auth_time.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-auth_time.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-auth_time.Tpo -c -o libtirpc_la-auth_time.lo `test -f 'auth_time.c' || echo '$(srcdir)/'`auth_time.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-auth_time.Tpo $(DEPDIR)/libtirpc_la-auth_time.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth_time.c' object='libtirpc_la-auth_time.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-auth_time.lo `test -f 'auth_time.c' || echo '$(srcdir)/'`auth_time.c
+
+libtirpc_la-debug.lo: debug.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-debug.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-debug.Tpo -c -o libtirpc_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-debug.Tpo $(DEPDIR)/libtirpc_la-debug.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='debug.c' object='libtirpc_la-debug.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-debug.lo `test -f 'debug.c' || echo '$(srcdir)/'`debug.c
+
+libtirpc_la-auth_des.lo: auth_des.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-auth_des.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-auth_des.Tpo -c -o libtirpc_la-auth_des.lo `test -f 'auth_des.c' || echo '$(srcdir)/'`auth_des.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-auth_des.Tpo $(DEPDIR)/libtirpc_la-auth_des.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth_des.c' object='libtirpc_la-auth_des.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-auth_des.lo `test -f 'auth_des.c' || echo '$(srcdir)/'`auth_des.c
+
+libtirpc_la-authdes_prot.lo: authdes_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-authdes_prot.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-authdes_prot.Tpo -c -o libtirpc_la-authdes_prot.lo `test -f 'authdes_prot.c' || echo '$(srcdir)/'`authdes_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-authdes_prot.Tpo $(DEPDIR)/libtirpc_la-authdes_prot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='authdes_prot.c' object='libtirpc_la-authdes_prot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-authdes_prot.lo `test -f 'authdes_prot.c' || echo '$(srcdir)/'`authdes_prot.c
+
+libtirpc_la-des_crypt.lo: des_crypt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-des_crypt.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-des_crypt.Tpo -c -o libtirpc_la-des_crypt.lo `test -f 'des_crypt.c' || echo '$(srcdir)/'`des_crypt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-des_crypt.Tpo $(DEPDIR)/libtirpc_la-des_crypt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='des_crypt.c' object='libtirpc_la-des_crypt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-des_crypt.lo `test -f 'des_crypt.c' || echo '$(srcdir)/'`des_crypt.c
+
+libtirpc_la-des_impl.lo: des_impl.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-des_impl.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-des_impl.Tpo -c -o libtirpc_la-des_impl.lo `test -f 'des_impl.c' || echo '$(srcdir)/'`des_impl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-des_impl.Tpo $(DEPDIR)/libtirpc_la-des_impl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='des_impl.c' object='libtirpc_la-des_impl.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-des_impl.lo `test -f 'des_impl.c' || echo '$(srcdir)/'`des_impl.c
+
+libtirpc_la-des_soft.lo: des_soft.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-des_soft.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-des_soft.Tpo -c -o libtirpc_la-des_soft.lo `test -f 'des_soft.c' || echo '$(srcdir)/'`des_soft.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-des_soft.Tpo $(DEPDIR)/libtirpc_la-des_soft.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='des_soft.c' object='libtirpc_la-des_soft.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-des_soft.lo `test -f 'des_soft.c' || echo '$(srcdir)/'`des_soft.c
+
+libtirpc_la-svc_auth_des.lo: svc_auth_des.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_auth_des.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_auth_des.Tpo -c -o libtirpc_la-svc_auth_des.lo `test -f 'svc_auth_des.c' || echo '$(srcdir)/'`svc_auth_des.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_auth_des.Tpo $(DEPDIR)/libtirpc_la-svc_auth_des.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_auth_des.c' object='libtirpc_la-svc_auth_des.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_auth_des.lo `test -f 'svc_auth_des.c' || echo '$(srcdir)/'`svc_auth_des.c
+
+libtirpc_la-xdr.lo: xdr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr.Tpo -c -o libtirpc_la-xdr.lo `test -f 'xdr.c' || echo '$(srcdir)/'`xdr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr.Tpo $(DEPDIR)/libtirpc_la-xdr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr.c' object='libtirpc_la-xdr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr.lo `test -f 'xdr.c' || echo '$(srcdir)/'`xdr.c
+
+libtirpc_la-xdr_rec.lo: xdr_rec.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_rec.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_rec.Tpo -c -o libtirpc_la-xdr_rec.lo `test -f 'xdr_rec.c' || echo '$(srcdir)/'`xdr_rec.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_rec.Tpo $(DEPDIR)/libtirpc_la-xdr_rec.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_rec.c' object='libtirpc_la-xdr_rec.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_rec.lo `test -f 'xdr_rec.c' || echo '$(srcdir)/'`xdr_rec.c
+
+libtirpc_la-xdr_array.lo: xdr_array.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_array.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_array.Tpo -c -o libtirpc_la-xdr_array.lo `test -f 'xdr_array.c' || echo '$(srcdir)/'`xdr_array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_array.Tpo $(DEPDIR)/libtirpc_la-xdr_array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_array.c' object='libtirpc_la-xdr_array.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_array.lo `test -f 'xdr_array.c' || echo '$(srcdir)/'`xdr_array.c
+
+libtirpc_la-xdr_float.lo: xdr_float.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_float.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_float.Tpo -c -o libtirpc_la-xdr_float.lo `test -f 'xdr_float.c' || echo '$(srcdir)/'`xdr_float.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_float.Tpo $(DEPDIR)/libtirpc_la-xdr_float.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_float.c' object='libtirpc_la-xdr_float.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_float.lo `test -f 'xdr_float.c' || echo '$(srcdir)/'`xdr_float.c
+
+libtirpc_la-xdr_mem.lo: xdr_mem.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_mem.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_mem.Tpo -c -o libtirpc_la-xdr_mem.lo `test -f 'xdr_mem.c' || echo '$(srcdir)/'`xdr_mem.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_mem.Tpo $(DEPDIR)/libtirpc_la-xdr_mem.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_mem.c' object='libtirpc_la-xdr_mem.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_mem.lo `test -f 'xdr_mem.c' || echo '$(srcdir)/'`xdr_mem.c
+
+libtirpc_la-xdr_reference.lo: xdr_reference.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_reference.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_reference.Tpo -c -o libtirpc_la-xdr_reference.lo `test -f 'xdr_reference.c' || echo '$(srcdir)/'`xdr_reference.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_reference.Tpo $(DEPDIR)/libtirpc_la-xdr_reference.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_reference.c' object='libtirpc_la-xdr_reference.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_reference.lo `test -f 'xdr_reference.c' || echo '$(srcdir)/'`xdr_reference.c
+
+libtirpc_la-xdr_stdio.lo: xdr_stdio.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_stdio.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_stdio.Tpo -c -o libtirpc_la-xdr_stdio.lo `test -f 'xdr_stdio.c' || echo '$(srcdir)/'`xdr_stdio.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_stdio.Tpo $(DEPDIR)/libtirpc_la-xdr_stdio.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_stdio.c' object='libtirpc_la-xdr_stdio.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_stdio.lo `test -f 'xdr_stdio.c' || echo '$(srcdir)/'`xdr_stdio.c
+
+libtirpc_la-xdr_sizeof.lo: xdr_sizeof.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-xdr_sizeof.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-xdr_sizeof.Tpo -c -o libtirpc_la-xdr_sizeof.lo `test -f 'xdr_sizeof.c' || echo '$(srcdir)/'`xdr_sizeof.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-xdr_sizeof.Tpo $(DEPDIR)/libtirpc_la-xdr_sizeof.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdr_sizeof.c' object='libtirpc_la-xdr_sizeof.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-xdr_sizeof.lo `test -f 'xdr_sizeof.c' || echo '$(srcdir)/'`xdr_sizeof.c
+
+libtirpc_la-auth_gss.lo: auth_gss.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-auth_gss.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-auth_gss.Tpo -c -o libtirpc_la-auth_gss.lo `test -f 'auth_gss.c' || echo '$(srcdir)/'`auth_gss.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-auth_gss.Tpo $(DEPDIR)/libtirpc_la-auth_gss.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth_gss.c' object='libtirpc_la-auth_gss.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-auth_gss.lo `test -f 'auth_gss.c' || echo '$(srcdir)/'`auth_gss.c
+
+libtirpc_la-authgss_prot.lo: authgss_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-authgss_prot.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-authgss_prot.Tpo -c -o libtirpc_la-authgss_prot.lo `test -f 'authgss_prot.c' || echo '$(srcdir)/'`authgss_prot.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-authgss_prot.Tpo $(DEPDIR)/libtirpc_la-authgss_prot.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='authgss_prot.c' object='libtirpc_la-authgss_prot.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-authgss_prot.lo `test -f 'authgss_prot.c' || echo '$(srcdir)/'`authgss_prot.c
+
+libtirpc_la-svc_auth_gss.lo: svc_auth_gss.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-svc_auth_gss.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-svc_auth_gss.Tpo -c -o libtirpc_la-svc_auth_gss.lo `test -f 'svc_auth_gss.c' || echo '$(srcdir)/'`svc_auth_gss.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-svc_auth_gss.Tpo $(DEPDIR)/libtirpc_la-svc_auth_gss.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_auth_gss.c' object='libtirpc_la-svc_auth_gss.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-svc_auth_gss.lo `test -f 'svc_auth_gss.c' || echo '$(srcdir)/'`svc_auth_gss.c
+
+libtirpc_la-rpc_gss_utils.lo: rpc_gss_utils.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpc_gss_utils.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpc_gss_utils.Tpo -c -o libtirpc_la-rpc_gss_utils.lo `test -f 'rpc_gss_utils.c' || echo '$(srcdir)/'`rpc_gss_utils.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpc_gss_utils.Tpo $(DEPDIR)/libtirpc_la-rpc_gss_utils.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_gss_utils.c' object='libtirpc_la-rpc_gss_utils.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpc_gss_utils.lo `test -f 'rpc_gss_utils.c' || echo '$(srcdir)/'`rpc_gss_utils.c
+
+libtirpc_la-key_call.lo: key_call.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-key_call.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-key_call.Tpo -c -o libtirpc_la-key_call.lo `test -f 'key_call.c' || echo '$(srcdir)/'`key_call.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-key_call.Tpo $(DEPDIR)/libtirpc_la-key_call.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='key_call.c' object='libtirpc_la-key_call.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-key_call.lo `test -f 'key_call.c' || echo '$(srcdir)/'`key_call.c
+
+libtirpc_la-key_prot_xdr.lo: key_prot_xdr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-key_prot_xdr.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-key_prot_xdr.Tpo -c -o libtirpc_la-key_prot_xdr.lo `test -f 'key_prot_xdr.c' || echo '$(srcdir)/'`key_prot_xdr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-key_prot_xdr.Tpo $(DEPDIR)/libtirpc_la-key_prot_xdr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='key_prot_xdr.c' object='libtirpc_la-key_prot_xdr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-key_prot_xdr.lo `test -f 'key_prot_xdr.c' || echo '$(srcdir)/'`key_prot_xdr.c
+
+libtirpc_la-getpublickey.lo: getpublickey.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-getpublickey.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-getpublickey.Tpo -c -o libtirpc_la-getpublickey.lo `test -f 'getpublickey.c' || echo '$(srcdir)/'`getpublickey.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-getpublickey.Tpo $(DEPDIR)/libtirpc_la-getpublickey.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getpublickey.c' object='libtirpc_la-getpublickey.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-getpublickey.lo `test -f 'getpublickey.c' || echo '$(srcdir)/'`getpublickey.c
+
+libtirpc_la-netname.lo: netname.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-netname.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-netname.Tpo -c -o libtirpc_la-netname.lo `test -f 'netname.c' || echo '$(srcdir)/'`netname.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-netname.Tpo $(DEPDIR)/libtirpc_la-netname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netname.c' object='libtirpc_la-netname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-netname.lo `test -f 'netname.c' || echo '$(srcdir)/'`netname.c
+
+libtirpc_la-netnamer.lo: netnamer.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-netnamer.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-netnamer.Tpo -c -o libtirpc_la-netnamer.lo `test -f 'netnamer.c' || echo '$(srcdir)/'`netnamer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-netnamer.Tpo $(DEPDIR)/libtirpc_la-netnamer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netnamer.c' object='libtirpc_la-netnamer.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-netnamer.lo `test -f 'netnamer.c' || echo '$(srcdir)/'`netnamer.c
+
+libtirpc_la-rpcdname.lo: rpcdname.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rpcdname.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rpcdname.Tpo -c -o libtirpc_la-rpcdname.lo `test -f 'rpcdname.c' || echo '$(srcdir)/'`rpcdname.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rpcdname.Tpo $(DEPDIR)/libtirpc_la-rpcdname.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpcdname.c' object='libtirpc_la-rpcdname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rpcdname.lo `test -f 'rpcdname.c' || echo '$(srcdir)/'`rpcdname.c
+
+libtirpc_la-rtime.lo: rtime.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -MT libtirpc_la-rtime.lo -MD -MP -MF $(DEPDIR)/libtirpc_la-rtime.Tpo -c -o libtirpc_la-rtime.lo `test -f 'rtime.c' || echo '$(srcdir)/'`rtime.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtirpc_la-rtime.Tpo $(DEPDIR)/libtirpc_la-rtime.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtime.c' object='libtirpc_la-rtime.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtirpc_la_CFLAGS) $(CFLAGS) -c -o libtirpc_la-rtime.lo `test -f 'rtime.c' || echo '$(srcdir)/'`rtime.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_des.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_gss.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_none.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_time.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_unix.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-authdes_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-authgss_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-authunix_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-binddynport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-bindresvport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_bcast.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_dg.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_generic.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_perror.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_raw.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_simple.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_vc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-debug.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-des_crypt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-des_impl.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-des_soft.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getnetconfig.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getnetpath.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getpeereid.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getpublickey.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getrpcent.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getrpcport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-key_call.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-key_prot_xdr.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-mt_misc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-netname.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-netnamer.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_clnt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_getmaps.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_getport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_prot2.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_rmt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_callmsg.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_commondata.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_dtablesize.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_generic.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_gss_utils.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_soc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcb_clnt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcb_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcb_st_xdr.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcdname.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rtime.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_des.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_gss.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_none.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_unix.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_dg.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_generic.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_raw.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_run.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_simple.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_vc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_array.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_float.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_mem.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_rec.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_reference.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_sizeof.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_stdio.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_des.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_gss.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_none.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_time.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-auth_unix.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-authdes_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-authgss_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-authunix_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-binddynport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-bindresvport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_bcast.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_dg.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_generic.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_perror.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_raw.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_simple.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-clnt_vc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-debug.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-des_crypt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-des_impl.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-des_soft.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getnetconfig.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getnetpath.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getpeereid.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getpublickey.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getrpcent.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-getrpcport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-key_call.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-key_prot_xdr.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-mt_misc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-netname.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-netnamer.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_clnt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_getmaps.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_getport.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_prot2.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-pmap_rmt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_callmsg.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_commondata.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_dtablesize.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_generic.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_gss_utils.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpc_soc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcb_clnt.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcb_prot.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcb_st_xdr.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rpcdname.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-rtime.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_des.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_gss.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_none.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_auth_unix.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_dg.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_generic.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_raw.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_run.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_simple.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-svc_vc.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_array.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_float.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_mem.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_rec.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_reference.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_sizeof.Plo
+ -rm -f ./$(DEPDIR)/libtirpc_la-xdr_stdio.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/auth_des.c b/src/auth_des.c
new file mode 100644
index 0000000..c9af2e9
--- /dev/null
+++ b/src/auth_des.c
@@ -0,0 +1,500 @@
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <rpc/des_crypt.h>
+#include <syslog.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_des.h>
+#include <rpc/clnt.h>
+#include <rpc/xdr.h>
+#include <sys/socket.h>
+
+#include "nis.h"
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#endif
+
+#include "debug.h"
+
+#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( char *, netobj *, des_block *);
+
+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 (memcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp,
+ sizeof(struct timeval)) != 0) {
+ LIBTIRPC_DEBUG(1, ("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) {
+ ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr,
+ ad->ad_timehost, &(ad->ad_uaddr),
+ &(ad->ad_netid));
+ if (! ok) {
+ /*
+ * Hope the clocks are synced!
+ */
+ ad->ad_dosync = 0;
+ LIBTIRPC_DEBUG(1, ("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) {
+ LIBTIRPC_DEBUG(1,
+ ("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 bool_t
+authdes_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
+{
+ return ((*xfunc)(xdrs, xwhere));
+}
+
+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;
+ ops.ah_wrap = authdes_wrap;
+ ops.ah_unwrap = authdes_wrap;
+ }
+ mutex_unlock(&authdes_ops_lock);
+ return (&ops);
+}
diff --git a/src/auth_gss.c b/src/auth_gss.c
new file mode 100644
index 0000000..3127b92
--- /dev/null
+++ b/src/auth_gss.c
@@ -0,0 +1,992 @@
+/*
+ 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 <dugsong@UMICH.EDU>.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_gss.h>
+#include <rpc/rpcsec_gss.h>
+#include <rpc/clnt.h>
+#include <netinet/in.h>
+#include <reentrant.h>
+
+#include "debug.h"
+
+static void authgss_nextverf(AUTH *);
+static bool_t authgss_marshal(AUTH *, XDR *);
+static bool_t authgss_refresh(AUTH *, void *);
+static bool_t authgss_validate(AUTH *, struct opaque_auth *);
+static void authgss_destroy(AUTH *);
+static void authgss_destroy_context(AUTH *);
+static bool_t authgss_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t authgss_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+
+void rpc_gss_set_error(int);
+void rpc_gss_clear_error(void);
+bool_t rpc_gss_oid_to_mech(rpc_gss_OID, char **);
+
+/*
+ * 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
+};
+
+
+/* useful as i add more mechanisms */
+void
+print_rpc_gss_sec(struct rpc_gss_sec *ptr)
+{
+int i;
+char *p;
+
+ if (libtirpc_debug_level < 4 || log_stderr == 0)
+ return;
+
+ gss_log_debug("rpc_gss_sec:");
+ if(ptr->mech == NULL)
+ gss_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);
+}
+
+extern pthread_mutex_t auth_ref_lock;
+
+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 */
+ int time_req; /* init_sec_context time_req */
+ gss_channel_bindings_t icb; /* input channel bindings */
+ int refcnt; /* reference count gss AUTHs */
+};
+
+#define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private)
+
+static struct timeval AUTH_TIMEOUT = { 25, 0 };
+
+static void
+authgss_auth_get(AUTH *auth)
+{
+ struct rpc_gss_data *gd = AUTH_PRIVATE(auth);
+
+ mutex_lock(&auth_ref_lock);
+ ++gd->refcnt;
+ mutex_unlock(&auth_ref_lock);
+}
+
+static int
+authgss_auth_put(AUTH *auth)
+{
+ int refcnt;
+ struct rpc_gss_data *gd = AUTH_PRIVATE(auth);
+
+ mutex_lock(&auth_ref_lock);
+ refcnt = --gd->refcnt;
+ mutex_unlock(&auth_ref_lock);
+ return refcnt;
+}
+
+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;
+ rpc_gss_options_ret_t ret;
+
+ gss_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);
+ }
+ LIBTIRPC_DEBUG(3, ("authgss_create: name is %p", name));
+ 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);
+ free(gd);
+ return (NULL);
+ }
+ }
+ else
+ gd->name = name;
+
+ LIBTIRPC_DEBUG(3, ("authgss_create: gd->name is %p", gd->name));
+ 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;
+
+ memset(&ret, 0, sizeof(rpc_gss_options_ret_t));
+ if (!authgss_refresh(auth, &ret)) {
+ auth = NULL;
+ sec->major_status = ret.major_status;
+ sec->minor_status = ret.minor_status;
+ }
+ else
+ authgss_auth_get(auth); /* Reference for caller */
+
+ 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;
+
+ gss_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) {
+ gss_log_status("authgss_create_default: 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) {
+ LIBTIRPC_DEBUG(3, ("authgss_create_default: freeing name %p", name));
+ 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;
+
+ gss_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;
+ /*
+ * We've given this away -- don't try to use it ourself any more
+ * Caller should call authgss_free_private_data to free data.
+ * This also ensures that authgss_destroy_context() won't try to
+ * send an RPCSEC_GSS_DESTROY request which might inappropriately
+ * destroy the context.
+ */
+ gd->ctx = GSS_C_NO_CONTEXT;
+ gd->gc.gc_ctx.length = 0;
+ gd->gc.gc_ctx.value = NULL;
+
+ return (TRUE);
+}
+
+bool_t
+authgss_free_private_data(struct authgss_private_data *pd)
+{
+ OM_uint32 min_stat;
+ gss_log_debug("in authgss_free_private_data()");
+
+ if (!pd)
+ return (FALSE);
+
+ if (pd->pd_ctx != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&min_stat, &pd->pd_ctx, NULL);
+ gss_release_buffer(&min_stat, &pd->pd_ctx_hndl);
+ memset(&pd->pd_ctx_hndl, 0, sizeof(pd->pd_ctx_hndl));
+ pd->pd_seq_win = 0;
+
+ return (TRUE);
+}
+
+static void
+authgss_nextverf(AUTH *auth)
+{
+ gss_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;
+
+ gss_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) {
+ gss_log_status("authgss_marshal: 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;
+
+ gss_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 = &num;
+ 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) {
+ gss_log_status("authgss_validate: 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
+_rpc_gss_refresh(AUTH *auth, rpc_gss_options_ret_t *options_ret)
+{
+ 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,
+ time_ret;
+ gss_OID actual_mech_type;
+ char *mechanism;
+
+ gss_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;
+
+ print_rpc_gss_sec(&gd->sec);
+
+ for (;;) {
+ /* print the token we just received */
+ if (recv_tokenp != GSS_C_NO_BUFFER) {
+ gss_log_debug("The token we just received (length %lu):",
+ recv_tokenp->length);
+ gss_log_hexdump(recv_tokenp->value, recv_tokenp->length, 0);
+ }
+ maj_stat = gss_init_sec_context(&min_stat,
+ gd->sec.cred,
+ &gd->ctx,
+ gd->name,
+ gd->sec.mech,
+ gd->sec.req_flags,
+ gd->time_req,
+ gd->icb,
+ recv_tokenp,
+ &actual_mech_type,
+ &send_token,
+ &ret_flags,
+ &time_ret);
+
+ 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) {
+ gss_log_status("gss_init_sec_context", maj_stat, min_stat);
+ options_ret->major_status = maj_stat;
+ options_ret->minor_status = min_stat;
+ break;
+ }
+ if (send_token.length != 0) {
+ memset(&gr, 0, sizeof(gr));
+
+ /* print the token we are about to send */
+ gss_log_debug("The token being sent (length %lu):",
+ send_token.length);
+ gss_log_hexdump(send_token.value, send_token.length, 0);
+
+ 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)) {
+ options_ret->major_status = gr.gr_major;
+ options_ret->minor_status = gr.gr_minor;
+ if (call_stat != RPC_SUCCESS) {
+ struct rpc_err err;
+ clnt_geterr(gd->clnt, &err);
+ LIBTIRPC_DEBUG(1, ("authgss_refresh: %s errno: %s",
+ clnt_sperrno(call_stat), strerror(err.re_errno)));
+ } else
+ gss_log_status("authgss_refresh:",
+ gr.gr_major, gr.gr_minor);
+ 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) {
+ gss_log_status("authgss_refresh: gss_verify_mic",
+ maj_stat, min_stat);
+ if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
+ gd->established = FALSE;
+ authgss_destroy_context(auth);
+ }
+ rpc_gss_set_error(EPERM);
+ options_ret->major_status = maj_stat;
+ options_ret->minor_status = min_stat;
+ return (FALSE);
+ }
+
+ options_ret->major_status = GSS_S_COMPLETE;
+ options_ret->minor_status = 0;
+ options_ret->rpcsec_version = gd->gc.gc_v;
+ options_ret->ret_flags = ret_flags;
+ options_ret->time_ret = time_ret;
+ options_ret->gss_context = gd->ctx;
+ options_ret->actual_mechanism[0] = '\0';
+ if (rpc_gss_oid_to_mech(actual_mech_type, &mechanism)) {
+ strncpy(options_ret->actual_mechanism,
+ mechanism,
+ (sizeof(options_ret->actual_mechanism)-1));
+ }
+
+ 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;
+ rpc_gss_set_error(EPERM);
+
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+static bool_t
+authgss_refresh(AUTH *auth, void *ret)
+{
+ return _rpc_gss_refresh(auth, (rpc_gss_options_ret_t *)ret);
+}
+
+bool_t
+authgss_service(AUTH *auth, int svc)
+{
+ struct rpc_gss_data *gd;
+
+ gss_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;
+
+ gss_log_debug("in authgss_destroy_context()");
+
+ gd = AUTH_PRIVATE(auth);
+
+ if (gd->gc.gc_ctx.length != 0) {
+ if (gd->established) {
+ AUTH *save_auth = NULL;
+
+ /* Make sure we use the right auth_ops */
+ if (gd->clnt->cl_auth != auth) {
+ save_auth = gd->clnt->cl_auth;
+ gd->clnt->cl_auth = auth;
+ }
+
+ gd->gc.gc_proc = RPCSEC_GSS_DESTROY;
+ clnt_call(gd->clnt, NULLPROC, (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT);
+
+ if (save_auth != NULL)
+ gd->clnt->cl_auth = save_auth;
+ }
+ 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)
+{
+ if(authgss_auth_put(auth) == 0)
+ {
+ struct rpc_gss_data *gd;
+ OM_uint32 min_stat;
+
+ gss_log_debug("in authgss_destroy()");
+
+ gd = AUTH_PRIVATE(auth);
+
+ authgss_destroy_context(auth);
+
+ LIBTIRPC_DEBUG(3, ("authgss_destroy: freeing name %p", gd->name));
+ if (gd->name != GSS_C_NO_NAME)
+ gss_release_name(&min_stat, &gd->name);
+
+ free(gd);
+ free(auth);
+ }
+}
+
+static bool_t
+authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+ struct rpc_gss_data *gd;
+
+ gss_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));
+}
+
+static bool_t
+authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+ struct rpc_gss_data *gd;
+
+ gss_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));
+}
+
+static AUTH *
+_rpc_gss_seccreate_error(int system_error)
+{
+ rpc_gss_set_error(system_error);
+ return NULL;
+}
+
+/*
+ * External API: Create a GSS security context for this "clnt"
+ *
+ * clnt: a valid RPC CLIENT structure
+ * principal: NUL-terminated C string containing GSS principal
+ * mechanism: NUL-terminated C string containing GSS mechanism name
+ * service: GSS security value to use
+ * qop: NUL-terminated C string containing QOP name
+ * req: pointer to additional request parameters, or NULL
+ * ret: pointer to additional results, or NULL
+ *
+ * Returns pointer to a filled in RPC AUTH structure or NULL.
+ * Caller must free returned structure with AUTH_DESTROY.
+ */
+AUTH *
+rpc_gss_seccreate(CLIENT *clnt, char *principal, char *mechanism,
+ rpc_gss_service_t service, char *qop,
+ rpc_gss_options_req_t *req, rpc_gss_options_ret_t *ret)
+{
+ rpc_gss_options_ret_t options_ret;
+ OM_uint32 maj_stat, min_stat;
+ struct rpc_gss_sec sec = {
+ .req_flags = GSS_C_MUTUAL_FLAG,
+ .cred = GSS_C_NO_CREDENTIAL,
+ };
+ struct rpc_gss_data *gd;
+ AUTH *auth, *save_auth;
+ gss_buffer_desc sname;
+
+ if (clnt == NULL || principal == NULL)
+ return _rpc_gss_seccreate_error(EINVAL);
+
+ if (rpc_gss_mech_to_oid(mechanism, &sec.mech) == FALSE)
+ return NULL;
+
+ sec.qop = GSS_C_QOP_DEFAULT;
+ if (qop != NULL) {
+ u_int qop_num;
+ if (rpc_gss_qop_to_num(qop, mechanism, &qop_num) == FALSE)
+ return NULL;
+ sec.qop = qop_num;
+ }
+
+ switch (service) {
+ case rpcsec_gss_svc_none:
+ sec.svc = RPCSEC_GSS_SVC_NONE;
+ break;
+ case rpcsec_gss_svc_integrity:
+ sec.svc = RPCSEC_GSS_SVC_INTEGRITY;
+ break;
+ case rpcsec_gss_svc_privacy:
+ sec.svc = RPCSEC_GSS_SVC_PRIVACY;
+ break;
+ case rpcsec_gss_svc_default:
+ sec.svc = RPCSEC_GSS_SVC_INTEGRITY;
+ break;
+ default:
+ return _rpc_gss_seccreate_error(ENOENT);
+ }
+
+ if (ret == NULL)
+ ret = &options_ret;
+ memset(ret, 0, sizeof(*ret));
+
+ auth = calloc(1, sizeof(*auth));
+ gd = calloc(1, sizeof(*gd));
+ if (auth == NULL || gd == NULL) {
+ free(gd);
+ free(auth);
+ return _rpc_gss_seccreate_error(ENOMEM);
+ }
+
+ sname.value = principal;
+ sname.length = strlen(principal);
+ maj_stat = gss_import_name(&min_stat, &sname,
+ (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
+ &gd->name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ ret->major_status = maj_stat;
+ ret->minor_status = min_stat;
+ free(gd);
+ free(auth);
+ return _rpc_gss_seccreate_error(ENOMEM);
+ }
+
+ gd->clnt = clnt;
+ gd->ctx = GSS_C_NO_CONTEXT;
+ gd->sec = sec;
+
+ if (req) {
+ sec.req_flags = req->req_flags;
+ gd->time_req = req->time_req;
+ sec.cred = req->my_cred;
+ gd->icb = req->input_channel_bindings;
+ }
+
+ gd->gc.gc_v = RPCSEC_GSS_VERSION;
+ gd->gc.gc_proc = RPCSEC_GSS_INIT;
+ gd->gc.gc_svc = sec.svc;
+
+ auth->ah_ops = &authgss_ops;
+ auth->ah_private = (caddr_t)gd;
+
+ save_auth = clnt->cl_auth;
+ clnt->cl_auth = auth;
+
+ if (_rpc_gss_refresh(auth, ret) == FALSE) {
+ auth = NULL;
+ } else {
+ rpc_gss_clear_error();
+ authgss_auth_get(auth);
+ }
+
+ clnt->cl_auth = save_auth;
+
+ return auth;
+}
+
+/*
+ * External API: Modify an AUTH's service and QOP settings
+ *
+ * auth: a valid RPC AUTH structure
+ * service: GSS security value to use
+ * qop: NUL-terminated C string containing QOP name
+ *
+ * Returns TRUE if successful, otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, char *qop)
+{
+ struct rpc_gss_data *gd;
+ char *mechanism;
+ u_int qop_num;
+
+ if (auth == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ gd = AUTH_PRIVATE(auth);
+ if (gd == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ if (rpc_gss_oid_to_mech(gd->sec.mech, &mechanism) == FALSE)
+ return FALSE;
+
+ qop_num = GSS_C_QOP_DEFAULT;
+ if (qop != NULL) {
+ if (rpc_gss_qop_to_num(qop, mechanism, &qop_num) == FALSE)
+ return FALSE;
+ }
+
+ switch (service) {
+ case rpcsec_gss_svc_none:
+ gd->gc.gc_svc = gd->sec.svc = RPCSEC_GSS_SVC_NONE;
+ break;
+ case rpcsec_gss_svc_integrity:
+ gd->gc.gc_svc = gd->sec.svc = RPCSEC_GSS_SVC_INTEGRITY;
+ break;
+ case rpcsec_gss_svc_privacy:
+ gd->gc.gc_svc = gd->sec.svc = RPCSEC_GSS_SVC_PRIVACY;
+ break;
+ case rpcsec_gss_svc_default:
+ gd->gc.gc_svc = gd->sec.svc = RPCSEC_GSS_SVC_INTEGRITY;
+ break;
+ default:
+ rpc_gss_set_error(ENOENT);
+ return FALSE;
+ }
+
+ gd->sec.qop = (gss_qop_t)qop_num;
+ rpc_gss_clear_error();
+ return TRUE;
+}
+
+/*
+ * External API: Return maximum data size for a security mechanism and transport
+ *
+ * auth: a valid RPC AUTH structure
+ * maxlen: transport's maximum data size, in bytes
+ *
+ * Returns maximum data size given transformations done by current
+ * security setting of "auth", in bytes, or zero if that value
+ * cannot be determined.
+ */
+int
+rpc_gss_max_data_length(AUTH *auth, int maxlen)
+{
+ OM_uint32 max_input_size, maj_stat, min_stat;
+ struct rpc_gss_data *gd;
+ int conf_req_flag;
+ int result;
+
+ if (auth == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return 0;
+ }
+
+ gd = AUTH_PRIVATE(auth);
+ if (gd == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return 0;
+ }
+
+ switch (gd->sec.svc) {
+ case RPCSEC_GSS_SVC_NONE:
+ rpc_gss_clear_error();
+ return maxlen;
+ case RPCSEC_GSS_SVC_INTEGRITY:
+ conf_req_flag = 0;
+ break;
+ case RPCSEC_GSS_SVC_PRIVACY:
+ conf_req_flag = 1;
+ break;
+ default:
+ rpc_gss_set_error(ENOENT);
+ return 0;
+ }
+
+ result = 0;
+ maj_stat = gss_wrap_size_limit(&min_stat, gd->ctx, conf_req_flag,
+ gd->sec.qop, maxlen, &max_input_size);
+ if (maj_stat == GSS_S_COMPLETE)
+ if ((int)max_input_size > 0)
+ result = (int)max_input_size;
+ rpc_gss_clear_error();
+ return result;
+}
+
+bool_t
+is_authgss_client(CLIENT *clnt)
+{
+ return (clnt->cl_auth->ah_ops == &authgss_ops);
+}
diff --git a/src/auth_none.c b/src/auth_none.c
new file mode 100644
index 0000000..0b0bbd1
--- /dev/null
+++ b/src/auth_none.c
@@ -0,0 +1,182 @@
+/*
+ * 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
+__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 <pthread.h>
+#include <reentrant.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+
+#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 rv = FALSE;
+ extern mutex_t authnone_lock;
+
+ assert(xdrs != NULL);
+
+ mutex_lock(&authnone_lock);
+ ap = authnone_private;
+ if (ap) {
+ rv = (*xdrs->x_ops->x_putbytes)(xdrs, ap->marshalled_client,
+ ap->mcnt);
+ }
+ mutex_unlock(&authnone_lock);
+ return (rv);
+}
+
+/* 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 bool_t
+authnone_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
+{
+ return ((*xfunc)(xdrs, xwhere));
+}
+
+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;
+ ops.ah_wrap = authnone_wrap;
+ ops.ah_unwrap = authnone_wrap;
+ }
+ mutex_unlock(&ops_lock);
+ return (&ops);
+}
diff --git a/src/auth_time.c b/src/auth_time.c
new file mode 100644
index 0000000..936dd76
--- /dev/null
+++ b/src/auth_time.c
@@ -0,0 +1,495 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpcb_prot.h>
+//#include <clnt_soc.h>
+#include <sys/select.h>
+
+#include "nis.h"
+
+
+#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 */
+ memcpy((char *)&sin->sin_port, (char *)&p_bytes, 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 */
+ u_long thetime, 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;
+ int 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];
+
+ memset(&sin, 0, 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 == -1) {
+ 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, &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 < 0 && errno == EINTR);
+ if (res <= 0)
+ goto error;
+ len = sizeof(from);
+ res = recvfrom(s, (char *)&thetime, sizeof(thetime), 0,
+ (struct sockaddr *)&from, &len);
+ if (res == -1) {
+ msg("recvfrom failed on udp transport.");
+ goto error;
+ }
+ time_valid = 1;
+ } else {
+ int res;
+
+ oldsig = (void (*)())signal(SIGALRM, alarm_hndler);
+ saw_alarm = 0; /* global tracking the alarm */
+ alarm(20); /* only wait 20 seconds */
+ res = connect(s, (struct sockaddr *)&sin, sizeof(sin));
+ if (res == -1) {
+ 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));
+ 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 = errno;
+ (void)close(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)close(s);
+
+ if (clnt != NULL)
+ clnt_destroy(clnt);
+
+ alarm(0); /* reset that alarm if its outstanding */
+ if (oldsig) {
+ signal(SIGALRM, oldsig);
+ }
+
+ /*
+ * 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/src/auth_unix.c b/src/auth_unix.c
new file mode 100644
index 0000000..fc2be02
--- /dev/null
+++ b/src/auth_unix.c
@@ -0,0 +1,424 @@
+/*
+ * 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_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 <pthread.h>
+#include <reentrant.h>
+#include <sys/param.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <rpc/clnt.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+
+/* 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;
+
+ memset(&rpc_createerr, 0, sizeof(rpc_createerr));
+
+ /*
+ * Allocate and set up auth handle
+ */
+ au = NULL;
+ auth = mem_alloc(sizeof(*auth));
+#ifndef _KERNEL
+ if (auth == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = ENOMEM;
+ goto cleanup_authunix_create;
+ }
+#endif
+ au = mem_alloc(sizeof(*au));
+#ifndef _KERNEL
+ if (au == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = ENOMEM;
+ 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)) {
+ rpc_createerr.cf_stat = RPC_CANTENCODEARGS;
+ goto cleanup_authunix_create;
+ }
+ 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) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = ENOMEM;
+ 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, *gids;
+ AUTH *result;
+
+ memset(&rpc_createerr, 0, sizeof(rpc_createerr));
+
+ if (gethostname(machname, sizeof machname) == -1) {
+ rpc_createerr.cf_error.re_errno = errno;
+ goto out_err;
+ }
+ machname[sizeof(machname) - 1] = 0;
+ uid = geteuid();
+ gid = getegid();
+
+ /* According to glibc comments, an intervening setgroups(2)
+ * call can increase the number of supplemental groups between
+ * these two getgroups(2) calls. */
+retry:
+ len = getgroups(0, NULL);
+ if (len == -1) {
+ rpc_createerr.cf_error.re_errno = errno;
+ goto out_err;
+ }
+
+ /* Bump allocation size. A zero allocation size may result in a
+ * NULL calloc(3) result, which is not reliably distinguishable
+ * from a memory allocation error. */
+ gids = calloc(len + 1, sizeof(gid_t));
+ if (gids == NULL) {
+ rpc_createerr.cf_error.re_errno = ENOMEM;
+ goto out_err;
+ }
+
+ len = getgroups(len, gids);
+ if (len == -1) {
+ rpc_createerr.cf_error.re_errno = errno;
+ free(gids);
+ if (rpc_createerr.cf_error.re_errno == EINVAL) {
+ rpc_createerr.cf_error.re_errno = 0;
+ goto retry;
+ }
+ goto out_err;
+ }
+
+ /*
+ * AUTH_UNIX sends on the wire only the first NGRPS groups in the
+ * supplemental groups list.
+ */
+ if (len > NGRPS)
+ len = NGRPS;
+
+ /* XXX: interface problem; those should all have been unsigned */
+ result = authunix_create(machname, uid, gid, len, gids);
+ free(gids);
+ return result;
+
+out_err:
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ return NULL;
+}
+
+/*
+ * 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))))
+ warnx("auth_none.c - Fatal marshalling problem");
+ else
+ au->au_mpos = XDR_GETPOS(xdrs);
+ XDR_DESTROY(xdrs);
+}
+
+static bool_t
+authunix_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
+{
+ return ((*xfunc)(xdrs, xwhere));
+}
+
+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;
+ ops.ah_wrap = authunix_wrap;
+ ops.ah_unwrap = authunix_wrap;
+ }
+ mutex_unlock(&ops_lock);
+ return (&ops);
+}
diff --git a/src/authdes_prot.c b/src/authdes_prot.c
new file mode 100644
index 0000000..227d08a
--- /dev/null
+++ b/src/authdes_prot.c
@@ -0,0 +1,85 @@
+/*
+ * 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 <rpc/types.h>
+
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_des.h>
+
+#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/src/authgss_prot.c b/src/authgss_prot.c
new file mode 100644
index 0000000..c2b25db
--- /dev/null
+++ b/src/authgss_prot.c
@@ -0,0 +1,371 @@
+/*
+ authgss_prot.c
+
+ Copyright (c) 2000 The Regents of the University of Michigan.
+ All rights reserved.
+
+ Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_gss.h>
+#include <rpc/rpc.h>
+#include <ctype.h>
+#include <gssapi/gssapi.h>
+
+#include "debug.h"
+
+/* additional space needed for encoding */
+#define RPC_SLACK_SPACE 1024
+
+bool_t
+xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
+{
+ bool_t xdr_stat;
+ u_int tmplen;
+
+ if (xdrs->x_op != XDR_DECODE) {
+ if (buf->length > UINT_MAX)
+ return FALSE;
+ else
+ tmplen = buf->length;
+ }
+ xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
+
+ if (xdr_stat && xdrs->x_op == XDR_DECODE)
+ buf->length = tmplen;
+
+ gss_log_debug("xdr_rpc_gss_buf: %s %s (%p:%lu)",
+ (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+ (xdr_stat == TRUE) ? "success" : "failure",
+ buf->value, buf->length);
+
+ return xdr_stat;
+}
+
+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_rpc_gss_buf(xdrs, &p->gc_ctx, MAX_AUTH_BYTES));
+
+ gss_log_debug("xdr_rpc_gss_cred: %s %s "
+ "(v %d, proc %d, seq %d, svc %d, ctx %p:%lu)",
+ (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;
+ u_int maxlen = (u_int)(p->length + RPC_SLACK_SPACE);
+
+ xdr_stat = xdr_rpc_gss_buf(xdrs, p, maxlen);
+
+ gss_log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%lu)",
+ (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;
+
+ u_int ctx_maxlen = (u_int)(p->gr_ctx.length + RPC_SLACK_SPACE);
+ u_int tok_maxlen = (u_int)(p->gr_token.length + RPC_SLACK_SPACE);
+
+ xdr_stat = (xdr_rpc_gss_buf(xdrs, &p->gr_ctx, ctx_maxlen) &&
+ xdr_u_int(xdrs, &p->gr_major) &&
+ xdr_u_int(xdrs, &p->gr_minor) &&
+ xdr_u_int(xdrs, &p->gr_win) &&
+ xdr_rpc_gss_buf(xdrs, &p->gr_token, tok_maxlen));
+
+ gss_log_debug("xdr_rpc_gss_init_res %s %s "
+ "(ctx %p:%lu, maj %d, min %d, win %d, token %p:%lu)",
+ (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;
+ u_int databuflen, maxwrapsz;
+
+ /* Skip databody length. */
+ start = XDR_GETPOS(xdrs);
+ XDR_SETPOS(xdrs, start + 4);
+
+ memset(&databuf, 0, sizeof(databuf));
+ memset(&wrapbuf, 0, sizeof(wrapbuf));
+
+ /* 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. */
+ databuflen = end - start - 4;
+ XDR_SETPOS(xdrs, start + 4);
+ databuf.value = XDR_INLINE(xdrs, databuflen);
+ databuf.length = databuflen;
+
+ xdr_stat = FALSE;
+
+ if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
+ /* Marshal databody_integ length. */
+ XDR_SETPOS(xdrs, start);
+ if (!xdr_u_int(xdrs, (u_int *)&databuflen))
+ return (FALSE);
+
+ /* Checksum rpc_gss_data_t. */
+ maj_stat = gss_get_mic(&min_stat, ctx, qop,
+ &databuf, &wrapbuf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("xdr_rpc_gss_wrap_data: gss_get_mic",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ /* Marshal checksum. */
+ XDR_SETPOS(xdrs, end);
+ maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
+ xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
+ 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) {
+ gss_log_status("xdr_rpc_gss_wrap_data: gss_wrap",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ /* Marshal databody_priv. */
+ XDR_SETPOS(xdrs, start);
+ maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
+ xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
+ 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_rpc_gss_buf(xdrs, &databuf, (u_int)-1)) {
+ LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: decode databody_integ failed"));
+ return (FALSE);
+ }
+ /* Decode checksum. */
+ if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
+ gss_release_buffer(&min_stat, &databuf);
+ LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: 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);
+ gss_log_status("xdr_rpc_gss_unwrap_data: gss_verify_mic",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ }
+ else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
+ /* Decode databody_priv. */
+ if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
+ LIBTIRPC_DEBUG(1, ("xdr_rpc_gss_unwrap_data: 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);
+ gss_log_status("xdr_rpc_gss_unwrap_data: 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) {
+ LIBTIRPC_DEBUG(1,
+ ("xdr_rpc_gss_unwrap_data: 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);
+}
+
+void
+gss_log_debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlibtirpc_log_dbg(2, fmt, ap);
+ va_end(ap);
+}
+
+void
+gss_log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+ OM_uint32 min, maj;
+ gss_buffer_desc maj_msg, min_msg;
+ u_int32_t msg_ctx = 0;
+
+ gss_display_status(&maj, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &maj_msg);
+ gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
+ &msg_ctx, &min_msg);
+
+ LIBTIRPC_DEBUG(1, ("%s: %s - %s", m, (char *)maj_msg.value, (char *)min_msg.value));
+
+ gss_release_buffer(&maj, &maj_msg);
+ gss_release_buffer(&min, &min_msg);
+}
+
+void
+gss_log_hexdump(const u_char *buf, int len, int offset)
+{
+ u_int i, j, jm;
+ int c;
+
+ if (libtirpc_debug_level < 4 || log_stderr == 0)
+ return;
+
+ 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");
+ }
+}
+
diff --git a/src/authunix_prot.c b/src/authunix_prot.c
new file mode 100644
index 0000000..0a04336
--- /dev/null
+++ b/src/authunix_prot.c
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * authunix_prot.c
+ * XDR for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <assert.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+
+/*
+ * 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/src/binddynport.c b/src/binddynport.c
new file mode 100644
index 0000000..c2e9a20
--- /dev/null
+++ b/src/binddynport.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Oracle America, 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 "Oracle America, 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <rpc/rpc.h>
+
+#include "reentrant.h"
+#include "rpc_com.h"
+
+extern pthread_mutex_t port_lock;
+
+/*
+ * Dynamic port range as defined in RFC 6335 Section 6.
+ * This range avoids all IANA-assigned service port
+ * numbers.
+ */
+enum {
+ LOWPORT = 49152,
+ ENDPORT = 65534,
+ NPORTS = ENDPORT - LOWPORT + 1,
+};
+
+/*
+ * This function decodes information about given port from provided array and
+ * return if port is reserved or not.
+ *
+ * @reserved_ports an array of size at least "NPORTS / (8*sizeof(char)) + 1".
+ * @port port number within range LOWPORT and ENDPORT
+ *
+ * Returns 0 if port is not reserved, non-negative if port is reserved.
+ */
+static int is_reserved(char *reserved_ports, int port) {
+ port -= LOWPORT;
+ if (port < 0 || port >= NPORTS)
+ return 0;
+ return reserved_ports[port/(8*sizeof(char))] & 1<<(port%(8*sizeof(char)));
+}
+
+/*
+ * This function encodes information about given *reserved* port into provided
+ * array. Don't call this function for ports which are not reserved.
+ *
+ * @reserved_ports an array of size at least "NPORTS / (8*sizeof(char)) + 1".
+ * @port port number within range LOWPORT and ENDPORT
+ *
+ */
+static void set_reserved(char *reserved_ports, int port) {
+ port -= LOWPORT;
+ if (port < 0 || port >= NPORTS)
+ return;
+ reserved_ports[port/(8*sizeof(char))] |= 1<<(port%(8*sizeof(char)));
+}
+
+/*
+ * Parse local reserved ports obtained from
+ * /proc/sys/net/ipv4/ip_local_reserved_ports into bit array.
+ *
+ * @reserved_ports a zeroed array of size at least
+ * "NPORTS / (8*sizeof(char)) + 1". Will be used for bit-wise encoding of
+ * reserved ports.
+ *
+ * On each call, reserved ports are read from /proc and bit-wise stored into
+ * provided array
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+
+static int parse_reserved_ports(char *reserved_ports) {
+ int from=0, to;
+ char delimiter = ',';
+ int res;
+ FILE * file_ptr = fopen("/proc/sys/net/ipv4/ip_local_reserved_ports","r");
+ if (file_ptr == NULL) {
+ (void) syslog(LOG_ERR,
+ "Unable to open open /proc/sys/net/ipv4/ip_local_reserved_ports.");
+ return -1;
+ }
+ do {
+ if ((res = fscanf(file_ptr, "%d", &to)) != 1) {
+ if (res == EOF) break;
+ goto err;
+ }
+ if (delimiter != '-') {
+ from = to;
+ }
+ for (int i = from; i <= to; ++i) {
+ set_reserved(reserved_ports, i);
+ }
+ } while ((res = fscanf(file_ptr, "%c", &delimiter)) == 1);
+ if (res != EOF)
+ goto err;
+ fclose(file_ptr);
+ return 0;
+err:
+ (void) syslog(LOG_ERR,
+ "An error occurred while parsing ip_local_reserved_ports.");
+ fclose(file_ptr);
+ return -1;
+}
+
+/*
+ * Bind a socket to a dynamically-assigned IP port.
+ *
+ * @fd is an open but unbound socket.
+ *
+ * On each call, a port number is chosen at random from
+ * within the dynamic/private port range, even if the
+ * caller has CAP_NET_ADMIN_BIND.
+ *
+ * Returns 0 on success, -1 on failure. errno may be
+ * set to a non-determinant value.
+ *
+ * This function is re-entrant.
+ */
+int __binddynport(int fd)
+{
+ struct sockaddr_storage ss;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ struct sockaddr_in *sin;
+ static unsigned int seed;
+ in_port_t port, *portp;
+ struct sockaddr *sap;
+ socklen_t salen;
+ int i, res, array_size;
+ char *reserved_ports = NULL;
+
+ if (__rpc_sockisbound(fd))
+ return 0;
+
+ res = -1;
+ sap = (struct sockaddr *)(void *)&ss;
+ salen = sizeof(ss);
+ memset(sap, 0, salen);
+
+ mutex_lock(&port_lock);
+
+ if (getsockname(fd, sap, &salen) == -1)
+ goto out;
+
+ switch (ss.ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)(void *)&ss;
+ portp = &sin->sin_port;
+ salen = sizeof(struct sockaddr_in);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)(void *)&ss;
+ portp = &sin6->sin6_port;
+ salen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ goto out;
+ }
+
+ if (!seed) {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ seed = tv.tv_usec * getpid();
+ }
+ array_size = NPORTS / (8*sizeof(char)) + 1;
+ reserved_ports = malloc(array_size);
+ if (!reserved_ports) {
+ goto out;
+ }
+ memset(reserved_ports, 0, array_size);
+ if (parse_reserved_ports(reserved_ports) < 0)
+ goto out;
+
+ port = (rand_r(&seed) % NPORTS) + LOWPORT;
+ for (i = 0; i < NPORTS; ++i) {
+ *portp = htons(port);
+ if (!is_reserved(reserved_ports, port++)) {
+ res = bind(fd, sap, salen);
+ if (res >= 0) {
+ res = 0;
+ break;
+ }
+ if (errno != EADDRINUSE)
+ break;
+ }
+ if (port > ENDPORT)
+ port = LOWPORT;
+ }
+
+out:
+ free(reserved_ports);
+ mutex_unlock(&port_lock);
+ return res;
+}
diff --git a/src/bindresvport.c b/src/bindresvport.c
new file mode 100644
index 0000000..efeb1cc
--- /dev/null
+++ b/src/bindresvport.c
@@ -0,0 +1,338 @@
+/*
+ * 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) 1987 by Sun Microsystems, Inc.
+ *
+ * Portions Copyright(C) 1996, Jason Downs. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+
+#include <string.h>
+#include <reentrant.h>
+
+extern pthread_mutex_t port_lock;
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport(sd, sin)
+ int 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)
+
+/*
+ * Read the file /etc/bindresvport.blacklist, so that we don't bind
+ * to these ports.
+ */
+
+static int blacklist_read;
+static int *list;
+static int list_size = 0;
+
+static void
+load_blacklist (void)
+{
+ FILE *fp;
+ char *buf = NULL;
+ size_t buflen = 0;
+ int size = 0, ptr = 0;
+
+ blacklist_read = 1;
+
+ fp = fopen ("/etc/bindresvport.blacklist", "r");
+ if (NULL == fp)
+ return;
+
+ while (!feof (fp))
+ {
+ unsigned long port;
+ char *tmp, *cp;
+ ssize_t n = getline (&buf, &buflen, fp);
+ if (n < 1)
+ break;
+
+ cp = buf;
+ tmp = strchr (cp, '#'); /* remove comments */
+ if (tmp)
+ *tmp = '\0';
+ while (isspace ((int)*cp)) /* remove spaces and tabs */
+ ++cp;
+ if (*cp == '\0') /* ignore empty lines */
+ continue;
+ if (cp[strlen (cp) - 1] == '\n')
+ cp[strlen (cp) - 1] = '\0';
+
+ port = strtoul (cp, &tmp, 0);
+ while (isspace(*tmp))
+ ++tmp;
+ if (*tmp != '\0' || (port == ULONG_MAX && errno == ERANGE))
+ continue;
+
+ /* Don't bother with out-of-range ports */
+ if (port < LOWPORT || port > ENDPORT)
+ continue;
+
+ if (ptr >= size)
+ {
+ size += 10;
+ list = realloc (list, size * sizeof (int));
+ if (list == NULL)
+ {
+ free (buf);
+ fclose (fp);
+ return;
+ }
+ }
+
+ list[ptr++] = port;
+ }
+
+ fclose (fp);
+
+ if (buf)
+ free (buf);
+
+ list_size = ptr;
+}
+
+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;
+ int endport = ENDPORT;
+ int i;
+
+ mutex_lock(&port_lock);
+
+ if (!blacklist_read)
+ load_blacklist();
+
+ nports = ENDPORT - startport + 1;
+
+ if (sa == NULL) {
+ salen = sizeof(myaddr);
+ sa = (struct sockaddr *)&myaddr;
+
+ if (getsockname(sd, (struct sockaddr *)&myaddr, &salen) == -1) {
+ mutex_unlock(&port_lock);
+ 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;
+ mutex_unlock(&port_lock);
+ return (-1);
+ }
+ sa->sa_family = af;
+
+ if (port == 0) {
+ port = (getpid() % NPORTS) + STARTPORT;
+ }
+ res = -1;
+ errno = EADDRINUSE;
+ again:
+ for (i = 0; i < nports; ++i) {
+ int j;
+
+ /* Check if this port is not blacklisted. */
+ for (j = 0; j < list_size; j++)
+ if (port == list[j])
+ goto try_next_port;
+
+ *portp = htons(port);
+ res = bind(sd, sa, salen);
+ if (res >= 0 || errno != EADDRINUSE)
+ break;
+
+try_next_port:
+ if (++port > endport)
+ port = startport;
+ }
+ if (i == nports && startport != LOWPORT) {
+ startport = LOWPORT;
+ endport = STARTPORT - 1;
+ nports = STARTPORT - LOWPORT;
+ port = LOWPORT + port % (STARTPORT - LOWPORT);
+ goto again;
+ }
+ mutex_unlock(&port_lock);
+
+ return (res);
+}
+#else
+
+#define IP_PORTRANGE 19
+#define IP_PORTRANGE_LOW 2
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport_sa(sd, sa)
+ int sd;
+ struct sockaddr *sa;
+{
+ int old, 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;
+
+ if (sa == NULL) {
+ salen = sizeof(myaddr);
+ sa = (struct sockaddr *)&myaddr;
+
+ if (getsockname(sd, sa, &salen) == -1)
+ return -1; /* errno is correctly set */
+
+ af = sa->sa_family;
+ memset(sa, 0, salen);
+ } 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;
+ portrange = IPV6_PORTRANGE;
+ portlow = IPV6_PORTRANGE_LOW;
+ sin6 = (struct sockaddr_in6 *)sa;
+ salen = sizeof(struct sockaddr_in6);
+ portp = &sin6->sin6_port;
+ break;
+#endif
+ default:
+ errno = EPFNOSUPPORT;
+ return (-1);
+ }
+ sa->sa_family = af;
+
+ 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);
+ }
+
+ error = bind(sd, sa, salen);
+
+ 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);
+ }
+ }
+ return (error);
+}
+#endif
diff --git a/src/clnt_bcast.c b/src/clnt_bcast.c
new file mode 100644
index 0000000..2ad6c89
--- /dev/null
+++ b/src/clnt_bcast.c
@@ -0,0 +1,698 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 <sys/socket.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#include <poll.h>
+#include <rpc/rpc.h>
+#ifdef PORTMAP
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_rmt.h>
+#endif /* PORTMAP */
+#include <rpc/nettype.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <err.h>
+#include <string.h>
+
+#include "rpc_com.h"
+#include "debug.h"
+
+#define MAXBCAST 20 /* Max no of broadcasting transports */
+#define INITTIME 4000 /* Time to wait initially */
+#define WAITTIME 8000 /* Maximum time to wait */
+
+# define POLLRDNORM 0x040 /* Normal data may be read. */
+# define POLLRDBAND 0x080 /* Priority data may be read. */
+
+
+
+/*
+ * 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 (getifaddrs(&ifp) < 0)
+ return 0;
+
+ 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 == NULL || /* happens for eg tuntap devices */
+ 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) < 0)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Some rpcbind implementations use an IPv6 socket to serve both
+ * IPv4 and IPv6 messages, but neglect to check for the caller's
+ * address family when sending broadcast replies. These rpcbind
+ * implementations return an IPv6 address in reply to an IPv4
+ * broadcast. We can either ignore them, or try to patch them up.
+ */
+static struct netbuf *
+__ipv6v4_fixup(struct sockaddr_storage *ss, const char *uaddr)
+{
+ struct sockaddr_in sin;
+ struct netbuf *np;
+
+ /* ss is the remote rpcbind server's address */
+ if (ss->ss_family != AF_INET)
+ return NULL;
+ memcpy(&sin, ss, sizeof(sin));
+
+ np = __rpc_uaddr2taddr_af(AF_INET6, uaddr);
+ if (np == NULL)
+ return NULL;
+
+ /* Overwrite the port with that of the service we
+ * wanted to talk to. */
+ sin.sin_port = ((struct sockaddr_in6 *) np)->sin6_port;
+
+ /* We know netbuf holds a sockaddr_in6, so it can easily
+ * hold a sockaddr_in as well. */
+ memcpy(np->buf, &sin, sizeof(sin));
+ np->len = sizeof(sin);
+
+ return np;
+}
+
+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) {
+ AUTH_DESTROY(sys_auth);
+ 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 < 0) {
+ 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) {
+ close(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) {
+ LIBTIRPC_DEBUG(1,
+ ("rpc_broadcast_exp: sendto failed: errno %d", errno));
+ warnx("rpc_broadcast_exp: cannot send broadcast packet");
+ stat = RPC_CANTSEND;
+ continue;
+ };
+ if (!__rpc_lowvers)
+ LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: Broadcast packet sent for %s\n",
+ fdlist[i].nconf->nc_netid));
+#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;
+ }
+ }
+ LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: PMAP Broadcast packet sent for %s\n",
+ fdlist[i].nconf->nc_netid));
+#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++;
+ LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: response for %s\n",
+ fdlist[i].nconf->nc_netid));
+ 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 */
+ LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: uaddr %s\n", uaddrp));
+ np = uaddr2taddr(
+ fdlist[i].nconf, uaddrp);
+ /* Some misguided rpcbind implemenations
+ * seem to return an IPv6 uaddr in IPv4
+ * responses. */
+ if (np == NULL)
+ np = __ipv6v4_fixup(
+ &fdlist[i].raddr,
+ uaddrp);
+ if (np != NULL) {
+ 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)close(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);
+}
diff --git a/src/clnt_dg.c b/src/clnt_dg.c
new file mode 100644
index 0000000..166af63
--- /dev/null
+++ b/src/clnt_dg.c
@@ -0,0 +1,809 @@
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <poll.h>
+
+#include <sys/time.h>
+
+#include <sys/ioctl.h>
+#include <rpc/clnt.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <err.h>
+#include "rpc_com.h"
+#include "clnt_fd_locks.h"
+
+#ifdef IP_RECVERR
+#include <asm/types.h>
+#include <linux/errqueue.h>
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_RPCSEC_GSS
+#include <rpc/auth_gss.h>
+#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.
+ *
+ * We keep track of a list of per-fd locks, protected by the clnt_fd_lock
+ * mutex. Each per-fd lock consists of a predicate indicating whether is
+ * active or not: fd_lock->active == TRUE => a call is active on some
+ * CLIENT handle created for that fd. Each fd predicate is guarded by a
+ * condition variable so that the global mutex can be unlocked while
+ * waiting for the predicate to change.
+ *
+ * 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 fd_locks_t *dg_fd_locks;
+extern mutex_t clnt_fd_lock;
+#define release_fd_lock(fd_lock, mask) { \
+ mutex_lock(&clnt_fd_lock); \
+ fd_lock->active = FALSE; \
+ fd_lock->pending--; \
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
+ cond_signal(&fd_lock->cv); \
+ mutex_unlock(&clnt_fd_lock); \
+}
+
+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 {
+ int cu_fd; /* connections fd */
+ fd_lock_t *cu_fd_lock;
+ 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)
+ int 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;
+ sigset_t mask;
+ sigset_t newmask;
+ struct __rpc_sockinfo si;
+ int one = 1;
+ fd_lock_t *fd_lock;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ if (dg_fd_locks == (fd_locks_t *) NULL) {
+ dg_fd_locks = fd_locks_init();
+ if (dg_fd_locks == (fd_locks_t *) NULL) {
+ mutex_unlock(&clnt_fd_lock);
+ goto err1;
+ }
+ }
+ fd_lock = fd_lock_create(fd, dg_fd_locks);
+ if (fd_lock == (fd_lock_t *) NULL) {
+ mutex_unlock(&clnt_fd_lock);
+ goto err1;
+ }
+
+ 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_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
+ ioctl(fd, FIONBIO, (char *)(void *)&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;
+ cu->cu_fd_lock = fd_lock;
+ 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;
+ sigset_t mask;
+ sigset_t newmask;
+ socklen_t salen;
+ ssize_t recvlen = 0;
+ u_int32_t xid, inval, outval;
+
+ outlen = 0;
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ cu->cu_fd_lock->pending++;
+ while (cu->cu_fd_lock->active)
+ cond_wait(&cu->cu_fd_lock->cv, &clnt_fd_lock);
+ cu->cu_fd_lock->active = TRUE;
+ 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;
+ }
+
+#ifdef HAVE_RPCSEC_GSS
+ if (is_authgss_client(cl))
+ nrefreshes = 0;
+#endif
+
+ /* 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)) ||
+ (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, 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, 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 = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+
+ 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;
+ 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 *) mem_alloc((outlen + 256));
+ int ret;
+
+ if (cbuf == NULL)
+ {
+ cu->cu_error.re_errno = errno;
+ return (cu->cu_error.re_status = RPC_CANTRECV);
+ }
+ 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;
+ mem_free(cbuf, (outlen + 256));
+ release_fd_lock(cu->cu_fd_lock, mask);
+ return (cu->cu_error.re_status = RPC_CANTRECV);
+ }
+ mem_free(cbuf, (outlen + 256));
+ }
+#endif
+
+ /* We have some data now */
+ do {
+ recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf,
+ cu->cu_recvsz, 0, NULL, NULL);
+ } while (recvlen < 0 && errno == EINTR);
+ if (recvlen < 0 && errno != EWOULDBLOCK) {
+ 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 == FALSE) {
+ 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;
+ }
+ }
+
+ /*
+ * 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;
+ } else if (! AUTH_UNWRAP(cl->cl_auth, &reply_xdrs,
+ xresults, resultsp)) {
+ if (cu->cu_error.re_status == RPC_SUCCESS)
+ cu->cu_error.re_status = RPC_CANTDECODERES;
+ }
+ 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_lock, 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;
+ sigset_t mask;
+ sigset_t newmask;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ cu->cu_fd_lock->pending++;
+ while (cu->cu_fd_lock->active)
+ cond_wait(&cu->cu_fd_lock->cv, &clnt_fd_lock);
+ xdrs->x_op = XDR_FREE;
+ dummy = (*xdr_res)(xdrs, res_ptr);
+ cu->cu_fd_lock->pending--;
+ thr_sigsetmask(SIG_SETMASK, &mask, NULL);
+ cond_signal(&cu->cu_fd_lock->cv);
+ mutex_unlock(&clnt_fd_lock);
+ 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;
+ sigset_t mask;
+ sigset_t newmask;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ cu->cu_fd_lock->pending++;
+ while (cu->cu_fd_lock->active)
+ cond_wait(&cu->cu_fd_lock->cv, &clnt_fd_lock);
+ cu->cu_fd_lock->active = TRUE;
+ mutex_unlock(&clnt_fd_lock);
+ switch (request) {
+ case CLSET_FD_CLOSE:
+ cu->cu_closeit = TRUE;
+ release_fd_lock(cu->cu_fd_lock, mask);
+ return (TRUE);
+ case CLSET_FD_NCLOSE:
+ cu->cu_closeit = FALSE;
+ release_fd_lock(cu->cu_fd_lock, mask);
+ return (TRUE);
+ }
+
+ /* for other requests which use info */
+ if (info == NULL) {
+ release_fd_lock(cu->cu_fd_lock, mask);
+ return (FALSE);
+ }
+ switch (request) {
+ case CLSET_TIMEOUT:
+ if (time_not_ok((struct timeval *)info)) {
+ release_fd_lock(cu->cu_fd_lock, 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_lock, mask);
+ return (FALSE);
+ }
+ cu->cu_wait = *(struct timeval *)info;
+ break;
+ case CLGET_RETRY_TIMEOUT:
+ *(struct timeval *)info = cu->cu_wait;
+ break;
+ case CLGET_FD:
+ *(int *)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_lock, 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_lock, mask);
+ return (FALSE);
+ }
+ release_fd_lock(cu->cu_fd_lock, mask);
+ return (TRUE);
+}
+
+static void
+clnt_dg_destroy(cl)
+ CLIENT *cl;
+{
+ struct cu_data *cu = (struct cu_data *)cl->cl_private;
+ int cu_fd = cu->cu_fd;
+ fd_lock_t *cu_fd_lock = cu->cu_fd_lock;
+ sigset_t mask;
+ sigset_t newmask;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ /* wait until all pending operations on client are completed. */
+ while (cu_fd_lock->pending > 0) {
+ /* If a blocked operation can be awakened, then do it. */
+ if (cu_fd_lock->active == FALSE)
+ cond_signal(&cu_fd_lock->cv);
+ /* keep waiting... */
+ cond_wait(&cu_fd_lock->cv, &clnt_fd_lock);
+ }
+ if (cu->cu_closeit)
+ (void)close(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));
+ cond_signal(&cu_fd_lock->cv);
+ fd_lock_destroy(cu_fd, cu_fd_lock, dg_fd_locks);
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &mask, NULL);
+}
+
+static struct clnt_ops *
+clnt_dg_ops()
+{
+ static struct clnt_ops ops;
+ extern mutex_t ops_lock;
+ sigset_t mask;
+ sigset_t newmask;
+
+/* VARIABLES PROTECTED BY ops_lock: ops */
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ 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/src/clnt_fd_locks.h b/src/clnt_fd_locks.h
new file mode 100644
index 0000000..6ba62cb
--- /dev/null
+++ b/src/clnt_fd_locks.h
@@ -0,0 +1,209 @@
+/*
+ * debug.h -- debugging routines for libtirpc
+ *
+ * Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
+ *
+ * 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.
+ */
+
+#ifndef _CLNT_FD_LOCKS_H
+#define _CLNT_FD_LOCKS_H
+
+#include <sys/queue.h>
+#include <errno.h>
+#include <reentrant.h>
+#include <rpc/xdr.h>
+
+
+/*
+ * This utility manages a list of per-fd locks for the clients.
+ *
+ * If MAX_FDLOCKS_PREALLOC is defined, a number of pre-fd locks will be
+ * pre-allocated. This number is the minimum of MAX_FDLOCKS_PREALLOC or
+ * the process soft limit of allowed fds.
+ */
+#ifdef MAX_FDLOCKS_PREALLOC
+static unsigned int fd_locks_prealloc = 0;
+#endif
+
+/* per-fd lock */
+struct fd_lock_t {
+ bool_t active;
+ int pending; /* Number of pending operations on fd */
+ cond_t cv;
+};
+typedef struct fd_lock_t fd_lock_t;
+
+
+/* internal type to store per-fd locks in a list */
+struct fd_lock_item_t {
+ /* fd_lock_t first so we can cast to fd_lock_item_t */
+ fd_lock_t fd_lock;
+ int fd;
+ unsigned int refs;
+ TAILQ_ENTRY(fd_lock_item_t) link;
+};
+typedef struct fd_lock_item_t fd_lock_item_t;
+#define to_fd_lock_item(fdlock_t_ptr) ((fd_lock_item_t*) fdlock_t_ptr)
+
+
+/* internal list of per-fd locks */
+typedef TAILQ_HEAD(,fd_lock_item_t) fd_lock_list_t;
+
+
+#ifdef MAX_FDLOCKS_PREALLOC
+
+/* With pre-allocation, keep track of both an array and a list */
+struct fd_locks_t {
+ fd_lock_list_t fd_lock_list;
+ fd_lock_t *fd_lock_array;
+};
+typedef struct fd_locks_t fd_locks_t;
+#define to_fd_lock_list(fd_locks_t_ptr) (&fd_locks_t_ptr->fd_lock_list)
+
+#else
+
+/* With no pre-allocation, just keep track of a list */
+typedef fd_lock_list_t fd_locks_t;
+#define to_fd_lock_list(fd_locks_t_ptr) ((fd_lock_list_t *) fd_locks_t_ptr)
+
+#endif
+
+
+/* allocate fd locks */
+static inline
+fd_locks_t* fd_locks_init() {
+ fd_locks_t *fd_locks;
+
+ fd_locks = (fd_locks_t *) mem_alloc(sizeof(fd_locks_t));
+ if (fd_locks == (fd_locks_t *) NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ TAILQ_INIT(to_fd_lock_list(fd_locks));
+
+#ifdef MAX_FDLOCKS_PREALLOC
+ size_t fd_lock_arraysz;
+
+ if (fd_locks_prealloc == 0) {
+ unsigned int dtbsize = __rpc_dtbsize();
+ if (0 < dtbsize && dtbsize < MAX_FDLOCKS_PREALLOC)
+ fd_locks_prealloc = dtbsize;
+ else
+ fd_locks_prealloc = MAX_FDLOCKS_PREALLOC;
+ }
+
+ if ( (size_t) fd_locks_prealloc > SIZE_MAX/sizeof(fd_lock_t)) {
+ mem_free(fd_locks, sizeof (*fd_locks));
+ errno = EOVERFLOW;
+ return (NULL);
+ }
+
+ fd_lock_arraysz = fd_locks_prealloc * sizeof (fd_lock_t);
+ fd_locks->fd_lock_array = (fd_lock_t *) mem_alloc(fd_lock_arraysz);
+ if (fd_locks->fd_lock_array == (fd_lock_t *) NULL) {
+ mem_free(fd_locks, sizeof (*fd_locks));
+ errno = ENOMEM;
+ return (NULL);
+ }
+ else {
+ int i;
+
+ for (i = 0; i < fd_locks_prealloc; i++) {
+ fd_locks->fd_lock_array[i].active = FALSE;
+ cond_init(&fd_locks->fd_lock_array[i].cv, 0, (void *) 0);
+ }
+ }
+#endif
+
+ return fd_locks;
+}
+
+/* de-allocate fd locks */
+static inline
+void fd_locks_destroy(fd_locks_t *fd_locks) {
+#ifdef MAX_FDLOCKS_PREALLOC
+ fd_lock_t *array = fd_locks->fd_lock_array;
+ mem_free(array, fd_locks_prealloc * sizeof (fd_lock_t));
+#endif
+ fd_lock_item_t *item;
+ fd_lock_list_t *list = to_fd_lock_list(fd_locks);
+
+ TAILQ_FOREACH(item, list, link) {
+ cond_destroy(&item->fd_lock.cv);
+ mem_free(item, sizeof (*item));
+ }
+ mem_free(fd_locks, sizeof (*fd_locks));
+}
+
+/* allocate per-fd lock */
+static inline
+fd_lock_t* fd_lock_create(int fd, fd_locks_t *fd_locks) {
+#ifdef MAX_FDLOCKS_PREALLOC
+ if (fd < fd_locks_prealloc) {
+ return &fd_locks->fd_lock_array[fd];
+ }
+#endif
+ fd_lock_item_t *item;
+ fd_lock_list_t *list = to_fd_lock_list(fd_locks);
+
+ for (item = TAILQ_FIRST(list);
+ item != (fd_lock_item_t *) NULL && item->fd != fd;
+ item = TAILQ_NEXT(item, link));
+
+ if (item == (fd_lock_item_t *) NULL) {
+ item = (fd_lock_item_t *) mem_alloc(sizeof(fd_lock_item_t));
+ if (item == (fd_lock_item_t *) NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ item->fd = fd;
+ item->refs = 1;
+ item->fd_lock.active = FALSE;
+ item->fd_lock.pending = 0;
+ cond_init(&item->fd_lock.cv, 0, (void *) 0);
+ TAILQ_INSERT_HEAD(list, item, link);
+ } else {
+ item->refs++;
+ }
+ return &item->fd_lock;
+}
+
+/* de-allocate per-fd lock */
+static inline
+void fd_lock_destroy(int fd, fd_lock_t *fd_lock, fd_locks_t *fd_locks) {
+#ifdef MAX_FDLOCKS_PREALLOC
+ if (fd < fd_locks_prealloc)
+ return;
+#endif
+ fd_lock_item_t* item = to_fd_lock_item(fd_lock);
+ item->refs--;
+ if (item->refs <= 0) {
+ TAILQ_REMOVE(to_fd_lock_list(fd_locks), item, link);
+ cond_destroy(&item->fd_lock.cv);
+ mem_free(item, sizeof (*item));
+ }
+}
+
+#endif /* _CLNT_FD_LOCKS_H */
diff --git a/src/clnt_generic.c b/src/clnt_generic.c
new file mode 100644
index 0000000..3f3dabf
--- /dev/null
+++ b/src/clnt_generic.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2010, Oracle America, 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 the "Oracle America, 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 <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "rpc_com.h"
+
+extern bool_t __rpc_is_local_host(const char *);
+int __rpc_raise_fd(int);
+
+#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, rpcprog_t prog, rpcvers_t *vers_out,
+ rpcvers_t vers_low, 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, rpcprog_t prog,
+ rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
+ const char *nettype, const struct timeval *tp)
+{
+ CLIENT *clnt;
+ struct timeval to;
+ enum clnt_stat rpc_stat;
+ struct rpc_err rpcerr;
+
+ 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, rpcprog_t prog, 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, rpcprog_t prog, 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, rpcprog_t prog, 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, rpcprog_t prog, 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);
+ } 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);
+ }
+ }
+ 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(int fd, const struct netconfig *nconf,
+ struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
+ uint sendsz, uint recvsz)
+{
+ CLIENT *cl; /* client handle */
+ bool_t madefd = FALSE; /* whether fd opened here */
+ long servtype;
+ int one = 1;
+ struct __rpc_sockinfo si;
+ extern int __rpc_minfd;
+
+ if (fd == RPC_ANYFD) {
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return (NULL);
+ }
+
+ fd = __rpc_nconf2fd(nconf);
+
+ if (fd == -1)
+ goto err;
+ if (fd < __rpc_minfd)
+ fd = __rpc_raise_fd(fd);
+ madefd = TRUE;
+ servtype = nconf->nc_semantics;
+ if (!__rpc_fd2sockinfo(fd, &si))
+ goto err;
+ bindresvport(fd, NULL);
+ } 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);
+ 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, &one,
+ sizeof (one));
+ }
+ cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
+ 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)close(fd);
+ return (NULL);
+}
+
+/*
+ * 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) {
+ close(nfd);
+ return (fd);
+ }
+
+ if (close(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);
+}
diff --git a/src/clnt_perror.c b/src/clnt_perror.c
new file mode 100644
index 0000000..fb7fb80
--- /dev/null
+++ b/src/clnt_perror.c
@@ -0,0 +1,335 @@
+/*
+ * 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_perror.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+
+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/src/clnt_raw.c b/src/clnt_raw.c
new file mode 100644
index 0000000..03f839d
--- /dev/null
+++ b/src/clnt_raw.c
@@ -0,0 +1,307 @@
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rpc/rpc.h>
+#include <rpc/raw.h>
+
+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;
+ 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);
+ }
+ xdrs = &clp->xdr_stream;
+ 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;
+ bool_t rval;
+
+ mutex_lock(&clntraw_lock);
+ if (clp == NULL) {
+ rval = (bool_t) RPC_FAILED;
+ mutex_unlock(&clntraw_lock);
+ return (rval);
+ }
+ xdrs = &clp->xdr_stream;
+ 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/src/clnt_simple.c b/src/clnt_simple.c
new file mode 100644
index 0000000..1700060
--- /dev/null
+++ b/src/clnt_simple.c
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * clnt_simple.c
+ * Simplified front end to client rpc.
+ */
+#include <pthread.h>
+#include <reentrant.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <rpc/clnt.h>
+
+#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 == KEY_INITIALIZER) {
+ mutex_lock(&tsd_lock);
+ if (rpc_call_key == KEY_INITIALIZER)
+ 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))
+ 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/src/clnt_vc.c b/src/clnt_vc.c
new file mode 100644
index 0000000..5bbc78b
--- /dev/null
+++ b/src/clnt_vc.c
@@ -0,0 +1,801 @@
+/*
+ * 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 <pthread.h>
+
+#include <reentrant.h>
+#include <sys/types.h>
+#include <poll.h>
+#include <sys/syslog.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdint.h>
+
+#include <rpc/rpc.h>
+#include "rpc_com.h"
+#include "clnt_fd_locks.h"
+
+#ifdef HAVE_RPCSEC_GSS
+#include <rpc/auth_gss.h>
+#endif
+
+#define MCALL_MSG_SIZE 24
+
+#define CMGROUP_MAX 16
+#define SCM_CREDS 0x03 /* process creds (struct cmsgcred) */
+
+#undef rpc_createerr /* make it clear it is a thread safe variable */
+
+/*
+ * 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 */
+ fd_lock_t *ct_fd_lock;
+ 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 */
+};
+
+/*
+ * 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.
+ *
+ * We keep track of a list of per-fd locks, protected by the clnt_fd_lock
+ * mutex. Each per-fd lock consists of a predicate indicating whether is
+ * active or not: fd_lock->active == TRUE => a call is active on some
+ * CLIENT handle created for that fd. Each fd predicate is guarded by a
+ * condition variable so that the global mutex can be unlocked while
+ * waiting for the predicate to change.
+ *
+ * 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 fd_locks_t *vc_fd_locks;
+extern pthread_mutex_t disrupt_lock;
+extern mutex_t clnt_fd_lock;
+#define release_fd_lock(fd_lock, mask) { \
+ mutex_lock(&clnt_fd_lock); \
+ fd_lock->active = FALSE; \
+ fd_lock->pending--; \
+ thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \
+ cond_signal(&fd_lock->cv); \
+ 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 __no_mem_str[] = "out of memory";
+
+/*
+ * 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)
+ 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 */
+{
+ CLIENT *cl; /* client handle */
+ struct ct_data *ct = NULL; /* client handle */
+ struct timeval now;
+ struct rpc_msg call_msg;
+ static u_int32_t disrupt;
+ sigset_t mask;
+ sigset_t newmask;
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ struct __rpc_sockinfo si;
+ fd_lock_t *fd_lock;
+
+ mutex_lock(&disrupt_lock);
+ if (disrupt == 0)
+ disrupt = (u_int32_t)(long)raddr;
+ mutex_unlock(&disrupt_lock);
+
+ cl = (CLIENT *)mem_alloc(sizeof (*cl));
+ ct = (struct ct_data *)mem_alloc(sizeof (*ct));
+ if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
+ struct rpc_createerr *ce = &get_rpc_createerr();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ (void) syslog(LOG_ERR, clnt_vc_errstr,
+ clnt_vc_str, __no_mem_str);
+ goto err;
+ }
+ ct->ct_addr.buf = NULL;
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ if (vc_fd_locks == (fd_locks_t *) NULL) {
+ vc_fd_locks = fd_locks_init();
+ if (vc_fd_locks == (fd_locks_t *) NULL) {
+ struct rpc_createerr *ce;
+ mutex_unlock(&clnt_fd_lock);
+ ce = &get_rpc_createerr();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ goto err;
+ }
+ }
+ fd_lock = fd_lock_create(fd, vc_fd_locks);
+ if (fd_lock == (fd_lock_t *) NULL) {
+ struct rpc_createerr *ce;
+ mutex_unlock(&clnt_fd_lock);
+ ce = &get_rpc_createerr();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ goto err;
+ }
+
+ /*
+ * Do not hold mutex during connect
+ */
+ mutex_unlock(&clnt_fd_lock);
+
+ slen = sizeof ss;
+ if (getpeername(fd, (struct sockaddr *)&ss, &slen) < 0) {
+ if (errno != ENOTCONN) {
+ struct rpc_createerr *ce = &get_rpc_createerr();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err;
+ }
+ if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
+ if (errno != EISCONN) {
+ struct rpc_createerr *ce = &get_rpc_createerr();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ goto err;
+ }
+ }
+ }
+ 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_fd_lock = fd_lock;
+ 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;
+
+ /*
+ * Initialize call message
+ */
+ (void)gettimeofday(&now, NULL);
+ mutex_lock(&disrupt_lock);
+ call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
+ mutex_unlock(&disrupt_lock);
+ 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)close(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);
+ 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));
+ }
+ mem_free(cl, sizeof (CLIENT));
+ } else if (ct) {
+ if (ct->ct_addr.len)
+ mem_free(ct->ct_addr.buf, ct->ct_addr.len);
+ mem_free(ct, sizeof (struct ct_data));
+ }
+ 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);
+ struct rpc_msg reply_msg;
+ u_int32_t x_id;
+ u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
+ bool_t shipnow;
+ int refreshes = 2;
+ sigset_t mask, newmask;
+
+ assert(cl != NULL);
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ ct->ct_fd_lock->pending++;
+ while (ct->ct_fd_lock->active)
+ cond_wait(&ct->ct_fd_lock->cv, &clnt_fd_lock);
+ ct->ct_fd_lock->active = TRUE;
+ mutex_unlock(&clnt_fd_lock);
+ 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;
+
+#ifdef HAVE_RPCSEC_GSS
+ if (is_authgss_client(cl))
+ refreshes = 0;
+#endif
+
+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)) ||
+ (! AUTH_WRAP(cl->cl_auth, xdrs, xdr_args, 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_lock, mask);
+ return (ct->ct_error.re_status);
+ }
+ if (! xdrrec_endofrecord(xdrs, shipnow)) {
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (ct->ct_error.re_status = RPC_CANTSEND);
+ }
+ if (! shipnow) {
+ release_fd_lock(ct->ct_fd_lock, 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_lock, mask);
+ return(ct->ct_error.re_status = RPC_TIMEDOUT);
+ }
+
+
+ /*
+ * Keep receiving until we get a valid transaction id
+ */
+ xdrs->x_op = XDR_DECODE;
+ while (TRUE) {
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ if (! xdrrec_skiprecord(xdrs)) {
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (ct->ct_error.re_status);
+ }
+ /* now decode and validate the response header */
+ if (! xdr_replymsg(xdrs, &reply_msg)) {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ continue;
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (ct->ct_error.re_status);
+ }
+ if (reply_msg.rm_xid == x_id)
+ break;
+ }
+
+ /*
+ * process header
+ */
+ _seterr_reply(&reply_msg, &(ct->ct_error));
+ if (ct->ct_error.re_status == RPC_SUCCESS) {
+ if (! AUTH_VALIDATE(cl->cl_auth,
+ &reply_msg.acpted_rply.ar_verf)) {
+ ct->ct_error.re_status = RPC_AUTHERROR;
+ ct->ct_error.re_why = AUTH_INVALIDRESP;
+ } else if (! AUTH_UNWRAP(cl->cl_auth, xdrs,
+ xdr_results, results_ptr)) {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTDECODERES;
+ }
+ /* free verifier ... */
+ 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 */
+ else {
+ /* maybe our credentials need to be refreshed ... */
+ if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
+ goto call_again;
+ } /* end of unsuccessful completion */
+ release_fd_lock(ct->ct_fd_lock, 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;
+ sigset_t mask;
+ sigset_t newmask;
+
+ assert(cl != NULL);
+
+ ct = (struct ct_data *)cl->cl_private;
+ xdrs = &(ct->ct_xdrs);
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ ct->ct_fd_lock->pending++;
+ while (ct->ct_fd_lock->active)
+ cond_wait(&ct->ct_fd_lock->cv, &clnt_fd_lock);
+ xdrs->x_op = XDR_FREE;
+ dummy = (*xdr_res)(xdrs, res_ptr);
+ ct->ct_fd_lock->pending--;
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+ cond_signal(&ct->ct_fd_lock->cv);
+ mutex_unlock(&clnt_fd_lock);
+
+ 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;
+ sigset_t mask;
+ sigset_t newmask;
+ u_int32_t tmp;
+ u_int32_t ltmp;
+
+ assert(cl != NULL);
+
+ ct = (struct ct_data *)cl->cl_private;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ ct->ct_fd_lock->pending++;
+ while (ct->ct_fd_lock->active)
+ cond_wait(&ct->ct_fd_lock->cv, &clnt_fd_lock);
+ ct->ct_fd_lock->active = TRUE;
+ mutex_unlock(&clnt_fd_lock);
+
+ switch (request) {
+ case CLSET_FD_CLOSE:
+ ct->ct_closeit = TRUE;
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (TRUE);
+ case CLSET_FD_NCLOSE:
+ ct->ct_closeit = FALSE;
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (TRUE);
+ default:
+ break;
+ }
+
+ /* for other requests which use info */
+ if (info == NULL) {
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (FALSE);
+ }
+ switch (request) {
+ case CLSET_TIMEOUT:
+ if (time_not_ok((struct timeval *)info)) {
+ release_fd_lock(ct->ct_fd_lock, 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_lock, 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
+ */
+ memcpy(&tmp, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, sizeof (tmp));
+ ltmp = ntohl(tmp);
+ memcpy(info, &ltmp, sizeof (ltmp));
+ break;
+
+ case CLSET_VERS:
+ memcpy(&ltmp, info, sizeof (ltmp));
+ tmp = htonl(ltmp);
+ memcpy(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, &tmp, sizeof(tmp));
+ 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
+ */
+ memcpy(&tmp, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, sizeof (tmp));
+ ltmp = ntohl (tmp);
+ memcpy(info, &ltmp, sizeof (ltmp));
+ break;
+
+ case CLSET_PROG:
+ memcpy(&ltmp, info, sizeof (ltmp));
+ tmp = htonl(ltmp);
+ memcpy(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, &tmp, sizeof(tmp));
+ break;
+
+ default:
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (FALSE);
+ }
+ release_fd_lock(ct->ct_fd_lock, mask);
+ return (TRUE);
+}
+
+
+static void
+clnt_vc_destroy(cl)
+ CLIENT *cl;
+{
+ assert(cl != NULL);
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+ int ct_fd = ct->ct_fd;
+ fd_lock_t *ct_fd_lock = ct->ct_fd_lock;
+ sigset_t mask;
+ sigset_t newmask;
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ mutex_lock(&clnt_fd_lock);
+ /* wait until all pending operations on client are completed. */
+ while (ct_fd_lock->pending > 0) {
+ /* If a blocked operation can be awakened, then do it. */
+ if (ct_fd_lock->active == FALSE)
+ cond_signal(&ct_fd_lock->cv);
+ /* keep waiting... */
+ cond_wait(&ct_fd_lock->cv, &clnt_fd_lock);
+ }
+ if (ct->ct_closeit && ct->ct_fd != -1) {
+ (void)close(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);
+ mem_free(cl, sizeof(CLIENT));
+ cond_signal(&ct_fd_lock->cv);
+ fd_lock_destroy(ct_fd, ct_fd_lock, vc_fd_locks);
+ mutex_unlock(&clnt_fd_lock);
+ thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
+}
+
+/*
+ * 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 -1:
+ if (errno == EINTR)
+ continue;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ ct->ct_error.re_errno = errno;
+ return (-1);
+ }
+ break;
+ }
+
+ len = read(ct->ct_fd, buf, (size_t)len);
+
+ switch (len) {
+ case 0:
+ /* premature eof */
+ ct->ct_error.re_errno = ECONNRESET;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ len = -1; /* it's really an error */
+ break;
+
+ case -1:
+ 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;
+ void *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 = write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
+ ct->ct_error.re_errno = errno;
+ 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;
+ sigset_t mask, newmask;
+
+ /* VARIABLES PROTECTED BY ops_lock: ops */
+
+ sigfillset(&newmask);
+ thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
+ 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/src/crypt_client.c b/src/crypt_client.c
new file mode 100644
index 0000000..cd6f7de
--- /dev/null
+++ b/src/crypt_client.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 <err.h>
+#include <sys/types.h>
+#include <rpc/des_crypt.h>
+#include <rpc/des.h>
+#include <string.h>
+#include <rpcsvc/crypt.h>
+
+#include <netconfig.h>
+
+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;
+ memcpy(des_crypt_1_arg.des_ivec, dparms->des_ivec, 8);
+ memcpy(des_crypt_1_arg.des_key, dparms->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) {
+ memcpy(buf, result_1->desbuf.desbuf_val, len);
+ memcpy(dparms->des_ivec, result_1->des_ivec, 8);
+ }
+
+ clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1);
+ clnt_destroy(clnt);
+
+ return(stat);
+}
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..332831c
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,73 @@
+/*
+ * debug.c -- debugging routines for libtirpc
+ *
+ * Copyright (C) 2014 Red Hat, Steve Dickson <steved@redhat.com>
+ *
+ * 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 <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+
+#include "debug.h"
+
+/* library global debug level */
+int libtirpc_debug_level = 0;
+int log_stderr = 1; /* log to stderr instead of systlog */
+
+/*
+ * Set the debug level for the entire library.
+ * Different area will used the value to determin
+ * the verbosity of the debugging output.
+ */
+void
+libtirpc_set_debug(char *name, int level, int use_stderr)
+{
+ if (level < 0)
+ level = 0;
+
+ log_stderr = use_stderr;
+ if (!use_stderr)
+ openlog(name, LOG_PID, LOG_DAEMON);
+
+ libtirpc_debug_level = level;
+ LIBTIRPC_DEBUG(1, ("libtirpc: debug level %d", libtirpc_debug_level));
+}
+
+void
+libtirpc_log_dbg(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (log_stderr) {
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ } else
+ vsyslog(LOG_NOTICE, fmt, args);
+ va_end(args);
+}
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..0c98ba4
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,59 @@
+/*
+ * debug.h -- debugging routines for libtirpc
+ *
+ * Copyright (C) 2014 Red Hat, Steve Dickson <steved@redhat.com>
+ *
+ * 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.
+ */
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#include <stdarg.h>
+#include <syslog.h>
+
+extern int libtirpc_debug_level;
+extern int log_stderr;
+
+void libtirpc_log_dbg(char *format, ...);
+void libtirpc_set_debug(char *name, int level, int use_stderr);
+
+#define LIBTIRPC_DEBUG(level, msg) \
+ do { \
+ if (level <= libtirpc_debug_level) \
+ libtirpc_log_dbg msg; \
+ } while (0)
+
+static inline void
+vlibtirpc_log_dbg(int level, const char *fmt, va_list args)
+{
+ if (level <= libtirpc_debug_level) {
+ if (log_stderr) {
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ } else
+ vsyslog(LOG_NOTICE, fmt, args);
+ }
+}
+#endif /* _DEBUG_H */
diff --git a/src/des_crypt.c b/src/des_crypt.c
new file mode 100644
index 0000000..1d1badd
--- /dev/null
+++ b/src/des_crypt.c
@@ -0,0 +1,146 @@
+/*
+ * 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 <sys/types.h>
+#include <rpc/types.h>
+#include <rpc/des_crypt.h>
+#include <rpc/des.h>
+#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
+
+static int common_crypt( char *, char *, unsigned, unsigned, 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(buf, len, desp)) {
+ return (DESERR_HWERROR);
+ }
+
+ return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE);
+}
diff --git a/src/des_impl.c b/src/des_impl.c
new file mode 100644
index 0000000..15bec2a
--- /dev/null
+++ b/src/des_impl.c
@@ -0,0 +1,594 @@
+/* Copyright (C) 1992 Eric Young */
+/* Collected from libdes and modified for SECURE RPC by Martin Kuck 1994 */
+/* This file is distributed under the terms of the GNU Lesser General */
+/* Public License, version 2.1 or later - see the file COPYING.LIB for details.*/
+/* If you did not receive a copy of the license with this program, please*/
+/* see <http://www.gnu.org/licenses/> to obtain a copy. */
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <rpc/des.h>
+
+
+static const uint32_t des_SPtrans[8][64] =
+{
+ { /* nibble 0 */
+ 0x00820200, 0x00020000, 0x80800000, 0x80820200,
+ 0x00800000, 0x80020200, 0x80020000, 0x80800000,
+ 0x80020200, 0x00820200, 0x00820000, 0x80000200,
+ 0x80800200, 0x00800000, 0x00000000, 0x80020000,
+ 0x00020000, 0x80000000, 0x00800200, 0x00020200,
+ 0x80820200, 0x00820000, 0x80000200, 0x00800200,
+ 0x80000000, 0x00000200, 0x00020200, 0x80820000,
+ 0x00000200, 0x80800200, 0x80820000, 0x00000000,
+ 0x00000000, 0x80820200, 0x00800200, 0x80020000,
+ 0x00820200, 0x00020000, 0x80000200, 0x00800200,
+ 0x80820000, 0x00000200, 0x00020200, 0x80800000,
+ 0x80020200, 0x80000000, 0x80800000, 0x00820000,
+ 0x80820200, 0x00020200, 0x00820000, 0x80800200,
+ 0x00800000, 0x80000200, 0x80020000, 0x00000000,
+ 0x00020000, 0x00800000, 0x80800200, 0x00820200,
+ 0x80000000, 0x80820000, 0x00000200, 0x80020200},
+
+ { /* nibble 1 */
+ 0x10042004, 0x00000000, 0x00042000, 0x10040000,
+ 0x10000004, 0x00002004, 0x10002000, 0x00042000,
+ 0x00002000, 0x10040004, 0x00000004, 0x10002000,
+ 0x00040004, 0x10042000, 0x10040000, 0x00000004,
+ 0x00040000, 0x10002004, 0x10040004, 0x00002000,
+ 0x00042004, 0x10000000, 0x00000000, 0x00040004,
+ 0x10002004, 0x00042004, 0x10042000, 0x10000004,
+ 0x10000000, 0x00040000, 0x00002004, 0x10042004,
+ 0x00040004, 0x10042000, 0x10002000, 0x00042004,
+ 0x10042004, 0x00040004, 0x10000004, 0x00000000,
+ 0x10000000, 0x00002004, 0x00040000, 0x10040004,
+ 0x00002000, 0x10000000, 0x00042004, 0x10002004,
+ 0x10042000, 0x00002000, 0x00000000, 0x10000004,
+ 0x00000004, 0x10042004, 0x00042000, 0x10040000,
+ 0x10040004, 0x00040000, 0x00002004, 0x10002000,
+ 0x10002004, 0x00000004, 0x10040000, 0x00042000},
+
+ { /* nibble 2 */
+ 0x41000000, 0x01010040, 0x00000040, 0x41000040,
+ 0x40010000, 0x01000000, 0x41000040, 0x00010040,
+ 0x01000040, 0x00010000, 0x01010000, 0x40000000,
+ 0x41010040, 0x40000040, 0x40000000, 0x41010000,
+ 0x00000000, 0x40010000, 0x01010040, 0x00000040,
+ 0x40000040, 0x41010040, 0x00010000, 0x41000000,
+ 0x41010000, 0x01000040, 0x40010040, 0x01010000,
+ 0x00010040, 0x00000000, 0x01000000, 0x40010040,
+ 0x01010040, 0x00000040, 0x40000000, 0x00010000,
+ 0x40000040, 0x40010000, 0x01010000, 0x41000040,
+ 0x00000000, 0x01010040, 0x00010040, 0x41010000,
+ 0x40010000, 0x01000000, 0x41010040, 0x40000000,
+ 0x40010040, 0x41000000, 0x01000000, 0x41010040,
+ 0x00010000, 0x01000040, 0x41000040, 0x00010040,
+ 0x01000040, 0x00000000, 0x41010000, 0x40000040,
+ 0x41000000, 0x40010040, 0x00000040, 0x01010000},
+
+ { /* nibble 3 */
+ 0x00100402, 0x04000400, 0x00000002, 0x04100402,
+ 0x00000000, 0x04100000, 0x04000402, 0x00100002,
+ 0x04100400, 0x04000002, 0x04000000, 0x00000402,
+ 0x04000002, 0x00100402, 0x00100000, 0x04000000,
+ 0x04100002, 0x00100400, 0x00000400, 0x00000002,
+ 0x00100400, 0x04000402, 0x04100000, 0x00000400,
+ 0x00000402, 0x00000000, 0x00100002, 0x04100400,
+ 0x04000400, 0x04100002, 0x04100402, 0x00100000,
+ 0x04100002, 0x00000402, 0x00100000, 0x04000002,
+ 0x00100400, 0x04000400, 0x00000002, 0x04100000,
+ 0x04000402, 0x00000000, 0x00000400, 0x00100002,
+ 0x00000000, 0x04100002, 0x04100400, 0x00000400,
+ 0x04000000, 0x04100402, 0x00100402, 0x00100000,
+ 0x04100402, 0x00000002, 0x04000400, 0x00100402,
+ 0x00100002, 0x00100400, 0x04100000, 0x04000402,
+ 0x00000402, 0x04000000, 0x04000002, 0x04100400},
+
+ { /* nibble 4 */
+ 0x02000000, 0x00004000, 0x00000100, 0x02004108,
+ 0x02004008, 0x02000100, 0x00004108, 0x02004000,
+ 0x00004000, 0x00000008, 0x02000008, 0x00004100,
+ 0x02000108, 0x02004008, 0x02004100, 0x00000000,
+ 0x00004100, 0x02000000, 0x00004008, 0x00000108,
+ 0x02000100, 0x00004108, 0x00000000, 0x02000008,
+ 0x00000008, 0x02000108, 0x02004108, 0x00004008,
+ 0x02004000, 0x00000100, 0x00000108, 0x02004100,
+ 0x02004100, 0x02000108, 0x00004008, 0x02004000,
+ 0x00004000, 0x00000008, 0x02000008, 0x02000100,
+ 0x02000000, 0x00004100, 0x02004108, 0x00000000,
+ 0x00004108, 0x02000000, 0x00000100, 0x00004008,
+ 0x02000108, 0x00000100, 0x00000000, 0x02004108,
+ 0x02004008, 0x02004100, 0x00000108, 0x00004000,
+ 0x00004100, 0x02004008, 0x02000100, 0x00000108,
+ 0x00000008, 0x00004108, 0x02004000, 0x02000008},
+
+ { /* nibble 5 */
+ 0x20000010, 0x00080010, 0x00000000, 0x20080800,
+ 0x00080010, 0x00000800, 0x20000810, 0x00080000,
+ 0x00000810, 0x20080810, 0x00080800, 0x20000000,
+ 0x20000800, 0x20000010, 0x20080000, 0x00080810,
+ 0x00080000, 0x20000810, 0x20080010, 0x00000000,
+ 0x00000800, 0x00000010, 0x20080800, 0x20080010,
+ 0x20080810, 0x20080000, 0x20000000, 0x00000810,
+ 0x00000010, 0x00080800, 0x00080810, 0x20000800,
+ 0x00000810, 0x20000000, 0x20000800, 0x00080810,
+ 0x20080800, 0x00080010, 0x00000000, 0x20000800,
+ 0x20000000, 0x00000800, 0x20080010, 0x00080000,
+ 0x00080010, 0x20080810, 0x00080800, 0x00000010,
+ 0x20080810, 0x00080800, 0x00080000, 0x20000810,
+ 0x20000010, 0x20080000, 0x00080810, 0x00000000,
+ 0x00000800, 0x20000010, 0x20000810, 0x20080800,
+ 0x20080000, 0x00000810, 0x00000010, 0x20080010},
+
+ { /* nibble 6 */
+ 0x00001000, 0x00000080, 0x00400080, 0x00400001,
+ 0x00401081, 0x00001001, 0x00001080, 0x00000000,
+ 0x00400000, 0x00400081, 0x00000081, 0x00401000,
+ 0x00000001, 0x00401080, 0x00401000, 0x00000081,
+ 0x00400081, 0x00001000, 0x00001001, 0x00401081,
+ 0x00000000, 0x00400080, 0x00400001, 0x00001080,
+ 0x00401001, 0x00001081, 0x00401080, 0x00000001,
+ 0x00001081, 0x00401001, 0x00000080, 0x00400000,
+ 0x00001081, 0x00401000, 0x00401001, 0x00000081,
+ 0x00001000, 0x00000080, 0x00400000, 0x00401001,
+ 0x00400081, 0x00001081, 0x00001080, 0x00000000,
+ 0x00000080, 0x00400001, 0x00000001, 0x00400080,
+ 0x00000000, 0x00400081, 0x00400080, 0x00001080,
+ 0x00000081, 0x00001000, 0x00401081, 0x00400000,
+ 0x00401080, 0x00000001, 0x00001001, 0x00401081,
+ 0x00400001, 0x00401080, 0x00401000, 0x00001001},
+
+ { /* nibble 7 */
+ 0x08200020, 0x08208000, 0x00008020, 0x00000000,
+ 0x08008000, 0x00200020, 0x08200000, 0x08208020,
+ 0x00000020, 0x08000000, 0x00208000, 0x00008020,
+ 0x00208020, 0x08008020, 0x08000020, 0x08200000,
+ 0x00008000, 0x00208020, 0x00200020, 0x08008000,
+ 0x08208020, 0x08000020, 0x00000000, 0x00208000,
+ 0x08000000, 0x00200000, 0x08008020, 0x08200020,
+ 0x00200000, 0x00008000, 0x08208000, 0x00000020,
+ 0x00200000, 0x00008000, 0x08000020, 0x08208020,
+ 0x00008020, 0x08000000, 0x00000000, 0x00208000,
+ 0x08200020, 0x08008020, 0x08008000, 0x00200020,
+ 0x08208000, 0x00000020, 0x00200020, 0x08008000,
+ 0x08208020, 0x00200000, 0x08200000, 0x08000020,
+ 0x00208000, 0x00008020, 0x08008020, 0x08200000,
+ 0x00000020, 0x08208000, 0x00208020, 0x00000000,
+ 0x08000000, 0x08200020, 0x00008000, 0x00208020}};
+
+static const uint32_t des_skb[8][64] =
+{
+ { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+ 0x00000000, 0x00000010, 0x20000000, 0x20000010,
+ 0x00010000, 0x00010010, 0x20010000, 0x20010010,
+ 0x00000800, 0x00000810, 0x20000800, 0x20000810,
+ 0x00010800, 0x00010810, 0x20010800, 0x20010810,
+ 0x00000020, 0x00000030, 0x20000020, 0x20000030,
+ 0x00010020, 0x00010030, 0x20010020, 0x20010030,
+ 0x00000820, 0x00000830, 0x20000820, 0x20000830,
+ 0x00010820, 0x00010830, 0x20010820, 0x20010830,
+ 0x00080000, 0x00080010, 0x20080000, 0x20080010,
+ 0x00090000, 0x00090010, 0x20090000, 0x20090010,
+ 0x00080800, 0x00080810, 0x20080800, 0x20080810,
+ 0x00090800, 0x00090810, 0x20090800, 0x20090810,
+ 0x00080020, 0x00080030, 0x20080020, 0x20080030,
+ 0x00090020, 0x00090030, 0x20090020, 0x20090030,
+ 0x00080820, 0x00080830, 0x20080820, 0x20080830,
+ 0x00090820, 0x00090830, 0x20090820, 0x20090830},
+ { /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+ 0x00000000, 0x02000000, 0x00002000, 0x02002000,
+ 0x00200000, 0x02200000, 0x00202000, 0x02202000,
+ 0x00000004, 0x02000004, 0x00002004, 0x02002004,
+ 0x00200004, 0x02200004, 0x00202004, 0x02202004,
+ 0x00000400, 0x02000400, 0x00002400, 0x02002400,
+ 0x00200400, 0x02200400, 0x00202400, 0x02202400,
+ 0x00000404, 0x02000404, 0x00002404, 0x02002404,
+ 0x00200404, 0x02200404, 0x00202404, 0x02202404,
+ 0x10000000, 0x12000000, 0x10002000, 0x12002000,
+ 0x10200000, 0x12200000, 0x10202000, 0x12202000,
+ 0x10000004, 0x12000004, 0x10002004, 0x12002004,
+ 0x10200004, 0x12200004, 0x10202004, 0x12202004,
+ 0x10000400, 0x12000400, 0x10002400, 0x12002400,
+ 0x10200400, 0x12200400, 0x10202400, 0x12202400,
+ 0x10000404, 0x12000404, 0x10002404, 0x12002404,
+ 0x10200404, 0x12200404, 0x10202404, 0x12202404},
+ { /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+ 0x00000000, 0x00000001, 0x00040000, 0x00040001,
+ 0x01000000, 0x01000001, 0x01040000, 0x01040001,
+ 0x00000002, 0x00000003, 0x00040002, 0x00040003,
+ 0x01000002, 0x01000003, 0x01040002, 0x01040003,
+ 0x00000200, 0x00000201, 0x00040200, 0x00040201,
+ 0x01000200, 0x01000201, 0x01040200, 0x01040201,
+ 0x00000202, 0x00000203, 0x00040202, 0x00040203,
+ 0x01000202, 0x01000203, 0x01040202, 0x01040203,
+ 0x08000000, 0x08000001, 0x08040000, 0x08040001,
+ 0x09000000, 0x09000001, 0x09040000, 0x09040001,
+ 0x08000002, 0x08000003, 0x08040002, 0x08040003,
+ 0x09000002, 0x09000003, 0x09040002, 0x09040003,
+ 0x08000200, 0x08000201, 0x08040200, 0x08040201,
+ 0x09000200, 0x09000201, 0x09040200, 0x09040201,
+ 0x08000202, 0x08000203, 0x08040202, 0x08040203,
+ 0x09000202, 0x09000203, 0x09040202, 0x09040203},
+ { /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+ 0x00000000, 0x00100000, 0x00000100, 0x00100100,
+ 0x00000008, 0x00100008, 0x00000108, 0x00100108,
+ 0x00001000, 0x00101000, 0x00001100, 0x00101100,
+ 0x00001008, 0x00101008, 0x00001108, 0x00101108,
+ 0x04000000, 0x04100000, 0x04000100, 0x04100100,
+ 0x04000008, 0x04100008, 0x04000108, 0x04100108,
+ 0x04001000, 0x04101000, 0x04001100, 0x04101100,
+ 0x04001008, 0x04101008, 0x04001108, 0x04101108,
+ 0x00020000, 0x00120000, 0x00020100, 0x00120100,
+ 0x00020008, 0x00120008, 0x00020108, 0x00120108,
+ 0x00021000, 0x00121000, 0x00021100, 0x00121100,
+ 0x00021008, 0x00121008, 0x00021108, 0x00121108,
+ 0x04020000, 0x04120000, 0x04020100, 0x04120100,
+ 0x04020008, 0x04120008, 0x04020108, 0x04120108,
+ 0x04021000, 0x04121000, 0x04021100, 0x04121100,
+ 0x04021008, 0x04121008, 0x04021108, 0x04121108},
+ { /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+ 0x00000000, 0x10000000, 0x00010000, 0x10010000,
+ 0x00000004, 0x10000004, 0x00010004, 0x10010004,
+ 0x20000000, 0x30000000, 0x20010000, 0x30010000,
+ 0x20000004, 0x30000004, 0x20010004, 0x30010004,
+ 0x00100000, 0x10100000, 0x00110000, 0x10110000,
+ 0x00100004, 0x10100004, 0x00110004, 0x10110004,
+ 0x20100000, 0x30100000, 0x20110000, 0x30110000,
+ 0x20100004, 0x30100004, 0x20110004, 0x30110004,
+ 0x00001000, 0x10001000, 0x00011000, 0x10011000,
+ 0x00001004, 0x10001004, 0x00011004, 0x10011004,
+ 0x20001000, 0x30001000, 0x20011000, 0x30011000,
+ 0x20001004, 0x30001004, 0x20011004, 0x30011004,
+ 0x00101000, 0x10101000, 0x00111000, 0x10111000,
+ 0x00101004, 0x10101004, 0x00111004, 0x10111004,
+ 0x20101000, 0x30101000, 0x20111000, 0x30111000,
+ 0x20101004, 0x30101004, 0x20111004, 0x30111004},
+ { /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+ 0x00000000, 0x08000000, 0x00000008, 0x08000008,
+ 0x00000400, 0x08000400, 0x00000408, 0x08000408,
+ 0x00020000, 0x08020000, 0x00020008, 0x08020008,
+ 0x00020400, 0x08020400, 0x00020408, 0x08020408,
+ 0x00000001, 0x08000001, 0x00000009, 0x08000009,
+ 0x00000401, 0x08000401, 0x00000409, 0x08000409,
+ 0x00020001, 0x08020001, 0x00020009, 0x08020009,
+ 0x00020401, 0x08020401, 0x00020409, 0x08020409,
+ 0x02000000, 0x0A000000, 0x02000008, 0x0A000008,
+ 0x02000400, 0x0A000400, 0x02000408, 0x0A000408,
+ 0x02020000, 0x0A020000, 0x02020008, 0x0A020008,
+ 0x02020400, 0x0A020400, 0x02020408, 0x0A020408,
+ 0x02000001, 0x0A000001, 0x02000009, 0x0A000009,
+ 0x02000401, 0x0A000401, 0x02000409, 0x0A000409,
+ 0x02020001, 0x0A020001, 0x02020009, 0x0A020009,
+ 0x02020401, 0x0A020401, 0x02020409, 0x0A020409},
+ { /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+ 0x00000000, 0x00000100, 0x00080000, 0x00080100,
+ 0x01000000, 0x01000100, 0x01080000, 0x01080100,
+ 0x00000010, 0x00000110, 0x00080010, 0x00080110,
+ 0x01000010, 0x01000110, 0x01080010, 0x01080110,
+ 0x00200000, 0x00200100, 0x00280000, 0x00280100,
+ 0x01200000, 0x01200100, 0x01280000, 0x01280100,
+ 0x00200010, 0x00200110, 0x00280010, 0x00280110,
+ 0x01200010, 0x01200110, 0x01280010, 0x01280110,
+ 0x00000200, 0x00000300, 0x00080200, 0x00080300,
+ 0x01000200, 0x01000300, 0x01080200, 0x01080300,
+ 0x00000210, 0x00000310, 0x00080210, 0x00080310,
+ 0x01000210, 0x01000310, 0x01080210, 0x01080310,
+ 0x00200200, 0x00200300, 0x00280200, 0x00280300,
+ 0x01200200, 0x01200300, 0x01280200, 0x01280300,
+ 0x00200210, 0x00200310, 0x00280210, 0x00280310,
+ 0x01200210, 0x01200310, 0x01280210, 0x01280310},
+ { /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+ 0x00000000, 0x04000000, 0x00040000, 0x04040000,
+ 0x00000002, 0x04000002, 0x00040002, 0x04040002,
+ 0x00002000, 0x04002000, 0x00042000, 0x04042000,
+ 0x00002002, 0x04002002, 0x00042002, 0x04042002,
+ 0x00000020, 0x04000020, 0x00040020, 0x04040020,
+ 0x00000022, 0x04000022, 0x00040022, 0x04040022,
+ 0x00002020, 0x04002020, 0x00042020, 0x04042020,
+ 0x00002022, 0x04002022, 0x00042022, 0x04042022,
+ 0x00000800, 0x04000800, 0x00040800, 0x04040800,
+ 0x00000802, 0x04000802, 0x00040802, 0x04040802,
+ 0x00002800, 0x04002800, 0x00042800, 0x04042800,
+ 0x00002802, 0x04002802, 0x00042802, 0x04042802,
+ 0x00000820, 0x04000820, 0x00040820, 0x04040820,
+ 0x00000822, 0x04000822, 0x00040822, 0x04040822,
+ 0x00002820, 0x04002820, 0x00042820, 0x04042820,
+ 0x00002822, 0x04002822, 0x00042822, 0x04042822},
+};
+
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+ l|=((unsigned long)(*((c)++)))<< 8, \
+ l|=((unsigned long)(*((c)++)))<<16, \
+ l|=((unsigned long)(*((c)++)))<<24)
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+/*
+ * IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ * 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ * 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+ * 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+ * 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+ *
+ * 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+ * 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+ * 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+ * 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+ *
+ * The output has been subject to swaps of the form
+ * 0 1 -> 3 1 but the odd and even bits have been put into
+ * 2 3 2 0
+ * different words. The main trick is to remember that
+ * t=((l>>size)^r)&(mask);
+ * r^=t;
+ * l^=(t<<size);
+ * can be used to swap and move bits between words.
+ *
+ * So l = 0 1 2 3 r = 16 17 18 19
+ * 4 5 6 7 20 21 22 23
+ * 8 9 10 11 24 25 26 27
+ * 12 13 14 15 28 29 30 31
+ * becomes (for size == 2 and mask == 0x3333)
+ * t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ * 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ * 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ * 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+ *
+ * Thanks for hints from Richard Outerbridge - he told me IP&FP
+ * could be done in 15 xor, 10 shifts and 5 ands.
+ * When I finally started to think of the problem in 2D
+ * I first got ~42 operations without xors. When I remembered
+ * how to use xors I got it to its final state.
+ */
+
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))
+
+
+#define D_ENCRYPT(L,R,S) \
+ u=(R^s[S ]); \
+ t=R^s[S+1]; \
+ t=((t>>4)+(t<<28)); \
+ L^= des_SPtrans[1][(t )&0x3f]| \
+ des_SPtrans[3][(t>> 8)&0x3f]| \
+ des_SPtrans[5][(t>>16)&0x3f]| \
+ des_SPtrans[7][(t>>24)&0x3f]| \
+ des_SPtrans[0][(u )&0x3f]| \
+ des_SPtrans[2][(u>> 8)&0x3f]| \
+ des_SPtrans[4][(u>>16)&0x3f]| \
+ des_SPtrans[6][(u>>24)&0x3f];
+
+#define ITERATIONS 16
+
+static const char shifts2[16] =
+{0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0};
+
+static void des_set_key (unsigned char *, unsigned long *);
+static void des_encrypt (unsigned long *, unsigned long *, int);
+int _des_crypt (char *, unsigned, struct desparams *);
+
+static void
+des_set_key (unsigned char *key, unsigned long *schedule)
+{
+ register unsigned long c, d, t, s;
+ register unsigned char *in;
+ register unsigned long *k;
+ register int i;
+
+ k = (unsigned long *) schedule;
+ in = key;
+
+ c2l (in, c);
+ c2l (in, d);
+
+ /* I now do it in 47 simple operations
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. */
+ PERM_OP (d, c, t, 4, 0x0f0f0f0f);
+ HPERM_OP (c, t, -2, 0xcccc0000);
+ HPERM_OP (d, t, -2, 0xcccc0000);
+ PERM_OP (d, c, t, 1, 0x55555555);
+ PERM_OP (c, d, t, 8, 0x00ff00ff);
+ PERM_OP (d, c, t, 1, 0x55555555);
+ d = (((d & 0x000000ff) << 16) | (d & 0x0000ff00) |
+ ((d & 0x00ff0000) >> 16) | ((c & 0xf0000000) >> 4));
+ c &= 0x0fffffff;
+
+ for (i = 0; i < ITERATIONS; i++)
+ {
+ if (shifts2[i])
+ {
+ c = ((c >> 2) | (c << 26));
+ d = ((d >> 2) | (d << 26));
+ }
+ else
+ {
+ c = ((c >> 1) | (c << 27));
+ d = ((d >> 1) | (d << 27));
+ }
+ c &= 0x0fffffff;
+ d &= 0x0fffffff;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s = des_skb[0][(c) & 0x3f] |
+ des_skb[1][((c >> 6) & 0x03) | ((c >> 7) & 0x3c)] |
+ des_skb[2][((c >> 13) & 0x0f) | ((c >> 14) & 0x30)] |
+ des_skb[3][((c >> 20) & 0x01) | ((c >> 21) & 0x06) | ((c >> 22) & 0x38)];
+ t = des_skb[4][(d) & 0x3f] |
+ des_skb[5][((d >> 7) & 0x03) | ((d >> 8) & 0x3c)] |
+ des_skb[6][(d >> 15) & 0x3f] |
+ des_skb[7][((d >> 21) & 0x0f) | ((d >> 22) & 0x30)];
+
+ /* table contained 0213 4657 */
+ *(k++) = ((t << 16) | (s & 0x0000ffff)) & 0xffffffff;
+ s = ((s >> 16) | (t & 0xffff0000));
+
+ s = (s << 4) | (s >> 28);
+ *(k++) = s & 0xffffffff;
+ }
+}
+
+
+static void
+des_encrypt (unsigned long *buf, unsigned long *schedule, int encrypt)
+{
+ register unsigned long l, r, t, u;
+ register int i;
+ register unsigned long *s;
+
+ l = buf[0];
+ r = buf[1];
+
+ /* do IP */
+ PERM_OP (r, l, t, 4, 0x0f0f0f0f);
+ PERM_OP (l, r, t, 16, 0x0000ffff);
+ PERM_OP (r, l, t, 2, 0x33333333);
+ PERM_OP (l, r, t, 8, 0x00ff00ff);
+ PERM_OP (r, l, t, 1, 0x55555555);
+ /* r and l are reversed - remember that - fix
+ * it in the next step */
+
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ t = (r << 1) | (r >> 31);
+ r = (l << 1) | (l >> 31);
+ l = t;
+
+ /* clear the top bits on machines with 8byte longs */
+ l &= 0xffffffff;
+ r &= 0xffffffff;
+
+ s = (unsigned long *) schedule;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (encrypt)
+ {
+ for (i = 0; i < 32; i += 4)
+ {
+ D_ENCRYPT (l, r, i + 0); /* 1 */
+ D_ENCRYPT (r, l, i + 2); /* 2 */
+ }
+ }
+ else
+ {
+ for (i = 30; i > 0; i -= 4)
+ {
+ D_ENCRYPT (l, r, i - 0); /* 16 */
+ D_ENCRYPT (r, l, i - 2); /* 15 */
+ }
+ }
+ l = (l >> 1) | (l << 31);
+ r = (r >> 1) | (r << 31);
+ /* clear the top bits on machines with 8byte longs */
+ l &= 0xffffffff;
+ r &= 0xffffffff;
+
+ /* swap l and r
+ * we will not do the swap so just remember they are
+ * reversed for the rest of the subroutine
+ * luckily FP fixes this problem */
+
+ PERM_OP (r, l, t, 1, 0x55555555);
+ PERM_OP (l, r, t, 8, 0x00ff00ff);
+ PERM_OP (r, l, t, 2, 0x33333333);
+ PERM_OP (l, r, t, 16, 0x0000ffff);
+ PERM_OP (r, l, t, 4, 0x0f0f0f0f);
+
+ buf[0] = l;
+ buf[1] = r;
+
+ l = r = t = u = 0;
+}
+
+
+int
+_des_crypt (char *buf, unsigned len, struct desparams *desp)
+{
+ unsigned long schedule[32];
+ register unsigned long tin0, tin1;
+ register unsigned long tout0, tout1, xor0, xor1;
+ register unsigned char *in, *out;
+ unsigned long tbuf[2];
+ unsigned char *iv, *oiv;
+ int cbc_mode;
+
+ cbc_mode = (desp->des_mode == CBC) ? 1 : 0;
+
+ in = (unsigned char *) buf;
+ out = (unsigned char *) buf;
+ oiv = iv = (unsigned char *) desp->des_ivec;
+
+ des_set_key (desp->des_key, schedule);
+
+ tin0 = tin1 = 0; /* For GCC */
+ if (desp->des_dir == ENCRYPT)
+ {
+ c2l (iv, tout0);
+ c2l (iv, tout1);
+ for (; len > 0; len -= 8)
+ {
+ c2l (in, tin0);
+ c2l (in, tin1);
+ if (cbc_mode)
+ {
+ tin0 ^= tout0;
+ tin1 ^= tout1;
+ }
+ tbuf[0] = tin0;
+ tbuf[1] = tin1;
+ des_encrypt (tbuf, schedule, 1);
+ tout0 = tbuf[0];
+ tout1 = tbuf[1];
+ l2c (tout0, out);
+ l2c (tout1, out);
+ }
+ l2c (tout0, oiv);
+ l2c (tout1, oiv);
+ }
+ else
+ {
+ c2l (iv, xor0);
+ c2l (iv, xor1);
+ for (; len > 0; len -= 8)
+ {
+ c2l (in, tin0);
+ c2l (in, tin1);
+ tbuf[0] = tin0;
+ tbuf[1] = tin1;
+ des_encrypt (tbuf, schedule, 0);
+ if (cbc_mode)
+ {
+ tout0 = tbuf[0] ^ xor0;
+ tout1 = tbuf[1] ^ xor1;
+ xor0 = tin0;
+ xor1 = tin1;
+ }
+ else
+ {
+ tout0 = tbuf[0];
+ tout1 = tbuf[1];
+ }
+ l2c (tout0, out);
+ l2c (tout1, out);
+ }
+ l2c (tin0, oiv);
+ l2c (tin1, oiv);
+ }
+ tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
+ tbuf[0] = tbuf[1] = 0;
+ memset (schedule, 0, sizeof (schedule));
+
+ return (1);
+}
diff --git a/src/des_soft.c b/src/des_soft.c
new file mode 100644
index 0000000..e6fdf20
--- /dev/null
+++ b/src/des_soft.c
@@ -0,0 +1,65 @@
+//#include <sys/cdefs.h>
+
+/*
+ * 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/src/epoll_sub.c b/src/epoll_sub.c
new file mode 100644
index 0000000..16583ba
--- /dev/null
+++ b/src/epoll_sub.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2003 Niels Provos <provos@citi.umich.edu>
+ * 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 <stdint.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+
+/*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));
+}
diff --git a/src/getnetconfig.c b/src/getnetconfig.c
new file mode 100644
index 0000000..d547dce
--- /dev/null
+++ b/src/getnetconfig.c
@@ -0,0 +1,716 @@
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netconfig.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <unistd.h>
+#include "rpc_com.h"
+
+/*
+ * 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 ENOPROTOOPT /* 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};
+extern pthread_mutex_t nc_db_lock;
+
+#define MAXNETCONFIGLINE 1000
+
+static int *
+__nc_error()
+{
+ static pthread_mutex_t nc_lock = PTHREAD_MUTEX_INITIALIZER;
+ 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 == KEY_INITIALIZER) {
+ error = 0;
+ mutex_lock(&nc_lock);
+ if (nc_key == KEY_INITIALIZER)
+ error = thr_keycreate(&nc_key, free);
+ mutex_unlock(&nc_lock);
+ if (error)
+ return (&nc_error);
+ }
+ if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) {
+ if((nc_addr = (int *)malloc(sizeof (int))) == NULL)
+ return (&nc_error);
+ 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.
+ */
+ mutex_lock(&nc_db_lock);
+ 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;
+ mutex_unlock(&nc_db_lock);
+ return ((void *)nc_vars);
+ }
+ ni.ref--;
+ mutex_unlock(&nc_db_lock);
+ 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;
+ struct netconfig *result;
+
+ /*
+ * Verify that handle is valid
+ */
+ mutex_lock(&nc_db_lock);
+ if (ncp == NULL || nc_file == NULL) {
+ nc_error = NC_NOTINIT;
+ mutex_unlock(&nc_db_lock);
+ 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 */ {
+ mutex_unlock(&nc_db_lock);
+ return(ncp->nc_configs->ncp);
+ }
+ }
+ else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) {
+ ncp->nc_configs = ncp->nc_configs->next;
+ mutex_unlock(&nc_db_lock);
+ 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) {
+ mutex_unlock(&nc_db_lock);
+ return(NULL);
+ }
+ break;
+ default:
+ nc_error = NC_NOTINIT;
+ mutex_unlock(&nc_db_lock);
+ return (NULL);
+ }
+
+ stringp = (char *) malloc(MAXNETCONFIGLINE);
+ if (stringp == NULL) {
+ mutex_unlock(&nc_db_lock);
+ 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;
+ mutex_unlock(&nc_db_lock);
+ return (NULL);
+ }
+ } while (*stringp == '#');
+
+ list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list));
+ if (list == NULL) {
+ free(stringp);
+ mutex_unlock(&nc_db_lock);
+ return(NULL);
+ }
+ np = (struct netconfig *) malloc(sizeof (struct netconfig));
+ if (np == NULL) {
+ free(stringp);
+ free(list);
+ mutex_unlock(&nc_db_lock);
+ return(NULL);
+ }
+ list->ncp = np;
+ list->next = NULL;
+ list->ncp->nc_lookups = NULL;
+ list->linep = stringp;
+ if (parse_ncp(stringp, list->ncp) == -1) {
+ free(stringp);
+ free(np);
+ free(list);
+ mutex_unlock(&nc_db_lock);
+ return (NULL);
+ }
+ else {
+ /*
+ * 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;
+ result = ni.tail->ncp;
+ mutex_unlock(&nc_db_lock);
+ return result;
+ }
+}
+
+/*
+ * 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;
+ mutex_lock(&nc_db_lock);
+ if (--ni.ref > 0) {
+ mutex_unlock(&nc_db_lock);
+ 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);
+ if(nc_file != NULL) {
+ fclose(nc_file);
+ }
+ nc_file = NULL;
+ mutex_unlock(&nc_db_lock);
+ 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");
+ }
+
+ /*
+ * 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.
+ */
+ mutex_lock(&nc_db_lock);
+ if (ni.head != NULL) {
+ for (list = ni.head; list; list = list->next) {
+ if (strcmp(list->ncp->nc_netid, netid) == 0) {
+ ncp = dup_ncp(list->ncp);
+ mutex_unlock(&nc_db_lock);
+ return ncp;
+ }
+ }
+ if (ni.eof == 1) { /* that's all the entries */
+ mutex_unlock(&nc_db_lock);
+ return(NULL);
+ }
+ }
+ mutex_unlock(&nc_db_lock);
+
+ 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 */
+ stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */
+ /* 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;
+ char *t;
+ 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);
+ t = strchr(tmp, 0) + 1;
+ p->nc_protofmly = (char *)strcpy(t,ncp->nc_protofmly);
+ t = strchr(t, 0) + 1;
+ p->nc_proto = (char *)strcpy(t,ncp->nc_proto);
+ t = strchr(t, 0) + 1;
+ p->nc_device = (char *)strcpy(t,ncp->nc_device);
+ p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *));
+ if (p->nc_lookups == NULL) {
+ free(p);
+ free(tmp);
+ return(NULL);
+ }
+ for (i=0; i < p->nc_nlookups; i++) {
+ t = strchr(t, 0) + 1;
+ p->nc_lookups[i] = (char *)strcpy(t,ncp->nc_lookups[i]);
+ }
+ return(p);
+}
diff --git a/src/getnetpath.c b/src/getnetpath.c
new file mode 100644
index 0000000..ea1a18c
--- /dev/null
+++ b/src/getnetpath.c
@@ -0,0 +1,261 @@
+/*
+ * 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 <stdio.h>
+#include <errno.h>
+#include <netconfig.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+/*
+ * 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);
+ free(np_sessionp);
+ 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/src/getpeereid.c b/src/getpeereid.c
new file mode 100644
index 0000000..dd85270
--- /dev/null
+++ b/src/getpeereid.c
@@ -0,0 +1,51 @@
+/*
+ * 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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+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);
+ }
diff --git a/src/getpublickey.c b/src/getpublickey.c
new file mode 100644
index 0000000..be37a24
--- /dev/null
+++ b/src/getpublickey.c
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+/*
+ * publickey.c
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+/*
+ * Public key lookup routines
+ */
+#include <stdio.h>
+#include <pwd.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+
+#include "debug.h"
+
+#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';
+ memcpy(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) {
+ LIBTIRPC_DEBUG(1,
+ ("getpublicandprivatekey: match failed error %d\n", err));
+ continue;
+ }
+ lookup[len] = 0;
+ strcpy(ret, lookup);
+ fclose(fd);
+ free(lookup);
+ return (2);
+#else /* YP */
+ LIBTIRPC_DEBUG(1,
+("Bad record in %s '+' -- NIS not supported in this library copy\n", PKFILE));
+ 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));
+}
diff --git a/src/getrpcent.c b/src/getrpcent.c
new file mode 100644
index 0000000..e49dc05
--- /dev/null
+++ b/src/getrpcent.c
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+#include <libc_private.h>
+#endif
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if !HAVE_GETRPCBYNAME || !HAVE_GETRPCBYNUMBER || \
+ !HAVE_SETRPCENT || !HAVE_ENDRPCENT || !HAVE_GETRPCENT
+
+/*
+ * 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);
+}
+
+#if !HAVE_GETRPCBYNUMBER
+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);
+}
+#endif /* !HAVE_GETRPCBYNUMBER */
+
+#if !HAVE_GETRPCBYNAME
+struct rpcent *
+getrpcbyname(name)
+ const 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 /* !HAVE_GETRPCBYNAME */
+
+#if !HAVE_SETRPCENT
+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;
+}
+#endif
+
+#if !HAVE_ENDRPCENT
+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;
+ }
+}
+#endif
+
+#if !HAVE_GETRPCENT
+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)));
+}
+#endif
+
+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);
+}
+
+#endif
diff --git a/src/getrpcport.c b/src/getrpcport.c
new file mode 100644
index 0000000..c28cd61
--- /dev/null
+++ b/src/getrpcport.c
@@ -0,0 +1,66 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+
+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.sin_addr.s_addr))
+ hp->h_length = sizeof(addr.sin_addr.s_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/src/key_call.c b/src/key_call.c
new file mode 100644
index 0000000..9f4b1d2
--- /dev/null
+++ b/src/key_call.c
@@ -0,0 +1,446 @@
+/*
+ * 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.
+ */
+
+
+
+/*
+ * 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
+ */
+
+#include <pthread.h>
+#include <reentrant.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include <rpc/key_prot.h>
+#include <string.h>
+#include <netconfig.h>
+#include <sys/utsname.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include "debug.h"
+
+#define KEY_TIMEOUT 5 /* per-try timeout in seconds */
+#define KEY_NRETRY 12 /* number of retries */
+
+/*
+ * 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) {
+ LIBTIRPC_DEBUG(1, ("key_setsecret: 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) {
+ LIBTIRPC_DEBUG(1, ("key_encryptsession_pk: 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) {
+ LIBTIRPC_DEBUG(1, ("key_decryptsession_pk: 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) {
+ LIBTIRPC_DEBUG(1, ("key_encryptsession: 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) {
+ LIBTIRPC_DEBUG(1, ("key_decryptsession: 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) {
+ LIBTIRPC_DEBUG(1, ("key_setnet: 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) {
+ LIBTIRPC_DEBUG(1, ("key_get_conv: 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 (uname(&u) == -1) {
+ 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);
+ }
+}
diff --git a/src/key_prot_xdr.c b/src/key_prot_xdr.c
new file mode 100644
index 0000000..772f582
--- /dev/null
+++ b/src/key_prot_xdr.c
@@ -0,0 +1,170 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <rpc/key_prot.h>
+/*
+ * 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. */
+
+
+/*
+ * 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);
+}
diff --git a/src/libtirpc.map b/src/libtirpc.map
new file mode 100644
index 0000000..21d6065
--- /dev/null
+++ b/src/libtirpc.map
@@ -0,0 +1,335 @@
+TIRPC_0.3.0 {
+ global:
+ # __*
+ __rpc_createerr;
+ __rpc_dtbsize;
+ __rpc_endconf;
+ __rpc_fd2sockinfo;
+ __rpc_fixup_addr;
+ __rpc_get_a_size;
+ __rpc_get_local_uid;
+ __rpc_get_t_size;
+ __rpc_getconf;
+ __rpc_getconfip;
+ __rpc_nconf2fd;
+ __rpc_nconf2fd_flags;
+ __rpc_nconf2sockinfo;
+ __rpc_rawcombuf;
+ __rpc_seman2socktype;
+ __rpc_setconf;
+ __rpc_sockinfo2netid;
+ __rpc_sockisbound;
+ __rpc_socktype2seman;
+ __rpc_taddr2uaddr_af;
+ __rpc_uaddr2taddr_af;
+ __rpcgettp;
+
+ # _*
+ _authenticate;
+ _get_next_token;
+ _gss_authenticate;
+ _null_auth;
+ _rpc_dtablesize;
+ _seterr_reply;
+ _svcauth_none;
+ _svcauth_short;
+ _svcauth_unix;
+ _svcauth_gss;
+
+ # a*
+ authdes_create;
+ authdes_seccreate;
+ authgss_create;
+ authgss_create_default;
+ authgss_free_private_data;
+ authgss_get_private_data;
+ authgss_service;
+ authnone_create;
+ authunix_create;
+ authunix_create_default;
+
+ # b*
+ bindresvport;
+ bindresvport_sa;
+
+ # c*
+ callrpc;
+ cbc_crypt;
+ clnt_broadcast;
+ clnt_create;
+ clnt_create_timed;
+ clnt_create_vers;
+ clnt_create_vers_timed;
+ clnt_dg_create;
+ clnt_pcreateerror;
+ clnt_perrno;
+ clnt_perror;
+ clnt_raw_create;
+ clnt_spcreateerror;
+ clnt_sperrno;
+ clnt_sperror;
+ clnt_tli_create;
+ clnt_tp_create;
+ clnt_tp_create_timed;
+ clnt_vc_create;
+ clntraw_create;
+ clnttcp_create;
+ clntudp_bufcreate;
+ clntudp_create;
+ clntunix_create;
+
+ # e*
+ ecb_crypt;
+ endnetconfig;
+ endnetpath;
+ endrpcent;
+
+ # f*
+ freenetconfigent;
+
+ # g*
+ get_myaddress;
+ getnetconfig;
+ getnetconfigent;
+ getnetpath;
+ getrpcent;
+ getrpcbynumber;
+ getrpcbyname;
+ getrpcport;
+ gss_log_debug;
+ gss_log_hexdump;
+ gss_log_status;
+
+ # n*
+ nc_perror;
+ nc_sperror;
+
+ # p*
+ pmap_getmaps;
+ pmap_getport;
+ pmap_rmtcall;
+ pmap_set;
+ pmap_unset;
+
+ # r*
+ registerrpc;
+ rpc_broadcast;
+ rpc_broadcast_exp;
+ rpc_call;
+ rpc_control;
+ rpc_createerr;
+ rpc_gss_get_error;
+ rpc_gss_get_mech_info;
+ rpc_gss_get_mechanisms;
+ rpc_gss_get_principal_name;
+ rpc_gss_get_versions;
+ rpc_gss_getcred;
+ rpc_gss_is_installed;
+ rpc_gss_max_data_length;
+ rpc_gss_mech_to_oid;
+ rpc_gss_qop_to_num;
+ rpc_gss_seccreate;
+ rpc_gss_set_callback;
+ rpc_gss_set_defaults;
+ rpc_gss_set_svc_name;
+ rpc_gss_svc_max_data_length;
+ rpc_nullproc;
+ rpc_reg;
+ rpcb_getaddr;
+ rpcb_getmaps;
+ rpcb_gettime;
+ rpcb_rmtcall;
+ rpcb_set;
+ rpcb_taddr2uaddr;
+ rpcb_uaddr2taddr;
+ rpcb_unset;
+
+ # s*
+ setnetconfig;
+ setnetpath;
+ setrpcent;
+ svc_auth_reg;
+ svc_create;
+ svc_dg_create;
+ svc_dg_enablecache;
+ svc_exit;
+ svc_fd_create;
+ svc_fdset;
+ svc_getreq;
+ svc_getreq_common;
+ svc_getreq_poll;
+ svc_getreqset;
+ svc_maxfd;
+ svc_raw_create;
+ svc_reg;
+ svc_register;
+ svc_run;
+ svc_sendreply;
+ svc_tli_create;
+ svc_tp_create;
+ svc_unreg;
+ svc_unregister;
+ svc_vc_create;
+ svcerr_auth;
+ svcerr_decode;
+ svcerr_noproc;
+ svcerr_noprog;
+ svcerr_progvers;
+ svcerr_systemerr;
+ svcerr_weakauth;
+ svcfd_create;
+ svcraw_create;
+ svctcp_create;
+ svcudp_bufcreate;
+ svcudp_create;
+ svcunix_create;
+ svcunixfd_create;
+
+ # t*
+ taddr2uaddr;
+
+ # u*
+ uaddr2taddr;
+
+ # x*
+ xdr_accepted_reply;
+ xdr_array;
+ xdr_authdes_cred;
+ xdr_authdes_verf;
+ 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_int16_t;
+ xdr_int32_t;
+ xdr_int64_t;
+ xdr_int8_t;
+ xdr_int;
+ xdr_long;
+ xdr_longlong_t;
+ xdr_netbuf;
+ xdr_netobj;
+ xdr_opaque;
+ xdr_opaque_auth;
+ xdr_pmap;
+ xdr_pmaplist;
+ xdr_pmaplist_ptr;
+ xdr_pointer;
+ xdr_quad_t;
+ xdr_reference;
+ xdr_rejected_reply;
+ xdr_replymsg;
+ xdr_rmtcall_args;
+ xdr_rmtcallres;
+ xdr_rpc_gss_cred;
+ xdr_rpc_gss_data;
+ xdr_rpc_gss_init_args;
+ xdr_rpc_gss_init_res;
+ xdr_rpcb;
+ xdr_rpcb_entry;
+ xdr_rpcb_entry_list_ptr;
+ xdr_rpcb_rmtcallargs;
+ xdr_rpcb_rmtcallres;
+ xdr_rpcb_stat;
+ xdr_rpcb_stat_byvers;
+ xdr_rpcblist;
+ xdr_rpcblist_ptr;
+ xdr_rpcbs_addrlist;
+ xdr_rpcbs_addrlist_ptr;
+ xdr_rpcbs_proc;
+ xdr_rpcbs_rmtcalllist;
+ xdr_rpcbs_rmtcalllist_ptr;
+ xdr_short;
+ xdr_string;
+ xdr_u_char;
+ xdr_u_hyper;
+ xdr_u_int16_t;
+ xdr_u_int32_t;
+ xdr_u_int64_t;
+ xdr_u_int8_t;
+ xdr_u_int;
+ xdr_u_long;
+ xdr_u_longlong_t;
+ xdr_u_quad_t;
+ xdr_u_short;
+ xdr_uint16_t;
+ xdr_uint32_t;
+ xdr_uint64_t;
+ xdr_uint8_t;
+ xdr_union;
+ xdr_vector;
+ xdr_void;
+ xdr_wrapstring;
+ xdrmem_create;
+ xdrrec_create;
+ xdrrec_endofrecord;
+ xdrrec_eof;
+ xdrrec_skiprecord;
+ xdrstdio_create;
+ xprt_register;
+ xprt_unregister;
+
+ local:
+ *;
+};
+
+TIRPC_0.3.1 {
+ svcauth_gss_get_principal;
+ svcauth_gss_set_svc_name;
+} TIRPC_0.3.0;
+
+TIRPC_0.3.2 {
+ getnetname;
+ getpublicandprivatekey;
+ getpublickey;
+ host2netname;
+ key_call_destroy;
+ key_decryptsession;
+ key_decryptsession_pk;
+ key_encryptsession;
+ key_encryptsession_pk;
+ key_gendes;
+ key_get_conv;
+ key_setsecret;
+ key_secretkey_is_set;
+ key_setnet;
+ netname2host;
+ netname2user;
+ rtime;
+ user2netname;
+ xdr_cryptkeyarg;
+ xdr_cryptkeyarg2;
+ xdr_cryptkeyres;
+ xdr_getcredres;
+ xdr_key_netstarg;
+ xdr_key_netstres;
+ xdr_keybuf;
+ xdr_keystatus;
+ xdr_netnamestr;
+ xdr_unixcred;
+} TIRPC_0.3.1;
+
+TIRPC_0.3.3 {
+ __getpublickey_LOCAL;
+ __key_decryptsession_pk_LOCAL;
+ __key_encryptsession_pk_LOCAL;
+ __key_gendes_LOCAL;
+ xdr_sizeof;
+ authdes_pk_create;
+ svc_pollfd;
+ svc_max_pollfd;
+} TIRPC_0.3.2;
+
+TIRPC_PRIVATE {
+ global:
+ __libc_clntudp_bufcreate;
+ # private, but used by rpcbind:
+ __svc_clean_idle; svc_auth_none; libtirpc_set_debug;
+};
diff --git a/src/mt_misc.c b/src/mt_misc.c
new file mode 100644
index 0000000..3a2bc51
--- /dev/null
+++ b/src/mt_misc.c
@@ -0,0 +1,153 @@
+
+#include <pthread.h>
+#include <reentrant.h>
+#include <rpc/rpc.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* protects the services list (svc.c) */
+pthread_rwlock_t svc_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/* protects svc_fdset and the xports[] array */
+pthread_rwlock_t svc_fd_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/* protects the RPCBIND address cache */
+pthread_mutex_t rpcbaddr_cache_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects authdes cache (svcauth_des.c) */
+pthread_mutex_t authdes_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes authdes ops initializations */
+pthread_mutex_t authdes_ops_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects des stats list */
+pthread_mutex_t svcauthdesstats_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* auth_none.c serialization */
+pthread_mutex_t authnone_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects the Auths list (svc_auth.c) */
+pthread_mutex_t authsvc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects client-side fd lock array */
+pthread_mutex_t clnt_fd_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* clnt_raw.c serialization */
+pthread_mutex_t clntraw_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* domainname and domain_fd (getdname.c) and default_domain (rpcdname.c) */
+pthread_mutex_t dname_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* dupreq variables (svc_dg.c) */
+pthread_mutex_t dupreq_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects first_time and hostname (key_call.c) */
+pthread_mutex_t keyserv_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes rpc_trace() (rpc_trace.c) */
+pthread_mutex_t libnsl_trace_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* loopnconf (rpcb_clnt.c) */
+pthread_mutex_t loopnconf_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes ops initializations */
+pthread_mutex_t ops_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects ``port'' static in bindresvport() */
+pthread_mutex_t portnum_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects proglst list (svc_simple.c) */
+pthread_mutex_t proglst_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes clnt_com_create() (rpc_soc.c) */
+pthread_mutex_t rpcsoc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* svc_raw.c serialization */
+pthread_mutex_t svcraw_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects TSD key creation */
+pthread_mutex_t tsd_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects RPCSEC GSS callback list */
+pthread_mutex_t svcauth_cb_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serialize updates to AUTH ref count */
+pthread_mutex_t auth_ref_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects RPCSEC GSS cache */
+pthread_mutex_t svcauth_gss_cache_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Library global tsd keys */
+thread_key_t clnt_broadcast_key = KEY_INITIALIZER;
+thread_key_t rpc_call_key = KEY_INITIALIZER;
+thread_key_t tcp_key = KEY_INITIALIZER;
+thread_key_t udp_key = KEY_INITIALIZER;
+thread_key_t nc_key = KEY_INITIALIZER;
+thread_key_t rce_key = KEY_INITIALIZER;
+thread_key_t rg_key = KEY_INITIALIZER;
+thread_key_t key_call_key = KEY_INITIALIZER;
+
+/* xprtlist (svc_generic.c) */
+pthread_mutex_t xprtlist_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* serializes calls to public key routines */
+pthread_mutex_t serialize_pkey = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects global variables ni and nc_file (getnetconfig.c) */
+pthread_mutex_t nc_db_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects static port and startport (bindresvport.c) */
+pthread_mutex_t port_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* protects static disrupt (clnt_vc.c) */
+pthread_mutex_t disrupt_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#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 == KEY_INITIALIZER)
+ 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 != KEY_INITIALIZER)
+ pthread_key_delete(clnt_broadcast_key);
+ if (rpc_call_key != KEY_INITIALIZER)
+ pthread_key_delete(rpc_call_key);
+ if (tcp_key != KEY_INITIALIZER)
+ pthread_key_delete(tcp_key);
+ if (udp_key != KEY_INITIALIZER)
+ pthread_key_delete(udp_key);
+ if (nc_key != KEY_INITIALIZER)
+ pthread_key_delete(nc_key);
+ if (rce_key != KEY_INITIALIZER)
+ pthread_key_delete(rce_key);
+ if (rg_key != KEY_INITIALIZER)
+ pthread_key_delete(rce_key);
+ return;
+}
+
diff --git a/src/netname.c b/src/netname.c
new file mode 100644
index 0000000..ea61b1a
--- /dev/null
+++ b/src/netname.c
@@ -0,0 +1,143 @@
+/*
+ * 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 <sys/param.h>
+#include <rpc/rpc.h>
+#include "rpc_com.h"
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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];
+{
+ uid_t uid;
+
+ uid = geteuid();
+ if (uid == 0) {
+ return (host2netname(name, (char *) NULL, (char *) NULL));
+ } else {
+ return (user2netname(name, uid, (char *) NULL));
+ }
+}
+
+
+/*
+ * 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);
+}
diff --git a/src/netnamer.c b/src/netnamer.c
new file mode 100644
index 0000000..6b6c8e0
--- /dev/null
+++ b/src/netnamer.c
@@ -0,0 +1,322 @@
+/*
+ * 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 <sys/param.h>
+#include <rpc/rpc.h>
+#include "rpc_com.h"
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <ctype.h>
+#include <stdio.h>
+#include <grp.h>
+#include <pwd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "debug.h"
+
+static char *OPSYS = "unix";
+#ifdef YP
+static char *NETID = "netid.byname";
+#endif
+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) {
+ LIBTIRPC_DEBUG(1,
+ ("_getgroups: %s is in too many groups\n", uname));
+ 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.
+ */
+static 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) {
+ LIBTIRPC_DEBUG(1, ("getnetid: match failed error %d", err));
+ continue;
+ }
+ lookup[len] = 0;
+ strcpy(ret, lookup);
+ free(lookup);
+ if (fd != NULL)
+ fclose(fd);
+ return (2);
+#else /* YP */
+ LIBTIRPC_DEBUG(1,
+("Bad record in %s '+' -- NIS not supported in this library copy\n",
+ NETIDFILE));
+ 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);
+
+ }
+ }
+ }
+}
diff --git a/src/nis.h b/src/nis.h
new file mode 100644
index 0000000..588c041
--- /dev/null
+++ b/src/nis.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010, Oracle America, Inc.
+ *
+ * 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 the "Oracle America, 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.
+ */
+
+#ifndef _INTERNAL_NIS_H
+#define _INTERNAL_NIS_H 1
+
+/* This file only contains the definition of nis_server, to be
+ able to compile libtirpc without the need to have a glibc
+ with sunrpc or a libnsl already installed. */
+
+#define NIS_PK_NONE 0
+
+struct nis_attr {
+ char *zattr_ndx;
+ struct {
+ u_int zattr_val_len;
+ char *zattr_val_val;
+ } zattr_val;
+};
+typedef struct nis_attr nis_attr;
+
+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 /* ! _INTERNAL_NIS_H */
diff --git a/src/pmap_clnt.c b/src/pmap_clnt.c
new file mode 100644
index 0000000..4b5fd85
--- /dev/null
+++ b/src/pmap_clnt.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.
+ */
+
+
+/*
+ * pmap_clnt.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/nettype.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#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/src/pmap_getmaps.c b/src/pmap_getmaps.c
new file mode 100644
index 0000000..853f724
--- /dev/null
+++ b/src/pmap_getmaps.c
@@ -0,0 +1,89 @@
+/*
+ * 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_getmap.c
+ * Client interface to pmap rpc service.
+ * contains pmap_getmaps, which is only tcp service involved
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+//#include <clnt_soc.h>
+#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;
+ int sock = -1;
+ 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);
+}
diff --git a/src/pmap_getport.c b/src/pmap_getport.c
new file mode 100644
index 0000000..72853a0
--- /dev/null
+++ b/src/pmap_getport.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.
+ */
+/*
+ * pmap_getport.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <assert.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+
+static const struct timeval timeout = { 5, 0 };
+static const struct timeval tottimeout = { 60, 0 };
+
+/*
+ * 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);
+}
diff --git a/src/pmap_prot.c b/src/pmap_prot.c
new file mode 100644
index 0000000..c0a642b
--- /dev/null
+++ b/src/pmap_prot.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <assert.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+
+
+bool_t
+xdr_pmap(xdrs, regs)
+ XDR *xdrs;
+ struct pmap *regs;
+{
+
+ assert(xdrs != NULL);
+ assert(regs != NULL);
+
+ if (xdr_u_long(xdrs, &regs->pm_prog) &&
+ xdr_u_long(xdrs, &regs->pm_vers) &&
+ xdr_u_long(xdrs, &regs->pm_prot))
+ return (xdr_u_long(xdrs, &regs->pm_port));
+ return (FALSE);
+}
diff --git a/src/pmap_prot2.c b/src/pmap_prot2.c
new file mode 100644
index 0000000..5583ff0
--- /dev/null
+++ b/src/pmap_prot2.c
@@ -0,0 +1,131 @@
+/*
+ * 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 <assert.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+
+
+/*
+ * 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/src/pmap_rmt.c b/src/pmap_rmt.c
new file mode 100644
index 0000000..1c76114
--- /dev/null
+++ b/src/pmap_rmt.c
@@ -0,0 +1,168 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_rmt.h>
+
+// For the clnttcp_create function
+//#include <clnt_soc.h>
+
+
+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/src/rpc_callmsg.c b/src/rpc_callmsg.c
new file mode 100644
index 0000000..d5f7d0c
--- /dev/null
+++ b/src/rpc_callmsg.c
@@ -0,0 +1,196 @@
+/*
+ * 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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+
+#include <sys/select.h>
+
+/*
+ * 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/src/rpc_com.h b/src/rpc_com.h
new file mode 100644
index 0000000..76badef
--- /dev/null
+++ b/src/rpc_com.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <rpc/rpc_com.h>,
+ * but as it contains only non-exported interfaces, it was moved here.
+ */
+
+#ifndef _TIRPC_RPCCOM_H
+#define _TIRPC_RPCCOM_H
+
+#include <rpc/rpc_com.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct netbuf *__rpc_set_netbuf(struct netbuf *, const void *, size_t);
+
+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 *);
+
+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 *);
+
+
+extern int __svc_maxrec;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TIRPC_RPCCOM_H */
diff --git a/src/rpc_commondata.c b/src/rpc_commondata.c
new file mode 100644
index 0000000..918c1aa
--- /dev/null
+++ b/src/rpc_commondata.c
@@ -0,0 +1,41 @@
+/*
+ * 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 <rpc/rpc.h>
+
+
+/*
+ * 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;
+struct pollfd *svc_pollfd;
+int svc_max_pollfd;
+
diff --git a/src/rpc_dtablesize.c b/src/rpc_dtablesize.c
new file mode 100644
index 0000000..bce97e8
--- /dev/null
+++ b/src/rpc_dtablesize.c
@@ -0,0 +1,47 @@
+/*
+ * 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 <unistd.h>
+#include <sys/select.h>
+#include <rpc/clnt.h>
+#include <rpc/rpc_com.h>
+
+/*
+ * Cache the result of getdtablesize(), so we don't have to do an
+ * expensive system call every time.
+ */
+int
+_rpc_dtablesize(void)
+{
+ static int size;
+
+ if (size == 0) {
+ size = sysconf(_SC_OPEN_MAX);
+ }
+ return (size);
+}
diff --git a/src/rpc_generic.c b/src/rpc_generic.c
new file mode 100644
index 0000000..aabbe4b
--- /dev/null
+++ b/src/rpc_generic.c
@@ -0,0 +1,879 @@
+/*
+ * 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_generic.c, Miscl routines for RPC.
+ *
+ */
+#include <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <netconfig.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <rpc/nettype.h>
+#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;
+ int 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
+ { "local", AF_LOCAL, 0 }
+};
+
+#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()
+{
+ static int tbsize;
+ struct rlimit rl;
+
+ if (tbsize) {
+ return (tbsize);
+ }
+ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
+ return (tbsize = (int)rl.rlim_cur);
+ }
+ /*
+ * Something wrong. I'll try to save face by returning a
+ * pessimistic number.
+ */
+ return (32);
+}
+
+
+/*
+ * 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 = 64 * 1024; /* XXX */
+ break;
+ case IPPROTO_UDP:
+ defsize = UDPMSGSIZE;
+ break;
+ default:
+ defsize = RPC_MAXDATASIZE;
+ break;
+ }
+ if (size == 0)
+ return defsize;
+
+ /* Check whether the value is within the upper max limit */
+ return (size > maxsize ? (u_int)maxsize : (u_int)size);
+}
+
+/*
+ * 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
+ case AF_LOCAL:
+ return sizeof (struct sockaddr_un);
+ 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 <rpc/nettype.h>
+ * 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
+ * IPv4 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 == KEY_INITIALIZER) {
+ mutex_lock(&tsd_lock);
+ if (tcp_key == KEY_INITIALIZER)
+ thr_keycreate(&tcp_key, free);
+ mutex_unlock(&tsd_lock);
+ }
+ netid_tcp = (char *)thr_getspecific(tcp_key);
+ if (udp_key == KEY_INITIALIZER) {
+ mutex_lock(&tsd_lock);
+ if (udp_key == KEY_INITIALIZER)
+ 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) {
+ 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:
+ free(handle);
+ 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)
+ int 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(int fd, struct __rpc_sockinfo *sip)
+{
+ socklen_t len;
+ int type, proto;
+ struct sockaddr_storage ss;
+
+ len = sizeof ss;
+ if (getsockname(fd, (struct sockaddr *)&ss, &len) < 0)
+ return 0;
+ sip->si_alen = len;
+
+ len = sizeof type;
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+ return 0;
+
+ /* XXX */
+ if (ss.ss_family != AF_LOCAL) {
+ if (type == SOCK_STREAM)
+ proto = IPPROTO_TCP;
+ else if (type == SOCK_DGRAM)
+ proto = IPPROTO_UDP;
+ else
+ return 0;
+ } else
+ proto = 0;
+
+ 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;
+}
+
+int
+__rpc_nconf2fd_flags(const struct netconfig *nconf, int flags)
+{
+ struct __rpc_sockinfo si;
+ int fd;
+
+ if (!__rpc_nconf2sockinfo(nconf, &si))
+ return 0;
+
+ if ((fd = socket(si.si_af, si.si_socktype | flags, si.si_proto)) >= 0 &&
+ si.si_af == AF_INET6) {
+ int val = 1;
+
+#ifdef INET6
+ setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+#endif
+ }
+ return fd;
+}
+
+int
+__rpc_nconf2fd(const struct netconfig *nconf)
+{
+ return __rpc_nconf2fd_flags(nconf, 0);
+}
+
+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);
+}
+
+char *
+__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
+{
+ char *ret;
+ struct sockaddr_in *sin;
+ struct sockaddr_un *sun;
+ char namebuf[INET_ADDRSTRLEN];
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ char namebuf6[INET6_ADDRSTRLEN];
+#endif
+ int path_len;
+ u_int16_t port;
+
+ if (nbuf->len <= 0)
+ return NULL;
+
+ switch (af) {
+ case AF_INET:
+ if (nbuf->len < sizeof(*sin)) {
+ return NULL;
+ }
+ 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:
+ if (nbuf->len < sizeof(*sin6)) {
+ return NULL;
+ }
+ 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
+ case AF_LOCAL:
+ sun = nbuf->buf;
+
+ path_len = nbuf->len - offsetof(struct sockaddr_un, sun_path);
+ if (path_len < 0)
+ return NULL;
+
+ if (asprintf(&ret, "%.*s", path_len, sun->sun_path) < 0)
+ return (NULL);
+ break;
+ default:
+ return NULL;
+ }
+
+ return ret;
+}
+
+struct netbuf *
+__rpc_uaddr2taddr_af(int af, const char *uaddr)
+{
+ struct netbuf *ret = NULL;
+ char *addrstr, *p;
+ unsigned port, portlo, porthi;
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ struct sockaddr_un *sun;
+
+ port = 0;
+ sin = NULL;
+ if (uaddr == NULL)
+ return 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
+ 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;
+ 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(int fd)
+{
+ struct sockaddr_storage ss;
+ union {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_un usin;
+ } u_addr;
+ socklen_t slen;
+
+ slen = sizeof (struct sockaddr_storage);
+ if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
+ 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
+ case AF_LOCAL:
+ /* XXX check this */
+ memcpy(&u_addr.usin, &ss, sizeof(u_addr.usin));
+ return (u_addr.usin.sun_path[0] != 0);
+ 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/src/rpc_gss_utils.c b/src/rpc_gss_utils.c
new file mode 100644
index 0000000..80fc78a
--- /dev/null
+++ b/src/rpc_gss_utils.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2013, Oracle America, 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 "Oracle America, 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 <string.h>
+#include <errno.h>
+#include <reentrant.h>
+
+#include <rpc/auth_gss.h>
+#include <rpc/rpcsec_gss.h>
+
+#include <gssapi/gssapi_krb5.h>
+
+/* Internal only */
+void rpc_gss_set_error(int);
+void rpc_gss_clear_error(void);
+bool_t rpc_gss_oid_to_mech(rpc_gss_OID, char **);
+
+/*
+ * Return the static "_rpc_gss_error" if we are the main thread
+ * (including non-threaded programs), or if an allocation fails.
+ */
+static rpc_gss_error_t *
+__rpc_gss_error(void)
+{
+ static rpc_gss_error_t _rpc_gss_error = { 0, 0 };
+ extern thread_key_t rg_key;
+ rpc_gss_error_t *result;
+
+ if (rg_key == KEY_INITIALIZER) {
+ static mutex_t _rpc_gss_error_lock = MUTEX_INITIALIZER;
+ int err = 0;
+
+ mutex_lock(&_rpc_gss_error_lock);
+ if (rg_key == KEY_INITIALIZER)
+ err = thr_keycreate(&rg_key, free);
+ mutex_unlock(&_rpc_gss_error_lock);
+
+ if (err != 0)
+ return &_rpc_gss_error;
+ }
+
+ result = thr_getspecific(rg_key);
+ if (result == NULL) {
+ result = calloc(1, sizeof(*result));
+ if (result == NULL)
+ return &_rpc_gss_error;
+
+ if (thr_setspecific(rg_key, result) != 0) {
+ free(result);
+ return &_rpc_gss_error;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * External API: Retrieve thread-specific error values
+ *
+ * error: address of rpc_gss_error_t structure to fill in
+ */
+void
+rpc_gss_get_error(rpc_gss_error_t *result)
+{
+ rpc_gss_error_t *error = __rpc_gss_error();
+
+ result->rpc_gss_error = error->rpc_gss_error;
+ result->system_error = error->system_error;
+}
+
+/*
+ * Internal only: Set thread-specific error value
+ *
+ * system_error: new value for thread's .system_error field.
+ * .rpc_gss_error is always set to RPC_GSS_ER_SYSTEMERROR.
+ */
+void
+rpc_gss_set_error(int system_error)
+{
+ rpc_gss_error_t *error = __rpc_gss_error();
+
+ error->rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
+ error->system_error = system_error;
+}
+
+/*
+ * Internal only: Clear thread-specific error values
+ */
+void
+rpc_gss_clear_error(void)
+{
+ rpc_gss_error_t *error = __rpc_gss_error();
+
+ error->rpc_gss_error = RPC_GSS_ER_SUCCESS;
+ error->system_error = 0;
+}
+
+/*
+ * On Solaris, the GSS-API implementation consults the files
+ * /etc/gss/mech and /etc/gss/qop for a mapping of mechanism
+ * names to OIDs, and QOP names to numbers.
+ *
+ * GNU's GSS-API has no such database. We emulate it here
+ * with a built-in table of supported mechanisms and qops,
+ * since the set of supported mechanisms is unlikely to
+ * change often.
+ */
+
+struct _rpc_gss_qop {
+ char *qi_name;
+ unsigned int qi_num;
+};
+
+struct _rpc_gss_mechanism {
+ char *mi_name;
+ rpc_gss_OID_desc mi_oid;
+ char **mi_qop_names;
+ struct _rpc_gss_qop **mi_qops;
+};
+
+
+static struct _rpc_gss_qop _rpc_gss_qop_default = {
+ .qi_name = "GSS_C_QOP_DEFAULT",
+ .qi_num = GSS_C_QOP_DEFAULT,
+};
+
+static struct _rpc_gss_qop *_rpc_gss_krb5_qops[] = {
+ &_rpc_gss_qop_default,
+ NULL,
+};
+
+static char *_rpc_gss_krb5_qop_names[] = {
+ "GSS_C_QOP_DEFAULT",
+ NULL,
+};
+
+/* GSS_MECH_KRB5_OID: Defined by RFC 1964 */
+static struct _rpc_gss_mechanism _rpc_gss_mech_kerberos_v5 = {
+ .mi_name = "kerberos_v5",
+ .mi_oid = { 9, "\052\206\110\206\367\022\001\002\002" },
+ .mi_qop_names = _rpc_gss_krb5_qop_names,
+ .mi_qops = _rpc_gss_krb5_qops,
+};
+
+/* GSS_KRB5_NT_PRINCIPAL_NAME: Defined by RFC 1964 */
+static struct _rpc_gss_mechanism _rpc_gss_mech_kerberos_v5_princname = {
+ .mi_name = "kerberos_v5",
+ .mi_oid = { 10, "\052\206\110\206\367\022\001\002\002\001" },
+ .mi_qop_names = _rpc_gss_krb5_qop_names,
+ .mi_qops = _rpc_gss_krb5_qops,
+};
+
+static struct _rpc_gss_mechanism *_rpc_gss_mechanisms[] = {
+ &_rpc_gss_mech_kerberos_v5,
+ &_rpc_gss_mech_kerberos_v5_princname,
+ NULL,
+};
+
+static char *_rpc_gss_mechanism_names[] = {
+ "kerberos_v5",
+ NULL,
+};
+
+static struct _rpc_gss_mechanism *
+_rpc_gss_find_mechanism(char *mechanism)
+{
+ unsigned int i;
+
+ for (i = 0; _rpc_gss_mechanisms[i] != NULL; i++)
+ if (strcmp(mechanism, _rpc_gss_mechanisms[i]->mi_name) == 0)
+ return _rpc_gss_mechanisms[i];
+ return NULL;
+}
+
+static bool_t
+_rpc_gss_OID_equal(rpc_gss_OID o1, rpc_gss_OID o2)
+{
+ return (o1->length == o2->length) &&
+ (memcmp(o1->elements, o2->elements, o1->length) == 0);
+}
+
+static struct _rpc_gss_mechanism *
+_rpc_gss_find_oid(rpc_gss_OID oid)
+{
+ unsigned int i;
+
+ for (i = 0; _rpc_gss_mechanisms[i] != NULL; i++)
+ if (_rpc_gss_OID_equal(oid, &_rpc_gss_mechanisms[i]->mi_oid))
+ return _rpc_gss_mechanisms[i];
+ return NULL;
+}
+
+static struct _rpc_gss_qop *
+_rpc_gss_find_qop_by_name(struct _rpc_gss_mechanism *m, char *qop)
+{
+ unsigned int i;
+
+ for (i = 0; m->mi_qops[i] != NULL; i++)
+ if (strcmp(qop, m->mi_qops[i]->qi_name) == 0)
+ return m->mi_qops[i];
+ return NULL;
+}
+
+static struct _rpc_gss_qop *
+_rpc_gss_find_qop_by_num(struct _rpc_gss_mechanism *m, u_int num)
+{
+ unsigned int i;
+
+ for (i = 0; m->mi_qops[i] != NULL; i++)
+ if (num == m->mi_qops[i]->qi_num)
+ return m->mi_qops[i];
+ return NULL;
+}
+
+/*
+ * External API: Return array of security mechanism names
+ *
+ * Returns NULL-terminated array of pointers to NUL-terminated C
+ * strings, each containing a mechanism name. This is statically
+ * allocated memory. Caller must not free this array.
+ */
+char **
+rpc_gss_get_mechanisms(void)
+{
+ rpc_gss_clear_error();
+ return (char **)_rpc_gss_mechanism_names;
+}
+
+/*
+ * External API: Return array of qop names for a security mechanism
+ *
+ * mechanism: NUL-terminated C string containing mechanism name
+ * dummy: address of a service enum
+ *
+ * Returns NULL-terminated array of pointers to NUL-terminated C
+ * strings, each containing a qop name. This is statically
+ * allocated memory. Caller must not free this array.
+ */
+char **
+rpc_gss_get_mech_info(char *mechanism, rpc_gss_service_t *dummy)
+{
+ struct _rpc_gss_mechanism *m;
+
+ if (mechanism == NULL || dummy == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return NULL;
+ }
+
+ m = _rpc_gss_find_mechanism(mechanism);
+ if (m == NULL) {
+ rpc_gss_set_error(ENOENT);
+ return NULL;
+ }
+
+ rpc_gss_clear_error();
+ *dummy = rpcsec_gss_svc_privacy;
+ return (char **)m->mi_qop_names;
+}
+
+/*
+ * External API: Return range of supported RPCSEC_GSS versions
+ *
+ * high: address of highest supported version to fill in
+ * low: address of lowest supported version to fill in
+ *
+ * Returns TRUE if successful, or FALSE if an error occurs.
+ */
+bool_t
+rpc_gss_get_versions(u_int *high, u_int *low)
+{
+ if (high == NULL || low == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ rpc_gss_clear_error();
+ *high = *low = RPCSEC_GSS_VERSION;
+ return TRUE;
+}
+
+/*
+ * External API: Check if a security mechanism is supported
+ *
+ * mechanism: NUL-terminated C string containing mechanism name
+ *
+ * Returns TRUE if the mechanism name is recognized and supported,
+ * otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_is_installed(char *mechanism)
+{
+ struct _rpc_gss_mechanism *m;
+
+ if (mechanism == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ rpc_gss_clear_error();
+ m = _rpc_gss_find_mechanism(mechanism);
+ if (m == NULL)
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * External API: Return the OID for a given security mechanism
+ *
+ * mechanism: NUL-terminated C string containing mechanism name
+ * oid: address of OID buffer to fill in
+ *
+ * Returns TRUE if the mechanism name is recognized and supported,
+ * otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_mech_to_oid(char *mechanism, rpc_gss_OID *result)
+{
+ struct _rpc_gss_mechanism *m;
+
+ if (mechanism == NULL || result == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ m = _rpc_gss_find_mechanism(mechanism);
+ if (m == NULL) {
+ rpc_gss_set_error(ENOENT);
+ return FALSE;
+ }
+
+ *result = &m->mi_oid;
+ rpc_gss_clear_error();
+ return TRUE;
+}
+
+/*
+ * Internal only: Return the mechanism name for a given OID
+ *
+ * oid: GSS mechanism OID
+ * mechanism: address of a char * to fill in. This is statically
+ * allocated memory. Caller must not free this memory.
+ *
+ * Returns TRUE if the OID is a recognized and supported mechanism,
+ * otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_oid_to_mech(rpc_gss_OID oid, char **mechanism)
+{
+ struct _rpc_gss_mechanism *m;
+
+ if (oid == NULL || mechanism == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ m = _rpc_gss_find_oid(oid);
+ if (m == NULL) {
+ rpc_gss_set_error(ENOENT);
+ return FALSE;
+ }
+
+ *mechanism = m->mi_name;
+ rpc_gss_clear_error();
+ return TRUE;
+}
+
+/*
+ * External API: Return the QOP number for a given QOP and mechanism name
+ *
+ * qop: NUL-terminated C string containing qop name
+ * mechanism: NUL-terminated C string containing mechanism name
+ * num: address of QOP buffer to fill in
+ *
+ * Returns TRUE if the qop and mechanism name are recognized and
+ * supported, otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_qop_to_num(char *qop, char *mechanism, u_int *num)
+{
+ struct _rpc_gss_mechanism *m;
+ struct _rpc_gss_qop *q;
+
+ if (qop == NULL || mechanism == NULL || num == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ m = _rpc_gss_find_mechanism(mechanism);
+ if (m == NULL)
+ goto out_err;
+
+ q = _rpc_gss_find_qop_by_name(m, qop);
+ if (q == NULL)
+ goto out_err;
+
+ *num = q->qi_num;
+ rpc_gss_clear_error();
+ return TRUE;
+
+out_err:
+ rpc_gss_set_error(ENOENT);
+ return FALSE;
+}
+
+/*
+ * Internal only: Return the QOP name for a given mechanism and QOP number
+ *
+ * mechanism: NUL-terminated C string containing security mechanism name
+ * num: QOP number
+ * qop: address of a char * to fill in. This is statically
+ * allocated memory. Caller must not free this memory.
+ *
+ * Returns TRUE if the QOP and mechanism are recognized and supported,
+ * otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_num_to_qop(char *mechanism, u_int num, char **qop)
+{
+ struct _rpc_gss_mechanism *m;
+ struct _rpc_gss_qop *q;
+
+ if (mechanism == NULL || qop == NULL) {
+ rpc_gss_set_error(EINVAL);
+ return FALSE;
+ }
+
+ m = _rpc_gss_find_mechanism(mechanism);
+ if (m == NULL)
+ goto out_err;
+
+ q = _rpc_gss_find_qop_by_num(m, num);
+ if (q == NULL)
+ goto out_err;
+
+ *qop = q->qi_name;
+ rpc_gss_clear_error();
+ return TRUE;
+
+out_err:
+ rpc_gss_set_error(ENOENT);
+ return FALSE;
+}
diff --git a/src/rpc_prot.c b/src/rpc_prot.c
new file mode 100644
index 0000000..5841e51
--- /dev/null
+++ b/src/rpc_prot.c
@@ -0,0 +1,342 @@
+/*
+ * 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 <sys/param.h>
+
+#include <assert.h>
+
+#include <rpc/rpc.h>
+
+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 */
+ 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);
+}
+
+
+/*
+ * 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/src/rpc_soc.c b/src/rpc_soc.c
new file mode 100644
index 0000000..fde121d
--- /dev/null
+++ b/src/rpc_soc.c
@@ -0,0 +1,745 @@
+
+/*
+ * 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.
+ */
+
+#ifdef PORTMAP
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/nettype.h>
+#include <syslog.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "nis.h"
+#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 *, int);
+static SVCXPRT *svc_com_create(int, 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, flags)
+ struct sockaddr_in *raddr;
+ rpcprog_t prog;
+ rpcvers_t vers;
+ int *sockp;
+ u_int sendsz;
+ u_int recvsz;
+ char *tp;
+ int flags;
+{
+ CLIENT *cl;
+ int madefd = FALSE;
+ int 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) {
+ static int have_cloexec;
+ fd = __rpc_nconf2fd_flags(nconf, flags);
+#ifdef SOCK_CLOEXEC
+ if (fd == -1) {
+ if ((flags & SOCK_CLOEXEC) && have_cloexec <= 0) {
+ fd = __rpc_nconf2fd(nconf);
+ if (fd == -1)
+ goto syserror;
+ if (flags & SOCK_CLOEXEC) {
+ have_cloexec = -1;
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ }
+ } else
+ goto syserror;
+ } else if (flags & SOCK_CLOEXEC)
+ have_cloexec = 1;
+#else
+ if (fd == -1)
+ goto syserror;
+#endif
+ 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);
+ 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)close(fd);
+ (void) freenetconfigent(nconf);
+ mutex_unlock(&rpcsoc_lock);
+ return (NULL);
+}
+
+CLIENT *
+__libc_clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz, flags)
+ struct sockaddr_in *raddr;
+ u_long prog;
+ u_long vers;
+ struct timeval wait;
+ int *sockp;
+ u_int sendsz;
+ u_int recvsz;
+ int flags;
+{
+ CLIENT *cl;
+
+ cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
+ sendsz, recvsz, "udp", flags);
+ if (cl == NULL) {
+ return (NULL);
+ }
+ (void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
+ return (cl);
+}
+
+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", 0);
+ 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", 0);
+}
+
+/* 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", 0);
+ 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", 0);
+}
+
+#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)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+ char *netid;
+{
+ struct netconfig *nconf;
+ SVCXPRT *svc;
+ int madefd = FALSE;
+ int port;
+
+ 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;
+ }
+
+ svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
+ (void) freenetconfigent(nconf);
+ if (svc == NULL) {
+ if (madefd)
+ (void)close(fd);
+ return (NULL);
+ }
+ port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
+ svc->xp_port = ntohs(port);
+ return (svc);
+}
+
+SVCXPRT *
+svctcp_create(fd, sendsize, recvsize)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+
+ return svc_com_create(fd, sendsize, recvsize, "tcp");
+}
+
+
+
+SVCXPRT *
+svcudp_bufcreate(fd, sendsz, recvsz)
+ int fd;
+ u_int sendsz, recvsz;
+{
+
+ return svc_com_create(fd, sendsz, recvsz, "udp");
+}
+
+
+
+SVCXPRT *
+svcfd_create(fd, sendsize, recvsize)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+
+ return svc_fd_create(fd, sendsize, recvsize);
+}
+
+
+SVCXPRT *
+svcudp_create(fd)
+ int 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 == KEY_INITIALIZER) {
+ mutex_lock(&tsd_lock);
+ if (clnt_broadcast_key == KEY_INITIALIZER)
+ 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");
+}
+
+#ifdef AUTHDES_SUPPORT
+/*
+ * 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 *nauth;
+ char hostname[NI_MAXHOST];
+
+ if (syncaddr) {
+ /*
+ * Change addr to hostname, because that is the way
+ * new interface takes it.
+ */
+ switch (syncaddr->sa_family) {
+ case AF_INET:
+ if (getnameinfo(syncaddr, sizeof(struct sockaddr_in), hostname,
+ sizeof hostname, NULL, 0, 0) != 0)
+ goto fallback;
+ break;
+ case AF_INET6:
+ if (getnameinfo(syncaddr, sizeof(struct sockaddr_in6), hostname,
+ sizeof hostname, NULL, 0, 0) != 0)
+ goto fallback;
+ break;
+ default:
+ goto fallback;
+ }
+ nauth = authdes_seccreate(servername, window, hostname, ckey);
+ return (nauth);
+ }
+fallback:
+ return authdes_seccreate(servername, window, NULL, ckey);
+}
+
+/*
+ * Create the client des authentication object. Obsoleted by
+ * authdes_pk_seccreate().
+ */
+extern AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *,
+ const des_block *, nis_server *);
+
+AUTH *
+authdes_pk_create(servername, pkey, window, syncaddr, ckey)
+ char *servername; /* network name of server */
+ netobj *pkey; /* public key */
+ u_int window; /* time to live */
+ struct sockaddr *syncaddr; /* optional hostaddr to sync with */
+ des_block *ckey; /* optional conversation key to use */
+{
+ AUTH *nauth;
+ char hostname[NI_MAXHOST];
+
+ if (syncaddr) {
+ /*
+ * Change addr to hostname, because that is the way
+ * new interface takes it.
+ */
+ switch (syncaddr->sa_family) {
+ case AF_INET:
+ if (getnameinfo(syncaddr, sizeof(struct sockaddr_in), hostname,
+ sizeof hostname, NULL, 0, 0) != 0)
+ goto fallback;
+ break;
+ default:
+ goto fallback;
+ }
+ nauth = authdes_pk_seccreate(servername, pkey, window, hostname, ckey, NULL);
+ return (nauth);
+ }
+fallback:
+ return authdes_pk_seccreate(servername, pkey, window, NULL, ckey, NULL);
+}
+#else
+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 */
+{ return (NULL); }
+
+AUTH *
+authdes_pk_create(servername, pkey, window, syncaddr, ckey)
+ char *servername; /* network name of server */
+ netobj *pkey; /* public key */
+ u_int window; /* time to live */
+ struct sockaddr *syncaddr; /* optional hostaddr to sync with */
+ des_block *ckey; /* optional conversation key to use */
+{ return (NULL); }
+
+AUTH *
+authdes_seccreate(const char *servername, const u_int win,
+ const char *timehost, const des_block *ckey)
+{
+ return (NULL);
+}
+
+#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;
+ int *sockp;
+ u_int sendsz;
+ u_int recvsz;
+{
+ struct netbuf svcaddr = {0, 0, NULL};
+ CLIENT *cl = NULL;
+ int len;
+
+ memset(&svcaddr, 0, sizeof(svcaddr));
+ if (__rpc_set_netbuf(&svcaddr, raddr, sizeof(*raddr)) == NULL) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ return(cl);
+ }
+ if (*sockp < 0) {
+ *sockp = socket(AF_LOCAL, SOCK_STREAM, 0);
+ len = SUN_LEN(raddr);
+ if ((*sockp < 0) || (connect(*sockp,
+ (struct sockaddr *)raddr, len) < 0)) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ rpc_createerr.cf_error.re_errno = errno;
+ if (*sockp != -1)
+ (void)close(*sockp);
+ goto done;
+ }
+ }
+ cl = clnt_vc_create(*sockp, &svcaddr, prog,
+ vers, sendsz, recvsz);
+done:
+ free(svcaddr.buf);
+ return(cl);
+}
+
+/*
+ * Creates, registers, and returns a (rpc) unix based transporter.
+ * Obsoleted by svc_vc_create().
+ */
+SVCXPRT *
+svcunix_create(sock, sendsize, recvsize, path)
+ int 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) {
+ endnetconfig(localhandle);
+ return(xprt);
+ }
+
+ if ((sock = __rpc_nconf2fd(nconf)) < 0)
+ goto done;
+
+ memset(&sun, 0, sizeof sun);
+ sun.sun_family = AF_LOCAL;
+ strncpy(sun.sun_path, path, (sizeof(sun.sun_path)-1));
+ addrlen = sizeof(struct sockaddr_un);
+ sa = (struct sockaddr *)&sun;
+
+ if (bind(sock, sa, addrlen) < 0)
+ 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) < 0) {
+ free(taddr.addr.buf);
+ goto done;
+ }
+ }
+
+ xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);
+ if (xprt == NULL)
+ close(sock);
+
+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)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+ return (svc_fd_create(fd, sendsize, recvsize));
+}
+
+#endif /* PORTMAP */
diff --git a/src/rpcb_clnt.c b/src/rpcb_clnt.c
new file mode 100644
index 0000000..68fe69a
--- /dev/null
+++ b/src/rpcb_clnt.c
@@ -0,0 +1,1398 @@
+/*
+ * Copyright (c) 2010, Oracle America, 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 the "Oracle America, 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.
+ */
+
+/*
+ * rpcb_clnt.c
+ * interface to rpcbind rpc service.
+ */
+#include <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/utsname.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/nettype.h>
+#include <netconfig.h>
+#ifdef PORTMAP
+#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
+#include <rpc/pmap_prot.h>
+#endif /* PORTMAP */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <assert.h>
+
+#include "rpc_com.h"
+#include "debug.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 *copy_of_cached(const char *, 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
+
+/*
+ * Destroys a cached address entry structure.
+ *
+ */
+static void
+destroy_addr(addr)
+ struct address_cache *addr;
+{
+ if (addr == NULL)
+ return;
+ if (addr->ac_host != NULL) {
+ free(addr->ac_host);
+ addr->ac_host = NULL;
+ }
+ if (addr->ac_netid != NULL) {
+ free(addr->ac_netid);
+ addr->ac_netid = NULL;
+ }
+ if (addr->ac_uaddr != NULL) {
+ free(addr->ac_uaddr);
+ addr->ac_uaddr = NULL;
+ }
+ if (addr->ac_taddr != NULL) {
+ if(addr->ac_taddr->buf != NULL) {
+ free(addr->ac_taddr->buf);
+ addr->ac_taddr->buf = NULL;
+ }
+ addr->ac_taddr = NULL;
+ }
+ free(addr);
+ addr = NULL;
+}
+
+/*
+ * Creates an unlinked copy of an address cache entry. If the argument is NULL
+ * or the new entry cannot be allocated then NULL is returned.
+ */
+static struct address_cache *
+copy_addr(addr)
+ const struct address_cache *addr;
+{
+ struct address_cache *copy;
+
+ if (addr == NULL)
+ return (NULL);
+
+ copy = calloc(1, sizeof(*addr));
+ if (copy == NULL)
+ return (NULL);
+
+ if (addr->ac_host != NULL) {
+ copy->ac_host = strdup(addr->ac_host);
+ if (copy->ac_host == NULL)
+ goto err;
+ }
+ if (addr->ac_netid != NULL) {
+ copy->ac_netid = strdup(addr->ac_netid);
+ if (copy->ac_netid == NULL)
+ goto err;
+ }
+ if (addr->ac_uaddr != NULL) {
+ copy->ac_uaddr = strdup(addr->ac_uaddr);
+ if (copy->ac_uaddr == NULL)
+ goto err;
+ }
+
+ if (addr->ac_taddr == NULL)
+ return (copy);
+
+ copy->ac_taddr = calloc(1, sizeof(*addr->ac_taddr));
+ if (copy->ac_taddr == NULL)
+ goto err;
+
+ memcpy(copy->ac_taddr, addr->ac_taddr, sizeof(*addr->ac_taddr));
+ copy->ac_taddr->buf = malloc(addr->ac_taddr->len);
+ if (copy->ac_taddr->buf == NULL)
+ goto err;
+
+ memcpy(copy->ac_taddr->buf, addr->ac_taddr->buf, addr->ac_taddr->len);
+ return (copy);
+
+err:
+ destroy_addr(copy);
+ return (NULL);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Protect against concurrent access to the address cache and modifications
+ * (esp. deletions) of cache entries.
+ *
+ * Previously a bidirectional R/W lock was used. However, R/W locking is
+ * dangerous as it allows concurrent modification (e.g. deletion with write
+ * lock) at the same time as the deleted element is accessed via check_cache()
+ * and a read lock). We absolutely need a single mutex for all access to
+ * prevent cache corruption. If the mutexing is restricted to only the
+ * relevant code sections, deadlocking should be avoided even with recursed
+ * client creation.
+ */
+extern pthread_mutex_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 *
+copy_of_cached(host, netid)
+ const char *host;
+ char *netid;
+{
+ struct address_cache *cptr, *copy = NULL;
+
+ mutex_lock(&rpcbaddr_cache_lock);
+ for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
+ if (!strcmp(cptr->ac_host, host) &&
+ !strcmp(cptr->ac_netid, netid)) {
+ LIBTIRPC_DEBUG(3, ("check_cache: Found cache entry for %s: %s\n",
+ host, netid));
+ copy = copy_addr(cptr);
+ break;
+ }
+ }
+ mutex_unlock(&rpcbaddr_cache_lock);
+ return copy;
+}
+
+static void
+delete_cache(addr)
+ struct netbuf *addr;
+{
+ struct address_cache *cptr = NULL, *prevptr = NULL;
+
+ /* LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
+ mutex_lock(&rpcbaddr_cache_lock);
+
+ for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
+ if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
+ /* Unlink from cache. We'll destroy it after releasing the mutex. */
+ if (cptr->ac_uaddr) {
+ free(cptr->ac_uaddr);
+ cptr->ac_uaddr = NULL;
+ }
+ if (prevptr) {
+ prevptr->ac_next = cptr->ac_next;
+ } else {
+ front = cptr->ac_next;
+ }
+ cachesize--;
+ break;
+ }
+ prevptr = cptr;
+ }
+
+ mutex_unlock(&rpcbaddr_cache_lock);
+ destroy_addr(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))
+ goto out_free;
+ 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)
+ goto out_free;
+ memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
+ LIBTIRPC_DEBUG(3, ("add_cache: Added to cache: %s : %s\n", host, netid));
+
+/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
+
+ mutex_lock(&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;
+ }
+
+ LIBTIRPC_DEBUG(3, ("add_cache: Deleted from cache: %s : %s\n",
+ cptr->ac_host, cptr->ac_netid));
+ 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);
+ }
+ mutex_unlock(&rpcbaddr_cache_lock);
+ return;
+
+out_free:
+ free(ad_cache->ac_host);
+ free(ad_cache->ac_netid);
+ free(ad_cache->ac_uaddr);
+ free(ad_cache->ac_taddr);
+ free(ad_cache);
+}
+
+
+/*
+ * 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 taddr;
+ struct __rpc_sockinfo si;
+ struct addrinfo hints, *res, *tres;
+ char *tmpaddr;
+
+ if (nconf == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return NULL;
+ }
+
+ if (nconf->nc_protofmly != NULL &&
+ strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
+ host == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+ return NULL;
+ }
+
+
+
+ /* Get the address of the rpcbind. Check cache first */
+ client = NULL;
+ if (targaddr)
+ *targaddr = NULL;
+
+ if (host != NULL) {
+ struct address_cache *ad_cache;
+
+ /* Get an MT-safe copy of the cached address (if any) */
+ ad_cache = copy_of_cached(host, nconf->nc_netid);
+ if (ad_cache != NULL) {
+ client = clnt_tli_create(RPC_ANYFD, nconf, ad_cache->ac_taddr,
+ (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
+ if (client != NULL) {
+ if (targaddr && ad_cache->ac_uaddr) {
+ *targaddr = ad_cache->ac_uaddr;
+ ad_cache->ac_uaddr = NULL; /* De-reference before destruction */
+ }
+ destroy_addr(ad_cache);
+ return (client);
+ }
+
+ delete_cache(ad_cache->ac_taddr);
+ destroy_addr(ad_cache);
+ }
+ }
+
+ if (!__rpc_nconf2sockinfo(nconf, &si)) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ assert(client == NULL);
+ goto out_err;
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = si.si_af;
+ hints.ai_socktype = si.si_socktype;
+ hints.ai_protocol = si.si_proto;
+
+ LIBTIRPC_DEBUG(3, ("getclnthandle: trying netid %s family %d proto %d socktype %d\n",
+ nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype));
+
+ if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ client = local_rpcb();
+ if (! client) {
+ LIBTIRPC_DEBUG(1, ("getclnthandle: %s",
+ clnt_spcreateerror("local_rpcb failed")));
+ goto out_err;
+ } else {
+ struct sockaddr_un sun;
+
+ if (targaddr) {
+ *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;
+ assert(client == NULL);
+ goto out_err;
+ }
+ }
+
+ for (tres = res; tres != NULL; tres = tres->ai_next) {
+ taddr.buf = tres->ai_addr;
+ taddr.len = taddr.maxlen = tres->ai_addrlen;
+
+ if (libtirpc_debug_level > 3 && log_stderr) {
+ char *ua;
+ int i;
+
+ ua = taddr2uaddr(nconf, &taddr);
+ fprintf(stderr, "Got it [%s]\n", ua);
+ free(ua);
+
+ 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");
+ }
+
+ client = clnt_tli_create(RPC_ANYFD, nconf, &taddr,
+ (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
+ if (! client) {
+ LIBTIRPC_DEBUG(1, ("getclnthandle: %s",
+ clnt_spcreateerror("clnt_tli_create failed")));
+ }
+
+ if (client) {
+ tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL;
+ if (host)
+ add_cache(host, nconf->nc_netid, &taddr, tmpaddr);
+ if (targaddr)
+ *targaddr = tmpaddr;
+ break;
+ }
+ }
+ if (res)
+ freeaddrinfo(res);
+out_err:
+ if (!client && targaddr)
+ free(*targaddr);
+ return (client);
+}
+
+/*
+ * Create a PMAP client handle.
+ */
+static CLIENT *
+getpmaphandle(nconf, hostname, tgtaddr)
+ const struct netconfig *nconf;
+ const char *hostname;
+ char **tgtaddr;
+{
+ CLIENT *client = NULL;
+ rpcvers_t pmapvers = 2;
+
+ if (nconf == NULL) {
+ struct netconfig *newnconf;
+
+ if ((newnconf = getnetconfigent("udp")) == NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return NULL;
+ }
+ client = getclnthandle(hostname, newnconf, tgtaddr);
+ freenetconfigent(newnconf);
+ } else if (strcmp(nconf->nc_proto, NC_UDP) == 0 ||
+ strcmp(nconf->nc_proto, NC_TCP) == 0) {
+ if (strcmp(nconf->nc_protofmly, NC_INET) != 0)
+ return NULL;
+ client = getclnthandle(hostname, nconf, tgtaddr);
+ }
+
+ /* Set version */
+ if (client != NULL)
+ CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
+
+ 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;
+ int 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_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ goto try_nconf;
+ sun.sun_family = AF_LOCAL;
+ 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_LOCAL, 0, 0);
+ client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG,
+ (rpcvers_t)RPCBVERS, tsize, tsize);
+
+ 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. */
+ close(sock);
+
+try_nconf:
+
+/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
+ mutex_lock(&loopnconf_lock);
+ if (loopnconf == NULL) {
+ struct netconfig *nconf, *tmpnconf = NULL;
+ void *nc_handle;
+ int 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 < 0)
+ continue;
+ close(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);
+ endnetconfig(nc_handle);
+ 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", 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", 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);
+ LIBTIRPC_DEBUG(3, ("got_entry: Remote address is [%s] %s",
+ rmap->r_maddr, (na ? "Resolvable" : "Not Resolvable")));
+ break;
+ }
+ }
+ return (na);
+}
+
+/*
+ * 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;
+ int 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_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0)
+ return (FALSE);
+ sun.sun_family = AF_LOCAL;
+ strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path));
+
+ if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
+ close(sock);
+ return (FALSE);
+ }
+
+ close(sock);
+ return (TRUE);
+}
+#endif
+
+#ifdef PORTMAP
+static struct netbuf *
+__try_protocol_version_2(program, version, nconf, host, tp)
+ rpcprog_t program;
+ rpcvers_t version;
+ const struct netconfig *nconf;
+ const char *host;
+ struct timeval *tp;
+{
+ u_short port = 0;
+ struct netbuf remote;
+ struct pmap pmapparms;
+ CLIENT *client = NULL;
+ enum clnt_stat clnt_st;
+ struct netbuf *pmapaddress;
+ RPCB parms;
+
+ if (strcmp(nconf->nc_proto, NC_UDP) != 0
+ && strcmp(nconf->nc_proto, NC_TCP) != 0)
+ return (NULL);
+
+ client = getpmaphandle(nconf, host, &parms.r_addr);
+ if (client == NULL)
+ goto error;
+
+ /*
+ * Set retry timeout.
+ */
+ CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+
+ 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) {
+ rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ goto error;
+ } else if (port == 0) {
+ pmapaddress = NULL;
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ goto error;
+ }
+ port = htons(port);
+ CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
+ if (((pmapaddress = (struct netbuf *)
+ malloc(sizeof (struct netbuf))) == NULL) ||
+ ((pmapaddress->buf = (char *)
+ malloc(remote.len)) == NULL)) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ if (pmapaddress) {
+ free(pmapaddress);
+ pmapaddress = NULL;
+ }
+ goto error;
+ }
+ memcpy(pmapaddress->buf, remote.buf, remote.len);
+ memcpy(&((char *)pmapaddress->buf)[sizeof (short)],
+ (char *)(void *)&port, sizeof (short));
+ pmapaddress->len = pmapaddress->maxlen = remote.len;
+
+ CLNT_DESTROY(client);
+
+ if (parms.r_addr != NULL && parms.r_addr != nullstring)
+ free(parms.r_addr);
+
+ return pmapaddress;
+
+error:
+ if (client) {
+ CLNT_DESTROY(client);
+ client = NULL;
+
+ }
+
+ if (parms.r_addr != NULL && parms.r_addr != nullstring)
+ free(parms.r_addr);
+
+ return (NULL);
+
+}
+#endif
+
+/*
+ * 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 4 (srv4), then 3 and then fall back to version 2 (portmap).
+ * With this algorithm, we get performance as well as a plan for
+ * obsoleting version 2. This behaviour is reverted to old algorithm
+ * if RPCB_V2FIRST environment var is defined
+ *
+ * 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
+
+#ifdef PORTMAP
+ static bool_t portmap_first = FALSE;
+#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;
+ struct rpc_err rpcerr;
+
+ /* 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;
+
+ 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), except
+ * if env. var RPCB_V2FIRST is defined */
+
+#ifdef PORTMAP
+ if (getenv(V2FIRST)) {
+ portmap_first = TRUE;
+ LIBTIRPC_DEBUG(3, ("__rpcb_findaddr_timed: trying v2-port first\n"));
+ goto portmap;
+ }
+#endif
+
+rpcbind:
+ 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);
+ switch (clnt_st) {
+ case RPC_SUCCESS:
+ if ((ua == NULL) || (ua[0] == 0)) {
+ /* address unknown */
+ rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+ goto error;
+ }
+ address = uaddr2taddr(nconf, ua);
+ LIBTIRPC_DEBUG(3, ("__rpcb_findaddr_timed: Remote address is [%s] %s",
+ ua, (address ? "Resolvable" : "Not Resolvable")));
+
+ 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;
+ case RPC_PROGVERSMISMATCH:
+ clnt_geterr(client, &rpcerr);
+ if (rpcerr.re_vers.low > RPCBVERS4)
+ goto error; /* a new version, can't handle */
+ /* Try the next lower version */
+ case RPC_PROGUNAVAIL:
+ case RPC_CANTDECODEARGS:
+ break;
+ default:
+ /* Cant handle this error */
+ rpc_createerr.cf_stat = clnt_st;
+ clnt_geterr(client, &rpc_createerr.cf_error);
+ goto error;
+ }
+ }
+
+#ifdef PORTMAP /* Try version 2 for TCP or UDP */
+ if (portmap_first)
+ goto error; /* we tried all versions if reached here */
+portmap:
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+ address = __try_protocol_version_2(program, version, nconf, host, tp);
+ if (address == NULL) {
+ if (portmap_first)
+ goto rpcbind;
+ else
+ goto error;
+ }
+ }
+#endif /* PORTMAP */
+
+ 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);
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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/src/rpcb_prot.c b/src/rpcb_prot.c
new file mode 100644
index 0000000..a923c8e
--- /dev/null
+++ b/src/rpcb_prot.c
@@ -0,0 +1,324 @@
+
+/*
+ * 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 <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpcb_prot.h>
+#include "rpc_com.h"
+
+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, RPC_MAXDATASIZE)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_addr, RPC_MAXDATASIZE)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_owner, RPC_MAXDATASIZE)) {
+ 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, RPC_MAXDATASIZE)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_nc_netid, RPC_MAXDATASIZE)) {
+ return (FALSE);
+ }
+ if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_nc_protofmly, RPC_MAXDATASIZE)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->r_nc_proto, RPC_MAXDATASIZE)) {
+ 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, RPC_MAXDATASIZE)) {
+ 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);
+ }
+
+ if (objp->maxlen > RPC_MAXDATASIZE) {
+ return (FALSE);
+ }
+
+ dummy = xdr_bytes(xdrs, (char **)&(objp->buf),
+ (u_int *)&(objp->len), objp->maxlen);
+ return (dummy);
+}
diff --git a/src/rpcb_st_xdr.c b/src/rpcb_st_xdr.c
new file mode 100644
index 0000000..28e6a48
--- /dev/null
+++ b/src/rpcb_st_xdr.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.
+ */
+/*
+ * 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 <rpc/rpc.h>
+#include "rpc_com.h"
+
+/* 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, RPC_MAXDATASIZE)) {
+ 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, RPC_MAXDATASIZE)) {
+ 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, RPC_MAXDATASIZE)) {
+ 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, RPC_MAXDATASIZE)) {
+ 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/src/rpcdname.c b/src/rpcdname.c
new file mode 100644
index 0000000..3e6a988
--- /dev/null
+++ b/src/rpcdname.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+/*
+ * rpcdname.c
+ * Gets the default domain name
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+static char *default_domain = 0;
+
+static char *
+get_default_domain()
+{
+ char temp[256];
+
+ if (default_domain)
+ return (default_domain);
+ 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 (0);
+ (void) strcpy(default_domain, temp);
+ return (default_domain);
+ }
+ return (0);
+}
+
+/*
+ * 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/src/rtime.c b/src/rtime.c
new file mode 100644
index 0000000..29fbf0a
--- /dev/null
+++ b/src/rtime.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.
+ */
+
+/*
+ * 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 <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/select.h>
+
+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( int );
+
+int
+rtime(addrp, timep, timeout)
+ struct sockaddr_in *addrp;
+ struct timeval *timep;
+ struct timeval *timeout;
+{
+ int s;
+ struct pollfd fd;
+ int milliseconds;
+ int res;
+ unsigned long thetime;
+ struct sockaddr_in from;
+ socklen_t fromlen;
+ int type;
+ struct servent *serv;
+
+ if (timeout == NULL) {
+ type = SOCK_STREAM;
+ } else {
+ type = SOCK_DGRAM;
+ }
+ s = socket(AF_INET, type, 0);
+ if (s < 0) {
+ return(-1);
+ }
+ addrp->sin_family = AF_INET;
+
+ /* TCP and UDP port are the same in this case */
+ if ((serv = getservbyname("time", "tcp")) == NULL) {
+ do_close(s);
+ 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 < 0) {
+ do_close(s);
+ return(-1);
+ }
+
+ milliseconds = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
+ fd.fd = s;
+ fd.events = POLLIN;
+ do
+ res = poll (&fd, 1, milliseconds);
+ while (res < 0 && errno == EINTR);
+ if (res <= 0) {
+ if (res == 0) {
+ errno = ETIMEDOUT;
+ }
+ 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 < 0) {
+ return(-1);
+ }
+ } else {
+ if (connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) < 0) {
+ do_close(s);
+ return(-1);
+ }
+ res = read(s, (char *)&thetime, sizeof(thetime));
+ do_close(s);
+ if (res < 0) {
+ 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)close(s);
+ errno = save;
+}
diff --git a/src/svc.c b/src/svc.c
new file mode 100644
index 0000000..3a8709f
--- /dev/null
+++ b/src/svc.c
@@ -0,0 +1,821 @@
+
+/*
+ * 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 <pthread.h>
+
+#include <reentrant.h>
+#include <sys/types.h>
+#include <poll.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#ifdef PORTMAP
+#include <rpc/pmap_clnt.h>
+#endif /* PORTMAP */
+
+#include "rpc_com.h"
+
+#define RQCRED_SIZE 400 /* this size is excessive */
+
+#define max(a, b) (a > b ? a : b)
+
+SVCXPRT **__svc_xports;
+int __svc_maxrec;
+
+/*
+ * 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;
+
+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;
+{
+ int sock;
+
+ assert (xprt != NULL);
+
+ sock = xprt->xp_fd;
+
+ rwlock_wrlock (&svc_fd_lock);
+ if (__svc_xports == NULL)
+ {
+ __svc_xports = (SVCXPRT **) calloc (_rpc_dtablesize(), sizeof (SVCXPRT *));
+ if (__svc_xports == NULL)
+ goto unlock;
+ }
+ if (sock < _rpc_dtablesize())
+ {
+ int i;
+ struct pollfd *new_svc_pollfd;
+
+ __svc_xports[sock] = xprt;
+ if (sock < FD_SETSIZE)
+ {
+ FD_SET (sock, &svc_fdset);
+ svc_maxfd = max (svc_maxfd, sock);
+ }
+
+ /* Check if we have an empty slot */
+ for (i = 0; i < svc_max_pollfd; ++i)
+ if (svc_pollfd[i].fd == -1)
+ {
+ svc_pollfd[i].fd = sock;
+ svc_pollfd[i].events = (POLLIN | POLLPRI |
+ POLLRDNORM | POLLRDBAND);
+ goto unlock;
+ }
+
+ new_svc_pollfd = (struct pollfd *) realloc (svc_pollfd,
+ sizeof (struct pollfd)
+ * (svc_max_pollfd + 1));
+ if (new_svc_pollfd == NULL) /* Out of memory */
+ goto unlock;
+ svc_pollfd = new_svc_pollfd;
+ ++svc_max_pollfd;
+
+ svc_pollfd[svc_max_pollfd - 1].fd = sock;
+ svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
+ POLLRDNORM | POLLRDBAND);
+ }
+unlock:
+ 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;
+{
+ int sock;
+
+ assert (xprt != NULL);
+
+ sock = xprt->xp_fd;
+
+ if (dolock)
+ rwlock_wrlock (&svc_fd_lock);
+ if ((sock < _rpc_dtablesize() ) && (__svc_xports[sock] == xprt))
+ {
+ int i;
+
+ __svc_xports[sock] = NULL;
+ if (sock < FD_SETSIZE)
+ {
+ FD_CLR (sock, &svc_fdset);
+ if (sock >= svc_maxfd)
+ {
+ for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--)
+ if (__svc_xports[svc_maxfd])
+ break;
+ }
+ }
+
+ for (i = 0; i < svc_max_pollfd; ++i)
+ if (svc_pollfd[i].fd == sock)
+ svc_pollfd[i].fd = -1;
+ }
+ if (dolock)
+ rwlock_unlock (&svc_fd_lock);
+}
+
+int
+svc_open_fds()
+{
+ int ix;
+ int nfds = 0;
+
+ rwlock_rdlock (&svc_fd_lock);
+ for (ix = 0; ix < svc_max_pollfd; ++ix) {
+ if (svc_pollfd[ix].fd != -1)
+ nfds++;
+ }
+ rwlock_unlock (&svc_fd_lock);
+ return (nfds);
+}
+
+/*
+ * 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;
+{
+ svc_flags (xprt) |= SVC_VERSQUIET;
+}
+
+void
+__svc_versquiet_off (xprt)
+ SVCXPRT *xprt;
+{
+ svc_flags (xprt) &= ~SVC_VERSQUIET;
+}
+
+void
+svc_versquiet (xprt)
+ SVCXPRT *xprt;
+{
+ __svc_versquiet_on (xprt);
+}
+
+int
+__svc_versquiet_get (xprt)
+ SVCXPRT *xprt;
+{
+ return version_keepquiet (xprt);
+}
+#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);
+ readfds.fds_bits[0] = rdfds;
+ svc_getreqset (&readfds);
+}
+
+void
+svc_getreqset (readfds)
+ fd_set *readfds;
+{
+ int bit, fd;
+ fd_mask mask, *maskp;
+ int sock;
+ int setsize;
+
+ assert (readfds != NULL);
+
+ setsize = _rpc_dtablesize ();
+ if (setsize > FD_SETSIZE)
+ setsize = FD_SETSIZE;
+ maskp = readfds->fds_bits;
+ for (sock = 0; sock < setsize; sock += NFDBITS)
+ {
+ for (mask = *maskp++; (bit = ffsl(mask)) != 0; mask ^= (1L << (bit - 1)))
+ {
+ /* sock has input waiting */
+ fd = sock + bit - 1;
+ svc_getreq_common (fd);
+ }
+ }
+}
+
+void
+svc_getreq_common (fd)
+ int 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))
+ {
+ bool_t no_dispatch;
+
+ /* 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 */
+ why = _gss_authenticate(&r, &msg, &no_dispatch);
+ if (why != AUTH_OK)
+ {
+ svcerr_auth (xprt, why);
+ goto call_done;
+ }
+ if (no_dispatch)
+ 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;
+ }
+ }
+ while (stat == XPRT_MOREREQS);
+}
+
+
+void
+svc_getreq_poll (pfdp, pollretval)
+ struct pollfd *pfdp;
+ int pollretval;
+{
+ int fds_found, i;
+
+ for (i = fds_found = 0; i < svc_max_pollfd; ++i)
+ {
+ struct pollfd *p = &pfdp[i];
+
+ if (p->fd != -1 && p->revents)
+ {
+ /* fd has input waiting */
+ if (p->revents & POLLNVAL)
+ xprt_unregister (__svc_xports[p->fd]);
+ else
+ svc_getreq_common (p->fd);
+
+ if (++fds_found >= pollretval)
+ break;
+ }
+ }
+}
+
+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/src/svc_auth.c b/src/svc_auth.c
new file mode 100644
index 0000000..789d6af
--- /dev/null
+++ b/src/svc_auth.c
@@ -0,0 +1,219 @@
+
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/auth_des.h>
+#include <stdlib.h>
+
+/*
+ * 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;
+
+extern SVCAUTH svc_auth_none;
+
+#ifdef AUTHDES_SUPPORT
+extern enum auth_stat _svcauth_des(struct svc_req *rqst, struct rpc_msg *msg);
+#endif
+/*
+ * 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
+_gss_authenticate(rqst, msg, no_dispatch)
+ struct svc_req *rqst;
+ struct rpc_msg *msg;
+ bool_t *no_dispatch;
+{
+ 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;
+ SVC_XP_AUTH(rqst->rq_xprt).svc_ah_ops = svc_auth_none.svc_ah_ops;
+ SVC_XP_AUTH(rqst->rq_xprt).svc_ah_private = NULL;
+ 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;
+ *no_dispatch = FALSE;
+ switch (cred_flavor) {
+ case AUTH_NONE:
+ dummy = _svcauth_none(rqst, msg);
+ return (dummy);
+ case AUTH_SYS:
+ dummy = _svcauth_unix(rqst, msg);
+ return (dummy);
+ case AUTH_SHORT:
+ dummy = _svcauth_short(rqst, msg);
+ return (dummy);
+ case AUTH_DES:
+#ifdef AUTHDES_SUPPORT
+ dummy = _svcauth_des(rqst, msg);
+ return (dummy);
+#else
+ return (AUTH_FAILED);
+#endif
+#ifdef HAVE_RPCSEC_GSS
+ case RPCSEC_GSS:
+ dummy = _svcauth_gss(rqst, msg, no_dispatch);
+ 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);
+}
+
+enum auth_stat
+_authenticate(struct svc_req *rqst, struct rpc_msg *msg)
+{
+ bool_t no_dispatch;
+ return _gss_authenticate(rqst, msg, &no_dispatch);
+}
+
+/*
+ * 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:
+ case AUTH_DES:
+#ifndef AUTHDES_SUPPORT
+ return(-1);
+#endif
+#ifdef HAVE_RPCSEC_GSS
+ case RPCSEC_GSS:
+#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/src/svc_auth_des.c b/src/svc_auth_des.c
new file mode 100644
index 0000000..b096e08
--- /dev/null
+++ b/src/svc_auth_des.c
@@ -0,0 +1,529 @@
+
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <rpc/des_crypt.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_des.h>
+#include <rpc/svc.h>
+#include <rpc/rpc_msg.h>
+#include <rpc/svc_auth.h>
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+#include <libc_private.h>
+#endif
+
+#include "debug.h"
+
+extern int key_decryptsession_pk(const char *, netobj *, des_block *);
+
+#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(des_block *key, char *name, struct timeval *timestamp); /* find an entry in the cache */
+static void cache_ref(short sid); /* note that sid was ref'd */
+
+static void invalidate(char *cred); /* 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;
+ memcpy(cred->adc_fullname.name, (char *)ixdr,
+ (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)) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: getpublickey failed"));
+ 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) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: key_decryptsessionkey failed"));
+ return (AUTH_BADCRED); /* key not found */
+ }
+ } else { /* ADN_NICKNAME */
+ sid = (short)cred->adc_nickname;
+ if (sid < 0 || sid >= AUTHDES_CACHESZ) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: 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)) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: 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) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: window verifier mismatch"));
+ return (AUTH_BADCRED); /* garbled credential */
+ }
+ sid = cache_spot(sessionkey, cred->adc_fullname.name,
+ &timestamp);
+ if (sid < 0) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: 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) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: invalid usecs"));
+ /* cached out (bad key), or garbled verifier */
+ return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
+ }
+ if (nick && BEFORE(&timestamp,
+ &authdes_cache[sid].laststamp)) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: timestamp before last seen"));
+ return (AUTH_REJECTEDVERF); /* replay */
+ }
+ (void) gettimeofday(&current, (struct timezone *)NULL);
+ current.tv_sec -= window; /* allow for expiration */
+ if (!BEFORE(&current, &timestamp)) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: 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)) {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: 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 {
+ LIBTIRPC_DEBUG(1, ("_svcauth_des: 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);
+ memset(authdes_cache, 0,
+ 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 &&
+ memcmp(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 */
+}
+
+
+/*
+ * 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) {
+ LIBTIRPC_DEBUG(1, ("authdes_getucred: 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))
+ {
+ LIBTIRPC_DEBUG(1, ("authdes_getucred: unknown netname"));
+ cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */
+ return (0);
+ }
+ LIBTIRPC_DEBUG(1, ("authdes_getucred: 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;
+}
diff --git a/src/svc_auth_gss.c b/src/svc_auth_gss.c
new file mode 100644
index 0000000..bece46a
--- /dev/null
+++ b/src/svc_auth_gss.c
@@ -0,0 +1,1180 @@
+/*
+ svc_auth_gss.c
+
+ Copyright (c) 2000 The Regents of the University of Michigan.
+ All rights reserved.
+
+ Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+ 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 <sys/types.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <rpc/rpc.h>
+#include <rpc/auth_gss.h>
+#include <rpc/svc_auth_gss.h>
+#include <rpc/rpcsec_gss.h>
+
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
+/* MIT Kerberos */
+#include <gssapi/gssapi_ext.h>
+#else
+/* Heimdal Kerberos */
+#include <gssapi/gssapi.h>
+#endif
+
+#include <reentrant.h>
+
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+
+extern SVCAUTH svc_auth_none;
+
+/* Internal only */
+bool_t rpc_gss_oid_to_mech(rpc_gss_OID, char **);
+bool_t rpc_gss_num_to_qop(char *, u_int, char **);
+
+/*
+ * 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_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t svcauth_gss_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t svcauth_gss_destroy(SVCAUTH *);
+
+static struct svc_auth_ops svc_auth_gss_ops = {
+ svcauth_gss_wrap,
+ svcauth_gss_unwrap,
+ svcauth_gss_destroy
+};
+
+struct svcauth_gss_cache_entry {
+ SVCXPRT *xprt;
+ struct svc_rpc_gss_data *gd;
+ time_t time_to_die;
+ struct svcauth_gss_cache_entry *next;
+};
+
+extern pthread_mutex_t svcauth_gss_cache_lock;
+static struct svcauth_gss_cache_entry *svcauth_gss_cache = NULL;
+
+struct svc_rpc_gss_callback {
+ struct svc_rpc_gss_callback *cb_next;
+ rpc_gss_callback_t cb_args;
+};
+
+extern pthread_mutex_t svcauth_cb_lock;
+static struct svc_rpc_gss_callback *_svcauth_callbacks = NULL;
+
+struct svc_rpc_gss_data {
+ bool_t established; /* context established */
+ bool_t locked; /* service/qop unchanging */
+ gss_ctx_id_t ctx; /* context id */
+ gss_cred_id_t deleg; /* delegated creds */
+ 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 */
+ rpc_gss_rawcred_t rcred; /* internal raw credential */
+ rpc_gss_rawcred_t scratch; /* copy exposed to user */
+ rpc_gss_ucred_t ucred; /* cooked credential */
+ gid_t gids[NGRPS]; /* list of groups */
+ bool_t callback_done; /* TRUE after callback */
+ void * cookie; /* callback cookie */
+};
+
+#define SVCAUTH_PRIVATE(auth) \
+ ((struct svc_rpc_gss_data *)(auth)->svc_ah_private)
+
+/* Global server credentials. */
+static u_int _svcauth_req_time = 0;
+static gss_OID_set_desc _svcauth_oid_set = {1, GSS_C_NULL_OID };
+static gss_cred_id_t _svcauth_gss_creds;
+static gss_name_t _svcauth_gss_name = GSS_C_NO_NAME;
+static char * _svcauth_svc_name = NULL;
+
+bool_t
+svcauth_gss_set_svc_name(gss_name_t name)
+{
+ OM_uint32 maj_stat, min_stat;
+
+ gss_log_debug("in svcauth_gss_set_svc_name()");
+
+ if (_svcauth_gss_name != GSS_C_NO_NAME) {
+ maj_stat = gss_release_name(&min_stat, &_svcauth_gss_name);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("svcauth_gss_set_svc_name: gss_release_name",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ _svcauth_gss_name = GSS_C_NO_NAME;
+ }
+ maj_stat = gss_duplicate_name(&min_stat, name, &_svcauth_gss_name);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("svcauth_gss_set_svc_name: 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;
+ bool_t result;
+
+ gss_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) {
+ gss_log_status("svcauth_gss_import_name: gss_import_name",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ result = svcauth_gss_set_svc_name(name);
+ gss_release_name(&min_stat, &name);
+ return result;
+}
+
+static bool_t
+svcauth_gss_acquire_cred(void)
+{
+ OM_uint32 maj_stat, min_stat;
+
+ gss_log_debug("in svcauth_gss_acquire_cred()");
+
+ maj_stat = gss_acquire_cred(&min_stat, _svcauth_gss_name,
+ _svcauth_req_time, &_svcauth_oid_set,
+ GSS_C_ACCEPT,
+ &_svcauth_gss_creds, NULL, NULL);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("svcauth_gss_acquire_cred: 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;
+
+ gss_log_debug("in svcauth_gss_release_cred()");
+
+ maj_stat = gss_release_cred(&min_stat, &_svcauth_gss_creds);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("svcauth_gss_release_cred: gss_release_cred",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+
+ _svcauth_gss_creds = NULL;
+
+ return (TRUE);
+}
+
+static rpc_gss_service_t
+_rpc_gss_svc_to_service(rpc_gss_svc_t svc)
+{
+ switch (svc) {
+ case RPCSEC_GSS_SVC_NONE:
+ return rpcsec_gss_svc_none;
+ case RPCSEC_GSS_SVC_INTEGRITY:
+ return rpcsec_gss_svc_integrity;
+ case RPCSEC_GSS_SVC_PRIVACY:
+ return rpcsec_gss_svc_privacy;
+ }
+ return rpcsec_gss_svc_default;
+}
+
+static bool_t
+_rpc_gss_fill_in_creds(struct svc_rpc_gss_data *gd, struct rpc_gss_cred *gc)
+{
+ rpc_gss_rawcred_t *rcred = &gd->rcred;
+
+ rcred->version = gc->gc_v;
+ if (!rpc_gss_oid_to_mech(gd->sec.mech, &rcred->mechanism))
+ return FALSE;
+ rcred->service = _rpc_gss_svc_to_service(gd->sec.svc);
+
+ rcred->client_principal = calloc(1, sizeof(rpc_gss_principal_t) +
+ gd->cname.length);
+ if (rcred->client_principal == NULL)
+ return FALSE;
+
+ rcred->client_principal->len = gd->cname.length;
+ (void)memcpy(rcred->client_principal->name,
+ gd->cname.value, gd->cname.length);
+
+ rcred->svc_principal = _svcauth_svc_name;
+
+ 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;
+
+ gss_log_debug("in svcauth_gss_accept_context()");
+
+ gd = SVCAUTH_PRIVATE(&SVC_XP_AUTH(rqst->rq_xprt));
+ 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,
+ &gd->deleg);
+
+ xdr_free((xdrproc_t)xdr_rpc_gss_init_args, (caddr_t)&recv_tok);
+
+ if (gr->gr_major != GSS_S_COMPLETE &&
+ gr->gr_major != GSS_S_CONTINUE_NEEDED) {
+ gss_log_status("svcauth_gss_accept_sec_context: 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;
+ gd->callback_done = FALSE;
+
+ 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) {
+ gss_log_status("svcauth_gss_accept_sec_context: display_name",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ if (!_rpc_gss_fill_in_creds(gd, gc))
+ return (FALSE);
+
+ 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;
+ memcpy(rqst->rq_xprt->xp_verf.oa_base, checksum.value,
+ checksum.length);
+ rqst->rq_xprt->xp_verf.oa_length = checksum.length;
+
+ gss_release_buffer(&min_stat, &checksum);
+ }
+ return (TRUE);
+}
+
+static bool_t
+svcauth_gss_validate(struct svc_rpc_gss_data *gd, struct rpc_msg *msg,
+ gss_qop_t *qop)
+{
+ struct opaque_auth *oa;
+ gss_buffer_desc rpcbuf, checksum;
+ OM_uint32 maj_stat, min_stat, qop_state;
+ u_char *rpchdr;
+ int32_t *buf;
+
+ gss_log_debug("in svcauth_gss_validate()");
+
+ /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
+ oa = &msg->rm_call.cb_cred;
+ if (oa->oa_length > MAX_AUTH_BYTES)
+ return (FALSE);
+
+ rpchdr = (u_char *)calloc(((8 * BYTES_PER_XDR_UNIT) +
+ RNDUP(oa->oa_length)), 1);
+ if (rpchdr == NULL)
+ 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);
+
+ free(rpchdr);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("svcauth_gss_validate: gss_verify_mic",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+ *qop = qop_state;
+ return (TRUE);
+}
+
+static 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;
+
+ gss_log_debug("in svcauth_gss_nextverf()");
+
+ gd = SVCAUTH_PRIVATE(&SVC_XP_AUTH(rqst->rq_xprt));
+
+ signbuf.value = &num;
+ signbuf.length = sizeof(num);
+
+ maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
+ &signbuf, &checksum);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("svcauth_gss_nextverf: gss_get_mic",
+ maj_stat, min_stat);
+ return (FALSE);
+ }
+
+ rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
+ memcpy(rqst->rq_xprt->xp_verf.oa_base, checksum.value, checksum.length);
+ rqst->rq_xprt->xp_verf.oa_length = (u_int)checksum.length;
+
+ gss_release_buffer(&min_stat, &checksum);
+
+ return (TRUE);
+}
+
+static bool_t
+svcauth_gss_do_call(struct svc_req *rqst, struct svc_rpc_gss_data *gd,
+ struct svc_rpc_gss_callback *cb)
+{
+ rpc_gss_lock_t lock;
+ bool_t result;
+
+ lock.locked = FALSE;
+ lock.raw_cred = &gd->rcred;
+ result = cb->cb_args.callback(rqst, gd->deleg, gd->ctx,
+ &lock, &gd->cookie);
+ if (result) {
+ gd->locked = lock.locked;
+ gd->deleg = GSS_C_NO_CREDENTIAL;
+ }
+ return result;
+}
+
+static bool_t
+svcauth_gss_callback(struct svc_req *rqst, struct svc_rpc_gss_data *gd)
+{
+ struct svc_rpc_gss_callback *cb;
+ bool_t result;
+
+ result = TRUE;
+ mutex_lock(&svcauth_cb_lock);
+
+ for (cb = _svcauth_callbacks; cb != NULL; cb = cb->cb_next) {
+ if (cb->cb_args.program == rqst->rq_prog &&
+ cb->cb_args.version == rqst->rq_vers) {
+ result = svcauth_gss_do_call(rqst, gd, cb);
+ break;
+ }
+ }
+
+ if (gd->deleg != GSS_C_NO_CREDENTIAL) {
+ OM_uint32 min_stat;
+ (void)gss_release_cred(&min_stat, &gd->deleg);
+ }
+
+ mutex_unlock(&svcauth_cb_lock);
+ return result;
+}
+
+static void
+destroy_gd(struct svc_rpc_gss_data *gd)
+{
+ OM_uint32 min_stat;
+
+ 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);
+ if (gd->rcred.client_principal != NULL)
+ free(gd->rcred.client_principal);
+
+ mem_free(gd, sizeof(*gd));
+}
+
+/* call with svcauth_gss_cache_lock */
+static struct svcauth_gss_cache_entry **
+lookup_cache_entry(struct svc_req *rqst)
+{
+ struct svcauth_gss_cache_entry **ce;
+
+ /*
+ * for now, only one set of gss data per xprt, which is borked,
+ * but that gss data will at least survive if there are
+ * interleaved calls with another cred flavor on the same xprt
+ */
+ for (ce = &svcauth_gss_cache; *ce; ce = &(*ce)->next) {
+ if ((*ce)->xprt == rqst->rq_xprt)
+ break;
+ }
+
+ return (ce);
+}
+
+/* call with svcauth_gss_cache_lock */
+static void
+use_cache_entry(struct svcauth_gss_cache_entry **ce, time_t now)
+{
+ struct svcauth_gss_cache_entry *ce_new_head;
+
+ (*ce)->time_to_die = now + 300; /* 5 minutes */
+
+ if (ce == &svcauth_gss_cache)
+ return; /* ce already at the head */
+
+ ce_new_head = *ce;
+ *ce = (*ce)->next;
+ ce_new_head->next = svcauth_gss_cache;
+ svcauth_gss_cache = ce_new_head;
+}
+
+/* call with svcauth_gss_cache_lock */
+static void
+destroy_cold_cache_entries(time_t now)
+{
+ struct svcauth_gss_cache_entry **ce;
+
+ for (ce = &svcauth_gss_cache; *ce; ce = &(*ce)->next) {
+ if (now > (*ce)->time_to_die)
+ break;
+ }
+
+ while (*ce) {
+ struct svcauth_gss_cache_entry *ce_next = (*ce)->next;
+ destroy_gd((*ce)->gd);
+ mem_free(*ce, sizeof(**ce));
+ *ce = ce_next;
+ }
+}
+
+enum auth_stat
+_svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch)
+{
+ XDR xdrs;
+ struct svc_rpc_gss_data *gd;
+ struct rpc_gss_cred *gc;
+ struct rpc_gss_init_res gr;
+ int call_stat, offset;
+ gss_qop_t qop;
+ struct svcauth_gss_cache_entry **ce;
+ time_t now;
+ enum auth_stat result = AUTH_OK;
+ OM_uint32 min_stat;
+
+ gss_log_debug("in svcauth_gss()");
+
+ /* Initialize reply. */
+ rqst->rq_xprt->xp_verf = _null_auth;
+
+ now = time(NULL);
+ mutex_lock(&svcauth_gss_cache_lock);
+ ce = lookup_cache_entry(rqst);
+ if (!*ce) {
+ /* no cache entry for this xprt, allocate and set it up */
+ if ((*ce = calloc(sizeof(**ce), 1)) == NULL) {
+ fprintf(stderr, "svcauth_gss: out_of_memory\n");
+ mutex_unlock(&svcauth_gss_cache_lock);
+ return (AUTH_FAILED);
+ }
+ if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
+ free(*ce);
+ fprintf(stderr, "svcauth_gss: out_of_memory\n");
+ mutex_unlock(&svcauth_gss_cache_lock);
+ return (AUTH_FAILED);
+ }
+ gd->locked = FALSE;
+ (*ce)->xprt = rqst->rq_xprt;
+ (*ce)->gd = gd;
+ (*ce)->next = NULL;
+ }
+ else
+ gd = (*ce)->gd;
+ use_cache_entry(ce, now);
+ destroy_cold_cache_entries(now);
+ mutex_unlock(&svcauth_gss_cache_lock);
+
+ SVC_XP_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_gss_ops;
+ SVC_XP_AUTH(rqst->rq_xprt).svc_ah_private = (caddr_t) gd;
+
+ /* 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) {
+ result = AUTH_BADCRED;
+ goto out;
+ }
+
+ /* 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) {
+ result = AUTH_BADCRED;
+ goto out;
+ }
+
+ /* Check sequence number. */
+ if (gd->established) {
+ if (gc->gc_seq > MAXSEQ) {
+ result = RPCSEC_GSS_CTXPROBLEM;
+ goto out;
+ }
+
+ 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;
+ result = RPCSEC_GSS_CTXPROBLEM;
+ goto out;
+ }
+ 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;
+ }
+
+ rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
+
+ /* Handle RPCSEC_GSS control procedure. */
+ switch (gc->gc_proc) {
+
+ case RPCSEC_GSS_INIT:
+ case RPCSEC_GSS_CONTINUE_INIT:
+ if (rqst->rq_proc != NULLPROC) {
+ result = AUTH_FAILED; /* XXX ? */
+ break;
+ }
+
+ if (_svcauth_gss_name == GSS_C_NO_NAME) {
+ if (!svcauth_gss_import_name("nfs")) {
+ result = AUTH_FAILED;
+ break;
+ }
+ }
+
+ if (!svcauth_gss_acquire_cred()) {
+ result = AUTH_FAILED;
+ break;
+ }
+
+ if (!svcauth_gss_accept_sec_context(rqst, &gr)) {
+ result = AUTH_REJECTEDCRED;
+ break;
+ }
+
+ if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) {
+ result = AUTH_FAILED;
+ break;
+ }
+
+ *no_dispatch = TRUE;
+
+ call_stat = svc_sendreply(rqst->rq_xprt,
+ (xdrproc_t)xdr_rpc_gss_init_res, (caddr_t)&gr);
+
+ gss_release_buffer(&min_stat, &gr.gr_token);
+ free(gr.gr_ctx.value);
+
+ if (!call_stat) {
+ result = AUTH_FAILED;
+ break;
+ }
+
+ if (gr.gr_major == GSS_S_COMPLETE)
+ gd->established = TRUE;
+
+ break;
+
+ case RPCSEC_GSS_DATA:
+ if (!svcauth_gss_validate(gd, msg, &qop)) {
+ result = RPCSEC_GSS_CREDPROBLEM;
+ break;
+ }
+
+ if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) {
+ result = AUTH_FAILED;
+ break;
+ }
+
+ if (!gd->callback_done) {
+ gd->callback_done = TRUE;
+ gd->sec.qop = qop;
+ (void)rpc_gss_num_to_qop(gd->rcred.mechanism,
+ gd->sec.qop, &gd->rcred.qop);
+ if (!svcauth_gss_callback(rqst, gd)) {
+ result = AUTH_REJECTEDCRED;
+ break;
+ }
+ }
+
+ if (gd->locked) {
+ if (gd->rcred.service !=
+ _rpc_gss_svc_to_service(gc->gc_svc)) {
+ result = AUTH_FAILED;
+ break;
+ }
+ if (gd->sec.qop != qop) {
+ result = AUTH_BADVERF;
+ break;
+ }
+ }
+
+ if (gd->sec.qop != qop) {
+ gd->sec.qop = qop;
+ (void)rpc_gss_num_to_qop(gd->rcred.mechanism,
+ qop, &gd->rcred.qop);
+ }
+
+ gd->rcred.service = _rpc_gss_svc_to_service(gc->gc_svc);
+
+ break;
+
+ case RPCSEC_GSS_DESTROY:
+ if (rqst->rq_proc != NULLPROC) {
+ result = AUTH_FAILED; /* XXX ? */
+ break;
+ }
+
+ if (!svcauth_gss_validate(gd, msg, &qop)) {
+ result = RPCSEC_GSS_CREDPROBLEM;
+ break;
+ }
+
+ if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) {
+ result = AUTH_FAILED;
+ break;
+ }
+
+ if (!svcauth_gss_release_cred()) {
+ result = AUTH_FAILED;
+ break;
+ }
+
+ SVCAUTH_DESTROY(&SVC_XP_AUTH(rqst->rq_xprt));
+ SVC_XP_AUTH(rqst->rq_xprt).svc_ah_ops = svc_auth_none.svc_ah_ops;
+ SVC_XP_AUTH(rqst->rq_xprt).svc_ah_private = NULL;
+
+ break;
+
+ default:
+ result = AUTH_REJECTEDCRED;
+ break;
+ }
+out:
+ xdr_free((xdrproc_t)xdr_rpc_gss_cred, (caddr_t)gc);
+ return result;
+}
+
+static bool_t
+svcauth_gss_destroy(SVCAUTH *auth)
+{
+ struct svc_rpc_gss_data *gd;
+ struct svcauth_gss_cache_entry **ce;
+
+ gss_log_debug("in svcauth_gss_destroy()");
+
+ gd = SVCAUTH_PRIVATE(auth);
+
+ mutex_lock(&svcauth_gss_cache_lock);
+ for (ce = &svcauth_gss_cache; *ce; ce = &(*ce)->next) {
+ if ((*ce)->gd == gd) {
+ struct svcauth_gss_cache_entry *ce_destroy = *ce;
+ *ce = (*ce)->next;
+ mem_free(ce_destroy, sizeof(*ce_destroy));
+ break;
+ }
+ }
+ mutex_unlock(&svcauth_gss_cache_lock);
+
+ destroy_gd(gd);
+
+ return (TRUE);
+}
+
+static bool_t
+svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+ struct svc_rpc_gss_data *gd;
+
+ gss_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));
+}
+
+static bool_t
+svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+ struct svc_rpc_gss_data *gd;
+
+ gss_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);
+}
+
+/*
+ * External API: Return maximum data size for a security mechanism and transport
+ *
+ * rqst: an incoming RPC request
+ * maxlen: transport's maximum data size, in bytes
+ *
+ * Returns maximum data size given transformations done by current
+ * security setting of "auth", in bytes, or zero if that value
+ * cannot be determined.
+ */
+int
+rpc_gss_svc_max_data_length(struct svc_req *rqst, int maxlen)
+{
+ OM_uint32 max_input_size, maj_stat, min_stat;
+ struct svc_rpc_gss_data *gd;
+ int conf_req_flag;
+ int result;
+
+ if (!rqst)
+ return 0;
+
+ gd = SVCAUTH_PRIVATE(&SVC_XP_AUTH(rqst->rq_xprt));
+
+ switch (gd->rcred.service) {
+ case rpcsec_gss_svc_none:
+ return maxlen;
+ case rpcsec_gss_svc_default:
+ case rpcsec_gss_svc_integrity:
+ conf_req_flag = 0;
+ break;
+ case rpcsec_gss_svc_privacy:
+ conf_req_flag = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ result = 0;
+ maj_stat = gss_wrap_size_limit(&min_stat, gd->ctx, conf_req_flag,
+ gd->sec.qop, maxlen, &max_input_size);
+ if (maj_stat == GSS_S_COMPLETE)
+ if ((int)max_input_size > 0)
+ result = (int)max_input_size;
+ return result;
+}
+
+/*
+ * External API: Set server's GSS principal
+ *
+ * principal: NUL-terminated C string containing GSS principal
+ * mechanism: NUL-terminated C string containing GSS mechanism name
+ * req_time: time in seconds until credential expires
+ * program: program number of the RPC service
+ * version: version number of the RPC service
+ *
+ * Returns TRUE if successful, otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_set_svc_name(char *principal, char *mechanism, u_int req_time,
+ u_int UNUSED(program), u_int UNUSED(version))
+{
+ rpc_gss_OID oid;
+ char *save;
+
+ if (principal == NULL)
+ return FALSE;
+ save = strdup(principal);
+ if (save == NULL)
+ return FALSE;
+
+ if (!rpc_gss_mech_to_oid(mechanism, &oid))
+ goto out_err;
+
+ if (!svcauth_gss_import_name(principal))
+ goto out_err;
+
+ _svcauth_req_time = req_time;
+ _svcauth_oid_set.count = 1;
+ _svcauth_oid_set.elements = (gss_OID)oid;
+ free(_svcauth_svc_name);
+ _svcauth_svc_name = save;
+ return TRUE;
+
+out_err:
+ free(save);
+ return FALSE;
+}
+
+static void
+_rpc_gss_fill_in_ucreds(struct svc_rpc_gss_data *gd)
+{
+ rpc_gss_ucred_t *ucred = &gd->ucred;
+ OM_uint32 maj_stat, min_stat;
+ struct passwd pwd, *pw;
+ long buflen;
+ uid_t uid;
+ char *buf;
+ int len;
+
+ /* default: "nfsnobody" */
+ ucred->uid = 65534;
+ ucred->gid = 65534;
+ ucred->gidlen = 0;
+ ucred->gidlist = gd->gids;
+
+ maj_stat = gss_pname_to_uid(&min_stat, gd->client_name,
+ gd->sec.mech, &uid);
+ if (maj_stat != GSS_S_COMPLETE)
+ return;
+
+ buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (buflen == -1)
+ return;
+ buf = malloc((size_t)buflen);
+ if (buf == NULL)
+ return;
+
+ (void)getpwuid_r(uid, &pwd, buf, buflen, &pw);
+ if (pw == NULL) {
+ free(buf);
+ return;
+ }
+
+ ucred->uid = pw->pw_uid;
+ ucred->gid = pw->pw_gid;
+ len = NGRPS;
+ (void)getgrouplist(pw->pw_name, pw->pw_gid, ucred->gidlist, &len);
+ ucred->gidlen = len;
+
+ free(buf);
+}
+
+/*
+ * External API: Retrieve requesting client's GSS credential
+ *
+ * rqst: an incoming RPC request
+ * rcred: address of pointer to fill in, or NULL
+ * ucred: address of pointer to fill in, or NULL
+ * cookie: address of pointer to fill in, or NULL
+ *
+ * Returns TRUE if successful. "rcred," "ucred," and "cookie"
+ * are filled in with pointers to the relevant structures.
+ * Caller must not free the memory returned by this API.
+ */
+bool_t
+rpc_gss_getcred(struct svc_req *rqst, rpc_gss_rawcred_t **rcred,
+ rpc_gss_ucred_t **ucred, void **cookie)
+{
+ struct svc_rpc_gss_data *gd;
+
+ if (rqst == NULL)
+ return FALSE;
+
+ if (rqst->rq_xprt->xp_verf.oa_flavor != RPCSEC_GSS)
+ return FALSE;
+
+ gd = SVCAUTH_PRIVATE(&SVC_XP_AUTH(rqst->rq_xprt));
+
+ if (rcred != NULL) {
+ gd->scratch = gd->rcred;
+ gd->scratch.service = _rpc_gss_svc_to_service(gd->sec.svc);
+ (void)rpc_gss_num_to_qop(gd->scratch.mechanism, gd->sec.qop,
+ &gd->scratch.qop);
+ *rcred = &gd->scratch;
+ }
+
+ if (ucred != NULL) {
+ _rpc_gss_fill_in_ucreds(gd);
+ *ucred = &gd->ucred;
+ }
+
+ if (cookie != NULL)
+ *cookie = gd->cookie;
+
+ return TRUE;
+}
+
+/*
+ * External API: Register a callback function
+ *
+ * callback: callback structure containing function and parameters
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ *
+ * "callback" is copied by rpc_gss_set_callback(), and may be freed
+ * immediately after it returns.
+ */
+bool_t
+rpc_gss_set_callback(rpc_gss_callback_t *callback)
+{
+ struct svc_rpc_gss_callback *new;
+
+ if (callback == NULL)
+ return FALSE;
+
+ /* XXX: This is never freed */
+ new = malloc(sizeof(*new));
+ if (new == NULL)
+ return FALSE;
+
+ new->cb_args = *callback;
+
+ mutex_lock(&svcauth_cb_lock);
+ new->cb_next = _svcauth_callbacks;
+ _svcauth_callbacks = new;
+ mutex_unlock(&svcauth_cb_lock);
+
+ return TRUE;
+}
+
+/*
+ * External API: Form a generic rpc_gss_principal
+ *
+ * principal: address of buffer to fill in
+ * mechanism: NUL-terminated C string containing GSS mechanism name
+ * user_name: NUL-terminated C string containing user or service principal
+ * node: NUL-terminated C string containing a hostname
+ * secdomain: NUL-terminated C string containing a security realm
+ *
+ * Returns TRUE if successful, otherwise FALSE. Caller must free
+ * returned "principal" with free(3).
+ */
+bool_t
+rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mechanism,
+ char *user_name, char *node, char *secdomain)
+{
+ OM_uint32 maj_stat, min_stat;
+ rpc_gss_principal_t result;
+ size_t nodelen, secdomlen;
+ gss_name_t name, mechname;
+ gss_buffer_desc namebuf;
+ rpc_gss_OID oid;
+
+
+ if (principal == NULL || user_name == NULL || strlen(user_name) == 0)
+ return FALSE;
+ if (!rpc_gss_mech_to_oid(mechanism, &oid))
+ return FALSE;
+
+ nodelen = 0;
+ if (node != NULL)
+ nodelen = strlen(node) + 1;
+ secdomlen = 0;
+ if (secdomain != NULL)
+ secdomlen = strlen(secdomain) + 1;
+ namebuf.length = strlen(user_name) + nodelen + secdomlen;
+ namebuf.value = calloc(1, namebuf.length);
+ if (namebuf.value == NULL)
+ return FALSE;
+ (void)strcpy(namebuf.value, user_name);
+ if (nodelen > 0) {
+ (void)strcat(namebuf.value, "/");
+ (void)strcat(namebuf.value, node);
+ }
+ if (secdomlen > 0) {
+ (void)strcat(namebuf.value, "@");
+ (void)strcat(namebuf.value, secdomain);
+ }
+
+ maj_stat = gss_import_name(&min_stat, &namebuf,
+ GSS_C_NT_USER_NAME, &name);
+ free(namebuf.value);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_import_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ maj_stat = gss_canonicalize_name(&min_stat, name, oid, &mechname);
+ (void)gss_release_name(&min_stat, &name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_canonicalize_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ maj_stat = gss_export_name(&min_stat, mechname, &namebuf);
+ (void)gss_release_name(&min_stat, &mechname);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_export_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ result = calloc(1, sizeof(*result) + namebuf.length);
+ if (result == NULL) {
+ (void)gss_release_buffer(&min_stat, &namebuf);
+ return FALSE;
+ }
+ result->len = namebuf.length;
+ (void)memcpy(result->name, namebuf.value, namebuf.length);
+ (void)gss_release_buffer(&min_stat, &namebuf);
+
+ *principal = result;
+ return TRUE;
+}
diff --git a/src/svc_auth_none.c b/src/svc_auth_none.c
new file mode 100644
index 0000000..887e809
--- /dev/null
+++ b/src/svc_auth_none.c
@@ -0,0 +1,71 @@
+/*
+ svc_auth_none.c
+
+ Copyright (c) 2000 The Regents of the University of Michigan.
+ All rights reserved.
+
+ Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+ 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 <rpc/rpc.h>
+
+static bool_t svcauth_none_destroy();
+static bool_t svcauth_none_wrap();
+
+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,
+};
+
+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));
+}
+
+enum auth_stat
+_svcauth_none(struct svc_req *rqst, struct rpc_msg *msg)
+{
+ return (AUTH_OK);
+}
diff --git a/src/svc_auth_unix.c b/src/svc_auth_unix.c
new file mode 100644
index 0000000..8f992a4
--- /dev/null
+++ b/src/svc_auth_unix.c
@@ -0,0 +1,148 @@
+/*
+ * 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 <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+
+extern SVCAUTH svc_auth_none;
+
+/*
+ * 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/src/svc_dg.c b/src/svc_dg.c
new file mode 100644
index 0000000..a9f63ff
--- /dev/null
+++ b/src/svc_dg.c
@@ -0,0 +1,721 @@
+
+/*
+ * 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_dg.c, Server side for connectionless RPC.
+ *
+ * Does some caching in the hopes of achieving execute-at-most-once semantics.
+ */
+#include <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <rpc/svc_dg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netconfig.h>
+#include <err.h>
+
+#include "rpc_com.h"
+#include "debug.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);
+static void svc_dg_enable_pktinfo(int, const struct __rpc_sockinfo *);
+static int svc_dg_valid_pktinfo(struct msghdr *);
+
+/*
+ * 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;
+ SVCXPRT_EXT *ext = NULL;
+ struct svc_dg_data *su = NULL;
+ struct __rpc_sockinfo si;
+ struct sockaddr_storage ss;
+ socklen_t slen;
+
+ if (!__rpc_fd2sockinfo(fd, &si)) {
+ 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)) {
+ warnx(svc_dg_str, svc_dg_err2);
+ return (NULL);
+ }
+
+ xprt = mem_alloc(sizeof (SVCXPRT));
+ if (xprt == NULL)
+ goto freedata;
+ memset(xprt, 0, sizeof (SVCXPRT));
+
+ ext = mem_alloc(sizeof (*ext));
+ if (ext == NULL)
+ goto freedata;
+ memset(ext, 0, sizeof (*ext));
+
+ 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_p3 = ext;
+ 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) < 0)
+ goto freedata;
+ __rpc_set_netbuf(&xprt->xp_ltaddr, &ss, slen);
+
+ /* Enable reception of IP*_PKTINFO control msgs */
+ svc_dg_enable_pktinfo(fd, &si);
+
+ xprt_register(xprt);
+ return (xprt);
+freedata:
+ (void) warnx(svc_dg_str, __no_mem_str);
+ if (xprt) {
+ if (su)
+ (void) mem_free(su, sizeof (*su));
+ if (ext)
+ (void) mem_free(ext, sizeof (*ext));
+ (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;
+ struct msghdr *mesgp;
+ struct iovec iov;
+ size_t replylen;
+ ssize_t rlen;
+
+again:
+ iov.iov_base = rpc_buffer(xprt);
+ iov.iov_len = su->su_iosz;
+ mesgp = &su->su_msghdr;
+ memset(mesgp, 0, sizeof(*mesgp));
+ mesgp->msg_iov = &iov;
+ mesgp->msg_iovlen = 1;
+ mesgp->msg_name = (struct sockaddr *)(void *) &ss;
+ mesgp->msg_namelen = sizeof (struct sockaddr_storage);
+ mesgp->msg_control = su->su_cmsg;
+ mesgp->msg_controllen = sizeof(su->su_cmsg);
+
+ rlen = recvmsg(xprt->xp_fd, mesgp, 0);
+ 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, mesgp->msg_namelen);
+
+ /* Check whether there's an IP_PKTINFO or IP6_PKTINFO control message.
+ * If yes, preserve it for svc_dg_reply; otherwise just zap any cmsgs */
+ if (!svc_dg_valid_pktinfo(mesgp)) {
+ mesgp->msg_control = NULL;
+ mesgp->msg_controllen = 0;
+ }
+
+ __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)) {
+ iov.iov_base = reply;
+ iov.iov_len = replylen;
+ (void) sendmsg(xprt->xp_fd, mesgp, 0);
+ 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;
+
+ xdrproc_t xdr_results;
+ caddr_t xdr_location;
+ bool_t has_args;
+
+ if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+ msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+ has_args = TRUE;
+ xdr_results = msg->acpted_rply.ar_results.proc;
+ xdr_location = msg->acpted_rply.ar_results.where;
+
+ msg->acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ msg->acpted_rply.ar_results.where = NULL;
+ } else
+ has_args = FALSE;
+
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS(xdrs, 0);
+ msg->rm_xid = su->su_xid;
+ if (xdr_replymsg(xdrs, msg) &&
+ (!has_args ||
+ SVCAUTH_WRAP(&SVC_XP_AUTH(xprt),
+ xdrs, xdr_results, xdr_location))) {
+ struct msghdr *msg = &su->su_msghdr;
+ struct iovec iov;
+
+ iov.iov_base = rpc_buffer(xprt);
+ iov.iov_len = slen = XDR_GETPOS(xdrs);
+ msg->msg_iov = &iov;
+ msg->msg_iovlen = 1;
+ msg->msg_name = (struct sockaddr *)(void *) xprt->xp_rtaddr.buf;
+ msg->msg_namelen = xprt->xp_rtaddr.len;
+ /* cmsg already set in svc_dg_recv */
+
+ if (sendmsg(xprt->xp_fd, msg, 0) == (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;
+{
+ if (!SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt),
+ &(su_data(xprt)->su_xdrs),
+ xdr_args, args_ptr)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+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;
+{
+ SVCXPRT_EXT *ext = SVCEXT(xprt);
+ struct svc_dg_data *su = su_data(xprt);
+
+ xprt_unregister(xprt);
+ if (xprt->xp_fd != -1)
+ (void)close(xprt->xp_fd);
+ XDR_DESTROY(&(su->su_xdrs));
+ (void) mem_free(rpc_buffer(xprt), su->su_iosz);
+ (void) mem_free(su, sizeof (*su));
+ (void) mem_free(ext, sizeof (*ext));
+ 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);
+ if (xprt->xp_netid)
+ (void) free(xprt->xp_netid);
+ (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) {
+ (void) warnx(cache_enable_str, enable_err, " ");
+ mutex_unlock(&dupreq_lock);
+ return (0);
+ }
+ uc = ALLOC(struct cl_cache, 1);
+ if (uc == NULL) {
+ 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) {
+ 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) {
+ 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;
+ struct netconfig *nconf;
+ char *uaddr;
+
+ 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) {
+ 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) {
+ warnx(cache_set_str, cache_set_err2);
+ mutex_unlock(&dupreq_lock);
+ return;
+ }
+ newbuf = mem_alloc(su->su_iosz);
+ if (newbuf == NULL) {
+ warnx(cache_set_str, cache_set_err3);
+ FREE(victim, struct cache_node, 1);
+ mutex_unlock(&dupreq_lock);
+ return;
+ }
+ }
+
+ /*
+ * Store it away
+ */
+ if (libtirpc_debug_level > 3) {
+ if ((nconf = getnetconfigent(xprt->xp_netid))) {
+ uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
+ freenetconfigent(nconf);
+ LIBTIRPC_DEBUG(4,
+ ("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);
+ }
+ }
+ 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;
+ struct netconfig *nconf;
+ char *uaddr;
+
+ 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)) {
+ if (libtirpc_debug_level > 3) {
+ if ((nconf = getnetconfigent(xprt->xp_netid))) {
+ uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
+ freenetconfigent(nconf);
+ LIBTIRPC_DEBUG(4,
+ ("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);
+ }
+ }
+ *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);
+}
+
+/*
+ * Enable reception of PKTINFO control messages
+ */
+void
+svc_dg_enable_pktinfo(int fd, const struct __rpc_sockinfo *si)
+{
+ int val = 1;
+
+ switch (si->si_af) {
+ case AF_INET:
+ (void) setsockopt(fd, SOL_IP, IP_PKTINFO, &val, sizeof(val));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ (void) setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
+ break;
+#endif
+ }
+}
+
+/*
+ * When given a control message received from the socket
+ * layer, check whether it contains valid PKTINFO data matching
+ * the address family of the peer address.
+ */
+int
+svc_dg_valid_pktinfo(struct msghdr *msg)
+{
+ struct cmsghdr *cmsg;
+
+ if (!msg->msg_name)
+ return 0;
+
+ if (msg->msg_flags & MSG_CTRUNC)
+ return 0;
+
+ cmsg = CMSG_FIRSTHDR(msg);
+ if (cmsg == NULL || CMSG_NXTHDR(msg, cmsg) != NULL)
+ return 0;
+
+ switch (((struct sockaddr *) msg->msg_name)->sa_family) {
+ case AF_INET:
+ if (cmsg->cmsg_level != SOL_IP
+ || cmsg->cmsg_type != IP_PKTINFO
+ || cmsg->cmsg_len < CMSG_LEN(sizeof (struct in_pktinfo))) {
+ return 0;
+ } else {
+ struct in_pktinfo *pkti;
+
+ pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+ pkti->ipi_ifindex = 0;
+ }
+ break;
+
+#ifdef INET6
+ case AF_INET6:
+ if (cmsg->cmsg_level != SOL_IPV6
+ || cmsg->cmsg_type != IPV6_PKTINFO
+ || cmsg->cmsg_len < CMSG_LEN(sizeof (struct in6_pktinfo))) {
+ return 0;
+ } else {
+ struct in6_pktinfo *pkti;
+
+ pkti = (struct in6_pktinfo *) CMSG_DATA (cmsg);
+ pkti->ipi6_ifindex = 0;
+ }
+ break;
+#endif
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/src/svc_generic.c b/src/svc_generic.c
new file mode 100644
index 0000000..20abaa2
--- /dev/null
+++ b/src/svc_generic.c
@@ -0,0 +1,299 @@
+
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "rpc_com.h"
+#include <rpc/svc.h>
+
+extern int __svc_vc_setflag(SVCXPRT *, int);
+extern int __binddynport(int fd);
+
+/*
+ * 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) {
+ 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)
+ 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) {
+ warnx("svc_create: no memory");
+ mutex_unlock(&xprtlist_lock);
+ __rpc_endconf(handle);
+ 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) {
+ 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) {
+ 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)
+ int 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) {
+ warnx("svc_tli_create: invalid netconfig");
+ return (NULL);
+ }
+ fd = __rpc_nconf2fd(nconf);
+ if (fd == -1) {
+ 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)) {
+ 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 (__binddynport(fd) == -1) {
+ 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) < 0) {
+ 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:
+ 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) {
+ if (xprt->xp_netid != NULL)
+ free(xprt->xp_netid);
+ xprt->xp_netid = strdup(nconf->nc_netid);
+ xprt->xp_tp = strdup(nconf->nc_device);
+ }
+ return (xprt);
+
+freedata:
+ if (madefd)
+ (void)close(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/src/svc_raw.c b/src/svc_raw.c
new file mode 100644
index 0000000..a8a396f
--- /dev/null
+++ b/src/svc_raw.c
@@ -0,0 +1,256 @@
+
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <rpc/rpc.h>
+#include <sys/types.h>
+#include <rpc/raw.h>
+#include <stdlib.h>
+
+#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;
+ SVCXPRT_EXT *ext = NULL;
+/* 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);
+ }
+ ext = mem_alloc(sizeof (*ext));
+ if (ext == NULL) {
+ free(srp);
+ mutex_unlock(&svcraw_lock);
+ return (NULL);
+ }
+ memset(ext, 0, sizeof (*ext));
+ srp->server.xp_p3 = ext;
+ 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;
+ svc_flags(&srp->server) = 0;
+ 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/src/svc_run.c b/src/svc_run.c
new file mode 100644
index 0000000..f40314b
--- /dev/null
+++ b/src/svc_run.c
@@ -0,0 +1,114 @@
+/*
+ * 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 <pthread.h>
+#include <reentrant.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/poll.h>
+
+
+#include <rpc/rpc.h>
+#include "rpc_com.h"
+#include <sys/select.h>
+
+void
+svc_run()
+{
+ int i;
+ struct pollfd *my_pollfd = NULL;
+ int last_max_pollfd = 0;
+
+ for (;;) {
+ int max_pollfd = svc_max_pollfd;
+ if (max_pollfd == 0 && svc_pollfd == NULL)
+ break;
+
+ if (last_max_pollfd != max_pollfd)
+ {
+ struct pollfd *new_pollfd
+ = realloc (my_pollfd, sizeof (struct pollfd) * max_pollfd);
+
+ if (new_pollfd == NULL)
+ {
+ warn ("svc_run: - out of memory");
+ break;
+ }
+
+ my_pollfd = new_pollfd;
+ last_max_pollfd = max_pollfd;
+ }
+
+ for (i = 0; i < max_pollfd; ++i)
+ {
+ my_pollfd[i].fd = svc_pollfd[i].fd;
+ my_pollfd[i].events = svc_pollfd[i].events;
+ my_pollfd[i].revents = 0;
+ }
+
+ switch (i = poll (my_pollfd, max_pollfd, -1))
+ {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ warn ("svc_run: - poll failed");
+ break;
+ case 0:
+ continue;
+ default:
+ svc_getreq_poll (my_pollfd, i);
+ continue;
+ }
+ break;
+ }
+
+ free (my_pollfd);
+}
+
+/*
+ * 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);
+ free (svc_pollfd);
+ svc_pollfd = NULL;
+ svc_max_pollfd = 0;
+ rwlock_unlock(&svc_fd_lock);
+}
diff --git a/src/svc_simple.c b/src/svc_simple.c
new file mode 100644
index 0000000..c32fe0a
--- /dev/null
+++ b/src/svc_simple.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_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 <pthread.h>
+#include <reentrant.h>
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#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) {
+ warnx("%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) {
+ 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)) {
+ 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) {
+ 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)) {
+ warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
+ SVC_DESTROY(svcxprt);
+ free(xdrbuf);
+ 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)) {
+ 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) {
+ 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) {
+ 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) {
+ 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)) {
+ 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 */
+ warnx("rpc: rpc_reg: never registered prog %u vers %u",
+ (unsigned)prog, (unsigned)vers);
+ return;
+}
diff --git a/src/svc_vc.c b/src/svc_vc.c
new file mode 100644
index 0000000..3dc8a75
--- /dev/null
+++ b/src/svc_vc.c
@@ -0,0 +1,882 @@
+
+/*
+ * 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_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 <pthread.h>
+#include <reentrant.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <poll.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+
+#include "rpc_com.h"
+
+#include <getpeereid.h>
+
+
+extern rwlock_t svc_fd_lock;
+extern SVCXPRT **__svc_xports;
+extern int svc_open_fds();
+
+static SVCXPRT *makefd_xprt(int, 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);
+static int __svc_destroy_idle(int timeout);
+
+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 = NULL;
+ SVCXPRT_EXT *ext = NULL;
+ struct cf_rendezvous *r = NULL;
+ struct __rpc_sockinfo si;
+ struct sockaddr_storage sslocal;
+ socklen_t slen;
+
+ r = mem_alloc(sizeof(*r));
+ if (r == NULL) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ if (!__rpc_fd2sockinfo(fd, &si)) {
+ warnx("svc_vc_create: __rpc_fd2sockinfo failed");
+ goto cleanup_svc_vc_create;
+ }
+ 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) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ ext = mem_alloc(sizeof (*ext));
+ if (ext == NULL) {
+ warnx("svc_vc_create: out of memory");
+ goto cleanup_svc_vc_create;
+ }
+ memset(ext, 0, sizeof (*ext));
+ xprt->xp_tp = NULL;
+ xprt->xp_p1 = r;
+ xprt->xp_p2 = NULL;
+ xprt->xp_p3 = ext;
+ 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) < 0) {
+ warnx("svc_vc_create: could not retrieve local addr");
+ goto cleanup_svc_vc_create;
+ }
+
+ if (!__rpc_set_netbuf(&xprt->xp_ltaddr, &sslocal, sizeof(sslocal))) {
+ 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));
+ if (xprt != NULL)
+ mem_free(xprt, sizeof(*xprt));
+ if (ext != NULL)
+ mem_free(ext, sizeof(*ext));
+ 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)
+ int 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) < 0) {
+ warnx("svc_fd_create: could not retrieve local addr");
+ goto freedata;
+ }
+ if (!__rpc_set_netbuf(&ret->xp_ltaddr, &ss, sizeof(ss))) {
+ warnx("svc_fd_create: no mem for local addr");
+ goto freedata;
+ }
+
+ slen = sizeof (struct sockaddr_storage);
+ if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
+ warnx("svc_fd_create: could not retrieve remote addr");
+ goto freedata;
+ }
+ if (!__rpc_set_netbuf(&ret->xp_rtaddr, &ss, sizeof(ss))) {
+ warnx("svc_fd_create: no mem for remote 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);
+ ret->xp_ltaddr.buf = NULL;
+ }
+ return NULL;
+}
+
+static SVCXPRT *
+makefd_xprt(fd, sendsize, recvsize)
+ int fd;
+ u_int sendsize;
+ u_int recvsize;
+{
+ SVCXPRT *xprt;
+ SVCXPRT_EXT *ext;
+ struct cf_conn *cd;
+ const char *netid;
+ struct __rpc_sockinfo si;
+
+ assert(fd != -1);
+
+ xprt = mem_alloc(sizeof(SVCXPRT));
+ if (xprt == NULL) {
+ warnx("svc_vc: makefd_xprt: out of memory");
+ goto done;
+ }
+ memset(xprt, 0, sizeof *xprt);
+ ext = mem_alloc(sizeof (*ext));
+ if (ext == NULL) {
+ warnx("svc_vc: makefd_xprt: out of memory");
+ mem_free(xprt, sizeof(SVCXPRT));
+ xprt = NULL;
+ goto done;
+ }
+ memset(ext, 0, sizeof (*ext));
+ cd = mem_alloc(sizeof(struct cf_conn));
+ if (cd == NULL) {
+ warnx("svc_vc: makefd_xprt: out of memory");
+ mem_free(ext, sizeof(*ext));
+ 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_p3 = ext;
+ 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;
+{
+ int sock, flags, nfds, cnt;
+ struct cf_rendezvous *r;
+ struct cf_conn *cd;
+ struct sockaddr_storage addr;
+ socklen_t len;
+ struct __rpc_sockinfo si;
+ SVCXPRT *newxprt;
+
+ assert(xprt != NULL);
+ assert(msg != NULL);
+
+ r = (struct cf_rendezvous *)xprt->xp_p1;
+again:
+ len = sizeof addr;
+ sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, &len);
+ if (sock < 0) {
+ if (errno == EINTR)
+ goto again;
+ return (FALSE);
+ }
+ /*
+ * make a new transporter (re-uses xprt)
+ */
+
+ newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
+ if (!newxprt)
+ return (FALSE);
+
+ 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, &len, sizeof (len));
+ }
+
+ cd = (struct cf_conn *)newxprt->xp_p1;
+
+ cd->recvsize = r->recvsize;
+ cd->sendsize = r->sendsize;
+ cd->maxrec = r->maxrec;
+
+ 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;
+
+ gettimeofday(&cd->last_recv_time, NULL);
+
+ nfds = svc_open_fds();
+ if (nfds >= (_rpc_dtablesize() / 5) * 4) {
+ /* destroy idle connections */
+ cnt = __svc_destroy_idle(15);
+ if (cnt == 0) {
+ /* destroy least active */
+ __svc_destroy_idle(0);
+ }
+ }
+
+ 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 bool_t
+__svc_rendezvous_socket(xprt)
+ SVCXPRT *xprt;
+{
+ return (xprt->xp_ops->xp_recv == rendezvous_request);
+}
+static void
+__svc_vc_dodestroy(xprt)
+ SVCXPRT *xprt;
+{
+ SVCXPRT_EXT *ext = SVCEXT(xprt);
+ struct cf_conn *cd;
+ struct cf_rendezvous *r;
+
+ cd = (struct cf_conn *)xprt->xp_p1;
+
+ if (xprt->xp_fd != RPC_ANYFD)
+ (void)close(xprt->xp_fd);
+ if (__svc_rendezvous_socket(xprt)) {
+ /* 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 (ext)
+ mem_free(ext, sizeof (*ext));
+ 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;
+ int 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) {
+ /* Since len == 0 is returned on zero length
+ * read or EOF errno needs to be reset before
+ * the read
+ */
+ errno = 0;
+ len = read(sock, buf, (size_t)len);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ 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);
+
+ if ((len = read(sock, buf, (size_t)len)) > 0) {
+ 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;
+ void *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) {
+ i = write(xprt->xp_fd, buf, (size_t)cnt);
+ if (i < 0) {
+ if (errno != EAGAIN || !cd->nonblock) {
+ cd->strm_stat = XPRT_DIED;
+ return (-1);
+ }
+ /*
+ * 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);
+ }
+ i = 0; /* Don't change buf and cnt */
+ }
+ }
+
+ 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;
+ /*
+ * No need skip records with nonblocking connections
+ */
+ if (cd->nonblock == FALSE)
+ (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 */
+
+ if (!SVCAUTH_UNWRAP(&SVC_XP_AUTH(xprt),
+ &(((struct cf_conn *)(xprt->xp_p1))->xdrs),
+ xdr_args, args_ptr)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+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;
+
+ xdrproc_t xdr_results;
+ caddr_t xdr_location;
+ bool_t has_args;
+
+ assert(xprt != NULL);
+ assert(msg != NULL);
+
+ cd = (struct cf_conn *)(xprt->xp_p1);
+ xdrs = &(cd->xdrs);
+
+ if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+ msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+ has_args = TRUE;
+ xdr_results = msg->acpted_rply.ar_results.proc;
+ xdr_location = msg->acpted_rply.ar_results.where;
+
+ msg->acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ msg->acpted_rply.ar_results.where = NULL;
+ } else
+ has_args = FALSE;
+
+ xdrs->x_op = XDR_ENCODE;
+ msg->rm_xid = cd->x_id;
+ rstat = FALSE;
+ if (xdr_replymsg(xdrs, msg) &&
+ (!has_args ||
+ SVCAUTH_WRAP(&SVC_XP_AUTH(xprt),
+ xdrs, xdr_results, xdr_location))) {
+ rstat = TRUE;
+ }
+ (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) {
+ int sock, 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_LOCAL) {
+ ret = getpeereid(sock, &euid, &egid);
+ if (ret == 0)
+ *uid = euid;
+ return (ret);
+ } else
+ return (-1);
+}
+
+/*
+ * 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.
+ *
+ * Though this is not a publicly documented interface, some versions of
+ * rpcbind are known to call this function. Do not alter or remove this
+ * API without changing the library's sonum.
+ */
+/* Since this is an exported interface used by rpcbind, we cannot
+ remove it. But since poll() can handle much more and much higher
+ file descriptors, this code doesn't really work anymore, too.
+ So for now, keep it as dummy function and do nothing to not break
+ existing binaries. If we have ported rpcbind to the poll() interface
+ and find out, that we really need this cleanup stuff (but nobody
+ besides FreeBSD has this), we need to re-implement it using poll().
+ But this means a new function name with different parameters. For
+ ABI/API compatibility, we cannot reuse this one. */
+bool_t
+__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
+{
+ return FALSE;
+}
+
+static int
+__svc_destroy_idle(int timeout)
+{
+ int i, ncleaned = 0;
+ 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 = 0; i <= svc_max_pollfd; i++) {
+ if (svc_pollfd[i].fd == -1)
+ continue;
+ 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 (!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);
+}
diff --git a/src/xdr.c b/src/xdr.c
new file mode 100644
index 0000000..28d1382
--- /dev/null
+++ b/src/xdr.c
@@ -0,0 +1,1025 @@
+/*
+ * 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.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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/rpc.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc_com.h>
+
+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)
+
+/*
+ * 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 unsigned 32-bit integers
+ */
+bool_t
+xdr_uint32_t(xdrs, uint32_p)
+ XDR *xdrs;
+ uint32_t *uint32_p;
+{
+ return (xdr_u_int32_t(xdrs, (u_int32_t *)uint32_p));
+}
+
+
+/*
+ * 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 unsigned 16-bit integers
+ */
+bool_t
+xdr_uint16_t(xdrs, uint16_p)
+ XDR *xdrs;
+ uint16_t *uint16_p;
+{
+ return (xdr_u_int16_t(xdrs, (u_int16_t *)uint16_p));
+}
+
+
+/*
+ * XDR 8-bit integers
+ */
+bool_t
+xdr_int8_t(xdrs, int8_p)
+ XDR *xdrs;
+ int8_t *int8_p;
+{
+ long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (long) *int8_p;
+ return (XDR_PUTLONG(xdrs, &l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, &l)) {
+ return (FALSE);
+ }
+ *int8_p = (int8_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR unsigned 8-bit integers
+ */
+bool_t
+xdr_u_int8_t(xdrs, uint8_p)
+ XDR *xdrs;
+ uint8_t *uint8_p;
+{
+ u_long l;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ l = (u_long) *uint8_p;
+ return (XDR_PUTLONG(xdrs, (long *)&l));
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG(xdrs, (long *)&l)) {
+ return (FALSE);
+ }
+ *uint8_p = (uint8_t) l;
+ return (TRUE);
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR unsigned 8-bit integers
+ */
+bool_t
+xdr_uint8_t(xdrs, uint8_p)
+ XDR *xdrs;
+ uint8_t *uint8_p;
+{
+ return (xdr_u_int8_t(xdrs, (uint8_t *)uint8_p));
+}
+
+
+/*
+ * 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 = 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;
+ 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;
+ bool_t ret, allocated = FALSE;
+
+ /*
+ * 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);
+ allocated = TRUE;
+ }
+ if (sp == NULL) {
+ warnx("xdr_bytes: out of memory");
+ return (FALSE);
+ }
+ /* FALLTHROUGH */
+
+ case XDR_ENCODE:
+ ret = xdr_opaque(xdrs, sp, nodesize);
+ if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
+ if (allocated == TRUE) {
+ free(sp);
+ *cpp = NULL;
+ }
+ }
+ return (ret);
+
+ 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;
+ bool_t ret, allocated = FALSE;
+
+ /*
+ * 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);
+ allocated = TRUE;
+ }
+ if (sp == NULL) {
+ warnx("xdr_string: out of memory");
+ return (FALSE);
+ }
+ sp[size] = 0;
+ /* FALLTHROUGH */
+
+ case XDR_ENCODE:
+ ret = xdr_opaque(xdrs, sp, size);
+ if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
+ if (allocated == TRUE) {
+ free(sp);
+ *cpp = NULL;
+ }
+ }
+ return (ret);
+
+ 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, RPC_MAXDATASIZE);
+}
+
+/*
+ * 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]) & 0xffffffff));
+ 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]) & 0xffffffff));
+ return (TRUE);
+ case XDR_FREE:
+ return (TRUE);
+ }
+ /* NOTREACHED */
+ return (FALSE);
+}
+
+
+/*
+ * XDR unsigned 64-bit integers
+ */
+bool_t
+xdr_uint64_t(xdrs, ullp)
+ XDR *xdrs;
+ uint64_t *ullp;
+{
+ return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp));
+}
+
+
+/*
+ * 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));
+}
+
+/*
+ * XDR quad_t
+ */
+bool_t
+xdr_quad_t(xdrs, llp)
+ XDR *xdrs;
+ int64_t *llp;
+{
+ return (xdr_int64_t(xdrs, (int64_t *)llp));
+}
+
+
+/*
+ * XDR u_quad_t
+ */
+bool_t
+xdr_u_quad_t(xdrs, ullp)
+ XDR *xdrs;
+ u_int64_t *ullp;
+{
+ return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp));
+}
diff --git a/src/xdr_array.c b/src/xdr_array.c
new file mode 100644
index 0000000..7fc8fb8
--- /dev/null
+++ b/src/xdr_array.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.
+ */
+
+
+/*
+ * 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 <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#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/src/xdr_float.c b/src/xdr_float.c
new file mode 100644
index 0000000..349d48f
--- /dev/null
+++ b/src/xdr_float.c
@@ -0,0 +1,297 @@
+
+/*
+ * 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_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 <sys/types.h>
+#include <sys/param.h>
+
+#include <stdio.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#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 <endian.h>
+#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/src/xdr_mem.c b/src/xdr_mem.c
new file mode 100644
index 0000000..ecdc932
--- /dev/null
+++ b/src/xdr_mem.c
@@ -0,0 +1,250 @@
+/*
+ * 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_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 <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#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 = ((unsigned long)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)((u_long)xdrs->x_private - (u_long)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) <? sizeof(ptrdiff_t) */
+ return (TRUE);
+}
+
+static int32_t *
+xdrmem_inline_aligned(xdrs, len)
+ XDR *xdrs;
+ u_int len;
+{
+ int32_t *buf = 0;
+
+ if (xdrs->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/src/xdr_rec.c b/src/xdr_rec.c
new file mode 100644
index 0000000..676cc82
--- /dev/null
+++ b/src/xdr_rec.c
@@ -0,0 +1,792 @@
+
+/*
+ * 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_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 <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/svc_auth.h>
+#include <rpc/svc.h>
+#include <rpc/clnt.h>
+#include <stddef.h>
+#include <errno.h>
+#include "rpc_com.h"
+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 */
+ long 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;
+ int in_hdrlen;
+ int in_reclen;
+ int in_received;
+ 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 *, int);
+static bool_t set_input_fragment(RECSTREAM *);
+static bool_t skip_input_bytes(RECSTREAM *, long);
+static bool_t realloc_stream(RECSTREAM *, 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)) &&
+ (((long)rstrm->in_boundry - (long)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);
+ 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)((u_long)rstrm->out_boundry -
+ (u_long)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;
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+ pos = rstrm->out_finger - rstrm->out_base
+ - BYTES_PER_XDR_UNIT;
+ break;
+
+ case XDR_DECODE:
+ pos = rstrm->in_boundry - rstrm->in_finger
+ - BYTES_PER_XDR_UNIT;
+ 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.
+ */
+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 ||
+ ((u_long)rstrm->out_finger + sizeof(u_int32_t) >=
+ (u_long)rstrm->out_boundry)) {
+ rstrm->frag_sent = FALSE;
+ return (flush_out(rstrm, TRUE));
+ }
+ len = (u_long)(rstrm->out_finger) - (u_long)(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);
+ ssize_t n;
+ 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) {
+ /* EAGAIN or EWOULDBLOCK means a zero length
+ * read not an EOF.
+ */
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ *statp = XPRT_IDLE;
+ else
+ *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;
+ }
+ rstrm->in_haveheader = 1;
+ }
+
+ 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) {
+ /* EAGAIN or EWOULDBLOCK means a zero length
+ * read not an EOF.
+ */
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ *statp = XPRT_IDLE;
+ else
+ *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)((u_long)(rstrm->out_finger) -
+ (u_long)(rstrm->frag_header) - sizeof(u_int32_t));
+
+ *(rstrm->frag_header) = htonl(len | eormask);
+ len = (u_int32_t)((u_long)(rstrm->out_finger) -
+ (u_long)(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)((u_long)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;
+ int len;
+{
+ size_t current;
+
+ if (rstrm->nonblock) {
+ if (len > (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)((long)rstrm->in_boundry -
+ (long)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;
+ long cnt;
+{
+ u_int32_t current;
+
+ while (cnt > 0) {
+ current = (size_t)((long)rstrm->in_boundry -
+ (long)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;
+ 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/src/xdr_reference.c b/src/xdr_reference.c
new file mode 100644
index 0000000..13f6410
--- /dev/null
+++ b/src/xdr_reference.c
@@ -0,0 +1,136 @@
+/*
+ * 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_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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+#include <libc_private.h>
+#endif
+
+/*
+ * 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/src/xdr_sizeof.c b/src/xdr_sizeof.c
new file mode 100644
index 0000000..79d6707
--- /dev/null
+++ b/src/xdr_sizeof.c
@@ -0,0 +1,165 @@
+/*
+ * 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 <rpc/types.h>
+#include <rpc/xdr.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "un-namespace.h"
+
+/* ARGSUSED */
+static bool_t
+x_putlong(xdrs, longp)
+ XDR *xdrs;
+ long *longp;
+{
+ xdrs->x_handy += BYTES_PER_XDR_UNIT;
+ return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+x_putbytes(xdrs, bp, len)
+ XDR *xdrs;
+ char *bp;
+ u_int len;
+{
+ xdrs->x_handy += len;
+ return (TRUE);
+}
+
+static u_int
+x_getpostn(xdrs)
+ XDR *xdrs;
+{
+ return (xdrs->x_handy);
+}
+
+/* ARGSUSED */
+static bool_t
+x_setpostn(xdrs, pos)
+ XDR *xdrs;
+ u_int pos;
+{
+ /* This is not allowed */
+ return (FALSE);
+}
+
+static int32_t *
+x_inline(xdrs, len)
+ XDR *xdrs;
+ u_int len;
+{
+ if (len == 0) {
+ return (NULL);
+ }
+ if (xdrs->x_op != XDR_ENCODE) {
+ return (NULL);
+ }
+ if (len < (uintptr_t)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 = (caddr_t)(uintptr_t)len;
+ 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(xdrs)
+ 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/src/xdr_stdio.c b/src/xdr_stdio.c
new file mode 100644
index 0000000..846c7bf
--- /dev/null
+++ b/src/xdr_stdio.c
@@ -0,0 +1,194 @@
+/*
+ * 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_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 <stdio.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#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;
+{
+ int32_t mycopy;
+
+ if (fread(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
+ return (FALSE);
+
+ *lp = (long)ntohl(mycopy);
+ return (TRUE);
+}
+
+static bool_t
+xdrstdio_putlong(xdrs, lp)
+ XDR *xdrs;
+ const long *lp;
+{
+ int32_t mycopy;
+
+#if defined(_LP64)
+ if ((*lp > UINT32_MAX) || (*lp < INT32_MIN))
+ return (FALSE);
+#endif
+
+ mycopy = (int32_t)htonl((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);
+}