diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:45:02 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:45:02 +0000 |
commit | 68a560641f7a38c184fd3346dd8008b86e12d77a (patch) | |
tree | d927b2a890d51e5d9e037c03042fb6fabd689cc0 /src | |
parent | Initial commit. (diff) | |
download | libtirpc-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 'src')
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 = # + 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, <mp, sizeof (ltmp)); + break; + + case CLSET_VERS: + memcpy(<mp, 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, <mp, sizeof (ltmp)); + break; + + case CLSET_PROG: + memcpy(<mp, 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, ®s->pm_prog) && + xdr_u_long(xdrs, ®s->pm_vers) && + xdr_u_long(xdrs, ®s->pm_prot)) + return (xdr_u_long(xdrs, ®s->pm_port)); + return (FALSE); +} 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, + ×tamp); + 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(×tamp, + &authdes_cache[sid].laststamp)) { + LIBTIRPC_DEBUG(1, ("_svcauth_des: timestamp before last seen")); + return (AUTH_REJECTEDVERF); /* replay */ + } + (void) gettimeofday(¤t, (struct timezone *)NULL); + current.tv_sec -= window; /* allow for expiration */ + if (!BEFORE(¤t, ×tamp)) { + 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 = # + 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); +} |